Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

app.bundle.js 2.3MB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741267422674326744267452674626747267482674926750267512675226753267542675526756267572675826759267602676126762267632676426765267662676726768267692677026771267722677326774267752677626777267782677926780267812678226783267842678526786267872678826789267902679126792267932679426795267962679726798267992680026801268022680326804268052680626807268082680926810268112681226813268142681526816268172681826819268202682126822268232682426825268262682726828268292683026831268322683326834268352683626837268382683926840268412684226843268442684526846268472684826849268502685126852268532685426855268562685726858268592686026861268622686326864268652686626867268682686926870268712687226873268742687526876268772687826879268802688126882268832688426885268862688726888268892689026891268922689326894268952689626897268982689926900269012690226903269042690526906269072690826909269102691126912269132691426915269162691726918269192692026921269222692326924269252692626927269282692926930269312693226933269342693526936269372693826939269402694126942269432694426945269462694726948269492695026951269522695326954269552695626957269582695926960269612696226963269642696526966269672696826969269702697126972269732697426975269762697726978269792698026981269822698326984269852698626987269882698926990269912699226993269942699526996269972699826999270002700127002270032700427005270062700727008270092701027011270122701327014270152701627017270182701927020270212702227023270242702527026270272702827029270302703127032270332703427035270362703727038270392704027041270422704327044270452704627047270482704927050270512705227053270542705527056270572705827059270602706127062270632706427065270662706727068270692707027071270722707327074270752707627077270782707927080270812708227083270842708527086270872708827089270902709127092270932709427095270962709727098270992710027101271022710327104271052710627107271082710927110271112711227113271142711527116271172711827119271202712127122271232712427125271262712727128271292713027131271322713327134271352713627137271382713927140271412714227143271442714527146271472714827149271502715127152271532715427155271562715727158271592716027161271622716327164271652716627167271682716927170271712717227173271742717527176271772717827179271802718127182271832718427185271862718727188271892719027191271922719327194271952719627197271982719927200272012720227203272042720527206272072720827209272102721127212272132721427215272162721727218272192722027221272222722327224272252722627227272282722927230272312723227233272342723527236272372723827239272402724127242272432724427245272462724727248272492725027251272522725327254272552725627257272582725927260272612726227263272642726527266272672726827269272702727127272272732727427275272762727727278272792728027281272822728327284272852728627287272882728927290272912729227293272942729527296272972729827299273002730127302273032730427305273062730727308273092731027311273122731327314273152731627317273182731927320273212732227323273242732527326273272732827329273302733127332273332733427335273362733727338273392734027341273422734327344273452734627347273482734927350273512735227353273542735527356273572735827359273602736127362273632736427365273662736727368273692737027371273722737327374273752737627377273782737927380273812738227383273842738527386273872738827389273902739127392273932739427395273962739727398273992740027401274022740327404274052740627407274082740927410274112741227413274142741527416274172741827419274202742127422274232742427425274262742727428274292743027431274322743327434274352743627437274382743927440274412744227443274442744527446274472744827449274502745127452274532745427455274562745727458274592746027461274622746327464
  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. this.settings = require("./modules/settings/Settings");
  18. }
  19. };
  20. function init() {
  21. APP.RTC.start();
  22. APP.xmpp.start();
  23. APP.statistics.start();
  24. APP.connectionquality.init();
  25. // Set default desktop sharing method
  26. APP.desktopsharing.init();
  27. APP.keyboardshortcut.init();
  28. }
  29. $(document).ready(function () {
  30. APP.init();
  31. APP.translation.init();
  32. if(APP.API.isEnabled())
  33. APP.API.init();
  34. APP.UI.start(init);
  35. });
  36. $(window).bind('beforeunload', function () {
  37. if(APP.API.isEnabled())
  38. APP.API.dispose();
  39. });
  40. module.exports = APP;
  41. },{"./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/settings/Settings":38,"./modules/simulcast/simulcast":43,"./modules/statistics/statistics":46,"./modules/translation/translation":47,"./modules/xmpp/xmpp":61}],2:[function(require,module,exports){
  42. /**
  43. * Implements API class that communicates with external api class
  44. * and provides interface to access Jitsi Meet features by external
  45. * applications that embed Jitsi Meet
  46. */
  47. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  48. /**
  49. * List of the available commands.
  50. * @type {{
  51. * displayName: inputDisplayNameHandler,
  52. * muteAudio: toggleAudio,
  53. * muteVideo: toggleVideo,
  54. * filmStrip: toggleFilmStrip
  55. * }}
  56. */
  57. var commands =
  58. {
  59. displayName: APP.UI.inputDisplayNameHandler,
  60. muteAudio: APP.UI.toggleAudio,
  61. muteVideo: APP.UI.toggleVideo,
  62. toggleFilmStrip: APP.UI.toggleFilmStrip,
  63. toggleChat: APP.UI.toggleChat,
  64. toggleContactList: APP.UI.toggleContactList
  65. };
  66. /**
  67. * Maps the supported events and their status
  68. * (true it the event is enabled and false if it is disabled)
  69. * @type {{
  70. * incomingMessage: boolean,
  71. * outgoingMessage: boolean,
  72. * displayNameChange: boolean,
  73. * participantJoined: boolean,
  74. * participantLeft: boolean
  75. * }}
  76. */
  77. var events =
  78. {
  79. incomingMessage: false,
  80. outgoingMessage:false,
  81. displayNameChange: false,
  82. participantJoined: false,
  83. participantLeft: false
  84. };
  85. var displayName = {};
  86. /**
  87. * Processes commands from external applicaiton.
  88. * @param message the object with the command
  89. */
  90. function processCommand(message)
  91. {
  92. if(message.action != "execute")
  93. {
  94. console.error("Unknown action of the message");
  95. return;
  96. }
  97. for(var key in message)
  98. {
  99. if(commands[key])
  100. commands[key].apply(null, message[key]);
  101. }
  102. }
  103. /**
  104. * Processes events objects from external applications
  105. * @param event the event
  106. */
  107. function processEvent(event) {
  108. if(!event.action)
  109. {
  110. console.error("Event with no action is received.");
  111. return;
  112. }
  113. var i = 0;
  114. switch(event.action)
  115. {
  116. case "add":
  117. for(; i < event.events.length; i++)
  118. {
  119. events[event.events[i]] = true;
  120. }
  121. break;
  122. case "remove":
  123. for(; i < event.events.length; i++)
  124. {
  125. events[event.events[i]] = false;
  126. }
  127. break;
  128. default:
  129. console.error("Unknown action for event.");
  130. }
  131. }
  132. /**
  133. * Sends message to the external application.
  134. * @param object
  135. */
  136. function sendMessage(object) {
  137. window.parent.postMessage(JSON.stringify(object), "*");
  138. }
  139. /**
  140. * Processes a message event from the external application
  141. * @param event the message event
  142. */
  143. function processMessage(event)
  144. {
  145. var message;
  146. try {
  147. message = JSON.parse(event.data);
  148. } catch (e) {}
  149. if(!message.type)
  150. return;
  151. switch (message.type)
  152. {
  153. case "command":
  154. processCommand(message);
  155. break;
  156. case "event":
  157. processEvent(message);
  158. break;
  159. default:
  160. console.error("Unknown type of the message");
  161. return;
  162. }
  163. }
  164. function setupListeners() {
  165. APP.xmpp.addListener(XMPPEvents.MUC_ENTER, function (from) {
  166. API.triggerEvent("participantJoined", {jid: from});
  167. });
  168. APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, function (from, nick, txt, myjid) {
  169. if (from != myjid)
  170. API.triggerEvent("incomingMessage",
  171. {"from": from, "nick": nick, "message": txt});
  172. });
  173. APP.xmpp.addListener(XMPPEvents.MUC_LEFT, function (jid) {
  174. API.triggerEvent("participantLeft", {jid: jid});
  175. });
  176. APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, function (jid, newDisplayName) {
  177. name = displayName[jid];
  178. if(!name || name != newDisplayName) {
  179. API.triggerEvent("displayNameChange", {jid: jid, displayname: newDisplayName});
  180. displayName[jid] = newDisplayName;
  181. }
  182. });
  183. APP.xmpp.addListener(XMPPEvents.SENDING_CHAT_MESSAGE, function (body) {
  184. APP.API.triggerEvent("outgoingMessage", {"message": body});
  185. });
  186. }
  187. var API = {
  188. /**
  189. * Check whether the API should be enabled or not.
  190. * @returns {boolean}
  191. */
  192. isEnabled: function () {
  193. var hash = location.hash;
  194. if(hash && hash.indexOf("external") > -1 && window.postMessage)
  195. return true;
  196. return false;
  197. },
  198. /**
  199. * Initializes the APIConnector. Setups message event listeners that will
  200. * receive information from external applications that embed Jitsi Meet.
  201. * It also sends a message to the external application that APIConnector
  202. * is initialized.
  203. */
  204. init: function () {
  205. if (window.addEventListener)
  206. {
  207. window.addEventListener('message',
  208. processMessage, false);
  209. }
  210. else
  211. {
  212. window.attachEvent('onmessage', processMessage);
  213. }
  214. sendMessage({type: "system", loaded: true});
  215. setupListeners();
  216. },
  217. /**
  218. * Checks whether the event is enabled ot not.
  219. * @param name the name of the event.
  220. * @returns {*}
  221. */
  222. isEventEnabled: function (name) {
  223. return events[name];
  224. },
  225. /**
  226. * Sends event object to the external application that has been subscribed
  227. * for that event.
  228. * @param name the name event
  229. * @param object data associated with the event
  230. */
  231. triggerEvent: function (name, object) {
  232. if(this.isEnabled() && this.isEventEnabled(name))
  233. sendMessage({
  234. type: "event", action: "result", event: name, result: object});
  235. },
  236. /**
  237. * Removes the listeners.
  238. */
  239. dispose: function () {
  240. if(window.removeEventListener)
  241. {
  242. window.removeEventListener("message",
  243. processMessage, false);
  244. }
  245. else
  246. {
  247. window.detachEvent('onmessage', processMessage);
  248. }
  249. }
  250. };
  251. module.exports = API;
  252. },{"../../service/xmpp/XMPPEvents":97}],3:[function(require,module,exports){
  253. /* global Strophe, focusedVideoSrc*/
  254. // cache datachannels to avoid garbage collection
  255. // https://code.google.com/p/chromium/issues/detail?id=405545
  256. var RTCEvents = require("../../service/RTC/RTCEvents");
  257. var _dataChannels = [];
  258. var eventEmitter = null;
  259. var DataChannels =
  260. {
  261. /**
  262. * Callback triggered by PeerConnection when new data channel is opened
  263. * on the bridge.
  264. * @param event the event info object.
  265. */
  266. onDataChannel: function (event)
  267. {
  268. var dataChannel = event.channel;
  269. dataChannel.onopen = function () {
  270. console.info("Data channel opened by the Videobridge!", dataChannel);
  271. // Code sample for sending string and/or binary data
  272. // Sends String message to the bridge
  273. //dataChannel.send("Hello bridge!");
  274. // Sends 12 bytes binary message to the bridge
  275. //dataChannel.send(new ArrayBuffer(12));
  276. // when the data channel becomes available, tell the bridge about video
  277. // selections so that it can do adaptive simulcast,
  278. // we want the notification to trigger even if userJid is undefined,
  279. // or null.
  280. var userJid = APP.UI.getLargeVideoState().userResourceJid;
  281. // we want the notification to trigger even if userJid is undefined,
  282. // or null.
  283. onSelectedEndpointChanged(userJid);
  284. };
  285. dataChannel.onerror = function (error) {
  286. console.error("Data Channel Error:", error, dataChannel);
  287. };
  288. dataChannel.onmessage = function (event) {
  289. var data = event.data;
  290. // JSON
  291. var obj;
  292. try {
  293. obj = JSON.parse(data);
  294. }
  295. catch (e) {
  296. console.error(
  297. "Failed to parse data channel message as JSON: ",
  298. data,
  299. dataChannel);
  300. }
  301. if (('undefined' !== typeof(obj)) && (null !== obj)) {
  302. var colibriClass = obj.colibriClass;
  303. if ("DominantSpeakerEndpointChangeEvent" === colibriClass) {
  304. // Endpoint ID from the Videobridge.
  305. var dominantSpeakerEndpoint = obj.dominantSpeakerEndpoint;
  306. console.info(
  307. "Data channel new dominant speaker event: ",
  308. dominantSpeakerEndpoint);
  309. eventEmitter.emit(RTCEvents.DOMINANTSPEAKER_CHANGED, dominantSpeakerEndpoint);
  310. }
  311. else if ("InLastNChangeEvent" === colibriClass)
  312. {
  313. var oldValue = obj.oldValue;
  314. var newValue = obj.newValue;
  315. // Make sure that oldValue and newValue are of type boolean.
  316. var type;
  317. if ((type = typeof oldValue) !== 'boolean') {
  318. if (type === 'string') {
  319. oldValue = (oldValue == "true");
  320. } else {
  321. oldValue = new Boolean(oldValue).valueOf();
  322. }
  323. }
  324. if ((type = typeof newValue) !== 'boolean') {
  325. if (type === 'string') {
  326. newValue = (newValue == "true");
  327. } else {
  328. newValue = new Boolean(newValue).valueOf();
  329. }
  330. }
  331. eventEmitter.emit(RTCEvents.LASTN_CHANGED, oldValue, newValue);
  332. }
  333. else if ("LastNEndpointsChangeEvent" === colibriClass)
  334. {
  335. // The new/latest list of last-n endpoint IDs.
  336. var lastNEndpoints = obj.lastNEndpoints;
  337. // The list of endpoint IDs which are entering the list of
  338. // last-n at this time i.e. were not in the old list of last-n
  339. // endpoint IDs.
  340. var endpointsEnteringLastN = obj.endpointsEnteringLastN;
  341. var stream = obj.stream;
  342. console.log(
  343. "Data channel new last-n event: ",
  344. lastNEndpoints, endpointsEnteringLastN, obj);
  345. eventEmitter.emit(RTCEvents.LASTN_ENDPOINT_CHANGED,
  346. lastNEndpoints, endpointsEnteringLastN, obj);
  347. }
  348. else if ("SimulcastLayersChangedEvent" === colibriClass)
  349. {
  350. eventEmitter.emit(RTCEvents.SIMULCAST_LAYER_CHANGED,
  351. obj.endpointSimulcastLayers);
  352. }
  353. else if ("SimulcastLayersChangingEvent" === colibriClass)
  354. {
  355. eventEmitter.emit(RTCEvents.SIMULCAST_LAYER_CHANGING,
  356. obj.endpointSimulcastLayers);
  357. }
  358. else if ("StartSimulcastLayerEvent" === colibriClass)
  359. {
  360. eventEmitter.emit(RTCEvents.SIMULCAST_START, obj.simulcastLayer);
  361. }
  362. else if ("StopSimulcastLayerEvent" === colibriClass)
  363. {
  364. eventEmitter.emit(RTCEvents.SIMULCAST_STOP, obj.simulcastLayer);
  365. }
  366. else
  367. {
  368. console.debug("Data channel JSON-formatted message: ", obj);
  369. }
  370. }
  371. };
  372. dataChannel.onclose = function ()
  373. {
  374. console.info("The Data Channel closed", dataChannel);
  375. var idx = _dataChannels.indexOf(dataChannel);
  376. if (idx > -1)
  377. _dataChannels = _dataChannels.splice(idx, 1);
  378. };
  379. _dataChannels.push(dataChannel);
  380. },
  381. /**
  382. * Binds "ondatachannel" event listener to given PeerConnection instance.
  383. * @param peerConnection WebRTC peer connection instance.
  384. */
  385. init: function (peerConnection, emitter) {
  386. if(!config.openSctp)
  387. return;
  388. peerConnection.ondatachannel = this.onDataChannel;
  389. eventEmitter = emitter;
  390. // Sample code for opening new data channel from Jitsi Meet to the bridge.
  391. // Although it's not a requirement to open separate channels from both bridge
  392. // and peer as single channel can be used for sending and receiving data.
  393. // So either channel opened by the bridge or the one opened here is enough
  394. // for communication with the bridge.
  395. /*var dataChannelOptions =
  396. {
  397. reliable: true
  398. };
  399. var dataChannel
  400. = peerConnection.createDataChannel("myChannel", dataChannelOptions);
  401. // Can be used only when is in open state
  402. dataChannel.onopen = function ()
  403. {
  404. dataChannel.send("My channel !!!");
  405. };
  406. dataChannel.onmessage = function (event)
  407. {
  408. var msgData = event.data;
  409. console.info("Got My Data Channel Message:", msgData, dataChannel);
  410. };*/
  411. },
  412. handleSelectedEndpointEvent: onSelectedEndpointChanged,
  413. handlePinnedEndpointEvent: onPinnedEndpointChanged
  414. };
  415. function onSelectedEndpointChanged(userResource)
  416. {
  417. console.log('selected endpoint changed: ', userResource);
  418. if (_dataChannels && _dataChannels.length != 0)
  419. {
  420. _dataChannels.some(function (dataChannel) {
  421. if (dataChannel.readyState == 'open')
  422. {
  423. console.log('sending selected endpoint changed '
  424. + 'notification to the bridge: ', userResource);
  425. dataChannel.send(JSON.stringify({
  426. 'colibriClass': 'SelectedEndpointChangedEvent',
  427. 'selectedEndpoint':
  428. (!userResource || userResource === null)?
  429. null : userResource
  430. }));
  431. return true;
  432. }
  433. });
  434. }
  435. }
  436. function onPinnedEndpointChanged(userResource)
  437. {
  438. console.log('pinned endpoint changed: ', userResource);
  439. if (_dataChannels && _dataChannels.length != 0)
  440. {
  441. _dataChannels.some(function (dataChannel) {
  442. if (dataChannel.readyState == 'open')
  443. {
  444. dataChannel.send(JSON.stringify({
  445. 'colibriClass': 'PinnedEndpointChangedEvent',
  446. 'pinnedEndpoint':
  447. (!userResource || userResource == null)?
  448. null : userResource
  449. }));
  450. return true;
  451. }
  452. });
  453. }
  454. }
  455. module.exports = DataChannels;
  456. },{"../../service/RTC/RTCEvents":89}],4:[function(require,module,exports){
  457. var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
  458. function LocalStream(stream, type, eventEmitter, videoType)
  459. {
  460. this.stream = stream;
  461. this.eventEmitter = eventEmitter;
  462. this.type = type;
  463. this.videoType = videoType;
  464. var self = this;
  465. if(type == "audio")
  466. {
  467. this.getTracks = function () {
  468. return self.stream.getAudioTracks();
  469. };
  470. }
  471. else
  472. {
  473. this.getTracks = function () {
  474. return self.stream.getVideoTracks();
  475. };
  476. }
  477. this.stream.onended = function()
  478. {
  479. self.streamEnded();
  480. };
  481. }
  482. LocalStream.prototype.streamEnded = function () {
  483. this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, this);
  484. }
  485. LocalStream.prototype.getOriginalStream = function()
  486. {
  487. return this.stream;
  488. }
  489. LocalStream.prototype.isAudioStream = function () {
  490. return (this.stream.getAudioTracks() && this.stream.getAudioTracks().length > 0);
  491. };
  492. LocalStream.prototype.mute = function()
  493. {
  494. var ismuted = false;
  495. var tracks = this.getTracks();
  496. for (var idx = 0; idx < tracks.length; idx++) {
  497. ismuted = !tracks[idx].enabled;
  498. tracks[idx].enabled = ismuted;
  499. }
  500. return ismuted;
  501. };
  502. LocalStream.prototype.setMute = function(mute)
  503. {
  504. if(window.location.protocol != "https:" ||
  505. this.isAudioStream() || this.videoType === "screen")
  506. {
  507. var tracks = this.getTracks();
  508. for (var idx = 0; idx < tracks.length; idx++) {
  509. tracks[idx].enabled = mute;
  510. }
  511. }
  512. else
  513. {
  514. if(mute === false) {
  515. APP.xmpp.removeStream(this.stream);
  516. this.stream.stop();
  517. }
  518. else
  519. {
  520. APP.RTC.rtcUtils.obtainAudioAndVideoPermissions(["video"],
  521. function (stream) {
  522. APP.RTC.changeLocalVideo(stream, false, function () {});
  523. });
  524. }
  525. }
  526. };
  527. LocalStream.prototype.isMuted = function () {
  528. var tracks = [];
  529. if(this.type == "audio")
  530. {
  531. tracks = this.stream.getAudioTracks();
  532. }
  533. else
  534. {
  535. if(this.stream.ended)
  536. return true;
  537. tracks = this.stream.getVideoTracks();
  538. }
  539. for (var idx = 0; idx < tracks.length; idx++) {
  540. if(tracks[idx].enabled)
  541. return false;
  542. }
  543. return true;
  544. }
  545. LocalStream.prototype.getId = function () {
  546. return this.stream.getTracks()[0].id;
  547. }
  548. module.exports = LocalStream;
  549. },{"../../service/RTC/StreamEventTypes.js":91}],5:[function(require,module,exports){
  550. ////These lines should be uncommented when require works in app.js
  551. var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
  552. var StreamEventType = require("../../service/RTC/StreamEventTypes");
  553. /**
  554. * Creates a MediaStream object for the given data, session id and ssrc.
  555. * It is a wrapper class for the MediaStream.
  556. *
  557. * @param data the data object from which we obtain the stream,
  558. * the peerjid, etc.
  559. * @param sid the session id
  560. * @param ssrc the ssrc corresponding to this MediaStream
  561. *
  562. * @constructor
  563. */
  564. function MediaStream(data, sid, ssrc, browser, eventEmitter) {
  565. // XXX(gp) to minimize headaches in the future, we should build our
  566. // abstractions around tracks and not streams. ORTC is track based API.
  567. // Mozilla expects m-lines to represent media tracks.
  568. //
  569. // Practically, what I'm saying is that we should have a MediaTrack class
  570. // and not a MediaStream class.
  571. //
  572. // Also, we should be able to associate multiple SSRCs with a MediaTrack as
  573. // a track might have an associated RTX and FEC sources.
  574. this.sid = sid;
  575. this.stream = data.stream;
  576. this.peerjid = data.peerjid;
  577. this.ssrc = ssrc;
  578. this.type = (this.stream.getVideoTracks().length > 0)?
  579. MediaStreamType.VIDEO_TYPE : MediaStreamType.AUDIO_TYPE;
  580. this.videoType = null;
  581. this.muted = false;
  582. this.eventEmitter = eventEmitter;
  583. }
  584. MediaStream.prototype.getOriginalStream = function()
  585. {
  586. return this.stream;
  587. };
  588. MediaStream.prototype.setMute = function (value)
  589. {
  590. this.stream.muted = value;
  591. this.muted = value;
  592. };
  593. MediaStream.prototype.setVideoType = function (value) {
  594. if(this.videoType === value)
  595. return;
  596. this.videoType = value;
  597. this.eventEmitter.emit(StreamEventType.EVENT_TYPE_REMOTE_CHANGED,
  598. this.peerjid);
  599. };
  600. module.exports = MediaStream;
  601. },{"../../service/RTC/MediaStreamTypes":87,"../../service/RTC/StreamEventTypes":91}],6:[function(require,module,exports){
  602. var EventEmitter = require("events");
  603. var RTCUtils = require("./RTCUtils.js");
  604. var LocalStream = require("./LocalStream.js");
  605. var DataChannels = require("./DataChannels");
  606. var MediaStream = require("./MediaStream.js");
  607. var DesktopSharingEventTypes
  608. = require("../../service/desktopsharing/DesktopSharingEventTypes");
  609. var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
  610. var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
  611. var RTCEvents = require("../../service/RTC/RTCEvents.js");
  612. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  613. var UIEvents = require("../../service/UI/UIEvents");
  614. var eventEmitter = new EventEmitter();
  615. var RTC = {
  616. rtcUtils: null,
  617. devices: {
  618. audio: false,
  619. video: false
  620. },
  621. localStreams: [],
  622. remoteStreams: {},
  623. localAudio: null,
  624. localVideo: null,
  625. addStreamListener: function (listener, eventType) {
  626. eventEmitter.on(eventType, listener);
  627. },
  628. addListener: function (type, listener) {
  629. eventEmitter.on(type, listener);
  630. },
  631. removeStreamListener: function (listener, eventType) {
  632. if(!(eventType instanceof StreamEventTypes))
  633. throw "Illegal argument";
  634. eventEmitter.removeListener(eventType, listener);
  635. },
  636. createLocalStream: function (stream, type, change, videoType) {
  637. var localStream = new LocalStream(stream, type, eventEmitter, videoType);
  638. //in firefox we have only one stream object
  639. if(this.localStreams.length == 0 ||
  640. this.localStreams[0].getOriginalStream() != stream)
  641. this.localStreams.push(localStream);
  642. if(type == "audio")
  643. {
  644. this.localAudio = localStream;
  645. }
  646. else
  647. {
  648. this.localVideo = localStream;
  649. }
  650. var eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CREATED;
  651. if(change)
  652. eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED;
  653. eventEmitter.emit(eventType, localStream);
  654. return localStream;
  655. },
  656. removeLocalStream: function (stream) {
  657. for(var i = 0; i < this.localStreams.length; i++)
  658. {
  659. if(this.localStreams[i].getOriginalStream() === stream) {
  660. delete this.localStreams[i];
  661. return;
  662. }
  663. }
  664. },
  665. createRemoteStream: function (data, sid, thessrc) {
  666. var remoteStream = new MediaStream(data, sid, thessrc,
  667. this.getBrowserType(), eventEmitter);
  668. var jid = data.peerjid || APP.xmpp.myJid();
  669. if(!this.remoteStreams[jid]) {
  670. this.remoteStreams[jid] = {};
  671. }
  672. this.remoteStreams[jid][remoteStream.type]= remoteStream;
  673. eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, remoteStream);
  674. return remoteStream;
  675. },
  676. getBrowserType: function () {
  677. return this.rtcUtils.browser;
  678. },
  679. getPCConstraints: function () {
  680. return this.rtcUtils.pc_constraints;
  681. },
  682. getUserMediaWithConstraints:function(um, success_callback,
  683. failure_callback, resolution,
  684. bandwidth, fps, desktopStream)
  685. {
  686. return this.rtcUtils.getUserMediaWithConstraints(um, success_callback,
  687. failure_callback, resolution, bandwidth, fps, desktopStream);
  688. },
  689. attachMediaStream: function (element, stream) {
  690. this.rtcUtils.attachMediaStream(element, stream);
  691. },
  692. getStreamID: function (stream) {
  693. return this.rtcUtils.getStreamID(stream);
  694. },
  695. getVideoSrc: function (element) {
  696. return this.rtcUtils.getVideoSrc(element);
  697. },
  698. setVideoSrc: function (element, src) {
  699. this.rtcUtils.setVideoSrc(element, src);
  700. },
  701. dispose: function() {
  702. if (this.rtcUtils) {
  703. this.rtcUtils = null;
  704. }
  705. },
  706. stop: function () {
  707. this.dispose();
  708. },
  709. start: function () {
  710. var self = this;
  711. APP.desktopsharing.addListener(
  712. function (stream, isUsingScreenStream, callback) {
  713. self.changeLocalVideo(stream, isUsingScreenStream, callback);
  714. }, DesktopSharingEventTypes.NEW_STREAM_CREATED);
  715. APP.xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
  716. for(var i = 0; i < changedStreams.length; i++) {
  717. var type = changedStreams[i].type;
  718. if (type != "audio") {
  719. var peerStreams = self.remoteStreams[jid];
  720. if(!peerStreams)
  721. continue;
  722. var videoStream = peerStreams[MediaStreamType.VIDEO_TYPE];
  723. if(!videoStream)
  724. continue;
  725. videoStream.setVideoType(changedStreams[i].type);
  726. }
  727. }
  728. });
  729. APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function(event) {
  730. DataChannels.init(event.peerconnection, eventEmitter);
  731. });
  732. APP.UI.addListener(UIEvents.SELECTED_ENDPOINT,
  733. DataChannels.handleSelectedEndpointEvent);
  734. APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
  735. DataChannels.handlePinnedEndpointEvent);
  736. this.rtcUtils = new RTCUtils(this);
  737. this.rtcUtils.obtainAudioAndVideoPermissions();
  738. },
  739. muteRemoteVideoStream: function (jid, value) {
  740. var stream;
  741. if(this.remoteStreams[jid] &&
  742. this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE])
  743. {
  744. stream = this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  745. }
  746. if(!stream)
  747. return true;
  748. if (value != stream.muted) {
  749. stream.setMute(value);
  750. return true;
  751. }
  752. return false;
  753. },
  754. switchVideoStreams: function (new_stream) {
  755. this.localVideo.stream = new_stream;
  756. this.localStreams = [];
  757. //in firefox we have only one stream object
  758. if (this.localAudio.getOriginalStream() != new_stream)
  759. this.localStreams.push(this.localAudio);
  760. this.localStreams.push(this.localVideo);
  761. },
  762. changeLocalVideo: function (stream, isUsingScreenStream, callback) {
  763. var oldStream = this.localVideo.getOriginalStream();
  764. var type = (isUsingScreenStream? "screen" : "video");
  765. var localCallback = callback;
  766. if(this.localVideo.isMuted() && this.localVideo.videoType !== type)
  767. {
  768. localCallback = function() {
  769. APP.xmpp.setVideoMute(false, APP.UI.setVideoMuteButtonsState);
  770. callback();
  771. };
  772. }
  773. var videoStream = this.rtcUtils.createVideoStream(stream);
  774. this.localVideo = this.createLocalStream(videoStream, "video", true, type);
  775. // Stop the stream to trigger onended event for old stream
  776. oldStream.stop();
  777. APP.xmpp.switchStreams(videoStream, oldStream,localCallback);
  778. },
  779. /**
  780. * Checks if video identified by given src is desktop stream.
  781. * @param videoSrc eg.
  782. * blob:https%3A//pawel.jitsi.net/9a46e0bd-131e-4d18-9c14-a9264e8db395
  783. * @returns {boolean}
  784. */
  785. isVideoSrcDesktop: function (jid) {
  786. if(!jid)
  787. return false;
  788. var isDesktop = false;
  789. var stream = null;
  790. if (APP.xmpp.myJid() === jid) {
  791. // local video
  792. stream = this.localVideo;
  793. } else {
  794. var peerStreams = this.remoteStreams[jid];
  795. if(!peerStreams)
  796. return false;
  797. stream = peerStreams[MediaStreamType.VIDEO_TYPE];
  798. }
  799. if(stream)
  800. isDesktop = (stream.videoType === "screen");
  801. return isDesktop;
  802. },
  803. setVideoMute: function(mute, callback, options) {
  804. if(!this.localVideo)
  805. return;
  806. if (mute == APP.RTC.localVideo.isMuted())
  807. {
  808. APP.xmpp.sendVideoInfoPresence(mute);
  809. if(callback)
  810. callback();
  811. }
  812. else
  813. {
  814. APP.RTC.localVideo.setMute(!mute);
  815. APP.xmpp.setVideoMute(
  816. mute,
  817. callback,
  818. options);
  819. }
  820. },
  821. setDeviceAvailability: function (devices) {
  822. if(!devices)
  823. return;
  824. if(devices.audio === true || devices.audio === false)
  825. this.devices.audio = devices.audio;
  826. if(devices.video === true || devices.video === false)
  827. this.devices.video = devices.video;
  828. eventEmitter.emit(RTCEvents.AVAILABLE_DEVICES_CHANGED, this.devices);
  829. }
  830. };
  831. module.exports = RTC;
  832. },{"../../service/RTC/MediaStreamTypes":87,"../../service/RTC/RTCEvents.js":89,"../../service/RTC/StreamEventTypes.js":91,"../../service/UI/UIEvents":92,"../../service/desktopsharing/DesktopSharingEventTypes":95,"../../service/xmpp/XMPPEvents":97,"./DataChannels":3,"./LocalStream.js":4,"./MediaStream.js":5,"./RTCUtils.js":7,"events":98}],7:[function(require,module,exports){
  833. var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
  834. var Resolutions = require("../../service/RTC/Resolutions");
  835. var currentResolution = null;
  836. function getPreviousResolution(resolution) {
  837. if(!Resolutions[resolution])
  838. return null;
  839. var order = Resolutions[resolution].order;
  840. var res = null;
  841. var resName = null;
  842. for(var i in Resolutions)
  843. {
  844. var tmp = Resolutions[i];
  845. if(res == null || (res.order < tmp.order && tmp.order < order))
  846. {
  847. resName = i;
  848. res = tmp;
  849. }
  850. }
  851. return resName;
  852. }
  853. function setResolutionConstraints(constraints, resolution, isAndroid)
  854. {
  855. if (resolution && !constraints.video || isAndroid) {
  856. constraints.video = { mandatory: {}, optional: [] };// same behaviour as true
  857. }
  858. if(Resolutions[resolution])
  859. {
  860. constraints.video.mandatory.minWidth = Resolutions[resolution].width;
  861. constraints.video.mandatory.minHeight = Resolutions[resolution].height;
  862. }
  863. else
  864. {
  865. if (isAndroid) {
  866. constraints.video.mandatory.minWidth = 320;
  867. constraints.video.mandatory.minHeight = 240;
  868. constraints.video.mandatory.maxFrameRate = 15;
  869. }
  870. }
  871. if (constraints.video.mandatory.minWidth)
  872. constraints.video.mandatory.maxWidth = constraints.video.mandatory.minWidth;
  873. if (constraints.video.mandatory.minHeight)
  874. constraints.video.mandatory.maxHeight = constraints.video.mandatory.minHeight;
  875. }
  876. function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid)
  877. {
  878. var constraints = {audio: false, video: false};
  879. if (um.indexOf('video') >= 0) {
  880. constraints.video = { mandatory: {}, optional: [] };// same behaviour as true
  881. }
  882. if (um.indexOf('audio') >= 0) {
  883. constraints.audio = { mandatory: {}, optional: []};// same behaviour as true
  884. }
  885. if (um.indexOf('screen') >= 0) {
  886. constraints.video = {
  887. mandatory: {
  888. chromeMediaSource: "screen",
  889. googLeakyBucket: true,
  890. maxWidth: window.screen.width,
  891. maxHeight: window.screen.height,
  892. maxFrameRate: 3
  893. },
  894. optional: []
  895. };
  896. }
  897. if (um.indexOf('desktop') >= 0) {
  898. constraints.video = {
  899. mandatory: {
  900. chromeMediaSource: "desktop",
  901. chromeMediaSourceId: desktopStream,
  902. googLeakyBucket: true,
  903. maxWidth: window.screen.width,
  904. maxHeight: window.screen.height,
  905. maxFrameRate: 3
  906. },
  907. optional: []
  908. };
  909. }
  910. if (constraints.audio) {
  911. // if it is good enough for hangouts...
  912. constraints.audio.optional.push(
  913. {googEchoCancellation: true},
  914. {googAutoGainControl: true},
  915. {googNoiseSupression: true},
  916. {googHighpassFilter: true},
  917. {googNoisesuppression2: true},
  918. {googEchoCancellation2: true},
  919. {googAutoGainControl2: true}
  920. );
  921. }
  922. if (constraints.video) {
  923. constraints.video.optional.push(
  924. {googNoiseReduction: false} // chrome 37 workaround for issue 3807, reenable in M38
  925. );
  926. if (um.indexOf('video') >= 0) {
  927. constraints.video.optional.push(
  928. {googLeakyBucket: true}
  929. );
  930. }
  931. }
  932. if (um.indexOf('video') >= 0) {
  933. setResolutionConstraints(constraints, resolution, isAndroid);
  934. }
  935. if (bandwidth) { // doesn't work currently, see webrtc issue 1846
  936. if (!constraints.video) constraints.video = {mandatory: {}, optional: []};//same behaviour as true
  937. constraints.video.optional.push({bandwidth: bandwidth});
  938. }
  939. if (fps) { // for some cameras it might be necessary to request 30fps
  940. // so they choose 30fps mjpg over 10fps yuy2
  941. if (!constraints.video) constraints.video = {mandatory: {}, optional: []};// same behaviour as true;
  942. constraints.video.mandatory.minFrameRate = fps;
  943. }
  944. return constraints;
  945. }
  946. function RTCUtils(RTCService)
  947. {
  948. this.service = RTCService;
  949. if (navigator.mozGetUserMedia) {
  950. console.log('This appears to be Firefox');
  951. var version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
  952. if (version >= 39) {
  953. this.peerconnection = mozRTCPeerConnection;
  954. this.browser = RTCBrowserType.RTC_BROWSER_FIREFOX;
  955. this.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
  956. this.pc_constraints = {};
  957. this.attachMediaStream = function (element, stream) {
  958. // srcObject is being standardized and FF will eventually
  959. // support that unprefixed. FF also supports the
  960. // "element.src = URL.createObjectURL(...)" combo, but that
  961. // will be deprecated in favour of srcObject.
  962. //
  963. // https://groups.google.com/forum/#!topic/mozilla.dev.media/pKOiioXonJg
  964. // https://github.com/webrtc/samples/issues/302
  965. element[0].mozSrcObject = stream;
  966. element[0].play();
  967. };
  968. this.getStreamID = function (stream) {
  969. var tracks = stream.getVideoTracks();
  970. if(!tracks || tracks.length == 0)
  971. {
  972. tracks = stream.getAudioTracks();
  973. }
  974. return tracks[0].id.replace(/[\{,\}]/g,"");
  975. };
  976. this.getVideoSrc = function (element) {
  977. return element.mozSrcObject;
  978. };
  979. this.setVideoSrc = function (element, src) {
  980. element.mozSrcObject = src;
  981. };
  982. RTCSessionDescription = mozRTCSessionDescription;
  983. RTCIceCandidate = mozRTCIceCandidate;
  984. } else {
  985. window.location.href = 'unsupported_browser.html';
  986. return;
  987. }
  988. } else if (navigator.webkitGetUserMedia) {
  989. console.log('This appears to be Chrome');
  990. this.peerconnection = webkitRTCPeerConnection;
  991. this.browser = RTCBrowserType.RTC_BROWSER_CHROME;
  992. this.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
  993. this.attachMediaStream = function (element, stream) {
  994. element.attr('src', webkitURL.createObjectURL(stream));
  995. };
  996. this.getStreamID = function (stream) {
  997. // streams from FF endpoints have the characters '{' and '}'
  998. // that make jQuery choke.
  999. return stream.id.replace(/[\{,\}]/g,"");
  1000. };
  1001. this.getVideoSrc = function (element) {
  1002. return element.getAttribute("src");
  1003. };
  1004. this.setVideoSrc = function (element, src) {
  1005. element.setAttribute("src", src);
  1006. };
  1007. // DTLS should now be enabled by default but..
  1008. this.pc_constraints = {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]};
  1009. if (navigator.userAgent.indexOf('Android') != -1) {
  1010. this.pc_constraints = {}; // disable DTLS on Android
  1011. }
  1012. if (!webkitMediaStream.prototype.getVideoTracks) {
  1013. webkitMediaStream.prototype.getVideoTracks = function () {
  1014. return this.videoTracks;
  1015. };
  1016. }
  1017. if (!webkitMediaStream.prototype.getAudioTracks) {
  1018. webkitMediaStream.prototype.getAudioTracks = function () {
  1019. return this.audioTracks;
  1020. };
  1021. }
  1022. }
  1023. else
  1024. {
  1025. try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }
  1026. window.location.href = 'unsupported_browser.html';
  1027. return;
  1028. }
  1029. }
  1030. RTCUtils.prototype.getUserMediaWithConstraints = function(
  1031. um, success_callback, failure_callback, resolution,bandwidth, fps,
  1032. desktopStream)
  1033. {
  1034. currentResolution = resolution;
  1035. // Check if we are running on Android device
  1036. var isAndroid = navigator.userAgent.indexOf('Android') != -1;
  1037. var constraints = getConstraints(
  1038. um, resolution, bandwidth, fps, desktopStream, isAndroid);
  1039. var isFF = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
  1040. var self = this;
  1041. try {
  1042. if (config.enableSimulcast
  1043. && constraints.video
  1044. && constraints.video.chromeMediaSource !== 'screen'
  1045. && constraints.video.chromeMediaSource !== 'desktop'
  1046. && !isAndroid
  1047. // We currently do not support FF, as it doesn't have multistream support.
  1048. && !isFF) {
  1049. APP.simulcast.getUserMedia(constraints, function (stream) {
  1050. console.log('onUserMediaSuccess');
  1051. self.setAvailableDevices(um, true);
  1052. success_callback(stream);
  1053. },
  1054. function (error) {
  1055. console.warn('Failed to get access to local media. Error ', error);
  1056. self.setAvailableDevices(um, false);
  1057. if (failure_callback) {
  1058. failure_callback(error);
  1059. }
  1060. });
  1061. } else {
  1062. this.getUserMedia(constraints,
  1063. function (stream) {
  1064. console.log('onUserMediaSuccess');
  1065. self.setAvailableDevices(um, true);
  1066. success_callback(stream);
  1067. },
  1068. function (error) {
  1069. self.setAvailableDevices(um, false);
  1070. console.warn('Failed to get access to local media. Error ',
  1071. error, constraints);
  1072. if (failure_callback) {
  1073. failure_callback(error);
  1074. }
  1075. });
  1076. }
  1077. } catch (e) {
  1078. console.error('GUM failed: ', e);
  1079. if(failure_callback) {
  1080. failure_callback(e);
  1081. }
  1082. }
  1083. };
  1084. RTCUtils.prototype.setAvailableDevices = function (um, available) {
  1085. var devices = {};
  1086. if(um.indexOf("video") != -1)
  1087. {
  1088. devices.video = available;
  1089. }
  1090. if(um.indexOf("audio") != -1)
  1091. {
  1092. devices.audio = available;
  1093. }
  1094. this.service.setDeviceAvailability(devices);
  1095. }
  1096. /**
  1097. * We ask for audio and video combined stream in order to get permissions and
  1098. * not to ask twice.
  1099. */
  1100. RTCUtils.prototype.obtainAudioAndVideoPermissions = function(devices, callback) {
  1101. var self = this;
  1102. // Get AV
  1103. if(!devices)
  1104. devices = ['audio', 'video'];
  1105. this.getUserMediaWithConstraints(
  1106. devices,
  1107. function (stream) {
  1108. if(callback)
  1109. callback(stream);
  1110. else
  1111. self.successCallback(stream);
  1112. },
  1113. function (error) {
  1114. self.errorCallback(error);
  1115. },
  1116. config.resolution || '360');
  1117. }
  1118. RTCUtils.prototype.successCallback = function (stream) {
  1119. if(stream)
  1120. console.log('got', stream, stream.getAudioTracks().length,
  1121. stream.getVideoTracks().length);
  1122. this.handleLocalStream(stream);
  1123. };
  1124. RTCUtils.prototype.errorCallback = function (error) {
  1125. var self = this;
  1126. console.error('failed to obtain audio/video stream - trying audio only', error);
  1127. var resolution = getPreviousResolution(currentResolution);
  1128. if(typeof error == "object" && error.constraintName && error.name
  1129. && (error.name == "ConstraintNotSatisfiedError" ||
  1130. error.name == "OverconstrainedError") &&
  1131. (error.constraintName == "minWidth" || error.constraintName == "maxWidth" ||
  1132. error.constraintName == "minHeight" || error.constraintName == "maxHeight")
  1133. && resolution != null)
  1134. {
  1135. self.getUserMediaWithConstraints(['audio', 'video'],
  1136. function (stream) {
  1137. return self.successCallback(stream);
  1138. }, function (error) {
  1139. return self.errorCallback(error);
  1140. }, resolution);
  1141. }
  1142. else
  1143. {
  1144. self.getUserMediaWithConstraints(
  1145. ['audio'],
  1146. function (stream) {
  1147. return self.successCallback(stream);
  1148. },
  1149. function (error) {
  1150. console.error('failed to obtain audio/video stream - stop',
  1151. error);
  1152. return self.successCallback(null);
  1153. }
  1154. );
  1155. }
  1156. }
  1157. RTCUtils.prototype.handleLocalStream = function(stream)
  1158. {
  1159. if(window.webkitMediaStream)
  1160. {
  1161. var audioStream = new webkitMediaStream();
  1162. var videoStream = new webkitMediaStream();
  1163. if(stream) {
  1164. var audioTracks = stream.getAudioTracks();
  1165. for (var i = 0; i < audioTracks.length; i++) {
  1166. audioStream.addTrack(audioTracks[i]);
  1167. }
  1168. var videoTracks = stream.getVideoTracks();
  1169. for (i = 0; i < videoTracks.length; i++) {
  1170. videoStream.addTrack(videoTracks[i]);
  1171. }
  1172. }
  1173. this.service.createLocalStream(audioStream, "audio");
  1174. this.service.createLocalStream(videoStream, "video");
  1175. }
  1176. else
  1177. {//firefox
  1178. this.service.createLocalStream(stream, "stream");
  1179. }
  1180. };
  1181. RTCUtils.prototype.createVideoStream = function(stream)
  1182. {
  1183. var videoStream = null;
  1184. if(window.webkitMediaStream)
  1185. {
  1186. videoStream = new webkitMediaStream();
  1187. if(stream)
  1188. {
  1189. var videoTracks = stream.getVideoTracks();
  1190. for (i = 0; i < videoTracks.length; i++) {
  1191. videoStream.addTrack(videoTracks[i]);
  1192. }
  1193. }
  1194. }
  1195. else
  1196. videoStream = stream;
  1197. return videoStream;
  1198. };
  1199. module.exports = RTCUtils;
  1200. },{"../../service/RTC/RTCBrowserType.js":88,"../../service/RTC/Resolutions":90}],8:[function(require,module,exports){
  1201. var UI = {};
  1202. var VideoLayout = require("./videolayout/VideoLayout.js");
  1203. var AudioLevels = require("./audio_levels/AudioLevels.js");
  1204. var Prezi = require("./prezi/Prezi.js");
  1205. var Etherpad = require("./etherpad/Etherpad.js");
  1206. var Chat = require("./side_pannels/chat/Chat.js");
  1207. var Toolbar = require("./toolbars/Toolbar");
  1208. var ToolbarToggler = require("./toolbars/ToolbarToggler");
  1209. var BottomToolbar = require("./toolbars/BottomToolbar");
  1210. var ContactList = require("./side_pannels/contactlist/ContactList");
  1211. var Avatar = require("./avatar/Avatar");
  1212. var EventEmitter = require("events");
  1213. var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
  1214. var Settings = require("./../settings/Settings");
  1215. var PanelToggler = require("./side_pannels/SidePanelToggler");
  1216. var RoomNameGenerator = require("./welcome_page/RoomnameGenerator");
  1217. UI.messageHandler = require("./util/MessageHandler");
  1218. var messageHandler = UI.messageHandler;
  1219. var Authentication = require("./authentication/Authentication");
  1220. var UIUtil = require("./util/UIUtil");
  1221. var NicknameHandler = require("./util/NicknameHandler");
  1222. var CQEvents = require("../../service/connectionquality/CQEvents");
  1223. var DesktopSharingEventTypes
  1224. = require("../../service/desktopsharing/DesktopSharingEventTypes");
  1225. var RTCEvents = require("../../service/RTC/RTCEvents");
  1226. var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
  1227. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  1228. var eventEmitter = new EventEmitter();
  1229. var roomName = null;
  1230. function setupPrezi()
  1231. {
  1232. $("#reloadPresentationLink").click(function()
  1233. {
  1234. Prezi.reloadPresentation();
  1235. });
  1236. }
  1237. function setupChat()
  1238. {
  1239. Chat.init();
  1240. $("#toggle_smileys").click(function() {
  1241. Chat.toggleSmileys();
  1242. });
  1243. }
  1244. function setupToolbars() {
  1245. Toolbar.init(UI);
  1246. Toolbar.setupButtonsFromConfig();
  1247. BottomToolbar.init();
  1248. }
  1249. function streamHandler(stream) {
  1250. switch (stream.type)
  1251. {
  1252. case "audio":
  1253. VideoLayout.changeLocalAudio(stream);
  1254. break;
  1255. case "video":
  1256. VideoLayout.changeLocalVideo(stream);
  1257. break;
  1258. case "stream":
  1259. VideoLayout.changeLocalStream(stream);
  1260. break;
  1261. }
  1262. }
  1263. function onDisposeConference(unload) {
  1264. Toolbar.showAuthenticateButton(false);
  1265. };
  1266. function onDisplayNameChanged(jid, displayName) {
  1267. ContactList.onDisplayNameChange(jid, displayName);
  1268. SettingsMenu.onDisplayNameChange(jid, displayName);
  1269. VideoLayout.onDisplayNameChanged(jid, displayName);
  1270. }
  1271. function registerListeners() {
  1272. APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  1273. APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED);
  1274. APP.RTC.addStreamListener(function (stream) {
  1275. VideoLayout.onRemoteStreamAdded(stream);
  1276. }, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED);
  1277. APP.RTC.addStreamListener(function (jid) {
  1278. VideoLayout.onVideoTypeChanged(jid);
  1279. }, StreamEventTypes.EVENT_TYPE_REMOTE_CHANGED);
  1280. APP.RTC.addListener(RTCEvents.LASTN_CHANGED, onLastNChanged);
  1281. APP.RTC.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (resourceJid) {
  1282. VideoLayout.onDominantSpeakerChanged(resourceJid);
  1283. });
  1284. APP.RTC.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED,
  1285. function (lastNEndpoints, endpointsEnteringLastN, stream) {
  1286. VideoLayout.onLastNEndpointsChanged(lastNEndpoints,
  1287. endpointsEnteringLastN, stream);
  1288. });
  1289. APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGED,
  1290. function (endpointSimulcastLayers) {
  1291. VideoLayout.onSimulcastLayersChanged(endpointSimulcastLayers);
  1292. });
  1293. APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGING,
  1294. function (endpointSimulcastLayers) {
  1295. VideoLayout.onSimulcastLayersChanging(endpointSimulcastLayers);
  1296. });
  1297. APP.RTC.addListener(RTCEvents.AVAILABLE_DEVICES_CHANGED,
  1298. function (devices) {
  1299. VideoLayout.setDeviceAvailabilityIcons(null, devices);
  1300. })
  1301. APP.statistics.addAudioLevelListener(function(jid, audioLevel)
  1302. {
  1303. var resourceJid;
  1304. if(jid === APP.statistics.LOCAL_JID)
  1305. {
  1306. resourceJid = AudioLevels.LOCAL_LEVEL;
  1307. if(APP.RTC.localAudio.isMuted())
  1308. {
  1309. audioLevel = 0;
  1310. }
  1311. }
  1312. else
  1313. {
  1314. resourceJid = Strophe.getResourceFromJid(jid);
  1315. }
  1316. AudioLevels.updateAudioLevel(resourceJid, audioLevel,
  1317. UI.getLargeVideoState().userResourceJid);
  1318. });
  1319. APP.desktopsharing.addListener(function () {
  1320. ToolbarToggler.showDesktopSharingButton();
  1321. }, DesktopSharingEventTypes.INIT);
  1322. APP.desktopsharing.addListener(
  1323. Toolbar.changeDesktopSharingButtonState,
  1324. DesktopSharingEventTypes.SWITCHING_DONE);
  1325. APP.connectionquality.addListener(CQEvents.LOCALSTATS_UPDATED,
  1326. VideoLayout.updateLocalConnectionStats);
  1327. APP.connectionquality.addListener(CQEvents.REMOTESTATS_UPDATED,
  1328. VideoLayout.updateConnectionStats);
  1329. APP.connectionquality.addListener(CQEvents.STOP,
  1330. VideoLayout.onStatsStop);
  1331. APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
  1332. APP.xmpp.addListener(XMPPEvents.GRACEFUL_SHUTDOWN, function () {
  1333. messageHandler.openMessageDialog(
  1334. 'dialog.serviceUnavailable',
  1335. 'dialog.gracefulShutdown'
  1336. );
  1337. });
  1338. APP.xmpp.addListener(XMPPEvents.RESERVATION_ERROR, function (code, msg) {
  1339. var title = APP.translation.generateTranslatonHTML(
  1340. "dialog.reservationError");
  1341. var message = APP.translation.generateTranslatonHTML(
  1342. "dialog.reservationErrorMsg", {code: code, msg: msg});
  1343. messageHandler.openDialog(
  1344. title,
  1345. message,
  1346. true, {},
  1347. function (event, value, message, formVals)
  1348. {
  1349. return false;
  1350. }
  1351. );
  1352. });
  1353. APP.xmpp.addListener(XMPPEvents.KICKED, function () {
  1354. messageHandler.openMessageDialog("dialog.sessTerminated",
  1355. "dialog.kickMessage");
  1356. });
  1357. APP.xmpp.addListener(XMPPEvents.MUC_DESTROYED, function (reason) {
  1358. //FIXME: use Session Terminated from translation, but
  1359. // 'reason' text comes from XMPP packet and is not translated
  1360. var title = APP.translation.generateTranslatonHTML("dialog.sessTerminated");
  1361. messageHandler.openDialog(
  1362. title, reason, true, {},
  1363. function (event, value, message, formVals)
  1364. {
  1365. return false;
  1366. }
  1367. );
  1368. });
  1369. APP.xmpp.addListener(XMPPEvents.BRIDGE_DOWN, function () {
  1370. messageHandler.showError("dialog.error",
  1371. "dialog.bridgeUnavailable");
  1372. });
  1373. APP.xmpp.addListener(XMPPEvents.USER_ID_CHANGED, function (from, id) {
  1374. Avatar.setUserAvatar(from, id);
  1375. });
  1376. APP.xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
  1377. for(stream in changedStreams)
  1378. {
  1379. // might need to update the direction if participant just went from sendrecv to recvonly
  1380. if (stream.type === 'video' || stream.type === 'screen') {
  1381. var el = $('#participant_' + Strophe.getResourceFromJid(jid) + '>video');
  1382. switch (stream.direction) {
  1383. case 'sendrecv':
  1384. el.show();
  1385. break;
  1386. case 'recvonly':
  1387. el.hide();
  1388. // FIXME: Check if we have to change large video
  1389. //VideoLayout.updateLargeVideo(el);
  1390. break;
  1391. }
  1392. }
  1393. }
  1394. });
  1395. APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, onDisplayNameChanged);
  1396. APP.xmpp.addListener(XMPPEvents.MUC_JOINED, onMucJoined);
  1397. APP.xmpp.addListener(XMPPEvents.LOCALROLE_CHANGED, onLocalRoleChange);
  1398. APP.xmpp.addListener(XMPPEvents.MUC_ENTER, onMucEntered);
  1399. APP.xmpp.addListener(XMPPEvents.MUC_ROLE_CHANGED, onMucRoleChanged);
  1400. APP.xmpp.addListener(XMPPEvents.PRESENCE_STATUS, onMucPresenceStatus);
  1401. APP.xmpp.addListener(XMPPEvents.SUBJECT_CHANGED, chatSetSubject);
  1402. APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, updateChatConversation);
  1403. APP.xmpp.addListener(XMPPEvents.MUC_LEFT, onMucLeft);
  1404. APP.xmpp.addListener(XMPPEvents.PASSWORD_REQUIRED, onPasswordReqiured);
  1405. APP.xmpp.addListener(XMPPEvents.CHAT_ERROR_RECEIVED, chatAddError);
  1406. APP.xmpp.addListener(XMPPEvents.ETHERPAD, initEtherpad);
  1407. APP.xmpp.addListener(XMPPEvents.AUTHENTICATION_REQUIRED,
  1408. onAuthenticationRequired);
  1409. APP.xmpp.addListener(XMPPEvents.DEVICE_AVAILABLE,
  1410. function (resource, devices) {
  1411. VideoLayout.setDeviceAvailabilityIcons(resource, devices);
  1412. });
  1413. }
  1414. /**
  1415. * Mutes/unmutes the local video.
  1416. *
  1417. * @param mute <tt>true</tt> to mute the local video; otherwise, <tt>false</tt>
  1418. * @param options an object which specifies optional arguments such as the
  1419. * <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
  1420. * specifies whether the method was initiated in response to a user command (in
  1421. * contrast to an automatic decision taken by the application logic)
  1422. */
  1423. function setVideoMute(mute, options) {
  1424. APP.RTC.setVideoMute(mute,
  1425. UI.setVideoMuteButtonsState,
  1426. options);
  1427. }
  1428. function bindEvents()
  1429. {
  1430. /**
  1431. * Resizes and repositions videos in full screen mode.
  1432. */
  1433. $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
  1434. function () {
  1435. VideoLayout.resizeLargeVideoContainer();
  1436. VideoLayout.positionLarge();
  1437. }
  1438. );
  1439. $(window).resize(function () {
  1440. VideoLayout.resizeLargeVideoContainer();
  1441. VideoLayout.positionLarge();
  1442. });
  1443. }
  1444. UI.start = function (init) {
  1445. document.title = interfaceConfig.APP_NAME;
  1446. if(config.enableWelcomePage && window.location.pathname == "/" &&
  1447. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  1448. {
  1449. $("#videoconference_page").hide();
  1450. var setupWelcomePage = require("./welcome_page/WelcomePage");
  1451. setupWelcomePage();
  1452. return;
  1453. }
  1454. if (interfaceConfig.SHOW_JITSI_WATERMARK) {
  1455. var leftWatermarkDiv
  1456. = $("#largeVideoContainer div[class='watermark leftwatermark']");
  1457. leftWatermarkDiv.css({display: 'block'});
  1458. leftWatermarkDiv.parent().get(0).href
  1459. = interfaceConfig.JITSI_WATERMARK_LINK;
  1460. }
  1461. if (interfaceConfig.SHOW_BRAND_WATERMARK) {
  1462. var rightWatermarkDiv
  1463. = $("#largeVideoContainer div[class='watermark rightwatermark']");
  1464. rightWatermarkDiv.css({display: 'block'});
  1465. rightWatermarkDiv.parent().get(0).href
  1466. = interfaceConfig.BRAND_WATERMARK_LINK;
  1467. rightWatermarkDiv.get(0).style.backgroundImage
  1468. = "url(images/rightwatermark.png)";
  1469. }
  1470. if (interfaceConfig.SHOW_POWERED_BY) {
  1471. $("#largeVideoContainer>a[class='poweredby']").css({display: 'block'});
  1472. }
  1473. $("#welcome_page").hide();
  1474. VideoLayout.resizeLargeVideoContainer();
  1475. $("#videospace").mousemove(function () {
  1476. return ToolbarToggler.showToolbar();
  1477. });
  1478. // Set the defaults for prompt dialogs.
  1479. jQuery.prompt.setDefaults({persistent: false});
  1480. VideoLayout.init(eventEmitter);
  1481. AudioLevels.init();
  1482. NicknameHandler.init(eventEmitter);
  1483. registerListeners();
  1484. bindEvents();
  1485. setupPrezi();
  1486. setupToolbars();
  1487. setupChat();
  1488. document.title = interfaceConfig.APP_NAME;
  1489. $("#downloadlog").click(function (event) {
  1490. dump(event.target);
  1491. });
  1492. if(config.enableWelcomePage && window.location.pathname == "/" &&
  1493. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  1494. {
  1495. $("#videoconference_page").hide();
  1496. var setupWelcomePage = require("./welcome_page/WelcomePage");
  1497. setupWelcomePage();
  1498. return;
  1499. }
  1500. $("#welcome_page").hide();
  1501. // Display notice message at the top of the toolbar
  1502. if (config.noticeMessage) {
  1503. $('#noticeText').text(config.noticeMessage);
  1504. $('#notice').css({display: 'block'});
  1505. }
  1506. document.getElementById('largeVideo').volume = 0;
  1507. if (!$('#settings').is(':visible')) {
  1508. console.log('init');
  1509. init();
  1510. } else {
  1511. loginInfo.onsubmit = function (e) {
  1512. if (e.preventDefault) e.preventDefault();
  1513. $('#settings').hide();
  1514. init();
  1515. };
  1516. }
  1517. toastr.options = {
  1518. "closeButton": true,
  1519. "debug": false,
  1520. "positionClass": "notification-bottom-right",
  1521. "onclick": null,
  1522. "showDuration": "300",
  1523. "hideDuration": "1000",
  1524. "timeOut": "2000",
  1525. "extendedTimeOut": "1000",
  1526. "showEasing": "swing",
  1527. "hideEasing": "linear",
  1528. "showMethod": "fadeIn",
  1529. "hideMethod": "fadeOut",
  1530. "reposition": function() {
  1531. if(PanelToggler.isVisible()) {
  1532. $("#toast-container").addClass("notification-bottom-right-center");
  1533. } else {
  1534. $("#toast-container").removeClass("notification-bottom-right-center");
  1535. }
  1536. },
  1537. "newestOnTop": false
  1538. };
  1539. SettingsMenu.init();
  1540. };
  1541. function chatAddError(errorMessage, originalText)
  1542. {
  1543. return Chat.chatAddError(errorMessage, originalText);
  1544. };
  1545. function chatSetSubject(text)
  1546. {
  1547. return Chat.chatSetSubject(text);
  1548. };
  1549. function updateChatConversation(from, displayName, message) {
  1550. return Chat.updateChatConversation(from, displayName, message);
  1551. };
  1552. function onMucJoined(jid, info) {
  1553. Toolbar.updateRoomUrl(window.location.href);
  1554. var meHTML = APP.translation.generateTranslatonHTML("me");
  1555. $("#localNick").html(Strophe.getResourceFromJid(jid) + " (" + meHTML + ")");
  1556. var settings = Settings.getSettings();
  1557. // Add myself to the contact list.
  1558. ContactList.addContact(jid, settings.email || settings.uid);
  1559. // Once we've joined the muc show the toolbar
  1560. ToolbarToggler.showToolbar();
  1561. var displayName = !config.displayJids
  1562. ? info.displayName : Strophe.getResourceFromJid(jid);
  1563. if (displayName)
  1564. onDisplayNameChanged('localVideoContainer', displayName);
  1565. }
  1566. function initEtherpad(name) {
  1567. Etherpad.init(name);
  1568. };
  1569. function onMucLeft(jid) {
  1570. console.log('left.muc', jid);
  1571. var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
  1572. '>.displayname').html();
  1573. messageHandler.notify(displayName,'notify.somebody',
  1574. 'disconnected',
  1575. 'notify.disconnected');
  1576. // Need to call this with a slight delay, otherwise the element couldn't be
  1577. // found for some reason.
  1578. // XXX(gp) it works fine without the timeout for me (with Chrome 38).
  1579. window.setTimeout(function () {
  1580. var container = document.getElementById(
  1581. 'participant_' + Strophe.getResourceFromJid(jid));
  1582. if (container) {
  1583. ContactList.removeContact(jid);
  1584. VideoLayout.removeConnectionIndicator(jid);
  1585. // hide here, wait for video to close before removing
  1586. $(container).hide();
  1587. VideoLayout.resizeThumbnails();
  1588. }
  1589. }, 10);
  1590. VideoLayout.participantLeft(jid);
  1591. };
  1592. function onLocalRoleChange(jid, info, pres, isModerator)
  1593. {
  1594. console.info("My role changed, new role: " + info.role);
  1595. onModeratorStatusChanged(isModerator);
  1596. VideoLayout.showModeratorIndicator();
  1597. if (isModerator) {
  1598. Authentication.closeAuthenticationWindow();
  1599. messageHandler.notify(null, "notify.me",
  1600. 'connected', "notify.moderator");
  1601. }
  1602. }
  1603. function onModeratorStatusChanged(isModerator) {
  1604. Toolbar.showSipCallButton(isModerator);
  1605. Toolbar.showRecordingButton(
  1606. isModerator); //&&
  1607. // FIXME:
  1608. // Recording visible if
  1609. // there are at least 2(+ 1 focus) participants
  1610. //Object.keys(connection.emuc.members).length >= 3);
  1611. if (isModerator && config.etherpad_base) {
  1612. Etherpad.init();
  1613. }
  1614. };
  1615. function onPasswordReqiured(callback) {
  1616. // password is required
  1617. Toolbar.lockLockButton();
  1618. var message = '<h2 data-i18n="dialog.passwordRequired">';
  1619. message += APP.translation.translateString(
  1620. "dialog.passwordRequired");
  1621. message += '</h2>' +
  1622. '<input name="lockKey" type="text" data-i18n=' +
  1623. '"[placeholder]dialog.password" placeholder="' +
  1624. APP.translation.translateString("dialog.password") +
  1625. '" autofocus>';
  1626. messageHandler.openTwoButtonDialog(null, null, null, message,
  1627. true,
  1628. "dialog.Ok",
  1629. function (e, v, m, f) {},
  1630. null,
  1631. function (e, v, m, f) {
  1632. if (v) {
  1633. var lockKey = f.lockKey;
  1634. if (lockKey) {
  1635. Toolbar.setSharedKey(lockKey);
  1636. callback(lockKey);
  1637. }
  1638. }
  1639. },
  1640. ':input:first'
  1641. );
  1642. }
  1643. function onMucEntered(jid, id, displayName) {
  1644. messageHandler.notify(displayName,'notify.somebody',
  1645. 'connected',
  1646. 'notify.connected');
  1647. // Add Peer's container
  1648. VideoLayout.ensurePeerContainerExists(jid,id);
  1649. }
  1650. function onMucPresenceStatus( jid, info) {
  1651. VideoLayout.setPresenceStatus(
  1652. 'participant_' + Strophe.getResourceFromJid(jid), info.status);
  1653. }
  1654. function onMucRoleChanged(role, displayName) {
  1655. VideoLayout.showModeratorIndicator();
  1656. if (role === 'moderator') {
  1657. var messageKey, messageOptions = {};
  1658. if (!displayName) {
  1659. messageKey = "notify.grantedToUnknown";
  1660. }
  1661. else
  1662. {
  1663. messageKey = "notify.grantedTo";
  1664. messageOptions = {to: displayName};
  1665. }
  1666. messageHandler.notify(
  1667. displayName,'notify.somebody',
  1668. 'connected', messageKey,
  1669. messageOptions);
  1670. }
  1671. }
  1672. function onAuthenticationRequired(intervalCallback) {
  1673. Authentication.openAuthenticationDialog(
  1674. roomName, intervalCallback, function () {
  1675. Toolbar.authenticateClicked();
  1676. });
  1677. };
  1678. function onLastNChanged(oldValue, newValue) {
  1679. if (config.muteLocalVideoIfNotInLastN) {
  1680. setVideoMute(!newValue, { 'byUser': false });
  1681. }
  1682. }
  1683. UI.toggleSmileys = function () {
  1684. Chat.toggleSmileys();
  1685. };
  1686. UI.getSettings = function () {
  1687. return Settings.getSettings();
  1688. };
  1689. UI.toggleFilmStrip = function () {
  1690. return BottomToolbar.toggleFilmStrip();
  1691. };
  1692. UI.toggleChat = function () {
  1693. return BottomToolbar.toggleChat();
  1694. };
  1695. UI.toggleContactList = function () {
  1696. return BottomToolbar.toggleContactList();
  1697. };
  1698. UI.inputDisplayNameHandler = function (value) {
  1699. VideoLayout.inputDisplayNameHandler(value);
  1700. };
  1701. UI.getLargeVideoState = function()
  1702. {
  1703. return VideoLayout.getLargeVideoState();
  1704. };
  1705. UI.generateRoomName = function() {
  1706. if(roomName)
  1707. return roomName;
  1708. var roomnode = null;
  1709. var path = window.location.pathname;
  1710. // determinde the room node from the url
  1711. // TODO: just the roomnode or the whole bare jid?
  1712. if (config.getroomnode && typeof config.getroomnode === 'function') {
  1713. // custom function might be responsible for doing the pushstate
  1714. roomnode = config.getroomnode(path);
  1715. } else {
  1716. /* fall back to default strategy
  1717. * this is making assumptions about how the URL->room mapping happens.
  1718. * It currently assumes deployment at root, with a rewrite like the
  1719. * following one (for nginx):
  1720. location ~ ^/([a-zA-Z0-9]+)$ {
  1721. rewrite ^/(.*)$ / break;
  1722. }
  1723. */
  1724. if (path.length > 1) {
  1725. roomnode = path.substr(1).toLowerCase();
  1726. } else {
  1727. var word = RoomNameGenerator.generateRoomWithoutSeparator();
  1728. roomnode = word.toLowerCase();
  1729. window.history.pushState('VideoChat',
  1730. 'Room: ' + word, window.location.pathname + word);
  1731. }
  1732. }
  1733. roomName = roomnode + '@' + config.hosts.muc;
  1734. return roomName;
  1735. };
  1736. UI.connectionIndicatorShowMore = function(id)
  1737. {
  1738. return VideoLayout.connectionIndicators[id].showMore();
  1739. };
  1740. UI.showLoginPopup = function(callback)
  1741. {
  1742. console.log('password is required');
  1743. var message = '<h2 data-i18n="dialog.passwordRequired">';
  1744. message += APP.translation.translateString(
  1745. "dialog.passwordRequired");
  1746. message += '</h2>' +
  1747. '<input name="username" type="text" ' +
  1748. 'placeholder="user@domain.net" autofocus>' +
  1749. '<input name="password" ' +
  1750. 'type="password" data-i18n="[placeholder]dialog.userPassword"' +
  1751. ' placeholder="user password">';
  1752. UI.messageHandler.openTwoButtonDialog(null, null, null, message,
  1753. true,
  1754. "dialog.Ok",
  1755. function (e, v, m, f) {
  1756. if (v) {
  1757. if (f.username !== null && f.password != null) {
  1758. callback(f.username, f.password);
  1759. }
  1760. }
  1761. },
  1762. null, null, ':input:first'
  1763. );
  1764. }
  1765. UI.checkForNicknameAndJoin = function () {
  1766. Authentication.closeAuthenticationDialog();
  1767. Authentication.stopInterval();
  1768. var nick = null;
  1769. if (config.useNicks) {
  1770. nick = window.prompt('Your nickname (optional)');
  1771. }
  1772. APP.xmpp.joinRoom(roomName, config.useNicks, nick);
  1773. };
  1774. function dump(elem, filename) {
  1775. elem = elem.parentNode;
  1776. elem.download = filename || 'meetlog.json';
  1777. elem.href = 'data:application/json;charset=utf-8,\n';
  1778. var data = APP.xmpp.populateData();
  1779. var metadata = {};
  1780. metadata.time = new Date();
  1781. metadata.url = window.location.href;
  1782. metadata.ua = navigator.userAgent;
  1783. var log = APP.xmpp.getLogger();
  1784. if (log) {
  1785. metadata.xmpp = log;
  1786. }
  1787. data.metadata = metadata;
  1788. elem.href += encodeURIComponent(JSON.stringify(data, null, ' '));
  1789. return false;
  1790. }
  1791. UI.getRoomName = function () {
  1792. return roomName;
  1793. };
  1794. /**
  1795. * Mutes/unmutes the local video.
  1796. */
  1797. UI.toggleVideo = function () {
  1798. setVideoMute(!APP.RTC.localVideo.isMuted());
  1799. };
  1800. /**
  1801. * Mutes / unmutes audio for the local participant.
  1802. */
  1803. UI.toggleAudio = function() {
  1804. UI.setAudioMuted(!APP.RTC.localAudio.isMuted());
  1805. };
  1806. /**
  1807. * Sets muted audio state for the local participant.
  1808. */
  1809. UI.setAudioMuted = function (mute) {
  1810. if(!APP.xmpp.setAudioMute(mute, function () {
  1811. VideoLayout.showLocalAudioIndicator(mute);
  1812. UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
  1813. }))
  1814. {
  1815. // We still click the button.
  1816. UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
  1817. return;
  1818. }
  1819. }
  1820. UI.addListener = function (type, listener) {
  1821. eventEmitter.on(type, listener);
  1822. }
  1823. UI.clickOnVideo = function (videoNumber) {
  1824. var remoteVideos = $(".videocontainer:not(#mixedstream)");
  1825. if (remoteVideos.length > videoNumber) {
  1826. remoteVideos[videoNumber].click();
  1827. }
  1828. }
  1829. //Used by torture
  1830. UI.showToolbar = function () {
  1831. return ToolbarToggler.showToolbar();
  1832. }
  1833. //Used by torture
  1834. UI.dockToolbar = function (isDock) {
  1835. return ToolbarToggler.dockToolbar(isDock);
  1836. }
  1837. UI.setVideoMuteButtonsState = function (mute) {
  1838. var video = $('#video');
  1839. var communicativeClass = "icon-camera";
  1840. var muteClass = "icon-camera icon-camera-disabled";
  1841. if (mute) {
  1842. video.removeClass(communicativeClass);
  1843. video.addClass(muteClass);
  1844. } else {
  1845. video.removeClass(muteClass);
  1846. video.addClass(communicativeClass);
  1847. }
  1848. }
  1849. module.exports = UI;
  1850. },{"../../service/RTC/RTCEvents":89,"../../service/RTC/StreamEventTypes":91,"../../service/connectionquality/CQEvents":94,"../../service/desktopsharing/DesktopSharingEventTypes":95,"../../service/xmpp/XMPPEvents":97,"./../settings/Settings":38,"./audio_levels/AudioLevels.js":9,"./authentication/Authentication":11,"./avatar/Avatar":13,"./etherpad/Etherpad.js":14,"./prezi/Prezi.js":15,"./side_pannels/SidePanelToggler":17,"./side_pannels/chat/Chat.js":18,"./side_pannels/contactlist/ContactList":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":98}],9:[function(require,module,exports){
  1851. var CanvasUtil = require("./CanvasUtils");
  1852. var ASDrawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
  1853. function initActiveSpeakerAudioLevels() {
  1854. var ASRadius = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2;
  1855. var ASCenter = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + ASRadius) / 2;
  1856. // Draw a circle.
  1857. ASDrawContext.arc(ASCenter, ASCenter, ASRadius, 0, 2 * Math.PI);
  1858. // Add a shadow around the circle
  1859. ASDrawContext.shadowColor = interfaceConfig.SHADOW_COLOR;
  1860. ASDrawContext.shadowOffsetX = 0;
  1861. ASDrawContext.shadowOffsetY = 0;
  1862. }
  1863. /**
  1864. * The audio Levels plugin.
  1865. */
  1866. var AudioLevels = (function(my) {
  1867. var audioLevelCanvasCache = {};
  1868. my.LOCAL_LEVEL = 'local';
  1869. my.init = function () {
  1870. initActiveSpeakerAudioLevels();
  1871. }
  1872. /**
  1873. * Updates the audio level canvas for the given peerJid. If the canvas
  1874. * didn't exist we create it.
  1875. */
  1876. my.updateAudioLevelCanvas = function (peerJid, VideoLayout) {
  1877. var resourceJid = null;
  1878. var videoSpanId = null;
  1879. if (!peerJid)
  1880. videoSpanId = 'localVideoContainer';
  1881. else {
  1882. resourceJid = Strophe.getResourceFromJid(peerJid);
  1883. videoSpanId = 'participant_' + resourceJid;
  1884. }
  1885. var videoSpan = document.getElementById(videoSpanId);
  1886. if (!videoSpan) {
  1887. if (resourceJid)
  1888. console.error("No video element for jid", resourceJid);
  1889. else
  1890. console.error("No video element for local video.");
  1891. return;
  1892. }
  1893. var audioLevelCanvas = $('#' + videoSpanId + '>canvas');
  1894. var videoSpaceWidth = $('#remoteVideos').width();
  1895. var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
  1896. var thumbnailWidth = thumbnailSize[0];
  1897. var thumbnailHeight = thumbnailSize[1];
  1898. if (!audioLevelCanvas || audioLevelCanvas.length === 0) {
  1899. audioLevelCanvas = document.createElement('canvas');
  1900. audioLevelCanvas.className = "audiolevel";
  1901. audioLevelCanvas.style.bottom = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
  1902. audioLevelCanvas.style.left = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
  1903. resizeAudioLevelCanvas( audioLevelCanvas,
  1904. thumbnailWidth,
  1905. thumbnailHeight);
  1906. videoSpan.appendChild(audioLevelCanvas);
  1907. } else {
  1908. audioLevelCanvas = audioLevelCanvas.get(0);
  1909. resizeAudioLevelCanvas( audioLevelCanvas,
  1910. thumbnailWidth,
  1911. thumbnailHeight);
  1912. }
  1913. };
  1914. /**
  1915. * Updates the audio level UI for the given resourceJid.
  1916. *
  1917. * @param resourceJid the resource jid indicating the video element for
  1918. * which we draw the audio level
  1919. * @param audioLevel the newAudio level to render
  1920. */
  1921. my.updateAudioLevel = function (resourceJid, audioLevel, largeVideoResourceJid) {
  1922. drawAudioLevelCanvas(resourceJid, audioLevel);
  1923. var videoSpanId = getVideoSpanId(resourceJid);
  1924. var audioLevelCanvas = $('#' + videoSpanId + '>canvas').get(0);
  1925. if (!audioLevelCanvas)
  1926. return;
  1927. var drawContext = audioLevelCanvas.getContext('2d');
  1928. var canvasCache = audioLevelCanvasCache[resourceJid];
  1929. drawContext.clearRect (0, 0,
  1930. audioLevelCanvas.width, audioLevelCanvas.height);
  1931. drawContext.drawImage(canvasCache, 0, 0);
  1932. if(resourceJid === AudioLevels.LOCAL_LEVEL) {
  1933. if(!APP.xmpp.myJid()) {
  1934. return;
  1935. }
  1936. resourceJid = APP.xmpp.myResource();
  1937. }
  1938. if(resourceJid === largeVideoResourceJid) {
  1939. window.requestAnimationFrame(function () {
  1940. AudioLevels.updateActiveSpeakerAudioLevel(audioLevel);
  1941. });
  1942. }
  1943. };
  1944. my.updateActiveSpeakerAudioLevel = function(audioLevel) {
  1945. if($("#activeSpeaker").css("visibility") == "hidden")
  1946. return;
  1947. ASDrawContext.clearRect(0, 0, 300, 300);
  1948. if(audioLevel == 0)
  1949. return;
  1950. ASDrawContext.shadowBlur = getShadowLevel(audioLevel);
  1951. // Fill the shape.
  1952. ASDrawContext.fill();
  1953. };
  1954. /**
  1955. * Resizes the given audio level canvas to match the given thumbnail size.
  1956. */
  1957. function resizeAudioLevelCanvas(audioLevelCanvas,
  1958. thumbnailWidth,
  1959. thumbnailHeight) {
  1960. audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
  1961. audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
  1962. }
  1963. /**
  1964. * Draws the audio level canvas into the cached canvas object.
  1965. *
  1966. * @param resourceJid the resource jid indicating the video element for
  1967. * which we draw the audio level
  1968. * @param audioLevel the newAudio level to render
  1969. */
  1970. function drawAudioLevelCanvas(resourceJid, audioLevel) {
  1971. if (!audioLevelCanvasCache[resourceJid]) {
  1972. var videoSpanId = getVideoSpanId(resourceJid);
  1973. var audioLevelCanvasOrig = $('#' + videoSpanId + '>canvas').get(0);
  1974. /*
  1975. * FIXME Testing has shown that audioLevelCanvasOrig may not exist.
  1976. * In such a case, the method CanvasUtil.cloneCanvas may throw an
  1977. * error. Since audio levels are frequently updated, the errors have
  1978. * been observed to pile into the console, strain the CPU.
  1979. */
  1980. if (audioLevelCanvasOrig)
  1981. {
  1982. audioLevelCanvasCache[resourceJid]
  1983. = CanvasUtil.cloneCanvas(audioLevelCanvasOrig);
  1984. }
  1985. }
  1986. var canvas = audioLevelCanvasCache[resourceJid];
  1987. if (!canvas)
  1988. return;
  1989. var drawContext = canvas.getContext('2d');
  1990. drawContext.clearRect(0, 0, canvas.width, canvas.height);
  1991. var shadowLevel = getShadowLevel(audioLevel);
  1992. if (shadowLevel > 0)
  1993. // drawContext, x, y, w, h, r, shadowColor, shadowLevel
  1994. CanvasUtil.drawRoundRectGlow( drawContext,
  1995. interfaceConfig.CANVAS_EXTRA/2, interfaceConfig.CANVAS_EXTRA/2,
  1996. canvas.width - interfaceConfig.CANVAS_EXTRA,
  1997. canvas.height - interfaceConfig.CANVAS_EXTRA,
  1998. interfaceConfig.CANVAS_RADIUS,
  1999. interfaceConfig.SHADOW_COLOR,
  2000. shadowLevel);
  2001. }
  2002. /**
  2003. * Returns the shadow/glow level for the given audio level.
  2004. *
  2005. * @param audioLevel the audio level from which we determine the shadow
  2006. * level
  2007. */
  2008. function getShadowLevel (audioLevel) {
  2009. var shadowLevel = 0;
  2010. if (audioLevel <= 0.3) {
  2011. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*(audioLevel/0.3));
  2012. }
  2013. else if (audioLevel <= 0.6) {
  2014. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3));
  2015. }
  2016. else {
  2017. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4));
  2018. }
  2019. return shadowLevel;
  2020. }
  2021. /**
  2022. * Returns the video span id corresponding to the given resourceJid or local
  2023. * user.
  2024. */
  2025. function getVideoSpanId(resourceJid) {
  2026. var videoSpanId = null;
  2027. if (resourceJid === AudioLevels.LOCAL_LEVEL
  2028. || (APP.xmpp.myResource() && resourceJid
  2029. === APP.xmpp.myResource()))
  2030. videoSpanId = 'localVideoContainer';
  2031. else
  2032. videoSpanId = 'participant_' + resourceJid;
  2033. return videoSpanId;
  2034. }
  2035. /**
  2036. * Indicates that the remote video has been resized.
  2037. */
  2038. $(document).bind('remotevideo.resized', function (event, width, height) {
  2039. var resized = false;
  2040. $('#remoteVideos>span>canvas').each(function() {
  2041. var canvas = $(this).get(0);
  2042. if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) {
  2043. canvas.width = width + interfaceConfig.CANVAS_EXTRA;
  2044. resized = true;
  2045. }
  2046. if (canvas.heigh !== height + interfaceConfig.CANVAS_EXTRA) {
  2047. canvas.height = height + interfaceConfig.CANVAS_EXTRA;
  2048. resized = true;
  2049. }
  2050. });
  2051. if (resized)
  2052. Object.keys(audioLevelCanvasCache).forEach(function (resourceJid) {
  2053. audioLevelCanvasCache[resourceJid].width
  2054. = width + interfaceConfig.CANVAS_EXTRA;
  2055. audioLevelCanvasCache[resourceJid].height
  2056. = height + interfaceConfig.CANVAS_EXTRA;
  2057. });
  2058. });
  2059. return my;
  2060. })(AudioLevels || {});
  2061. module.exports = AudioLevels;
  2062. },{"./CanvasUtils":10}],10:[function(require,module,exports){
  2063. /**
  2064. * Utility class for drawing canvas shapes.
  2065. */
  2066. var CanvasUtil = (function(my) {
  2067. /**
  2068. * Draws a round rectangle with a glow. The glowWidth indicates the depth
  2069. * of the glow.
  2070. *
  2071. * @param drawContext the context of the canvas to draw to
  2072. * @param x the x coordinate of the round rectangle
  2073. * @param y the y coordinate of the round rectangle
  2074. * @param w the width of the round rectangle
  2075. * @param h the height of the round rectangle
  2076. * @param glowColor the color of the glow
  2077. * @param glowWidth the width of the glow
  2078. */
  2079. my.drawRoundRectGlow
  2080. = function(drawContext, x, y, w, h, r, glowColor, glowWidth) {
  2081. // Save the previous state of the context.
  2082. drawContext.save();
  2083. if (w < 2 * r) r = w / 2;
  2084. if (h < 2 * r) r = h / 2;
  2085. // Draw a round rectangle.
  2086. drawContext.beginPath();
  2087. drawContext.moveTo(x+r, y);
  2088. drawContext.arcTo(x+w, y, x+w, y+h, r);
  2089. drawContext.arcTo(x+w, y+h, x, y+h, r);
  2090. drawContext.arcTo(x, y+h, x, y, r);
  2091. drawContext.arcTo(x, y, x+w, y, r);
  2092. drawContext.closePath();
  2093. // Add a shadow around the rectangle
  2094. drawContext.shadowColor = glowColor;
  2095. drawContext.shadowBlur = glowWidth;
  2096. drawContext.shadowOffsetX = 0;
  2097. drawContext.shadowOffsetY = 0;
  2098. // Fill the shape.
  2099. drawContext.fill();
  2100. drawContext.save();
  2101. drawContext.restore();
  2102. // 1) Uncomment this line to use Composite Operation, which is doing the
  2103. // same as the clip function below and is also antialiasing the round
  2104. // border, but is said to be less fast performance wise.
  2105. // drawContext.globalCompositeOperation='destination-out';
  2106. drawContext.beginPath();
  2107. drawContext.moveTo(x+r, y);
  2108. drawContext.arcTo(x+w, y, x+w, y+h, r);
  2109. drawContext.arcTo(x+w, y+h, x, y+h, r);
  2110. drawContext.arcTo(x, y+h, x, y, r);
  2111. drawContext.arcTo(x, y, x+w, y, r);
  2112. drawContext.closePath();
  2113. // 2) Uncomment this line to use Composite Operation, which is doing the
  2114. // same as the clip function below and is also antialiasing the round
  2115. // border, but is said to be less fast performance wise.
  2116. // drawContext.fill();
  2117. // Comment these two lines if choosing to do the same with composite
  2118. // operation above 1 and 2.
  2119. drawContext.clip();
  2120. drawContext.clearRect(0, 0, 277, 200);
  2121. // Restore the previous context state.
  2122. drawContext.restore();
  2123. };
  2124. /**
  2125. * Clones the given canvas.
  2126. *
  2127. * @return the new cloned canvas.
  2128. */
  2129. my.cloneCanvas = function (oldCanvas) {
  2130. /*
  2131. * FIXME Testing has shown that oldCanvas may not exist. In such a case,
  2132. * the method CanvasUtil.cloneCanvas may throw an error. Since audio
  2133. * levels are frequently updated, the errors have been observed to pile
  2134. * into the console, strain the CPU.
  2135. */
  2136. if (!oldCanvas)
  2137. return oldCanvas;
  2138. //create a new canvas
  2139. var newCanvas = document.createElement('canvas');
  2140. var context = newCanvas.getContext('2d');
  2141. //set dimensions
  2142. newCanvas.width = oldCanvas.width;
  2143. newCanvas.height = oldCanvas.height;
  2144. //apply the old canvas to the new one
  2145. context.drawImage(oldCanvas, 0, 0);
  2146. //return the new canvas
  2147. return newCanvas;
  2148. };
  2149. return my;
  2150. })(CanvasUtil || {});
  2151. module.exports = CanvasUtil;
  2152. },{}],11:[function(require,module,exports){
  2153. /* global $, APP*/
  2154. var LoginDialog = require('./LoginDialog');
  2155. var Moderator = require('../../xmpp/moderator');
  2156. /* Initial "authentication required" dialog */
  2157. var authDialog = null;
  2158. /* Loop retry ID that wits for other user to create the room */
  2159. var authRetryId = null;
  2160. var authenticationWindow = null;
  2161. var Authentication = {
  2162. openAuthenticationDialog: function (roomName, intervalCallback, callback) {
  2163. // This is the loop that will wait for the room to be created by
  2164. // someone else. 'auth_required.moderator' will bring us back here.
  2165. authRetryId = window.setTimeout(intervalCallback, 5000);
  2166. // Show prompt only if it's not open
  2167. if (authDialog !== null) {
  2168. return;
  2169. }
  2170. // extract room name from 'room@muc.server.net'
  2171. var room = roomName.substr(0, roomName.indexOf('@'));
  2172. var title = APP.translation.generateTranslatonHTML("dialog.Stop");
  2173. var msg = APP.translation.generateTranslatonHTML("dialog.AuthMsg",
  2174. {room: room});
  2175. var buttonTxt
  2176. = APP.translation.generateTranslatonHTML("dialog.Authenticate");
  2177. var buttons = [];
  2178. buttons.push({title: buttonTxt, value: "authNow"});
  2179. authDialog = APP.UI.messageHandler.openDialog(
  2180. title,
  2181. msg,
  2182. true,
  2183. buttons,
  2184. function (onSubmitEvent, submitValue) {
  2185. // Do not close the dialog yet
  2186. onSubmitEvent.preventDefault();
  2187. // Open login popup
  2188. if (submitValue === 'authNow') {
  2189. callback();
  2190. }
  2191. }
  2192. );
  2193. },
  2194. closeAuthenticationWindow: function () {
  2195. if (authenticationWindow) {
  2196. authenticationWindow.close();
  2197. authenticationWindow = null;
  2198. }
  2199. },
  2200. xmppAuthenticate: function () {
  2201. var loginDialog = LoginDialog.show(
  2202. function (connection, state) {
  2203. if (!state) {
  2204. // User cancelled
  2205. loginDialog.close();
  2206. return;
  2207. } else if (state == APP.xmpp.Status.CONNECTED) {
  2208. loginDialog.close();
  2209. Authentication.stopInterval();
  2210. Authentication.closeAuthenticationDialog();
  2211. // Close the connection as anonymous one will be used
  2212. // to create the conference. Session-id will authorize
  2213. // the request.
  2214. connection.disconnect();
  2215. var roomName = APP.UI.generateRoomName();
  2216. Moderator.allocateConferenceFocus(roomName, function () {
  2217. // If it's not "on the fly" authentication now join
  2218. // the conference room
  2219. if (!APP.xmpp.getMUCJoined()) {
  2220. APP.UI.checkForNicknameAndJoin();
  2221. }
  2222. });
  2223. }
  2224. }, true);
  2225. },
  2226. focusAuthenticationWindow: function () {
  2227. // If auth window exists just bring it to the front
  2228. if (authenticationWindow) {
  2229. authenticationWindow.focus();
  2230. return;
  2231. }
  2232. },
  2233. closeAuthenticationDialog: function () {
  2234. // Close authentication dialog if opened
  2235. if (authDialog) {
  2236. authDialog.close();
  2237. authDialog = null;
  2238. }
  2239. },
  2240. createAuthenticationWindow: function (callback, url) {
  2241. authenticationWindow = APP.UI.messageHandler.openCenteredPopup(
  2242. url, 910, 660,
  2243. // On closed
  2244. function () {
  2245. // Close authentication dialog if opened
  2246. Authentication.closeAuthenticationDialog();
  2247. callback();
  2248. authenticationWindow = null;
  2249. });
  2250. return authenticationWindow;
  2251. },
  2252. stopInterval: function () {
  2253. // Clear retry interval, so that we don't call 'doJoinAfterFocus' twice
  2254. if (authRetryId) {
  2255. window.clearTimeout(authRetryId);
  2256. authRetryId = null;
  2257. }
  2258. }
  2259. };
  2260. module.exports = Authentication;
  2261. },{"../../xmpp/moderator":53,"./LoginDialog":12}],12:[function(require,module,exports){
  2262. /* global $, APP, config*/
  2263. var XMPP = require('../../xmpp/xmpp');
  2264. var Moderator = require('../../xmpp/moderator');
  2265. //FIXME: use LoginDialog to add retries to XMPP.connect method used when
  2266. // anonymous domain is not enabled
  2267. /**
  2268. * Creates new <tt>Dialog</tt> instance.
  2269. * @param callback <tt>function(Strophe.Connection, Strophe.Status)</tt> called
  2270. * when we either fail to connect or succeed(check Strophe.Status).
  2271. * @param obtainSession <tt>true</tt> if we want to send ConferenceIQ to Jicofo
  2272. * in order to create session-id after the connection is established.
  2273. * @constructor
  2274. */
  2275. function Dialog(callback, obtainSession) {
  2276. var self = this;
  2277. var stop = false;
  2278. var connection = APP.xmpp.createConnection();
  2279. var message = '<h2 data-i18n="dialog.passwordRequired">';
  2280. message += APP.translation.translateString("dialog.passwordRequired");
  2281. message += '</h2>' +
  2282. '<input name="username" type="text" ' +
  2283. 'placeholder="user@domain.net" autofocus>' +
  2284. '<input name="password" ' +
  2285. 'type="password" data-i18n="[placeholder]dialog.userPassword"' +
  2286. ' placeholder="user password">';
  2287. var okButton = APP.translation.generateTranslatonHTML("dialog.Ok");
  2288. var cancelButton = APP.translation.generateTranslatonHTML("dialog.Cancel");
  2289. var states = {
  2290. login: {
  2291. html: message,
  2292. buttons: [
  2293. { title: okButton, value: true},
  2294. { title: cancelButton, value: false}
  2295. ],
  2296. focus: ':input:first',
  2297. submit: function (e, v, m, f) {
  2298. e.preventDefault();
  2299. if (v) {
  2300. var jid = f.username;
  2301. var password = f.password;
  2302. if (jid && password) {
  2303. stop = false;
  2304. connection.reset();
  2305. connDialog.goToState('connecting');
  2306. connection.connect(jid, password, stateHandler);
  2307. }
  2308. } else {
  2309. // User cancelled
  2310. stop = true;
  2311. callback();
  2312. }
  2313. }
  2314. },
  2315. connecting: {
  2316. title: APP.translation.translateString('dialog.connecting'),
  2317. html: '<div id="connectionStatus"></div>',
  2318. buttons: [],
  2319. defaultButton: 0
  2320. },
  2321. finished: {
  2322. title: APP.translation.translateString('dialog.error'),
  2323. html: '<div id="errorMessage"></div>',
  2324. buttons: [
  2325. {
  2326. title: APP.translation.translateString('dialog.retry'),
  2327. value: 'retry'
  2328. },
  2329. {
  2330. title: APP.translation.translateString('dialog.Cancel'),
  2331. value: 'cancel'
  2332. },
  2333. ],
  2334. defaultButton: 0,
  2335. submit: function (e, v, m, f) {
  2336. e.preventDefault();
  2337. if (v === 'retry')
  2338. connDialog.goToState('login');
  2339. else
  2340. callback();
  2341. }
  2342. }
  2343. };
  2344. var connDialog
  2345. = APP.UI.messageHandler.openDialogWithStates(states,
  2346. { persistent: true, closeText: '' }, null);
  2347. var stateHandler = function (status, message) {
  2348. if (stop) {
  2349. return;
  2350. }
  2351. var translateKey = "connection." + XMPP.getStatusString(status);
  2352. var statusStr = APP.translation.translateString(translateKey);
  2353. // Display current state
  2354. var connectionStatus =
  2355. connDialog.getState('connecting').find('#connectionStatus');
  2356. connectionStatus.text(statusStr);
  2357. switch (status) {
  2358. case XMPP.Status.CONNECTED:
  2359. stop = true;
  2360. if (!obtainSession) {
  2361. callback(connection, status);
  2362. return;
  2363. }
  2364. // Obtaining session-id status
  2365. connectionStatus.text(
  2366. APP.translation.translateString(
  2367. 'connection.FETCH_SESSION_ID'));
  2368. // Authenticate with Jicofo and obtain session-id
  2369. var roomName = APP.UI.generateRoomName();
  2370. // Jicofo will return new session-id when connected
  2371. // from authenticated domain
  2372. connection.sendIQ(
  2373. Moderator.createConferenceIq(roomName),
  2374. function (result) {
  2375. connectionStatus.text(
  2376. APP.translation.translateString(
  2377. 'connection.GOT_SESSION_ID'));
  2378. stop = true;
  2379. // Parse session-id
  2380. Moderator.parseSessionId(result);
  2381. callback(connection, status);
  2382. },
  2383. function (error) {
  2384. console.error("Auth on the fly failed", error);
  2385. stop = true;
  2386. var errorMsg =
  2387. APP.translation.translateString(
  2388. 'connection.GET_SESSION_ID_ERROR') +
  2389. $(error).find('>error').attr('code');
  2390. self.displayError(errorMsg);
  2391. connection.disconnect();
  2392. });
  2393. break;
  2394. case XMPP.Status.AUTHFAIL:
  2395. case XMPP.Status.CONNFAIL:
  2396. case XMPP.Status.DISCONNECTED:
  2397. stop = true;
  2398. callback(connection, status);
  2399. var errorMessage = statusStr;
  2400. if (message)
  2401. {
  2402. errorMessage += ': ' + message;
  2403. }
  2404. self.displayError(errorMessage);
  2405. break;
  2406. default:
  2407. break;
  2408. }
  2409. };
  2410. /**
  2411. * Displays error message in 'finished' state which allows either to cancel
  2412. * or retry.
  2413. * @param message the final message to be displayed.
  2414. */
  2415. this.displayError = function (message) {
  2416. var finishedState = connDialog.getState('finished');
  2417. var errorMessageElem = finishedState.find('#errorMessage');
  2418. errorMessageElem.text(message);
  2419. connDialog.goToState('finished');
  2420. };
  2421. /**
  2422. * Closes LoginDialog.
  2423. */
  2424. this.close = function () {
  2425. stop = true;
  2426. connDialog.close();
  2427. };
  2428. }
  2429. var LoginDialog = {
  2430. /**
  2431. * Displays login prompt used to establish new XMPP connection. Given
  2432. * <tt>callback(Strophe.Connection, Strophe.Status)</tt> function will be
  2433. * called when we connect successfully(status === CONNECTED) or when we fail
  2434. * to do so. On connection failure program can call Dialog.close() method in
  2435. * order to cancel or do nothing to let the user retry.
  2436. * @param callback <tt>function(Strophe.Connection, Strophe.Status)</tt>
  2437. * called when we either fail to connect or succeed(check
  2438. * Strophe.Status).
  2439. * @param obtainSession <tt>true</tt> if we want to send ConferenceIQ to
  2440. * Jicofo in order to create session-id after the connection is
  2441. * established.
  2442. * @returns {Dialog}
  2443. */
  2444. show: function (callback, obtainSession) {
  2445. return new Dialog(callback, obtainSession);
  2446. }
  2447. };
  2448. module.exports = LoginDialog;
  2449. },{"../../xmpp/moderator":53,"../../xmpp/xmpp":61}],13:[function(require,module,exports){
  2450. var Settings = require("../../settings/Settings");
  2451. var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
  2452. var users = {};
  2453. var activeSpeakerJid;
  2454. function setVisibility(selector, show) {
  2455. if (selector && selector.length > 0) {
  2456. selector.css("visibility", show ? "visible" : "hidden");
  2457. }
  2458. }
  2459. function isUserMuted(jid) {
  2460. // XXX(gp) we may want to rename this method to something like
  2461. // isUserStreaming, for example.
  2462. if (jid && jid != APP.xmpp.myJid()) {
  2463. var resource = Strophe.getResourceFromJid(jid);
  2464. if (!require("../videolayout/VideoLayout").isInLastN(resource)) {
  2465. return true;
  2466. }
  2467. }
  2468. if (!APP.RTC.remoteStreams[jid] || !APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
  2469. return null;
  2470. }
  2471. return APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted;
  2472. }
  2473. function getGravatarUrl(id, size) {
  2474. if(id === APP.xmpp.myJid() || !id) {
  2475. id = Settings.getSettings().uid;
  2476. }
  2477. return 'https://www.gravatar.com/avatar/' +
  2478. MD5.hexdigest(id.trim().toLowerCase()) +
  2479. "?d=wavatar&size=" + (size || "30");
  2480. }
  2481. var Avatar = {
  2482. /**
  2483. * Sets the user's avatar in the settings menu(if local user), contact list
  2484. * and thumbnail
  2485. * @param jid jid of the user
  2486. * @param id email or userID to be used as a hash
  2487. */
  2488. setUserAvatar: function (jid, id) {
  2489. if (id) {
  2490. if (users[jid] === id) {
  2491. return;
  2492. }
  2493. users[jid] = id;
  2494. }
  2495. var thumbUrl = getGravatarUrl(users[jid] || jid, 100);
  2496. var contactListUrl = getGravatarUrl(users[jid] || jid);
  2497. var resourceJid = Strophe.getResourceFromJid(jid);
  2498. var thumbnail = $('#participant_' + resourceJid);
  2499. var avatar = $('#avatar_' + resourceJid);
  2500. // set the avatar in the settings menu if it is local user and get the
  2501. // local video container
  2502. if (jid === APP.xmpp.myJid()) {
  2503. $('#avatar').get(0).src = thumbUrl;
  2504. thumbnail = $('#localVideoContainer');
  2505. }
  2506. // set the avatar in the contact list
  2507. var contact = $('#' + resourceJid + '>img');
  2508. if (contact && contact.length > 0) {
  2509. contact.get(0).src = contactListUrl;
  2510. }
  2511. // set the avatar in the thumbnail
  2512. if (avatar && avatar.length > 0) {
  2513. avatar[0].src = thumbUrl;
  2514. } else {
  2515. if (thumbnail && thumbnail.length > 0) {
  2516. avatar = document.createElement('img');
  2517. avatar.id = 'avatar_' + resourceJid;
  2518. avatar.className = 'userAvatar';
  2519. avatar.src = thumbUrl;
  2520. thumbnail.append(avatar);
  2521. }
  2522. }
  2523. //if the user is the current active speaker - update the active speaker
  2524. // avatar
  2525. if (jid === activeSpeakerJid) {
  2526. this.updateActiveSpeakerAvatarSrc(jid);
  2527. }
  2528. },
  2529. /**
  2530. * Hides or shows the user's avatar
  2531. * @param jid jid of the user
  2532. * @param show whether we should show the avatar or not
  2533. * video because there is no dominant speaker and no focused speaker
  2534. */
  2535. showUserAvatar: function (jid, show) {
  2536. if (users[jid]) {
  2537. var resourceJid = Strophe.getResourceFromJid(jid);
  2538. var video = $('#participant_' + resourceJid + '>video');
  2539. var avatar = $('#avatar_' + resourceJid);
  2540. if (jid === APP.xmpp.myJid()) {
  2541. video = $('#localVideoWrapper>video');
  2542. }
  2543. if (show === undefined || show === null) {
  2544. show = isUserMuted(jid);
  2545. }
  2546. //if the user is the currently focused, the dominant speaker or if
  2547. //there is no focused and no dominant speaker and the large video is
  2548. //currently shown
  2549. if (activeSpeakerJid === jid && require("../videolayout/VideoLayout").isLargeVideoOnTop()) {
  2550. setVisibility($("#largeVideo"), !show);
  2551. setVisibility($('#activeSpeaker'), show);
  2552. setVisibility(avatar, false);
  2553. setVisibility(video, false);
  2554. } else {
  2555. if (video && video.length > 0) {
  2556. setVisibility(video, !show);
  2557. setVisibility(avatar, show);
  2558. }
  2559. }
  2560. }
  2561. },
  2562. /**
  2563. * Updates the src of the active speaker avatar
  2564. * @param jid of the current active speaker
  2565. */
  2566. updateActiveSpeakerAvatarSrc: function (jid) {
  2567. if (!jid) {
  2568. jid = APP.xmpp.findJidFromResource(
  2569. require("../videolayout/VideoLayout").getLargeVideoState().userResourceJid);
  2570. }
  2571. var avatar = $("#activeSpeakerAvatar")[0];
  2572. var url = getGravatarUrl(users[jid],
  2573. interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE);
  2574. if (jid === activeSpeakerJid && avatar.src === url) {
  2575. return;
  2576. }
  2577. activeSpeakerJid = jid;
  2578. var isMuted = isUserMuted(jid);
  2579. if (jid && isMuted !== null) {
  2580. avatar.src = url;
  2581. setVisibility($("#largeVideo"), !isMuted);
  2582. Avatar.showUserAvatar(jid, isMuted);
  2583. }
  2584. }
  2585. };
  2586. module.exports = Avatar;
  2587. },{"../../../service/RTC/MediaStreamTypes":87,"../../settings/Settings":38,"../videolayout/VideoLayout":32}],14:[function(require,module,exports){
  2588. /* global $, config,
  2589. setLargeVideoVisible, Util */
  2590. var VideoLayout = require("../videolayout/VideoLayout");
  2591. var Prezi = require("../prezi/Prezi");
  2592. var UIUtil = require("../util/UIUtil");
  2593. var etherpadName = null;
  2594. var etherpadIFrame = null;
  2595. var domain = null;
  2596. var options = "?showControls=true&showChat=false&showLineNumbers=true&useMonospaceFont=false";
  2597. /**
  2598. * Resizes the etherpad.
  2599. */
  2600. function resize() {
  2601. if ($('#etherpad>iframe').length) {
  2602. var remoteVideos = $('#remoteVideos');
  2603. var availableHeight
  2604. = window.innerHeight - remoteVideos.outerHeight();
  2605. var availableWidth = UIUtil.getAvailableVideoWidth();
  2606. $('#etherpad>iframe').width(availableWidth);
  2607. $('#etherpad>iframe').height(availableHeight);
  2608. }
  2609. }
  2610. /**
  2611. * Shares the Etherpad name with other participants.
  2612. */
  2613. function shareEtherpad() {
  2614. APP.xmpp.addToPresence("etherpad", etherpadName);
  2615. }
  2616. /**
  2617. * Creates the Etherpad button and adds it to the toolbar.
  2618. */
  2619. function enableEtherpadButton() {
  2620. if (!$('#etherpadButton').is(":visible"))
  2621. $('#etherpadButton').css({display: 'inline-block'});
  2622. }
  2623. /**
  2624. * Creates the IFrame for the etherpad.
  2625. */
  2626. function createIFrame() {
  2627. etherpadIFrame = document.createElement('iframe');
  2628. etherpadIFrame.src = domain + etherpadName + options;
  2629. etherpadIFrame.frameBorder = 0;
  2630. etherpadIFrame.scrolling = "no";
  2631. etherpadIFrame.width = $('#largeVideoContainer').width() || 640;
  2632. etherpadIFrame.height = $('#largeVideoContainer').height() || 480;
  2633. etherpadIFrame.setAttribute('style', 'visibility: hidden;');
  2634. document.getElementById('etherpad').appendChild(etherpadIFrame);
  2635. etherpadIFrame.onload = function() {
  2636. document.domain = document.domain;
  2637. bubbleIframeMouseMove(etherpadIFrame);
  2638. setTimeout(function() {
  2639. // the iframes inside of the etherpad are
  2640. // not yet loaded when the etherpad iframe is loaded
  2641. var outer = etherpadIFrame.
  2642. contentDocument.getElementsByName("ace_outer")[0];
  2643. bubbleIframeMouseMove(outer);
  2644. var inner = outer.
  2645. contentDocument.getElementsByName("ace_inner")[0];
  2646. bubbleIframeMouseMove(inner);
  2647. }, 2000);
  2648. };
  2649. }
  2650. function bubbleIframeMouseMove(iframe){
  2651. var existingOnMouseMove = iframe.contentWindow.onmousemove;
  2652. iframe.contentWindow.onmousemove = function(e){
  2653. if(existingOnMouseMove) existingOnMouseMove(e);
  2654. var evt = document.createEvent("MouseEvents");
  2655. var boundingClientRect = iframe.getBoundingClientRect();
  2656. evt.initMouseEvent(
  2657. "mousemove",
  2658. true, // bubbles
  2659. false, // not cancelable
  2660. window,
  2661. e.detail,
  2662. e.screenX,
  2663. e.screenY,
  2664. e.clientX + boundingClientRect.left,
  2665. e.clientY + boundingClientRect.top,
  2666. e.ctrlKey,
  2667. e.altKey,
  2668. e.shiftKey,
  2669. e.metaKey,
  2670. e.button,
  2671. null // no related element
  2672. );
  2673. iframe.dispatchEvent(evt);
  2674. };
  2675. }
  2676. /**
  2677. * On video selected event.
  2678. */
  2679. $(document).bind('video.selected', function (event, isPresentation) {
  2680. if (config.etherpad_base && etherpadIFrame && etherpadIFrame.style.visibility !== 'hidden')
  2681. Etherpad.toggleEtherpad(isPresentation);
  2682. });
  2683. var Etherpad = {
  2684. /**
  2685. * Initializes the etherpad.
  2686. */
  2687. init: function (name) {
  2688. if (config.etherpad_base && !etherpadName) {
  2689. domain = config.etherpad_base;
  2690. if (!name) {
  2691. // In case we're the focus we generate the name.
  2692. etherpadName = Math.random().toString(36).substring(7) +
  2693. '_' + (new Date().getTime()).toString();
  2694. shareEtherpad();
  2695. }
  2696. else
  2697. etherpadName = name;
  2698. enableEtherpadButton();
  2699. /**
  2700. * Resizes the etherpad, when the window is resized.
  2701. */
  2702. $(window).resize(function () {
  2703. resize();
  2704. });
  2705. }
  2706. },
  2707. /**
  2708. * Opens/hides the Etherpad.
  2709. */
  2710. toggleEtherpad: function (isPresentation) {
  2711. if (!etherpadIFrame)
  2712. createIFrame();
  2713. var largeVideo = null;
  2714. if (Prezi.isPresentationVisible())
  2715. largeVideo = $('#presentation>iframe');
  2716. else
  2717. largeVideo = $('#largeVideo');
  2718. if ($('#etherpad>iframe').css('visibility') === 'hidden') {
  2719. $('#activeSpeaker').css('visibility', 'hidden');
  2720. largeVideo.fadeOut(300, function () {
  2721. if (Prezi.isPresentationVisible()) {
  2722. largeVideo.css({opacity: '0'});
  2723. } else {
  2724. VideoLayout.setLargeVideoVisible(false);
  2725. }
  2726. });
  2727. $('#etherpad>iframe').fadeIn(300, function () {
  2728. document.body.style.background = '#eeeeee';
  2729. $('#etherpad>iframe').css({visibility: 'visible'});
  2730. $('#etherpad').css({zIndex: 2});
  2731. });
  2732. }
  2733. else if ($('#etherpad>iframe')) {
  2734. $('#etherpad>iframe').fadeOut(300, function () {
  2735. $('#etherpad>iframe').css({visibility: 'hidden'});
  2736. $('#etherpad').css({zIndex: 0});
  2737. document.body.style.background = 'black';
  2738. });
  2739. if (!isPresentation) {
  2740. $('#largeVideo').fadeIn(300, function () {
  2741. VideoLayout.setLargeVideoVisible(true);
  2742. });
  2743. }
  2744. }
  2745. resize();
  2746. },
  2747. isVisible: function() {
  2748. var etherpadIframe = $('#etherpad>iframe');
  2749. return etherpadIframe && etherpadIframe.is(':visible');
  2750. }
  2751. };
  2752. module.exports = Etherpad;
  2753. },{"../prezi/Prezi":15,"../util/UIUtil":30,"../videolayout/VideoLayout":32}],15:[function(require,module,exports){
  2754. var ToolbarToggler = require("../toolbars/ToolbarToggler");
  2755. var UIUtil = require("../util/UIUtil");
  2756. var VideoLayout = require("../videolayout/VideoLayout");
  2757. var messageHandler = require("../util/MessageHandler");
  2758. var PreziPlayer = require("./PreziPlayer");
  2759. var preziPlayer = null;
  2760. var Prezi = {
  2761. /**
  2762. * Reloads the current presentation.
  2763. */
  2764. reloadPresentation: function() {
  2765. var iframe = document.getElementById(preziPlayer.options.preziId);
  2766. iframe.src = iframe.src;
  2767. },
  2768. /**
  2769. * Returns <tt>true</tt> if the presentation is visible, <tt>false</tt> -
  2770. * otherwise.
  2771. */
  2772. isPresentationVisible: function () {
  2773. return ($('#presentation>iframe') != null
  2774. && $('#presentation>iframe').css('opacity') == 1);
  2775. },
  2776. /**
  2777. * Opens the Prezi dialog, from which the user could choose a presentation
  2778. * to load.
  2779. */
  2780. openPreziDialog: function() {
  2781. var myprezi = APP.xmpp.getPrezi();
  2782. if (myprezi) {
  2783. messageHandler.openTwoButtonDialog("dialog.removePreziTitle",
  2784. null,
  2785. "dialog.removePreziMsg",
  2786. null,
  2787. false,
  2788. "dialog.Remove",
  2789. function(e,v,m,f) {
  2790. if(v) {
  2791. APP.xmpp.removePreziFromPresence();
  2792. }
  2793. }
  2794. );
  2795. }
  2796. else if (preziPlayer != null) {
  2797. messageHandler.openTwoButtonDialog("dialog.sharePreziTitle",
  2798. null, "dialog.sharePreziMsg",
  2799. null,
  2800. false,
  2801. "dialog.Ok",
  2802. function(e,v,m,f) {
  2803. $.prompt.close();
  2804. }
  2805. );
  2806. }
  2807. else {
  2808. var html = APP.translation.generateTranslatonHTML(
  2809. "dialog.sharePreziTitle");
  2810. var cancelButton = APP.translation.generateTranslatonHTML(
  2811. "dialog.Cancel");
  2812. var shareButton = APP.translation.generateTranslatonHTML(
  2813. "dialog.Share");
  2814. var backButton = APP.translation.generateTranslatonHTML(
  2815. "dialog.Back");
  2816. var buttons = [];
  2817. var buttons1 = [];
  2818. // Cancel button to both states
  2819. buttons.push({title: cancelButton, value: false});
  2820. buttons1.push({title: cancelButton, value: false});
  2821. // Share button
  2822. buttons.push({title: shareButton, value: true});
  2823. // Back button
  2824. buttons1.push({title: backButton, value: true});
  2825. var linkError = APP.translation.generateTranslatonHTML(
  2826. "dialog.preziLinkError");
  2827. var defaultUrl = APP.translation.translateString("defaultPreziLink",
  2828. {url: "http://prezi.com/wz7vhjycl7e6/my-prezi"});
  2829. var openPreziState = {
  2830. state0: {
  2831. html: '<h2>' + html + '</h2>' +
  2832. '<input name="preziUrl" type="text" ' +
  2833. 'data-i18n="[placeholder]defaultPreziLink" data-i18n-options=\'' +
  2834. JSON.stringify({"url": "http://prezi.com/wz7vhjycl7e6/my-prezi"}) +
  2835. '\' placeholder="' + defaultUrl + '" autofocus>',
  2836. persistent: false,
  2837. buttons: buttons,
  2838. focus: ':input:first',
  2839. defaultButton: 0,
  2840. submit: function (e, v, m, f) {
  2841. e.preventDefault();
  2842. if(v)
  2843. {
  2844. var preziUrl = f.preziUrl;
  2845. if (preziUrl)
  2846. {
  2847. var urlValue
  2848. = encodeURI(UIUtil.escapeHtml(preziUrl));
  2849. if (urlValue.indexOf('http://prezi.com/') != 0
  2850. && urlValue.indexOf('https://prezi.com/') != 0)
  2851. {
  2852. $.prompt.goToState('state1');
  2853. return false;
  2854. }
  2855. else {
  2856. var presIdTmp = urlValue.substring(
  2857. urlValue.indexOf("prezi.com/") + 10);
  2858. if (!isAlphanumeric(presIdTmp)
  2859. || presIdTmp.indexOf('/') < 2) {
  2860. $.prompt.goToState('state1');
  2861. return false;
  2862. }
  2863. else {
  2864. APP.xmpp.addToPresence("prezi", urlValue);
  2865. $.prompt.close();
  2866. }
  2867. }
  2868. }
  2869. }
  2870. else
  2871. $.prompt.close();
  2872. }
  2873. },
  2874. state1: {
  2875. html: '<h2>' + html + '</h2>' +
  2876. linkError,
  2877. persistent: false,
  2878. buttons: buttons1,
  2879. focus: ':input:first',
  2880. defaultButton: 1,
  2881. submit: function (e, v, m, f) {
  2882. e.preventDefault();
  2883. if (v === 0)
  2884. $.prompt.close();
  2885. else
  2886. $.prompt.goToState('state0');
  2887. }
  2888. }
  2889. };
  2890. messageHandler.openDialogWithStates(openPreziState);
  2891. }
  2892. }
  2893. };
  2894. /**
  2895. * A new presentation has been added.
  2896. *
  2897. * @param event the event indicating the add of a presentation
  2898. * @param jid the jid from which the presentation was added
  2899. * @param presUrl url of the presentation
  2900. * @param currentSlide the current slide to which we should move
  2901. */
  2902. function presentationAdded(event, jid, presUrl, currentSlide) {
  2903. console.log("presentation added", presUrl);
  2904. var presId = getPresentationId(presUrl);
  2905. var elementId = 'participant_'
  2906. + Strophe.getResourceFromJid(jid)
  2907. + '_' + presId;
  2908. // We explicitly don't specify the peer jid here, because we don't want
  2909. // this video to be dealt with as a peer related one (for example we
  2910. // don't want to show a mute/kick menu for this one, etc.).
  2911. VideoLayout.addRemoteVideoContainer(null, elementId);
  2912. VideoLayout.resizeThumbnails();
  2913. var controlsEnabled = false;
  2914. if (jid === APP.xmpp.myJid())
  2915. controlsEnabled = true;
  2916. setPresentationVisible(true);
  2917. $('#largeVideoContainer').hover(
  2918. function (event) {
  2919. if (Prezi.isPresentationVisible()) {
  2920. var reloadButtonRight = window.innerWidth
  2921. - $('#presentation>iframe').offset().left
  2922. - $('#presentation>iframe').width();
  2923. $('#reloadPresentation').css({ right: reloadButtonRight,
  2924. display:'inline-block'});
  2925. }
  2926. },
  2927. function (event) {
  2928. if (!Prezi.isPresentationVisible())
  2929. $('#reloadPresentation').css({display:'none'});
  2930. else {
  2931. var e = event.toElement || event.relatedTarget;
  2932. if (e && e.id != 'reloadPresentation' && e.id != 'header')
  2933. $('#reloadPresentation').css({display:'none'});
  2934. }
  2935. });
  2936. preziPlayer = new PreziPlayer(
  2937. 'presentation',
  2938. {preziId: presId,
  2939. width: getPresentationWidth(),
  2940. height: getPresentationHeihgt(),
  2941. controls: controlsEnabled,
  2942. debug: true
  2943. });
  2944. $('#presentation>iframe').attr('id', preziPlayer.options.preziId);
  2945. preziPlayer.on(PreziPlayer.EVENT_STATUS, function(event) {
  2946. console.log("prezi status", event.value);
  2947. if (event.value == PreziPlayer.STATUS_CONTENT_READY) {
  2948. if (jid != APP.xmpp.myJid())
  2949. preziPlayer.flyToStep(currentSlide);
  2950. }
  2951. });
  2952. preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function(event) {
  2953. console.log("event value", event.value);
  2954. APP.xmpp.addToPresence("preziSlide", event.value);
  2955. });
  2956. $("#" + elementId).css( 'background-image',
  2957. 'url(../images/avatarprezi.png)');
  2958. $("#" + elementId).click(
  2959. function () {
  2960. setPresentationVisible(true);
  2961. }
  2962. );
  2963. };
  2964. /**
  2965. * A presentation has been removed.
  2966. *
  2967. * @param event the event indicating the remove of a presentation
  2968. * @param jid the jid for which the presentation was removed
  2969. * @param the url of the presentation
  2970. */
  2971. function presentationRemoved(event, jid, presUrl) {
  2972. console.log('presentation removed', presUrl);
  2973. var presId = getPresentationId(presUrl);
  2974. setPresentationVisible(false);
  2975. $('#participant_'
  2976. + Strophe.getResourceFromJid(jid)
  2977. + '_' + presId).remove();
  2978. $('#presentation>iframe').remove();
  2979. if (preziPlayer != null) {
  2980. preziPlayer.destroy();
  2981. preziPlayer = null;
  2982. }
  2983. };
  2984. /**
  2985. * Indicates if the given string is an alphanumeric string.
  2986. * Note that some special characters are also allowed (-, _ , /, &, ?, =, ;) for the
  2987. * purpose of checking URIs.
  2988. */
  2989. function isAlphanumeric(unsafeText) {
  2990. var regex = /^[a-z0-9-_\/&\?=;]+$/i;
  2991. return regex.test(unsafeText);
  2992. }
  2993. /**
  2994. * Returns the presentation id from the given url.
  2995. */
  2996. function getPresentationId (presUrl) {
  2997. var presIdTmp = presUrl.substring(presUrl.indexOf("prezi.com/") + 10);
  2998. return presIdTmp.substring(0, presIdTmp.indexOf('/'));
  2999. }
  3000. /**
  3001. * Returns the presentation width.
  3002. */
  3003. function getPresentationWidth() {
  3004. var availableWidth = UIUtil.getAvailableVideoWidth();
  3005. var availableHeight = getPresentationHeihgt();
  3006. var aspectRatio = 16.0 / 9.0;
  3007. if (availableHeight < availableWidth / aspectRatio) {
  3008. availableWidth = Math.floor(availableHeight * aspectRatio);
  3009. }
  3010. return availableWidth;
  3011. }
  3012. /**
  3013. * Returns the presentation height.
  3014. */
  3015. function getPresentationHeihgt() {
  3016. var remoteVideos = $('#remoteVideos');
  3017. return window.innerHeight - remoteVideos.outerHeight();
  3018. }
  3019. /**
  3020. * Resizes the presentation iframe.
  3021. */
  3022. function resize() {
  3023. if ($('#presentation>iframe')) {
  3024. $('#presentation>iframe').width(getPresentationWidth());
  3025. $('#presentation>iframe').height(getPresentationHeihgt());
  3026. }
  3027. }
  3028. /**
  3029. * Shows/hides a presentation.
  3030. */
  3031. function setPresentationVisible(visible) {
  3032. var prezi = $('#presentation>iframe');
  3033. if (visible) {
  3034. // Trigger the video.selected event to indicate a change in the
  3035. // large video.
  3036. $(document).trigger("video.selected", [true]);
  3037. $('#largeVideo').fadeOut(300);
  3038. prezi.fadeIn(300, function() {
  3039. prezi.css({opacity:'1'});
  3040. ToolbarToggler.dockToolbar(true);
  3041. VideoLayout.setLargeVideoVisible(false);
  3042. });
  3043. $('#activeSpeaker').css('visibility', 'hidden');
  3044. }
  3045. else {
  3046. if (prezi.css('opacity') == '1') {
  3047. prezi.fadeOut(300, function () {
  3048. prezi.css({opacity:'0'});
  3049. $('#reloadPresentation').css({display:'none'});
  3050. $('#largeVideo').fadeIn(300, function() {
  3051. VideoLayout.setLargeVideoVisible(true);
  3052. ToolbarToggler.dockToolbar(false);
  3053. });
  3054. });
  3055. }
  3056. }
  3057. }
  3058. /**
  3059. * Presentation has been removed.
  3060. */
  3061. $(document).bind('presentationremoved.muc', presentationRemoved);
  3062. /**
  3063. * Presentation has been added.
  3064. */
  3065. $(document).bind('presentationadded.muc', presentationAdded);
  3066. /*
  3067. * Indicates presentation slide change.
  3068. */
  3069. $(document).bind('gotoslide.muc', function (event, jid, presUrl, current) {
  3070. if (preziPlayer && preziPlayer.getCurrentStep() != current) {
  3071. preziPlayer.flyToStep(current);
  3072. var animationStepsArray = preziPlayer.getAnimationCountOnSteps();
  3073. for (var i = 0; i < parseInt(animationStepsArray[current]); i++) {
  3074. preziPlayer.flyToStep(current, i);
  3075. }
  3076. }
  3077. });
  3078. /**
  3079. * On video selected event.
  3080. */
  3081. $(document).bind('video.selected', function (event, isPresentation) {
  3082. if (!isPresentation && $('#presentation>iframe')) {
  3083. setPresentationVisible(false);
  3084. }
  3085. });
  3086. $(window).resize(function () {
  3087. resize();
  3088. });
  3089. module.exports = Prezi;
  3090. },{"../toolbars/ToolbarToggler":26,"../util/MessageHandler":28,"../util/UIUtil":30,"../videolayout/VideoLayout":32,"./PreziPlayer":16}],16:[function(require,module,exports){
  3091. (function() {
  3092. "use strict";
  3093. var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
  3094. window.PreziPlayer = (function() {
  3095. PreziPlayer.API_VERSION = 1;
  3096. PreziPlayer.CURRENT_STEP = 'currentStep';
  3097. PreziPlayer.CURRENT_ANIMATION_STEP = 'currentAnimationStep';
  3098. PreziPlayer.CURRENT_OBJECT = 'currentObject';
  3099. PreziPlayer.STATUS_LOADING = 'loading';
  3100. PreziPlayer.STATUS_READY = 'ready';
  3101. PreziPlayer.STATUS_CONTENT_READY = 'contentready';
  3102. PreziPlayer.EVENT_CURRENT_STEP = "currentStepChange";
  3103. PreziPlayer.EVENT_CURRENT_ANIMATION_STEP = "currentAnimationStepChange";
  3104. PreziPlayer.EVENT_CURRENT_OBJECT = "currentObjectChange";
  3105. PreziPlayer.EVENT_STATUS = "statusChange";
  3106. PreziPlayer.EVENT_PLAYING = "isAutoPlayingChange";
  3107. PreziPlayer.EVENT_IS_MOVING = "isMovingChange";
  3108. PreziPlayer.domain = "https://prezi.com";
  3109. PreziPlayer.path = "/player/";
  3110. PreziPlayer.players = {};
  3111. PreziPlayer.binded_methods = ['changesHandler'];
  3112. PreziPlayer.createMultiplePlayers = function(optionArray){
  3113. for(var i=0; i<optionArray.length; i++) {
  3114. var optionSet = optionArray[i];
  3115. new PreziPlayer(optionSet.id, optionSet);
  3116. };
  3117. };
  3118. PreziPlayer.messageReceived = function(event){
  3119. var message, item, player;
  3120. try {
  3121. message = JSON.parse(event.data);
  3122. if (message.id && (player = PreziPlayer.players[message.id])) {
  3123. if (player.options.debug === true) {
  3124. if (console && console.log)
  3125. console.log('received', message);
  3126. }
  3127. if (message.type === "changes") {
  3128. player.changesHandler(message);
  3129. }
  3130. for (var i = 0; i < player.callbacks.length; i++) {
  3131. item = player.callbacks[i];
  3132. if (item && message.type === item.event) {
  3133. item.callback(message);
  3134. }
  3135. }
  3136. }
  3137. } catch (e) { }
  3138. };
  3139. function PreziPlayer(id, options) {
  3140. var params, paramString = "", _this = this;
  3141. if (PreziPlayer.players[id]){
  3142. PreziPlayer.players[id].destroy();
  3143. }
  3144. for(var i=0; i<PreziPlayer.binded_methods.length; i++) {
  3145. var method_name = PreziPlayer.binded_methods[i];
  3146. _this[method_name] = __bind(_this[method_name], _this);
  3147. };
  3148. options = options || {};
  3149. this.options = options;
  3150. this.values = {'status': PreziPlayer.STATUS_LOADING};
  3151. this.values[PreziPlayer.CURRENT_STEP] = 0;
  3152. this.values[PreziPlayer.CURRENT_ANIMATION_STEP] = 0;
  3153. this.values[PreziPlayer.CURRENT_OBJECT] = null;
  3154. this.callbacks = [];
  3155. this.id = id;
  3156. this.embedTo = document.getElementById(id);
  3157. if (!this.embedTo) {
  3158. throw "The element id is not available.";
  3159. }
  3160. this.iframe = document.createElement('iframe');
  3161. params = [
  3162. { name: 'oid', value: options.preziId },
  3163. { name: 'explorable', value: options.explorable ? 1 : 0 },
  3164. { name: 'controls', value: options.controls ? 1 : 0 }
  3165. ];
  3166. for(var i=0; i<params.length; i++) {
  3167. var param = params[i];
  3168. paramString += (i===0 ? "?" : "&") + param.name + "=" + param.value;
  3169. };
  3170. this.iframe.src = PreziPlayer.domain + PreziPlayer.path + paramString;
  3171. this.iframe.frameBorder = 0;
  3172. this.iframe.scrolling = "no";
  3173. this.iframe.width = options.width || 640;
  3174. this.iframe.height = options.height || 480;
  3175. this.embedTo.innerHTML = '';
  3176. // JITSI: IN CASE SOMETHING GOES WRONG.
  3177. try {
  3178. this.embedTo.appendChild(this.iframe);
  3179. }
  3180. catch (err) {
  3181. console.log("CATCH ERROR");
  3182. }
  3183. // JITSI: Increase interval from 200 to 500, which fixes prezi
  3184. // crashes for us.
  3185. this.initPollInterval = setInterval(function(){
  3186. _this.sendMessage({'action': 'init'});
  3187. }, 500);
  3188. PreziPlayer.players[id] = this;
  3189. }
  3190. PreziPlayer.prototype.changesHandler = function(message) {
  3191. var key, value, j, item;
  3192. if (this.initPollInterval) {
  3193. clearInterval(this.initPollInterval);
  3194. this.initPollInterval = false;
  3195. }
  3196. for (key in message.data) {
  3197. if (message.data.hasOwnProperty(key)){
  3198. value = message.data[key];
  3199. this.values[key] = value;
  3200. for (j=0; j<this.callbacks.length; j++) {
  3201. item = this.callbacks[j];
  3202. if (item && item.event === key + "Change"){
  3203. item.callback({type: item.event, value: value});
  3204. }
  3205. }
  3206. }
  3207. }
  3208. };
  3209. PreziPlayer.prototype.destroy = function() {
  3210. if (this.initPollInterval) {
  3211. clearInterval(this.initPollInterval);
  3212. this.initPollInterval = false;
  3213. }
  3214. this.embedTo.innerHTML = '';
  3215. };
  3216. PreziPlayer.prototype.sendMessage = function(message) {
  3217. if (this.options.debug === true) {
  3218. if (console && console.log) console.log('sent', message);
  3219. }
  3220. message.version = PreziPlayer.API_VERSION;
  3221. message.id = this.id;
  3222. return this.iframe.contentWindow.postMessage(JSON.stringify(message), '*');
  3223. };
  3224. PreziPlayer.prototype.nextStep = /* nextStep is DEPRECATED */
  3225. PreziPlayer.prototype.flyToNextStep = function() {
  3226. return this.sendMessage({
  3227. 'action': 'present',
  3228. 'data': ['moveToNextStep']
  3229. });
  3230. };
  3231. PreziPlayer.prototype.previousStep = /* previousStep is DEPRECATED */
  3232. PreziPlayer.prototype.flyToPreviousStep = function() {
  3233. return this.sendMessage({
  3234. 'action': 'present',
  3235. 'data': ['moveToPrevStep']
  3236. });
  3237. };
  3238. PreziPlayer.prototype.toStep = /* toStep is DEPRECATED */
  3239. PreziPlayer.prototype.flyToStep = function(step, animation_step) {
  3240. var obj = this;
  3241. // check animation_step
  3242. if (animation_step > 0 &&
  3243. obj.values.animationCountOnSteps &&
  3244. obj.values.animationCountOnSteps[step] <= animation_step) {
  3245. animation_step = obj.values.animationCountOnSteps[step];
  3246. }
  3247. // jump to animation steps by calling flyToNextStep()
  3248. function doAnimationSteps() {
  3249. if (obj.values.isMoving == true) {
  3250. setTimeout(doAnimationSteps, 100); // wait until the flight ends
  3251. return;
  3252. }
  3253. while (animation_step-- > 0) {
  3254. obj.flyToNextStep(); // do the animation steps
  3255. }
  3256. }
  3257. setTimeout(doAnimationSteps, 200); // 200ms is the internal "reporting" time
  3258. // jump to the step
  3259. return this.sendMessage({
  3260. 'action': 'present',
  3261. 'data': ['moveToStep', step]
  3262. });
  3263. };
  3264. PreziPlayer.prototype.toObject = /* toObject is DEPRECATED */
  3265. PreziPlayer.prototype.flyToObject = function(objectId) {
  3266. return this.sendMessage({
  3267. 'action': 'present',
  3268. 'data': ['moveToObject', objectId]
  3269. });
  3270. };
  3271. PreziPlayer.prototype.play = function(defaultDelay) {
  3272. return this.sendMessage({
  3273. 'action': 'present',
  3274. 'data': ['startAutoPlay', defaultDelay]
  3275. });
  3276. };
  3277. PreziPlayer.prototype.stop = function() {
  3278. return this.sendMessage({
  3279. 'action': 'present',
  3280. 'data': ['stopAutoPlay']
  3281. });
  3282. };
  3283. PreziPlayer.prototype.pause = function(defaultDelay) {
  3284. return this.sendMessage({
  3285. 'action': 'present',
  3286. 'data': ['pauseAutoPlay', defaultDelay]
  3287. });
  3288. };
  3289. PreziPlayer.prototype.getCurrentStep = function() {
  3290. return this.values.currentStep;
  3291. };
  3292. PreziPlayer.prototype.getCurrentAnimationStep = function() {
  3293. return this.values.currentAnimationStep;
  3294. };
  3295. PreziPlayer.prototype.getCurrentObject = function() {
  3296. return this.values.currentObject;
  3297. };
  3298. PreziPlayer.prototype.getStatus = function() {
  3299. return this.values.status;
  3300. };
  3301. PreziPlayer.prototype.isPlaying = function() {
  3302. return this.values.isAutoPlaying;
  3303. };
  3304. PreziPlayer.prototype.getStepCount = function() {
  3305. return this.values.stepCount;
  3306. };
  3307. PreziPlayer.prototype.getAnimationCountOnSteps = function() {
  3308. return this.values.animationCountOnSteps;
  3309. };
  3310. PreziPlayer.prototype.getTitle = function() {
  3311. return this.values.title;
  3312. };
  3313. PreziPlayer.prototype.setDimensions = function(dims) {
  3314. for (var parameter in dims) {
  3315. this.iframe[parameter] = dims[parameter];
  3316. }
  3317. }
  3318. PreziPlayer.prototype.getDimensions = function() {
  3319. return {
  3320. width: parseInt(this.iframe.width, 10),
  3321. height: parseInt(this.iframe.height, 10)
  3322. }
  3323. }
  3324. PreziPlayer.prototype.on = function(event, callback) {
  3325. this.callbacks.push({
  3326. event: event,
  3327. callback: callback
  3328. });
  3329. };
  3330. PreziPlayer.prototype.off = function(event, callback) {
  3331. var j, item;
  3332. if (event === undefined) {
  3333. this.callbacks = [];
  3334. }
  3335. j = this.callbacks.length;
  3336. while (j--) {
  3337. item = this.callbacks[j];
  3338. if (item && item.event === event && (callback === undefined || item.callback === callback)){
  3339. this.callbacks.splice(j, 1);
  3340. }
  3341. }
  3342. };
  3343. if (window.addEventListener) {
  3344. window.addEventListener('message', PreziPlayer.messageReceived, false);
  3345. } else {
  3346. window.attachEvent('onmessage', PreziPlayer.messageReceived);
  3347. }
  3348. return PreziPlayer;
  3349. })();
  3350. })();
  3351. module.exports = PreziPlayer;
  3352. },{}],17:[function(require,module,exports){
  3353. var Chat = require("./chat/Chat");
  3354. var ContactList = require("./contactlist/ContactList");
  3355. var Settings = require("./../../settings/Settings");
  3356. var SettingsMenu = require("./settings/SettingsMenu");
  3357. var VideoLayout = require("../videolayout/VideoLayout");
  3358. var ToolbarToggler = require("../toolbars/ToolbarToggler");
  3359. var UIUtil = require("../util/UIUtil");
  3360. /**
  3361. * Toggler for the chat, contact list, settings menu, etc..
  3362. */
  3363. var PanelToggler = (function(my) {
  3364. var currentlyOpen = null;
  3365. var buttons = {
  3366. '#chatspace': '#chatBottomButton',
  3367. '#contactlist': '#contactListButton',
  3368. '#settingsmenu': '#settingsButton'
  3369. };
  3370. /**
  3371. * Resizes the video area
  3372. * @param isClosing whether the side panel is going to be closed or is going to open / remain opened
  3373. * @param completeFunction a function to be called when the video space is resized
  3374. */
  3375. var resizeVideoArea = function(isClosing, completeFunction) {
  3376. var videospace = $('#videospace');
  3377. var panelSize = isClosing ? [0, 0] : PanelToggler.getPanelSize();
  3378. var videospaceWidth = window.innerWidth - panelSize[0];
  3379. var videospaceHeight = window.innerHeight;
  3380. var videoSize
  3381. = VideoLayout.getVideoSize(null, null, videospaceWidth, videospaceHeight);
  3382. var videoWidth = videoSize[0];
  3383. var videoHeight = videoSize[1];
  3384. var videoPosition = VideoLayout.getVideoPosition(videoWidth,
  3385. videoHeight,
  3386. videospaceWidth,
  3387. videospaceHeight);
  3388. var horizontalIndent = videoPosition[0];
  3389. var verticalIndent = videoPosition[1];
  3390. var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
  3391. var thumbnailsWidth = thumbnailSize[0];
  3392. var thumbnailsHeight = thumbnailSize[1];
  3393. //for chat
  3394. videospace.animate({
  3395. right: panelSize[0],
  3396. width: videospaceWidth,
  3397. height: videospaceHeight
  3398. },
  3399. {
  3400. queue: false,
  3401. duration: 500,
  3402. complete: completeFunction
  3403. });
  3404. $('#remoteVideos').animate({
  3405. height: thumbnailsHeight
  3406. },
  3407. {
  3408. queue: false,
  3409. duration: 500
  3410. });
  3411. $('#remoteVideos>span').animate({
  3412. height: thumbnailsHeight,
  3413. width: thumbnailsWidth
  3414. },
  3415. {
  3416. queue: false,
  3417. duration: 500,
  3418. complete: function () {
  3419. $(document).trigger(
  3420. "remotevideo.resized",
  3421. [thumbnailsWidth,
  3422. thumbnailsHeight]);
  3423. }
  3424. });
  3425. $('#largeVideoContainer').animate({
  3426. width: videospaceWidth,
  3427. height: videospaceHeight
  3428. },
  3429. {
  3430. queue: false,
  3431. duration: 500
  3432. });
  3433. $('#largeVideo').animate({
  3434. width: videoWidth,
  3435. height: videoHeight,
  3436. top: verticalIndent,
  3437. bottom: verticalIndent,
  3438. left: horizontalIndent,
  3439. right: horizontalIndent
  3440. },
  3441. {
  3442. queue: false,
  3443. duration: 500
  3444. });
  3445. };
  3446. /**
  3447. * Toggles the windows in the side panel
  3448. * @param object the window that should be shown
  3449. * @param selector the selector for the element containing the panel
  3450. * @param onOpenComplete function to be called when the panel is opened
  3451. * @param onOpen function to be called if the window is going to be opened
  3452. * @param onClose function to be called if the window is going to be closed
  3453. */
  3454. var toggle = function(object, selector, onOpenComplete, onOpen, onClose) {
  3455. UIUtil.buttonClick(buttons[selector], "active");
  3456. if (object.isVisible()) {
  3457. $("#toast-container").animate({
  3458. right: '5px'
  3459. },
  3460. {
  3461. queue: false,
  3462. duration: 500
  3463. });
  3464. $(selector).hide("slide", {
  3465. direction: "right",
  3466. queue: false,
  3467. duration: 500
  3468. });
  3469. if(typeof onClose === "function") {
  3470. onClose();
  3471. }
  3472. currentlyOpen = null;
  3473. }
  3474. else {
  3475. // Undock the toolbar when the chat is shown and if we're in a
  3476. // video mode.
  3477. if (VideoLayout.isLargeVideoVisible()) {
  3478. ToolbarToggler.dockToolbar(false);
  3479. }
  3480. if(currentlyOpen) {
  3481. var current = $(currentlyOpen);
  3482. UIUtil.buttonClick(buttons[currentlyOpen], "active");
  3483. current.css('z-index', 4);
  3484. setTimeout(function () {
  3485. current.css('display', 'none');
  3486. current.css('z-index', 5);
  3487. }, 500);
  3488. }
  3489. $("#toast-container").animate({
  3490. right: (PanelToggler.getPanelSize()[0] + 5) + 'px'
  3491. },
  3492. {
  3493. queue: false,
  3494. duration: 500
  3495. });
  3496. $(selector).show("slide", {
  3497. direction: "right",
  3498. queue: false,
  3499. duration: 500,
  3500. complete: onOpenComplete
  3501. });
  3502. if(typeof onOpen === "function") {
  3503. onOpen();
  3504. }
  3505. currentlyOpen = selector;
  3506. }
  3507. };
  3508. /**
  3509. * Opens / closes the chat area.
  3510. */
  3511. my.toggleChat = function() {
  3512. var chatCompleteFunction = Chat.isVisible() ?
  3513. function() {} : function () {
  3514. Chat.scrollChatToBottom();
  3515. $('#chatspace').trigger('shown');
  3516. };
  3517. resizeVideoArea(Chat.isVisible(), chatCompleteFunction);
  3518. toggle(Chat,
  3519. '#chatspace',
  3520. function () {
  3521. // Request the focus in the nickname field or the chat input field.
  3522. if ($('#nickname').css('visibility') === 'visible') {
  3523. $('#nickinput').focus();
  3524. } else {
  3525. $('#usermsg').focus();
  3526. }
  3527. },
  3528. null,
  3529. Chat.resizeChat,
  3530. null);
  3531. };
  3532. /**
  3533. * Opens / closes the contact list area.
  3534. */
  3535. my.toggleContactList = function () {
  3536. var completeFunction = ContactList.isVisible() ?
  3537. function() {} : function () { $('#contactlist').trigger('shown');};
  3538. resizeVideoArea(ContactList.isVisible(), completeFunction);
  3539. toggle(ContactList,
  3540. '#contactlist',
  3541. null,
  3542. function() {
  3543. ContactList.setVisualNotification(false);
  3544. },
  3545. null);
  3546. };
  3547. /**
  3548. * Opens / closes the settings menu
  3549. */
  3550. my.toggleSettingsMenu = function() {
  3551. resizeVideoArea(SettingsMenu.isVisible(), function (){});
  3552. toggle(SettingsMenu,
  3553. '#settingsmenu',
  3554. null,
  3555. function() {
  3556. var settings = Settings.getSettings();
  3557. $('#setDisplayName').get(0).value = settings.displayName;
  3558. $('#setEmail').get(0).value = settings.email;
  3559. },
  3560. null);
  3561. };
  3562. /**
  3563. * Returns the size of the side panel.
  3564. */
  3565. my.getPanelSize = function () {
  3566. var availableHeight = window.innerHeight;
  3567. var availableWidth = window.innerWidth;
  3568. var panelWidth = 200;
  3569. if (availableWidth * 0.2 < 200) {
  3570. panelWidth = availableWidth * 0.2;
  3571. }
  3572. return [panelWidth, availableHeight];
  3573. };
  3574. my.isVisible = function() {
  3575. return (Chat.isVisible() || ContactList.isVisible() || SettingsMenu.isVisible());
  3576. };
  3577. return my;
  3578. }(PanelToggler || {}));
  3579. module.exports = PanelToggler;
  3580. },{"../toolbars/ToolbarToggler":26,"../util/UIUtil":30,"../videolayout/VideoLayout":32,"./../../settings/Settings":38,"./chat/Chat":18,"./contactlist/ContactList":22,"./settings/SettingsMenu":23}],18:[function(require,module,exports){
  3581. /* global $, Util, nickname:true */
  3582. var Replacement = require("./Replacement");
  3583. var CommandsProcessor = require("./Commands");
  3584. var ToolbarToggler = require("../../toolbars/ToolbarToggler");
  3585. var smileys = require("./smileys.json").smileys;
  3586. var NicknameHandler = require("../../util/NicknameHandler");
  3587. var UIUtil = require("../../util/UIUtil");
  3588. var UIEvents = require("../../../../service/UI/UIEvents");
  3589. var notificationInterval = false;
  3590. var unreadMessages = 0;
  3591. /**
  3592. * Shows/hides a visual notification, indicating that a message has arrived.
  3593. */
  3594. function setVisualNotification(show) {
  3595. var unreadMsgElement = document.getElementById('unreadMessages');
  3596. var unreadMsgBottomElement
  3597. = document.getElementById('bottomUnreadMessages');
  3598. var glower = $('#chatButton');
  3599. var bottomGlower = $('#chatBottomButton');
  3600. if (unreadMessages) {
  3601. unreadMsgElement.innerHTML = unreadMessages.toString();
  3602. unreadMsgBottomElement.innerHTML = unreadMessages.toString();
  3603. ToolbarToggler.dockToolbar(true);
  3604. var chatButtonElement
  3605. = document.getElementById('chatButton').parentNode;
  3606. var leftIndent = (UIUtil.getTextWidth(chatButtonElement) -
  3607. UIUtil.getTextWidth(unreadMsgElement)) / 2;
  3608. var topIndent = (UIUtil.getTextHeight(chatButtonElement) -
  3609. UIUtil.getTextHeight(unreadMsgElement)) / 2 - 3;
  3610. unreadMsgElement.setAttribute(
  3611. 'style',
  3612. 'top:' + topIndent +
  3613. '; left:' + leftIndent + ';');
  3614. var chatBottomButtonElement
  3615. = document.getElementById('chatBottomButton').parentNode;
  3616. var bottomLeftIndent = (UIUtil.getTextWidth(chatBottomButtonElement) -
  3617. UIUtil.getTextWidth(unreadMsgBottomElement)) / 2;
  3618. var bottomTopIndent = (UIUtil.getTextHeight(chatBottomButtonElement) -
  3619. UIUtil.getTextHeight(unreadMsgBottomElement)) / 2 - 2;
  3620. unreadMsgBottomElement.setAttribute(
  3621. 'style',
  3622. 'top:' + bottomTopIndent +
  3623. '; left:' + bottomLeftIndent + ';');
  3624. if (!glower.hasClass('icon-chat-simple')) {
  3625. glower.removeClass('icon-chat');
  3626. glower.addClass('icon-chat-simple');
  3627. }
  3628. }
  3629. else {
  3630. unreadMsgElement.innerHTML = '';
  3631. unreadMsgBottomElement.innerHTML = '';
  3632. glower.removeClass('icon-chat-simple');
  3633. glower.addClass('icon-chat');
  3634. }
  3635. if (show && !notificationInterval) {
  3636. notificationInterval = window.setInterval(function () {
  3637. glower.toggleClass('active');
  3638. bottomGlower.toggleClass('active glowing');
  3639. }, 800);
  3640. }
  3641. else if (!show && notificationInterval) {
  3642. window.clearInterval(notificationInterval);
  3643. notificationInterval = false;
  3644. glower.removeClass('active');
  3645. bottomGlower.removeClass('glowing');
  3646. bottomGlower.addClass('active');
  3647. }
  3648. }
  3649. /**
  3650. * Returns the current time in the format it is shown to the user
  3651. * @returns {string}
  3652. */
  3653. function getCurrentTime() {
  3654. var now = new Date();
  3655. var hour = now.getHours();
  3656. var minute = now.getMinutes();
  3657. var second = now.getSeconds();
  3658. if(hour.toString().length === 1) {
  3659. hour = '0'+hour;
  3660. }
  3661. if(minute.toString().length === 1) {
  3662. minute = '0'+minute;
  3663. }
  3664. if(second.toString().length === 1) {
  3665. second = '0'+second;
  3666. }
  3667. return hour+':'+minute+':'+second;
  3668. }
  3669. function toggleSmileys()
  3670. {
  3671. var smileys = $('#smileysContainer');
  3672. if(!smileys.is(':visible')) {
  3673. smileys.show("slide", { direction: "down", duration: 300});
  3674. } else {
  3675. smileys.hide("slide", { direction: "down", duration: 300});
  3676. }
  3677. $('#usermsg').focus();
  3678. }
  3679. function addClickFunction(smiley, number) {
  3680. smiley.onclick = function addSmileyToMessage() {
  3681. var usermsg = $('#usermsg');
  3682. var message = usermsg.val();
  3683. message += smileys['smiley' + number];
  3684. usermsg.val(message);
  3685. usermsg.get(0).setSelectionRange(message.length, message.length);
  3686. toggleSmileys();
  3687. usermsg.focus();
  3688. };
  3689. }
  3690. /**
  3691. * Adds the smileys container to the chat
  3692. */
  3693. function addSmileys() {
  3694. var smileysContainer = document.createElement('div');
  3695. smileysContainer.id = 'smileysContainer';
  3696. for(var i = 1; i <= 21; i++) {
  3697. var smileyContainer = document.createElement('div');
  3698. smileyContainer.id = 'smiley' + i;
  3699. smileyContainer.className = 'smileyContainer';
  3700. var smiley = document.createElement('img');
  3701. smiley.src = 'images/smileys/smiley' + i + '.svg';
  3702. smiley.className = 'smiley';
  3703. addClickFunction(smiley, i);
  3704. smileyContainer.appendChild(smiley);
  3705. smileysContainer.appendChild(smileyContainer);
  3706. }
  3707. $("#chatspace").append(smileysContainer);
  3708. }
  3709. /**
  3710. * Resizes the chat conversation.
  3711. */
  3712. function resizeChatConversation() {
  3713. var msgareaHeight = $('#usermsg').outerHeight();
  3714. var chatspace = $('#chatspace');
  3715. var width = chatspace.width();
  3716. var chat = $('#chatconversation');
  3717. var smileys = $('#smileysarea');
  3718. smileys.height(msgareaHeight);
  3719. $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
  3720. $('#smileysContainer').css('bottom', msgareaHeight);
  3721. chat.width(width - 10);
  3722. chat.height(window.innerHeight - 15 - msgareaHeight);
  3723. }
  3724. /**
  3725. * Chat related user interface.
  3726. */
  3727. var Chat = (function (my) {
  3728. /**
  3729. * Initializes chat related interface.
  3730. */
  3731. my.init = function () {
  3732. if(NicknameHandler.getNickname())
  3733. Chat.setChatConversationMode(true);
  3734. NicknameHandler.addListener(UIEvents.NICKNAME_CHANGED,
  3735. function (nickname) {
  3736. Chat.setChatConversationMode(true);
  3737. });
  3738. $('#nickinput').keydown(function (event) {
  3739. if (event.keyCode === 13) {
  3740. event.preventDefault();
  3741. var val = UIUtil.escapeHtml(this.value);
  3742. this.value = '';
  3743. if (!NicknameHandler.getNickname()) {
  3744. NicknameHandler.setNickname(val);
  3745. return;
  3746. }
  3747. }
  3748. });
  3749. $('#usermsg').keydown(function (event) {
  3750. if (event.keyCode === 13) {
  3751. event.preventDefault();
  3752. var value = this.value;
  3753. $('#usermsg').val('').trigger('autosize.resize');
  3754. this.focus();
  3755. var command = new CommandsProcessor(value);
  3756. if(command.isCommand())
  3757. {
  3758. command.processCommand();
  3759. }
  3760. else
  3761. {
  3762. var message = UIUtil.escapeHtml(value);
  3763. APP.xmpp.sendChatMessage(message, NicknameHandler.getNickname());
  3764. }
  3765. }
  3766. });
  3767. var onTextAreaResize = function () {
  3768. resizeChatConversation();
  3769. Chat.scrollChatToBottom();
  3770. };
  3771. $('#usermsg').autosize({callback: onTextAreaResize});
  3772. $("#chatspace").bind("shown",
  3773. function () {
  3774. unreadMessages = 0;
  3775. setVisualNotification(false);
  3776. });
  3777. addSmileys();
  3778. };
  3779. /**
  3780. * Appends the given message to the chat conversation.
  3781. */
  3782. my.updateChatConversation = function (from, displayName, message) {
  3783. var divClassName = '';
  3784. if (APP.xmpp.myJid() === from) {
  3785. divClassName = "localuser";
  3786. }
  3787. else {
  3788. divClassName = "remoteuser";
  3789. if (!Chat.isVisible()) {
  3790. unreadMessages++;
  3791. UIUtil.playSoundNotification('chatNotification');
  3792. setVisualNotification(true);
  3793. }
  3794. }
  3795. // replace links and smileys
  3796. // Strophe already escapes special symbols on sending,
  3797. // so we escape here only tags to avoid double &amp;
  3798. var escMessage = message.replace(/</g, '&lt;').
  3799. replace(/>/g, '&gt;').replace(/\n/g, '<br/>');
  3800. var escDisplayName = UIUtil.escapeHtml(displayName);
  3801. message = Replacement.processReplacements(escMessage);
  3802. var messageContainer =
  3803. '<div class="chatmessage">'+
  3804. '<img src="../images/chatArrow.svg" class="chatArrow">' +
  3805. '<div class="username ' + divClassName +'">' + escDisplayName +
  3806. '</div>' + '<div class="timestamp">' + getCurrentTime() +
  3807. '</div>' + '<div class="usermessage">' + message + '</div>' +
  3808. '</div>';
  3809. $('#chatconversation').append(messageContainer);
  3810. $('#chatconversation').animate(
  3811. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  3812. };
  3813. /**
  3814. * Appends error message to the conversation
  3815. * @param errorMessage the received error message.
  3816. * @param originalText the original message.
  3817. */
  3818. my.chatAddError = function(errorMessage, originalText)
  3819. {
  3820. errorMessage = UIUtil.escapeHtml(errorMessage);
  3821. originalText = UIUtil.escapeHtml(originalText);
  3822. $('#chatconversation').append(
  3823. '<div class="errorMessage"><b>Error: </b>' + 'Your message' +
  3824. (originalText? (' \"'+ originalText + '\"') : "") +
  3825. ' was not sent.' +
  3826. (errorMessage? (' Reason: ' + errorMessage) : '') + '</div>');
  3827. $('#chatconversation').animate(
  3828. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  3829. };
  3830. /**
  3831. * Sets the subject to the UI
  3832. * @param subject the subject
  3833. */
  3834. my.chatSetSubject = function(subject)
  3835. {
  3836. if(subject)
  3837. subject = subject.trim();
  3838. $('#subject').html(Replacement.linkify(UIUtil.escapeHtml(subject)));
  3839. if(subject === "")
  3840. {
  3841. $("#subject").css({display: "none"});
  3842. }
  3843. else
  3844. {
  3845. $("#subject").css({display: "block"});
  3846. }
  3847. };
  3848. /**
  3849. * Sets the chat conversation mode.
  3850. */
  3851. my.setChatConversationMode = function (isConversationMode) {
  3852. if (isConversationMode) {
  3853. $('#nickname').css({visibility: 'hidden'});
  3854. $('#chatconversation').css({visibility: 'visible'});
  3855. $('#usermsg').css({visibility: 'visible'});
  3856. $('#smileysarea').css({visibility: 'visible'});
  3857. $('#usermsg').focus();
  3858. }
  3859. };
  3860. /**
  3861. * Resizes the chat area.
  3862. */
  3863. my.resizeChat = function () {
  3864. var chatSize = require("../SidePanelToggler").getPanelSize();
  3865. $('#chatspace').width(chatSize[0]);
  3866. $('#chatspace').height(chatSize[1]);
  3867. resizeChatConversation();
  3868. };
  3869. /**
  3870. * Indicates if the chat is currently visible.
  3871. */
  3872. my.isVisible = function () {
  3873. return $('#chatspace').is(":visible");
  3874. };
  3875. /**
  3876. * Shows and hides the window with the smileys
  3877. */
  3878. my.toggleSmileys = toggleSmileys;
  3879. /**
  3880. * Scrolls chat to the bottom.
  3881. */
  3882. my.scrollChatToBottom = function() {
  3883. setTimeout(function () {
  3884. $('#chatconversation').scrollTop(
  3885. $('#chatconversation')[0].scrollHeight);
  3886. }, 5);
  3887. };
  3888. return my;
  3889. }(Chat || {}));
  3890. module.exports = Chat;
  3891. },{"../../../../service/UI/UIEvents":92,"../../toolbars/ToolbarToggler":26,"../../util/NicknameHandler":29,"../../util/UIUtil":30,"../SidePanelToggler":17,"./Commands":19,"./Replacement":20,"./smileys.json":21}],19:[function(require,module,exports){
  3892. var UIUtil = require("../../util/UIUtil");
  3893. /**
  3894. * List with supported commands. The keys are the names of the commands and
  3895. * the value is the function that processes the message.
  3896. * @type {{String: function}}
  3897. */
  3898. var commands = {
  3899. "topic" : processTopic
  3900. };
  3901. /**
  3902. * Extracts the command from the message.
  3903. * @param message the received message
  3904. * @returns {string} the command
  3905. */
  3906. function getCommand(message)
  3907. {
  3908. if(message)
  3909. {
  3910. for(var command in commands)
  3911. {
  3912. if(message.indexOf("/" + command) == 0)
  3913. return command;
  3914. }
  3915. }
  3916. return "";
  3917. };
  3918. /**
  3919. * Processes the data for topic command.
  3920. * @param commandArguments the arguments of the topic command.
  3921. */
  3922. function processTopic(commandArguments)
  3923. {
  3924. var topic = UIUtil.escapeHtml(commandArguments);
  3925. APP.xmpp.setSubject(topic);
  3926. }
  3927. /**
  3928. * Constructs new CommandProccessor instance from a message that
  3929. * handles commands received via chat messages.
  3930. * @param message the message
  3931. * @constructor
  3932. */
  3933. function CommandsProcessor(message)
  3934. {
  3935. var command = getCommand(message);
  3936. /**
  3937. * Returns the name of the command.
  3938. * @returns {String} the command
  3939. */
  3940. this.getCommand = function()
  3941. {
  3942. return command;
  3943. };
  3944. var messageArgument = message.substr(command.length + 2);
  3945. /**
  3946. * Returns the arguments of the command.
  3947. * @returns {string}
  3948. */
  3949. this.getArgument = function()
  3950. {
  3951. return messageArgument;
  3952. };
  3953. }
  3954. /**
  3955. * Checks whether this instance is valid command or not.
  3956. * @returns {boolean}
  3957. */
  3958. CommandsProcessor.prototype.isCommand = function()
  3959. {
  3960. if(this.getCommand())
  3961. return true;
  3962. return false;
  3963. };
  3964. /**
  3965. * Processes the command.
  3966. */
  3967. CommandsProcessor.prototype.processCommand = function()
  3968. {
  3969. if(!this.isCommand())
  3970. return;
  3971. commands[this.getCommand()](this.getArgument());
  3972. };
  3973. module.exports = CommandsProcessor;
  3974. },{"../../util/UIUtil":30}],20:[function(require,module,exports){
  3975. var Smileys = require("./smileys.json");
  3976. /**
  3977. * Processes links and smileys in "body"
  3978. */
  3979. function processReplacements(body)
  3980. {
  3981. //make links clickable
  3982. body = linkify(body);
  3983. //add smileys
  3984. body = smilify(body);
  3985. return body;
  3986. }
  3987. /**
  3988. * Finds and replaces all links in the links in "body"
  3989. * with their <a href=""></a>
  3990. */
  3991. function linkify(inputText)
  3992. {
  3993. var replacedText, replacePattern1, replacePattern2, replacePattern3;
  3994. //URLs starting with http://, https://, or ftp://
  3995. replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
  3996. replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');
  3997. //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
  3998. replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
  3999. replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');
  4000. //Change email addresses to mailto:: links.
  4001. replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
  4002. replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
  4003. return replacedText;
  4004. }
  4005. /**
  4006. * Replaces common smiley strings with images
  4007. */
  4008. function smilify(body)
  4009. {
  4010. if(!body) {
  4011. return body;
  4012. }
  4013. var regexs = Smileys["regexs"];
  4014. for(var smiley in regexs) {
  4015. if(regexs.hasOwnProperty(smiley)) {
  4016. body = body.replace(regexs[smiley],
  4017. '<img class="smiley" src="images/smileys/' + smiley + '.svg">');
  4018. }
  4019. }
  4020. return body;
  4021. }
  4022. module.exports = {
  4023. processReplacements: processReplacements,
  4024. linkify: linkify
  4025. };
  4026. },{"./smileys.json":21}],21:[function(require,module,exports){
  4027. module.exports={
  4028. "smileys": {
  4029. "smiley1": ":)",
  4030. "smiley2": ":(",
  4031. "smiley3": ":D",
  4032. "smiley4": "(y)",
  4033. "smiley5": " :P",
  4034. "smiley6": "(wave)",
  4035. "smiley7": "(blush)",
  4036. "smiley8": "(chuckle)",
  4037. "smiley9": "(shocked)",
  4038. "smiley10": ":*",
  4039. "smiley11": "(n)",
  4040. "smiley12": "(search)",
  4041. "smiley13": " <3",
  4042. "smiley14": "(oops)",
  4043. "smiley15": "(angry)",
  4044. "smiley16": "(angel)",
  4045. "smiley17": "(sick)",
  4046. "smiley18": ";(",
  4047. "smiley19": "(bomb)",
  4048. "smiley20": "(clap)",
  4049. "smiley21": " ;)"
  4050. },
  4051. "regexs": {
  4052. "smiley2": /(:-\(\(|:-\(|:\(\(|:\(|\(sad\))/gi,
  4053. "smiley3": /(:-\)\)|:\)\)|\(lol\)|:-D|:D)/gi,
  4054. "smiley1": /(:-\)|:\))/gi,
  4055. "smiley4": /(\(y\)|\(Y\)|\(ok\))/gi,
  4056. "smiley5": /(:-P|:P|:-p|:p)/gi,
  4057. "smiley6": /(\(wave\))/gi,
  4058. "smiley7": /(\(blush\))/gi,
  4059. "smiley8": /(\(chuckle\))/gi,
  4060. "smiley9": /(:-0|\(shocked\))/gi,
  4061. "smiley10": /(:-\*|:\*|\(kiss\))/gi,
  4062. "smiley11": /(\(n\))/gi,
  4063. "smiley12": /(\(search\))/g,
  4064. "smiley13": /(<3|&lt;3|&amp;lt;3|\(L\)|\(l\)|\(H\)|\(h\))/gi,
  4065. "smiley14": /(\(oops\))/gi,
  4066. "smiley15": /(\(angry\))/gi,
  4067. "smiley16": /(\(angel\))/gi,
  4068. "smiley17": /(\(sick\))/gi,
  4069. "smiley18": /(;-\(\(|;\(\(|;-\(|;\(|:"\(|:"-\(|:~-\(|:~\(|\(upset\))/gi,
  4070. "smiley19": /(\(bomb\))/gi,
  4071. "smiley20": /(\(clap\))/gi,
  4072. "smiley21": /(;-\)|;\)|;-\)\)|;\)\)|;-D|;D|\(wink\))/gi
  4073. }
  4074. }
  4075. },{}],22:[function(require,module,exports){
  4076. var numberOfContacts = 0;
  4077. var notificationInterval;
  4078. /**
  4079. * Updates the number of participants in the contact list button and sets
  4080. * the glow
  4081. * @param delta indicates whether a new user has joined (1) or someone has
  4082. * left(-1)
  4083. */
  4084. function updateNumberOfParticipants(delta) {
  4085. //when the user is alone we don't show the number of participants
  4086. if(numberOfContacts === 0) {
  4087. $("#numberOfParticipants").text('');
  4088. numberOfContacts += delta;
  4089. } else if(numberOfContacts !== 0 && !ContactList.isVisible()) {
  4090. ContactList.setVisualNotification(true);
  4091. numberOfContacts += delta;
  4092. $("#numberOfParticipants").text(numberOfContacts);
  4093. }
  4094. }
  4095. /**
  4096. * Creates the avatar element.
  4097. *
  4098. * @return the newly created avatar element
  4099. */
  4100. function createAvatar(id) {
  4101. var avatar = document.createElement('img');
  4102. avatar.className = "icon-avatar avatar";
  4103. avatar.src = "https://www.gravatar.com/avatar/" + id + "?d=wavatar&size=30";
  4104. return avatar;
  4105. }
  4106. /**
  4107. * Creates the display name paragraph.
  4108. *
  4109. * @param displayName the display name to set
  4110. */
  4111. function createDisplayNameParagraph(key, displayName) {
  4112. var p = document.createElement('p');
  4113. if(displayName)
  4114. p.innerText = displayName;
  4115. else if(key)
  4116. {
  4117. p.setAttribute("data-i18n",key);
  4118. p.innerText = APP.translation.translateString(key);
  4119. }
  4120. return p;
  4121. }
  4122. function stopGlowing(glower) {
  4123. window.clearInterval(notificationInterval);
  4124. notificationInterval = false;
  4125. glower.removeClass('glowing');
  4126. if (!ContactList.isVisible()) {
  4127. glower.removeClass('active');
  4128. }
  4129. }
  4130. /**
  4131. * Contact list.
  4132. */
  4133. var ContactList = {
  4134. /**
  4135. * Indicates if the chat is currently visible.
  4136. *
  4137. * @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
  4138. * otherwise
  4139. */
  4140. isVisible: function () {
  4141. return $('#contactlist').is(":visible");
  4142. },
  4143. /**
  4144. * Adds a contact for the given peerJid if such doesn't yet exist.
  4145. *
  4146. * @param peerJid the peerJid corresponding to the contact
  4147. * @param id the user's email or userId used to get the user's avatar
  4148. */
  4149. ensureAddContact: function (peerJid, id) {
  4150. var resourceJid = Strophe.getResourceFromJid(peerJid);
  4151. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  4152. if (!contact || contact.length <= 0)
  4153. ContactList.addContact(peerJid, id);
  4154. },
  4155. /**
  4156. * Adds a contact for the given peer jid.
  4157. *
  4158. * @param peerJid the jid of the contact to add
  4159. * @param id the email or userId of the user
  4160. */
  4161. addContact: function (peerJid, id) {
  4162. var resourceJid = Strophe.getResourceFromJid(peerJid);
  4163. var contactlist = $('#contactlist>ul');
  4164. var newContact = document.createElement('li');
  4165. newContact.id = resourceJid;
  4166. newContact.className = "clickable";
  4167. newContact.onclick = function (event) {
  4168. if (event.currentTarget.className === "clickable") {
  4169. $(ContactList).trigger('contactclicked', [peerJid]);
  4170. }
  4171. };
  4172. newContact.appendChild(createAvatar(id));
  4173. newContact.appendChild(createDisplayNameParagraph("participant"));
  4174. var clElement = contactlist.get(0);
  4175. if (resourceJid === APP.xmpp.myResource()
  4176. && $('#contactlist>ul .title')[0].nextSibling.nextSibling) {
  4177. clElement.insertBefore(newContact,
  4178. $('#contactlist>ul .title')[0].nextSibling.nextSibling);
  4179. }
  4180. else {
  4181. clElement.appendChild(newContact);
  4182. }
  4183. updateNumberOfParticipants(1);
  4184. },
  4185. /**
  4186. * Removes a contact for the given peer jid.
  4187. *
  4188. * @param peerJid the peerJid corresponding to the contact to remove
  4189. */
  4190. removeContact: function (peerJid) {
  4191. var resourceJid = Strophe.getResourceFromJid(peerJid);
  4192. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  4193. if (contact && contact.length > 0) {
  4194. var contactlist = $('#contactlist>ul');
  4195. contactlist.get(0).removeChild(contact.get(0));
  4196. updateNumberOfParticipants(-1);
  4197. }
  4198. },
  4199. setVisualNotification: function (show, stopGlowingIn) {
  4200. var glower = $('#contactListButton');
  4201. if (show && !notificationInterval) {
  4202. notificationInterval = window.setInterval(function () {
  4203. glower.toggleClass('active glowing');
  4204. }, 800);
  4205. }
  4206. else if (!show && notificationInterval) {
  4207. stopGlowing(glower);
  4208. }
  4209. if (stopGlowingIn) {
  4210. setTimeout(function () {
  4211. stopGlowing(glower);
  4212. }, stopGlowingIn);
  4213. }
  4214. },
  4215. setClickable: function (resourceJid, isClickable) {
  4216. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  4217. if (isClickable) {
  4218. contact.addClass('clickable');
  4219. } else {
  4220. contact.removeClass('clickable');
  4221. }
  4222. },
  4223. onDisplayNameChange: function (peerJid, displayName) {
  4224. if (peerJid === 'localVideoContainer')
  4225. peerJid = APP.xmpp.myJid();
  4226. var resourceJid = Strophe.getResourceFromJid(peerJid);
  4227. var contactName = $('#contactlist #' + resourceJid + '>p');
  4228. if (contactName && displayName && displayName.length > 0)
  4229. contactName.html(displayName);
  4230. }
  4231. };
  4232. module.exports = ContactList;
  4233. },{}],23:[function(require,module,exports){
  4234. var Avatar = require("../../avatar/Avatar");
  4235. var Settings = require("./../../../settings/Settings");
  4236. var UIUtil = require("../../util/UIUtil");
  4237. var languages = require("../../../../service/translation/languages");
  4238. function generateLanguagesSelectBox()
  4239. {
  4240. var currentLang = APP.translation.getCurrentLanguage();
  4241. var html = "<select id=\"languages_selectbox\">";
  4242. var langArray = languages.getLanguages();
  4243. for(var i = 0; i < langArray.length; i++)
  4244. {
  4245. var lang = langArray[i];
  4246. html += "<option ";
  4247. if(lang === currentLang)
  4248. html += "selected ";
  4249. html += "value=\"" + lang + "\" data-i18n='languages:" + lang + "'>";
  4250. html += "</option>";
  4251. }
  4252. return html + "</select>";
  4253. }
  4254. var SettingsMenu = {
  4255. init: function () {
  4256. $("#updateSettings").before(generateLanguagesSelectBox());
  4257. APP.translation.translateElement($("#languages_selectbox"));
  4258. $('#settingsmenu>input').keyup(function(event){
  4259. if(event.keyCode === 13) {//enter
  4260. SettingsMenu.update();
  4261. }
  4262. });
  4263. $("#updateSettings").click(function () {
  4264. SettingsMenu.update();
  4265. });
  4266. },
  4267. update: function() {
  4268. var newDisplayName = UIUtil.escapeHtml($('#setDisplayName').get(0).value);
  4269. var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value);
  4270. if(newDisplayName) {
  4271. var displayName = Settings.setDisplayName(newDisplayName);
  4272. APP.xmpp.addToPresence("displayName", displayName, true);
  4273. }
  4274. var language = $("#languages_selectbox").val();
  4275. APP.translation.setLanguage(language);
  4276. Settings.setLanguage(language);
  4277. APP.xmpp.addToPresence("email", newEmail);
  4278. var email = Settings.setEmail(newEmail);
  4279. Avatar.setUserAvatar(APP.xmpp.myJid(), email);
  4280. },
  4281. isVisible: function() {
  4282. return $('#settingsmenu').is(':visible');
  4283. },
  4284. setDisplayName: function(newDisplayName) {
  4285. var displayName = Settings.setDisplayName(newDisplayName);
  4286. $('#setDisplayName').get(0).value = displayName;
  4287. },
  4288. onDisplayNameChange: function(peerJid, newDisplayName) {
  4289. if(peerJid === 'localVideoContainer' ||
  4290. peerJid === APP.xmpp.myJid()) {
  4291. this.setDisplayName(newDisplayName);
  4292. }
  4293. }
  4294. };
  4295. module.exports = SettingsMenu;
  4296. },{"../../../../service/translation/languages":96,"../../avatar/Avatar":13,"../../util/UIUtil":30,"./../../../settings/Settings":38}],24:[function(require,module,exports){
  4297. var PanelToggler = require("../side_pannels/SidePanelToggler");
  4298. var buttonHandlers = {
  4299. "bottom_toolbar_contact_list": function () {
  4300. BottomToolbar.toggleContactList();
  4301. },
  4302. "bottom_toolbar_film_strip": function () {
  4303. BottomToolbar.toggleFilmStrip();
  4304. },
  4305. "bottom_toolbar_chat": function () {
  4306. BottomToolbar.toggleChat();
  4307. }
  4308. };
  4309. var BottomToolbar = (function (my) {
  4310. my.init = function () {
  4311. for(var k in buttonHandlers)
  4312. $("#" + k).click(buttonHandlers[k]);
  4313. };
  4314. my.toggleChat = function() {
  4315. PanelToggler.toggleChat();
  4316. };
  4317. my.toggleContactList = function() {
  4318. PanelToggler.toggleContactList();
  4319. };
  4320. my.toggleFilmStrip = function() {
  4321. var filmstrip = $("#remoteVideos");
  4322. filmstrip.toggleClass("hidden");
  4323. };
  4324. $(document).bind("remotevideo.resized", function (event, width, height) {
  4325. var bottom = (height - $('#bottomToolbar').outerHeight())/2 + 18;
  4326. $('#bottomToolbar').css({bottom: bottom + 'px'});
  4327. });
  4328. return my;
  4329. }(BottomToolbar || {}));
  4330. module.exports = BottomToolbar;
  4331. },{"../side_pannels/SidePanelToggler":17}],25:[function(require,module,exports){
  4332. /* global APP,$, buttonClick, config, lockRoom,
  4333. setSharedKey, Util */
  4334. var messageHandler = require("../util/MessageHandler");
  4335. var BottomToolbar = require("./BottomToolbar");
  4336. var Prezi = require("../prezi/Prezi");
  4337. var Etherpad = require("../etherpad/Etherpad");
  4338. var PanelToggler = require("../side_pannels/SidePanelToggler");
  4339. var Authentication = require("../authentication/Authentication");
  4340. var UIUtil = require("../util/UIUtil");
  4341. var AuthenticationEvents
  4342. = require("../../../service/authentication/AuthenticationEvents");
  4343. var roomUrl = null;
  4344. var sharedKey = '';
  4345. var UI = null;
  4346. var buttonHandlers =
  4347. {
  4348. "toolbar_button_mute": function () {
  4349. return APP.UI.toggleAudio();
  4350. },
  4351. "toolbar_button_camera": function () {
  4352. return APP.UI.toggleVideo();
  4353. },
  4354. /*"toolbar_button_authentication": function () {
  4355. return Toolbar.authenticateClicked();
  4356. },*/
  4357. "toolbar_button_record": function () {
  4358. return toggleRecording();
  4359. },
  4360. "toolbar_button_security": function () {
  4361. return Toolbar.openLockDialog();
  4362. },
  4363. "toolbar_button_link": function () {
  4364. return Toolbar.openLinkDialog();
  4365. },
  4366. "toolbar_button_chat": function () {
  4367. return BottomToolbar.toggleChat();
  4368. },
  4369. "toolbar_button_prezi": function () {
  4370. return Prezi.openPreziDialog();
  4371. },
  4372. "toolbar_button_etherpad": function () {
  4373. return Etherpad.toggleEtherpad(0);
  4374. },
  4375. "toolbar_button_desktopsharing": function () {
  4376. return APP.desktopsharing.toggleScreenSharing();
  4377. },
  4378. "toolbar_button_fullScreen": function()
  4379. {
  4380. UIUtil.buttonClick("#fullScreen", "icon-full-screen icon-exit-full-screen");
  4381. return Toolbar.toggleFullScreen();
  4382. },
  4383. "toolbar_button_sip": function () {
  4384. return callSipButtonClicked();
  4385. },
  4386. "toolbar_button_settings": function () {
  4387. PanelToggler.toggleSettingsMenu();
  4388. },
  4389. "toolbar_button_hangup": function () {
  4390. return hangup();
  4391. },
  4392. "toolbar_button_login": function () {
  4393. Toolbar.authenticateClicked();
  4394. },
  4395. "toolbar_button_logout": function () {
  4396. // Ask for confirmation
  4397. messageHandler.openTwoButtonDialog(
  4398. "dialog.logoutTitle",
  4399. null,
  4400. "dialog.logoutQuestion",
  4401. null,
  4402. false,
  4403. "dialog.Yes",
  4404. function (evt, yes) {
  4405. if (yes) {
  4406. APP.xmpp.logout(function (url) {
  4407. if (url) {
  4408. window.location.href = url;
  4409. } else {
  4410. hangup();
  4411. }
  4412. });
  4413. }
  4414. });
  4415. }
  4416. };
  4417. function hangup() {
  4418. APP.xmpp.disposeConference();
  4419. if(config.enableWelcomePage)
  4420. {
  4421. setTimeout(function()
  4422. {
  4423. window.localStorage.welcomePageDisabled = false;
  4424. window.location.pathname = "/";
  4425. }, 10000);
  4426. }
  4427. var title = APP.translation.generateTranslatonHTML(
  4428. "dialog.sessTerminated");
  4429. var msg = APP.translation.generateTranslatonHTML(
  4430. "dialog.hungUp");
  4431. var button = APP.translation.generateTranslatonHTML(
  4432. "dialog.joinAgain");
  4433. var buttons = [];
  4434. buttons.push({title: button, value: true});
  4435. UI.messageHandler.openDialog(
  4436. title,
  4437. msg,
  4438. true,
  4439. buttons,
  4440. function(event, value, message, formVals)
  4441. {
  4442. window.location.reload();
  4443. return false;
  4444. }
  4445. );
  4446. }
  4447. /**
  4448. * Starts or stops the recording for the conference.
  4449. */
  4450. function toggleRecording() {
  4451. APP.xmpp.toggleRecording(function (callback) {
  4452. var msg = APP.translation.generateTranslatonHTML(
  4453. "dialog.recordingToken");
  4454. var token = APP.translation.translateString("dialog.token");
  4455. APP.UI.messageHandler.openTwoButtonDialog(null, null, null,
  4456. '<h2>' + msg + '</h2>' +
  4457. '<input name="recordingToken" type="text" ' +
  4458. ' data-i18n="[placeholder]dialog.token" ' +
  4459. 'placeholder="' + token + '" autofocus>',
  4460. false,
  4461. "dialog.Save",
  4462. function (e, v, m, f) {
  4463. if (v) {
  4464. var token = f.recordingToken;
  4465. if (token) {
  4466. callback(UIUtil.escapeHtml(token));
  4467. }
  4468. }
  4469. },
  4470. null,
  4471. function () { },
  4472. ':input:first'
  4473. );
  4474. }, Toolbar.setRecordingButtonState, Toolbar.setRecordingButtonState);
  4475. }
  4476. /**
  4477. * Locks / unlocks the room.
  4478. */
  4479. function lockRoom(lock) {
  4480. var currentSharedKey = '';
  4481. if (lock)
  4482. currentSharedKey = sharedKey;
  4483. APP.xmpp.lockRoom(currentSharedKey, function (res) {
  4484. // password is required
  4485. if (sharedKey)
  4486. {
  4487. console.log('set room password');
  4488. Toolbar.lockLockButton();
  4489. }
  4490. else
  4491. {
  4492. console.log('removed room password');
  4493. Toolbar.unlockLockButton();
  4494. }
  4495. }, function (err) {
  4496. console.warn('setting password failed', err);
  4497. messageHandler.showError("dialog.lockTitle",
  4498. "dialog.lockMessage");
  4499. Toolbar.setSharedKey('');
  4500. }, function () {
  4501. console.warn('room passwords not supported');
  4502. messageHandler.showError("dialog.warning",
  4503. "dialog.passwordNotSupported");
  4504. Toolbar.setSharedKey('');
  4505. });
  4506. };
  4507. /**
  4508. * Invite participants to conference.
  4509. */
  4510. function inviteParticipants() {
  4511. if (roomUrl === null)
  4512. return;
  4513. var sharedKeyText = "";
  4514. if (sharedKey && sharedKey.length > 0) {
  4515. sharedKeyText =
  4516. APP.translation.translateString("email.sharedKey",
  4517. {sharedKey: sharedKey});
  4518. sharedKeyText = sharedKeyText.replace(/\n/g, "%0D%0A");
  4519. }
  4520. var supportedBrowsers = "Chromium, Google Chrome " +
  4521. APP.translation.translateString("email.and") + " Opera";
  4522. var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
  4523. var subject = APP.translation.translateString("email.subject",
  4524. {appName:interfaceConfig.APP_NAME, conferenceName: conferenceName});
  4525. var body = APP.translation.translateString("email.body",
  4526. {appName:interfaceConfig.APP_NAME, sharedKeyText: sharedKeyText,
  4527. roomUrl: roomUrl, supportedBrowsers: supportedBrowsers});
  4528. body = body.replace(/\n/g, "%0D%0A");
  4529. if (window.localStorage.displayname) {
  4530. body += "%0D%0A%0D%0A" + window.localStorage.displayname;
  4531. }
  4532. if (interfaceConfig.INVITATION_POWERED_BY) {
  4533. body += "%0D%0A%0D%0A--%0D%0Apowered by jitsi.org";
  4534. }
  4535. window.open("mailto:?subject=" + subject + "&body=" + body, '_blank');
  4536. }
  4537. function callSipButtonClicked()
  4538. {
  4539. var defaultNumber
  4540. = config.defaultSipNumber ? config.defaultSipNumber : '';
  4541. var sipMsg = APP.translation.generateTranslatonHTML(
  4542. "dialog.sipMsg");
  4543. messageHandler.openTwoButtonDialog(null, null, null,
  4544. '<h2>' + sipMsg + '</h2>' +
  4545. '<input name="sipNumber" type="text"' +
  4546. ' value="' + defaultNumber + '" autofocus>',
  4547. false,
  4548. "dialog.Dial",
  4549. function (e, v, m, f) {
  4550. if (v) {
  4551. var numberInput = f.sipNumber;
  4552. if (numberInput) {
  4553. APP.xmpp.dial(
  4554. numberInput, 'fromnumber', UI.getRoomName(), sharedKey);
  4555. }
  4556. }
  4557. },
  4558. null, null, ':input:first'
  4559. );
  4560. }
  4561. var Toolbar = (function (my) {
  4562. my.init = function (ui) {
  4563. for(var k in buttonHandlers)
  4564. $("#" + k).click(buttonHandlers[k]);
  4565. UI = ui;
  4566. // Update login info
  4567. APP.xmpp.addListener(
  4568. AuthenticationEvents.IDENTITY_UPDATED,
  4569. function (authenticationEnabled, userIdentity) {
  4570. var loggedIn = false;
  4571. if (userIdentity) {
  4572. loggedIn = true;
  4573. }
  4574. Toolbar.showAuthenticateButton(authenticationEnabled);
  4575. if (authenticationEnabled) {
  4576. Toolbar.setAuthenticatedIdentity(userIdentity);
  4577. Toolbar.showLoginButton(!loggedIn);
  4578. Toolbar.showLogoutButton(loggedIn);
  4579. }
  4580. }
  4581. );
  4582. },
  4583. /**
  4584. * Sets shared key
  4585. * @param sKey the shared key
  4586. */
  4587. my.setSharedKey = function (sKey) {
  4588. sharedKey = sKey;
  4589. };
  4590. my.authenticateClicked = function () {
  4591. Authentication.focusAuthenticationWindow();
  4592. if (!APP.xmpp.isExternalAuthEnabled()) {
  4593. Authentication.xmppAuthenticate();
  4594. return;
  4595. }
  4596. // Get authentication URL
  4597. if (!APP.xmpp.getMUCJoined()) {
  4598. APP.xmpp.getLoginUrl(UI.getRoomName(), function (url) {
  4599. // If conference has not been started yet - redirect to login page
  4600. window.location.href = url;
  4601. });
  4602. } else {
  4603. APP.xmpp.getPopupLoginUrl(UI.getRoomName(), function (url) {
  4604. // Otherwise - open popup with authentication URL
  4605. var authenticationWindow = Authentication.createAuthenticationWindow(
  4606. function () {
  4607. // On popup closed - retry room allocation
  4608. APP.xmpp.allocateConferenceFocus(
  4609. APP.UI.getRoomName(),
  4610. function () { console.info("AUTH DONE"); }
  4611. );
  4612. }, url);
  4613. if (!authenticationWindow) {
  4614. messageHandler.openMessageDialog(
  4615. null, "dialog.popupError");
  4616. }
  4617. });
  4618. }
  4619. };
  4620. /**
  4621. * Updates the room invite url.
  4622. */
  4623. my.updateRoomUrl = function (newRoomUrl) {
  4624. roomUrl = newRoomUrl;
  4625. // If the invite dialog has been already opened we update the information.
  4626. var inviteLink = document.getElementById('inviteLinkRef');
  4627. if (inviteLink) {
  4628. inviteLink.value = roomUrl;
  4629. inviteLink.select();
  4630. document.getElementById('jqi_state0_buttonInvite').disabled = false;
  4631. }
  4632. };
  4633. /**
  4634. * Disables and enables some of the buttons.
  4635. */
  4636. my.setupButtonsFromConfig = function () {
  4637. if (config.disablePrezi)
  4638. {
  4639. $("#prezi_button").css({display: "none"});
  4640. }
  4641. };
  4642. /**
  4643. * Opens the lock room dialog.
  4644. */
  4645. my.openLockDialog = function () {
  4646. // Only the focus is able to set a shared key.
  4647. if (!APP.xmpp.isModerator()) {
  4648. if (sharedKey) {
  4649. messageHandler.openMessageDialog(null,
  4650. "dialog.passwordError");
  4651. } else {
  4652. messageHandler.openMessageDialog(null, "dialog.passwordError2");
  4653. }
  4654. } else {
  4655. if (sharedKey) {
  4656. messageHandler.openTwoButtonDialog(null, null,
  4657. "dialog.passwordCheck",
  4658. null,
  4659. false,
  4660. "dialog.Remove",
  4661. function (e, v) {
  4662. if (v) {
  4663. Toolbar.setSharedKey('');
  4664. lockRoom(false);
  4665. }
  4666. });
  4667. } else {
  4668. var msg = APP.translation.generateTranslatonHTML(
  4669. "dialog.passwordMsg");
  4670. var yourPassword = APP.translation.translateString(
  4671. "dialog.yourPassword");
  4672. messageHandler.openTwoButtonDialog(null, null, null,
  4673. '<h2>' + msg + '</h2>' +
  4674. '<input name="lockKey" type="text"' +
  4675. ' data-i18n="[placeholder]dialog.yourPassword" ' +
  4676. 'placeholder="' + yourPassword + '" autofocus>',
  4677. false,
  4678. "dialog.Save",
  4679. function (e, v, m, f) {
  4680. if (v) {
  4681. var lockKey = f.lockKey;
  4682. if (lockKey) {
  4683. Toolbar.setSharedKey(
  4684. UIUtil.escapeHtml(lockKey));
  4685. lockRoom(true);
  4686. }
  4687. }
  4688. },
  4689. null, null, 'input:first'
  4690. );
  4691. }
  4692. }
  4693. };
  4694. /**
  4695. * Opens the invite link dialog.
  4696. */
  4697. my.openLinkDialog = function () {
  4698. var inviteAttreibutes;
  4699. if (roomUrl === null) {
  4700. inviteAttreibutes = 'data-i18n="[value]roomUrlDefaultMsg" value="' +
  4701. APP.translation.translateString("roomUrlDefaultMsg") + '"';
  4702. } else {
  4703. inviteAttreibutes = "value=\"" + encodeURI(roomUrl) + "\"";
  4704. }
  4705. messageHandler.openTwoButtonDialog("dialog.shareLink",
  4706. null, null,
  4707. '<input id="inviteLinkRef" type="text" ' +
  4708. inviteAttreibutes + ' onclick="this.select();" readonly>',
  4709. false,
  4710. "dialog.Invite",
  4711. function (e, v) {
  4712. if (v) {
  4713. if (roomUrl) {
  4714. inviteParticipants();
  4715. }
  4716. }
  4717. },
  4718. function () {
  4719. if (roomUrl) {
  4720. document.getElementById('inviteLinkRef').select();
  4721. } else {
  4722. document.getElementById('jqi_state0_buttonInvite')
  4723. .disabled = true;
  4724. }
  4725. }
  4726. );
  4727. };
  4728. /**
  4729. * Opens the settings dialog.
  4730. * FIXME: not used ?
  4731. */
  4732. my.openSettingsDialog = function () {
  4733. var settings1 = APP.translation.generateTranslatonHTML(
  4734. "dialog.settings1");
  4735. var settings2 = APP.translation.generateTranslatonHTML(
  4736. "dialog.settings2");
  4737. var settings3 = APP.translation.generateTranslatonHTML(
  4738. "dialog.settings3");
  4739. var yourPassword = APP.translation.translateString(
  4740. "dialog.yourPassword");
  4741. messageHandler.openTwoButtonDialog(null,
  4742. '<h2>' + settings1 + '</h2>' +
  4743. '<input type="checkbox" id="initMuted">' +
  4744. settings2 + '<br/>' +
  4745. '<input type="checkbox" id="requireNicknames">' +
  4746. settings3 +
  4747. '<input id="lockKey" type="text" placeholder="' + yourPassword +
  4748. '" data-i18n="[placeholder]dialog.yourPassword" autofocus>',
  4749. null,
  4750. null,
  4751. false,
  4752. "dialog.Save",
  4753. function () {
  4754. document.getElementById('lockKey').focus();
  4755. },
  4756. function (e, v) {
  4757. if (v) {
  4758. if ($('#initMuted').is(":checked")) {
  4759. // it is checked
  4760. }
  4761. if ($('#requireNicknames').is(":checked")) {
  4762. // it is checked
  4763. }
  4764. /*
  4765. var lockKey = document.getElementById('lockKey');
  4766. if (lockKey.value) {
  4767. setSharedKey(lockKey.value);
  4768. lockRoom(true);
  4769. }
  4770. */
  4771. }
  4772. }
  4773. );
  4774. };
  4775. /**
  4776. * Toggles the application in and out of full screen mode
  4777. * (a.k.a. presentation mode in Chrome).
  4778. */
  4779. my.toggleFullScreen = function () {
  4780. var fsElement = document.documentElement;
  4781. if (!document.mozFullScreen && !document.webkitIsFullScreen) {
  4782. //Enter Full Screen
  4783. if (fsElement.mozRequestFullScreen) {
  4784. fsElement.mozRequestFullScreen();
  4785. }
  4786. else {
  4787. fsElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
  4788. }
  4789. } else {
  4790. //Exit Full Screen
  4791. if (document.mozCancelFullScreen) {
  4792. document.mozCancelFullScreen();
  4793. } else {
  4794. document.webkitCancelFullScreen();
  4795. }
  4796. }
  4797. };
  4798. /**
  4799. * Unlocks the lock button state.
  4800. */
  4801. my.unlockLockButton = function () {
  4802. if ($("#lockIcon").hasClass("icon-security-locked"))
  4803. UIUtil.buttonClick("#lockIcon", "icon-security icon-security-locked");
  4804. };
  4805. /**
  4806. * Updates the lock button state to locked.
  4807. */
  4808. my.lockLockButton = function () {
  4809. if ($("#lockIcon").hasClass("icon-security"))
  4810. UIUtil.buttonClick("#lockIcon", "icon-security icon-security-locked");
  4811. };
  4812. /**
  4813. * Shows or hides authentication button
  4814. * @param show <tt>true</tt> to show or <tt>false</tt> to hide
  4815. */
  4816. my.showAuthenticateButton = function (show) {
  4817. if (show) {
  4818. $('#authentication').css({display: "inline"});
  4819. }
  4820. else {
  4821. $('#authentication').css({display: "none"});
  4822. }
  4823. };
  4824. // Shows or hides the 'recording' button.
  4825. my.showRecordingButton = function (show) {
  4826. if (!config.enableRecording) {
  4827. return;
  4828. }
  4829. if (show) {
  4830. $('#recording').css({display: "inline"});
  4831. }
  4832. else {
  4833. $('#recording').css({display: "none"});
  4834. }
  4835. };
  4836. // Sets the state of the recording button
  4837. my.setRecordingButtonState = function (isRecording) {
  4838. if (isRecording) {
  4839. $('#recordButton').removeClass("icon-recEnable");
  4840. $('#recordButton').addClass("icon-recEnable active");
  4841. } else {
  4842. $('#recordButton').removeClass("icon-recEnable active");
  4843. $('#recordButton').addClass("icon-recEnable");
  4844. }
  4845. };
  4846. // Shows or hides SIP calls button
  4847. my.showSipCallButton = function (show) {
  4848. if (APP.xmpp.isSipGatewayEnabled() && show) {
  4849. $('#sipCallButton').css({display: "inline-block"});
  4850. } else {
  4851. $('#sipCallButton').css({display: "none"});
  4852. }
  4853. };
  4854. /**
  4855. * Displays user authenticated identity name(login).
  4856. * @param authIdentity identity name to be displayed.
  4857. */
  4858. my.setAuthenticatedIdentity = function (authIdentity) {
  4859. if (authIdentity) {
  4860. $('#toolbar_auth_identity').css({display: "list-item"});
  4861. $('#toolbar_auth_identity').text(authIdentity);
  4862. } else {
  4863. $('#toolbar_auth_identity').css({display: "none"});
  4864. }
  4865. };
  4866. /**
  4867. * Shows/hides login button.
  4868. * @param show <tt>true</tt> to show
  4869. */
  4870. my.showLoginButton = function (show) {
  4871. if (show) {
  4872. $('#toolbar_button_login').css({display: "list-item"});
  4873. } else {
  4874. $('#toolbar_button_login').css({display: "none"});
  4875. }
  4876. };
  4877. /**
  4878. * Shows/hides logout button.
  4879. * @param show <tt>true</tt> to show
  4880. */
  4881. my.showLogoutButton = function (show) {
  4882. if (show) {
  4883. $('#toolbar_button_logout').css({display: "list-item"});
  4884. } else {
  4885. $('#toolbar_button_logout').css({display: "none"});
  4886. }
  4887. };
  4888. /**
  4889. * Sets the state of the button. The button has blue glow if desktop
  4890. * streaming is active.
  4891. * @param active the state of the desktop streaming.
  4892. */
  4893. my.changeDesktopSharingButtonState = function (active) {
  4894. var button = $("#desktopsharing > a");
  4895. if (active)
  4896. {
  4897. button.addClass("glow");
  4898. }
  4899. else
  4900. {
  4901. button.removeClass("glow");
  4902. }
  4903. };
  4904. return my;
  4905. }(Toolbar || {}));
  4906. module.exports = Toolbar;
  4907. },{"../../../service/authentication/AuthenticationEvents":93,"../authentication/Authentication":11,"../etherpad/Etherpad":14,"../prezi/Prezi":15,"../side_pannels/SidePanelToggler":17,"../util/MessageHandler":28,"../util/UIUtil":30,"./BottomToolbar":24}],26:[function(require,module,exports){
  4908. /* global $, interfaceConfig, Moderator, DesktopStreaming.showDesktopSharingButton */
  4909. var toolbarTimeoutObject,
  4910. toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
  4911. function showDesktopSharingButton() {
  4912. if (APP.desktopsharing.isDesktopSharingEnabled()) {
  4913. $('#desktopsharing').css({display: "inline"});
  4914. } else {
  4915. $('#desktopsharing').css({display: "none"});
  4916. }
  4917. }
  4918. /**
  4919. * Hides the toolbar.
  4920. */
  4921. function hideToolbar() {
  4922. var header = $("#header"),
  4923. bottomToolbar = $("#bottomToolbar");
  4924. var isToolbarHover = false;
  4925. header.find('*').each(function () {
  4926. var id = $(this).attr('id');
  4927. if ($("#" + id + ":hover").length > 0) {
  4928. isToolbarHover = true;
  4929. }
  4930. });
  4931. if ($("#bottomToolbar:hover").length > 0) {
  4932. isToolbarHover = true;
  4933. }
  4934. clearTimeout(toolbarTimeoutObject);
  4935. toolbarTimeoutObject = null;
  4936. if (!isToolbarHover) {
  4937. header.hide("slide", { direction: "up", duration: 300});
  4938. $('#subject').animate({top: "-=40"}, 300);
  4939. if ($("#remoteVideos").hasClass("hidden")) {
  4940. bottomToolbar.hide(
  4941. "slide", {direction: "right", duration: 300});
  4942. }
  4943. }
  4944. else {
  4945. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  4946. }
  4947. }
  4948. var ToolbarToggler = {
  4949. /**
  4950. * Shows the main toolbar.
  4951. */
  4952. showToolbar: function () {
  4953. var header = $("#header"),
  4954. bottomToolbar = $("#bottomToolbar");
  4955. if (!header.is(':visible') || !bottomToolbar.is(":visible")) {
  4956. header.show("slide", { direction: "up", duration: 300});
  4957. $('#subject').animate({top: "+=40"}, 300);
  4958. if (!bottomToolbar.is(":visible")) {
  4959. bottomToolbar.show(
  4960. "slide", {direction: "right", duration: 300});
  4961. }
  4962. if (toolbarTimeoutObject) {
  4963. clearTimeout(toolbarTimeoutObject);
  4964. toolbarTimeoutObject = null;
  4965. }
  4966. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  4967. toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
  4968. }
  4969. if (APP.xmpp.isModerator())
  4970. {
  4971. // TODO: Enable settings functionality.
  4972. // Need to uncomment the settings button in index.html.
  4973. // $('#settingsButton').css({visibility:"visible"});
  4974. }
  4975. // Show/hide desktop sharing button
  4976. showDesktopSharingButton();
  4977. },
  4978. /**
  4979. * Docks/undocks the toolbar.
  4980. *
  4981. * @param isDock indicates what operation to perform
  4982. */
  4983. dockToolbar: function (isDock) {
  4984. if (isDock) {
  4985. // First make sure the toolbar is shown.
  4986. if (!$('#header').is(':visible')) {
  4987. this.showToolbar();
  4988. }
  4989. // Then clear the time out, to dock the toolbar.
  4990. if (toolbarTimeoutObject) {
  4991. clearTimeout(toolbarTimeoutObject);
  4992. toolbarTimeoutObject = null;
  4993. }
  4994. }
  4995. else {
  4996. if (!$('#header').is(':visible')) {
  4997. this.showToolbar();
  4998. }
  4999. else {
  5000. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  5001. }
  5002. }
  5003. },
  5004. showDesktopSharingButton: showDesktopSharingButton
  5005. };
  5006. module.exports = ToolbarToggler;
  5007. },{}],27:[function(require,module,exports){
  5008. var JitsiPopover = (function () {
  5009. /**
  5010. * Constructs new JitsiPopover and attaches it to the element
  5011. * @param element jquery selector
  5012. * @param options the options for the popover.
  5013. * @constructor
  5014. */
  5015. function JitsiPopover(element, options)
  5016. {
  5017. this.options = {
  5018. skin: "white",
  5019. content: ""
  5020. };
  5021. if(options)
  5022. {
  5023. if(options.skin)
  5024. this.options.skin = options.skin;
  5025. if(options.content)
  5026. this.options.content = options.content;
  5027. }
  5028. this.elementIsHovered = false;
  5029. this.popoverIsHovered = false;
  5030. this.popoverShown = false;
  5031. element.data("jitsi_popover", this);
  5032. this.element = element;
  5033. this.template = ' <div class="jitsipopover ' + this.options.skin +
  5034. '"><div class="arrow"></div><div class="jitsipopover-content"></div>' +
  5035. '<div class="jitsiPopupmenuPadding"></div></div>';
  5036. var self = this;
  5037. this.element.on("mouseenter", function () {
  5038. self.elementIsHovered = true;
  5039. self.show();
  5040. }).on("mouseleave", function () {
  5041. self.elementIsHovered = false;
  5042. setTimeout(function () {
  5043. self.hide();
  5044. }, 10);
  5045. });
  5046. }
  5047. /**
  5048. * Shows the popover
  5049. */
  5050. JitsiPopover.prototype.show = function () {
  5051. this.createPopover();
  5052. this.popoverShown = true;
  5053. };
  5054. /**
  5055. * Hides the popover
  5056. */
  5057. JitsiPopover.prototype.hide = function () {
  5058. if(!this.elementIsHovered && !this.popoverIsHovered && this.popoverShown)
  5059. {
  5060. this.forceHide();
  5061. }
  5062. };
  5063. /**
  5064. * Hides the popover
  5065. */
  5066. JitsiPopover.prototype.forceHide = function () {
  5067. $(".jitsipopover").remove();
  5068. this.popoverShown = false;
  5069. };
  5070. /**
  5071. * Creates the popover html
  5072. */
  5073. JitsiPopover.prototype.createPopover = function () {
  5074. $("body").append(this.template);
  5075. $(".jitsipopover > .jitsipopover-content").html(this.options.content);
  5076. var self = this;
  5077. $(".jitsipopover").on("mouseenter", function () {
  5078. self.popoverIsHovered = true;
  5079. }).on("mouseleave", function () {
  5080. self.popoverIsHovered = false;
  5081. self.hide();
  5082. });
  5083. this.refreshPosition();
  5084. };
  5085. /**
  5086. * Refreshes the position of the popover
  5087. */
  5088. JitsiPopover.prototype.refreshPosition = function () {
  5089. $(".jitsipopover").position({
  5090. my: "bottom",
  5091. at: "top",
  5092. collision: "fit",
  5093. of: this.element,
  5094. using: function (position, elements) {
  5095. var calcLeft = elements.target.left - elements.element.left + elements.target.width/2;
  5096. $(".jitsipopover").css({top: position.top, left: position.left, display: "table"});
  5097. $(".jitsipopover > .arrow").css({left: calcLeft});
  5098. $(".jitsipopover > .jitsiPopupmenuPadding").css({left: calcLeft - 50});
  5099. }
  5100. });
  5101. };
  5102. /**
  5103. * Updates the content of popover.
  5104. * @param content new content
  5105. */
  5106. JitsiPopover.prototype.updateContent = function (content) {
  5107. this.options.content = content;
  5108. if(!this.popoverShown)
  5109. return;
  5110. $(".jitsipopover").remove();
  5111. this.createPopover();
  5112. };
  5113. return JitsiPopover;
  5114. })();
  5115. module.exports = JitsiPopover;
  5116. },{}],28:[function(require,module,exports){
  5117. /* global $, APP, jQuery, toastr */
  5118. var messageHandler = (function(my) {
  5119. /**
  5120. * Shows a message to the user.
  5121. *
  5122. * @param titleString the title of the message
  5123. * @param messageString the text of the message
  5124. */
  5125. my.openMessageDialog = function(titleKey, messageKey) {
  5126. var title = null;
  5127. if(titleKey)
  5128. {
  5129. title = APP.translation.generateTranslatonHTML(titleKey);
  5130. }
  5131. var message = APP.translation.generateTranslatonHTML(messageKey);
  5132. $.prompt(message,
  5133. {
  5134. title: title,
  5135. persistent: false
  5136. }
  5137. );
  5138. };
  5139. /**
  5140. * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel.
  5141. *
  5142. * @param titleString the title of the message
  5143. * @param msgString the text of the message
  5144. * @param persistent boolean value which determines whether the message is persistent or not
  5145. * @param leftButton the fist button's text
  5146. * @param submitFunction function to be called on submit
  5147. * @param loadedFunction function to be called after the prompt is fully loaded
  5148. * @param closeFunction function to be called after the prompt is closed
  5149. * @param focus optional focus selector or button index to be focused after
  5150. * the dialog is opened
  5151. * @param defaultButton index of default button which will be activated when
  5152. * the user press 'enter'. Indexed from 0.
  5153. */
  5154. my.openTwoButtonDialog = function(titleKey, titleString, msgKey, msgString,
  5155. persistent, leftButtonKey, submitFunction, loadedFunction,
  5156. closeFunction, focus, defaultButton)
  5157. {
  5158. var buttons = [];
  5159. var leftButton = APP.translation.generateTranslatonHTML(leftButtonKey);
  5160. buttons.push({ title: leftButton, value: true});
  5161. var cancelButton
  5162. = APP.translation.generateTranslatonHTML("dialog.Cancel");
  5163. buttons.push({title: cancelButton, value: false});
  5164. var message = msgString, title = titleString;
  5165. if (titleKey)
  5166. {
  5167. title = APP.translation.generateTranslatonHTML(titleKey);
  5168. }
  5169. if (msgKey) {
  5170. message = APP.translation.generateTranslatonHTML(msgKey);
  5171. }
  5172. $.prompt(message, {
  5173. title: title,
  5174. persistent: false,
  5175. buttons: buttons,
  5176. defaultButton: defaultButton,
  5177. focus: focus,
  5178. loaded: loadedFunction,
  5179. submit: submitFunction,
  5180. close: closeFunction
  5181. });
  5182. };
  5183. /**
  5184. * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel.
  5185. *
  5186. * @param titleString the title of the message
  5187. * @param msgString the text of the message
  5188. * @param persistent boolean value which determines whether the message is persistent or not
  5189. * @param buttons object with the buttons. The keys must be the name of the button and value is the value
  5190. * that will be passed to submitFunction
  5191. * @param submitFunction function to be called on submit
  5192. * @param loadedFunction function to be called after the prompt is fully loaded
  5193. */
  5194. my.openDialog = function (titleString, msgString, persistent, buttons,
  5195. submitFunction, loadedFunction) {
  5196. var args = {
  5197. title: titleString,
  5198. persistent: persistent,
  5199. buttons: buttons,
  5200. defaultButton: 1,
  5201. loaded: loadedFunction,
  5202. submit: submitFunction
  5203. };
  5204. if (persistent) {
  5205. args.closeText = '';
  5206. }
  5207. return new Impromptu(msgString, args);
  5208. };
  5209. /**
  5210. * Closes currently opened dialog.
  5211. */
  5212. my.closeDialog = function () {
  5213. $.prompt.close();
  5214. };
  5215. /**
  5216. * Shows a dialog with different states to the user.
  5217. *
  5218. * @param statesObject object containing all the states of the dialog
  5219. */
  5220. my.openDialogWithStates = function (statesObject, options) {
  5221. return new Impromptu(statesObject, options);
  5222. };
  5223. /**
  5224. * Opens new popup window for given <tt>url</tt> centered over current
  5225. * window.
  5226. *
  5227. * @param url the URL to be displayed in the popup window
  5228. * @param w the width of the popup window
  5229. * @param h the height of the popup window
  5230. * @param onPopupClosed optional callback function called when popup window
  5231. * has been closed.
  5232. *
  5233. * @returns popup window object if opened successfully or undefined
  5234. * in case we failed to open it(popup blocked)
  5235. */
  5236. my.openCenteredPopup = function (url, w, h, onPopupClosed) {
  5237. var l = window.screenX + (window.innerWidth / 2) - (w / 2);
  5238. var t = window.screenY + (window.innerHeight / 2) - (h / 2);
  5239. var popup = window.open(
  5240. url, '_blank',
  5241. 'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + '');
  5242. if (popup && onPopupClosed) {
  5243. var pollTimer = window.setInterval(function () {
  5244. if (popup.closed !== false) {
  5245. window.clearInterval(pollTimer);
  5246. onPopupClosed();
  5247. }
  5248. }, 200);
  5249. }
  5250. return popup;
  5251. };
  5252. /**
  5253. * Shows a dialog prompting the user to send an error report.
  5254. *
  5255. * @param titleString the title of the message
  5256. * @param msgString the text of the message
  5257. * @param error the error that is being reported
  5258. */
  5259. my.openReportDialog = function(titleKey, msgKey, error) {
  5260. my.openMessageDialog(titleKey, msgKey);
  5261. console.log(error);
  5262. //FIXME send the error to the server
  5263. };
  5264. /**
  5265. * Shows an error dialog to the user.
  5266. * @param title the title of the message
  5267. * @param message the text of the messafe
  5268. */
  5269. my.showError = function(titleKey, msgKey) {
  5270. if(!titleKey) {
  5271. titleKey = "dialog.oops";
  5272. }
  5273. if(!msgKey)
  5274. {
  5275. msgKey = "dialog.defaultError";
  5276. }
  5277. messageHandler.openMessageDialog(titleKey, msgKey);
  5278. };
  5279. my.notify = function(displayName, displayNameKey,
  5280. cls, messageKey, messageArguments) {
  5281. var displayNameSpan = '<span class="nickname" ';
  5282. if(displayName)
  5283. {
  5284. displayNameSpan += ">" + displayName;
  5285. }
  5286. else
  5287. {
  5288. displayNameSpan += "data-i18n='" + displayNameKey +
  5289. "'>" + APP.translation.translateString(displayNameKey);
  5290. }
  5291. displayNameSpan += "</span>";
  5292. toastr.info(
  5293. displayNameSpan + '<br>' +
  5294. '<span class=' + cls + ' data-i18n="' + messageKey + '"' +
  5295. (messageArguments?
  5296. " data-i18n-options='" + JSON.stringify(messageArguments) + "'"
  5297. : "") + ">" +
  5298. APP.translation.translateString(messageKey,
  5299. messageArguments) +
  5300. '</span>');
  5301. };
  5302. return my;
  5303. }(messageHandler || {}));
  5304. module.exports = messageHandler;
  5305. },{}],29:[function(require,module,exports){
  5306. var UIEvents = require("../../../service/UI/UIEvents");
  5307. var nickname = null;
  5308. var eventEmitter = null;
  5309. var NickanameHandler = {
  5310. init: function (emitter) {
  5311. eventEmitter = emitter;
  5312. var storedDisplayName = window.localStorage.displayname;
  5313. if (storedDisplayName) {
  5314. nickname = storedDisplayName;
  5315. }
  5316. },
  5317. setNickname: function (newNickname) {
  5318. if (!newNickname || nickname === newNickname)
  5319. return;
  5320. nickname = newNickname;
  5321. window.localStorage.displayname = nickname;
  5322. eventEmitter.emit(UIEvents.NICKNAME_CHANGED, newNickname);
  5323. },
  5324. getNickname: function () {
  5325. return nickname;
  5326. },
  5327. addListener: function (type, listener) {
  5328. eventEmitter.on(type, listener);
  5329. }
  5330. };
  5331. module.exports = NickanameHandler;
  5332. },{"../../../service/UI/UIEvents":92}],30:[function(require,module,exports){
  5333. /**
  5334. * Created by hristo on 12/22/14.
  5335. */
  5336. module.exports = {
  5337. /**
  5338. * Returns the available video width.
  5339. */
  5340. getAvailableVideoWidth: function () {
  5341. var PanelToggler = require("../side_pannels/SidePanelToggler");
  5342. var rightPanelWidth
  5343. = PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
  5344. return window.innerWidth - rightPanelWidth;
  5345. },
  5346. /**
  5347. * Changes the style class of the element given by id.
  5348. */
  5349. buttonClick: function(id, classname) {
  5350. $(id).toggleClass(classname); // add the class to the clicked element
  5351. },
  5352. /**
  5353. * Returns the text width for the given element.
  5354. *
  5355. * @param el the element
  5356. */
  5357. getTextWidth: function (el) {
  5358. return (el.clientWidth + 1);
  5359. },
  5360. /**
  5361. * Returns the text height for the given element.
  5362. *
  5363. * @param el the element
  5364. */
  5365. getTextHeight: function (el) {
  5366. return (el.clientHeight + 1);
  5367. },
  5368. /**
  5369. * Plays the sound given by id.
  5370. *
  5371. * @param id the identifier of the audio element.
  5372. */
  5373. playSoundNotification: function (id) {
  5374. document.getElementById(id).play();
  5375. },
  5376. /**
  5377. * Escapes the given text.
  5378. */
  5379. escapeHtml: function (unsafeText) {
  5380. return $('<div/>').text(unsafeText).html();
  5381. },
  5382. imageToGrayScale: function (canvas) {
  5383. var context = canvas.getContext('2d');
  5384. var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
  5385. var pixels = imgData.data;
  5386. for (var i = 0, n = pixels.length; i < n; i += 4) {
  5387. var grayscale
  5388. = pixels[i] * .3 + pixels[i+1] * .59 + pixels[i+2] * .11;
  5389. pixels[i ] = grayscale; // red
  5390. pixels[i+1] = grayscale; // green
  5391. pixels[i+2] = grayscale; // blue
  5392. // pixels[i+3] is alpha
  5393. }
  5394. // redraw the image in black & white
  5395. context.putImageData(imgData, 0, 0);
  5396. },
  5397. setTooltip: function (element, key, position) {
  5398. element.setAttribute("data-i18n", "[data-content]" + key);
  5399. element.setAttribute("data-toggle", "popover");
  5400. element.setAttribute("data-placement", position);
  5401. element.setAttribute("data-html", true);
  5402. element.setAttribute("data-container", "body");
  5403. }
  5404. };
  5405. },{"../side_pannels/SidePanelToggler":17}],31:[function(require,module,exports){
  5406. var JitsiPopover = require("../util/JitsiPopover");
  5407. /**
  5408. * Constructs new connection indicator.
  5409. * @param videoContainer the video container associated with the indicator.
  5410. * @constructor
  5411. */
  5412. function ConnectionIndicator(videoContainer, jid, VideoLayout)
  5413. {
  5414. this.videoContainer = videoContainer;
  5415. this.bandwidth = null;
  5416. this.packetLoss = null;
  5417. this.bitrate = null;
  5418. this.showMoreValue = false;
  5419. this.resolution = null;
  5420. this.transport = [];
  5421. this.popover = null;
  5422. this.jid = jid;
  5423. this.create();
  5424. this.videoLayout = VideoLayout;
  5425. }
  5426. /**
  5427. * Values for the connection quality
  5428. * @type {{98: string,
  5429. * 81: string,
  5430. * 64: string,
  5431. * 47: string,
  5432. * 30: string,
  5433. * 0: string}}
  5434. */
  5435. ConnectionIndicator.connectionQualityValues = {
  5436. 98: "18px", //full
  5437. 81: "15px",//4 bars
  5438. 64: "11px",//3 bars
  5439. 47: "7px",//2 bars
  5440. 30: "3px",//1 bar
  5441. 0: "0px"//empty
  5442. };
  5443. ConnectionIndicator.getIP = function(value)
  5444. {
  5445. return value.substring(0, value.lastIndexOf(":"));
  5446. };
  5447. ConnectionIndicator.getPort = function(value)
  5448. {
  5449. return value.substring(value.lastIndexOf(":") + 1, value.length);
  5450. };
  5451. ConnectionIndicator.getStringFromArray = function (array) {
  5452. var res = "";
  5453. for(var i = 0; i < array.length; i++)
  5454. {
  5455. res += (i === 0? "" : ", ") + array[i];
  5456. }
  5457. return res;
  5458. };
  5459. /**
  5460. * Generates the html content.
  5461. * @returns {string} the html content.
  5462. */
  5463. ConnectionIndicator.prototype.generateText = function () {
  5464. var downloadBitrate, uploadBitrate, packetLoss, resolution, i;
  5465. var translate = APP.translation.translateString;
  5466. if(this.bitrate === null)
  5467. {
  5468. downloadBitrate = "N/A";
  5469. uploadBitrate = "N/A";
  5470. }
  5471. else
  5472. {
  5473. downloadBitrate =
  5474. this.bitrate.download? this.bitrate.download + " Kbps" : "N/A";
  5475. uploadBitrate =
  5476. this.bitrate.upload? this.bitrate.upload + " Kbps" : "N/A";
  5477. }
  5478. if(this.packetLoss === null)
  5479. {
  5480. packetLoss = "N/A";
  5481. }
  5482. else
  5483. {
  5484. packetLoss = "<span class='jitsipopover_green'>&darr;</span>" +
  5485. (this.packetLoss.download !== null? this.packetLoss.download : "N/A") +
  5486. "% <span class='jitsipopover_orange'>&uarr;</span>" +
  5487. (this.packetLoss.upload !== null? this.packetLoss.upload : "N/A") + "%";
  5488. }
  5489. var resolutionValue = null;
  5490. if(this.resolution && this.jid != null)
  5491. {
  5492. var keys = Object.keys(this.resolution);
  5493. if(keys.length == 1)
  5494. {
  5495. for(var ssrc in this.resolution)
  5496. {
  5497. resolutionValue = this.resolution[ssrc];
  5498. }
  5499. }
  5500. else if(keys.length > 1)
  5501. {
  5502. var displayedSsrc = APP.simulcast.getReceivingSSRC(this.jid);
  5503. resolutionValue = this.resolution[displayedSsrc];
  5504. }
  5505. }
  5506. if(this.jid === null)
  5507. {
  5508. resolution = "";
  5509. if(this.resolution === null || !Object.keys(this.resolution) ||
  5510. Object.keys(this.resolution).length === 0)
  5511. {
  5512. resolution = "N/A";
  5513. }
  5514. else
  5515. for(i in this.resolution)
  5516. {
  5517. resolutionValue = this.resolution[i];
  5518. if(resolutionValue)
  5519. {
  5520. if(resolutionValue.height &&
  5521. resolutionValue.width)
  5522. {
  5523. resolution += (resolution === ""? "" : ", ") +
  5524. resolutionValue.width + "x" +
  5525. resolutionValue.height;
  5526. }
  5527. }
  5528. }
  5529. }
  5530. else if(!resolutionValue ||
  5531. !resolutionValue.height ||
  5532. !resolutionValue.width)
  5533. {
  5534. resolution = "N/A";
  5535. }
  5536. else
  5537. {
  5538. resolution = resolutionValue.width + "x" + resolutionValue.height;
  5539. }
  5540. var result = "<table style='width:100%'>" +
  5541. "<tr>" +
  5542. "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.bitrate'>" +
  5543. translate("connectionindicator.bitrate") + "</span></td>" +
  5544. "<td><span class='jitsipopover_green'>&darr;</span>" +
  5545. downloadBitrate + " <span class='jitsipopover_orange'>&uarr;</span>" +
  5546. uploadBitrate + "</td>" +
  5547. "</tr><tr>" +
  5548. "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.packetloss'>" +
  5549. translate("connectionindicator.packetloss") + "</span></td>" +
  5550. "<td>" + packetLoss + "</td>" +
  5551. "</tr><tr>" +
  5552. "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.resolution'>" +
  5553. translate("connectionindicator.resolution") + "</span></td>" +
  5554. "<td>" + resolution + "</td></tr></table>";
  5555. if(this.videoContainer.id == "localVideoContainer") {
  5556. result += "<div class=\"jitsipopover_showmore\" " +
  5557. "onclick = \"APP.UI.connectionIndicatorShowMore('" +
  5558. this.videoContainer.id + "')\" data-i18n='connectionindicator." +
  5559. (this.showMoreValue ? "less" : "more") + "'>" +
  5560. translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
  5561. "</div><br />";
  5562. }
  5563. if(this.showMoreValue)
  5564. {
  5565. var downloadBandwidth, uploadBandwidth, transport;
  5566. if(this.bandwidth === null)
  5567. {
  5568. downloadBandwidth = "N/A";
  5569. uploadBandwidth = "N/A";
  5570. }
  5571. else
  5572. {
  5573. downloadBandwidth = this.bandwidth.download?
  5574. this.bandwidth.download + " Kbps" :
  5575. "N/A";
  5576. uploadBandwidth = this.bandwidth.upload?
  5577. this.bandwidth.upload + " Kbps" :
  5578. "N/A";
  5579. }
  5580. if(!this.transport || this.transport.length === 0)
  5581. {
  5582. transport = "<tr>" +
  5583. "<td><span class='jitsipopover_blue' " +
  5584. "data-i18n='connectionindicator.address'>" +
  5585. translate("connectionindicator.address") + "</span></td>" +
  5586. "<td> N/A</td></tr>";
  5587. }
  5588. else
  5589. {
  5590. var data = {remoteIP: [], localIP:[], remotePort:[], localPort:[]};
  5591. for(i = 0; i < this.transport.length; i++)
  5592. {
  5593. var ip = ConnectionIndicator.getIP(this.transport[i].ip);
  5594. var port = ConnectionIndicator.getPort(this.transport[i].ip);
  5595. var localIP =
  5596. ConnectionIndicator.getIP(this.transport[i].localip);
  5597. var localPort =
  5598. ConnectionIndicator.getPort(this.transport[i].localip);
  5599. if(data.remoteIP.indexOf(ip) == -1)
  5600. {
  5601. data.remoteIP.push(ip);
  5602. }
  5603. if(data.remotePort.indexOf(port) == -1)
  5604. {
  5605. data.remotePort.push(port);
  5606. }
  5607. if(data.localIP.indexOf(localIP) == -1)
  5608. {
  5609. data.localIP.push(localIP);
  5610. }
  5611. if(data.localPort.indexOf(localPort) == -1)
  5612. {
  5613. data.localPort.push(localPort);
  5614. }
  5615. }
  5616. var local_address_key = "connectionindicator.localaddress";
  5617. var remote_address_key = "connectionindicator.remoteaddress";
  5618. var localTransport =
  5619. "<tr><td><span class='jitsipopover_blue' data-i18n='" +
  5620. local_address_key +"' data-i18n-options='" +
  5621. JSON.stringify({count: data.localIP.length}) + "'>" +
  5622. translate(local_address_key, {count: data.localIP.length}) +
  5623. "</span></td><td> " +
  5624. ConnectionIndicator.getStringFromArray(data.localIP) +
  5625. "</td></tr>";
  5626. transport =
  5627. "<tr><td><span class='jitsipopover_blue' data-i18n='" +
  5628. remote_address_key + "' data-i18n-options='" +
  5629. JSON.stringify({count: data.remoteIP.length}) + "'>" +
  5630. translate(remote_address_key,
  5631. {count: data.remoteIP.length}) +
  5632. "</span></td><td> " +
  5633. ConnectionIndicator.getStringFromArray(data.remoteIP) +
  5634. "</td></tr>";
  5635. var key_remote = "connectionindicator.remoteport",
  5636. key_local = "connectionindicator.localport";
  5637. transport += "<tr>" +
  5638. "<td>" +
  5639. "<span class='jitsipopover_blue' data-i18n='" + key_remote +
  5640. "' data-i18n-options='" +
  5641. JSON.stringify({count: this.transport.length}) + "'>" +
  5642. translate(key_remote, {count: this.transport.length}) +
  5643. "</span></td><td>";
  5644. localTransport += "<tr>" +
  5645. "<td>" +
  5646. "<span class='jitsipopover_blue' data-i18n='" + key_local +
  5647. "' data-i18n-options='" +
  5648. JSON.stringify({count: this.transport.length}) + "'>" +
  5649. translate(key_local, {count: this.transport.length}) +
  5650. "</span></td><td>";
  5651. transport +=
  5652. ConnectionIndicator.getStringFromArray(data.remotePort);
  5653. localTransport +=
  5654. ConnectionIndicator.getStringFromArray(data.localPort);
  5655. transport += "</td></tr>";
  5656. transport += localTransport + "</td></tr>";
  5657. transport +="<tr>" +
  5658. "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.transport'>" +
  5659. translate("connectionindicator.transport") + "</span></td>" +
  5660. "<td>" + this.transport[0].type + "</td></tr>";
  5661. }
  5662. result += "<table style='width:100%'>" +
  5663. "<tr>" +
  5664. "<td>" +
  5665. "<span class='jitsipopover_blue' data-i18n='connectionindicator.bandwidth'>" +
  5666. translate("connectionindicator.bandwidth") + "</span>" +
  5667. "</td><td>" +
  5668. "<span class='jitsipopover_green'>&darr;</span>" +
  5669. downloadBandwidth +
  5670. " <span class='jitsipopover_orange'>&uarr;</span>" +
  5671. uploadBandwidth + "</td></tr>";
  5672. result += transport + "</table>";
  5673. }
  5674. return result;
  5675. };
  5676. /**
  5677. * Shows or hide the additional information.
  5678. */
  5679. ConnectionIndicator.prototype.showMore = function () {
  5680. this.showMoreValue = !this.showMoreValue;
  5681. this.updatePopoverData();
  5682. };
  5683. function createIcon(classes)
  5684. {
  5685. var icon = document.createElement("span");
  5686. for(var i in classes)
  5687. {
  5688. icon.classList.add(classes[i]);
  5689. }
  5690. icon.appendChild(
  5691. document.createElement("i")).classList.add("icon-connection");
  5692. return icon;
  5693. }
  5694. /**
  5695. * Creates the indicator
  5696. */
  5697. ConnectionIndicator.prototype.create = function () {
  5698. this.connectionIndicatorContainer = document.createElement("div");
  5699. this.connectionIndicatorContainer.className = "connectionindicator";
  5700. this.connectionIndicatorContainer.style.display = "none";
  5701. this.videoContainer.appendChild(this.connectionIndicatorContainer);
  5702. this.popover = new JitsiPopover(
  5703. $("#" + this.videoContainer.id + " > .connectionindicator"),
  5704. {content: "<div class=\"connection_info\" data-i18n='connectionindicator.na'>" +
  5705. APP.translation.translateString("connectionindicator.na") + "</div>",
  5706. skin: "black"});
  5707. this.emptyIcon = this.connectionIndicatorContainer.appendChild(
  5708. createIcon(["connection", "connection_empty"]));
  5709. this.fullIcon = this.connectionIndicatorContainer.appendChild(
  5710. createIcon(["connection", "connection_full"]));
  5711. };
  5712. /**
  5713. * Removes the indicator
  5714. */
  5715. ConnectionIndicator.prototype.remove = function()
  5716. {
  5717. this.connectionIndicatorContainer.remove();
  5718. this.popover.forceHide();
  5719. };
  5720. /**
  5721. * Updates the data of the indicator
  5722. * @param percent the percent of connection quality
  5723. * @param object the statistics data.
  5724. */
  5725. ConnectionIndicator.prototype.updateConnectionQuality =
  5726. function (percent, object) {
  5727. if(percent === null)
  5728. {
  5729. this.connectionIndicatorContainer.style.display = "none";
  5730. this.popover.forceHide();
  5731. return;
  5732. }
  5733. else
  5734. {
  5735. if(this.connectionIndicatorContainer.style.display == "none") {
  5736. this.connectionIndicatorContainer.style.display = "block";
  5737. this.videoLayout.updateMutePosition(this.videoContainer.id);
  5738. }
  5739. }
  5740. this.bandwidth = object.bandwidth;
  5741. this.bitrate = object.bitrate;
  5742. this.packetLoss = object.packetLoss;
  5743. this.transport = object.transport;
  5744. if(object.resolution)
  5745. {
  5746. this.resolution = object.resolution;
  5747. }
  5748. for(var quality in ConnectionIndicator.connectionQualityValues)
  5749. {
  5750. if(percent >= quality)
  5751. {
  5752. this.fullIcon.style.width =
  5753. ConnectionIndicator.connectionQualityValues[quality];
  5754. }
  5755. }
  5756. this.updatePopoverData();
  5757. };
  5758. /**
  5759. * Updates the resolution
  5760. * @param resolution the new resolution
  5761. */
  5762. ConnectionIndicator.prototype.updateResolution = function (resolution) {
  5763. this.resolution = resolution;
  5764. this.updatePopoverData();
  5765. };
  5766. /**
  5767. * Updates the content of the popover
  5768. */
  5769. ConnectionIndicator.prototype.updatePopoverData = function () {
  5770. this.popover.updateContent(
  5771. "<div class=\"connection_info\">" + this.generateText() + "</div>");
  5772. APP.translation.translateElement($(".connection_info"));
  5773. };
  5774. /**
  5775. * Hides the popover
  5776. */
  5777. ConnectionIndicator.prototype.hide = function () {
  5778. this.popover.forceHide();
  5779. };
  5780. /**
  5781. * Hides the indicator
  5782. */
  5783. ConnectionIndicator.prototype.hideIndicator = function () {
  5784. this.connectionIndicatorContainer.style.display = "none";
  5785. if(this.popover)
  5786. this.popover.forceHide();
  5787. };
  5788. module.exports = ConnectionIndicator;
  5789. },{"../util/JitsiPopover":27}],32:[function(require,module,exports){
  5790. var AudioLevels = require("../audio_levels/AudioLevels");
  5791. var Avatar = require("../avatar/Avatar");
  5792. var Chat = require("../side_pannels/chat/Chat");
  5793. var ContactList = require("../side_pannels/contactlist/ContactList");
  5794. var UIUtil = require("../util/UIUtil");
  5795. var ConnectionIndicator = require("./ConnectionIndicator");
  5796. var NicknameHandler = require("../util/NicknameHandler");
  5797. var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
  5798. var UIEvents = require("../../../service/UI/UIEvents");
  5799. var currentDominantSpeaker = null;
  5800. var lastNCount = config.channelLastN;
  5801. var localLastNCount = config.channelLastN;
  5802. var localLastNSet = [];
  5803. var lastNEndpointsCache = [];
  5804. var lastNPickupJid = null;
  5805. var largeVideoState = {
  5806. updateInProgress: false,
  5807. newSrc: ''
  5808. };
  5809. var eventEmitter = null;
  5810. /**
  5811. * Currently focused video "src"(displayed in large video).
  5812. * @type {String}
  5813. */
  5814. var focusedVideoInfo = null;
  5815. /**
  5816. * Indicates if we have muted our audio before the conference has started.
  5817. * @type {boolean}
  5818. */
  5819. var preMuted = false;
  5820. var mutedAudios = {};
  5821. var flipXLocalVideo = true;
  5822. var currentVideoWidth = null;
  5823. var currentVideoHeight = null;
  5824. var localVideoSrc = null;
  5825. function videoactive( videoelem) {
  5826. if (videoelem.attr('id').indexOf('mixedmslabel') === -1) {
  5827. // ignore mixedmslabela0 and v0
  5828. videoelem.show();
  5829. VideoLayout.resizeThumbnails();
  5830. var videoParent = videoelem.parent();
  5831. var parentResourceJid = null;
  5832. if (videoParent)
  5833. parentResourceJid
  5834. = VideoLayout.getPeerContainerResourceJid(videoParent[0]);
  5835. // Update the large video to the last added video only if there's no
  5836. // current dominant, focused speaker or prezi playing or update it to
  5837. // the current dominant speaker.
  5838. if ((!focusedVideoInfo &&
  5839. !VideoLayout.getDominantSpeakerResourceJid() &&
  5840. !require("../prezi/Prezi").isPresentationVisible()) ||
  5841. (parentResourceJid &&
  5842. VideoLayout.getDominantSpeakerResourceJid() === parentResourceJid)) {
  5843. VideoLayout.updateLargeVideo(
  5844. APP.RTC.getVideoSrc(videoelem[0]),
  5845. 1,
  5846. parentResourceJid);
  5847. }
  5848. VideoLayout.showModeratorIndicator();
  5849. }
  5850. }
  5851. function waitForRemoteVideo(selector, ssrc, stream, jid) {
  5852. // XXX(gp) so, every call to this function is *always* preceded by a call
  5853. // to the RTC.attachMediaStream() function but that call is *not* followed
  5854. // by an update to the videoSrcToSsrc map!
  5855. //
  5856. // The above way of doing things results in video SRCs that don't correspond
  5857. // to any SSRC for a short period of time (to be more precise, for as long
  5858. // the waitForRemoteVideo takes to complete). This causes problems (see
  5859. // bellow).
  5860. //
  5861. // I'm wondering why we need to do that; i.e. why call RTC.attachMediaStream()
  5862. // a second time in here and only then update the videoSrcToSsrc map? Why
  5863. // not simply update the videoSrcToSsrc map when the RTC.attachMediaStream()
  5864. // is called the first time? I actually do that in the lastN changed event
  5865. // handler because the "orphan" video SRC is causing troubles there. The
  5866. // purpose of this method would then be to fire the "videoactive.jingle".
  5867. //
  5868. // Food for though I guess :-)
  5869. if (selector.removed || !selector.parent().is(":visible")) {
  5870. console.warn("Media removed before had started", selector);
  5871. return;
  5872. }
  5873. if (stream.id === 'mixedmslabel') return;
  5874. if (selector[0].currentTime > 0) {
  5875. var videoStream = APP.simulcast.getReceivingVideoStream(stream);
  5876. APP.RTC.attachMediaStream(selector, videoStream); // FIXME: why do i have to do this for FF?
  5877. videoactive(selector);
  5878. } else {
  5879. setTimeout(function () {
  5880. waitForRemoteVideo(selector, ssrc, stream, jid);
  5881. }, 250);
  5882. }
  5883. }
  5884. /**
  5885. * Returns an array of the video horizontal and vertical indents,
  5886. * so that if fits its parent.
  5887. *
  5888. * @return an array with 2 elements, the horizontal indent and the vertical
  5889. * indent
  5890. */
  5891. function getCameraVideoPosition(videoWidth,
  5892. videoHeight,
  5893. videoSpaceWidth,
  5894. videoSpaceHeight) {
  5895. // Parent height isn't completely calculated when we position the video in
  5896. // full screen mode and this is why we use the screen height in this case.
  5897. // Need to think it further at some point and implement it properly.
  5898. var isFullScreen = document.fullScreen ||
  5899. document.mozFullScreen ||
  5900. document.webkitIsFullScreen;
  5901. if (isFullScreen)
  5902. videoSpaceHeight = window.innerHeight;
  5903. var horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
  5904. var verticalIndent = (videoSpaceHeight - videoHeight) / 2;
  5905. return [horizontalIndent, verticalIndent];
  5906. }
  5907. /**
  5908. * Returns an array of the video horizontal and vertical indents.
  5909. * Centers horizontally and top aligns vertically.
  5910. *
  5911. * @return an array with 2 elements, the horizontal indent and the vertical
  5912. * indent
  5913. */
  5914. function getDesktopVideoPosition(videoWidth,
  5915. videoHeight,
  5916. videoSpaceWidth,
  5917. videoSpaceHeight) {
  5918. var horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
  5919. var verticalIndent = 0;// Top aligned
  5920. return [horizontalIndent, verticalIndent];
  5921. }
  5922. /**
  5923. * Returns an array of the video dimensions, so that it covers the screen.
  5924. * It leaves no empty areas, but some parts of the video might not be visible.
  5925. *
  5926. * @return an array with 2 elements, the video width and the video height
  5927. */
  5928. function getCameraVideoSize(videoWidth,
  5929. videoHeight,
  5930. videoSpaceWidth,
  5931. videoSpaceHeight) {
  5932. if (!videoWidth)
  5933. videoWidth = currentVideoWidth;
  5934. if (!videoHeight)
  5935. videoHeight = currentVideoHeight;
  5936. var aspectRatio = videoWidth / videoHeight;
  5937. var availableWidth = Math.max(videoWidth, videoSpaceWidth);
  5938. var availableHeight = Math.max(videoHeight, videoSpaceHeight);
  5939. if (availableWidth / aspectRatio < videoSpaceHeight) {
  5940. availableHeight = videoSpaceHeight;
  5941. availableWidth = availableHeight * aspectRatio;
  5942. }
  5943. if (availableHeight * aspectRatio < videoSpaceWidth) {
  5944. availableWidth = videoSpaceWidth;
  5945. availableHeight = availableWidth / aspectRatio;
  5946. }
  5947. return [availableWidth, availableHeight];
  5948. }
  5949. /**
  5950. * Sets the display name for the given video span id.
  5951. */
  5952. function setDisplayName(videoSpanId, displayName, key) {
  5953. var nameSpan = $('#' + videoSpanId + '>span.displayname');
  5954. var defaultLocalDisplayName = APP.translation.generateTranslatonHTML(
  5955. interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
  5956. // If we already have a display name for this video.
  5957. if (nameSpan.length > 0) {
  5958. var nameSpanElement = nameSpan.get(0);
  5959. if (nameSpanElement.id === 'localDisplayName' &&
  5960. $('#localDisplayName').text() !== displayName) {
  5961. if (displayName && displayName.length > 0)
  5962. {
  5963. var meHTML = APP.translation.generateTranslatonHTML("me");
  5964. $('#localDisplayName').html(displayName + ' (' + meHTML + ')');
  5965. }
  5966. else
  5967. $('#localDisplayName').html(defaultLocalDisplayName);
  5968. } else {
  5969. if (displayName && displayName.length > 0)
  5970. {
  5971. $('#' + videoSpanId + '_name').html(displayName);
  5972. }
  5973. else if (key && key.length > 0)
  5974. {
  5975. var nameHtml = APP.translation.generateTranslatonHTML(key);
  5976. $('#' + videoSpanId + '_name').html(nameHtml);
  5977. }
  5978. else
  5979. $('#' + videoSpanId + '_name').text(
  5980. interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
  5981. }
  5982. } else {
  5983. var editButton = null;
  5984. nameSpan = document.createElement('span');
  5985. nameSpan.className = 'displayname';
  5986. $('#' + videoSpanId)[0].appendChild(nameSpan);
  5987. if (videoSpanId === 'localVideoContainer') {
  5988. editButton = createEditDisplayNameButton();
  5989. if (displayName && displayName.length > 0) {
  5990. var meHTML = APP.translation.generateTranslatonHTML("me");
  5991. nameSpan.innerHTML = displayName + meHTML;
  5992. }
  5993. else
  5994. nameSpan.innerHTML = defaultLocalDisplayName;
  5995. }
  5996. else {
  5997. if (displayName && displayName.length > 0) {
  5998. nameSpan.innerText = displayName;
  5999. }
  6000. else
  6001. nameSpan.innerText = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
  6002. }
  6003. if (!editButton) {
  6004. nameSpan.id = videoSpanId + '_name';
  6005. } else {
  6006. nameSpan.id = 'localDisplayName';
  6007. $('#' + videoSpanId)[0].appendChild(editButton);
  6008. //translates popover of edit button
  6009. APP.translation.translateElement($("a.displayname"));
  6010. var editableText = document.createElement('input');
  6011. editableText.className = 'displayname';
  6012. editableText.type = 'text';
  6013. editableText.id = 'editDisplayName';
  6014. if (displayName && displayName.length) {
  6015. editableText.value
  6016. = displayName;
  6017. }
  6018. var defaultNickname = APP.translation.translateString(
  6019. "defaultNickname", {name: "Jane Pink"});
  6020. editableText.setAttribute('style', 'display:none;');
  6021. editableText.setAttribute('data-18n',
  6022. '[placeholder]defaultNickname');
  6023. editableText.setAttribute("data-i18n-options",
  6024. JSON.stringify({name: "Jane Pink"}));
  6025. editableText.setAttribute("placeholder", defaultNickname);
  6026. $('#' + videoSpanId)[0].appendChild(editableText);
  6027. $('#localVideoContainer .displayname')
  6028. .bind("click", function (e) {
  6029. e.preventDefault();
  6030. e.stopPropagation();
  6031. $('#localDisplayName').hide();
  6032. $('#editDisplayName').show();
  6033. $('#editDisplayName').focus();
  6034. $('#editDisplayName').select();
  6035. $('#editDisplayName').one("focusout", function (e) {
  6036. VideoLayout.inputDisplayNameHandler(this.value);
  6037. });
  6038. $('#editDisplayName').on('keydown', function (e) {
  6039. if (e.keyCode === 13) {
  6040. e.preventDefault();
  6041. VideoLayout.inputDisplayNameHandler(this.value);
  6042. }
  6043. });
  6044. });
  6045. }
  6046. }
  6047. }
  6048. /**
  6049. * Gets the selector of video thumbnail container for the user identified by
  6050. * given <tt>userJid</tt>
  6051. * @param resourceJid user's Jid for whom we want to get the video container.
  6052. */
  6053. function getParticipantContainer(resourceJid)
  6054. {
  6055. if (!resourceJid)
  6056. return null;
  6057. if (resourceJid === APP.xmpp.myResource())
  6058. return $("#localVideoContainer");
  6059. else
  6060. return $("#participant_" + resourceJid);
  6061. }
  6062. /**
  6063. * Sets the size and position of the given video element.
  6064. *
  6065. * @param video the video element to position
  6066. * @param width the desired video width
  6067. * @param height the desired video height
  6068. * @param horizontalIndent the left and right indent
  6069. * @param verticalIndent the top and bottom indent
  6070. */
  6071. function positionVideo(video,
  6072. width,
  6073. height,
  6074. horizontalIndent,
  6075. verticalIndent) {
  6076. video.width(width);
  6077. video.height(height);
  6078. video.css({ top: verticalIndent + 'px',
  6079. bottom: verticalIndent + 'px',
  6080. left: horizontalIndent + 'px',
  6081. right: horizontalIndent + 'px'});
  6082. }
  6083. /**
  6084. * Adds the remote video menu element for the given <tt>jid</tt> in the
  6085. * given <tt>parentElement</tt>.
  6086. *
  6087. * @param jid the jid indicating the video for which we're adding a menu.
  6088. * @param parentElement the parent element where this menu will be added
  6089. */
  6090. function addRemoteVideoMenu(jid, parentElement) {
  6091. var spanElement = document.createElement('span');
  6092. spanElement.className = 'remotevideomenu';
  6093. parentElement.appendChild(spanElement);
  6094. var menuElement = document.createElement('i');
  6095. menuElement.className = 'fa fa-angle-down';
  6096. menuElement.title = 'Remote user controls';
  6097. spanElement.appendChild(menuElement);
  6098. // <ul class="popupmenu">
  6099. // <li><a href="#">Mute</a></li>
  6100. // <li><a href="#">Eject</a></li>
  6101. // </ul>
  6102. var popupmenuElement = document.createElement('ul');
  6103. popupmenuElement.className = 'popupmenu';
  6104. popupmenuElement.id
  6105. = 'remote_popupmenu_' + Strophe.getResourceFromJid(jid);
  6106. spanElement.appendChild(popupmenuElement);
  6107. var muteMenuItem = document.createElement('li');
  6108. var muteLinkItem = document.createElement('a');
  6109. var mutedIndicator = "<i style='float:left;' class='icon-mic-disabled'></i>";
  6110. if (!mutedAudios[jid]) {
  6111. muteLinkItem.innerHTML = mutedIndicator +
  6112. " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
  6113. muteLinkItem.className = 'mutelink';
  6114. }
  6115. else {
  6116. muteLinkItem.innerHTML = mutedIndicator +
  6117. " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
  6118. muteLinkItem.className = 'mutelink disabled';
  6119. }
  6120. muteLinkItem.onclick = function(){
  6121. if ($(this).attr('disabled') != undefined) {
  6122. event.preventDefault();
  6123. }
  6124. var isMute = mutedAudios[jid] == true;
  6125. APP.xmpp.setMute(jid, !isMute);
  6126. popupmenuElement.setAttribute('style', 'display:none;');
  6127. if (isMute) {
  6128. this.innerHTML = mutedIndicator +
  6129. " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
  6130. this.className = 'mutelink disabled';
  6131. }
  6132. else {
  6133. this.innerHTML = mutedIndicator +
  6134. " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
  6135. this.className = 'mutelink';
  6136. }
  6137. };
  6138. muteMenuItem.appendChild(muteLinkItem);
  6139. popupmenuElement.appendChild(muteMenuItem);
  6140. var ejectIndicator = "<i style='float:left;' class='fa fa-eject'></i>";
  6141. var ejectMenuItem = document.createElement('li');
  6142. var ejectLinkItem = document.createElement('a');
  6143. var ejectText = "<div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.kick'>&nbsp;</div>";
  6144. ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
  6145. ejectLinkItem.onclick = function(){
  6146. APP.xmpp.eject(jid);
  6147. popupmenuElement.setAttribute('style', 'display:none;');
  6148. };
  6149. ejectMenuItem.appendChild(ejectLinkItem);
  6150. popupmenuElement.appendChild(ejectMenuItem);
  6151. var paddingSpan = document.createElement('span');
  6152. paddingSpan.className = 'popupmenuPadding';
  6153. popupmenuElement.appendChild(paddingSpan);
  6154. APP.translation.translateElement($("#" + popupmenuElement.id + " > li > a > div"));
  6155. }
  6156. /**
  6157. * Removes remote video menu element from video element identified by
  6158. * given <tt>videoElementId</tt>.
  6159. *
  6160. * @param videoElementId the id of local or remote video element.
  6161. */
  6162. function removeRemoteVideoMenu(videoElementId) {
  6163. var menuSpan = $('#' + videoElementId + '>span.remotevideomenu');
  6164. if (menuSpan.length) {
  6165. menuSpan.remove();
  6166. }
  6167. }
  6168. /**
  6169. * Updates the data for the indicator
  6170. * @param id the id of the indicator
  6171. * @param percent the percent for connection quality
  6172. * @param object the data
  6173. */
  6174. function updateStatsIndicator(id, percent, object) {
  6175. if(VideoLayout.connectionIndicators[id])
  6176. VideoLayout.connectionIndicators[id].updateConnectionQuality(percent, object);
  6177. }
  6178. /**
  6179. * Returns an array of the video dimensions, so that it keeps it's aspect
  6180. * ratio and fits available area with it's larger dimension. This method
  6181. * ensures that whole video will be visible and can leave empty areas.
  6182. *
  6183. * @return an array with 2 elements, the video width and the video height
  6184. */
  6185. function getDesktopVideoSize(videoWidth,
  6186. videoHeight,
  6187. videoSpaceWidth,
  6188. videoSpaceHeight) {
  6189. if (!videoWidth)
  6190. videoWidth = currentVideoWidth;
  6191. if (!videoHeight)
  6192. videoHeight = currentVideoHeight;
  6193. var aspectRatio = videoWidth / videoHeight;
  6194. var availableWidth = Math.max(videoWidth, videoSpaceWidth);
  6195. var availableHeight = Math.max(videoHeight, videoSpaceHeight);
  6196. videoSpaceHeight -= $('#remoteVideos').outerHeight();
  6197. if (availableWidth / aspectRatio >= videoSpaceHeight)
  6198. {
  6199. availableHeight = videoSpaceHeight;
  6200. availableWidth = availableHeight * aspectRatio;
  6201. }
  6202. if (availableHeight * aspectRatio >= videoSpaceWidth)
  6203. {
  6204. availableWidth = videoSpaceWidth;
  6205. availableHeight = availableWidth / aspectRatio;
  6206. }
  6207. return [availableWidth, availableHeight];
  6208. }
  6209. /**
  6210. * Creates the edit display name button.
  6211. *
  6212. * @returns the edit button
  6213. */
  6214. function createEditDisplayNameButton() {
  6215. var editButton = document.createElement('a');
  6216. editButton.className = 'displayname';
  6217. UIUtil.setTooltip(editButton,
  6218. "videothumbnail.editnickname",
  6219. "top");
  6220. editButton.innerHTML = '<i class="fa fa-pencil"></i>';
  6221. return editButton;
  6222. }
  6223. /**
  6224. * Creates the element indicating the moderator(owner) of the conference.
  6225. *
  6226. * @param parentElement the parent element where the owner indicator will
  6227. * be added
  6228. */
  6229. function createModeratorIndicatorElement(parentElement) {
  6230. var moderatorIndicator = document.createElement('i');
  6231. moderatorIndicator.className = 'fa fa-star';
  6232. parentElement.appendChild(moderatorIndicator);
  6233. UIUtil.setTooltip(parentElement,
  6234. "videothumbnail.moderator",
  6235. "top");
  6236. }
  6237. var VideoLayout = (function (my) {
  6238. my.connectionIndicators = {};
  6239. // By default we use camera
  6240. my.getVideoSize = getCameraVideoSize;
  6241. my.getVideoPosition = getCameraVideoPosition;
  6242. my.init = function (emitter) {
  6243. // Listen for large video size updates
  6244. document.getElementById('largeVideo')
  6245. .addEventListener('loadedmetadata', function (e) {
  6246. currentVideoWidth = this.videoWidth;
  6247. currentVideoHeight = this.videoHeight;
  6248. VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
  6249. });
  6250. eventEmitter = emitter;
  6251. };
  6252. my.isInLastN = function(resource) {
  6253. return lastNCount < 0 // lastN is disabled, return true
  6254. || (lastNCount > 0 && lastNEndpointsCache.length == 0) // lastNEndpoints cache not built yet, return true
  6255. || (lastNEndpointsCache && lastNEndpointsCache.indexOf(resource) !== -1);
  6256. };
  6257. my.changeLocalStream = function (stream) {
  6258. VideoLayout.changeLocalVideo(stream);
  6259. };
  6260. my.changeLocalAudio = function(stream) {
  6261. APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
  6262. document.getElementById('localAudio').autoplay = true;
  6263. document.getElementById('localAudio').volume = 0;
  6264. if (preMuted) {
  6265. if(!APP.UI.setAudioMuted(true))
  6266. {
  6267. preMuted = mute;
  6268. }
  6269. preMuted = false;
  6270. }
  6271. };
  6272. my.changeLocalVideo = function(stream) {
  6273. var flipX = true;
  6274. if(stream.videoType == "screen")
  6275. flipX = false;
  6276. var localVideo = document.createElement('video');
  6277. localVideo.id = 'localVideo_' +
  6278. APP.RTC.getStreamID(stream.getOriginalStream());
  6279. localVideo.autoplay = true;
  6280. localVideo.volume = 0; // is it required if audio is separated ?
  6281. localVideo.oncontextmenu = function () { return false; };
  6282. var localVideoContainer = document.getElementById('localVideoWrapper');
  6283. localVideoContainer.appendChild(localVideo);
  6284. // Set default display name.
  6285. setDisplayName('localVideoContainer');
  6286. if(!VideoLayout.connectionIndicators["localVideoContainer"]) {
  6287. VideoLayout.connectionIndicators["localVideoContainer"]
  6288. = new ConnectionIndicator($("#localVideoContainer")[0], null, VideoLayout);
  6289. }
  6290. AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
  6291. var localVideoSelector = $('#' + localVideo.id);
  6292. function localVideoClick(event) {
  6293. event.stopPropagation();
  6294. VideoLayout.handleVideoThumbClicked(
  6295. APP.RTC.getVideoSrc(localVideo),
  6296. false,
  6297. APP.xmpp.myResource());
  6298. }
  6299. // Add click handler to both video and video wrapper elements in case
  6300. // there's no video.
  6301. localVideoSelector.click(localVideoClick);
  6302. $('#localVideoContainer').click(localVideoClick);
  6303. // Add hover handler
  6304. $('#localVideoContainer').hover(
  6305. function() {
  6306. VideoLayout.showDisplayName('localVideoContainer', true);
  6307. },
  6308. function() {
  6309. if (!VideoLayout.isLargeVideoVisible()
  6310. || APP.RTC.getVideoSrc(localVideo) !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
  6311. VideoLayout.showDisplayName('localVideoContainer', false);
  6312. }
  6313. );
  6314. // Add stream ended handler
  6315. stream.getOriginalStream().onended = function () {
  6316. localVideoContainer.removeChild(localVideo);
  6317. VideoLayout.updateRemovedVideo(APP.RTC.getVideoSrc(localVideo));
  6318. };
  6319. // Flip video x axis if needed
  6320. flipXLocalVideo = flipX;
  6321. if (flipX) {
  6322. localVideoSelector.addClass("flipVideoX");
  6323. }
  6324. // Attach WebRTC stream
  6325. var videoStream = APP.simulcast.getLocalVideoStream();
  6326. APP.RTC.attachMediaStream(localVideoSelector, videoStream);
  6327. localVideoSrc = APP.RTC.getVideoSrc(localVideo);
  6328. var myResourceJid = APP.xmpp.myResource();
  6329. VideoLayout.updateLargeVideo(localVideoSrc, 0,
  6330. myResourceJid);
  6331. };
  6332. /**
  6333. * Adds or removes icons for not available camera and microphone.
  6334. * @param resourceJid the jid of user
  6335. * @param devices available devices
  6336. */
  6337. my.setDeviceAvailabilityIcons = function (resourceJid, devices) {
  6338. if(!devices)
  6339. return;
  6340. var container = null
  6341. if(!resourceJid)
  6342. {
  6343. container = $("#localVideoContainer")[0];
  6344. }
  6345. else
  6346. {
  6347. container = $("#participant_" + resourceJid)[0];
  6348. }
  6349. if(!container)
  6350. return;
  6351. $("#" + container.id + " > .noMic").remove();
  6352. $("#" + container.id + " > .noVideo").remove();
  6353. if(!devices.audio)
  6354. {
  6355. container.appendChild(document.createElement("div")).setAttribute("class","noMic");
  6356. }
  6357. if(!devices.video)
  6358. {
  6359. container.appendChild(document.createElement("div")).setAttribute("class","noVideo");
  6360. }
  6361. if(!devices.audio && !devices.video)
  6362. {
  6363. $("#" + container.id + " > .noMic").css("background-position", "75%");
  6364. $("#" + container.id + " > .noVideo").css("background-position", "25%");
  6365. $("#" + container.id + " > .noVideo").css("background-color", "transparent");
  6366. }
  6367. }
  6368. /**
  6369. * Checks if removed video is currently displayed and tries to display
  6370. * another one instead.
  6371. * @param removedVideoSrc src stream identifier of the video.
  6372. */
  6373. my.updateRemovedVideo = function(removedVideoSrc) {
  6374. if (removedVideoSrc === APP.RTC.getVideoSrc($('#largeVideo')[0])) {
  6375. // this is currently displayed as large
  6376. // pick the last visible video in the row
  6377. // if nobody else is left, this picks the local video
  6378. var pick
  6379. = $('#remoteVideos>span[id!="mixedstream"]:visible:last>video')
  6380. .get(0);
  6381. if (!pick) {
  6382. console.info("Last visible video no longer exists");
  6383. pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0);
  6384. if (!pick || !APP.RTC.getVideoSrc(pick)) {
  6385. // Try local video
  6386. console.info("Fallback to local video...");
  6387. pick = $('#remoteVideos>span>span>video').get(0);
  6388. }
  6389. }
  6390. // mute if localvideo
  6391. if (pick) {
  6392. var container = pick.parentNode;
  6393. var jid = null;
  6394. if(container)
  6395. {
  6396. if(container.id == "localVideoWrapper")
  6397. {
  6398. jid = APP.xmpp.myResource();
  6399. }
  6400. else
  6401. {
  6402. jid = VideoLayout.getPeerContainerResourceJid(container);
  6403. }
  6404. }
  6405. VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(pick), pick.volume, jid);
  6406. } else {
  6407. console.warn("Failed to elect large video");
  6408. }
  6409. }
  6410. };
  6411. my.onRemoteStreamAdded = function (stream) {
  6412. var container;
  6413. var remotes = document.getElementById('remoteVideos');
  6414. if (stream.peerjid) {
  6415. VideoLayout.ensurePeerContainerExists(stream.peerjid);
  6416. container = document.getElementById(
  6417. 'participant_' + Strophe.getResourceFromJid(stream.peerjid));
  6418. } else {
  6419. var id = stream.getOriginalStream().id;
  6420. if (id !== 'mixedmslabel'
  6421. // FIXME: default stream is added always with new focus
  6422. // (to be investigated)
  6423. && id !== 'default') {
  6424. console.error('can not associate stream',
  6425. id,
  6426. 'with a participant');
  6427. // We don't want to add it here since it will cause troubles
  6428. return;
  6429. }
  6430. // FIXME: for the mixed ms we dont need a video -- currently
  6431. container = document.createElement('span');
  6432. container.id = 'mixedstream';
  6433. container.className = 'videocontainer';
  6434. remotes.appendChild(container);
  6435. UIUtil.playSoundNotification('userJoined');
  6436. }
  6437. if (container) {
  6438. VideoLayout.addRemoteStreamElement( container,
  6439. stream.sid,
  6440. stream.getOriginalStream(),
  6441. stream.peerjid,
  6442. stream.ssrc);
  6443. }
  6444. }
  6445. my.getLargeVideoState = function () {
  6446. return largeVideoState;
  6447. };
  6448. /**
  6449. * Updates the large video with the given new video source.
  6450. */
  6451. my.updateLargeVideo = function(newSrc, vol, resourceJid) {
  6452. console.log('hover in', newSrc);
  6453. if (APP.RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc) {
  6454. $('#activeSpeaker').css('visibility', 'hidden');
  6455. // Due to the simulcast the localVideoSrc may have changed when the
  6456. // fadeOut event triggers. In that case the getJidFromVideoSrc and
  6457. // isVideoSrcDesktop methods will not function correctly.
  6458. //
  6459. // Also, again due to the simulcast, the updateLargeVideo method can
  6460. // be called multiple times almost simultaneously. Therefore, we
  6461. // store the state here and update only once.
  6462. largeVideoState.newSrc = newSrc;
  6463. largeVideoState.isVisible = $('#largeVideo').is(':visible');
  6464. largeVideoState.isDesktop = APP.RTC.isVideoSrcDesktop(
  6465. APP.xmpp.findJidFromResource(resourceJid));
  6466. if(largeVideoState.userResourceJid) {
  6467. largeVideoState.oldResourceJid = largeVideoState.userResourceJid;
  6468. } else {
  6469. largeVideoState.oldResourceJid = null;
  6470. }
  6471. largeVideoState.userResourceJid = resourceJid;
  6472. // Screen stream is already rotated
  6473. largeVideoState.flipX = (newSrc === localVideoSrc) && flipXLocalVideo;
  6474. var userChanged = false;
  6475. if (largeVideoState.oldResourceJid !== largeVideoState.userResourceJid) {
  6476. userChanged = true;
  6477. // we want the notification to trigger even if userJid is undefined,
  6478. // or null.
  6479. eventEmitter.emit(UIEvents.SELECTED_ENDPOINT,
  6480. largeVideoState.userResourceJid);
  6481. }
  6482. if (!largeVideoState.updateInProgress) {
  6483. largeVideoState.updateInProgress = true;
  6484. var doUpdate = function () {
  6485. Avatar.updateActiveSpeakerAvatarSrc(
  6486. APP.xmpp.findJidFromResource(
  6487. largeVideoState.userResourceJid));
  6488. if (!userChanged && largeVideoState.preload &&
  6489. largeVideoState.preload !== null &&
  6490. APP.RTC.getVideoSrc($(largeVideoState.preload)[0]) === newSrc)
  6491. {
  6492. console.info('Switching to preloaded video');
  6493. var attributes = $('#largeVideo').prop("attributes");
  6494. // loop through largeVideo attributes and apply them on
  6495. // preload.
  6496. $.each(attributes, function () {
  6497. if (this.name !== 'id' && this.name !== 'src') {
  6498. largeVideoState.preload.attr(this.name, this.value);
  6499. }
  6500. });
  6501. largeVideoState.preload.appendTo($('#largeVideoContainer'));
  6502. $('#largeVideo').attr('id', 'previousLargeVideo');
  6503. largeVideoState.preload.attr('id', 'largeVideo');
  6504. $('#previousLargeVideo').remove();
  6505. largeVideoState.preload.on('loadedmetadata', function (e) {
  6506. currentVideoWidth = this.videoWidth;
  6507. currentVideoHeight = this.videoHeight;
  6508. VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
  6509. });
  6510. largeVideoState.preload = null;
  6511. largeVideoState.preload_ssrc = 0;
  6512. } else {
  6513. APP.RTC.setVideoSrc($('#largeVideo')[0], largeVideoState.newSrc);
  6514. }
  6515. var videoTransform = document.getElementById('largeVideo')
  6516. .style.webkitTransform;
  6517. if (largeVideoState.flipX && videoTransform !== 'scaleX(-1)') {
  6518. document.getElementById('largeVideo').style.webkitTransform
  6519. = "scaleX(-1)";
  6520. }
  6521. else if (!largeVideoState.flipX && videoTransform === 'scaleX(-1)') {
  6522. document.getElementById('largeVideo').style.webkitTransform
  6523. = "none";
  6524. }
  6525. // Change the way we'll be measuring and positioning large video
  6526. VideoLayout.getVideoSize = largeVideoState.isDesktop
  6527. ? getDesktopVideoSize
  6528. : getCameraVideoSize;
  6529. VideoLayout.getVideoPosition = largeVideoState.isDesktop
  6530. ? getDesktopVideoPosition
  6531. : getCameraVideoPosition;
  6532. // Only if the large video is currently visible.
  6533. // Disable previous dominant speaker video.
  6534. if (largeVideoState.oldResourceJid) {
  6535. VideoLayout.enableDominantSpeaker(
  6536. largeVideoState.oldResourceJid,
  6537. false);
  6538. }
  6539. // Enable new dominant speaker in the remote videos section.
  6540. if (largeVideoState.userResourceJid) {
  6541. VideoLayout.enableDominantSpeaker(
  6542. largeVideoState.userResourceJid,
  6543. true);
  6544. }
  6545. if (userChanged && largeVideoState.isVisible) {
  6546. // using "this" should be ok because we're called
  6547. // from within the fadeOut event.
  6548. $(this).fadeIn(300);
  6549. }
  6550. if(userChanged) {
  6551. Avatar.showUserAvatar(
  6552. APP.xmpp.findJidFromResource(
  6553. largeVideoState.oldResourceJid));
  6554. }
  6555. largeVideoState.updateInProgress = false;
  6556. };
  6557. if (userChanged) {
  6558. $('#largeVideo').fadeOut(300, doUpdate);
  6559. } else {
  6560. doUpdate();
  6561. }
  6562. }
  6563. } else {
  6564. Avatar.showUserAvatar(
  6565. APP.xmpp.findJidFromResource(
  6566. largeVideoState.userResourceJid));
  6567. }
  6568. };
  6569. my.handleVideoThumbClicked = function(videoSrc,
  6570. noPinnedEndpointChangedEvent,
  6571. resourceJid) {
  6572. // Restore style for previously focused video
  6573. var oldContainer = null;
  6574. if(focusedVideoInfo) {
  6575. var focusResourceJid = focusedVideoInfo.resourceJid;
  6576. oldContainer = getParticipantContainer(focusResourceJid);
  6577. }
  6578. if (oldContainer) {
  6579. oldContainer.removeClass("videoContainerFocused");
  6580. }
  6581. // Unlock current focused.
  6582. if (focusedVideoInfo && focusedVideoInfo.src === videoSrc)
  6583. {
  6584. focusedVideoInfo = null;
  6585. var dominantSpeakerVideo = null;
  6586. // Enable the currently set dominant speaker.
  6587. if (currentDominantSpeaker) {
  6588. dominantSpeakerVideo
  6589. = $('#participant_' + currentDominantSpeaker + '>video')
  6590. .get(0);
  6591. if (dominantSpeakerVideo) {
  6592. VideoLayout.updateLargeVideo(
  6593. APP.RTC.getVideoSrc(dominantSpeakerVideo),
  6594. 1,
  6595. currentDominantSpeaker);
  6596. }
  6597. }
  6598. if (!noPinnedEndpointChangedEvent) {
  6599. eventEmitter.emit(UIEvents.PINNED_ENDPOINT);
  6600. }
  6601. return;
  6602. }
  6603. // Lock new video
  6604. focusedVideoInfo = {
  6605. src: videoSrc,
  6606. resourceJid: resourceJid
  6607. };
  6608. // Update focused/pinned interface.
  6609. if (resourceJid)
  6610. {
  6611. var container = getParticipantContainer(resourceJid);
  6612. container.addClass("videoContainerFocused");
  6613. if (!noPinnedEndpointChangedEvent) {
  6614. eventEmitter.emit(UIEvents.PINNED_ENDPOINT, resourceJid);
  6615. }
  6616. }
  6617. if ($('#largeVideo').attr('src') === videoSrc &&
  6618. VideoLayout.isLargeVideoOnTop()) {
  6619. return;
  6620. }
  6621. // Triggers a "video.selected" event. The "false" parameter indicates
  6622. // this isn't a prezi.
  6623. $(document).trigger("video.selected", [false]);
  6624. VideoLayout.updateLargeVideo(videoSrc, 1, resourceJid);
  6625. $('audio').each(function (idx, el) {
  6626. if (el.id.indexOf('mixedmslabel') !== -1) {
  6627. el.volume = 0;
  6628. el.volume = 1;
  6629. }
  6630. });
  6631. };
  6632. /**
  6633. * Positions the large video.
  6634. *
  6635. * @param videoWidth the stream video width
  6636. * @param videoHeight the stream video height
  6637. */
  6638. my.positionLarge = function (videoWidth, videoHeight) {
  6639. var videoSpaceWidth = $('#videospace').width();
  6640. var videoSpaceHeight = window.innerHeight;
  6641. var videoSize = VideoLayout.getVideoSize(videoWidth,
  6642. videoHeight,
  6643. videoSpaceWidth,
  6644. videoSpaceHeight);
  6645. var largeVideoWidth = videoSize[0];
  6646. var largeVideoHeight = videoSize[1];
  6647. var videoPosition = VideoLayout.getVideoPosition(largeVideoWidth,
  6648. largeVideoHeight,
  6649. videoSpaceWidth,
  6650. videoSpaceHeight);
  6651. var horizontalIndent = videoPosition[0];
  6652. var verticalIndent = videoPosition[1];
  6653. positionVideo($('#largeVideo'),
  6654. largeVideoWidth,
  6655. largeVideoHeight,
  6656. horizontalIndent, verticalIndent);
  6657. };
  6658. /**
  6659. * Shows/hides the large video.
  6660. */
  6661. my.setLargeVideoVisible = function(isVisible) {
  6662. var resourceJid = largeVideoState.userResourceJid;
  6663. if (isVisible) {
  6664. $('#largeVideo').css({visibility: 'visible'});
  6665. $('.watermark').css({visibility: 'visible'});
  6666. VideoLayout.enableDominantSpeaker(resourceJid, true);
  6667. }
  6668. else {
  6669. $('#largeVideo').css({visibility: 'hidden'});
  6670. $('#activeSpeaker').css('visibility', 'hidden');
  6671. $('.watermark').css({visibility: 'hidden'});
  6672. VideoLayout.enableDominantSpeaker(resourceJid, false);
  6673. if(focusedVideoInfo) {
  6674. var focusResourceJid = focusedVideoInfo.resourceJid;
  6675. var oldContainer = getParticipantContainer(focusResourceJid);
  6676. if (oldContainer && oldContainer.length > 0) {
  6677. oldContainer.removeClass("videoContainerFocused");
  6678. }
  6679. focusedVideoInfo = null;
  6680. if(focusResourceJid) {
  6681. Avatar.showUserAvatar(
  6682. APP.xmpp.findJidFromResource(focusResourceJid));
  6683. }
  6684. }
  6685. }
  6686. };
  6687. /**
  6688. * Indicates if the large video is currently visible.
  6689. *
  6690. * @return <tt>true</tt> if visible, <tt>false</tt> - otherwise
  6691. */
  6692. my.isLargeVideoVisible = function() {
  6693. return $('#largeVideo').is(':visible');
  6694. };
  6695. my.isLargeVideoOnTop = function () {
  6696. var Etherpad = require("../etherpad/Etherpad");
  6697. var Prezi = require("../prezi/Prezi");
  6698. return !Prezi.isPresentationVisible() && !Etherpad.isVisible();
  6699. };
  6700. /**
  6701. * Checks if container for participant identified by given peerJid exists
  6702. * in the document and creates it eventually.
  6703. *
  6704. * @param peerJid peer Jid to check.
  6705. * @param userId user email or id for setting the avatar
  6706. *
  6707. * @return Returns <tt>true</tt> if the peer container exists,
  6708. * <tt>false</tt> - otherwise
  6709. */
  6710. my.ensurePeerContainerExists = function(peerJid, userId) {
  6711. ContactList.ensureAddContact(peerJid, userId);
  6712. var resourceJid = Strophe.getResourceFromJid(peerJid);
  6713. var videoSpanId = 'participant_' + resourceJid;
  6714. if (!$('#' + videoSpanId).length) {
  6715. var container =
  6716. VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId, userId);
  6717. Avatar.setUserAvatar(peerJid, userId);
  6718. // Set default display name.
  6719. setDisplayName(videoSpanId);
  6720. VideoLayout.connectionIndicators[videoSpanId] =
  6721. new ConnectionIndicator(container, peerJid, VideoLayout);
  6722. var nickfield = document.createElement('span');
  6723. nickfield.className = "nick";
  6724. nickfield.appendChild(document.createTextNode(resourceJid));
  6725. container.appendChild(nickfield);
  6726. // In case this is not currently in the last n we don't show it.
  6727. if (localLastNCount
  6728. && localLastNCount > 0
  6729. && $('#remoteVideos>span').length >= localLastNCount + 2) {
  6730. showPeerContainer(resourceJid, 'hide');
  6731. }
  6732. else
  6733. VideoLayout.resizeThumbnails();
  6734. }
  6735. };
  6736. my.addRemoteVideoContainer = function(peerJid, spanId) {
  6737. var container = document.createElement('span');
  6738. container.id = spanId;
  6739. container.className = 'videocontainer';
  6740. var remotes = document.getElementById('remoteVideos');
  6741. remotes.appendChild(container);
  6742. // If the peerJid is null then this video span couldn't be directly
  6743. // associated with a participant (this could happen in the case of prezi).
  6744. if (APP.xmpp.isModerator() && peerJid !== null)
  6745. addRemoteVideoMenu(peerJid, container);
  6746. AudioLevels.updateAudioLevelCanvas(peerJid, VideoLayout);
  6747. return container;
  6748. };
  6749. /**
  6750. * Creates an audio or video stream element.
  6751. */
  6752. my.createStreamElement = function (sid, stream) {
  6753. var isVideo = stream.getVideoTracks().length > 0;
  6754. var element = isVideo
  6755. ? document.createElement('video')
  6756. : document.createElement('audio');
  6757. var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_')
  6758. + sid + '_' + APP.RTC.getStreamID(stream);
  6759. element.id = id;
  6760. element.autoplay = true;
  6761. element.oncontextmenu = function () { return false; };
  6762. return element;
  6763. };
  6764. my.addRemoteStreamElement
  6765. = function (container, sid, stream, peerJid, thessrc) {
  6766. var newElementId = null;
  6767. var isVideo = stream.getVideoTracks().length > 0;
  6768. if (container) {
  6769. var streamElement = VideoLayout.createStreamElement(sid, stream);
  6770. newElementId = streamElement.id;
  6771. container.appendChild(streamElement);
  6772. var sel = $('#' + newElementId);
  6773. sel.hide();
  6774. // If the container is currently visible we attach the stream.
  6775. if (!isVideo
  6776. || (container.offsetParent !== null && isVideo)) {
  6777. var videoStream = APP.simulcast.getReceivingVideoStream(stream);
  6778. APP.RTC.attachMediaStream(sel, videoStream);
  6779. if (isVideo)
  6780. waitForRemoteVideo(sel, thessrc, stream, peerJid);
  6781. }
  6782. stream.onended = function () {
  6783. console.log('stream ended', this);
  6784. VideoLayout.removeRemoteStreamElement(
  6785. stream, isVideo, container);
  6786. // NOTE(gp) it seems that under certain circumstances, the
  6787. // onended event is not fired and thus the contact list is not
  6788. // updated.
  6789. //
  6790. // The onended event of a stream should be fired when the SSRCs
  6791. // corresponding to that stream are removed from the SDP; but
  6792. // this doesn't seem to always be the case, resulting in ghost
  6793. // contacts.
  6794. //
  6795. // In an attempt to fix the ghost contacts problem, I'm moving
  6796. // the removeContact() method call in app.js, inside the
  6797. // 'muc.left' event handler.
  6798. //if (peerJid)
  6799. // ContactList.removeContact(peerJid);
  6800. };
  6801. // Add click handler.
  6802. container.onclick = function (event) {
  6803. /*
  6804. * FIXME It turns out that videoThumb may not exist (if there is
  6805. * no actual video).
  6806. */
  6807. var videoThumb = $('#' + container.id + '>video').get(0);
  6808. if (videoThumb) {
  6809. VideoLayout.handleVideoThumbClicked(
  6810. APP.RTC.getVideoSrc(videoThumb),
  6811. false,
  6812. Strophe.getResourceFromJid(peerJid));
  6813. }
  6814. event.stopPropagation();
  6815. event.preventDefault();
  6816. return false;
  6817. };
  6818. // Add hover handler
  6819. $(container).hover(
  6820. function() {
  6821. VideoLayout.showDisplayName(container.id, true);
  6822. },
  6823. function() {
  6824. var videoSrc = null;
  6825. if ($('#' + container.id + '>video')
  6826. && $('#' + container.id + '>video').length > 0) {
  6827. videoSrc = APP.RTC.getVideoSrc($('#' + container.id + '>video').get(0));
  6828. }
  6829. // If the video has been "pinned" by the user we want to
  6830. // keep the display name on place.
  6831. if (!VideoLayout.isLargeVideoVisible()
  6832. || videoSrc !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
  6833. VideoLayout.showDisplayName(container.id, false);
  6834. }
  6835. );
  6836. }
  6837. return newElementId;
  6838. };
  6839. /**
  6840. * Removes the remote stream element corresponding to the given stream and
  6841. * parent container.
  6842. *
  6843. * @param stream the stream
  6844. * @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
  6845. * @param container
  6846. */
  6847. my.removeRemoteStreamElement = function (stream, isVideo, container) {
  6848. if (!container)
  6849. return;
  6850. var select = null;
  6851. var removedVideoSrc = null;
  6852. if (isVideo) {
  6853. select = $('#' + container.id + '>video');
  6854. removedVideoSrc = APP.RTC.getVideoSrc(select.get(0));
  6855. }
  6856. else
  6857. select = $('#' + container.id + '>audio');
  6858. // Mark video as removed to cancel waiting loop(if video is removed
  6859. // before has started)
  6860. select.removed = true;
  6861. select.remove();
  6862. var audioCount = $('#' + container.id + '>audio').length;
  6863. var videoCount = $('#' + container.id + '>video').length;
  6864. if (!audioCount && !videoCount) {
  6865. console.log("Remove whole user", container.id);
  6866. if(VideoLayout.connectionIndicators[container.id])
  6867. VideoLayout.connectionIndicators[container.id].remove();
  6868. // Remove whole container
  6869. container.remove();
  6870. UIUtil.playSoundNotification('userLeft');
  6871. VideoLayout.resizeThumbnails();
  6872. }
  6873. if (removedVideoSrc)
  6874. VideoLayout.updateRemovedVideo(removedVideoSrc);
  6875. };
  6876. /**
  6877. * Show/hide peer container for the given resourceJid.
  6878. */
  6879. function showPeerContainer(resourceJid, state) {
  6880. var peerContainer = $('#participant_' + resourceJid);
  6881. if (!peerContainer)
  6882. return;
  6883. var isHide = state === 'hide';
  6884. var resizeThumbnails = false;
  6885. if (!isHide) {
  6886. if (!peerContainer.is(':visible')) {
  6887. resizeThumbnails = true;
  6888. peerContainer.show();
  6889. }
  6890. var jid = APP.xmpp.findJidFromResource(resourceJid);
  6891. if (state == 'show')
  6892. {
  6893. // peerContainer.css('-webkit-filter', '');
  6894. Avatar.showUserAvatar(jid, false);
  6895. }
  6896. else // if (state == 'avatar')
  6897. {
  6898. // peerContainer.css('-webkit-filter', 'grayscale(100%)');
  6899. Avatar.showUserAvatar(jid, true);
  6900. }
  6901. }
  6902. else if (peerContainer.is(':visible') && isHide)
  6903. {
  6904. resizeThumbnails = true;
  6905. peerContainer.hide();
  6906. if(VideoLayout.connectionIndicators['participant_' + resourceJid])
  6907. VideoLayout.connectionIndicators['participant_' + resourceJid].hide();
  6908. }
  6909. if (resizeThumbnails) {
  6910. VideoLayout.resizeThumbnails();
  6911. }
  6912. // We want to be able to pin a participant from the contact list, even
  6913. // if he's not in the lastN set!
  6914. // ContactList.setClickable(resourceJid, !isHide);
  6915. };
  6916. my.inputDisplayNameHandler = function (name) {
  6917. NicknameHandler.setNickname(name);
  6918. if (!$('#localDisplayName').is(":visible")) {
  6919. if (NicknameHandler.getNickname())
  6920. {
  6921. var meHTML = APP.translation.generateTranslatonHTML("me");
  6922. $('#localDisplayName').html(NicknameHandler.getNickname() + " (" + meHTML + ")");
  6923. }
  6924. else
  6925. {
  6926. var defaultHTML = APP.translation.generateTranslatonHTML(
  6927. interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
  6928. $('#localDisplayName')
  6929. .html(defaultHTML);
  6930. }
  6931. $('#localDisplayName').show();
  6932. }
  6933. $('#editDisplayName').hide();
  6934. };
  6935. /**
  6936. * Shows/hides the display name on the remote video.
  6937. * @param videoSpanId the identifier of the video span element
  6938. * @param isShow indicates if the display name should be shown or hidden
  6939. */
  6940. my.showDisplayName = function(videoSpanId, isShow) {
  6941. var nameSpan = $('#' + videoSpanId + '>span.displayname').get(0);
  6942. if (isShow) {
  6943. if (nameSpan && nameSpan.innerHTML && nameSpan.innerHTML.length)
  6944. nameSpan.setAttribute("style", "display:inline-block;");
  6945. }
  6946. else {
  6947. if (nameSpan)
  6948. nameSpan.setAttribute("style", "display:none;");
  6949. }
  6950. };
  6951. /**
  6952. * Shows the presence status message for the given video.
  6953. */
  6954. my.setPresenceStatus = function (videoSpanId, statusMsg) {
  6955. if (!$('#' + videoSpanId).length) {
  6956. // No container
  6957. return;
  6958. }
  6959. var statusSpan = $('#' + videoSpanId + '>span.status');
  6960. if (!statusSpan.length) {
  6961. //Add status span
  6962. statusSpan = document.createElement('span');
  6963. statusSpan.className = 'status';
  6964. statusSpan.id = videoSpanId + '_status';
  6965. $('#' + videoSpanId)[0].appendChild(statusSpan);
  6966. statusSpan = $('#' + videoSpanId + '>span.status');
  6967. }
  6968. // Display status
  6969. if (statusMsg && statusMsg.length) {
  6970. $('#' + videoSpanId + '_status').text(statusMsg);
  6971. statusSpan.get(0).setAttribute("style", "display:inline-block;");
  6972. }
  6973. else {
  6974. // Hide
  6975. statusSpan.get(0).setAttribute("style", "display:none;");
  6976. }
  6977. };
  6978. /**
  6979. * Shows a visual indicator for the moderator of the conference.
  6980. */
  6981. my.showModeratorIndicator = function () {
  6982. var isModerator = APP.xmpp.isModerator();
  6983. if (isModerator) {
  6984. var indicatorSpan = $('#localVideoContainer .focusindicator');
  6985. if (indicatorSpan.children().length === 0)
  6986. {
  6987. createModeratorIndicatorElement(indicatorSpan[0]);
  6988. //translates text in focus indicator
  6989. APP.translation.translateElement($('#localVideoContainer .focusindicator'));
  6990. }
  6991. }
  6992. var members = APP.xmpp.getMembers();
  6993. Object.keys(members).forEach(function (jid) {
  6994. if (Strophe.getResourceFromJid(jid) === 'focus') {
  6995. // Skip server side focus
  6996. return;
  6997. }
  6998. var resourceJid = Strophe.getResourceFromJid(jid);
  6999. var videoSpanId = 'participant_' + resourceJid;
  7000. var videoContainer = document.getElementById(videoSpanId);
  7001. if (!videoContainer) {
  7002. console.error("No video container for " + jid);
  7003. return;
  7004. }
  7005. var member = members[jid];
  7006. if (member.role === 'moderator') {
  7007. // Remove menu if peer is moderator
  7008. var menuSpan = $('#' + videoSpanId + '>span.remotevideomenu');
  7009. if (menuSpan.length) {
  7010. removeRemoteVideoMenu(videoSpanId);
  7011. }
  7012. // Show moderator indicator
  7013. var indicatorSpan
  7014. = $('#' + videoSpanId + ' .focusindicator');
  7015. if (!indicatorSpan || indicatorSpan.length === 0) {
  7016. indicatorSpan = document.createElement('span');
  7017. indicatorSpan.className = 'focusindicator';
  7018. videoContainer.appendChild(indicatorSpan);
  7019. createModeratorIndicatorElement(indicatorSpan);
  7020. //translates text in focus indicators
  7021. APP.translation.translateElement($('#' + videoSpanId + ' .focusindicator'));
  7022. }
  7023. } else if (isModerator) {
  7024. // We are moderator, but user is not - add menu
  7025. if ($('#remote_popupmenu_' + resourceJid).length <= 0) {
  7026. addRemoteVideoMenu(
  7027. jid,
  7028. document.getElementById('participant_' + resourceJid));
  7029. }
  7030. }
  7031. });
  7032. };
  7033. /**
  7034. * Shows video muted indicator over small videos.
  7035. */
  7036. my.showVideoIndicator = function(videoSpanId, isMuted) {
  7037. var videoMutedSpan = $('#' + videoSpanId + '>span.videoMuted');
  7038. if (isMuted === 'false') {
  7039. if (videoMutedSpan.length > 0) {
  7040. videoMutedSpan.remove();
  7041. }
  7042. }
  7043. else {
  7044. if(videoMutedSpan.length == 0) {
  7045. videoMutedSpan = document.createElement('span');
  7046. videoMutedSpan.className = 'videoMuted';
  7047. $('#' + videoSpanId)[0].appendChild(videoMutedSpan);
  7048. var mutedIndicator = document.createElement('i');
  7049. mutedIndicator.className = 'icon-camera-disabled';
  7050. UIUtil.setTooltip(mutedIndicator,
  7051. "videothumbnail.videomute",
  7052. "top");
  7053. videoMutedSpan.appendChild(mutedIndicator);
  7054. //translate texts for muted indicator
  7055. APP.translation.translateElement($('#' + videoSpanId + " > span > i"));
  7056. }
  7057. VideoLayout.updateMutePosition(videoSpanId);
  7058. }
  7059. };
  7060. my.updateMutePosition = function (videoSpanId) {
  7061. var audioMutedSpan = $('#' + videoSpanId + '>span.audioMuted');
  7062. var connectionIndicator = $('#' + videoSpanId + '>div.connectionindicator');
  7063. var videoMutedSpan = $('#' + videoSpanId + '>span.videoMuted');
  7064. if(connectionIndicator.length > 0
  7065. && connectionIndicator[0].style.display != "none") {
  7066. audioMutedSpan.css({right: "23px"});
  7067. videoMutedSpan.css({right: ((audioMutedSpan.length > 0? 23 : 0) + 30) + "px"});
  7068. }
  7069. else
  7070. {
  7071. audioMutedSpan.css({right: "0px"});
  7072. videoMutedSpan.css({right: (audioMutedSpan.length > 0? 30 : 0) + "px"});
  7073. }
  7074. }
  7075. /**
  7076. * Shows audio muted indicator over small videos.
  7077. * @param {string} isMuted
  7078. */
  7079. my.showAudioIndicator = function(videoSpanId, isMuted) {
  7080. var audioMutedSpan = $('#' + videoSpanId + '>span.audioMuted');
  7081. if (isMuted === 'false') {
  7082. if (audioMutedSpan.length > 0) {
  7083. audioMutedSpan.popover('hide');
  7084. audioMutedSpan.remove();
  7085. }
  7086. }
  7087. else {
  7088. if(audioMutedSpan.length == 0 ) {
  7089. audioMutedSpan = document.createElement('span');
  7090. audioMutedSpan.className = 'audioMuted';
  7091. UIUtil.setTooltip(audioMutedSpan,
  7092. "videothumbnail.mute",
  7093. "top");
  7094. $('#' + videoSpanId)[0].appendChild(audioMutedSpan);
  7095. APP.translation.translateElement($('#' + videoSpanId + " > span"));
  7096. var mutedIndicator = document.createElement('i');
  7097. mutedIndicator.className = 'icon-mic-disabled';
  7098. audioMutedSpan.appendChild(mutedIndicator);
  7099. }
  7100. VideoLayout.updateMutePosition(videoSpanId);
  7101. }
  7102. };
  7103. /*
  7104. * Shows or hides the audio muted indicator over the local thumbnail video.
  7105. * @param {boolean} isMuted
  7106. */
  7107. my.showLocalAudioIndicator = function(isMuted) {
  7108. VideoLayout.showAudioIndicator('localVideoContainer', isMuted.toString());
  7109. };
  7110. /**
  7111. * Resizes the large video container.
  7112. */
  7113. my.resizeLargeVideoContainer = function () {
  7114. Chat.resizeChat();
  7115. var availableHeight = window.innerHeight;
  7116. var availableWidth = UIUtil.getAvailableVideoWidth();
  7117. if (availableWidth < 0 || availableHeight < 0) return;
  7118. $('#videospace').width(availableWidth);
  7119. $('#videospace').height(availableHeight);
  7120. $('#largeVideoContainer').width(availableWidth);
  7121. $('#largeVideoContainer').height(availableHeight);
  7122. var avatarSize = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE;
  7123. var top = availableHeight / 2 - avatarSize / 4 * 3;
  7124. $('#activeSpeaker').css('top', top);
  7125. VideoLayout.resizeThumbnails();
  7126. };
  7127. /**
  7128. * Resizes thumbnails.
  7129. */
  7130. my.resizeThumbnails = function() {
  7131. var videoSpaceWidth = $('#remoteVideos').width();
  7132. var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
  7133. var width = thumbnailSize[0];
  7134. var height = thumbnailSize[1];
  7135. // size videos so that while keeping AR and max height, we have a
  7136. // nice fit
  7137. $('#remoteVideos').height(height);
  7138. $('#remoteVideos>span').width(width);
  7139. $('#remoteVideos>span').height(height);
  7140. $('.userAvatar').css('left', (width - height) / 2);
  7141. $(document).trigger("remotevideo.resized", [width, height]);
  7142. };
  7143. /**
  7144. * Enables the dominant speaker UI.
  7145. *
  7146. * @param resourceJid the jid indicating the video element to
  7147. * activate/deactivate
  7148. * @param isEnable indicates if the dominant speaker should be enabled or
  7149. * disabled
  7150. */
  7151. my.enableDominantSpeaker = function(resourceJid, isEnable) {
  7152. var videoSpanId = null;
  7153. var videoContainerId = null;
  7154. if (resourceJid
  7155. === APP.xmpp.myResource()) {
  7156. videoSpanId = 'localVideoWrapper';
  7157. videoContainerId = 'localVideoContainer';
  7158. }
  7159. else {
  7160. videoSpanId = 'participant_' + resourceJid;
  7161. videoContainerId = videoSpanId;
  7162. }
  7163. var displayName = resourceJid;
  7164. var nameSpan = $('#' + videoContainerId + '>span.displayname');
  7165. if (nameSpan.length > 0)
  7166. displayName = nameSpan.html();
  7167. console.log("UI enable dominant speaker",
  7168. displayName,
  7169. resourceJid,
  7170. isEnable);
  7171. videoSpan = document.getElementById(videoContainerId);
  7172. if (!videoSpan) {
  7173. return;
  7174. }
  7175. var video = $('#' + videoSpanId + '>video');
  7176. if (video && video.length > 0) {
  7177. if (isEnable) {
  7178. var isLargeVideoVisible = VideoLayout.isLargeVideoOnTop();
  7179. VideoLayout.showDisplayName(videoContainerId, isLargeVideoVisible);
  7180. if (!videoSpan.classList.contains("dominantspeaker"))
  7181. videoSpan.classList.add("dominantspeaker");
  7182. }
  7183. else {
  7184. VideoLayout.showDisplayName(videoContainerId, false);
  7185. if (videoSpan.classList.contains("dominantspeaker"))
  7186. videoSpan.classList.remove("dominantspeaker");
  7187. }
  7188. Avatar.showUserAvatar(
  7189. APP.xmpp.findJidFromResource(resourceJid));
  7190. }
  7191. };
  7192. /**
  7193. * Calculates the thumbnail size.
  7194. *
  7195. * @param videoSpaceWidth the width of the video space
  7196. */
  7197. my.calculateThumbnailSize = function (videoSpaceWidth) {
  7198. // Calculate the available height, which is the inner window height minus
  7199. // 39px for the header minus 2px for the delimiter lines on the top and
  7200. // bottom of the large video, minus the 36px space inside the remoteVideos
  7201. // container used for highlighting shadow.
  7202. var availableHeight = 100;
  7203. var numvids = $('#remoteVideos>span:visible').length;
  7204. if (localLastNCount && localLastNCount > 0) {
  7205. numvids = Math.min(localLastNCount + 1, numvids);
  7206. }
  7207. // Remove the 3px borders arround videos and border around the remote
  7208. // videos area and the 4 pixels between the local video and the others
  7209. //TODO: Find out where the 4 pixels come from and remove them
  7210. var availableWinWidth = videoSpaceWidth - 2 * 3 * numvids - 70 - 4;
  7211. var availableWidth = availableWinWidth / numvids;
  7212. var aspectRatio = 16.0 / 9.0;
  7213. var maxHeight = Math.min(160, availableHeight);
  7214. availableHeight = Math.min(maxHeight, availableWidth / aspectRatio);
  7215. if (availableHeight < availableWidth / aspectRatio) {
  7216. availableWidth = Math.floor(availableHeight * aspectRatio);
  7217. }
  7218. return [availableWidth, availableHeight];
  7219. };
  7220. /**
  7221. * Updates the remote video menu.
  7222. *
  7223. * @param jid the jid indicating the video for which we're adding a menu.
  7224. * @param isMuted indicates the current mute state
  7225. */
  7226. my.updateRemoteVideoMenu = function(jid, isMuted) {
  7227. var muteMenuItem
  7228. = $('#remote_popupmenu_'
  7229. + Strophe.getResourceFromJid(jid)
  7230. + '>li>a.mutelink');
  7231. var mutedIndicator = "<i class='icon-mic-disabled'></i>";
  7232. if (muteMenuItem.length) {
  7233. var muteLink = muteMenuItem.get(0);
  7234. if (isMuted === 'true') {
  7235. muteLink.innerHTML = mutedIndicator + ' Muted';
  7236. muteLink.className = 'mutelink disabled';
  7237. }
  7238. else {
  7239. muteLink.innerHTML = mutedIndicator + ' Mute';
  7240. muteLink.className = 'mutelink';
  7241. }
  7242. }
  7243. };
  7244. /**
  7245. * Returns the current dominant speaker resource jid.
  7246. */
  7247. my.getDominantSpeakerResourceJid = function () {
  7248. return currentDominantSpeaker;
  7249. };
  7250. /**
  7251. * Returns the corresponding resource jid to the given peer container
  7252. * DOM element.
  7253. *
  7254. * @return the corresponding resource jid to the given peer container
  7255. * DOM element
  7256. */
  7257. my.getPeerContainerResourceJid = function (containerElement) {
  7258. var i = containerElement.id.indexOf('participant_');
  7259. if (i >= 0)
  7260. return containerElement.id.substring(i + 12);
  7261. };
  7262. /**
  7263. * On contact list item clicked.
  7264. */
  7265. $(ContactList).bind('contactclicked', function(event, jid) {
  7266. if (!jid) {
  7267. return;
  7268. }
  7269. var resource = Strophe.getResourceFromJid(jid);
  7270. var videoContainer = $("#participant_" + resource);
  7271. if (videoContainer.length > 0) {
  7272. var videoThumb = $('video', videoContainer).get(0);
  7273. // It is not always the case that a videoThumb exists (if there is
  7274. // no actual video).
  7275. if (videoThumb) {
  7276. if (videoThumb.src && videoThumb.src != '') {
  7277. // We have a video src, great! Let's update the large video
  7278. // now.
  7279. VideoLayout.handleVideoThumbClicked(
  7280. videoThumb.src,
  7281. false,
  7282. Strophe.getResourceFromJid(jid));
  7283. } else {
  7284. // If we don't have a video src for jid, there's absolutely
  7285. // no point in calling handleVideoThumbClicked; Quite
  7286. // simply, it won't work because it needs an src to attach
  7287. // to the large video.
  7288. //
  7289. // Instead, we trigger the pinned endpoint changed event to
  7290. // let the bridge adjust its lastN set for myjid and store
  7291. // the pinned user in the lastNPickupJid variable to be
  7292. // picked up later by the lastN changed event handler.
  7293. lastNPickupJid = jid;
  7294. eventEmitter.emit(UIEvents.PINNED_ENDPOINT,
  7295. Strophe.getResourceFromJid(jid));
  7296. }
  7297. } else if (jid == APP.xmpp.myJid()) {
  7298. $("#localVideoContainer").click();
  7299. }
  7300. }
  7301. });
  7302. /**
  7303. * On audio muted event.
  7304. */
  7305. $(document).bind('audiomuted.muc', function (event, jid, isMuted) {
  7306. /*
  7307. // FIXME: but focus can not mute in this case ? - check
  7308. if (jid === xmpp.myJid()) {
  7309. // The local mute indicator is controlled locally
  7310. return;
  7311. }*/
  7312. var videoSpanId = null;
  7313. if (jid === APP.xmpp.myJid()) {
  7314. videoSpanId = 'localVideoContainer';
  7315. } else {
  7316. VideoLayout.ensurePeerContainerExists(jid);
  7317. videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
  7318. }
  7319. mutedAudios[jid] = isMuted;
  7320. if (APP.xmpp.isModerator()) {
  7321. VideoLayout.updateRemoteVideoMenu(jid, isMuted);
  7322. }
  7323. if (videoSpanId)
  7324. VideoLayout.showAudioIndicator(videoSpanId, isMuted);
  7325. });
  7326. /**
  7327. * On video muted event.
  7328. */
  7329. $(document).bind('videomuted.muc', function (event, jid, value) {
  7330. var isMuted = (value === "true");
  7331. if(jid !== APP.xmpp.myJid() && !APP.RTC.muteRemoteVideoStream(jid, isMuted))
  7332. return;
  7333. Avatar.showUserAvatar(jid, isMuted);
  7334. var videoSpanId = null;
  7335. if (jid === APP.xmpp.myJid()) {
  7336. videoSpanId = 'localVideoContainer';
  7337. } else {
  7338. VideoLayout.ensurePeerContainerExists(jid);
  7339. videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
  7340. }
  7341. if (videoSpanId)
  7342. VideoLayout.showVideoIndicator(videoSpanId, value);
  7343. });
  7344. /**
  7345. * Display name changed.
  7346. */
  7347. my.onDisplayNameChanged =
  7348. function (jid, displayName, status) {
  7349. if (jid === 'localVideoContainer'
  7350. || jid === APP.xmpp.myJid()) {
  7351. setDisplayName('localVideoContainer',
  7352. displayName);
  7353. } else {
  7354. VideoLayout.ensurePeerContainerExists(jid);
  7355. setDisplayName(
  7356. 'participant_' + Strophe.getResourceFromJid(jid),
  7357. displayName,
  7358. status);
  7359. }
  7360. };
  7361. /**
  7362. * On dominant speaker changed event.
  7363. */
  7364. my.onDominantSpeakerChanged = function (resourceJid) {
  7365. // We ignore local user events.
  7366. if (resourceJid
  7367. === APP.xmpp.myResource())
  7368. return;
  7369. var members = APP.xmpp.getMembers();
  7370. // Update the current dominant speaker.
  7371. if (resourceJid !== currentDominantSpeaker) {
  7372. var oldSpeakerVideoSpanId = "participant_" + currentDominantSpeaker,
  7373. newSpeakerVideoSpanId = "participant_" + resourceJid;
  7374. var currentJID = APP.xmpp.findJidFromResource(currentDominantSpeaker);
  7375. var newJID = APP.xmpp.findJidFromResource(resourceJid);
  7376. if(currentDominantSpeaker && (!members || !members[currentJID] ||
  7377. !members[currentJID].displayName)) {
  7378. setDisplayName(oldSpeakerVideoSpanId, null);
  7379. }
  7380. if(resourceJid && (!members || !members[newJID] ||
  7381. !members[newJID].displayName)) {
  7382. setDisplayName(newSpeakerVideoSpanId, null,
  7383. interfaceConfig.DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME);
  7384. }
  7385. currentDominantSpeaker = resourceJid;
  7386. } else {
  7387. return;
  7388. }
  7389. // Obtain container for new dominant speaker.
  7390. var container = document.getElementById(
  7391. 'participant_' + resourceJid);
  7392. // Local video will not have container found, but that's ok
  7393. // since we don't want to switch to local video.
  7394. if (container && !focusedVideoInfo)
  7395. {
  7396. var video = container.getElementsByTagName("video");
  7397. // Update the large video if the video source is already available,
  7398. // otherwise wait for the "videoactive.jingle" event.
  7399. if (video.length && video[0].currentTime > 0)
  7400. VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(video[0]), resourceJid);
  7401. }
  7402. };
  7403. /**
  7404. * On last N change event.
  7405. *
  7406. * @param lastNEndpoints the list of last N endpoints
  7407. * @param endpointsEnteringLastN the list currently entering last N
  7408. * endpoints
  7409. */
  7410. my.onLastNEndpointsChanged = function ( lastNEndpoints,
  7411. endpointsEnteringLastN,
  7412. stream) {
  7413. if (lastNCount !== lastNEndpoints.length)
  7414. lastNCount = lastNEndpoints.length;
  7415. lastNEndpointsCache = lastNEndpoints;
  7416. // Say A, B, C, D, E, and F are in a conference and LastN = 3.
  7417. //
  7418. // If LastN drops to, say, 2, because of adaptivity, then E should see
  7419. // thumbnails for A, B and C. A and B are in E's server side LastN set,
  7420. // so E sees them. C is only in E's local LastN set.
  7421. //
  7422. // If F starts talking and LastN = 3, then E should see thumbnails for
  7423. // F, A, B. B gets "ejected" from E's server side LastN set, but it
  7424. // enters E's local LastN ejecting C.
  7425. // Increase the local LastN set size, if necessary.
  7426. if (lastNCount > localLastNCount) {
  7427. localLastNCount = lastNCount;
  7428. }
  7429. // Update the local LastN set preserving the order in which the
  7430. // endpoints appeared in the LastN/local LastN set.
  7431. var nextLocalLastNSet = lastNEndpoints.slice(0);
  7432. for (var i = 0; i < localLastNSet.length; i++) {
  7433. if (nextLocalLastNSet.length >= localLastNCount) {
  7434. break;
  7435. }
  7436. var resourceJid = localLastNSet[i];
  7437. if (nextLocalLastNSet.indexOf(resourceJid) === -1) {
  7438. nextLocalLastNSet.push(resourceJid);
  7439. }
  7440. }
  7441. localLastNSet = nextLocalLastNSet;
  7442. var updateLargeVideo = false;
  7443. // Handle LastN/local LastN changes.
  7444. $('#remoteVideos>span').each(function( index, element ) {
  7445. var resourceJid = VideoLayout.getPeerContainerResourceJid(element);
  7446. var isReceived = true;
  7447. if (resourceJid
  7448. && lastNEndpoints.indexOf(resourceJid) < 0
  7449. && localLastNSet.indexOf(resourceJid) < 0) {
  7450. console.log("Remove from last N", resourceJid);
  7451. showPeerContainer(resourceJid, 'hide');
  7452. isReceived = false;
  7453. } else if (resourceJid
  7454. && $('#participant_' + resourceJid).is(':visible')
  7455. && lastNEndpoints.indexOf(resourceJid) < 0
  7456. && localLastNSet.indexOf(resourceJid) >= 0) {
  7457. showPeerContainer(resourceJid, 'avatar');
  7458. isReceived = false;
  7459. }
  7460. if (!isReceived) {
  7461. // resourceJid has dropped out of the server side lastN set, so
  7462. // it is no longer being received. If resourceJid was being
  7463. // displayed in the large video we have to switch to another
  7464. // user.
  7465. var largeVideoResource = largeVideoState.userResourceJid;
  7466. if (!updateLargeVideo && resourceJid === largeVideoResource) {
  7467. updateLargeVideo = true;
  7468. }
  7469. }
  7470. });
  7471. if (!endpointsEnteringLastN || endpointsEnteringLastN.length < 0)
  7472. endpointsEnteringLastN = lastNEndpoints;
  7473. if (endpointsEnteringLastN && endpointsEnteringLastN.length > 0) {
  7474. endpointsEnteringLastN.forEach(function (resourceJid) {
  7475. var isVisible = $('#participant_' + resourceJid).is(':visible');
  7476. showPeerContainer(resourceJid, 'show');
  7477. if (!isVisible) {
  7478. console.log("Add to last N", resourceJid);
  7479. var jid = APP.xmpp.findJidFromResource(resourceJid);
  7480. var mediaStream = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  7481. var sel = $('#participant_' + resourceJid + '>video');
  7482. var videoStream = APP.simulcast.getReceivingVideoStream(
  7483. mediaStream.stream);
  7484. APP.RTC.attachMediaStream(sel, videoStream);
  7485. if (lastNPickupJid == mediaStream.peerjid) {
  7486. // Clean up the lastN pickup jid.
  7487. lastNPickupJid = null;
  7488. // Don't fire the events again, they've already
  7489. // been fired in the contact list click handler.
  7490. VideoLayout.handleVideoThumbClicked(
  7491. $(sel).attr('src'),
  7492. false,
  7493. Strophe.getResourceFromJid(mediaStream.peerjid));
  7494. updateLargeVideo = false;
  7495. }
  7496. waitForRemoteVideo(sel, mediaStream.ssrc, mediaStream.stream, resourceJid);
  7497. }
  7498. })
  7499. }
  7500. // The endpoint that was being shown in the large video has dropped out
  7501. // of the lastN set and there was no lastN pickup jid. We need to update
  7502. // the large video now.
  7503. if (updateLargeVideo) {
  7504. var resource, container, src;
  7505. var myResource
  7506. = APP.xmpp.myResource();
  7507. // Find out which endpoint to show in the large video.
  7508. for (var i = 0; i < lastNEndpoints.length; i++) {
  7509. resource = lastNEndpoints[i];
  7510. if (!resource || resource === myResource)
  7511. continue;
  7512. container = $("#participant_" + resource);
  7513. if (container.length == 0)
  7514. continue;
  7515. src = $('video', container).attr('src');
  7516. if (!src)
  7517. continue;
  7518. // videoSrcToSsrc needs to be update for this call to succeed.
  7519. VideoLayout.updateLargeVideo(src);
  7520. break;
  7521. }
  7522. }
  7523. };
  7524. my.onSimulcastLayersChanging = function (endpointSimulcastLayers) {
  7525. endpointSimulcastLayers.forEach(function (esl) {
  7526. var resource = esl.endpoint;
  7527. // if lastN is enabled *and* the endpoint is *not* in the lastN set,
  7528. // then ignore the event (= do not preload anything).
  7529. //
  7530. // The bridge could probably stop sending this message if it's for
  7531. // an endpoint that's not in lastN.
  7532. if (lastNCount != -1
  7533. && (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) {
  7534. return;
  7535. }
  7536. var primarySSRC = esl.simulcastLayer.primarySSRC;
  7537. // Get session and stream from primary ssrc.
  7538. var res = APP.simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
  7539. var sid = res.sid;
  7540. var electedStream = res.stream;
  7541. if (sid && electedStream) {
  7542. var msid = APP.simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
  7543. console.info([esl, primarySSRC, msid, sid, electedStream]);
  7544. var preload = (Strophe.getResourceFromJid(APP.xmpp.getJidFromSSRC(primarySSRC)) == largeVideoState.userResourceJid);
  7545. if (preload) {
  7546. if (largeVideoState.preload)
  7547. {
  7548. $(largeVideoState.preload).remove();
  7549. }
  7550. console.info('Preloading remote video');
  7551. largeVideoState.preload = $('<video autoplay></video>');
  7552. // ssrcs are unique in an rtp session
  7553. largeVideoState.preload_ssrc = primarySSRC;
  7554. APP.RTC.attachMediaStream(largeVideoState.preload, electedStream)
  7555. }
  7556. } else {
  7557. console.error('Could not find a stream or a session.', sid, electedStream);
  7558. }
  7559. });
  7560. };
  7561. /**
  7562. * On simulcast layers changed event.
  7563. */
  7564. my.onSimulcastLayersChanged = function (endpointSimulcastLayers) {
  7565. endpointSimulcastLayers.forEach(function (esl) {
  7566. var resource = esl.endpoint;
  7567. // if lastN is enabled *and* the endpoint is *not* in the lastN set,
  7568. // then ignore the event (= do not change large video/thumbnail
  7569. // SRCs).
  7570. //
  7571. // Note that even if we ignore the "changed" event in this event
  7572. // handler, the bridge must continue sending these events because
  7573. // the simulcast code in simulcast.js uses it to know what's going
  7574. // to be streamed by the bridge when/if the endpoint gets back into
  7575. // the lastN set.
  7576. if (lastNCount != -1
  7577. && (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) {
  7578. return;
  7579. }
  7580. var primarySSRC = esl.simulcastLayer.primarySSRC;
  7581. // Get session and stream from primary ssrc.
  7582. var res = APP.simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
  7583. var sid = res.sid;
  7584. var electedStream = res.stream;
  7585. if (sid && electedStream) {
  7586. var msid = APP.simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
  7587. console.info('Switching simulcast substream.');
  7588. console.info([esl, primarySSRC, msid, sid, electedStream]);
  7589. var msidParts = msid.split(' ');
  7590. var selRemoteVideo = $(['#', 'remoteVideo_', sid, '_', msidParts[0]].join(''));
  7591. var updateLargeVideo = (Strophe.getResourceFromJid(APP.xmpp.getJidFromSSRC(primarySSRC))
  7592. == largeVideoState.userResourceJid);
  7593. var updateFocusedVideoSrc = (focusedVideoInfo && focusedVideoInfo.src && focusedVideoInfo.src != '' &&
  7594. (APP.RTC.getVideoSrc(selRemoteVideo[0]) == focusedVideoInfo.src));
  7595. var electedStreamUrl;
  7596. if (largeVideoState.preload_ssrc == primarySSRC)
  7597. {
  7598. APP.RTC.setVideoSrc(selRemoteVideo[0], APP.RTC.getVideoSrc(largeVideoState.preload[0]));
  7599. }
  7600. else
  7601. {
  7602. if (largeVideoState.preload
  7603. && largeVideoState.preload != null) {
  7604. $(largeVideoState.preload).remove();
  7605. }
  7606. largeVideoState.preload_ssrc = 0;
  7607. APP.RTC.attachMediaStream(selRemoteVideo, electedStream);
  7608. }
  7609. var jid = APP.xmpp.getJidFromSSRC(primarySSRC);
  7610. if (updateLargeVideo) {
  7611. VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(selRemoteVideo[0]), null,
  7612. Strophe.getResourceFromJid(jid));
  7613. }
  7614. if (updateFocusedVideoSrc) {
  7615. focusedVideoInfo.src = APP.RTC.getVideoSrc(selRemoteVideo[0]);
  7616. }
  7617. var videoId;
  7618. if(resource == APP.xmpp.myResource())
  7619. {
  7620. videoId = "localVideoContainer";
  7621. }
  7622. else
  7623. {
  7624. videoId = "participant_" + resource;
  7625. }
  7626. var connectionIndicator = VideoLayout.connectionIndicators[videoId];
  7627. if(connectionIndicator)
  7628. connectionIndicator.updatePopoverData();
  7629. } else {
  7630. console.error('Could not find a stream or a sid.', sid, electedStream);
  7631. }
  7632. });
  7633. };
  7634. /**
  7635. * Updates local stats
  7636. * @param percent
  7637. * @param object
  7638. */
  7639. my.updateLocalConnectionStats = function (percent, object) {
  7640. var resolution = null;
  7641. if(object.resolution !== null)
  7642. {
  7643. resolution = object.resolution;
  7644. object.resolution = resolution[APP.xmpp.myJid()];
  7645. delete resolution[APP.xmpp.myJid()];
  7646. }
  7647. updateStatsIndicator("localVideoContainer", percent, object);
  7648. for(var jid in resolution)
  7649. {
  7650. if(resolution[jid] === null)
  7651. continue;
  7652. var id = 'participant_' + Strophe.getResourceFromJid(jid);
  7653. if(VideoLayout.connectionIndicators[id])
  7654. {
  7655. VideoLayout.connectionIndicators[id].updateResolution(resolution[jid]);
  7656. }
  7657. }
  7658. };
  7659. /**
  7660. * Updates remote stats.
  7661. * @param jid the jid associated with the stats
  7662. * @param percent the connection quality percent
  7663. * @param object the stats data
  7664. */
  7665. my.updateConnectionStats = function (jid, percent, object) {
  7666. var resourceJid = Strophe.getResourceFromJid(jid);
  7667. var videoSpanId = 'participant_' + resourceJid;
  7668. updateStatsIndicator(videoSpanId, percent, object);
  7669. };
  7670. /**
  7671. * Removes the connection
  7672. * @param jid
  7673. */
  7674. my.removeConnectionIndicator = function (jid) {
  7675. if(VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)])
  7676. VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)].remove();
  7677. };
  7678. /**
  7679. * Hides the connection indicator
  7680. * @param jid
  7681. */
  7682. my.hideConnectionIndicator = function (jid) {
  7683. if(VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)])
  7684. VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)].hide();
  7685. };
  7686. /**
  7687. * Hides all the indicators
  7688. */
  7689. my.onStatsStop = function () {
  7690. for(var indicator in VideoLayout.connectionIndicators)
  7691. {
  7692. VideoLayout.connectionIndicators[indicator].hideIndicator();
  7693. }
  7694. };
  7695. my.participantLeft = function (jid) {
  7696. // Unlock large video
  7697. if (focusedVideoInfo && focusedVideoInfo.jid === jid)
  7698. {
  7699. console.info("Focused video owner has left the conference");
  7700. focusedVideoInfo = null;
  7701. }
  7702. }
  7703. my.onVideoTypeChanged = function (jid) {
  7704. if(jid &&
  7705. Strophe.getResourceFromJid(jid) === largeVideoState.userResourceJid)
  7706. {
  7707. largeVideoState.isDesktop = APP.RTC.isVideoSrcDesktop(jid);
  7708. VideoLayout.getVideoSize = largeVideoState.isDesktop
  7709. ? getDesktopVideoSize
  7710. : getCameraVideoSize;
  7711. VideoLayout.getVideoPosition = largeVideoState.isDesktop
  7712. ? getDesktopVideoPosition
  7713. : getCameraVideoPosition;
  7714. VideoLayout.positionLarge(null, null);
  7715. }
  7716. }
  7717. return my;
  7718. }(VideoLayout || {}));
  7719. module.exports = VideoLayout;
  7720. },{"../../../service/RTC/MediaStreamTypes":87,"../../../service/UI/UIEvents":92,"../audio_levels/AudioLevels":9,"../avatar/Avatar":13,"../etherpad/Etherpad":14,"../prezi/Prezi":15,"../side_pannels/chat/Chat":18,"../side_pannels/contactlist/ContactList":22,"../util/NicknameHandler":29,"../util/UIUtil":30,"./ConnectionIndicator":31}],33:[function(require,module,exports){
  7721. //var nouns = [
  7722. //];
  7723. var pluralNouns = [
  7724. "Aliens", "Animals", "Antelopes", "Ants", "Apes", "Apples", "Baboons", "Bacteria", "Badgers", "Bananas", "Bats",
  7725. "Bears", "Birds", "Bonobos", "Brides", "Bugs", "Bulls", "Butterflies", "Cheetahs",
  7726. "Cherries", "Chicken", "Children", "Chimps", "Clowns", "Cows", "Creatures", "Dinosaurs", "Dogs", "Dolphins",
  7727. "Donkeys", "Dragons", "Ducks", "Dwarfs", "Eagles", "Elephants", "Elves", "FAIL", "Fathers",
  7728. "Fish", "Flowers", "Frogs", "Fruit", "Fungi", "Galaxies", "Geese", "Goats",
  7729. "Gorillas", "Hedgehogs", "Hippos", "Horses", "Hunters", "Insects", "Kids", "Knights",
  7730. "Lemons", "Lemurs", "Leopards", "LifeForms", "Lions", "Lizards", "Mice", "Monkeys", "Monsters",
  7731. "Mushrooms", "Octopodes", "Oranges", "Orangutans", "Organisms", "Pants", "Parrots", "Penguins",
  7732. "People", "Pigeons", "Pigs", "Pineapples", "Plants", "Potatoes", "Priests", "Rats", "Reptiles", "Reptilians",
  7733. "Rhinos", "Seagulls", "Sheep", "Siblings", "Snakes", "Spaghetti", "Spiders", "Squid", "Squirrels",
  7734. "Stars", "Students", "Teachers", "Tigers", "Tomatoes", "Trees", "Vampires", "Vegetables", "Viruses", "Vulcans",
  7735. "Warewolves", "Weasels", "Whales", "Witches", "Wizards", "Wolves", "Workers", "Worms", "Zebras"
  7736. ];
  7737. //var places = [
  7738. //"Pub", "University", "Airport", "Library", "Mall", "Theater", "Stadium", "Office", "Show", "Gallows", "Beach",
  7739. // "Cemetery", "Hospital", "Reception", "Restaurant", "Bar", "Church", "House", "School", "Square", "Village",
  7740. // "Cinema", "Movies", "Party", "Restroom", "End", "Jail", "PostOffice", "Station", "Circus", "Gates", "Entrance",
  7741. // "Bridge"
  7742. //];
  7743. var verbs = [
  7744. "Abandon", "Adapt", "Advertise", "Answer", "Anticipate", "Appreciate",
  7745. "Approach", "Argue", "Ask", "Bite", "Blossom", "Blush", "Breathe", "Breed", "Bribe", "Burn", "Calculate",
  7746. "Clean", "Code", "Communicate", "Compute", "Confess", "Confiscate", "Conjugate", "Conjure", "Consume",
  7747. "Contemplate", "Crawl", "Dance", "Delegate", "Devour", "Develop", "Differ", "Discuss",
  7748. "Dissolve", "Drink", "Eat", "Elaborate", "Emancipate", "Estimate", "Expire", "Extinguish",
  7749. "Extract", "FAIL", "Facilitate", "Fall", "Feed", "Finish", "Floss", "Fly", "Follow", "Fragment", "Freeze",
  7750. "Gather", "Glow", "Grow", "Hex", "Hide", "Hug", "Hurry", "Improve", "Intersect", "Investigate", "Jinx",
  7751. "Joke", "Jubilate", "Kiss", "Laugh", "Manage", "Meet", "Merge", "Move", "Object", "Observe", "Offer",
  7752. "Paint", "Participate", "Party", "Perform", "Plan", "Pursue", "Pierce", "Play", "Postpone", "Pray", "Proclaim",
  7753. "Question", "Read", "Reckon", "Rejoice", "Represent", "Resize", "Rhyme", "Scream", "Search", "Select", "Share", "Shoot",
  7754. "Shout", "Signal", "Sing", "Skate", "Sleep", "Smile", "Smoke", "Solve", "Spell", "Steer", "Stink",
  7755. "Substitute", "Swim", "Taste", "Teach", "Terminate", "Think", "Type", "Unite", "Vanish", "Worship"
  7756. ];
  7757. var adverbs = [
  7758. "Absently", "Accurately", "Accusingly", "Adorably", "AllTheTime", "Alone", "Always", "Amazingly", "Angrily",
  7759. "Anxiously", "Anywhere", "Appallingly", "Apparently", "Articulately", "Astonishingly", "Badly", "Barely",
  7760. "Beautifully", "Blindly", "Bravely", "Brightly", "Briskly", "Brutally", "Calmly", "Carefully", "Casually",
  7761. "Cautiously", "Cleverly", "Constantly", "Correctly", "Crazily", "Curiously", "Cynically", "Daily",
  7762. "Dangerously", "Deliberately", "Delicately", "Desperately", "Discreetly", "Eagerly", "Easily", "Euphoricly",
  7763. "Evenly", "Everywhere", "Exactly", "Expectantly", "Extensively", "FAIL", "Ferociously", "Fiercely", "Finely",
  7764. "Flatly", "Frequently", "Frighteningly", "Gently", "Gloriously", "Grimly", "Guiltily", "Happily",
  7765. "Hard", "Hastily", "Heroically", "High", "Highly", "Hourly", "Humbly", "Hysterically", "Immensely",
  7766. "Impartially", "Impolitely", "Indifferently", "Intensely", "Jealously", "Jovially", "Kindly", "Lazily",
  7767. "Lightly", "Loudly", "Lovingly", "Loyally", "Magnificently", "Malevolently", "Merrily", "Mightily", "Miserably",
  7768. "Mysteriously", "NOT", "Nervously", "Nicely", "Nowhere", "Objectively", "Obnoxiously", "Obsessively",
  7769. "Obviously", "Often", "Painfully", "Patiently", "Playfully", "Politely", "Poorly", "Precisely", "Promptly",
  7770. "Quickly", "Quietly", "Randomly", "Rapidly", "Rarely", "Recklessly", "Regularly", "Remorsefully", "Responsibly",
  7771. "Rudely", "Ruthlessly", "Sadly", "Scornfully", "Seamlessly", "Seldom", "Selfishly", "Seriously", "Shakily",
  7772. "Sharply", "Sideways", "Silently", "Sleepily", "Slightly", "Slowly", "Slyly", "Smoothly", "Softly", "Solemnly", "Steadily", "Sternly", "Strangely", "Strongly", "Stunningly", "Surely", "Tenderly", "Thoughtfully",
  7773. "Tightly", "Uneasily", "Vanishingly", "Violently", "Warmly", "Weakly", "Wearily", "Weekly", "Weirdly", "Well",
  7774. "Well", "Wickedly", "Wildly", "Wisely", "Wonderfully", "Yearly"
  7775. ];
  7776. var adjectives = [
  7777. "Abominable", "Accurate", "Adorable", "All", "Alleged", "Ancient", "Angry", "Angry", "Anxious", "Appalling",
  7778. "Apparent", "Astonishing", "Attractive", "Awesome", "Baby", "Bad", "Beautiful", "Benign", "Big", "Bitter",
  7779. "Blind", "Blue", "Bold", "Brave", "Bright", "Brisk", "Calm", "Camouflaged", "Casual", "Cautious",
  7780. "Choppy", "Chosen", "Clever", "Cold", "Cool", "Crawly", "Crazy", "Creepy", "Cruel", "Curious", "Cynical",
  7781. "Dangerous", "Dark", "Delicate", "Desperate", "Difficult", "Discreet", "Disguised", "Dizzy",
  7782. "Dumb", "Eager", "Easy", "Edgy", "Electric", "Elegant", "Emancipated", "Enormous", "Euphoric", "Evil",
  7783. "FAIL", "Fast", "Ferocious", "Fierce", "Fine", "Flawed", "Flying", "Foolish", "Foxy",
  7784. "Freezing", "Funny", "Furious", "Gentle", "Glorious", "Golden", "Good", "Green", "Green", "Guilty",
  7785. "Hairy", "Happy", "Hard", "Hasty", "Hazy", "Heroic", "Hostile", "Hot", "Humble", "Humongous",
  7786. "Humorous", "Hysterical", "Idealistic", "Ignorant", "Immense", "Impartial", "Impolite", "Indifferent",
  7787. "Infuriated", "Insightful", "Intense", "Interesting", "Intimidated", "Intriguing", "Jealous", "Jolly", "Jovial",
  7788. "Jumpy", "Kind", "Laughing", "Lazy", "Liquid", "Lonely", "Longing", "Loud", "Loving", "Loyal", "Macabre", "Mad",
  7789. "Magical", "Magnificent", "Malevolent", "Medieval", "Memorable", "Mere", "Merry", "Mighty",
  7790. "Mischievous", "Miserable", "Modified", "Moody", "Most", "Mysterious", "Mystical", "Needy",
  7791. "Nervous", "Nice", "Objective", "Obnoxious", "Obsessive", "Obvious", "Opinionated", "Orange",
  7792. "Painful", "Passionate", "Perfect", "Pink", "Playful", "Poisonous", "Polite", "Poor", "Popular", "Powerful",
  7793. "Precise", "Preserved", "Pretty", "Purple", "Quick", "Quiet", "Random", "Rapid", "Rare", "Real",
  7794. "Reassuring", "Reckless", "Red", "Regular", "Remorseful", "Responsible", "Rich", "Rude", "Ruthless",
  7795. "Sad", "Scared", "Scary", "Scornful", "Screaming", "Selfish", "Serious", "Shady", "Shaky", "Sharp",
  7796. "Shiny", "Shy", "Simple", "Sleepy", "Slow", "Sly", "Small", "Smart", "Smelly", "Smiling", "Smooth",
  7797. "Smug", "Sober", "Soft", "Solemn", "Square", "Square", "Steady", "Strange", "Strong",
  7798. "Stunning", "Subjective", "Successful", "Surly", "Sweet", "Tactful", "Tense",
  7799. "Thoughtful", "Tight", "Tiny", "Tolerant", "Uneasy", "Unique", "Unseen", "Warm", "Weak",
  7800. "Weird", "WellCooked", "Wild", "Wise", "Witty", "Wonderful", "Worried", "Yellow", "Young",
  7801. "Zealous"
  7802. ];
  7803. //var pronouns = [
  7804. //];
  7805. //var conjunctions = [
  7806. //"And", "Or", "For", "Above", "Before", "Against", "Between"
  7807. //];
  7808. /*
  7809. * Maps a string (category name) to the array of words from that category.
  7810. */
  7811. var CATEGORIES =
  7812. {
  7813. //"_NOUN_": nouns,
  7814. "_PLURALNOUN_": pluralNouns,
  7815. //"_PLACE_": places,
  7816. "_VERB_": verbs,
  7817. "_ADVERB_": adverbs,
  7818. "_ADJECTIVE_": adjectives
  7819. //"_PRONOUN_": pronouns,
  7820. //"_CONJUNCTION_": conjunctions,
  7821. };
  7822. var PATTERNS = [
  7823. "_ADJECTIVE__PLURALNOUN__VERB__ADVERB_"
  7824. // BeautifulFungiOrSpaghetti
  7825. //"_ADJECTIVE__PLURALNOUN__CONJUNCTION__PLURALNOUN_",
  7826. // AmazinglyScaryToy
  7827. //"_ADVERB__ADJECTIVE__NOUN_",
  7828. // NeitherTrashNorRifle
  7829. //"Neither_NOUN_Nor_NOUN_",
  7830. //"Either_NOUN_Or_NOUN_",
  7831. // EitherCopulateOrInvestigate
  7832. //"Either_VERB_Or_VERB_",
  7833. //"Neither_VERB_Nor_VERB_",
  7834. //"The_ADJECTIVE__ADJECTIVE__NOUN_",
  7835. //"The_ADVERB__ADJECTIVE__NOUN_",
  7836. //"The_ADVERB__ADJECTIVE__NOUN_s",
  7837. //"The_ADVERB__ADJECTIVE__PLURALNOUN__VERB_",
  7838. // WolvesComputeBadly
  7839. //"_PLURALNOUN__VERB__ADVERB_",
  7840. // UniteFacilitateAndMerge
  7841. //"_VERB__VERB_And_VERB_",
  7842. //NastyWitchesAtThePub
  7843. //"_ADJECTIVE__PLURALNOUN_AtThe_PLACE_",
  7844. ];
  7845. /*
  7846. * Returns a random element from the array 'arr'
  7847. */
  7848. function randomElement(arr)
  7849. {
  7850. return arr[Math.floor(Math.random() * arr.length)];
  7851. }
  7852. /*
  7853. * Returns true if the string 's' contains one of the
  7854. * template strings.
  7855. */
  7856. function hasTemplate(s)
  7857. {
  7858. for (var template in CATEGORIES){
  7859. if (s.indexOf(template) >= 0){
  7860. return true;
  7861. }
  7862. }
  7863. }
  7864. /**
  7865. * Generates new room name.
  7866. */
  7867. var RoomNameGenerator = {
  7868. generateRoomWithoutSeparator: function()
  7869. {
  7870. // Note that if more than one pattern is available, the choice of 'name' won't be random (names from patterns
  7871. // with fewer options will have higher probability of being chosen that names from patterns with more options).
  7872. var name = randomElement(PATTERNS);
  7873. var word;
  7874. while (hasTemplate(name)){
  7875. for (var template in CATEGORIES){
  7876. word = randomElement(CATEGORIES[template]);
  7877. name = name.replace(template, word);
  7878. }
  7879. }
  7880. return name;
  7881. }
  7882. }
  7883. module.exports = RoomNameGenerator;
  7884. },{}],34:[function(require,module,exports){
  7885. var animateTimeout, updateTimeout;
  7886. var RoomNameGenerator = require("./RoomnameGenerator");
  7887. function enter_room()
  7888. {
  7889. var val = $("#enter_room_field").val();
  7890. if(!val) {
  7891. val = $("#enter_room_field").attr("room_name");
  7892. }
  7893. if (val) {
  7894. window.location.pathname = "/" + val;
  7895. }
  7896. }
  7897. function animate(word) {
  7898. var currentVal = $("#enter_room_field").attr("placeholder");
  7899. $("#enter_room_field").attr("placeholder", currentVal + word.substr(0, 1));
  7900. animateTimeout = setTimeout(function() {
  7901. animate(word.substring(1, word.length))
  7902. }, 70);
  7903. }
  7904. function update_roomname()
  7905. {
  7906. var word = RoomNameGenerator.generateRoomWithoutSeparator();
  7907. $("#enter_room_field").attr("room_name", word);
  7908. $("#enter_room_field").attr("placeholder", "");
  7909. clearTimeout(animateTimeout);
  7910. animate(word);
  7911. updateTimeout = setTimeout(update_roomname, 10000);
  7912. }
  7913. function setupWelcomePage()
  7914. {
  7915. $("#videoconference_page").hide();
  7916. $("#domain_name").text(
  7917. window.location.protocol + "//" + window.location.host + "/");
  7918. if (interfaceConfig.SHOW_JITSI_WATERMARK) {
  7919. var leftWatermarkDiv
  7920. = $("#welcome_page_header div[class='watermark leftwatermark']");
  7921. if(leftWatermarkDiv && leftWatermarkDiv.length > 0)
  7922. {
  7923. leftWatermarkDiv.css({display: 'block'});
  7924. leftWatermarkDiv.parent().get(0).href
  7925. = interfaceConfig.JITSI_WATERMARK_LINK;
  7926. }
  7927. }
  7928. if (interfaceConfig.SHOW_BRAND_WATERMARK) {
  7929. var rightWatermarkDiv
  7930. = $("#welcome_page_header div[class='watermark rightwatermark']");
  7931. if(rightWatermarkDiv && rightWatermarkDiv.length > 0) {
  7932. rightWatermarkDiv.css({display: 'block'});
  7933. rightWatermarkDiv.parent().get(0).href
  7934. = interfaceConfig.BRAND_WATERMARK_LINK;
  7935. rightWatermarkDiv.get(0).style.backgroundImage
  7936. = "url(images/rightwatermark.png)";
  7937. }
  7938. }
  7939. if (interfaceConfig.SHOW_POWERED_BY) {
  7940. $("#welcome_page_header>a[class='poweredby']")
  7941. .css({display: 'block'});
  7942. }
  7943. $("#enter_room_button").click(function()
  7944. {
  7945. enter_room();
  7946. });
  7947. $("#enter_room_field").keydown(function (event) {
  7948. if (event.keyCode === 13 /* enter */) {
  7949. enter_room();
  7950. }
  7951. });
  7952. if (!(interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE === false)){
  7953. var updateTimeout;
  7954. var animateTimeout;
  7955. $("#reload_roomname").click(function () {
  7956. clearTimeout(updateTimeout);
  7957. clearTimeout(animateTimeout);
  7958. update_roomname();
  7959. });
  7960. $("#reload_roomname").show();
  7961. update_roomname();
  7962. }
  7963. $("#disable_welcome").click(function () {
  7964. window.localStorage.welcomePageDisabled
  7965. = $("#disable_welcome").is(":checked");
  7966. });
  7967. }
  7968. module.exports = setupWelcomePage;
  7969. },{"./RoomnameGenerator":33}],35:[function(require,module,exports){
  7970. var EventEmitter = require("events");
  7971. var eventEmitter = new EventEmitter();
  7972. var CQEvents = require("../../service/connectionquality/CQEvents");
  7973. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  7974. /**
  7975. * local stats
  7976. * @type {{}}
  7977. */
  7978. var stats = {};
  7979. /**
  7980. * remote stats
  7981. * @type {{}}
  7982. */
  7983. var remoteStats = {};
  7984. /**
  7985. * Interval for sending statistics to other participants
  7986. * @type {null}
  7987. */
  7988. var sendIntervalId = null;
  7989. /**
  7990. * Start statistics sending.
  7991. */
  7992. function startSendingStats() {
  7993. sendStats();
  7994. sendIntervalId = setInterval(sendStats, 10000);
  7995. }
  7996. /**
  7997. * Sends statistics to other participants
  7998. */
  7999. function sendStats() {
  8000. APP.xmpp.addToPresence("connectionQuality", convertToMUCStats(stats));
  8001. }
  8002. /**
  8003. * Converts statistics to format for sending through XMPP
  8004. * @param stats the statistics
  8005. * @returns {{bitrate_donwload: *, bitrate_uplpoad: *, packetLoss_total: *, packetLoss_download: *, packetLoss_upload: *}}
  8006. */
  8007. function convertToMUCStats(stats) {
  8008. return {
  8009. "bitrate_download": stats.bitrate.download,
  8010. "bitrate_upload": stats.bitrate.upload,
  8011. "packetLoss_total": stats.packetLoss.total,
  8012. "packetLoss_download": stats.packetLoss.download,
  8013. "packetLoss_upload": stats.packetLoss.upload
  8014. };
  8015. }
  8016. /**
  8017. * Converts statitistics to format used by VideoLayout
  8018. * @param stats
  8019. * @returns {{bitrate: {download: *, upload: *}, packetLoss: {total: *, download: *, upload: *}}}
  8020. */
  8021. function parseMUCStats(stats) {
  8022. return {
  8023. bitrate: {
  8024. download: stats.bitrate_download,
  8025. upload: stats.bitrate_upload
  8026. },
  8027. packetLoss: {
  8028. total: stats.packetLoss_total,
  8029. download: stats.packetLoss_download,
  8030. upload: stats.packetLoss_upload
  8031. }
  8032. };
  8033. }
  8034. var ConnectionQuality = {
  8035. init: function () {
  8036. APP.xmpp.addListener(XMPPEvents.REMOTE_STATS, this.updateRemoteStats);
  8037. APP.statistics.addConnectionStatsListener(this.updateLocalStats);
  8038. APP.statistics.addRemoteStatsStopListener(this.stopSendingStats);
  8039. },
  8040. /**
  8041. * Updates the local statistics
  8042. * @param data new statistics
  8043. */
  8044. updateLocalStats: function (data) {
  8045. stats = data;
  8046. eventEmitter.emit(CQEvents.LOCALSTATS_UPDATED, 100 - stats.packetLoss.total, stats);
  8047. if (sendIntervalId == null) {
  8048. startSendingStats();
  8049. }
  8050. },
  8051. /**
  8052. * Updates remote statistics
  8053. * @param jid the jid associated with the statistics
  8054. * @param data the statistics
  8055. */
  8056. updateRemoteStats: function (jid, data) {
  8057. if (data == null || data.packetLoss_total == null) {
  8058. eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, jid, null, null);
  8059. return;
  8060. }
  8061. remoteStats[jid] = parseMUCStats(data);
  8062. eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED,
  8063. jid, 100 - data.packetLoss_total, remoteStats[jid]);
  8064. },
  8065. /**
  8066. * Stops statistics sending.
  8067. */
  8068. stopSendingStats: function () {
  8069. clearInterval(sendIntervalId);
  8070. sendIntervalId = null;
  8071. //notify UI about stopping statistics gathering
  8072. eventEmitter.emit(CQEvents.STOP);
  8073. },
  8074. /**
  8075. * Returns the local statistics.
  8076. */
  8077. getStats: function () {
  8078. return stats;
  8079. },
  8080. addListener: function (type, listener) {
  8081. eventEmitter.on(type, listener);
  8082. }
  8083. };
  8084. module.exports = ConnectionQuality;
  8085. },{"../../service/connectionquality/CQEvents":94,"../../service/xmpp/XMPPEvents":97,"events":98}],36:[function(require,module,exports){
  8086. /* global $, alert, APP, changeLocalVideo, chrome, config, getConferenceHandler,
  8087. getUserMediaWithConstraints */
  8088. /**
  8089. * Indicates that desktop stream is currently in use(for toggle purpose).
  8090. * @type {boolean}
  8091. */
  8092. var isUsingScreenStream = false;
  8093. /**
  8094. * Indicates that switch stream operation is in progress and prevent from
  8095. * triggering new events.
  8096. * @type {boolean}
  8097. */
  8098. var switchInProgress = false;
  8099. /**
  8100. * Method used to get screen sharing stream.
  8101. *
  8102. * @type {function (stream_callback, failure_callback}
  8103. */
  8104. var obtainDesktopStream = null;
  8105. /**
  8106. * Indicates whether desktop sharing extension is installed.
  8107. * @type {boolean}
  8108. */
  8109. var extInstalled = false;
  8110. /**
  8111. * Indicates whether update of desktop sharing extension is required.
  8112. * @type {boolean}
  8113. */
  8114. var extUpdateRequired = false;
  8115. /**
  8116. * Flag used to cache desktop sharing enabled state. Do not use directly as
  8117. * it can be <tt>null</tt>.
  8118. *
  8119. * @type {null|boolean}
  8120. */
  8121. var _desktopSharingEnabled = null;
  8122. var EventEmitter = require("events");
  8123. var eventEmitter = new EventEmitter();
  8124. var DesktopSharingEventTypes
  8125. = require("../../service/desktopsharing/DesktopSharingEventTypes");
  8126. /**
  8127. * Method obtains desktop stream from WebRTC 'screen' source.
  8128. * Flag 'chrome://flags/#enable-usermedia-screen-capture' must be enabled.
  8129. */
  8130. function obtainWebRTCScreen(streamCallback, failCallback) {
  8131. APP.RTC.getUserMediaWithConstraints(
  8132. ['screen'],
  8133. streamCallback,
  8134. failCallback
  8135. );
  8136. }
  8137. /**
  8138. * Constructs inline install URL for Chrome desktop streaming extension.
  8139. * The 'chromeExtensionId' must be defined in config.js.
  8140. * @returns {string}
  8141. */
  8142. function getWebStoreInstallUrl()
  8143. {
  8144. return "https://chrome.google.com/webstore/detail/" +
  8145. config.chromeExtensionId;
  8146. }
  8147. /**
  8148. * Checks whether extension update is required.
  8149. * @param minVersion minimal required version
  8150. * @param extVersion current extension version
  8151. * @returns {boolean}
  8152. */
  8153. function isUpdateRequired(minVersion, extVersion)
  8154. {
  8155. try
  8156. {
  8157. var s1 = minVersion.split('.');
  8158. var s2 = extVersion.split('.');
  8159. var len = Math.max(s1.length, s2.length);
  8160. for (var i = 0; i < len; i++)
  8161. {
  8162. var n1 = 0,
  8163. n2 = 0;
  8164. if (i < s1.length)
  8165. n1 = parseInt(s1[i]);
  8166. if (i < s2.length)
  8167. n2 = parseInt(s2[i]);
  8168. if (isNaN(n1) || isNaN(n2))
  8169. {
  8170. return true;
  8171. }
  8172. else if (n1 !== n2)
  8173. {
  8174. return n1 > n2;
  8175. }
  8176. }
  8177. // will happen if boths version has identical numbers in
  8178. // their components (even if one of them is longer, has more components)
  8179. return false;
  8180. }
  8181. catch (e)
  8182. {
  8183. console.error("Failed to parse extension version", e);
  8184. APP.UI.messageHandler.showError("dialog.error",
  8185. "dialog.detectext");
  8186. return true;
  8187. }
  8188. }
  8189. function checkExtInstalled(callback) {
  8190. if (!chrome.runtime) {
  8191. // No API, so no extension for sure
  8192. callback(false, false);
  8193. return;
  8194. }
  8195. chrome.runtime.sendMessage(
  8196. config.chromeExtensionId,
  8197. { getVersion: true },
  8198. function (response) {
  8199. if (!response || !response.version) {
  8200. // Communication failure - assume that no endpoint exists
  8201. console.warn(
  8202. "Extension not installed?: ", chrome.runtime.lastError);
  8203. callback(false, false);
  8204. return;
  8205. }
  8206. // Check installed extension version
  8207. var extVersion = response.version;
  8208. console.log('Extension version is: ' + extVersion);
  8209. var updateRequired
  8210. = isUpdateRequired(config.minChromeExtVersion, extVersion);
  8211. callback(!updateRequired, updateRequired);
  8212. }
  8213. );
  8214. }
  8215. function doGetStreamFromExtension(streamCallback, failCallback) {
  8216. // Sends 'getStream' msg to the extension.
  8217. // Extension id must be defined in the config.
  8218. chrome.runtime.sendMessage(
  8219. config.chromeExtensionId,
  8220. { getStream: true, sources: config.desktopSharingSources },
  8221. function (response) {
  8222. if (!response) {
  8223. failCallback(chrome.runtime.lastError);
  8224. return;
  8225. }
  8226. console.log("Response from extension: " + response);
  8227. if (response.streamId) {
  8228. APP.RTC.getUserMediaWithConstraints(
  8229. ['desktop'],
  8230. function (stream) {
  8231. streamCallback(stream);
  8232. },
  8233. failCallback,
  8234. null, null, null,
  8235. response.streamId);
  8236. } else {
  8237. failCallback("Extension failed to get the stream");
  8238. }
  8239. }
  8240. );
  8241. }
  8242. /**
  8243. * Asks Chrome extension to call chooseDesktopMedia and gets chrome 'desktop'
  8244. * stream for returned stream token.
  8245. */
  8246. function obtainScreenFromExtension(streamCallback, failCallback) {
  8247. if (extInstalled) {
  8248. doGetStreamFromExtension(streamCallback, failCallback);
  8249. } else {
  8250. if (extUpdateRequired) {
  8251. alert(
  8252. 'Jitsi Desktop Streamer requires update. ' +
  8253. 'Changes will take effect after next Chrome restart.');
  8254. }
  8255. chrome.webstore.install(
  8256. getWebStoreInstallUrl(),
  8257. function (arg) {
  8258. console.log("Extension installed successfully", arg);
  8259. // We need to reload the page in order to get the access to
  8260. // chrome.runtime
  8261. window.location.reload(false);
  8262. },
  8263. function (arg) {
  8264. console.log("Failed to install the extension", arg);
  8265. failCallback(arg);
  8266. APP.UI.messageHandler.showError("dialog.error",
  8267. "dialog.failtoinstall");
  8268. }
  8269. );
  8270. }
  8271. }
  8272. /**
  8273. * Call this method to toggle desktop sharing feature.
  8274. * @param method pass "ext" to use chrome extension for desktop capture(chrome
  8275. * extension required), pass "webrtc" to use WebRTC "screen" desktop
  8276. * source('chrome://flags/#enable-usermedia-screen-capture' must be
  8277. * enabled), pass any other string or nothing in order to disable this
  8278. * feature completely.
  8279. */
  8280. function setDesktopSharing(method) {
  8281. // Check if we are running chrome
  8282. if (!navigator.webkitGetUserMedia) {
  8283. obtainDesktopStream = null;
  8284. console.info("Desktop sharing disabled");
  8285. } else if (method == "ext") {
  8286. obtainDesktopStream = obtainScreenFromExtension;
  8287. console.info("Using Chrome extension for desktop sharing");
  8288. } else if (method == "webrtc") {
  8289. obtainDesktopStream = obtainWebRTCScreen;
  8290. console.info("Using Chrome WebRTC for desktop sharing");
  8291. }
  8292. // Reset enabled cache
  8293. _desktopSharingEnabled = null;
  8294. }
  8295. /**
  8296. * Initializes <link rel=chrome-webstore-item /> with extension id set in
  8297. * config.js to support inline installs. Host site must be selected as main
  8298. * website of published extension.
  8299. */
  8300. function initInlineInstalls()
  8301. {
  8302. $("link[rel=chrome-webstore-item]").attr("href", getWebStoreInstallUrl());
  8303. }
  8304. function getVideoStreamFailed(error) {
  8305. console.error("Failed to obtain the stream to switch to", error);
  8306. switchInProgress = false;
  8307. isUsingScreenStream = false;
  8308. newStreamCreated(null);
  8309. }
  8310. function getDesktopStreamFailed(error) {
  8311. console.error("Failed to obtain the stream to switch to", error);
  8312. switchInProgress = false;
  8313. }
  8314. function streamSwitchDone() {
  8315. switchInProgress = false;
  8316. eventEmitter.emit(
  8317. DesktopSharingEventTypes.SWITCHING_DONE,
  8318. isUsingScreenStream);
  8319. }
  8320. function newStreamCreated(stream)
  8321. {
  8322. eventEmitter.emit(DesktopSharingEventTypes.NEW_STREAM_CREATED,
  8323. stream, isUsingScreenStream, streamSwitchDone);
  8324. }
  8325. module.exports = {
  8326. isUsingScreenStream: function () {
  8327. return isUsingScreenStream;
  8328. },
  8329. /**
  8330. * @returns {boolean} <tt>true</tt> if desktop sharing feature is available
  8331. * and enabled.
  8332. */
  8333. isDesktopSharingEnabled: function () {
  8334. if (_desktopSharingEnabled === null) {
  8335. if (obtainDesktopStream === obtainScreenFromExtension) {
  8336. // Parse chrome version
  8337. var userAgent = navigator.userAgent.toLowerCase();
  8338. // We can assume that user agent is chrome, because it's
  8339. // enforced when 'ext' streaming method is set
  8340. var ver = parseInt(userAgent.match(/chrome\/(\d+)\./)[1], 10);
  8341. console.log("Chrome version" + userAgent, ver);
  8342. _desktopSharingEnabled = ver >= 34;
  8343. } else {
  8344. _desktopSharingEnabled =
  8345. obtainDesktopStream === obtainWebRTCScreen;
  8346. }
  8347. }
  8348. return _desktopSharingEnabled;
  8349. },
  8350. init: function () {
  8351. setDesktopSharing(config.desktopSharing);
  8352. // Initialize Chrome extension inline installs
  8353. if (config.chromeExtensionId) {
  8354. initInlineInstalls();
  8355. // Check if extension is installed
  8356. checkExtInstalled(function (installed, updateRequired) {
  8357. extInstalled = installed;
  8358. extUpdateRequired = updateRequired;
  8359. console.info(
  8360. "Chrome extension installed: " + extInstalled +
  8361. " updateRequired: " + extUpdateRequired);
  8362. });
  8363. }
  8364. eventEmitter.emit(DesktopSharingEventTypes.INIT);
  8365. },
  8366. addListener: function (listener, type)
  8367. {
  8368. eventEmitter.on(type, listener);
  8369. },
  8370. removeListener: function (listener, type) {
  8371. eventEmitter.removeListener(type, listener);
  8372. },
  8373. /*
  8374. * Toggles screen sharing.
  8375. */
  8376. toggleScreenSharing: function () {
  8377. if (switchInProgress || !obtainDesktopStream) {
  8378. console.warn("Switch in progress or no method defined");
  8379. return;
  8380. }
  8381. switchInProgress = true;
  8382. if (!isUsingScreenStream)
  8383. {
  8384. // Switch to desktop stream
  8385. obtainDesktopStream(
  8386. function (stream) {
  8387. // We now use screen stream
  8388. isUsingScreenStream = true;
  8389. // Hook 'ended' event to restore camera
  8390. // when screen stream stops
  8391. stream.addEventListener('ended',
  8392. function (e) {
  8393. if (!switchInProgress && isUsingScreenStream) {
  8394. APP.desktopsharing.toggleScreenSharing();
  8395. }
  8396. }
  8397. );
  8398. newStreamCreated(stream);
  8399. },
  8400. getDesktopStreamFailed);
  8401. } else {
  8402. // Disable screen stream
  8403. APP.RTC.getUserMediaWithConstraints(
  8404. ['video'],
  8405. function (stream) {
  8406. // We are now using camera stream
  8407. isUsingScreenStream = false;
  8408. newStreamCreated(stream);
  8409. },
  8410. getVideoStreamFailed, config.resolution || '360'
  8411. );
  8412. }
  8413. }
  8414. };
  8415. },{"../../service/desktopsharing/DesktopSharingEventTypes":95,"events":98}],37:[function(require,module,exports){
  8416. //maps keycode to character, id of popover for given function and function
  8417. var shortcuts = {
  8418. 67: {
  8419. character: "C",
  8420. id: "toggleChatPopover",
  8421. function: APP.UI.toggleChat
  8422. },
  8423. 70: {
  8424. character: "F",
  8425. id: "filmstripPopover",
  8426. function: APP.UI.toggleFilmStrip
  8427. },
  8428. 77: {
  8429. character: "M",
  8430. id: "mutePopover",
  8431. function: APP.UI.toggleAudio
  8432. },
  8433. 84: {
  8434. character: "T",
  8435. function: function() {
  8436. if(!APP.RTC.localAudio.isMuted()) {
  8437. APP.UI.toggleAudio();
  8438. }
  8439. }
  8440. },
  8441. 86: {
  8442. character: "V",
  8443. id: "toggleVideoPopover",
  8444. function: APP.UI.toggleVideo
  8445. }
  8446. };
  8447. var KeyboardShortcut = {
  8448. init: function () {
  8449. window.onkeyup = function(e) {
  8450. var keycode = e.which;
  8451. if(!($(":focus").is("input[type=text]") ||
  8452. $(":focus").is("input[type=password]") ||
  8453. $(":focus").is("textarea"))) {
  8454. if (typeof shortcuts[keycode] === "object") {
  8455. shortcuts[keycode].function();
  8456. }
  8457. else if (keycode >= "0".charCodeAt(0) &&
  8458. keycode <= "9".charCodeAt(0)) {
  8459. APP.UI.clickOnVideo(keycode - "0".charCodeAt(0) + 1);
  8460. }
  8461. //esc while the smileys are visible hides them
  8462. } else if (keycode === 27 && $('#smileysContainer').is(':visible')) {
  8463. APP.UI.toggleSmileys();
  8464. }
  8465. };
  8466. window.onkeydown = function(e) {
  8467. if(!($(":focus").is("input[type=text]") ||
  8468. $(":focus").is("input[type=password]") ||
  8469. $(":focus").is("textarea"))) {
  8470. if(e.which === "T".charCodeAt(0)) {
  8471. if(APP.RTC.localAudio.isMuted()) {
  8472. APP.UI.toggleAudio();
  8473. }
  8474. }
  8475. }
  8476. };
  8477. var self = this;
  8478. $('body').popover({ selector: '[data-toggle=popover]',
  8479. trigger: 'click hover',
  8480. content: function() {
  8481. return this.getAttribute("content") +
  8482. self.getShortcut(this.getAttribute("shortcut"));
  8483. }
  8484. });
  8485. },
  8486. /**
  8487. *
  8488. * @param id indicates the popover associated with the shortcut
  8489. * @returns {string} the keyboard shortcut used for the id given
  8490. */
  8491. getShortcut: function (id) {
  8492. for (var keycode in shortcuts) {
  8493. if (shortcuts.hasOwnProperty(keycode)) {
  8494. if (shortcuts[keycode].id === id) {
  8495. return " (" + shortcuts[keycode].character + ")";
  8496. }
  8497. }
  8498. }
  8499. return "";
  8500. }
  8501. };
  8502. module.exports = KeyboardShortcut;
  8503. },{}],38:[function(require,module,exports){
  8504. var email = '';
  8505. var displayName = '';
  8506. var userId;
  8507. var language = null;
  8508. function supportsLocalStorage() {
  8509. try {
  8510. return 'localStorage' in window && window.localStorage !== null;
  8511. } catch (e) {
  8512. console.log("localstorage is not supported");
  8513. return false;
  8514. }
  8515. }
  8516. function generateUniqueId() {
  8517. function _p8() {
  8518. return (Math.random().toString(16) + "000000000").substr(2, 8);
  8519. }
  8520. return _p8() + _p8() + _p8() + _p8();
  8521. }
  8522. if (supportsLocalStorage()) {
  8523. if (!window.localStorage.jitsiMeetId) {
  8524. window.localStorage.jitsiMeetId = generateUniqueId();
  8525. console.log("generated id", window.localStorage.jitsiMeetId);
  8526. }
  8527. userId = window.localStorage.jitsiMeetId || '';
  8528. email = window.localStorage.email || '';
  8529. displayName = window.localStorage.displayname || '';
  8530. language = window.localStorage.language;
  8531. } else {
  8532. console.log("local storage is not supported");
  8533. userId = generateUniqueId();
  8534. }
  8535. var Settings =
  8536. {
  8537. setDisplayName: function (newDisplayName) {
  8538. displayName = newDisplayName;
  8539. window.localStorage.displayname = displayName;
  8540. return displayName;
  8541. },
  8542. setEmail: function (newEmail)
  8543. {
  8544. email = newEmail;
  8545. window.localStorage.email = newEmail;
  8546. return email;
  8547. },
  8548. getSettings: function () {
  8549. return {
  8550. email: email,
  8551. displayName: displayName,
  8552. uid: userId,
  8553. language: language
  8554. };
  8555. },
  8556. setLanguage: function (lang) {
  8557. language = lang;
  8558. window.localStorage.language = lang;
  8559. }
  8560. };
  8561. module.exports = Settings;
  8562. },{}],39:[function(require,module,exports){
  8563. /**
  8564. *
  8565. * @constructor
  8566. */
  8567. function SimulcastLogger(name, lvl) {
  8568. this.name = name;
  8569. this.lvl = lvl;
  8570. }
  8571. SimulcastLogger.prototype.log = function (text) {
  8572. if (this.lvl) {
  8573. console.log(text);
  8574. }
  8575. };
  8576. SimulcastLogger.prototype.info = function (text) {
  8577. if (this.lvl > 1) {
  8578. console.info(text);
  8579. }
  8580. };
  8581. SimulcastLogger.prototype.fine = function (text) {
  8582. if (this.lvl > 2) {
  8583. console.log(text);
  8584. }
  8585. };
  8586. SimulcastLogger.prototype.error = function (text) {
  8587. console.error(text);
  8588. };
  8589. module.exports = SimulcastLogger;
  8590. },{}],40:[function(require,module,exports){
  8591. var SimulcastLogger = require("./SimulcastLogger");
  8592. var SimulcastUtils = require("./SimulcastUtils");
  8593. var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
  8594. function SimulcastReceiver() {
  8595. this.simulcastUtils = new SimulcastUtils();
  8596. this.logger = new SimulcastLogger('SimulcastReceiver', 1);
  8597. }
  8598. SimulcastReceiver.prototype._remoteVideoSourceCache = '';
  8599. SimulcastReceiver.prototype._remoteMaps = {
  8600. msid2Quality: {},
  8601. ssrc2Msid: {},
  8602. msid2ssrc: {},
  8603. receivingVideoStreams: {}
  8604. };
  8605. SimulcastReceiver.prototype._cacheRemoteVideoSources = function (lines) {
  8606. this._remoteVideoSourceCache = this.simulcastUtils._getVideoSources(lines);
  8607. };
  8608. SimulcastReceiver.prototype._restoreRemoteVideoSources = function (lines) {
  8609. this.simulcastUtils._replaceVideoSources(lines, this._remoteVideoSourceCache);
  8610. };
  8611. SimulcastReceiver.prototype._ensureGoogConference = function (lines) {
  8612. var sb;
  8613. this.logger.info('Ensuring x-google-conference flag...')
  8614. if (this.simulcastUtils._indexOfArray('a=x-google-flag:conference', lines) === this.simulcastUtils._emptyCompoundIndex) {
  8615. // TODO(gp) do that for the audio as well as suggested by fippo.
  8616. // Add the google conference flag
  8617. sb = this.simulcastUtils._getVideoSources(lines);
  8618. sb = ['a=x-google-flag:conference'].concat(sb);
  8619. this.simulcastUtils._replaceVideoSources(lines, sb);
  8620. }
  8621. };
  8622. SimulcastReceiver.prototype._restoreSimulcastGroups = function (sb) {
  8623. this._restoreRemoteVideoSources(sb);
  8624. };
  8625. /**
  8626. * Restores the simulcast groups of the remote description. In
  8627. * transformRemoteDescription we remove those in order for the set remote
  8628. * description to succeed. The focus needs the signal the groups to new
  8629. * participants.
  8630. *
  8631. * @param desc
  8632. * @returns {*}
  8633. */
  8634. SimulcastReceiver.prototype.reverseTransformRemoteDescription = function (desc) {
  8635. var sb;
  8636. if (!this.simulcastUtils.isValidDescription(desc)) {
  8637. return desc;
  8638. }
  8639. if (config.enableSimulcast) {
  8640. sb = desc.sdp.split('\r\n');
  8641. this._restoreSimulcastGroups(sb);
  8642. desc = new RTCSessionDescription({
  8643. type: desc.type,
  8644. sdp: sb.join('\r\n')
  8645. });
  8646. }
  8647. return desc;
  8648. };
  8649. SimulcastUtils.prototype._ensureOrder = function (lines) {
  8650. var videoSources, sb;
  8651. videoSources = this.parseMedia(lines, ['video'])[0];
  8652. sb = this._compileVideoSources(videoSources);
  8653. this._replaceVideoSources(lines, sb);
  8654. };
  8655. SimulcastReceiver.prototype._updateRemoteMaps = function (lines) {
  8656. var remoteVideoSources = this.simulcastUtils.parseMedia(lines, ['video'])[0],
  8657. videoSource, quality;
  8658. // (re) initialize the remote maps.
  8659. this._remoteMaps.msid2Quality = {};
  8660. this._remoteMaps.ssrc2Msid = {};
  8661. this._remoteMaps.msid2ssrc = {};
  8662. var self = this;
  8663. if (remoteVideoSources.groups && remoteVideoSources.groups.length !== 0) {
  8664. remoteVideoSources.groups.forEach(function (group) {
  8665. if (group.semantics === 'SIM' && group.ssrcs && group.ssrcs.length !== 0) {
  8666. quality = 0;
  8667. group.ssrcs.forEach(function (ssrc) {
  8668. videoSource = remoteVideoSources.sources[ssrc];
  8669. self._remoteMaps.msid2Quality[videoSource.msid] = quality++;
  8670. self._remoteMaps.ssrc2Msid[videoSource.ssrc] = videoSource.msid;
  8671. self._remoteMaps.msid2ssrc[videoSource.msid] = videoSource.ssrc;
  8672. });
  8673. }
  8674. });
  8675. }
  8676. };
  8677. SimulcastReceiver.prototype._setReceivingVideoStream = function (resource, ssrc) {
  8678. this._remoteMaps.receivingVideoStreams[resource] = ssrc;
  8679. };
  8680. /**
  8681. * Returns a stream with single video track, the one currently being
  8682. * received by this endpoint.
  8683. *
  8684. * @param stream the remote simulcast stream.
  8685. * @returns {webkitMediaStream}
  8686. */
  8687. SimulcastReceiver.prototype.getReceivingVideoStream = function (stream) {
  8688. var tracks, i, electedTrack, msid, quality = 0, receivingTrackId;
  8689. var self = this;
  8690. if (config.enableSimulcast) {
  8691. stream.getVideoTracks().some(function (track) {
  8692. return Object.keys(self._remoteMaps.receivingVideoStreams).some(function (resource) {
  8693. var ssrc = self._remoteMaps.receivingVideoStreams[resource];
  8694. var msid = self._remoteMaps.ssrc2Msid[ssrc];
  8695. if (msid == [stream.id, track.id].join(' ')) {
  8696. electedTrack = track;
  8697. return true;
  8698. }
  8699. });
  8700. });
  8701. if (!electedTrack) {
  8702. // we don't have an elected track, choose by initial quality.
  8703. tracks = stream.getVideoTracks();
  8704. for (i = 0; i < tracks.length; i++) {
  8705. msid = [stream.id, tracks[i].id].join(' ');
  8706. if (this._remoteMaps.msid2Quality[msid] === quality) {
  8707. electedTrack = tracks[i];
  8708. break;
  8709. }
  8710. }
  8711. // TODO(gp) if the initialQuality could not be satisfied, lower
  8712. // the requirement and try again.
  8713. }
  8714. }
  8715. return (electedTrack)
  8716. ? new webkitMediaStream([electedTrack])
  8717. : stream;
  8718. };
  8719. SimulcastReceiver.prototype.getReceivingSSRC = function (jid) {
  8720. var resource = Strophe.getResourceFromJid(jid);
  8721. var ssrc = this._remoteMaps.receivingVideoStreams[resource];
  8722. // If we haven't receiving a "changed" event yet, then we must be receiving
  8723. // low quality (that the sender always streams).
  8724. if(!ssrc)
  8725. {
  8726. var remoteStreamObject = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  8727. var remoteStream = remoteStreamObject.getOriginalStream();
  8728. var tracks = remoteStream.getVideoTracks();
  8729. if (tracks) {
  8730. for (var k = 0; k < tracks.length; k++) {
  8731. var track = tracks[k];
  8732. var msid = [remoteStream.id, track.id].join(' ');
  8733. var _ssrc = this._remoteMaps.msid2ssrc[msid];
  8734. var quality = this._remoteMaps.msid2Quality[msid];
  8735. if (quality == 0) {
  8736. ssrc = _ssrc;
  8737. }
  8738. }
  8739. }
  8740. }
  8741. return ssrc;
  8742. };
  8743. SimulcastReceiver.prototype.getReceivingVideoStreamBySSRC = function (ssrc)
  8744. {
  8745. var sid, electedStream;
  8746. var i, j, k;
  8747. var jid = APP.xmpp.getJidFromSSRC(ssrc);
  8748. if(jid && APP.RTC.remoteStreams[jid])
  8749. {
  8750. var remoteStreamObject = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  8751. var remoteStream = remoteStreamObject.getOriginalStream();
  8752. var tracks = remoteStream.getVideoTracks();
  8753. if (tracks) {
  8754. for (k = 0; k < tracks.length; k++) {
  8755. var track = tracks[k];
  8756. var msid = [remoteStream.id, track.id].join(' ');
  8757. var tmp = this._remoteMaps.msid2ssrc[msid];
  8758. if (tmp == ssrc) {
  8759. electedStream = new webkitMediaStream([track]);
  8760. sid = remoteStreamObject.sid;
  8761. // stream found, stop.
  8762. break;
  8763. }
  8764. }
  8765. }
  8766. }
  8767. else
  8768. {
  8769. console.debug(APP.RTC.remoteStreams, jid, ssrc);
  8770. }
  8771. return {
  8772. sid: sid,
  8773. stream: electedStream
  8774. };
  8775. };
  8776. /**
  8777. * Gets the fully qualified msid (stream.id + track.id) associated to the
  8778. * SSRC.
  8779. *
  8780. * @param ssrc
  8781. * @returns {*}
  8782. */
  8783. SimulcastReceiver.prototype.getRemoteVideoStreamIdBySSRC = function (ssrc) {
  8784. return this._remoteMaps.ssrc2Msid[ssrc];
  8785. };
  8786. /**
  8787. * Removes the ssrc-group:SIM from the remote description bacause Chrome
  8788. * either gets confused and thinks this is an FID group or, if an FID group
  8789. * is already present, it fails to set the remote description.
  8790. *
  8791. * @param desc
  8792. * @returns {*}
  8793. */
  8794. SimulcastReceiver.prototype.transformRemoteDescription = function (desc) {
  8795. if (desc && desc.sdp) {
  8796. var sb = desc.sdp.split('\r\n');
  8797. this._updateRemoteMaps(sb);
  8798. this._cacheRemoteVideoSources(sb);
  8799. // NOTE(gp) this needs to be called after updateRemoteMaps because we
  8800. // need the simulcast group in the _updateRemoteMaps() method.
  8801. this.simulcastUtils._removeSimulcastGroup(sb);
  8802. if (desc.sdp.indexOf('a=ssrc-group:SIM') !== -1) {
  8803. // We don't need the goog conference flag if we're not doing
  8804. // simulcast.
  8805. this._ensureGoogConference(sb);
  8806. }
  8807. desc = new RTCSessionDescription({
  8808. type: desc.type,
  8809. sdp: sb.join('\r\n')
  8810. });
  8811. this.logger.fine(['Transformed remote description', desc.sdp].join(' '));
  8812. }
  8813. return desc;
  8814. };
  8815. module.exports = SimulcastReceiver;
  8816. },{"../../service/RTC/MediaStreamTypes":87,"./SimulcastLogger":39,"./SimulcastUtils":42}],41:[function(require,module,exports){
  8817. var SimulcastLogger = require("./SimulcastLogger");
  8818. var SimulcastUtils = require("./SimulcastUtils");
  8819. function SimulcastSender() {
  8820. this.simulcastUtils = new SimulcastUtils();
  8821. this.logger = new SimulcastLogger('SimulcastSender', 1);
  8822. }
  8823. SimulcastSender.prototype.displayedLocalVideoStream = null;
  8824. SimulcastSender.prototype._generateGuid = (function () {
  8825. function s4() {
  8826. return Math.floor((1 + Math.random()) * 0x10000)
  8827. .toString(16)
  8828. .substring(1);
  8829. }
  8830. return function () {
  8831. return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
  8832. s4() + '-' + s4() + s4() + s4();
  8833. };
  8834. }());
  8835. // Returns a random integer between min (included) and max (excluded)
  8836. // Using Math.round() gives a non-uniform distribution!
  8837. SimulcastSender.prototype._generateRandomSSRC = function () {
  8838. var min = 0, max = 0xffffffff;
  8839. return Math.floor(Math.random() * (max - min)) + min;
  8840. };
  8841. SimulcastSender.prototype.getLocalVideoStream = function () {
  8842. return (this.displayedLocalVideoStream != null)
  8843. ? this.displayedLocalVideoStream
  8844. // in case we have no simulcast at all, i.e. we didn't perform the GUM
  8845. : APP.RTC.localVideo.getOriginalStream();
  8846. };
  8847. function NativeSimulcastSender() {
  8848. SimulcastSender.call(this); // call the super constructor.
  8849. }
  8850. NativeSimulcastSender.prototype = Object.create(SimulcastSender.prototype);
  8851. NativeSimulcastSender.prototype._localExplosionMap = {};
  8852. NativeSimulcastSender.prototype._isUsingScreenStream = false;
  8853. NativeSimulcastSender.prototype._localVideoSourceCache = '';
  8854. NativeSimulcastSender.prototype.reset = function () {
  8855. this._localExplosionMap = {};
  8856. this._isUsingScreenStream = APP.desktopsharing.isUsingScreenStream();
  8857. };
  8858. NativeSimulcastSender.prototype._cacheLocalVideoSources = function (lines) {
  8859. this._localVideoSourceCache = this.simulcastUtils._getVideoSources(lines);
  8860. };
  8861. NativeSimulcastSender.prototype._restoreLocalVideoSources = function (lines) {
  8862. this.simulcastUtils._replaceVideoSources(lines, this._localVideoSourceCache);
  8863. };
  8864. NativeSimulcastSender.prototype._appendSimulcastGroup = function (lines) {
  8865. var videoSources, ssrcGroup, simSSRC, numOfSubs = 2, i, sb, msid;
  8866. this.logger.info('Appending simulcast group...');
  8867. // Get the primary SSRC information.
  8868. videoSources = this.simulcastUtils.parseMedia(lines, ['video'])[0];
  8869. // Start building the SIM SSRC group.
  8870. ssrcGroup = ['a=ssrc-group:SIM'];
  8871. // The video source buffer.
  8872. sb = [];
  8873. // Create the simulcast sub-streams.
  8874. for (i = 0; i < numOfSubs; i++) {
  8875. // TODO(gp) prevent SSRC collision.
  8876. simSSRC = this._generateRandomSSRC();
  8877. ssrcGroup.push(simSSRC);
  8878. if (videoSources.base) {
  8879. sb.splice.apply(sb, [sb.length, 0].concat(
  8880. [["a=ssrc:", simSSRC, " cname:", videoSources.base.cname].join(''),
  8881. ["a=ssrc:", simSSRC, " msid:", videoSources.base.msid].join('')]
  8882. ));
  8883. }
  8884. this.logger.info(['Generated substream ', i, ' with SSRC ', simSSRC, '.'].join(''));
  8885. }
  8886. // Add the group sim layers.
  8887. sb.splice(0, 0, ssrcGroup.join(' '))
  8888. this.simulcastUtils._replaceVideoSources(lines, sb);
  8889. };
  8890. // Does the actual patching.
  8891. NativeSimulcastSender.prototype._ensureSimulcastGroup = function (lines) {
  8892. this.logger.info('Ensuring simulcast group...');
  8893. if (this.simulcastUtils._indexOfArray('a=ssrc-group:SIM', lines) === this.simulcastUtils._emptyCompoundIndex) {
  8894. this._appendSimulcastGroup(lines);
  8895. this._cacheLocalVideoSources(lines);
  8896. } else {
  8897. // verify that the ssrcs participating in the SIM group are present
  8898. // in the SDP (needed for presence).
  8899. this._restoreLocalVideoSources(lines);
  8900. }
  8901. };
  8902. /**
  8903. * Produces a single stream with multiple tracks for local video sources.
  8904. *
  8905. * @param lines
  8906. * @private
  8907. */
  8908. NativeSimulcastSender.prototype._explodeSimulcastSenderSources = function (lines) {
  8909. var sb, msid, sid, tid, videoSources, self;
  8910. this.logger.info('Exploding local video sources...');
  8911. videoSources = this.simulcastUtils.parseMedia(lines, ['video'])[0];
  8912. self = this;
  8913. if (videoSources.groups && videoSources.groups.length !== 0) {
  8914. videoSources.groups.forEach(function (group) {
  8915. if (group.semantics === 'SIM') {
  8916. group.ssrcs.forEach(function (ssrc) {
  8917. // Get the msid for this ssrc..
  8918. if (self._localExplosionMap[ssrc]) {
  8919. // .. either from the explosion map..
  8920. msid = self._localExplosionMap[ssrc];
  8921. } else {
  8922. // .. or generate a new one (msid).
  8923. sid = videoSources.sources[ssrc].msid
  8924. .substring(0, videoSources.sources[ssrc].msid.indexOf(' '));
  8925. tid = self._generateGuid();
  8926. msid = [sid, tid].join(' ');
  8927. self._localExplosionMap[ssrc] = msid;
  8928. }
  8929. // Assign it to the source object.
  8930. videoSources.sources[ssrc].msid = msid;
  8931. // TODO(gp) Change the msid of associated sources.
  8932. });
  8933. }
  8934. });
  8935. }
  8936. sb = this.simulcastUtils._compileVideoSources(videoSources);
  8937. this.simulcastUtils._replaceVideoSources(lines, sb);
  8938. };
  8939. /**
  8940. * GUM for simulcast.
  8941. *
  8942. * @param constraints
  8943. * @param success
  8944. * @param err
  8945. */
  8946. NativeSimulcastSender.prototype.getUserMedia = function (constraints, success, err) {
  8947. // There's nothing special to do for native simulcast, so just do a normal GUM.
  8948. navigator.webkitGetUserMedia(constraints, function (hqStream) {
  8949. success(hqStream);
  8950. }, err);
  8951. };
  8952. /**
  8953. * Prepares the local description for public usage (i.e. to be signaled
  8954. * through Jingle to the focus).
  8955. *
  8956. * @param desc
  8957. * @returns {RTCSessionDescription}
  8958. */
  8959. NativeSimulcastSender.prototype.reverseTransformLocalDescription = function (desc) {
  8960. var sb;
  8961. if (!this.simulcastUtils.isValidDescription(desc) || this._isUsingScreenStream) {
  8962. return desc;
  8963. }
  8964. sb = desc.sdp.split('\r\n');
  8965. this._explodeSimulcastSenderSources(sb);
  8966. desc = new RTCSessionDescription({
  8967. type: desc.type,
  8968. sdp: sb.join('\r\n')
  8969. });
  8970. this.logger.fine(['Exploded local video sources', desc.sdp].join(' '));
  8971. return desc;
  8972. };
  8973. /**
  8974. * Ensures that the simulcast group is present in the answer, _if_ native
  8975. * simulcast is enabled,
  8976. *
  8977. * @param desc
  8978. * @returns {*}
  8979. */
  8980. NativeSimulcastSender.prototype.transformAnswer = function (desc) {
  8981. if (!this.simulcastUtils.isValidDescription(desc) || this._isUsingScreenStream) {
  8982. return desc;
  8983. }
  8984. var sb = desc.sdp.split('\r\n');
  8985. // Even if we have enabled native simulcasting previously
  8986. // (with a call to SLD with an appropriate SDP, for example),
  8987. // createAnswer seems to consistently generate incomplete SDP
  8988. // with missing SSRCS.
  8989. //
  8990. // So, subsequent calls to SLD will have missing SSRCS and presence
  8991. // won't have the complete list of SRCs.
  8992. this._ensureSimulcastGroup(sb);
  8993. desc = new RTCSessionDescription({
  8994. type: desc.type,
  8995. sdp: sb.join('\r\n')
  8996. });
  8997. this.logger.fine(['Transformed answer', desc.sdp].join(' '));
  8998. return desc;
  8999. };
  9000. /**
  9001. *
  9002. *
  9003. * @param desc
  9004. * @returns {*}
  9005. */
  9006. NativeSimulcastSender.prototype.transformLocalDescription = function (desc) {
  9007. return desc;
  9008. };
  9009. NativeSimulcastSender.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
  9010. // Nothing to do here, native simulcast does that auto-magically.
  9011. };
  9012. NativeSimulcastSender.prototype.constructor = NativeSimulcastSender;
  9013. function SimpleSimulcastSender() {
  9014. SimulcastSender.call(this);
  9015. }
  9016. SimpleSimulcastSender.prototype = Object.create(SimulcastSender.prototype);
  9017. SimpleSimulcastSender.prototype.localStream = null;
  9018. SimpleSimulcastSender.prototype._localMaps = {
  9019. msids: [],
  9020. msid2ssrc: {}
  9021. };
  9022. /**
  9023. * Groups local video sources together in the ssrc-group:SIM group.
  9024. *
  9025. * @param lines
  9026. * @private
  9027. */
  9028. SimpleSimulcastSender.prototype._groupLocalVideoSources = function (lines) {
  9029. var sb, videoSources, ssrcs = [], ssrc;
  9030. this.logger.info('Grouping local video sources...');
  9031. videoSources = this.simulcastUtils.parseMedia(lines, ['video'])[0];
  9032. for (ssrc in videoSources.sources) {
  9033. // jitsi-meet destroys/creates streams at various places causing
  9034. // the original local stream ids to change. The only thing that
  9035. // remains unchanged is the trackid.
  9036. this._localMaps.msid2ssrc[videoSources.sources[ssrc].msid.split(' ')[1]] = ssrc;
  9037. }
  9038. var self = this;
  9039. // TODO(gp) add only "free" sources.
  9040. this._localMaps.msids.forEach(function (msid) {
  9041. ssrcs.push(self._localMaps.msid2ssrc[msid]);
  9042. });
  9043. if (!videoSources.groups) {
  9044. videoSources.groups = [];
  9045. }
  9046. videoSources.groups.push({
  9047. 'semantics': 'SIM',
  9048. 'ssrcs': ssrcs
  9049. });
  9050. sb = this.simulcastUtils._compileVideoSources(videoSources);
  9051. this.simulcastUtils._replaceVideoSources(lines, sb);
  9052. };
  9053. /**
  9054. * GUM for simulcast.
  9055. *
  9056. * @param constraints
  9057. * @param success
  9058. * @param err
  9059. */
  9060. SimpleSimulcastSender.prototype.getUserMedia = function (constraints, success, err) {
  9061. // TODO(gp) what if we request a resolution not supported by the hardware?
  9062. // TODO(gp) make the lq stream configurable; although this wouldn't work with native simulcast
  9063. var lqConstraints = {
  9064. audio: false,
  9065. video: {
  9066. mandatory: {
  9067. maxWidth: 320,
  9068. maxHeight: 180,
  9069. maxFrameRate: 15
  9070. }
  9071. }
  9072. };
  9073. this.logger.info('HQ constraints: ', constraints);
  9074. this.logger.info('LQ constraints: ', lqConstraints);
  9075. // NOTE(gp) if we request the lq stream first webkitGetUserMedia
  9076. // fails randomly. Tested with Chrome 37. As fippo suggested, the
  9077. // reason appears to be that Chrome only acquires the cam once and
  9078. // then downscales the picture (https://code.google.com/p/chromium/issues/detail?id=346616#c11)
  9079. var self = this;
  9080. navigator.webkitGetUserMedia(constraints, function (hqStream) {
  9081. self.localStream = hqStream;
  9082. // reset local maps.
  9083. self._localMaps.msids = [];
  9084. self._localMaps.msid2ssrc = {};
  9085. // add hq trackid to local map
  9086. self._localMaps.msids.push(hqStream.getVideoTracks()[0].id);
  9087. navigator.webkitGetUserMedia(lqConstraints, function (lqStream) {
  9088. self.displayedLocalVideoStream = lqStream;
  9089. // NOTE(gp) The specification says Array.forEach() will visit
  9090. // the array elements in numeric order, and that it doesn't
  9091. // visit elements that don't exist.
  9092. // add lq trackid to local map
  9093. self._localMaps.msids.splice(0, 0, lqStream.getVideoTracks()[0].id);
  9094. self.localStream.addTrack(lqStream.getVideoTracks()[0]);
  9095. success(self.localStream);
  9096. }, err);
  9097. }, err);
  9098. };
  9099. /**
  9100. * Prepares the local description for public usage (i.e. to be signaled
  9101. * through Jingle to the focus).
  9102. *
  9103. * @param desc
  9104. * @returns {RTCSessionDescription}
  9105. */
  9106. SimpleSimulcastSender.prototype.reverseTransformLocalDescription = function (desc) {
  9107. var sb;
  9108. if (!this.simulcastUtils.isValidDescription(desc)) {
  9109. return desc;
  9110. }
  9111. sb = desc.sdp.split('\r\n');
  9112. this._groupLocalVideoSources(sb);
  9113. desc = new RTCSessionDescription({
  9114. type: desc.type,
  9115. sdp: sb.join('\r\n')
  9116. });
  9117. this.logger.fine('Grouped local video sources');
  9118. this.logger.fine(desc.sdp);
  9119. return desc;
  9120. };
  9121. /**
  9122. * Ensures that the simulcast group is present in the answer, _if_ native
  9123. * simulcast is enabled,
  9124. *
  9125. * @param desc
  9126. * @returns {*}
  9127. */
  9128. SimpleSimulcastSender.prototype.transformAnswer = function (desc) {
  9129. return desc;
  9130. };
  9131. /**
  9132. *
  9133. *
  9134. * @param desc
  9135. * @returns {*}
  9136. */
  9137. SimpleSimulcastSender.prototype.transformLocalDescription = function (desc) {
  9138. var sb = desc.sdp.split('\r\n');
  9139. this.simulcastUtils._removeSimulcastGroup(sb);
  9140. desc = new RTCSessionDescription({
  9141. type: desc.type,
  9142. sdp: sb.join('\r\n')
  9143. });
  9144. this.logger.fine('Transformed local description');
  9145. this.logger.fine(desc.sdp);
  9146. return desc;
  9147. };
  9148. SimpleSimulcastSender.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
  9149. var trackid;
  9150. var self = this;
  9151. this.logger.log(['Requested to', enabled ? 'enable' : 'disable', ssrc].join(' '));
  9152. if (Object.keys(this._localMaps.msid2ssrc).some(function (tid) {
  9153. // Search for the track id that corresponds to the ssrc
  9154. if (self._localMaps.msid2ssrc[tid] == ssrc) {
  9155. trackid = tid;
  9156. return true;
  9157. }
  9158. }) && self.localStream.getVideoTracks().some(function (track) {
  9159. // Start/stop the track that corresponds to the track id
  9160. if (track.id === trackid) {
  9161. track.enabled = enabled;
  9162. return true;
  9163. }
  9164. })) {
  9165. this.logger.log([trackid, enabled ? 'enabled' : 'disabled'].join(' '));
  9166. $(document).trigger(enabled
  9167. ? 'simulcastlayerstarted'
  9168. : 'simulcastlayerstopped');
  9169. } else {
  9170. this.logger.error("I don't have a local stream with SSRC " + ssrc);
  9171. }
  9172. };
  9173. SimpleSimulcastSender.prototype.constructor = SimpleSimulcastSender;
  9174. function NoSimulcastSender() {
  9175. SimulcastSender.call(this);
  9176. }
  9177. NoSimulcastSender.prototype = Object.create(SimulcastSender.prototype);
  9178. /**
  9179. * GUM for simulcast.
  9180. *
  9181. * @param constraints
  9182. * @param success
  9183. * @param err
  9184. */
  9185. NoSimulcastSender.prototype.getUserMedia = function (constraints, success, err) {
  9186. navigator.webkitGetUserMedia(constraints, function (hqStream) {
  9187. success(hqStream);
  9188. }, err);
  9189. };
  9190. /**
  9191. * Prepares the local description for public usage (i.e. to be signaled
  9192. * through Jingle to the focus).
  9193. *
  9194. * @param desc
  9195. * @returns {RTCSessionDescription}
  9196. */
  9197. NoSimulcastSender.prototype.reverseTransformLocalDescription = function (desc) {
  9198. return desc;
  9199. };
  9200. /**
  9201. * Ensures that the simulcast group is present in the answer, _if_ native
  9202. * simulcast is enabled,
  9203. *
  9204. * @param desc
  9205. * @returns {*}
  9206. */
  9207. NoSimulcastSender.prototype.transformAnswer = function (desc) {
  9208. return desc;
  9209. };
  9210. /**
  9211. *
  9212. *
  9213. * @param desc
  9214. * @returns {*}
  9215. */
  9216. NoSimulcastSender.prototype.transformLocalDescription = function (desc) {
  9217. return desc;
  9218. };
  9219. NoSimulcastSender.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
  9220. };
  9221. NoSimulcastSender.prototype.constructor = NoSimulcastSender;
  9222. module.exports = {
  9223. "native": NativeSimulcastSender,
  9224. "no": NoSimulcastSender
  9225. }
  9226. },{"./SimulcastLogger":39,"./SimulcastUtils":42}],42:[function(require,module,exports){
  9227. var SimulcastLogger = require("./SimulcastLogger");
  9228. /**
  9229. *
  9230. * @constructor
  9231. */
  9232. function SimulcastUtils() {
  9233. this.logger = new SimulcastLogger("SimulcastUtils", 1);
  9234. }
  9235. /**
  9236. *
  9237. * @type {{}}
  9238. * @private
  9239. */
  9240. SimulcastUtils.prototype._emptyCompoundIndex = {};
  9241. /**
  9242. *
  9243. * @param lines
  9244. * @param videoSources
  9245. * @private
  9246. */
  9247. SimulcastUtils.prototype._replaceVideoSources = function (lines, videoSources) {
  9248. var i, inVideo = false, index = -1, howMany = 0;
  9249. this.logger.info('Replacing video sources...');
  9250. for (i = 0; i < lines.length; i++) {
  9251. if (inVideo && lines[i].substring(0, 'm='.length) === 'm=') {
  9252. // Out of video.
  9253. break;
  9254. }
  9255. if (!inVideo && lines[i].substring(0, 'm=video '.length) === 'm=video ') {
  9256. // In video.
  9257. inVideo = true;
  9258. }
  9259. if (inVideo && (lines[i].substring(0, 'a=ssrc:'.length) === 'a=ssrc:'
  9260. || lines[i].substring(0, 'a=ssrc-group:'.length) === 'a=ssrc-group:')) {
  9261. if (index === -1) {
  9262. index = i;
  9263. }
  9264. howMany++;
  9265. }
  9266. }
  9267. // efficiency baby ;)
  9268. lines.splice.apply(lines,
  9269. [index, howMany].concat(videoSources));
  9270. };
  9271. SimulcastUtils.prototype.isValidDescription = function (desc)
  9272. {
  9273. return desc && desc != null
  9274. && desc.type && desc.type != ''
  9275. && desc.sdp && desc.sdp != '';
  9276. };
  9277. SimulcastUtils.prototype._getVideoSources = function (lines) {
  9278. var i, inVideo = false, sb = [];
  9279. this.logger.info('Getting video sources...');
  9280. for (i = 0; i < lines.length; i++) {
  9281. if (inVideo && lines[i].substring(0, 'm='.length) === 'm=') {
  9282. // Out of video.
  9283. break;
  9284. }
  9285. if (!inVideo && lines[i].substring(0, 'm=video '.length) === 'm=video ') {
  9286. // In video.
  9287. inVideo = true;
  9288. }
  9289. if (inVideo && lines[i].substring(0, 'a=ssrc:'.length) === 'a=ssrc:') {
  9290. // In SSRC.
  9291. sb.push(lines[i]);
  9292. }
  9293. if (inVideo && lines[i].substring(0, 'a=ssrc-group:'.length) === 'a=ssrc-group:') {
  9294. sb.push(lines[i]);
  9295. }
  9296. }
  9297. return sb;
  9298. };
  9299. SimulcastUtils.prototype.parseMedia = function (lines, mediatypes) {
  9300. var i, res = [], type, cur_media, idx, ssrcs, cur_ssrc, ssrc,
  9301. ssrc_attribute, group, semantics, skip = true;
  9302. this.logger.info('Parsing media sources...');
  9303. for (i = 0; i < lines.length; i++) {
  9304. if (lines[i].substring(0, 'm='.length) === 'm=') {
  9305. type = lines[i]
  9306. .substr('m='.length, lines[i].indexOf(' ') - 'm='.length);
  9307. skip = mediatypes !== undefined && mediatypes.indexOf(type) === -1;
  9308. if (!skip) {
  9309. cur_media = {
  9310. 'type': type,
  9311. 'sources': {},
  9312. 'groups': []
  9313. };
  9314. res.push(cur_media);
  9315. }
  9316. } else if (!skip && lines[i].substring(0, 'a=ssrc:'.length) === 'a=ssrc:') {
  9317. idx = lines[i].indexOf(' ');
  9318. ssrc = lines[i].substring('a=ssrc:'.length, idx);
  9319. if (cur_media.sources[ssrc] === undefined) {
  9320. cur_ssrc = {'ssrc': ssrc};
  9321. cur_media.sources[ssrc] = cur_ssrc;
  9322. }
  9323. ssrc_attribute = lines[i].substr(idx + 1).split(':', 2)[0];
  9324. cur_ssrc[ssrc_attribute] = lines[i].substr(idx + 1).split(':', 2)[1];
  9325. if (cur_media.base === undefined) {
  9326. cur_media.base = cur_ssrc;
  9327. }
  9328. } else if (!skip && lines[i].substring(0, 'a=ssrc-group:'.length) === 'a=ssrc-group:') {
  9329. idx = lines[i].indexOf(' ');
  9330. semantics = lines[i].substr(0, idx).substr('a=ssrc-group:'.length);
  9331. ssrcs = lines[i].substr(idx).trim().split(' ');
  9332. group = {
  9333. 'semantics': semantics,
  9334. 'ssrcs': ssrcs
  9335. };
  9336. cur_media.groups.push(group);
  9337. } else if (!skip && (lines[i].substring(0, 'a=sendrecv'.length) === 'a=sendrecv' ||
  9338. lines[i].substring(0, 'a=recvonly'.length) === 'a=recvonly' ||
  9339. lines[i].substring(0, 'a=sendonly'.length) === 'a=sendonly' ||
  9340. lines[i].substring(0, 'a=inactive'.length) === 'a=inactive')) {
  9341. cur_media.direction = lines[i].substring('a='.length);
  9342. }
  9343. }
  9344. return res;
  9345. };
  9346. /**
  9347. * The _indexOfArray() method returns the first a CompoundIndex at which a
  9348. * given element can be found in the array, or _emptyCompoundIndex if it is
  9349. * not present.
  9350. *
  9351. * Example:
  9352. *
  9353. * _indexOfArray('3', [ 'this is line 1', 'this is line 2', 'this is line 3' ])
  9354. *
  9355. * returns {row: 2, column: 14}
  9356. *
  9357. * @param needle
  9358. * @param haystack
  9359. * @param start
  9360. * @returns {}
  9361. * @private
  9362. */
  9363. SimulcastUtils.prototype._indexOfArray = function (needle, haystack, start) {
  9364. var length = haystack.length, idx, i;
  9365. if (!start) {
  9366. start = 0;
  9367. }
  9368. for (i = start; i < length; i++) {
  9369. idx = haystack[i].indexOf(needle);
  9370. if (idx !== -1) {
  9371. return {row: i, column: idx};
  9372. }
  9373. }
  9374. return this._emptyCompoundIndex;
  9375. };
  9376. SimulcastUtils.prototype._removeSimulcastGroup = function (lines) {
  9377. var i;
  9378. for (i = lines.length - 1; i >= 0; i--) {
  9379. if (lines[i].indexOf('a=ssrc-group:SIM') !== -1) {
  9380. lines.splice(i, 1);
  9381. }
  9382. }
  9383. };
  9384. SimulcastUtils.prototype._compileVideoSources = function (videoSources) {
  9385. var sb = [], ssrc, addedSSRCs = [];
  9386. this.logger.info('Compiling video sources...');
  9387. // Add the groups
  9388. if (videoSources.groups && videoSources.groups.length !== 0) {
  9389. videoSources.groups.forEach(function (group) {
  9390. if (group.ssrcs && group.ssrcs.length !== 0) {
  9391. sb.push([['a=ssrc-group:', group.semantics].join(''), group.ssrcs.join(' ')].join(' '));
  9392. // if (group.semantics !== 'SIM') {
  9393. group.ssrcs.forEach(function (ssrc) {
  9394. addedSSRCs.push(ssrc);
  9395. sb.splice.apply(sb, [sb.length, 0].concat([
  9396. ["a=ssrc:", ssrc, " cname:", videoSources.sources[ssrc].cname].join(''),
  9397. ["a=ssrc:", ssrc, " msid:", videoSources.sources[ssrc].msid].join('')]));
  9398. });
  9399. //}
  9400. }
  9401. });
  9402. }
  9403. // Then add any free sources.
  9404. if (videoSources.sources) {
  9405. for (ssrc in videoSources.sources) {
  9406. if (addedSSRCs.indexOf(ssrc) === -1) {
  9407. sb.splice.apply(sb, [sb.length, 0].concat([
  9408. ["a=ssrc:", ssrc, " cname:", videoSources.sources[ssrc].cname].join(''),
  9409. ["a=ssrc:", ssrc, " msid:", videoSources.sources[ssrc].msid].join('')]));
  9410. }
  9411. }
  9412. }
  9413. return sb;
  9414. };
  9415. module.exports = SimulcastUtils;
  9416. },{"./SimulcastLogger":39}],43:[function(require,module,exports){
  9417. /*jslint plusplus: true */
  9418. /*jslint nomen: true*/
  9419. var SimulcastSender = require("./SimulcastSender");
  9420. var NoSimulcastSender = SimulcastSender["no"];
  9421. var NativeSimulcastSender = SimulcastSender["native"];
  9422. var SimulcastReceiver = require("./SimulcastReceiver");
  9423. var SimulcastUtils = require("./SimulcastUtils");
  9424. var RTCEvents = require("../../service/RTC/RTCEvents");
  9425. /**
  9426. *
  9427. * @constructor
  9428. */
  9429. function SimulcastManager() {
  9430. // Create the simulcast utilities.
  9431. this.simulcastUtils = new SimulcastUtils();
  9432. // Create remote simulcast.
  9433. this.simulcastReceiver = new SimulcastReceiver();
  9434. // Initialize local simulcast.
  9435. // TODO(gp) move into SimulcastManager.prototype.getUserMedia and take into
  9436. // account constraints.
  9437. if (!config.enableSimulcast) {
  9438. this.simulcastSender = new NoSimulcastSender();
  9439. } else {
  9440. var isChromium = window.chrome,
  9441. vendorName = window.navigator.vendor;
  9442. if(isChromium !== null && isChromium !== undefined
  9443. /* skip opera */
  9444. && vendorName === "Google Inc."
  9445. /* skip Chromium as suggested by fippo */
  9446. && !window.navigator.appVersion.match(/Chromium\//) ) {
  9447. var ver = parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10);
  9448. if (ver > 37) {
  9449. this.simulcastSender = new NativeSimulcastSender();
  9450. } else {
  9451. this.simulcastSender = new NoSimulcastSender();
  9452. }
  9453. } else {
  9454. this.simulcastSender = new NoSimulcastSender();
  9455. }
  9456. }
  9457. APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGED,
  9458. function (endpointSimulcastLayers) {
  9459. endpointSimulcastLayers.forEach(function (esl) {
  9460. var ssrc = esl.simulcastLayer.primarySSRC;
  9461. simulcast._setReceivingVideoStream(esl.endpoint, ssrc);
  9462. });
  9463. });
  9464. APP.RTC.addListener(RTCEvents.SIMULCAST_START, function (simulcastLayer) {
  9465. var ssrc = simulcastLayer.primarySSRC;
  9466. simulcast._setLocalVideoStreamEnabled(ssrc, true);
  9467. });
  9468. APP.RTC.addListener(RTCEvents.SIMULCAST_STOP, function (simulcastLayer) {
  9469. var ssrc = simulcastLayer.primarySSRC;
  9470. simulcast._setLocalVideoStreamEnabled(ssrc, false);
  9471. });
  9472. }
  9473. /**
  9474. * Restores the simulcast groups of the remote description. In
  9475. * transformRemoteDescription we remove those in order for the set remote
  9476. * description to succeed. The focus needs the signal the groups to new
  9477. * participants.
  9478. *
  9479. * @param desc
  9480. * @returns {*}
  9481. */
  9482. SimulcastManager.prototype.reverseTransformRemoteDescription = function (desc) {
  9483. return this.simulcastReceiver.reverseTransformRemoteDescription(desc);
  9484. };
  9485. /**
  9486. * Removes the ssrc-group:SIM from the remote description bacause Chrome
  9487. * either gets confused and thinks this is an FID group or, if an FID group
  9488. * is already present, it fails to set the remote description.
  9489. *
  9490. * @param desc
  9491. * @returns {*}
  9492. */
  9493. SimulcastManager.prototype.transformRemoteDescription = function (desc) {
  9494. return this.simulcastReceiver.transformRemoteDescription(desc);
  9495. };
  9496. /**
  9497. * Gets the fully qualified msid (stream.id + track.id) associated to the
  9498. * SSRC.
  9499. *
  9500. * @param ssrc
  9501. * @returns {*}
  9502. */
  9503. SimulcastManager.prototype.getRemoteVideoStreamIdBySSRC = function (ssrc) {
  9504. return this.simulcastReceiver.getRemoteVideoStreamIdBySSRC(ssrc);
  9505. };
  9506. /**
  9507. * Returns a stream with single video track, the one currently being
  9508. * received by this endpoint.
  9509. *
  9510. * @param stream the remote simulcast stream.
  9511. * @returns {webkitMediaStream}
  9512. */
  9513. SimulcastManager.prototype.getReceivingVideoStream = function (stream) {
  9514. return this.simulcastReceiver.getReceivingVideoStream(stream);
  9515. };
  9516. /**
  9517. *
  9518. *
  9519. * @param desc
  9520. * @returns {*}
  9521. */
  9522. SimulcastManager.prototype.transformLocalDescription = function (desc) {
  9523. return this.simulcastSender.transformLocalDescription(desc);
  9524. };
  9525. /**
  9526. *
  9527. * @returns {*}
  9528. */
  9529. SimulcastManager.prototype.getLocalVideoStream = function() {
  9530. return this.simulcastSender.getLocalVideoStream();
  9531. };
  9532. /**
  9533. * GUM for simulcast.
  9534. *
  9535. * @param constraints
  9536. * @param success
  9537. * @param err
  9538. */
  9539. SimulcastManager.prototype.getUserMedia = function (constraints, success, err) {
  9540. this.simulcastSender.getUserMedia(constraints, success, err);
  9541. };
  9542. /**
  9543. * Prepares the local description for public usage (i.e. to be signaled
  9544. * through Jingle to the focus).
  9545. *
  9546. * @param desc
  9547. * @returns {RTCSessionDescription}
  9548. */
  9549. SimulcastManager.prototype.reverseTransformLocalDescription = function (desc) {
  9550. return this.simulcastSender.reverseTransformLocalDescription(desc);
  9551. };
  9552. /**
  9553. * Ensures that the simulcast group is present in the answer, _if_ native
  9554. * simulcast is enabled,
  9555. *
  9556. * @param desc
  9557. * @returns {*}
  9558. */
  9559. SimulcastManager.prototype.transformAnswer = function (desc) {
  9560. return this.simulcastSender.transformAnswer(desc);
  9561. };
  9562. SimulcastManager.prototype.getReceivingSSRC = function (jid) {
  9563. return this.simulcastReceiver.getReceivingSSRC(jid);
  9564. };
  9565. SimulcastManager.prototype.getReceivingVideoStreamBySSRC = function (msid) {
  9566. return this.simulcastReceiver.getReceivingVideoStreamBySSRC(msid);
  9567. };
  9568. /**
  9569. *
  9570. * @param lines
  9571. * @param mediatypes
  9572. * @returns {*}
  9573. */
  9574. SimulcastManager.prototype.parseMedia = function(lines, mediatypes) {
  9575. var sb = lines.sdp.split('\r\n');
  9576. return this.simulcastUtils.parseMedia(sb, mediatypes);
  9577. };
  9578. SimulcastManager.prototype._setReceivingVideoStream = function(resource, ssrc) {
  9579. this.simulcastReceiver._setReceivingVideoStream(resource, ssrc);
  9580. };
  9581. SimulcastManager.prototype._setLocalVideoStreamEnabled = function(ssrc, enabled) {
  9582. this.simulcastSender._setLocalVideoStreamEnabled(ssrc, enabled);
  9583. };
  9584. SimulcastManager.prototype.resetSender = function() {
  9585. if (typeof this.simulcastSender.reset === 'function'){
  9586. this.simulcastSender.reset();
  9587. }
  9588. };
  9589. var simulcast = new SimulcastManager();
  9590. module.exports = simulcast;
  9591. },{"../../service/RTC/RTCEvents":89,"./SimulcastReceiver":40,"./SimulcastSender":41,"./SimulcastUtils":42}],44:[function(require,module,exports){
  9592. /**
  9593. * Provides statistics for the local stream.
  9594. */
  9595. /**
  9596. * Size of the webaudio analizer buffer.
  9597. * @type {number}
  9598. */
  9599. var WEBAUDIO_ANALIZER_FFT_SIZE = 2048;
  9600. /**
  9601. * Value of the webaudio analizer smoothing time parameter.
  9602. * @type {number}
  9603. */
  9604. var WEBAUDIO_ANALIZER_SMOOTING_TIME = 0.8;
  9605. /**
  9606. * Converts time domain data array to audio level.
  9607. * @param array the time domain data array.
  9608. * @returns {number} the audio level
  9609. */
  9610. function timeDomainDataToAudioLevel(samples) {
  9611. var maxVolume = 0;
  9612. var length = samples.length;
  9613. for (var i = 0; i < length; i++) {
  9614. if (maxVolume < samples[i])
  9615. maxVolume = samples[i];
  9616. }
  9617. return parseFloat(((maxVolume - 127) / 128).toFixed(3));
  9618. };
  9619. /**
  9620. * Animates audio level change
  9621. * @param newLevel the new audio level
  9622. * @param lastLevel the last audio level
  9623. * @returns {Number} the audio level to be set
  9624. */
  9625. function animateLevel(newLevel, lastLevel)
  9626. {
  9627. var value = 0;
  9628. var diff = lastLevel - newLevel;
  9629. if(diff > 0.2)
  9630. {
  9631. value = lastLevel - 0.2;
  9632. }
  9633. else if(diff < -0.4)
  9634. {
  9635. value = lastLevel + 0.4;
  9636. }
  9637. else
  9638. {
  9639. value = newLevel;
  9640. }
  9641. return parseFloat(value.toFixed(3));
  9642. }
  9643. /**
  9644. * <tt>LocalStatsCollector</tt> calculates statistics for the local stream.
  9645. *
  9646. * @param stream the local stream
  9647. * @param interval stats refresh interval given in ms.
  9648. * @param {function(LocalStatsCollector)} updateCallback the callback called on stats
  9649. * update.
  9650. * @constructor
  9651. */
  9652. function LocalStatsCollector(stream, interval, statisticsService, eventEmitter) {
  9653. window.AudioContext = window.AudioContext || window.webkitAudioContext;
  9654. this.stream = stream;
  9655. this.intervalId = null;
  9656. this.intervalMilis = interval;
  9657. this.eventEmitter = eventEmitter;
  9658. this.audioLevel = 0;
  9659. this.statisticsService = statisticsService;
  9660. }
  9661. /**
  9662. * Starts the collecting the statistics.
  9663. */
  9664. LocalStatsCollector.prototype.start = function () {
  9665. if (config.disableAudioLevels || !window.AudioContext)
  9666. return;
  9667. var context = new AudioContext();
  9668. var analyser = context.createAnalyser();
  9669. analyser.smoothingTimeConstant = WEBAUDIO_ANALIZER_SMOOTING_TIME;
  9670. analyser.fftSize = WEBAUDIO_ANALIZER_FFT_SIZE;
  9671. var source = context.createMediaStreamSource(this.stream);
  9672. source.connect(analyser);
  9673. var self = this;
  9674. this.intervalId = setInterval(
  9675. function () {
  9676. var array = new Uint8Array(analyser.frequencyBinCount);
  9677. analyser.getByteTimeDomainData(array);
  9678. var audioLevel = timeDomainDataToAudioLevel(array);
  9679. if(audioLevel != self.audioLevel) {
  9680. self.audioLevel = animateLevel(audioLevel, self.audioLevel);
  9681. self.eventEmitter.emit(
  9682. "statistics.audioLevel",
  9683. self.statisticsService.LOCAL_JID,
  9684. self.audioLevel);
  9685. }
  9686. },
  9687. this.intervalMilis
  9688. );
  9689. };
  9690. /**
  9691. * Stops collecting the statistics.
  9692. */
  9693. LocalStatsCollector.prototype.stop = function () {
  9694. if (this.intervalId) {
  9695. clearInterval(this.intervalId);
  9696. this.intervalId = null;
  9697. }
  9698. };
  9699. module.exports = LocalStatsCollector;
  9700. },{}],45:[function(require,module,exports){
  9701. /* global ssrc2jid */
  9702. /* jshint -W117 */
  9703. var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
  9704. /**
  9705. * Calculates packet lost percent using the number of lost packets and the
  9706. * number of all packet.
  9707. * @param lostPackets the number of lost packets
  9708. * @param totalPackets the number of all packets.
  9709. * @returns {number} packet loss percent
  9710. */
  9711. function calculatePacketLoss(lostPackets, totalPackets) {
  9712. if(!totalPackets || totalPackets <= 0 || !lostPackets || lostPackets <= 0)
  9713. return 0;
  9714. return Math.round((lostPackets/totalPackets)*100);
  9715. }
  9716. function getStatValue(item, name) {
  9717. if(!keyMap[APP.RTC.getBrowserType()][name])
  9718. throw "The property isn't supported!";
  9719. var key = keyMap[APP.RTC.getBrowserType()][name];
  9720. return APP.RTC.getBrowserType() == RTCBrowserType.RTC_BROWSER_CHROME? item.stat(key) : item[key];
  9721. }
  9722. /**
  9723. * Peer statistics data holder.
  9724. * @constructor
  9725. */
  9726. function PeerStats()
  9727. {
  9728. this.ssrc2Loss = {};
  9729. this.ssrc2AudioLevel = {};
  9730. this.ssrc2bitrate = {};
  9731. this.ssrc2resolution = {};
  9732. }
  9733. /**
  9734. * The bandwidth
  9735. * @type {{}}
  9736. */
  9737. PeerStats.bandwidth = {};
  9738. /**
  9739. * The bit rate
  9740. * @type {{}}
  9741. */
  9742. PeerStats.bitrate = {};
  9743. /**
  9744. * The packet loss rate
  9745. * @type {{}}
  9746. */
  9747. PeerStats.packetLoss = null;
  9748. /**
  9749. * Sets packets loss rate for given <tt>ssrc</tt> that blong to the peer
  9750. * represented by this instance.
  9751. * @param ssrc audio or video RTP stream SSRC.
  9752. * @param lossRate new packet loss rate value to be set.
  9753. */
  9754. PeerStats.prototype.setSsrcLoss = function (ssrc, lossRate)
  9755. {
  9756. this.ssrc2Loss[ssrc] = lossRate;
  9757. };
  9758. /**
  9759. * Sets resolution for given <tt>ssrc</tt> that belong to the peer
  9760. * represented by this instance.
  9761. * @param ssrc audio or video RTP stream SSRC.
  9762. * @param resolution new resolution value to be set.
  9763. */
  9764. PeerStats.prototype.setSsrcResolution = function (ssrc, resolution)
  9765. {
  9766. if(resolution === null && this.ssrc2resolution[ssrc])
  9767. {
  9768. delete this.ssrc2resolution[ssrc];
  9769. }
  9770. else if(resolution !== null)
  9771. this.ssrc2resolution[ssrc] = resolution;
  9772. };
  9773. /**
  9774. * Sets the bit rate for given <tt>ssrc</tt> that blong to the peer
  9775. * represented by this instance.
  9776. * @param ssrc audio or video RTP stream SSRC.
  9777. * @param bitrate new bitrate value to be set.
  9778. */
  9779. PeerStats.prototype.setSsrcBitrate = function (ssrc, bitrate)
  9780. {
  9781. if(this.ssrc2bitrate[ssrc])
  9782. {
  9783. this.ssrc2bitrate[ssrc].download += bitrate.download;
  9784. this.ssrc2bitrate[ssrc].upload += bitrate.upload;
  9785. }
  9786. else {
  9787. this.ssrc2bitrate[ssrc] = bitrate;
  9788. }
  9789. };
  9790. /**
  9791. * Sets new audio level(input or output) for given <tt>ssrc</tt> that identifies
  9792. * the stream which belongs to the peer represented by this instance.
  9793. * @param ssrc RTP stream SSRC for which current audio level value will be
  9794. * updated.
  9795. * @param audioLevel the new audio level value to be set. Value is truncated to
  9796. * fit the range from 0 to 1.
  9797. */
  9798. PeerStats.prototype.setSsrcAudioLevel = function (ssrc, audioLevel)
  9799. {
  9800. // Range limit 0 - 1
  9801. this.ssrc2AudioLevel[ssrc] = formatAudioLevel(audioLevel);
  9802. };
  9803. function formatAudioLevel(audioLevel) {
  9804. return Math.min(Math.max(audioLevel, 0), 1);
  9805. }
  9806. /**
  9807. * Array with the transport information.
  9808. * @type {Array}
  9809. */
  9810. PeerStats.transport = [];
  9811. /**
  9812. * <tt>StatsCollector</tt> registers for stats updates of given
  9813. * <tt>peerconnection</tt> in given <tt>interval</tt>. On each update particular
  9814. * stats are extracted and put in {@link PeerStats} objects. Once the processing
  9815. * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>
  9816. * instance as an event source.
  9817. *
  9818. * @param peerconnection webRTC peer connection object.
  9819. * @param interval stats refresh interval given in ms.
  9820. * @param {function(StatsCollector)} audioLevelsUpdateCallback the callback
  9821. * called on stats update.
  9822. * @constructor
  9823. */
  9824. function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter)
  9825. {
  9826. this.peerconnection = peerconnection;
  9827. this.baselineAudioLevelsReport = null;
  9828. this.currentAudioLevelsReport = null;
  9829. this.currentStatsReport = null;
  9830. this.baselineStatsReport = null;
  9831. this.audioLevelsIntervalId = null;
  9832. this.eventEmitter = eventEmitter;
  9833. /**
  9834. * Gather PeerConnection stats once every this many milliseconds.
  9835. */
  9836. this.GATHER_INTERVAL = 15000;
  9837. /**
  9838. * Log stats via the focus once every this many milliseconds.
  9839. */
  9840. this.LOG_INTERVAL = 60000;
  9841. /**
  9842. * Gather stats and store them in this.statsToBeLogged.
  9843. */
  9844. this.gatherStatsIntervalId = null;
  9845. /**
  9846. * Send the stats already saved in this.statsToBeLogged to be logged via
  9847. * the focus.
  9848. */
  9849. this.logStatsIntervalId = null;
  9850. /**
  9851. * Stores the statistics which will be send to the focus to be logged.
  9852. */
  9853. this.statsToBeLogged =
  9854. {
  9855. timestamps: [],
  9856. stats: {}
  9857. };
  9858. // Updates stats interval
  9859. this.audioLevelsIntervalMilis = audioLevelsInterval;
  9860. this.statsIntervalId = null;
  9861. this.statsIntervalMilis = statsInterval;
  9862. // Map of jids to PeerStats
  9863. this.jid2stats = {};
  9864. }
  9865. module.exports = StatsCollector;
  9866. /**
  9867. * Stops stats updates.
  9868. */
  9869. StatsCollector.prototype.stop = function () {
  9870. if (this.audioLevelsIntervalId) {
  9871. clearInterval(this.audioLevelsIntervalId);
  9872. this.audioLevelsIntervalId = null;
  9873. }
  9874. if (this.statsIntervalId)
  9875. {
  9876. clearInterval(this.statsIntervalId);
  9877. this.statsIntervalId = null;
  9878. }
  9879. if(this.logStatsIntervalId)
  9880. {
  9881. clearInterval(this.logStatsIntervalId);
  9882. this.logStatsIntervalId = null;
  9883. }
  9884. if(this.gatherStatsIntervalId)
  9885. {
  9886. clearInterval(this.gatherStatsIntervalId);
  9887. this.gatherStatsIntervalId = null;
  9888. }
  9889. };
  9890. /**
  9891. * Callback passed to <tt>getStats</tt> method.
  9892. * @param error an error that occurred on <tt>getStats</tt> call.
  9893. */
  9894. StatsCollector.prototype.errorCallback = function (error)
  9895. {
  9896. console.error("Get stats error", error);
  9897. this.stop();
  9898. };
  9899. /**
  9900. * Starts stats updates.
  9901. */
  9902. StatsCollector.prototype.start = function ()
  9903. {
  9904. var self = this;
  9905. if(!config.disableAudioLevels) {
  9906. this.audioLevelsIntervalId = setInterval(
  9907. function () {
  9908. // Interval updates
  9909. self.peerconnection.getStats(
  9910. function (report) {
  9911. var results = null;
  9912. if (!report || !report.result ||
  9913. typeof report.result != 'function') {
  9914. results = report;
  9915. }
  9916. else {
  9917. results = report.result();
  9918. }
  9919. //console.error("Got interval report", results);
  9920. self.currentAudioLevelsReport = results;
  9921. self.processAudioLevelReport();
  9922. self.baselineAudioLevelsReport =
  9923. self.currentAudioLevelsReport;
  9924. },
  9925. self.errorCallback
  9926. );
  9927. },
  9928. self.audioLevelsIntervalMilis
  9929. );
  9930. }
  9931. if(!config.disableStats) {
  9932. this.statsIntervalId = setInterval(
  9933. function () {
  9934. // Interval updates
  9935. self.peerconnection.getStats(
  9936. function (report) {
  9937. var results = null;
  9938. if (!report || !report.result ||
  9939. typeof report.result != 'function') {
  9940. //firefox
  9941. results = report;
  9942. }
  9943. else {
  9944. //chrome
  9945. results = report.result();
  9946. }
  9947. //console.error("Got interval report", results);
  9948. self.currentStatsReport = results;
  9949. try {
  9950. self.processStatsReport();
  9951. }
  9952. catch (e) {
  9953. console.error("Unsupported key:" + e, e);
  9954. }
  9955. self.baselineStatsReport = self.currentStatsReport;
  9956. },
  9957. self.errorCallback
  9958. );
  9959. },
  9960. self.statsIntervalMilis
  9961. );
  9962. }
  9963. if (config.logStats) {
  9964. this.gatherStatsIntervalId = setInterval(
  9965. function () {
  9966. self.peerconnection.getStats(
  9967. function (report) {
  9968. self.addStatsToBeLogged(report.result());
  9969. },
  9970. function () {
  9971. }
  9972. );
  9973. },
  9974. this.GATHER_INTERVAL
  9975. );
  9976. this.logStatsIntervalId = setInterval(
  9977. function() { self.logStats(); },
  9978. this.LOG_INTERVAL);
  9979. }
  9980. };
  9981. /**
  9982. * Checks whether a certain record should be included in the logged statistics.
  9983. */
  9984. function acceptStat(reportId, reportType, statName) {
  9985. if (reportType == "googCandidatePair" && statName == "googChannelId")
  9986. return false;
  9987. if (reportType == "ssrc") {
  9988. if (statName == "googTrackId" ||
  9989. statName == "transportId" ||
  9990. statName == "ssrc")
  9991. return false;
  9992. }
  9993. return true;
  9994. }
  9995. /**
  9996. * Checks whether a certain record should be included in the logged statistics.
  9997. */
  9998. function acceptReport(id, type) {
  9999. if (id.substring(0, 15) == "googCertificate" ||
  10000. id.substring(0, 9) == "googTrack" ||
  10001. id.substring(0, 20) == "googLibjingleSession")
  10002. return false;
  10003. if (type == "googComponent")
  10004. return false;
  10005. return true;
  10006. }
  10007. /**
  10008. * Converts the stats to the format used for logging, and saves the data in
  10009. * this.statsToBeLogged.
  10010. * @param reports Reports as given by webkitRTCPerConnection.getStats.
  10011. */
  10012. StatsCollector.prototype.addStatsToBeLogged = function (reports) {
  10013. var self = this;
  10014. var num_records = this.statsToBeLogged.timestamps.length;
  10015. this.statsToBeLogged.timestamps.push(new Date().getTime());
  10016. reports.map(function (report) {
  10017. if (!acceptReport(report.id, report.type))
  10018. return;
  10019. var stat = self.statsToBeLogged.stats[report.id];
  10020. if (!stat) {
  10021. stat = self.statsToBeLogged.stats[report.id] = {};
  10022. }
  10023. stat.type = report.type;
  10024. report.names().map(function (name) {
  10025. if (!acceptStat(report.id, report.type, name))
  10026. return;
  10027. var values = stat[name];
  10028. if (!values) {
  10029. values = stat[name] = [];
  10030. }
  10031. while (values.length < num_records) {
  10032. values.push(null);
  10033. }
  10034. values.push(report.stat(name));
  10035. });
  10036. });
  10037. };
  10038. StatsCollector.prototype.logStats = function () {
  10039. if(!APP.xmpp.sendLogs(this.statsToBeLogged))
  10040. return;
  10041. // Reset the stats
  10042. this.statsToBeLogged.stats = {};
  10043. this.statsToBeLogged.timestamps = [];
  10044. };
  10045. var keyMap = {};
  10046. keyMap[RTCBrowserType.RTC_BROWSER_FIREFOX] = {
  10047. "ssrc": "ssrc",
  10048. "packetsReceived": "packetsReceived",
  10049. "packetsLost": "packetsLost",
  10050. "packetsSent": "packetsSent",
  10051. "bytesReceived": "bytesReceived",
  10052. "bytesSent": "bytesSent"
  10053. };
  10054. keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
  10055. "receiveBandwidth": "googAvailableReceiveBandwidth",
  10056. "sendBandwidth": "googAvailableSendBandwidth",
  10057. "remoteAddress": "googRemoteAddress",
  10058. "transportType": "googTransportType",
  10059. "localAddress": "googLocalAddress",
  10060. "activeConnection": "googActiveConnection",
  10061. "ssrc": "ssrc",
  10062. "packetsReceived": "packetsReceived",
  10063. "packetsSent": "packetsSent",
  10064. "packetsLost": "packetsLost",
  10065. "bytesReceived": "bytesReceived",
  10066. "bytesSent": "bytesSent",
  10067. "googFrameHeightReceived": "googFrameHeightReceived",
  10068. "googFrameWidthReceived": "googFrameWidthReceived",
  10069. "googFrameHeightSent": "googFrameHeightSent",
  10070. "googFrameWidthSent": "googFrameWidthSent",
  10071. "audioInputLevel": "audioInputLevel",
  10072. "audioOutputLevel": "audioOutputLevel"
  10073. };
  10074. /**
  10075. * Stats processing logic.
  10076. */
  10077. StatsCollector.prototype.processStatsReport = function () {
  10078. if (!this.baselineStatsReport) {
  10079. return;
  10080. }
  10081. for (var idx in this.currentStatsReport) {
  10082. var now = this.currentStatsReport[idx];
  10083. try {
  10084. if (getStatValue(now, 'receiveBandwidth') ||
  10085. getStatValue(now, 'sendBandwidth')) {
  10086. PeerStats.bandwidth = {
  10087. "download": Math.round(
  10088. (getStatValue(now, 'receiveBandwidth')) / 1000),
  10089. "upload": Math.round(
  10090. (getStatValue(now, 'sendBandwidth')) / 1000)
  10091. };
  10092. }
  10093. }
  10094. catch(e){/*not supported*/}
  10095. if(now.type == 'googCandidatePair')
  10096. {
  10097. var ip, type, localIP, active;
  10098. try {
  10099. ip = getStatValue(now, 'remoteAddress');
  10100. type = getStatValue(now, "transportType");
  10101. localIP = getStatValue(now, "localAddress");
  10102. active = getStatValue(now, "activeConnection");
  10103. }
  10104. catch(e){/*not supported*/}
  10105. if(!ip || !type || !localIP || active != "true")
  10106. continue;
  10107. var addressSaved = false;
  10108. for(var i = 0; i < PeerStats.transport.length; i++)
  10109. {
  10110. if(PeerStats.transport[i].ip == ip &&
  10111. PeerStats.transport[i].type == type &&
  10112. PeerStats.transport[i].localip == localIP)
  10113. {
  10114. addressSaved = true;
  10115. }
  10116. }
  10117. if(addressSaved)
  10118. continue;
  10119. PeerStats.transport.push({localip: localIP, ip: ip, type: type});
  10120. continue;
  10121. }
  10122. if(now.type == "candidatepair")
  10123. {
  10124. if(now.state == "succeeded")
  10125. continue;
  10126. var local = this.currentStatsReport[now.localCandidateId];
  10127. var remote = this.currentStatsReport[now.remoteCandidateId];
  10128. PeerStats.transport.push({localip: local.ipAddress + ":" + local.portNumber,
  10129. ip: remote.ipAddress + ":" + remote.portNumber, type: local.transport});
  10130. }
  10131. if (now.type != 'ssrc' && now.type != "outboundrtp" &&
  10132. now.type != "inboundrtp") {
  10133. continue;
  10134. }
  10135. var before = this.baselineStatsReport[idx];
  10136. if (!before) {
  10137. console.warn(getStatValue(now, 'ssrc') + ' not enough data');
  10138. continue;
  10139. }
  10140. var ssrc = getStatValue(now, 'ssrc');
  10141. if(!ssrc)
  10142. continue;
  10143. var jid = APP.xmpp.getJidFromSSRC(ssrc);
  10144. if (!jid && (Date.now() - now.timestamp) < 3000) {
  10145. console.warn("No jid for ssrc: " + ssrc);
  10146. continue;
  10147. }
  10148. var jidStats = this.jid2stats[jid];
  10149. if (!jidStats) {
  10150. jidStats = new PeerStats();
  10151. this.jid2stats[jid] = jidStats;
  10152. }
  10153. var isDownloadStream = true;
  10154. var key = 'packetsReceived';
  10155. if (!getStatValue(now, key))
  10156. {
  10157. isDownloadStream = false;
  10158. key = 'packetsSent';
  10159. if (!getStatValue(now, key))
  10160. {
  10161. console.warn("No packetsReceived nor packetSent stat found");
  10162. continue;
  10163. }
  10164. }
  10165. var packetsNow = getStatValue(now, key);
  10166. if(!packetsNow || packetsNow < 0)
  10167. packetsNow = 0;
  10168. var packetsBefore = getStatValue(before, key);
  10169. if(!packetsBefore || packetsBefore < 0)
  10170. packetsBefore = 0;
  10171. var packetRate = packetsNow - packetsBefore;
  10172. if(!packetRate || packetRate < 0)
  10173. packetRate = 0;
  10174. var currentLoss = getStatValue(now, 'packetsLost');
  10175. if(!currentLoss || currentLoss < 0)
  10176. currentLoss = 0;
  10177. var previousLoss = getStatValue(before, 'packetsLost');
  10178. if(!previousLoss || previousLoss < 0)
  10179. previousLoss = 0;
  10180. var lossRate = currentLoss - previousLoss;
  10181. if(!lossRate || lossRate < 0)
  10182. lossRate = 0;
  10183. var packetsTotal = (packetRate + lossRate);
  10184. jidStats.setSsrcLoss(ssrc,
  10185. {"packetsTotal": packetsTotal,
  10186. "packetsLost": lossRate,
  10187. "isDownloadStream": isDownloadStream});
  10188. var bytesReceived = 0, bytesSent = 0;
  10189. if(getStatValue(now, "bytesReceived"))
  10190. {
  10191. bytesReceived = getStatValue(now, "bytesReceived") -
  10192. getStatValue(before, "bytesReceived");
  10193. }
  10194. if(getStatValue(now, "bytesSent"))
  10195. {
  10196. bytesSent = getStatValue(now, "bytesSent") -
  10197. getStatValue(before, "bytesSent");
  10198. }
  10199. var time = Math.round((now.timestamp - before.timestamp) / 1000);
  10200. if(bytesReceived <= 0 || time <= 0)
  10201. {
  10202. bytesReceived = 0;
  10203. }
  10204. else
  10205. {
  10206. bytesReceived = Math.round(((bytesReceived * 8) / time) / 1000);
  10207. }
  10208. if(bytesSent <= 0 || time <= 0)
  10209. {
  10210. bytesSent = 0;
  10211. }
  10212. else
  10213. {
  10214. bytesSent = Math.round(((bytesSent * 8) / time) / 1000);
  10215. }
  10216. jidStats.setSsrcBitrate(ssrc, {
  10217. "download": bytesReceived,
  10218. "upload": bytesSent});
  10219. var resolution = {height: null, width: null};
  10220. try {
  10221. if (getStatValue(now, "googFrameHeightReceived") &&
  10222. getStatValue(now, "googFrameWidthReceived")) {
  10223. resolution.height = getStatValue(now, "googFrameHeightReceived");
  10224. resolution.width = getStatValue(now, "googFrameWidthReceived");
  10225. }
  10226. else if (getStatValue(now, "googFrameHeightSent") &&
  10227. getStatValue(now, "googFrameWidthSent")) {
  10228. resolution.height = getStatValue(now, "googFrameHeightSent");
  10229. resolution.width = getStatValue(now, "googFrameWidthSent");
  10230. }
  10231. }
  10232. catch(e){/*not supported*/}
  10233. if(resolution.height && resolution.width)
  10234. {
  10235. jidStats.setSsrcResolution(ssrc, resolution);
  10236. }
  10237. else
  10238. {
  10239. jidStats.setSsrcResolution(ssrc, null);
  10240. }
  10241. }
  10242. var self = this;
  10243. // Jid stats
  10244. var totalPackets = {download: 0, upload: 0};
  10245. var lostPackets = {download: 0, upload: 0};
  10246. var bitrateDownload = 0;
  10247. var bitrateUpload = 0;
  10248. var resolutions = {};
  10249. Object.keys(this.jid2stats).forEach(
  10250. function (jid)
  10251. {
  10252. Object.keys(self.jid2stats[jid].ssrc2Loss).forEach(
  10253. function (ssrc)
  10254. {
  10255. var type = "upload";
  10256. if(self.jid2stats[jid].ssrc2Loss[ssrc].isDownloadStream)
  10257. type = "download";
  10258. totalPackets[type] +=
  10259. self.jid2stats[jid].ssrc2Loss[ssrc].packetsTotal;
  10260. lostPackets[type] +=
  10261. self.jid2stats[jid].ssrc2Loss[ssrc].packetsLost;
  10262. }
  10263. );
  10264. Object.keys(self.jid2stats[jid].ssrc2bitrate).forEach(
  10265. function (ssrc) {
  10266. bitrateDownload +=
  10267. self.jid2stats[jid].ssrc2bitrate[ssrc].download;
  10268. bitrateUpload +=
  10269. self.jid2stats[jid].ssrc2bitrate[ssrc].upload;
  10270. delete self.jid2stats[jid].ssrc2bitrate[ssrc];
  10271. }
  10272. );
  10273. resolutions[jid] = self.jid2stats[jid].ssrc2resolution;
  10274. }
  10275. );
  10276. PeerStats.bitrate = {"upload": bitrateUpload, "download": bitrateDownload};
  10277. PeerStats.packetLoss = {
  10278. total:
  10279. calculatePacketLoss(lostPackets.download + lostPackets.upload,
  10280. totalPackets.download + totalPackets.upload),
  10281. download:
  10282. calculatePacketLoss(lostPackets.download, totalPackets.download),
  10283. upload:
  10284. calculatePacketLoss(lostPackets.upload, totalPackets.upload)
  10285. };
  10286. this.eventEmitter.emit("statistics.connectionstats",
  10287. {
  10288. "bitrate": PeerStats.bitrate,
  10289. "packetLoss": PeerStats.packetLoss,
  10290. "bandwidth": PeerStats.bandwidth,
  10291. "resolution": resolutions,
  10292. "transport": PeerStats.transport
  10293. });
  10294. PeerStats.transport = [];
  10295. };
  10296. /**
  10297. * Stats processing logic.
  10298. */
  10299. StatsCollector.prototype.processAudioLevelReport = function ()
  10300. {
  10301. if (!this.baselineAudioLevelsReport)
  10302. {
  10303. return;
  10304. }
  10305. for (var idx in this.currentAudioLevelsReport)
  10306. {
  10307. var now = this.currentAudioLevelsReport[idx];
  10308. if (now.type != 'ssrc')
  10309. {
  10310. continue;
  10311. }
  10312. var before = this.baselineAudioLevelsReport[idx];
  10313. if (!before)
  10314. {
  10315. console.warn(getStatValue(now, 'ssrc') + ' not enough data');
  10316. continue;
  10317. }
  10318. var ssrc = getStatValue(now, 'ssrc');
  10319. var jid = APP.xmpp.getJidFromSSRC(ssrc);
  10320. if (!jid && (Date.now() - now.timestamp) < 3000)
  10321. {
  10322. console.warn("No jid for ssrc: " + ssrc);
  10323. continue;
  10324. }
  10325. var jidStats = this.jid2stats[jid];
  10326. if (!jidStats)
  10327. {
  10328. jidStats = new PeerStats();
  10329. this.jid2stats[jid] = jidStats;
  10330. }
  10331. // Audio level
  10332. var audioLevel = null;
  10333. try {
  10334. audioLevel = getStatValue(now, 'audioInputLevel');
  10335. if (!audioLevel)
  10336. audioLevel = getStatValue(now, 'audioOutputLevel');
  10337. }
  10338. catch(e) {/*not supported*/
  10339. console.warn("Audio Levels are not available in the statistics.");
  10340. clearInterval(this.audioLevelsIntervalId);
  10341. return;
  10342. }
  10343. if (audioLevel)
  10344. {
  10345. // TODO: can't find specs about what this value really is,
  10346. // but it seems to vary between 0 and around 32k.
  10347. audioLevel = audioLevel / 32767;
  10348. jidStats.setSsrcAudioLevel(ssrc, audioLevel);
  10349. if(jid != APP.xmpp.myJid())
  10350. this.eventEmitter.emit("statistics.audioLevel", jid, audioLevel);
  10351. }
  10352. }
  10353. };
  10354. },{"../../service/RTC/RTCBrowserType":88}],46:[function(require,module,exports){
  10355. /**
  10356. * Created by hristo on 8/4/14.
  10357. */
  10358. var LocalStats = require("./LocalStatsCollector.js");
  10359. var RTPStats = require("./RTPStatsCollector.js");
  10360. var EventEmitter = require("events");
  10361. var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
  10362. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  10363. var eventEmitter = new EventEmitter();
  10364. var localStats = null;
  10365. var rtpStats = null;
  10366. function stopLocal()
  10367. {
  10368. if(localStats)
  10369. {
  10370. localStats.stop();
  10371. localStats = null;
  10372. }
  10373. }
  10374. function stopRemote()
  10375. {
  10376. if(rtpStats)
  10377. {
  10378. rtpStats.stop();
  10379. eventEmitter.emit("statistics.stop");
  10380. rtpStats = null;
  10381. }
  10382. }
  10383. function startRemoteStats (peerconnection) {
  10384. if(rtpStats)
  10385. {
  10386. rtpStats.stop();
  10387. rtpStats = null;
  10388. }
  10389. rtpStats = new RTPStats(peerconnection, 200, 2000, eventEmitter);
  10390. rtpStats.start();
  10391. }
  10392. function onStreamCreated(stream)
  10393. {
  10394. if(stream.getOriginalStream().getAudioTracks().length === 0)
  10395. return;
  10396. localStats = new LocalStats(stream.getOriginalStream(), 200, statistics,
  10397. eventEmitter);
  10398. localStats.start();
  10399. }
  10400. function onDisposeConference(onUnload) {
  10401. stopRemote();
  10402. if(onUnload) {
  10403. stopLocal();
  10404. eventEmitter.removeAllListeners();
  10405. }
  10406. }
  10407. var statistics =
  10408. {
  10409. /**
  10410. * Indicates that this audio level is for local jid.
  10411. * @type {string}
  10412. */
  10413. LOCAL_JID: 'local',
  10414. addAudioLevelListener: function(listener)
  10415. {
  10416. eventEmitter.on("statistics.audioLevel", listener);
  10417. },
  10418. removeAudioLevelListener: function(listener)
  10419. {
  10420. eventEmitter.removeListener("statistics.audioLevel", listener);
  10421. },
  10422. addConnectionStatsListener: function(listener)
  10423. {
  10424. eventEmitter.on("statistics.connectionstats", listener);
  10425. },
  10426. removeConnectionStatsListener: function(listener)
  10427. {
  10428. eventEmitter.removeListener("statistics.connectionstats", listener);
  10429. },
  10430. addRemoteStatsStopListener: function(listener)
  10431. {
  10432. eventEmitter.on("statistics.stop", listener);
  10433. },
  10434. removeRemoteStatsStopListener: function(listener)
  10435. {
  10436. eventEmitter.removeListener("statistics.stop", listener);
  10437. },
  10438. stop: function () {
  10439. stopLocal();
  10440. stopRemote();
  10441. if(eventEmitter)
  10442. {
  10443. eventEmitter.removeAllListeners();
  10444. }
  10445. },
  10446. stopRemoteStatistics: function()
  10447. {
  10448. stopRemote();
  10449. },
  10450. start: function () {
  10451. APP.RTC.addStreamListener(onStreamCreated,
  10452. StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  10453. APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
  10454. APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
  10455. startRemoteStats(event.peerconnection);
  10456. });
  10457. }
  10458. };
  10459. module.exports = statistics;
  10460. },{"../../service/RTC/StreamEventTypes.js":91,"../../service/xmpp/XMPPEvents":97,"./LocalStatsCollector.js":44,"./RTPStatsCollector.js":45,"events":98}],47:[function(require,module,exports){
  10461. var i18n = require("i18next-client");
  10462. var languages = require("../../service/translation/languages");
  10463. var Settings = require("../settings/Settings");
  10464. var DEFAULT_LANG = languages.EN;
  10465. i18n.addPostProcessor("resolveAppName", function(value, key, options) {
  10466. return value.replace("__app__", interfaceConfig.APP_NAME);
  10467. });
  10468. var defaultOptions = {
  10469. detectLngQS: "lang",
  10470. useCookie: false,
  10471. fallbackLng: DEFAULT_LANG,
  10472. load: "unspecific",
  10473. resGetPath: 'lang/__ns__-__lng__.json',
  10474. ns: {
  10475. namespaces: ['main', 'languages'],
  10476. defaultNs: 'main'
  10477. },
  10478. lngWhitelist : languages.getLanguages(),
  10479. fallbackOnNull: true,
  10480. fallbackOnEmpty: true,
  10481. useDataAttrOptions: true,
  10482. defaultValueFromContent: false,
  10483. app: interfaceConfig.APP_NAME,
  10484. getAsync: false,
  10485. defaultValueFromContent: false,
  10486. customLoad: function(lng, ns, options, done) {
  10487. var resPath = "lang/__ns__-__lng__.json";
  10488. if(lng === languages.EN)
  10489. resPath = "lang/__ns__.json";
  10490. var url = i18n.functions.applyReplacement(resPath, { lng: lng, ns: ns });
  10491. i18n.functions.ajax({
  10492. url: url,
  10493. success: function(data, status, xhr) {
  10494. i18n.functions.log('loaded: ' + url);
  10495. done(null, data);
  10496. },
  10497. error : function(xhr, status, error) {
  10498. if ((status && status == 200) ||
  10499. (xhr && xhr.status && xhr.status == 200)) {
  10500. // file loaded but invalid json, stop waste time !
  10501. i18n.functions.error('There is a typo in: ' + url);
  10502. } else if ((status && status == 404) ||
  10503. (xhr && xhr.status && xhr.status == 404)) {
  10504. i18n.functions.log('Does not exist: ' + url);
  10505. } else {
  10506. var theStatus = status ? status :
  10507. ((xhr && xhr.status) ? xhr.status : null);
  10508. i18n.functions.log(theStatus + ' when loading ' + url);
  10509. }
  10510. done(error, {});
  10511. },
  10512. dataType: "json",
  10513. async : options.getAsync
  10514. });
  10515. }
  10516. // options for caching
  10517. // useLocalStorage: true,
  10518. // localStorageExpirationTime: 86400000 // in ms, default 1 week
  10519. };
  10520. function initCompleted(t)
  10521. {
  10522. $("[data-i18n]").i18n();
  10523. }
  10524. function checkForParameter() {
  10525. var query = window.location.search.substring(1);
  10526. var vars = query.split("&");
  10527. for (var i=0;i<vars.length;i++) {
  10528. var pair = vars[i].split("=");
  10529. if(pair[0] == "lang")
  10530. {
  10531. return pair[1];
  10532. }
  10533. }
  10534. return null;
  10535. }
  10536. module.exports = {
  10537. init: function (lang) {
  10538. var options = defaultOptions;
  10539. if(!lang)
  10540. {
  10541. lang = checkForParameter();
  10542. if(!lang)
  10543. {
  10544. var settings = Settings.getSettings();
  10545. if(settings)
  10546. lang = settings.language;
  10547. }
  10548. }
  10549. if(lang) {
  10550. options.lng = lang;
  10551. }
  10552. i18n.init(options, initCompleted);
  10553. },
  10554. translateString: function (key, options) {
  10555. return i18n.t(key, options);
  10556. },
  10557. setLanguage: function (lang) {
  10558. if(!lang)
  10559. lang = DEFAULT_LANG;
  10560. i18n.setLng(lang, defaultOptions, initCompleted);
  10561. },
  10562. getCurrentLanguage: function () {
  10563. return i18n.lng();
  10564. },
  10565. translateElement: function (selector) {
  10566. selector.i18n();
  10567. },
  10568. generateTranslatonHTML: function (key, options) {
  10569. var str = "<span data-i18n=\"" + key + "\"";
  10570. if(options)
  10571. {
  10572. str += " data-i18n-options=\"" + JSON.stringify(options) + "\"";
  10573. }
  10574. str += ">";
  10575. str += this.translateString(key, options);
  10576. str += "</span>";
  10577. return str;
  10578. }
  10579. };
  10580. },{"../../service/translation/languages":96,"../settings/Settings":38,"i18next-client":62}],48:[function(require,module,exports){
  10581. /* jshint -W117 */
  10582. var TraceablePeerConnection = require("./TraceablePeerConnection");
  10583. var SDPDiffer = require("./SDPDiffer");
  10584. var SDPUtil = require("./SDPUtil");
  10585. var SDP = require("./SDP");
  10586. var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
  10587. // Jingle stuff
  10588. function JingleSession(me, sid, connection, service) {
  10589. this.me = me;
  10590. this.sid = sid;
  10591. this.connection = connection;
  10592. this.initiator = null;
  10593. this.responder = null;
  10594. this.isInitiator = null;
  10595. this.peerjid = null;
  10596. this.state = null;
  10597. this.localSDP = null;
  10598. this.remoteSDP = null;
  10599. this.relayedStreams = [];
  10600. this.startTime = null;
  10601. this.stopTime = null;
  10602. this.media_constraints = null;
  10603. this.pc_constraints = null;
  10604. this.ice_config = {};
  10605. this.drip_container = [];
  10606. this.service = service;
  10607. this.usetrickle = true;
  10608. this.usepranswer = false; // early transport warmup -- mind you, this might fail. depends on webrtc issue 1718
  10609. this.usedrip = false; // dripping is sending trickle candidates not one-by-one
  10610. this.hadstuncandidate = false;
  10611. this.hadturncandidate = false;
  10612. this.lasticecandidate = false;
  10613. this.statsinterval = null;
  10614. this.reason = null;
  10615. this.addssrc = [];
  10616. this.removessrc = [];
  10617. this.pendingop = null;
  10618. this.switchstreams = false;
  10619. this.wait = true;
  10620. this.localStreamsSSRC = null;
  10621. /**
  10622. * The indicator which determines whether the (local) video has been muted
  10623. * in response to a user command in contrast to an automatic decision made
  10624. * by the application logic.
  10625. */
  10626. this.videoMuteByUser = false;
  10627. }
  10628. //TODO: this array must be removed when firefox implement multistream support
  10629. JingleSession.notReceivedSSRCs = [];
  10630. JingleSession.prototype.initiate = function (peerjid, isInitiator) {
  10631. var self = this;
  10632. if (this.state !== null) {
  10633. console.error('attempt to initiate on session ' + this.sid +
  10634. 'in state ' + this.state);
  10635. return;
  10636. }
  10637. this.isInitiator = isInitiator;
  10638. this.state = 'pending';
  10639. this.initiator = isInitiator ? this.me : peerjid;
  10640. this.responder = !isInitiator ? this.me : peerjid;
  10641. this.peerjid = peerjid;
  10642. this.hadstuncandidate = false;
  10643. this.hadturncandidate = false;
  10644. this.lasticecandidate = false;
  10645. this.peerconnection
  10646. = new TraceablePeerConnection(
  10647. this.connection.jingle.ice_config,
  10648. this.connection.jingle.pc_constraints );
  10649. this.peerconnection.onicecandidate = function (event) {
  10650. self.sendIceCandidate(event.candidate);
  10651. };
  10652. this.peerconnection.onaddstream = function (event) {
  10653. console.log("REMOTE STREAM ADDED: " + event.stream + " - " + event.stream.id);
  10654. self.remoteStreamAdded(event);
  10655. };
  10656. this.peerconnection.onremovestream = function (event) {
  10657. // Remove the stream from remoteStreams
  10658. // FIXME: remotestreamremoved.jingle not defined anywhere(unused)
  10659. $(document).trigger('remotestreamremoved.jingle', [event, self.sid]);
  10660. };
  10661. this.peerconnection.onsignalingstatechange = function (event) {
  10662. if (!(self && self.peerconnection)) return;
  10663. };
  10664. this.peerconnection.oniceconnectionstatechange = function (event) {
  10665. if (!(self && self.peerconnection)) return;
  10666. switch (self.peerconnection.iceConnectionState) {
  10667. case 'connected':
  10668. this.startTime = new Date();
  10669. break;
  10670. case 'disconnected':
  10671. this.stopTime = new Date();
  10672. break;
  10673. }
  10674. onIceConnectionStateChange(self.sid, self);
  10675. };
  10676. // add any local and relayed stream
  10677. APP.RTC.localStreams.forEach(function(stream) {
  10678. self.peerconnection.addStream(stream.getOriginalStream());
  10679. });
  10680. this.relayedStreams.forEach(function(stream) {
  10681. self.peerconnection.addStream(stream);
  10682. });
  10683. };
  10684. function onIceConnectionStateChange(sid, session) {
  10685. switch (session.peerconnection.iceConnectionState) {
  10686. case 'checking':
  10687. session.timeChecking = (new Date()).getTime();
  10688. session.firstconnect = true;
  10689. break;
  10690. case 'completed': // on caller side
  10691. case 'connected':
  10692. if (session.firstconnect) {
  10693. session.firstconnect = false;
  10694. var metadata = {};
  10695. metadata.setupTime
  10696. = (new Date()).getTime() - session.timeChecking;
  10697. session.peerconnection.getStats(function (res) {
  10698. if(res && res.result) {
  10699. res.result().forEach(function (report) {
  10700. if (report.type == 'googCandidatePair' &&
  10701. report.stat('googActiveConnection') == 'true') {
  10702. metadata.localCandidateType
  10703. = report.stat('googLocalCandidateType');
  10704. metadata.remoteCandidateType
  10705. = report.stat('googRemoteCandidateType');
  10706. // log pair as well so we can get nice pie
  10707. // charts
  10708. metadata.candidatePair
  10709. = report.stat('googLocalCandidateType') +
  10710. ';' +
  10711. report.stat('googRemoteCandidateType');
  10712. if (report.stat('googRemoteAddress').indexOf('[') === 0)
  10713. {
  10714. metadata.ipv6 = true;
  10715. }
  10716. }
  10717. });
  10718. }
  10719. });
  10720. }
  10721. break;
  10722. }
  10723. }
  10724. JingleSession.prototype.accept = function () {
  10725. var self = this;
  10726. this.state = 'active';
  10727. var pranswer = this.peerconnection.localDescription;
  10728. if (!pranswer || pranswer.type != 'pranswer') {
  10729. return;
  10730. }
  10731. console.log('going from pranswer to answer');
  10732. if (this.usetrickle) {
  10733. // remove candidates already sent from session-accept
  10734. var lines = SDPUtil.find_lines(pranswer.sdp, 'a=candidate:');
  10735. for (var i = 0; i < lines.length; i++) {
  10736. pranswer.sdp = pranswer.sdp.replace(lines[i] + '\r\n', '');
  10737. }
  10738. }
  10739. while (SDPUtil.find_line(pranswer.sdp, 'a=inactive')) {
  10740. // FIXME: change any inactive to sendrecv or whatever they were originally
  10741. pranswer.sdp = pranswer.sdp.replace('a=inactive', 'a=sendrecv');
  10742. }
  10743. pranswer = APP.simulcast.reverseTransformLocalDescription(pranswer);
  10744. var prsdp = new SDP(pranswer.sdp);
  10745. var accept = $iq({to: this.peerjid,
  10746. type: 'set'})
  10747. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10748. action: 'session-accept',
  10749. initiator: this.initiator,
  10750. responder: this.responder,
  10751. sid: this.sid });
  10752. prsdp.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder', this.localStreamsSSRC);
  10753. var sdp = this.peerconnection.localDescription.sdp;
  10754. while (SDPUtil.find_line(sdp, 'a=inactive')) {
  10755. // FIXME: change any inactive to sendrecv or whatever they were originally
  10756. sdp = sdp.replace('a=inactive', 'a=sendrecv');
  10757. }
  10758. var self = this;
  10759. this.peerconnection.setLocalDescription(new RTCSessionDescription({type: 'answer', sdp: sdp}),
  10760. function () {
  10761. //console.log('setLocalDescription success');
  10762. self.setLocalDescription();
  10763. self.connection.sendIQ(accept,
  10764. function () {
  10765. var ack = {};
  10766. ack.source = 'answer';
  10767. $(document).trigger('ack.jingle', [self.sid, ack]);
  10768. },
  10769. function (stanza) {
  10770. var error = ($(stanza).find('error').length) ? {
  10771. code: $(stanza).find('error').attr('code'),
  10772. reason: $(stanza).find('error :first')[0].tagName
  10773. }:{};
  10774. error.source = 'answer';
  10775. JingleSession.onJingleError(self.sid, error);
  10776. },
  10777. 10000);
  10778. },
  10779. function (e) {
  10780. console.error('setLocalDescription failed', e);
  10781. }
  10782. );
  10783. };
  10784. JingleSession.prototype.terminate = function (reason) {
  10785. this.state = 'ended';
  10786. this.reason = reason;
  10787. this.peerconnection.close();
  10788. if (this.statsinterval !== null) {
  10789. window.clearInterval(this.statsinterval);
  10790. this.statsinterval = null;
  10791. }
  10792. };
  10793. JingleSession.prototype.active = function () {
  10794. return this.state == 'active';
  10795. };
  10796. JingleSession.prototype.sendIceCandidate = function (candidate) {
  10797. var self = this;
  10798. if (candidate && !this.lasticecandidate) {
  10799. var ice = SDPUtil.iceparams(this.localSDP.media[candidate.sdpMLineIndex], this.localSDP.session);
  10800. var jcand = SDPUtil.candidateToJingle(candidate.candidate);
  10801. if (!(ice && jcand)) {
  10802. console.error('failed to get ice && jcand');
  10803. return;
  10804. }
  10805. ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
  10806. if (jcand.type === 'srflx') {
  10807. this.hadstuncandidate = true;
  10808. } else if (jcand.type === 'relay') {
  10809. this.hadturncandidate = true;
  10810. }
  10811. if (this.usetrickle) {
  10812. if (this.usedrip) {
  10813. if (this.drip_container.length === 0) {
  10814. // start 20ms callout
  10815. window.setTimeout(function () {
  10816. if (self.drip_container.length === 0) return;
  10817. self.sendIceCandidates(self.drip_container);
  10818. self.drip_container = [];
  10819. }, 20);
  10820. }
  10821. this.drip_container.push(candidate);
  10822. return;
  10823. } else {
  10824. self.sendIceCandidate([candidate]);
  10825. }
  10826. }
  10827. } else {
  10828. //console.log('sendIceCandidate: last candidate.');
  10829. if (!this.usetrickle) {
  10830. //console.log('should send full offer now...');
  10831. var init = $iq({to: this.peerjid,
  10832. type: 'set'})
  10833. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10834. action: this.peerconnection.localDescription.type == 'offer' ? 'session-initiate' : 'session-accept',
  10835. initiator: this.initiator,
  10836. sid: this.sid});
  10837. this.localSDP = new SDP(this.peerconnection.localDescription.sdp);
  10838. var self = this;
  10839. var sendJingle = function (ssrc) {
  10840. if(!ssrc)
  10841. ssrc = {};
  10842. self.localSDP.toJingle(init, self.initiator == self.me ? 'initiator' : 'responder', ssrc);
  10843. self.connection.sendIQ(init,
  10844. function () {
  10845. //console.log('session initiate ack');
  10846. var ack = {};
  10847. ack.source = 'offer';
  10848. $(document).trigger('ack.jingle', [self.sid, ack]);
  10849. },
  10850. function (stanza) {
  10851. self.state = 'error';
  10852. self.peerconnection.close();
  10853. var error = ($(stanza).find('error').length) ? {
  10854. code: $(stanza).find('error').attr('code'),
  10855. reason: $(stanza).find('error :first')[0].tagName,
  10856. }:{};
  10857. error.source = 'offer';
  10858. JingleSession.onJingleError(self.sid, error);
  10859. },
  10860. 10000);
  10861. }
  10862. sendJingle();
  10863. }
  10864. this.lasticecandidate = true;
  10865. console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate);
  10866. console.log('Have we encountered any relay candidates? ' + this.hadturncandidate);
  10867. if (!(this.hadstuncandidate || this.hadturncandidate) && this.peerconnection.signalingState != 'closed') {
  10868. $(document).trigger('nostuncandidates.jingle', [this.sid]);
  10869. }
  10870. }
  10871. };
  10872. JingleSession.prototype.sendIceCandidates = function (candidates) {
  10873. console.log('sendIceCandidates', candidates);
  10874. var cand = $iq({to: this.peerjid, type: 'set'})
  10875. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10876. action: 'transport-info',
  10877. initiator: this.initiator,
  10878. sid: this.sid});
  10879. for (var mid = 0; mid < this.localSDP.media.length; mid++) {
  10880. var cands = candidates.filter(function (el) { return el.sdpMLineIndex == mid; });
  10881. var mline = SDPUtil.parse_mline(this.localSDP.media[mid].split('\r\n')[0]);
  10882. if (cands.length > 0) {
  10883. var ice = SDPUtil.iceparams(this.localSDP.media[mid], this.localSDP.session);
  10884. ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
  10885. cand.c('content', {creator: this.initiator == this.me ? 'initiator' : 'responder',
  10886. name: (cands[0].sdpMid? cands[0].sdpMid : mline.media)
  10887. }).c('transport', ice);
  10888. for (var i = 0; i < cands.length; i++) {
  10889. cand.c('candidate', SDPUtil.candidateToJingle(cands[i].candidate)).up();
  10890. }
  10891. // add fingerprint
  10892. if (SDPUtil.find_line(this.localSDP.media[mid], 'a=fingerprint:', this.localSDP.session)) {
  10893. var tmp = SDPUtil.parse_fingerprint(SDPUtil.find_line(this.localSDP.media[mid], 'a=fingerprint:', this.localSDP.session));
  10894. tmp.required = true;
  10895. cand.c(
  10896. 'fingerprint',
  10897. {xmlns: 'urn:xmpp:jingle:apps:dtls:0'})
  10898. .t(tmp.fingerprint);
  10899. delete tmp.fingerprint;
  10900. cand.attrs(tmp);
  10901. cand.up();
  10902. }
  10903. cand.up(); // transport
  10904. cand.up(); // content
  10905. }
  10906. }
  10907. // might merge last-candidate notification into this, but it is called alot later. See webrtc issue #2340
  10908. //console.log('was this the last candidate', this.lasticecandidate);
  10909. this.connection.sendIQ(cand,
  10910. function () {
  10911. var ack = {};
  10912. ack.source = 'transportinfo';
  10913. $(document).trigger('ack.jingle', [this.sid, ack]);
  10914. },
  10915. function (stanza) {
  10916. var error = ($(stanza).find('error').length) ? {
  10917. code: $(stanza).find('error').attr('code'),
  10918. reason: $(stanza).find('error :first')[0].tagName,
  10919. }:{};
  10920. error.source = 'transportinfo';
  10921. JingleSession.onJingleError(this.sid, error);
  10922. },
  10923. 10000);
  10924. };
  10925. JingleSession.prototype.sendOffer = function () {
  10926. //console.log('sendOffer...');
  10927. var self = this;
  10928. this.peerconnection.createOffer(function (sdp) {
  10929. self.createdOffer(sdp);
  10930. },
  10931. function (e) {
  10932. console.error('createOffer failed', e);
  10933. },
  10934. this.media_constraints
  10935. );
  10936. };
  10937. JingleSession.prototype.createdOffer = function (sdp) {
  10938. //console.log('createdOffer', sdp);
  10939. var self = this;
  10940. this.localSDP = new SDP(sdp.sdp);
  10941. //this.localSDP.mangle();
  10942. var sendJingle = function () {
  10943. var init = $iq({to: this.peerjid,
  10944. type: 'set'})
  10945. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10946. action: 'session-initiate',
  10947. initiator: this.initiator,
  10948. sid: this.sid});
  10949. self.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder', this.localStreamsSSRC);
  10950. self.connection.sendIQ(init,
  10951. function () {
  10952. var ack = {};
  10953. ack.source = 'offer';
  10954. $(document).trigger('ack.jingle', [self.sid, ack]);
  10955. },
  10956. function (stanza) {
  10957. self.state = 'error';
  10958. self.peerconnection.close();
  10959. var error = ($(stanza).find('error').length) ? {
  10960. code: $(stanza).find('error').attr('code'),
  10961. reason: $(stanza).find('error :first')[0].tagName,
  10962. }:{};
  10963. error.source = 'offer';
  10964. JingleSession.onJingleError(self.sid, error);
  10965. },
  10966. 10000);
  10967. }
  10968. sdp.sdp = this.localSDP.raw;
  10969. this.peerconnection.setLocalDescription(sdp,
  10970. function () {
  10971. if(self.usetrickle)
  10972. {
  10973. sendJingle();
  10974. }
  10975. self.setLocalDescription();
  10976. //console.log('setLocalDescription success');
  10977. },
  10978. function (e) {
  10979. console.error('setLocalDescription failed', e);
  10980. }
  10981. );
  10982. var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
  10983. for (var i = 0; i < cands.length; i++) {
  10984. var cand = SDPUtil.parse_icecandidate(cands[i]);
  10985. if (cand.type == 'srflx') {
  10986. this.hadstuncandidate = true;
  10987. } else if (cand.type == 'relay') {
  10988. this.hadturncandidate = true;
  10989. }
  10990. }
  10991. };
  10992. JingleSession.prototype.setRemoteDescription = function (elem, desctype) {
  10993. //console.log('setting remote description... ', desctype);
  10994. this.remoteSDP = new SDP('');
  10995. this.remoteSDP.fromJingle(elem);
  10996. if (this.peerconnection.remoteDescription !== null) {
  10997. console.log('setRemoteDescription when remote description is not null, should be pranswer', this.peerconnection.remoteDescription);
  10998. if (this.peerconnection.remoteDescription.type == 'pranswer') {
  10999. var pranswer = new SDP(this.peerconnection.remoteDescription.sdp);
  11000. for (var i = 0; i < pranswer.media.length; i++) {
  11001. // make sure we have ice ufrag and pwd
  11002. if (!SDPUtil.find_line(this.remoteSDP.media[i], 'a=ice-ufrag:', this.remoteSDP.session)) {
  11003. if (SDPUtil.find_line(pranswer.media[i], 'a=ice-ufrag:', pranswer.session)) {
  11004. this.remoteSDP.media[i] += SDPUtil.find_line(pranswer.media[i], 'a=ice-ufrag:', pranswer.session) + '\r\n';
  11005. } else {
  11006. console.warn('no ice ufrag?');
  11007. }
  11008. if (SDPUtil.find_line(pranswer.media[i], 'a=ice-pwd:', pranswer.session)) {
  11009. this.remoteSDP.media[i] += SDPUtil.find_line(pranswer.media[i], 'a=ice-pwd:', pranswer.session) + '\r\n';
  11010. } else {
  11011. console.warn('no ice pwd?');
  11012. }
  11013. }
  11014. // copy over candidates
  11015. var lines = SDPUtil.find_lines(pranswer.media[i], 'a=candidate:');
  11016. for (var j = 0; j < lines.length; j++) {
  11017. this.remoteSDP.media[i] += lines[j] + '\r\n';
  11018. }
  11019. }
  11020. this.remoteSDP.raw = this.remoteSDP.session + this.remoteSDP.media.join('');
  11021. }
  11022. }
  11023. var remotedesc = new RTCSessionDescription({type: desctype, sdp: this.remoteSDP.raw});
  11024. this.peerconnection.setRemoteDescription(remotedesc,
  11025. function () {
  11026. //console.log('setRemoteDescription success');
  11027. },
  11028. function (e) {
  11029. console.error('setRemoteDescription error', e);
  11030. JingleSession.onJingleFatalError(self, e);
  11031. }
  11032. );
  11033. };
  11034. JingleSession.prototype.addIceCandidate = function (elem) {
  11035. var self = this;
  11036. if (this.peerconnection.signalingState == 'closed') {
  11037. return;
  11038. }
  11039. if (!this.peerconnection.remoteDescription && this.peerconnection.signalingState == 'have-local-offer') {
  11040. console.log('trickle ice candidate arriving before session accept...');
  11041. // create a PRANSWER for setRemoteDescription
  11042. if (!this.remoteSDP) {
  11043. var cobbled = 'v=0\r\n' +
  11044. 'o=- ' + '1923518516' + ' 2 IN IP4 0.0.0.0\r\n' +// FIXME
  11045. 's=-\r\n' +
  11046. 't=0 0\r\n';
  11047. // first, take some things from the local description
  11048. for (var i = 0; i < this.localSDP.media.length; i++) {
  11049. cobbled += SDPUtil.find_line(this.localSDP.media[i], 'm=') + '\r\n';
  11050. cobbled += SDPUtil.find_lines(this.localSDP.media[i], 'a=rtpmap:').join('\r\n') + '\r\n';
  11051. if (SDPUtil.find_line(this.localSDP.media[i], 'a=mid:')) {
  11052. cobbled += SDPUtil.find_line(this.localSDP.media[i], 'a=mid:') + '\r\n';
  11053. }
  11054. cobbled += 'a=inactive\r\n';
  11055. }
  11056. this.remoteSDP = new SDP(cobbled);
  11057. }
  11058. // then add things like ice and dtls from remote candidate
  11059. elem.each(function () {
  11060. for (var i = 0; i < self.remoteSDP.media.length; i++) {
  11061. if (SDPUtil.find_line(self.remoteSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
  11062. self.remoteSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
  11063. if (!SDPUtil.find_line(self.remoteSDP.media[i], 'a=ice-ufrag:')) {
  11064. var tmp = $(this).find('transport');
  11065. self.remoteSDP.media[i] += 'a=ice-ufrag:' + tmp.attr('ufrag') + '\r\n';
  11066. self.remoteSDP.media[i] += 'a=ice-pwd:' + tmp.attr('pwd') + '\r\n';
  11067. tmp = $(this).find('transport>fingerprint');
  11068. if (tmp.length) {
  11069. self.remoteSDP.media[i] += 'a=fingerprint:' + tmp.attr('hash') + ' ' + tmp.text() + '\r\n';
  11070. } else {
  11071. console.log('no dtls fingerprint (webrtc issue #1718?)');
  11072. self.remoteSDP.media[i] += 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:BAADBAADBAADBAADBAADBAADBAADBAADBAADBAAD\r\n';
  11073. }
  11074. break;
  11075. }
  11076. }
  11077. }
  11078. });
  11079. this.remoteSDP.raw = this.remoteSDP.session + this.remoteSDP.media.join('');
  11080. // we need a complete SDP with ice-ufrag/ice-pwd in all parts
  11081. // this makes the assumption that the PRANSWER is constructed such that the ice-ufrag is in all mediaparts
  11082. // but it could be in the session part as well. since the code above constructs this sdp this can't happen however
  11083. var iscomplete = this.remoteSDP.media.filter(function (mediapart) {
  11084. return SDPUtil.find_line(mediapart, 'a=ice-ufrag:');
  11085. }).length == this.remoteSDP.media.length;
  11086. if (iscomplete) {
  11087. console.log('setting pranswer');
  11088. try {
  11089. this.peerconnection.setRemoteDescription(new RTCSessionDescription({type: 'pranswer', sdp: this.remoteSDP.raw }),
  11090. function() {
  11091. },
  11092. function(e) {
  11093. console.log('setRemoteDescription pranswer failed', e.toString());
  11094. });
  11095. } catch (e) {
  11096. console.error('setting pranswer failed', e);
  11097. }
  11098. } else {
  11099. //console.log('not yet setting pranswer');
  11100. }
  11101. }
  11102. // operate on each content element
  11103. elem.each(function () {
  11104. // would love to deactivate this, but firefox still requires it
  11105. var idx = -1;
  11106. var i;
  11107. for (i = 0; i < self.remoteSDP.media.length; i++) {
  11108. if (SDPUtil.find_line(self.remoteSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
  11109. self.remoteSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
  11110. idx = i;
  11111. break;
  11112. }
  11113. }
  11114. if (idx == -1) { // fall back to localdescription
  11115. for (i = 0; i < self.localSDP.media.length; i++) {
  11116. if (SDPUtil.find_line(self.localSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
  11117. self.localSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
  11118. idx = i;
  11119. break;
  11120. }
  11121. }
  11122. }
  11123. var name = $(this).attr('name');
  11124. // TODO: check ice-pwd and ice-ufrag?
  11125. $(this).find('transport>candidate').each(function () {
  11126. var line, candidate;
  11127. line = SDPUtil.candidateFromJingle(this);
  11128. candidate = new RTCIceCandidate({sdpMLineIndex: idx,
  11129. sdpMid: name,
  11130. candidate: line});
  11131. try {
  11132. self.peerconnection.addIceCandidate(candidate);
  11133. } catch (e) {
  11134. console.error('addIceCandidate failed', e.toString(), line);
  11135. }
  11136. });
  11137. });
  11138. };
  11139. JingleSession.prototype.sendAnswer = function (provisional) {
  11140. //console.log('createAnswer', provisional);
  11141. var self = this;
  11142. this.peerconnection.createAnswer(
  11143. function (sdp) {
  11144. self.createdAnswer(sdp, provisional);
  11145. },
  11146. function (e) {
  11147. console.error('createAnswer failed', e);
  11148. },
  11149. this.media_constraints
  11150. );
  11151. };
  11152. JingleSession.prototype.createdAnswer = function (sdp, provisional) {
  11153. //console.log('createAnswer callback');
  11154. var self = this;
  11155. this.localSDP = new SDP(sdp.sdp);
  11156. //this.localSDP.mangle();
  11157. this.usepranswer = provisional === true;
  11158. if (this.usetrickle) {
  11159. if (this.usepranswer) {
  11160. sdp.type = 'pranswer';
  11161. for (var i = 0; i < this.localSDP.media.length; i++) {
  11162. this.localSDP.media[i] = this.localSDP.media[i].replace('a=sendrecv\r\n', 'a=inactive\r\n');
  11163. }
  11164. this.localSDP.raw = this.localSDP.session + '\r\n' + this.localSDP.media.join('');
  11165. }
  11166. }
  11167. var self = this;
  11168. var sendJingle = function (ssrcs) {
  11169. var accept = $iq({to: self.peerjid,
  11170. type: 'set'})
  11171. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  11172. action: 'session-accept',
  11173. initiator: self.initiator,
  11174. responder: self.responder,
  11175. sid: self.sid });
  11176. var publicLocalDesc = APP.simulcast.reverseTransformLocalDescription(sdp);
  11177. var publicLocalSDP = new SDP(publicLocalDesc.sdp);
  11178. publicLocalSDP.toJingle(accept, self.initiator == self.me ? 'initiator' : 'responder', ssrcs);
  11179. self.connection.sendIQ(accept,
  11180. function () {
  11181. var ack = {};
  11182. ack.source = 'answer';
  11183. $(document).trigger('ack.jingle', [self.sid, ack]);
  11184. },
  11185. function (stanza) {
  11186. var error = ($(stanza).find('error').length) ? {
  11187. code: $(stanza).find('error').attr('code'),
  11188. reason: $(stanza).find('error :first')[0].tagName,
  11189. }:{};
  11190. error.source = 'answer';
  11191. JingleSession.onJingleError(self.sid, error);
  11192. },
  11193. 10000);
  11194. }
  11195. sdp.sdp = this.localSDP.raw;
  11196. this.peerconnection.setLocalDescription(sdp,
  11197. function () {
  11198. //console.log('setLocalDescription success');
  11199. if (self.usetrickle && !self.usepranswer) {
  11200. sendJingle();
  11201. }
  11202. self.setLocalDescription();
  11203. },
  11204. function (e) {
  11205. console.error('setLocalDescription failed', e);
  11206. }
  11207. );
  11208. var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
  11209. for (var j = 0; j < cands.length; j++) {
  11210. var cand = SDPUtil.parse_icecandidate(cands[j]);
  11211. if (cand.type == 'srflx') {
  11212. this.hadstuncandidate = true;
  11213. } else if (cand.type == 'relay') {
  11214. this.hadturncandidate = true;
  11215. }
  11216. }
  11217. };
  11218. JingleSession.prototype.sendTerminate = function (reason, text) {
  11219. var self = this,
  11220. term = $iq({to: this.peerjid,
  11221. type: 'set'})
  11222. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  11223. action: 'session-terminate',
  11224. initiator: this.initiator,
  11225. sid: this.sid})
  11226. .c('reason')
  11227. .c(reason || 'success');
  11228. if (text) {
  11229. term.up().c('text').t(text);
  11230. }
  11231. this.connection.sendIQ(term,
  11232. function () {
  11233. self.peerconnection.close();
  11234. self.peerconnection = null;
  11235. self.terminate();
  11236. var ack = {};
  11237. ack.source = 'terminate';
  11238. $(document).trigger('ack.jingle', [self.sid, ack]);
  11239. },
  11240. function (stanza) {
  11241. var error = ($(stanza).find('error').length) ? {
  11242. code: $(stanza).find('error').attr('code'),
  11243. reason: $(stanza).find('error :first')[0].tagName,
  11244. }:{};
  11245. $(document).trigger('ack.jingle', [self.sid, error]);
  11246. },
  11247. 10000);
  11248. if (this.statsinterval !== null) {
  11249. window.clearInterval(this.statsinterval);
  11250. this.statsinterval = null;
  11251. }
  11252. };
  11253. JingleSession.prototype.addSource = function (elem, fromJid) {
  11254. var self = this;
  11255. // FIXME: dirty waiting
  11256. if (!this.peerconnection.localDescription)
  11257. {
  11258. console.warn("addSource - localDescription not ready yet")
  11259. setTimeout(function()
  11260. {
  11261. self.addSource(elem, fromJid);
  11262. },
  11263. 200
  11264. );
  11265. return;
  11266. }
  11267. console.log('addssrc', new Date().getTime());
  11268. console.log('ice', this.peerconnection.iceConnectionState);
  11269. var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
  11270. var mySdp = new SDP(this.peerconnection.localDescription.sdp);
  11271. $(elem).each(function (idx, content) {
  11272. var name = $(content).attr('name');
  11273. var lines = '';
  11274. $(content).find('ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
  11275. var semantics = this.getAttribute('semantics');
  11276. var ssrcs = $(this).find('>source').map(function () {
  11277. return this.getAttribute('ssrc');
  11278. }).get();
  11279. if (ssrcs.length != 0) {
  11280. lines += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
  11281. }
  11282. });
  11283. var tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
  11284. tmp.each(function () {
  11285. var ssrc = $(this).attr('ssrc');
  11286. if(mySdp.containsSSRC(ssrc)){
  11287. /**
  11288. * This happens when multiple participants change their streams at the same time and
  11289. * ColibriFocus.modifySources have to wait for stable state. In the meantime multiple
  11290. * addssrc are scheduled for update IQ. See
  11291. */
  11292. console.warn("Got add stream request for my own ssrc: "+ssrc);
  11293. return;
  11294. }
  11295. $(this).find('>parameter').each(function () {
  11296. lines += 'a=ssrc:' + ssrc + ' ' + $(this).attr('name');
  11297. if ($(this).attr('value') && $(this).attr('value').length)
  11298. lines += ':' + $(this).attr('value');
  11299. lines += '\r\n';
  11300. });
  11301. });
  11302. sdp.media.forEach(function(media, idx) {
  11303. if (!SDPUtil.find_line(media, 'a=mid:' + name))
  11304. return;
  11305. sdp.media[idx] += lines;
  11306. if (!self.addssrc[idx]) self.addssrc[idx] = '';
  11307. self.addssrc[idx] += lines;
  11308. });
  11309. sdp.raw = sdp.session + sdp.media.join('');
  11310. });
  11311. this.modifySources();
  11312. };
  11313. JingleSession.prototype.removeSource = function (elem, fromJid) {
  11314. var self = this;
  11315. // FIXME: dirty waiting
  11316. if (!this.peerconnection.localDescription)
  11317. {
  11318. console.warn("removeSource - localDescription not ready yet")
  11319. setTimeout(function()
  11320. {
  11321. self.removeSource(elem, fromJid);
  11322. },
  11323. 200
  11324. );
  11325. return;
  11326. }
  11327. console.log('removessrc', new Date().getTime());
  11328. console.log('ice', this.peerconnection.iceConnectionState);
  11329. var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
  11330. var mySdp = new SDP(this.peerconnection.localDescription.sdp);
  11331. $(elem).each(function (idx, content) {
  11332. var name = $(content).attr('name');
  11333. var lines = '';
  11334. $(content).find('ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
  11335. var semantics = this.getAttribute('semantics');
  11336. var ssrcs = $(this).find('>source').map(function () {
  11337. return this.getAttribute('ssrc');
  11338. }).get();
  11339. if (ssrcs.length != 0) {
  11340. lines += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
  11341. }
  11342. });
  11343. var tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
  11344. tmp.each(function () {
  11345. var ssrc = $(this).attr('ssrc');
  11346. // This should never happen, but can be useful for bug detection
  11347. if(mySdp.containsSSRC(ssrc)){
  11348. console.error("Got remove stream request for my own ssrc: "+ssrc);
  11349. return;
  11350. }
  11351. $(this).find('>parameter').each(function () {
  11352. lines += 'a=ssrc:' + ssrc + ' ' + $(this).attr('name');
  11353. if ($(this).attr('value') && $(this).attr('value').length)
  11354. lines += ':' + $(this).attr('value');
  11355. lines += '\r\n';
  11356. });
  11357. });
  11358. sdp.media.forEach(function(media, idx) {
  11359. if (!SDPUtil.find_line(media, 'a=mid:' + name))
  11360. return;
  11361. sdp.media[idx] += lines;
  11362. if (!self.removessrc[idx]) self.removessrc[idx] = '';
  11363. self.removessrc[idx] += lines;
  11364. });
  11365. sdp.raw = sdp.session + sdp.media.join('');
  11366. });
  11367. this.modifySources();
  11368. };
  11369. JingleSession.prototype.modifySources = function (successCallback) {
  11370. var self = this;
  11371. if (this.peerconnection.signalingState == 'closed') return;
  11372. if (!(this.addssrc.length || this.removessrc.length || this.pendingop !== null || this.switchstreams)){
  11373. // There is nothing to do since scheduled job might have been executed by another succeeding call
  11374. this.setLocalDescription();
  11375. if(successCallback){
  11376. successCallback();
  11377. }
  11378. return;
  11379. }
  11380. // FIXME: this is a big hack
  11381. // https://code.google.com/p/webrtc/issues/detail?id=2688
  11382. // ^ has been fixed.
  11383. if (!(this.peerconnection.signalingState == 'stable' && this.peerconnection.iceConnectionState == 'connected')) {
  11384. console.warn('modifySources not yet', this.peerconnection.signalingState, this.peerconnection.iceConnectionState);
  11385. this.wait = true;
  11386. window.setTimeout(function() { self.modifySources(successCallback); }, 250);
  11387. return;
  11388. }
  11389. if (this.wait) {
  11390. window.setTimeout(function() { self.modifySources(successCallback); }, 2500);
  11391. this.wait = false;
  11392. return;
  11393. }
  11394. // Reset switch streams flag
  11395. this.switchstreams = false;
  11396. var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
  11397. // add sources
  11398. this.addssrc.forEach(function(lines, idx) {
  11399. sdp.media[idx] += lines;
  11400. });
  11401. this.addssrc = [];
  11402. // remove sources
  11403. this.removessrc.forEach(function(lines, idx) {
  11404. lines = lines.split('\r\n');
  11405. lines.pop(); // remove empty last element;
  11406. lines.forEach(function(line) {
  11407. sdp.media[idx] = sdp.media[idx].replace(line + '\r\n', '');
  11408. });
  11409. });
  11410. this.removessrc = [];
  11411. // FIXME:
  11412. // this was a hack for the situation when only one peer exists
  11413. // in the conference.
  11414. // check if still required and remove
  11415. if (sdp.media[0])
  11416. sdp.media[0] = sdp.media[0].replace('a=recvonly', 'a=sendrecv');
  11417. if (sdp.media[1])
  11418. sdp.media[1] = sdp.media[1].replace('a=recvonly', 'a=sendrecv');
  11419. sdp.raw = sdp.session + sdp.media.join('');
  11420. this.peerconnection.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp.raw}),
  11421. function() {
  11422. if(self.signalingState == 'closed') {
  11423. console.error("createAnswer attempt on closed state");
  11424. return;
  11425. }
  11426. self.peerconnection.createAnswer(
  11427. function(modifiedAnswer) {
  11428. // change video direction, see https://github.com/jitsi/jitmeet/issues/41
  11429. if (self.pendingop !== null) {
  11430. var sdp = new SDP(modifiedAnswer.sdp);
  11431. if (sdp.media.length > 1) {
  11432. switch(self.pendingop) {
  11433. case 'mute':
  11434. sdp.media[1] = sdp.media[1].replace('a=sendrecv', 'a=recvonly');
  11435. break;
  11436. case 'unmute':
  11437. sdp.media[1] = sdp.media[1].replace('a=recvonly', 'a=sendrecv');
  11438. break;
  11439. }
  11440. sdp.raw = sdp.session + sdp.media.join('');
  11441. modifiedAnswer.sdp = sdp.raw;
  11442. }
  11443. self.pendingop = null;
  11444. }
  11445. // FIXME: pushing down an answer while ice connection state
  11446. // is still checking is bad...
  11447. //console.log(self.peerconnection.iceConnectionState);
  11448. // trying to work around another chrome bug
  11449. //modifiedAnswer.sdp = modifiedAnswer.sdp.replace(/a=setup:active/g, 'a=setup:actpass');
  11450. self.peerconnection.setLocalDescription(modifiedAnswer,
  11451. function() {
  11452. //console.log('modified setLocalDescription ok');
  11453. self.setLocalDescription();
  11454. if(successCallback){
  11455. successCallback();
  11456. }
  11457. },
  11458. function(error) {
  11459. console.error('modified setLocalDescription failed', error);
  11460. }
  11461. );
  11462. },
  11463. function(error) {
  11464. console.error('modified answer failed', error);
  11465. }
  11466. );
  11467. },
  11468. function(error) {
  11469. console.error('modify failed', error);
  11470. }
  11471. );
  11472. };
  11473. /**
  11474. * Switches video streams.
  11475. * @param new_stream new stream that will be used as video of this session.
  11476. * @param oldStream old video stream of this session.
  11477. * @param success_callback callback executed after successful stream switch.
  11478. */
  11479. JingleSession.prototype.switchStreams = function (new_stream, oldStream, success_callback) {
  11480. var self = this;
  11481. // Remember SDP to figure out added/removed SSRCs
  11482. var oldSdp = null;
  11483. if(self.peerconnection) {
  11484. if(self.peerconnection.localDescription) {
  11485. oldSdp = new SDP(self.peerconnection.localDescription.sdp);
  11486. }
  11487. self.peerconnection.removeStream(oldStream, true);
  11488. if(new_stream)
  11489. self.peerconnection.addStream(new_stream);
  11490. }
  11491. APP.RTC.switchVideoStreams(new_stream, oldStream);
  11492. // Conference is not active
  11493. if(!oldSdp || !self.peerconnection) {
  11494. success_callback();
  11495. return;
  11496. }
  11497. self.switchstreams = true;
  11498. self.modifySources(function() {
  11499. console.log('modify sources done');
  11500. success_callback();
  11501. var newSdp = new SDP(self.peerconnection.localDescription.sdp);
  11502. console.log("SDPs", oldSdp, newSdp);
  11503. self.notifyMySSRCUpdate(oldSdp, newSdp);
  11504. });
  11505. };
  11506. /**
  11507. * Figures out added/removed ssrcs and send update IQs.
  11508. * @param old_sdp SDP object for old description.
  11509. * @param new_sdp SDP object for new description.
  11510. */
  11511. JingleSession.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
  11512. if (!(this.peerconnection.signalingState == 'stable' &&
  11513. this.peerconnection.iceConnectionState == 'connected')){
  11514. console.log("Too early to send updates");
  11515. return;
  11516. }
  11517. // send source-remove IQ.
  11518. sdpDiffer = new SDPDiffer(new_sdp, old_sdp);
  11519. var remove = $iq({to: this.peerjid, type: 'set'})
  11520. .c('jingle', {
  11521. xmlns: 'urn:xmpp:jingle:1',
  11522. action: 'source-remove',
  11523. initiator: this.initiator,
  11524. sid: this.sid
  11525. }
  11526. );
  11527. var removed = sdpDiffer.toJingle(remove);
  11528. if (removed) {
  11529. this.connection.sendIQ(remove,
  11530. function (res) {
  11531. console.info('got remove result', res);
  11532. },
  11533. function (err) {
  11534. console.error('got remove error', err);
  11535. }
  11536. );
  11537. } else {
  11538. console.log('removal not necessary');
  11539. }
  11540. // send source-add IQ.
  11541. var sdpDiffer = new SDPDiffer(old_sdp, new_sdp);
  11542. var add = $iq({to: this.peerjid, type: 'set'})
  11543. .c('jingle', {
  11544. xmlns: 'urn:xmpp:jingle:1',
  11545. action: 'source-add',
  11546. initiator: this.initiator,
  11547. sid: this.sid
  11548. }
  11549. );
  11550. var added = sdpDiffer.toJingle(add);
  11551. if (added) {
  11552. this.connection.sendIQ(add,
  11553. function (res) {
  11554. console.info('got add result', res);
  11555. },
  11556. function (err) {
  11557. console.error('got add error', err);
  11558. }
  11559. );
  11560. } else {
  11561. console.log('addition not necessary');
  11562. }
  11563. };
  11564. /**
  11565. * Mutes/unmutes the (local) video i.e. enables/disables all video tracks.
  11566. *
  11567. * @param mute <tt>true</tt> to mute the (local) video i.e. to disable all video
  11568. * tracks; otherwise, <tt>false</tt>
  11569. * @param callback a function to be invoked with <tt>mute</tt> after all video
  11570. * tracks have been enabled/disabled. The function may, optionally, return
  11571. * another function which is to be invoked after the whole mute/unmute operation
  11572. * has completed successfully.
  11573. * @param options an object which specifies optional arguments such as the
  11574. * <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
  11575. * specifies whether the method was initiated in response to a user command (in
  11576. * contrast to an automatic decision made by the application logic)
  11577. */
  11578. JingleSession.prototype.setVideoMute = function (mute, callback, options) {
  11579. var byUser;
  11580. if (options) {
  11581. byUser = options.byUser;
  11582. if (typeof byUser === 'undefined') {
  11583. byUser = true;
  11584. }
  11585. } else {
  11586. byUser = true;
  11587. }
  11588. // The user's command to mute the (local) video takes precedence over any
  11589. // automatic decision made by the application logic.
  11590. if (byUser) {
  11591. this.videoMuteByUser = mute;
  11592. } else if (this.videoMuteByUser) {
  11593. return;
  11594. }
  11595. this.hardMuteVideo(mute);
  11596. this.modifySources(callback(mute));
  11597. };
  11598. JingleSession.prototype.hardMuteVideo = function (muted) {
  11599. this.pendingop = muted ? 'mute' : 'unmute';
  11600. };
  11601. JingleSession.prototype.sendMute = function (muted, content) {
  11602. var info = $iq({to: this.peerjid,
  11603. type: 'set'})
  11604. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  11605. action: 'session-info',
  11606. initiator: this.initiator,
  11607. sid: this.sid });
  11608. info.c(muted ? 'mute' : 'unmute', {xmlns: 'urn:xmpp:jingle:apps:rtp:info:1'});
  11609. info.attrs({'creator': this.me == this.initiator ? 'creator' : 'responder'});
  11610. if (content) {
  11611. info.attrs({'name': content});
  11612. }
  11613. this.connection.send(info);
  11614. };
  11615. JingleSession.prototype.sendRinging = function () {
  11616. var info = $iq({to: this.peerjid,
  11617. type: 'set'})
  11618. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  11619. action: 'session-info',
  11620. initiator: this.initiator,
  11621. sid: this.sid });
  11622. info.c('ringing', {xmlns: 'urn:xmpp:jingle:apps:rtp:info:1'});
  11623. this.connection.send(info);
  11624. };
  11625. JingleSession.prototype.getStats = function (interval) {
  11626. var self = this;
  11627. var recv = {audio: 0, video: 0};
  11628. var lost = {audio: 0, video: 0};
  11629. var lastrecv = {audio: 0, video: 0};
  11630. var lastlost = {audio: 0, video: 0};
  11631. var loss = {audio: 0, video: 0};
  11632. var delta = {audio: 0, video: 0};
  11633. this.statsinterval = window.setInterval(function () {
  11634. if (self && self.peerconnection && self.peerconnection.getStats) {
  11635. self.peerconnection.getStats(function (stats) {
  11636. var results = stats.result();
  11637. // TODO: there are so much statistics you can get from this..
  11638. for (var i = 0; i < results.length; ++i) {
  11639. if (results[i].type == 'ssrc') {
  11640. var packetsrecv = results[i].stat('packetsReceived');
  11641. var packetslost = results[i].stat('packetsLost');
  11642. if (packetsrecv && packetslost) {
  11643. packetsrecv = parseInt(packetsrecv, 10);
  11644. packetslost = parseInt(packetslost, 10);
  11645. if (results[i].stat('googFrameRateReceived')) {
  11646. lastlost.video = lost.video;
  11647. lastrecv.video = recv.video;
  11648. recv.video = packetsrecv;
  11649. lost.video = packetslost;
  11650. } else {
  11651. lastlost.audio = lost.audio;
  11652. lastrecv.audio = recv.audio;
  11653. recv.audio = packetsrecv;
  11654. lost.audio = packetslost;
  11655. }
  11656. }
  11657. }
  11658. }
  11659. delta.audio = recv.audio - lastrecv.audio;
  11660. delta.video = recv.video - lastrecv.video;
  11661. loss.audio = (delta.audio > 0) ? Math.ceil(100 * (lost.audio - lastlost.audio) / delta.audio) : 0;
  11662. loss.video = (delta.video > 0) ? Math.ceil(100 * (lost.video - lastlost.video) / delta.video) : 0;
  11663. $(document).trigger('packetloss.jingle', [self.sid, loss]);
  11664. });
  11665. }
  11666. }, interval || 3000);
  11667. return this.statsinterval;
  11668. };
  11669. JingleSession.onJingleError = function (session, error)
  11670. {
  11671. console.error("Jingle error", error);
  11672. }
  11673. JingleSession.onJingleFatalError = function (session, error)
  11674. {
  11675. this.service.sessionTerminated = true;
  11676. this.connection.emuc.doLeave();
  11677. APP.UI.messageHandler.showError("dialog.sorry",
  11678. "dialog.internalError");
  11679. }
  11680. JingleSession.prototype.setLocalDescription = function () {
  11681. // put our ssrcs into presence so other clients can identify our stream
  11682. var newssrcs = [];
  11683. var media = APP.simulcast.parseMedia(this.peerconnection.localDescription);
  11684. media.forEach(function (media) {
  11685. if(Object.keys(media.sources).length > 0) {
  11686. // TODO(gp) maybe exclude FID streams?
  11687. Object.keys(media.sources).forEach(function (ssrc) {
  11688. newssrcs.push({
  11689. 'ssrc': ssrc,
  11690. 'type': media.type,
  11691. 'direction': media.direction
  11692. });
  11693. });
  11694. }
  11695. else if(this.localStreamsSSRC && this.localStreamsSSRC[media.type])
  11696. {
  11697. newssrcs.push({
  11698. 'ssrc': this.localStreamsSSRC[media.type],
  11699. 'type': media.type,
  11700. 'direction': media.direction
  11701. });
  11702. }
  11703. });
  11704. console.log('new ssrcs', newssrcs);
  11705. // Have to clear presence map to get rid of removed streams
  11706. this.connection.emuc.clearPresenceMedia();
  11707. if (newssrcs.length > 0) {
  11708. for (var i = 1; i <= newssrcs.length; i ++) {
  11709. // Change video type to screen
  11710. if (newssrcs[i-1].type === 'video' && APP.desktopsharing.isUsingScreenStream()) {
  11711. newssrcs[i-1].type = 'screen';
  11712. }
  11713. this.connection.emuc.addMediaToPresence(i,
  11714. newssrcs[i-1].type, newssrcs[i-1].ssrc, newssrcs[i-1].direction);
  11715. }
  11716. this.connection.emuc.sendPresence();
  11717. }
  11718. }
  11719. // an attempt to work around https://github.com/jitsi/jitmeet/issues/32
  11720. function sendKeyframe(pc) {
  11721. console.log('sendkeyframe', pc.iceConnectionState);
  11722. if (pc.iceConnectionState !== 'connected') return; // safe...
  11723. pc.setRemoteDescription(
  11724. pc.remoteDescription,
  11725. function () {
  11726. pc.createAnswer(
  11727. function (modifiedAnswer) {
  11728. pc.setLocalDescription(
  11729. modifiedAnswer,
  11730. function () {
  11731. // noop
  11732. },
  11733. function (error) {
  11734. console.log('triggerKeyframe setLocalDescription failed', error);
  11735. APP.UI.messageHandler.showError();
  11736. }
  11737. );
  11738. },
  11739. function (error) {
  11740. console.log('triggerKeyframe createAnswer failed', error);
  11741. APP.UI.messageHandler.showError();
  11742. }
  11743. );
  11744. },
  11745. function (error) {
  11746. console.log('triggerKeyframe setRemoteDescription failed', error);
  11747. APP.UI.messageHandler.showError();
  11748. }
  11749. );
  11750. }
  11751. JingleSession.prototype.remoteStreamAdded = function (data, times) {
  11752. var self = this;
  11753. var thessrc;
  11754. var ssrc2jid = this.connection.emuc.ssrc2jid;
  11755. // look up an associated JID for a stream id
  11756. if (data.stream.id && data.stream.id.indexOf('mixedmslabel') === -1) {
  11757. // look only at a=ssrc: and _not_ at a=ssrc-group: lines
  11758. var ssrclines
  11759. = SDPUtil.find_lines(this.peerconnection.remoteDescription.sdp, 'a=ssrc:');
  11760. ssrclines = ssrclines.filter(function (line) {
  11761. // NOTE(gp) previously we filtered on the mslabel, but that property
  11762. // is not always present.
  11763. // return line.indexOf('mslabel:' + data.stream.label) !== -1;
  11764. return ((line.indexOf('msid:' + data.stream.id) !== -1));
  11765. });
  11766. if (ssrclines.length) {
  11767. thessrc = ssrclines[0].substring(7).split(' ')[0];
  11768. // We signal our streams (through Jingle to the focus) before we set
  11769. // our presence (through which peers associate remote streams to
  11770. // jids). So, it might arrive that a remote stream is added but
  11771. // ssrc2jid is not yet updated and thus data.peerjid cannot be
  11772. // successfully set. Here we wait for up to a second for the
  11773. // presence to arrive.
  11774. if (!ssrc2jid[thessrc]) {
  11775. if (typeof times === 'undefined')
  11776. {
  11777. times = 0;
  11778. }
  11779. if (times > 10)
  11780. {
  11781. console.warning('Waiting for jid timed out', thessrc);
  11782. }
  11783. else
  11784. {
  11785. setTimeout(function(d) {
  11786. return function() {
  11787. self.remoteStreamAdded(d, times++);
  11788. }
  11789. }(data), 250);
  11790. }
  11791. return;
  11792. }
  11793. // ok to overwrite the one from focus? might save work in colibri.js
  11794. console.log('associated jid', ssrc2jid[thessrc], data.peerjid);
  11795. if (ssrc2jid[thessrc]) {
  11796. data.peerjid = ssrc2jid[thessrc];
  11797. }
  11798. }
  11799. }
  11800. APP.RTC.createRemoteStream(data, this.sid, thessrc);
  11801. var isVideo = data.stream.getVideoTracks().length > 0;
  11802. // an attempt to work around https://github.com/jitsi/jitmeet/issues/32
  11803. if (isVideo &&
  11804. data.peerjid && this.peerjid === data.peerjid &&
  11805. data.stream.getVideoTracks().length === 0 &&
  11806. APP.RTC.localVideo.getTracks().length > 0) {
  11807. window.setTimeout(function () {
  11808. sendKeyframe(self.peerconnection);
  11809. }, 3000);
  11810. }
  11811. }
  11812. module.exports = JingleSession;
  11813. },{"../../service/RTC/RTCBrowserType":88,"./SDP":49,"./SDPDiffer":50,"./SDPUtil":51,"./TraceablePeerConnection":52}],49:[function(require,module,exports){
  11814. /* jshint -W117 */
  11815. var SDPUtil = require("./SDPUtil");
  11816. // SDP STUFF
  11817. function SDP(sdp) {
  11818. this.media = sdp.split('\r\nm=');
  11819. for (var i = 1; i < this.media.length; i++) {
  11820. this.media[i] = 'm=' + this.media[i];
  11821. if (i != this.media.length - 1) {
  11822. this.media[i] += '\r\n';
  11823. }
  11824. }
  11825. this.session = this.media.shift() + '\r\n';
  11826. this.raw = this.session + this.media.join('');
  11827. }
  11828. /**
  11829. * Returns map of MediaChannel mapped per channel idx.
  11830. */
  11831. SDP.prototype.getMediaSsrcMap = function() {
  11832. var self = this;
  11833. var media_ssrcs = {};
  11834. var tmp;
  11835. for (var mediaindex = 0; mediaindex < self.media.length; mediaindex++) {
  11836. tmp = SDPUtil.find_lines(self.media[mediaindex], 'a=ssrc:');
  11837. var mid = SDPUtil.parse_mid(SDPUtil.find_line(self.media[mediaindex], 'a=mid:'));
  11838. var media = {
  11839. mediaindex: mediaindex,
  11840. mid: mid,
  11841. ssrcs: {},
  11842. ssrcGroups: []
  11843. };
  11844. media_ssrcs[mediaindex] = media;
  11845. tmp.forEach(function (line) {
  11846. var linessrc = line.substring(7).split(' ')[0];
  11847. // allocate new ChannelSsrc
  11848. if(!media.ssrcs[linessrc]) {
  11849. media.ssrcs[linessrc] = {
  11850. ssrc: linessrc,
  11851. lines: []
  11852. };
  11853. }
  11854. media.ssrcs[linessrc].lines.push(line);
  11855. });
  11856. tmp = SDPUtil.find_lines(self.media[mediaindex], 'a=ssrc-group:');
  11857. tmp.forEach(function(line){
  11858. var semantics = line.substr(0, idx).substr(13);
  11859. var ssrcs = line.substr(14 + semantics.length).split(' ');
  11860. if (ssrcs.length != 0) {
  11861. media.ssrcGroups.push({
  11862. semantics: semantics,
  11863. ssrcs: ssrcs
  11864. });
  11865. }
  11866. });
  11867. }
  11868. return media_ssrcs;
  11869. };
  11870. /**
  11871. * Returns <tt>true</tt> if this SDP contains given SSRC.
  11872. * @param ssrc the ssrc to check.
  11873. * @returns {boolean} <tt>true</tt> if this SDP contains given SSRC.
  11874. */
  11875. SDP.prototype.containsSSRC = function(ssrc) {
  11876. var medias = this.getMediaSsrcMap();
  11877. var contains = false;
  11878. Object.keys(medias).forEach(function(mediaindex){
  11879. var media = medias[mediaindex];
  11880. //console.log("Check", channel, ssrc);
  11881. if(Object.keys(media.ssrcs).indexOf(ssrc) != -1){
  11882. contains = true;
  11883. }
  11884. });
  11885. return contains;
  11886. };
  11887. // remove iSAC and CN from SDP
  11888. SDP.prototype.mangle = function () {
  11889. var i, j, mline, lines, rtpmap, newdesc;
  11890. for (i = 0; i < this.media.length; i++) {
  11891. lines = this.media[i].split('\r\n');
  11892. lines.pop(); // remove empty last element
  11893. mline = SDPUtil.parse_mline(lines.shift());
  11894. if (mline.media != 'audio')
  11895. continue;
  11896. newdesc = '';
  11897. mline.fmt.length = 0;
  11898. for (j = 0; j < lines.length; j++) {
  11899. if (lines[j].substr(0, 9) == 'a=rtpmap:') {
  11900. rtpmap = SDPUtil.parse_rtpmap(lines[j]);
  11901. if (rtpmap.name == 'CN' || rtpmap.name == 'ISAC')
  11902. continue;
  11903. mline.fmt.push(rtpmap.id);
  11904. newdesc += lines[j] + '\r\n';
  11905. } else {
  11906. newdesc += lines[j] + '\r\n';
  11907. }
  11908. }
  11909. this.media[i] = SDPUtil.build_mline(mline) + '\r\n';
  11910. this.media[i] += newdesc;
  11911. }
  11912. this.raw = this.session + this.media.join('');
  11913. };
  11914. // remove lines matching prefix from session section
  11915. SDP.prototype.removeSessionLines = function(prefix) {
  11916. var self = this;
  11917. var lines = SDPUtil.find_lines(this.session, prefix);
  11918. lines.forEach(function(line) {
  11919. self.session = self.session.replace(line + '\r\n', '');
  11920. });
  11921. this.raw = this.session + this.media.join('');
  11922. return lines;
  11923. }
  11924. // remove lines matching prefix from a media section specified by mediaindex
  11925. // TODO: non-numeric mediaindex could match mid
  11926. SDP.prototype.removeMediaLines = function(mediaindex, prefix) {
  11927. var self = this;
  11928. var lines = SDPUtil.find_lines(this.media[mediaindex], prefix);
  11929. lines.forEach(function(line) {
  11930. self.media[mediaindex] = self.media[mediaindex].replace(line + '\r\n', '');
  11931. });
  11932. this.raw = this.session + this.media.join('');
  11933. return lines;
  11934. }
  11935. // add content's to a jingle element
  11936. SDP.prototype.toJingle = function (elem, thecreator, ssrcs) {
  11937. // console.log("SSRC" + ssrcs["audio"] + " - " + ssrcs["video"]);
  11938. var i, j, k, mline, ssrc, rtpmap, tmp, line, lines;
  11939. var self = this;
  11940. // new bundle plan
  11941. if (SDPUtil.find_line(this.session, 'a=group:')) {
  11942. lines = SDPUtil.find_lines(this.session, 'a=group:');
  11943. for (i = 0; i < lines.length; i++) {
  11944. tmp = lines[i].split(' ');
  11945. var semantics = tmp.shift().substr(8);
  11946. elem.c('group', {xmlns: 'urn:xmpp:jingle:apps:grouping:0', semantics:semantics});
  11947. for (j = 0; j < tmp.length; j++) {
  11948. elem.c('content', {name: tmp[j]}).up();
  11949. }
  11950. elem.up();
  11951. }
  11952. }
  11953. for (i = 0; i < this.media.length; i++) {
  11954. mline = SDPUtil.parse_mline(this.media[i].split('\r\n')[0]);
  11955. if (!(mline.media === 'audio' ||
  11956. mline.media === 'video' ||
  11957. mline.media === 'application'))
  11958. {
  11959. continue;
  11960. }
  11961. if (SDPUtil.find_line(this.media[i], 'a=ssrc:')) {
  11962. ssrc = SDPUtil.find_line(this.media[i], 'a=ssrc:').substring(7).split(' ')[0]; // take the first
  11963. } else {
  11964. if(ssrcs && ssrcs[mline.media])
  11965. {
  11966. ssrc = ssrcs[mline.media];
  11967. }
  11968. else
  11969. ssrc = false;
  11970. }
  11971. elem.c('content', {creator: thecreator, name: mline.media});
  11972. if (SDPUtil.find_line(this.media[i], 'a=mid:')) {
  11973. // prefer identifier from a=mid if present
  11974. var mid = SDPUtil.parse_mid(SDPUtil.find_line(this.media[i], 'a=mid:'));
  11975. elem.attrs({ name: mid });
  11976. }
  11977. if (SDPUtil.find_line(this.media[i], 'a=rtpmap:').length)
  11978. {
  11979. elem.c('description',
  11980. {xmlns: 'urn:xmpp:jingle:apps:rtp:1',
  11981. media: mline.media });
  11982. if (ssrc) {
  11983. elem.attrs({ssrc: ssrc});
  11984. }
  11985. for (j = 0; j < mline.fmt.length; j++) {
  11986. rtpmap = SDPUtil.find_line(this.media[i], 'a=rtpmap:' + mline.fmt[j]);
  11987. elem.c('payload-type', SDPUtil.parse_rtpmap(rtpmap));
  11988. // put any 'a=fmtp:' + mline.fmt[j] lines into <param name=foo value=bar/>
  11989. if (SDPUtil.find_line(this.media[i], 'a=fmtp:' + mline.fmt[j])) {
  11990. tmp = SDPUtil.parse_fmtp(SDPUtil.find_line(this.media[i], 'a=fmtp:' + mline.fmt[j]));
  11991. for (k = 0; k < tmp.length; k++) {
  11992. elem.c('parameter', tmp[k]).up();
  11993. }
  11994. }
  11995. this.RtcpFbToJingle(i, elem, mline.fmt[j]); // XEP-0293 -- map a=rtcp-fb
  11996. elem.up();
  11997. }
  11998. if (SDPUtil.find_line(this.media[i], 'a=crypto:', this.session)) {
  11999. elem.c('encryption', {required: 1});
  12000. var crypto = SDPUtil.find_lines(this.media[i], 'a=crypto:', this.session);
  12001. crypto.forEach(function(line) {
  12002. elem.c('crypto', SDPUtil.parse_crypto(line)).up();
  12003. });
  12004. elem.up(); // end of encryption
  12005. }
  12006. if (ssrc) {
  12007. // new style mapping
  12008. elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  12009. // FIXME: group by ssrc and support multiple different ssrcs
  12010. var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:');
  12011. if(ssrclines.length > 0) {
  12012. ssrclines.forEach(function (line) {
  12013. idx = line.indexOf(' ');
  12014. var linessrc = line.substr(0, idx).substr(7);
  12015. if (linessrc != ssrc) {
  12016. elem.up();
  12017. ssrc = linessrc;
  12018. elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  12019. }
  12020. var kv = line.substr(idx + 1);
  12021. elem.c('parameter');
  12022. if (kv.indexOf(':') == -1) {
  12023. elem.attrs({ name: kv });
  12024. } else {
  12025. elem.attrs({ name: kv.split(':', 2)[0] });
  12026. elem.attrs({ value: kv.split(':', 2)[1] });
  12027. }
  12028. elem.up();
  12029. });
  12030. elem.up();
  12031. }
  12032. else
  12033. {
  12034. elem.up();
  12035. elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  12036. elem.c('parameter');
  12037. elem.attrs({name: "cname", value:Math.random().toString(36).substring(7)});
  12038. elem.up();
  12039. var msid = null;
  12040. if(mline.media == "audio")
  12041. {
  12042. msid = APP.RTC.localAudio.getId();
  12043. }
  12044. else
  12045. {
  12046. msid = APP.RTC.localVideo.getId();
  12047. }
  12048. if(msid != null)
  12049. {
  12050. msid = msid.replace(/[\{,\}]/g,"");
  12051. elem.c('parameter');
  12052. elem.attrs({name: "msid", value:msid});
  12053. elem.up();
  12054. elem.c('parameter');
  12055. elem.attrs({name: "mslabel", value:msid});
  12056. elem.up();
  12057. elem.c('parameter');
  12058. elem.attrs({name: "label", value:msid});
  12059. elem.up();
  12060. elem.up();
  12061. }
  12062. }
  12063. // XEP-0339 handle ssrc-group attributes
  12064. var ssrc_group_lines = SDPUtil.find_lines(this.media[i], 'a=ssrc-group:');
  12065. ssrc_group_lines.forEach(function(line) {
  12066. idx = line.indexOf(' ');
  12067. var semantics = line.substr(0, idx).substr(13);
  12068. var ssrcs = line.substr(14 + semantics.length).split(' ');
  12069. if (ssrcs.length != 0) {
  12070. elem.c('ssrc-group', { semantics: semantics, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  12071. ssrcs.forEach(function(ssrc) {
  12072. elem.c('source', { ssrc: ssrc })
  12073. .up();
  12074. });
  12075. elem.up();
  12076. }
  12077. });
  12078. }
  12079. if (SDPUtil.find_line(this.media[i], 'a=rtcp-mux')) {
  12080. elem.c('rtcp-mux').up();
  12081. }
  12082. // XEP-0293 -- map a=rtcp-fb:*
  12083. this.RtcpFbToJingle(i, elem, '*');
  12084. // XEP-0294
  12085. if (SDPUtil.find_line(this.media[i], 'a=extmap:')) {
  12086. lines = SDPUtil.find_lines(this.media[i], 'a=extmap:');
  12087. for (j = 0; j < lines.length; j++) {
  12088. tmp = SDPUtil.parse_extmap(lines[j]);
  12089. elem.c('rtp-hdrext', { xmlns: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',
  12090. uri: tmp.uri,
  12091. id: tmp.value });
  12092. if (tmp.hasOwnProperty('direction')) {
  12093. switch (tmp.direction) {
  12094. case 'sendonly':
  12095. elem.attrs({senders: 'responder'});
  12096. break;
  12097. case 'recvonly':
  12098. elem.attrs({senders: 'initiator'});
  12099. break;
  12100. case 'sendrecv':
  12101. elem.attrs({senders: 'both'});
  12102. break;
  12103. case 'inactive':
  12104. elem.attrs({senders: 'none'});
  12105. break;
  12106. }
  12107. }
  12108. // TODO: handle params
  12109. elem.up();
  12110. }
  12111. }
  12112. elem.up(); // end of description
  12113. }
  12114. // map ice-ufrag/pwd, dtls fingerprint, candidates
  12115. this.TransportToJingle(i, elem);
  12116. if (SDPUtil.find_line(this.media[i], 'a=sendrecv', this.session)) {
  12117. elem.attrs({senders: 'both'});
  12118. } else if (SDPUtil.find_line(this.media[i], 'a=sendonly', this.session)) {
  12119. elem.attrs({senders: 'initiator'});
  12120. } else if (SDPUtil.find_line(this.media[i], 'a=recvonly', this.session)) {
  12121. elem.attrs({senders: 'responder'});
  12122. } else if (SDPUtil.find_line(this.media[i], 'a=inactive', this.session)) {
  12123. elem.attrs({senders: 'none'});
  12124. }
  12125. if (mline.port == '0') {
  12126. // estos hack to reject an m-line
  12127. elem.attrs({senders: 'rejected'});
  12128. }
  12129. elem.up(); // end of content
  12130. }
  12131. elem.up();
  12132. return elem;
  12133. };
  12134. SDP.prototype.TransportToJingle = function (mediaindex, elem) {
  12135. var i = mediaindex;
  12136. var tmp;
  12137. var self = this;
  12138. elem.c('transport');
  12139. // XEP-0343 DTLS/SCTP
  12140. if (SDPUtil.find_line(this.media[mediaindex], 'a=sctpmap:').length)
  12141. {
  12142. var sctpmap = SDPUtil.find_line(
  12143. this.media[i], 'a=sctpmap:', self.session);
  12144. if (sctpmap)
  12145. {
  12146. var sctpAttrs = SDPUtil.parse_sctpmap(sctpmap);
  12147. elem.c('sctpmap',
  12148. {
  12149. xmlns: 'urn:xmpp:jingle:transports:dtls-sctp:1',
  12150. number: sctpAttrs[0], /* SCTP port */
  12151. protocol: sctpAttrs[1], /* protocol */
  12152. });
  12153. // Optional stream count attribute
  12154. if (sctpAttrs.length > 2)
  12155. elem.attrs({ streams: sctpAttrs[2]});
  12156. elem.up();
  12157. }
  12158. }
  12159. // XEP-0320
  12160. var fingerprints = SDPUtil.find_lines(this.media[mediaindex], 'a=fingerprint:', this.session);
  12161. fingerprints.forEach(function(line) {
  12162. tmp = SDPUtil.parse_fingerprint(line);
  12163. tmp.xmlns = 'urn:xmpp:jingle:apps:dtls:0';
  12164. elem.c('fingerprint').t(tmp.fingerprint);
  12165. delete tmp.fingerprint;
  12166. line = SDPUtil.find_line(self.media[mediaindex], 'a=setup:', self.session);
  12167. if (line) {
  12168. tmp.setup = line.substr(8);
  12169. }
  12170. elem.attrs(tmp);
  12171. elem.up(); // end of fingerprint
  12172. });
  12173. tmp = SDPUtil.iceparams(this.media[mediaindex], this.session);
  12174. if (tmp) {
  12175. tmp.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
  12176. elem.attrs(tmp);
  12177. // XEP-0176
  12178. if (SDPUtil.find_line(this.media[mediaindex], 'a=candidate:', this.session)) { // add any a=candidate lines
  12179. var lines = SDPUtil.find_lines(this.media[mediaindex], 'a=candidate:', this.session);
  12180. lines.forEach(function (line) {
  12181. elem.c('candidate', SDPUtil.candidateToJingle(line)).up();
  12182. });
  12183. }
  12184. }
  12185. elem.up(); // end of transport
  12186. }
  12187. SDP.prototype.RtcpFbToJingle = function (mediaindex, elem, payloadtype) { // XEP-0293
  12188. var lines = SDPUtil.find_lines(this.media[mediaindex], 'a=rtcp-fb:' + payloadtype);
  12189. lines.forEach(function (line) {
  12190. var tmp = SDPUtil.parse_rtcpfb(line);
  12191. if (tmp.type == 'trr-int') {
  12192. elem.c('rtcp-fb-trr-int', {xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0', value: tmp.params[0]});
  12193. elem.up();
  12194. } else {
  12195. elem.c('rtcp-fb', {xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0', type: tmp.type});
  12196. if (tmp.params.length > 0) {
  12197. elem.attrs({'subtype': tmp.params[0]});
  12198. }
  12199. elem.up();
  12200. }
  12201. });
  12202. };
  12203. SDP.prototype.RtcpFbFromJingle = function (elem, payloadtype) { // XEP-0293
  12204. var media = '';
  12205. var tmp = elem.find('>rtcp-fb-trr-int[xmlns="urn:xmpp:jingle:apps:rtp:rtcp-fb:0"]');
  12206. if (tmp.length) {
  12207. media += 'a=rtcp-fb:' + '*' + ' ' + 'trr-int' + ' ';
  12208. if (tmp.attr('value')) {
  12209. media += tmp.attr('value');
  12210. } else {
  12211. media += '0';
  12212. }
  12213. media += '\r\n';
  12214. }
  12215. tmp = elem.find('>rtcp-fb[xmlns="urn:xmpp:jingle:apps:rtp:rtcp-fb:0"]');
  12216. tmp.each(function () {
  12217. media += 'a=rtcp-fb:' + payloadtype + ' ' + $(this).attr('type');
  12218. if ($(this).attr('subtype')) {
  12219. media += ' ' + $(this).attr('subtype');
  12220. }
  12221. media += '\r\n';
  12222. });
  12223. return media;
  12224. };
  12225. // construct an SDP from a jingle stanza
  12226. SDP.prototype.fromJingle = function (jingle) {
  12227. var self = this;
  12228. this.raw = 'v=0\r\n' +
  12229. 'o=- ' + '1923518516' + ' 2 IN IP4 0.0.0.0\r\n' +// FIXME
  12230. 's=-\r\n' +
  12231. 't=0 0\r\n';
  12232. // http://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-04#section-8
  12233. if ($(jingle).find('>group[xmlns="urn:xmpp:jingle:apps:grouping:0"]').length) {
  12234. $(jingle).find('>group[xmlns="urn:xmpp:jingle:apps:grouping:0"]').each(function (idx, group) {
  12235. var contents = $(group).find('>content').map(function (idx, content) {
  12236. return content.getAttribute('name');
  12237. }).get();
  12238. if (contents.length > 0) {
  12239. self.raw += 'a=group:' + (group.getAttribute('semantics') || group.getAttribute('type')) + ' ' + contents.join(' ') + '\r\n';
  12240. }
  12241. });
  12242. }
  12243. this.session = this.raw;
  12244. jingle.find('>content').each(function () {
  12245. var m = self.jingle2media($(this));
  12246. self.media.push(m);
  12247. });
  12248. // reconstruct msid-semantic -- apparently not necessary
  12249. /*
  12250. var msid = SDPUtil.parse_ssrc(this.raw);
  12251. if (msid.hasOwnProperty('mslabel')) {
  12252. this.session += "a=msid-semantic: WMS " + msid.mslabel + "\r\n";
  12253. }
  12254. */
  12255. this.raw = this.session + this.media.join('');
  12256. };
  12257. // translate a jingle content element into an an SDP media part
  12258. SDP.prototype.jingle2media = function (content) {
  12259. var media = '',
  12260. desc = content.find('description'),
  12261. ssrc = desc.attr('ssrc'),
  12262. self = this,
  12263. tmp;
  12264. var sctp = content.find(
  12265. '>transport>sctpmap[xmlns="urn:xmpp:jingle:transports:dtls-sctp:1"]');
  12266. tmp = { media: desc.attr('media') };
  12267. tmp.port = '1';
  12268. if (content.attr('senders') == 'rejected') {
  12269. // estos hack to reject an m-line.
  12270. tmp.port = '0';
  12271. }
  12272. if (content.find('>transport>fingerprint').length || desc.find('encryption').length) {
  12273. if (sctp.length)
  12274. tmp.proto = 'DTLS/SCTP';
  12275. else
  12276. tmp.proto = 'RTP/SAVPF';
  12277. } else {
  12278. tmp.proto = 'RTP/AVPF';
  12279. }
  12280. if (!sctp.length)
  12281. {
  12282. tmp.fmt = desc.find('payload-type').map(
  12283. function () { return this.getAttribute('id'); }).get();
  12284. media += SDPUtil.build_mline(tmp) + '\r\n';
  12285. }
  12286. else
  12287. {
  12288. media += 'm=application 1 DTLS/SCTP ' + sctp.attr('number') + '\r\n';
  12289. media += 'a=sctpmap:' + sctp.attr('number') +
  12290. ' ' + sctp.attr('protocol');
  12291. var streamCount = sctp.attr('streams');
  12292. if (streamCount)
  12293. media += ' ' + streamCount + '\r\n';
  12294. else
  12295. media += '\r\n';
  12296. }
  12297. media += 'c=IN IP4 0.0.0.0\r\n';
  12298. if (!sctp.length)
  12299. media += 'a=rtcp:1 IN IP4 0.0.0.0\r\n';
  12300. tmp = content.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
  12301. if (tmp.length) {
  12302. if (tmp.attr('ufrag')) {
  12303. media += SDPUtil.build_iceufrag(tmp.attr('ufrag')) + '\r\n';
  12304. }
  12305. if (tmp.attr('pwd')) {
  12306. media += SDPUtil.build_icepwd(tmp.attr('pwd')) + '\r\n';
  12307. }
  12308. tmp.find('>fingerprint').each(function () {
  12309. // FIXME: check namespace at some point
  12310. media += 'a=fingerprint:' + this.getAttribute('hash');
  12311. media += ' ' + $(this).text();
  12312. media += '\r\n';
  12313. if (this.getAttribute('setup')) {
  12314. media += 'a=setup:' + this.getAttribute('setup') + '\r\n';
  12315. }
  12316. });
  12317. }
  12318. switch (content.attr('senders')) {
  12319. case 'initiator':
  12320. media += 'a=sendonly\r\n';
  12321. break;
  12322. case 'responder':
  12323. media += 'a=recvonly\r\n';
  12324. break;
  12325. case 'none':
  12326. media += 'a=inactive\r\n';
  12327. break;
  12328. case 'both':
  12329. media += 'a=sendrecv\r\n';
  12330. break;
  12331. }
  12332. media += 'a=mid:' + content.attr('name') + '\r\n';
  12333. // <description><rtcp-mux/></description>
  12334. // see http://code.google.com/p/libjingle/issues/detail?id=309 -- no spec though
  12335. // and http://mail.jabber.org/pipermail/jingle/2011-December/001761.html
  12336. if (desc.find('rtcp-mux').length) {
  12337. media += 'a=rtcp-mux\r\n';
  12338. }
  12339. if (desc.find('encryption').length) {
  12340. desc.find('encryption>crypto').each(function () {
  12341. media += 'a=crypto:' + this.getAttribute('tag');
  12342. media += ' ' + this.getAttribute('crypto-suite');
  12343. media += ' ' + this.getAttribute('key-params');
  12344. if (this.getAttribute('session-params')) {
  12345. media += ' ' + this.getAttribute('session-params');
  12346. }
  12347. media += '\r\n';
  12348. });
  12349. }
  12350. desc.find('payload-type').each(function () {
  12351. media += SDPUtil.build_rtpmap(this) + '\r\n';
  12352. if ($(this).find('>parameter').length) {
  12353. media += 'a=fmtp:' + this.getAttribute('id') + ' ';
  12354. media += $(this).find('parameter').map(function () { return (this.getAttribute('name') ? (this.getAttribute('name') + '=') : '') + this.getAttribute('value'); }).get().join('; ');
  12355. media += '\r\n';
  12356. }
  12357. // xep-0293
  12358. media += self.RtcpFbFromJingle($(this), this.getAttribute('id'));
  12359. });
  12360. // xep-0293
  12361. media += self.RtcpFbFromJingle(desc, '*');
  12362. // xep-0294
  12363. tmp = desc.find('>rtp-hdrext[xmlns="urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"]');
  12364. tmp.each(function () {
  12365. media += 'a=extmap:' + this.getAttribute('id') + ' ' + this.getAttribute('uri') + '\r\n';
  12366. });
  12367. content.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]>candidate').each(function () {
  12368. media += SDPUtil.candidateFromJingle(this);
  12369. });
  12370. // XEP-0339 handle ssrc-group attributes
  12371. tmp = content.find('description>ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
  12372. var semantics = this.getAttribute('semantics');
  12373. var ssrcs = $(this).find('>source').map(function() {
  12374. return this.getAttribute('ssrc');
  12375. }).get();
  12376. if (ssrcs.length != 0) {
  12377. media += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
  12378. }
  12379. });
  12380. tmp = content.find('description>source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]');
  12381. tmp.each(function () {
  12382. var ssrc = this.getAttribute('ssrc');
  12383. $(this).find('>parameter').each(function () {
  12384. media += 'a=ssrc:' + ssrc + ' ' + this.getAttribute('name');
  12385. if (this.getAttribute('value') && this.getAttribute('value').length)
  12386. media += ':' + this.getAttribute('value');
  12387. media += '\r\n';
  12388. });
  12389. });
  12390. return media;
  12391. };
  12392. module.exports = SDP;
  12393. },{"./SDPUtil":51}],50:[function(require,module,exports){
  12394. function SDPDiffer(mySDP, otherSDP) {
  12395. this.mySDP = mySDP;
  12396. this.otherSDP = otherSDP;
  12397. }
  12398. /**
  12399. * Returns map of MediaChannel that contains only media not contained in <tt>otherSdp</tt>. Mapped by channel idx.
  12400. * @param otherSdp the other SDP to check ssrc with.
  12401. */
  12402. SDPDiffer.prototype.getNewMedia = function() {
  12403. // this could be useful in Array.prototype.
  12404. function arrayEquals(array) {
  12405. // if the other array is a falsy value, return
  12406. if (!array)
  12407. return false;
  12408. // compare lengths - can save a lot of time
  12409. if (this.length != array.length)
  12410. return false;
  12411. for (var i = 0, l=this.length; i < l; i++) {
  12412. // Check if we have nested arrays
  12413. if (this[i] instanceof Array && array[i] instanceof Array) {
  12414. // recurse into the nested arrays
  12415. if (!this[i].equals(array[i]))
  12416. return false;
  12417. }
  12418. else if (this[i] != array[i]) {
  12419. // Warning - two different object instances will never be equal: {x:20} != {x:20}
  12420. return false;
  12421. }
  12422. }
  12423. return true;
  12424. }
  12425. var myMedias = this.mySDP.getMediaSsrcMap();
  12426. var othersMedias = this.otherSDP.getMediaSsrcMap();
  12427. var newMedia = {};
  12428. Object.keys(othersMedias).forEach(function(othersMediaIdx) {
  12429. var myMedia = myMedias[othersMediaIdx];
  12430. var othersMedia = othersMedias[othersMediaIdx];
  12431. if(!myMedia && othersMedia) {
  12432. // Add whole channel
  12433. newMedia[othersMediaIdx] = othersMedia;
  12434. return;
  12435. }
  12436. // Look for new ssrcs accross the channel
  12437. Object.keys(othersMedia.ssrcs).forEach(function(ssrc) {
  12438. if(Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {
  12439. // Allocate channel if we've found ssrc that doesn't exist in our channel
  12440. if(!newMedia[othersMediaIdx]){
  12441. newMedia[othersMediaIdx] = {
  12442. mediaindex: othersMedia.mediaindex,
  12443. mid: othersMedia.mid,
  12444. ssrcs: {},
  12445. ssrcGroups: []
  12446. };
  12447. }
  12448. newMedia[othersMediaIdx].ssrcs[ssrc] = othersMedia.ssrcs[ssrc];
  12449. }
  12450. });
  12451. // Look for new ssrc groups across the channels
  12452. othersMedia.ssrcGroups.forEach(function(otherSsrcGroup){
  12453. // try to match the other ssrc-group with an ssrc-group of ours
  12454. var matched = false;
  12455. for (var i = 0; i < myMedia.ssrcGroups.length; i++) {
  12456. var mySsrcGroup = myMedia.ssrcGroups[i];
  12457. if (otherSsrcGroup.semantics == mySsrcGroup.semantics
  12458. && arrayEquals.apply(otherSsrcGroup.ssrcs, [mySsrcGroup.ssrcs])) {
  12459. matched = true;
  12460. break;
  12461. }
  12462. }
  12463. if (!matched) {
  12464. // Allocate channel if we've found an ssrc-group that doesn't
  12465. // exist in our channel
  12466. if(!newMedia[othersMediaIdx]){
  12467. newMedia[othersMediaIdx] = {
  12468. mediaindex: othersMedia.mediaindex,
  12469. mid: othersMedia.mid,
  12470. ssrcs: {},
  12471. ssrcGroups: []
  12472. };
  12473. }
  12474. newMedia[othersMediaIdx].ssrcGroups.push(otherSsrcGroup);
  12475. }
  12476. });
  12477. });
  12478. return newMedia;
  12479. };
  12480. /**
  12481. * Sends SSRC update IQ.
  12482. * @param sdpMediaSsrcs SSRCs map obtained from SDP.getNewMedia. Cntains SSRCs to add/remove.
  12483. * @param sid session identifier that will be put into the IQ.
  12484. * @param initiator initiator identifier.
  12485. * @param toJid destination Jid
  12486. * @param isAdd indicates if this is remove or add operation.
  12487. */
  12488. SDPDiffer.prototype.toJingle = function(modify) {
  12489. var sdpMediaSsrcs = this.getNewMedia();
  12490. var self = this;
  12491. // FIXME: only announce video ssrcs since we mix audio and dont need
  12492. // the audio ssrcs therefore
  12493. var modified = false;
  12494. Object.keys(sdpMediaSsrcs).forEach(function(mediaindex){
  12495. modified = true;
  12496. var media = sdpMediaSsrcs[mediaindex];
  12497. modify.c('content', {name: media.mid});
  12498. modify.c('description', {xmlns:'urn:xmpp:jingle:apps:rtp:1', media: media.mid});
  12499. // FIXME: not completly sure this operates on blocks and / or handles different ssrcs correctly
  12500. // generate sources from lines
  12501. Object.keys(media.ssrcs).forEach(function(ssrcNum) {
  12502. var mediaSsrc = media.ssrcs[ssrcNum];
  12503. modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  12504. modify.attrs({ssrc: mediaSsrc.ssrc});
  12505. // iterate over ssrc lines
  12506. mediaSsrc.lines.forEach(function (line) {
  12507. var idx = line.indexOf(' ');
  12508. var kv = line.substr(idx + 1);
  12509. modify.c('parameter');
  12510. if (kv.indexOf(':') == -1) {
  12511. modify.attrs({ name: kv });
  12512. } else {
  12513. modify.attrs({ name: kv.split(':', 2)[0] });
  12514. modify.attrs({ value: kv.split(':', 2)[1] });
  12515. }
  12516. modify.up(); // end of parameter
  12517. });
  12518. modify.up(); // end of source
  12519. });
  12520. // generate source groups from lines
  12521. media.ssrcGroups.forEach(function(ssrcGroup) {
  12522. if (ssrcGroup.ssrcs.length != 0) {
  12523. modify.c('ssrc-group', {
  12524. semantics: ssrcGroup.semantics,
  12525. xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
  12526. });
  12527. ssrcGroup.ssrcs.forEach(function (ssrc) {
  12528. modify.c('source', { ssrc: ssrc })
  12529. .up(); // end of source
  12530. });
  12531. modify.up(); // end of ssrc-group
  12532. }
  12533. });
  12534. modify.up(); // end of description
  12535. modify.up(); // end of content
  12536. });
  12537. return modified;
  12538. };
  12539. module.exports = SDPDiffer;
  12540. },{}],51:[function(require,module,exports){
  12541. SDPUtil = {
  12542. iceparams: function (mediadesc, sessiondesc) {
  12543. var data = null;
  12544. if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
  12545. SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc)) {
  12546. data = {
  12547. ufrag: SDPUtil.parse_iceufrag(SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc)),
  12548. pwd: SDPUtil.parse_icepwd(SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc))
  12549. };
  12550. }
  12551. return data;
  12552. },
  12553. parse_iceufrag: function (line) {
  12554. return line.substring(12);
  12555. },
  12556. build_iceufrag: function (frag) {
  12557. return 'a=ice-ufrag:' + frag;
  12558. },
  12559. parse_icepwd: function (line) {
  12560. return line.substring(10);
  12561. },
  12562. build_icepwd: function (pwd) {
  12563. return 'a=ice-pwd:' + pwd;
  12564. },
  12565. parse_mid: function (line) {
  12566. return line.substring(6);
  12567. },
  12568. parse_mline: function (line) {
  12569. var parts = line.substring(2).split(' '),
  12570. data = {};
  12571. data.media = parts.shift();
  12572. data.port = parts.shift();
  12573. data.proto = parts.shift();
  12574. if (parts[parts.length - 1] === '') { // trailing whitespace
  12575. parts.pop();
  12576. }
  12577. data.fmt = parts;
  12578. return data;
  12579. },
  12580. build_mline: function (mline) {
  12581. return 'm=' + mline.media + ' ' + mline.port + ' ' + mline.proto + ' ' + mline.fmt.join(' ');
  12582. },
  12583. parse_rtpmap: function (line) {
  12584. var parts = line.substring(9).split(' '),
  12585. data = {};
  12586. data.id = parts.shift();
  12587. parts = parts[0].split('/');
  12588. data.name = parts.shift();
  12589. data.clockrate = parts.shift();
  12590. data.channels = parts.length ? parts.shift() : '1';
  12591. return data;
  12592. },
  12593. /**
  12594. * Parses SDP line "a=sctpmap:..." and extracts SCTP port from it.
  12595. * @param line eg. "a=sctpmap:5000 webrtc-datachannel"
  12596. * @returns [SCTP port number, protocol, streams]
  12597. */
  12598. parse_sctpmap: function (line)
  12599. {
  12600. var parts = line.substring(10).split(' ');
  12601. var sctpPort = parts[0];
  12602. var protocol = parts[1];
  12603. // Stream count is optional
  12604. var streamCount = parts.length > 2 ? parts[2] : null;
  12605. return [sctpPort, protocol, streamCount];// SCTP port
  12606. },
  12607. build_rtpmap: function (el) {
  12608. var line = 'a=rtpmap:' + el.getAttribute('id') + ' ' + el.getAttribute('name') + '/' + el.getAttribute('clockrate');
  12609. if (el.getAttribute('channels') && el.getAttribute('channels') != '1') {
  12610. line += '/' + el.getAttribute('channels');
  12611. }
  12612. return line;
  12613. },
  12614. parse_crypto: function (line) {
  12615. var parts = line.substring(9).split(' '),
  12616. data = {};
  12617. data.tag = parts.shift();
  12618. data['crypto-suite'] = parts.shift();
  12619. data['key-params'] = parts.shift();
  12620. if (parts.length) {
  12621. data['session-params'] = parts.join(' ');
  12622. }
  12623. return data;
  12624. },
  12625. parse_fingerprint: function (line) { // RFC 4572
  12626. var parts = line.substring(14).split(' '),
  12627. data = {};
  12628. data.hash = parts.shift();
  12629. data.fingerprint = parts.shift();
  12630. // TODO assert that fingerprint satisfies 2UHEX *(":" 2UHEX) ?
  12631. return data;
  12632. },
  12633. parse_fmtp: function (line) {
  12634. var parts = line.split(' '),
  12635. i, key, value,
  12636. data = [];
  12637. parts.shift();
  12638. parts = parts.join(' ').split(';');
  12639. for (i = 0; i < parts.length; i++) {
  12640. key = parts[i].split('=')[0];
  12641. while (key.length && key[0] == ' ') {
  12642. key = key.substring(1);
  12643. }
  12644. value = parts[i].split('=')[1];
  12645. if (key && value) {
  12646. data.push({name: key, value: value});
  12647. } else if (key) {
  12648. // rfc 4733 (DTMF) style stuff
  12649. data.push({name: '', value: key});
  12650. }
  12651. }
  12652. return data;
  12653. },
  12654. parse_icecandidate: function (line) {
  12655. var candidate = {},
  12656. elems = line.split(' ');
  12657. candidate.foundation = elems[0].substring(12);
  12658. candidate.component = elems[1];
  12659. candidate.protocol = elems[2].toLowerCase();
  12660. candidate.priority = elems[3];
  12661. candidate.ip = elems[4];
  12662. candidate.port = elems[5];
  12663. // elems[6] => "typ"
  12664. candidate.type = elems[7];
  12665. candidate.generation = 0; // default value, may be overwritten below
  12666. for (var i = 8; i < elems.length; i += 2) {
  12667. switch (elems[i]) {
  12668. case 'raddr':
  12669. candidate['rel-addr'] = elems[i + 1];
  12670. break;
  12671. case 'rport':
  12672. candidate['rel-port'] = elems[i + 1];
  12673. break;
  12674. case 'generation':
  12675. candidate.generation = elems[i + 1];
  12676. break;
  12677. case 'tcptype':
  12678. candidate.tcptype = elems[i + 1];
  12679. break;
  12680. default: // TODO
  12681. console.log('parse_icecandidate not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
  12682. }
  12683. }
  12684. candidate.network = '1';
  12685. candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
  12686. return candidate;
  12687. },
  12688. build_icecandidate: function (cand) {
  12689. var line = ['a=candidate:' + cand.foundation, cand.component, cand.protocol, cand.priority, cand.ip, cand.port, 'typ', cand.type].join(' ');
  12690. line += ' ';
  12691. switch (cand.type) {
  12692. case 'srflx':
  12693. case 'prflx':
  12694. case 'relay':
  12695. if (cand.hasOwnAttribute('rel-addr') && cand.hasOwnAttribute('rel-port')) {
  12696. line += 'raddr';
  12697. line += ' ';
  12698. line += cand['rel-addr'];
  12699. line += ' ';
  12700. line += 'rport';
  12701. line += ' ';
  12702. line += cand['rel-port'];
  12703. line += ' ';
  12704. }
  12705. break;
  12706. }
  12707. if (cand.hasOwnAttribute('tcptype')) {
  12708. line += 'tcptype';
  12709. line += ' ';
  12710. line += cand.tcptype;
  12711. line += ' ';
  12712. }
  12713. line += 'generation';
  12714. line += ' ';
  12715. line += cand.hasOwnAttribute('generation') ? cand.generation : '0';
  12716. return line;
  12717. },
  12718. parse_ssrc: function (desc) {
  12719. // proprietary mapping of a=ssrc lines
  12720. // TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher on google docs
  12721. // and parse according to that
  12722. var lines = desc.split('\r\n'),
  12723. data = {};
  12724. for (var i = 0; i < lines.length; i++) {
  12725. if (lines[i].substring(0, 7) == 'a=ssrc:') {
  12726. var idx = lines[i].indexOf(' ');
  12727. data[lines[i].substr(idx + 1).split(':', 2)[0]] = lines[i].substr(idx + 1).split(':', 2)[1];
  12728. }
  12729. }
  12730. return data;
  12731. },
  12732. parse_rtcpfb: function (line) {
  12733. var parts = line.substr(10).split(' ');
  12734. var data = {};
  12735. data.pt = parts.shift();
  12736. data.type = parts.shift();
  12737. data.params = parts;
  12738. return data;
  12739. },
  12740. parse_extmap: function (line) {
  12741. var parts = line.substr(9).split(' ');
  12742. var data = {};
  12743. data.value = parts.shift();
  12744. if (data.value.indexOf('/') != -1) {
  12745. data.direction = data.value.substr(data.value.indexOf('/') + 1);
  12746. data.value = data.value.substr(0, data.value.indexOf('/'));
  12747. } else {
  12748. data.direction = 'both';
  12749. }
  12750. data.uri = parts.shift();
  12751. data.params = parts;
  12752. return data;
  12753. },
  12754. find_line: function (haystack, needle, sessionpart) {
  12755. var lines = haystack.split('\r\n');
  12756. for (var i = 0; i < lines.length; i++) {
  12757. if (lines[i].substring(0, needle.length) == needle) {
  12758. return lines[i];
  12759. }
  12760. }
  12761. if (!sessionpart) {
  12762. return false;
  12763. }
  12764. // search session part
  12765. lines = sessionpart.split('\r\n');
  12766. for (var j = 0; j < lines.length; j++) {
  12767. if (lines[j].substring(0, needle.length) == needle) {
  12768. return lines[j];
  12769. }
  12770. }
  12771. return false;
  12772. },
  12773. find_lines: function (haystack, needle, sessionpart) {
  12774. var lines = haystack.split('\r\n'),
  12775. needles = [];
  12776. for (var i = 0; i < lines.length; i++) {
  12777. if (lines[i].substring(0, needle.length) == needle)
  12778. needles.push(lines[i]);
  12779. }
  12780. if (needles.length || !sessionpart) {
  12781. return needles;
  12782. }
  12783. // search session part
  12784. lines = sessionpart.split('\r\n');
  12785. for (var j = 0; j < lines.length; j++) {
  12786. if (lines[j].substring(0, needle.length) == needle) {
  12787. needles.push(lines[j]);
  12788. }
  12789. }
  12790. return needles;
  12791. },
  12792. candidateToJingle: function (line) {
  12793. // a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host generation 0
  12794. // <candidate component=... foundation=... generation=... id=... ip=... network=... port=... priority=... protocol=... type=.../>
  12795. if (line.indexOf('candidate:') === 0) {
  12796. line = 'a=' + line;
  12797. } else if (line.substring(0, 12) != 'a=candidate:') {
  12798. console.log('parseCandidate called with a line that is not a candidate line');
  12799. console.log(line);
  12800. return null;
  12801. }
  12802. if (line.substring(line.length - 2) == '\r\n') // chomp it
  12803. line = line.substring(0, line.length - 2);
  12804. var candidate = {},
  12805. elems = line.split(' '),
  12806. i;
  12807. if (elems[6] != 'typ') {
  12808. console.log('did not find typ in the right place');
  12809. console.log(line);
  12810. return null;
  12811. }
  12812. candidate.foundation = elems[0].substring(12);
  12813. candidate.component = elems[1];
  12814. candidate.protocol = elems[2].toLowerCase();
  12815. candidate.priority = elems[3];
  12816. candidate.ip = elems[4];
  12817. candidate.port = elems[5];
  12818. // elems[6] => "typ"
  12819. candidate.type = elems[7];
  12820. candidate.generation = '0'; // default, may be overwritten below
  12821. for (i = 8; i < elems.length; i += 2) {
  12822. switch (elems[i]) {
  12823. case 'raddr':
  12824. candidate['rel-addr'] = elems[i + 1];
  12825. break;
  12826. case 'rport':
  12827. candidate['rel-port'] = elems[i + 1];
  12828. break;
  12829. case 'generation':
  12830. candidate.generation = elems[i + 1];
  12831. break;
  12832. case 'tcptype':
  12833. candidate.tcptype = elems[i + 1];
  12834. break;
  12835. default: // TODO
  12836. console.log('not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
  12837. }
  12838. }
  12839. candidate.network = '1';
  12840. candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
  12841. return candidate;
  12842. },
  12843. candidateFromJingle: function (cand) {
  12844. var line = 'a=candidate:';
  12845. line += cand.getAttribute('foundation');
  12846. line += ' ';
  12847. line += cand.getAttribute('component');
  12848. line += ' ';
  12849. line += cand.getAttribute('protocol'); //.toUpperCase(); // chrome M23 doesn't like this
  12850. line += ' ';
  12851. line += cand.getAttribute('priority');
  12852. line += ' ';
  12853. line += cand.getAttribute('ip');
  12854. line += ' ';
  12855. line += cand.getAttribute('port');
  12856. line += ' ';
  12857. line += 'typ';
  12858. line += ' ' + cand.getAttribute('type');
  12859. line += ' ';
  12860. switch (cand.getAttribute('type')) {
  12861. case 'srflx':
  12862. case 'prflx':
  12863. case 'relay':
  12864. if (cand.getAttribute('rel-addr') && cand.getAttribute('rel-port')) {
  12865. line += 'raddr';
  12866. line += ' ';
  12867. line += cand.getAttribute('rel-addr');
  12868. line += ' ';
  12869. line += 'rport';
  12870. line += ' ';
  12871. line += cand.getAttribute('rel-port');
  12872. line += ' ';
  12873. }
  12874. break;
  12875. }
  12876. if (cand.getAttribute('protocol').toLowerCase() == 'tcp') {
  12877. line += 'tcptype';
  12878. line += ' ';
  12879. line += cand.getAttribute('tcptype');
  12880. line += ' ';
  12881. }
  12882. line += 'generation';
  12883. line += ' ';
  12884. line += cand.getAttribute('generation') || '0';
  12885. return line + '\r\n';
  12886. }
  12887. };
  12888. module.exports = SDPUtil;
  12889. },{}],52:[function(require,module,exports){
  12890. function TraceablePeerConnection(ice_config, constraints) {
  12891. var self = this;
  12892. var RTCPeerconnection = navigator.mozGetUserMedia ? mozRTCPeerConnection : webkitRTCPeerConnection;
  12893. this.peerconnection = new RTCPeerconnection(ice_config, constraints);
  12894. this.updateLog = [];
  12895. this.stats = {};
  12896. this.statsinterval = null;
  12897. this.maxstats = 0; // limit to 300 values, i.e. 5 minutes; set to 0 to disable
  12898. var Interop = require('sdp-interop').Interop;
  12899. this.interop = new Interop();
  12900. // override as desired
  12901. this.trace = function (what, info) {
  12902. //console.warn('WTRACE', what, info);
  12903. self.updateLog.push({
  12904. time: new Date(),
  12905. type: what,
  12906. value: info || ""
  12907. });
  12908. };
  12909. this.onicecandidate = null;
  12910. this.peerconnection.onicecandidate = function (event) {
  12911. self.trace('onicecandidate', JSON.stringify(event.candidate, null, ' '));
  12912. if (self.onicecandidate !== null) {
  12913. self.onicecandidate(event);
  12914. }
  12915. };
  12916. this.onaddstream = null;
  12917. this.peerconnection.onaddstream = function (event) {
  12918. self.trace('onaddstream', event.stream.id);
  12919. if (self.onaddstream !== null) {
  12920. self.onaddstream(event);
  12921. }
  12922. };
  12923. this.onremovestream = null;
  12924. this.peerconnection.onremovestream = function (event) {
  12925. self.trace('onremovestream', event.stream.id);
  12926. if (self.onremovestream !== null) {
  12927. self.onremovestream(event);
  12928. }
  12929. };
  12930. this.onsignalingstatechange = null;
  12931. this.peerconnection.onsignalingstatechange = function (event) {
  12932. self.trace('onsignalingstatechange', self.signalingState);
  12933. if (self.onsignalingstatechange !== null) {
  12934. self.onsignalingstatechange(event);
  12935. }
  12936. };
  12937. this.oniceconnectionstatechange = null;
  12938. this.peerconnection.oniceconnectionstatechange = function (event) {
  12939. self.trace('oniceconnectionstatechange', self.iceConnectionState);
  12940. if (self.oniceconnectionstatechange !== null) {
  12941. self.oniceconnectionstatechange(event);
  12942. }
  12943. };
  12944. this.onnegotiationneeded = null;
  12945. this.peerconnection.onnegotiationneeded = function (event) {
  12946. self.trace('onnegotiationneeded');
  12947. if (self.onnegotiationneeded !== null) {
  12948. self.onnegotiationneeded(event);
  12949. }
  12950. };
  12951. self.ondatachannel = null;
  12952. this.peerconnection.ondatachannel = function (event) {
  12953. self.trace('ondatachannel', event);
  12954. if (self.ondatachannel !== null) {
  12955. self.ondatachannel(event);
  12956. }
  12957. };
  12958. if (!navigator.mozGetUserMedia && this.maxstats) {
  12959. this.statsinterval = window.setInterval(function() {
  12960. self.peerconnection.getStats(function(stats) {
  12961. var results = stats.result();
  12962. for (var i = 0; i < results.length; ++i) {
  12963. //console.log(results[i].type, results[i].id, results[i].names())
  12964. var now = new Date();
  12965. results[i].names().forEach(function (name) {
  12966. var id = results[i].id + '-' + name;
  12967. if (!self.stats[id]) {
  12968. self.stats[id] = {
  12969. startTime: now,
  12970. endTime: now,
  12971. values: [],
  12972. times: []
  12973. };
  12974. }
  12975. self.stats[id].values.push(results[i].stat(name));
  12976. self.stats[id].times.push(now.getTime());
  12977. if (self.stats[id].values.length > self.maxstats) {
  12978. self.stats[id].values.shift();
  12979. self.stats[id].times.shift();
  12980. }
  12981. self.stats[id].endTime = now;
  12982. });
  12983. }
  12984. });
  12985. }, 1000);
  12986. }
  12987. };
  12988. dumpSDP = function(description) {
  12989. if (typeof description === 'undefined' || description == null) {
  12990. return '';
  12991. }
  12992. return 'type: ' + description.type + '\r\n' + description.sdp;
  12993. };
  12994. if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
  12995. TraceablePeerConnection.prototype.__defineGetter__('signalingState', function() { return this.peerconnection.signalingState; });
  12996. TraceablePeerConnection.prototype.__defineGetter__('iceConnectionState', function() { return this.peerconnection.iceConnectionState; });
  12997. TraceablePeerConnection.prototype.__defineGetter__('localDescription', function() {
  12998. this.trace('getLocalDescription::preTransform (Plan A)', dumpSDP(this.peerconnection.localDescription));
  12999. // if we're running on FF, transform to Plan B first.
  13000. var desc = this.peerconnection.localDescription;
  13001. if (navigator.mozGetUserMedia) {
  13002. desc = this.interop.toPlanB(desc);
  13003. } else {
  13004. desc = APP.simulcast.reverseTransformLocalDescription(this.peerconnection.localDescription);
  13005. }
  13006. this.trace('getLocalDescription::postTransform (Plan B)', dumpSDP(desc));
  13007. return desc;
  13008. });
  13009. TraceablePeerConnection.prototype.__defineGetter__('remoteDescription', function() {
  13010. this.trace('getRemoteDescription::preTransform (Plan A)', dumpSDP(this.peerconnection.remoteDescription));
  13011. // if we're running on FF, transform to Plan B first.
  13012. var desc = this.peerconnection.remoteDescription;
  13013. if (navigator.mozGetUserMedia) {
  13014. desc = this.interop.toPlanB(desc);
  13015. } else {
  13016. desc = APP.simulcast.reverseTransformRemoteDescription(this.peerconnection.remoteDescription);
  13017. }
  13018. this.trace('getRemoteDescription::postTransform (Plan B)', dumpSDP(desc));
  13019. return desc;
  13020. });
  13021. }
  13022. TraceablePeerConnection.prototype.addStream = function (stream) {
  13023. this.trace('addStream', stream.id);
  13024. APP.simulcast.resetSender();
  13025. try
  13026. {
  13027. this.peerconnection.addStream(stream);
  13028. }
  13029. catch (e)
  13030. {
  13031. console.error(e);
  13032. return;
  13033. }
  13034. };
  13035. TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams) {
  13036. this.trace('removeStream', stream.id);
  13037. APP.simulcast.resetSender();
  13038. if(stopStreams) {
  13039. stream.getAudioTracks().forEach(function (track) {
  13040. track.stop();
  13041. });
  13042. stream.getVideoTracks().forEach(function (track) {
  13043. track.stop();
  13044. });
  13045. }
  13046. try {
  13047. // FF doesn't support this yet.
  13048. this.peerconnection.removeStream(stream);
  13049. } catch (e) {
  13050. console.error(e);
  13051. }
  13052. };
  13053. TraceablePeerConnection.prototype.createDataChannel = function (label, opts) {
  13054. this.trace('createDataChannel', label, opts);
  13055. return this.peerconnection.createDataChannel(label, opts);
  13056. };
  13057. TraceablePeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) {
  13058. this.trace('setLocalDescription::preTransform (Plan B)', dumpSDP(description));
  13059. // if we're running on FF, transform to Plan A first.
  13060. if (navigator.mozGetUserMedia) {
  13061. description = this.interop.toPlanA(description);
  13062. } else {
  13063. description = APP.simulcast.transformLocalDescription(description);
  13064. }
  13065. this.trace('setLocalDescription::postTransform (Plan A)', dumpSDP(description));
  13066. var self = this;
  13067. this.peerconnection.setLocalDescription(description,
  13068. function () {
  13069. self.trace('setLocalDescriptionOnSuccess');
  13070. successCallback();
  13071. },
  13072. function (err) {
  13073. self.trace('setLocalDescriptionOnFailure', err);
  13074. failureCallback(err);
  13075. }
  13076. );
  13077. /*
  13078. if (this.statsinterval === null && this.maxstats > 0) {
  13079. // start gathering stats
  13080. }
  13081. */
  13082. };
  13083. TraceablePeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
  13084. this.trace('setRemoteDescription::preTransform (Plan B)', dumpSDP(description));
  13085. // if we're running on FF, transform to Plan A first.
  13086. if (navigator.mozGetUserMedia) {
  13087. description = this.interop.toPlanA(description);
  13088. }
  13089. else {
  13090. description = APP.simulcast.transformRemoteDescription(description);
  13091. }
  13092. this.trace('setRemoteDescription::postTransform (Plan A)', dumpSDP(description));
  13093. var self = this;
  13094. this.peerconnection.setRemoteDescription(description,
  13095. function () {
  13096. self.trace('setRemoteDescriptionOnSuccess');
  13097. successCallback();
  13098. },
  13099. function (err) {
  13100. self.trace('setRemoteDescriptionOnFailure', err);
  13101. failureCallback(err);
  13102. }
  13103. );
  13104. /*
  13105. if (this.statsinterval === null && this.maxstats > 0) {
  13106. // start gathering stats
  13107. }
  13108. */
  13109. };
  13110. TraceablePeerConnection.prototype.close = function () {
  13111. this.trace('stop');
  13112. if (this.statsinterval !== null) {
  13113. window.clearInterval(this.statsinterval);
  13114. this.statsinterval = null;
  13115. }
  13116. this.peerconnection.close();
  13117. };
  13118. TraceablePeerConnection.prototype.createOffer = function (successCallback, failureCallback, constraints) {
  13119. var self = this;
  13120. this.trace('createOffer', JSON.stringify(constraints, null, ' '));
  13121. this.peerconnection.createOffer(
  13122. function (offer) {
  13123. self.trace('createOfferOnSuccess::preTransform (Plan A)', dumpSDP(offer));
  13124. // if we're running on FF, transform to Plan B first.
  13125. if (navigator.mozGetUserMedia) {
  13126. offer = self.interop.toPlanB(offer);
  13127. }
  13128. self.trace('createOfferOnSuccess::postTransform (Plan B)', dumpSDP(offer));
  13129. successCallback(offer);
  13130. },
  13131. function(err) {
  13132. self.trace('createOfferOnFailure', err);
  13133. failureCallback(err);
  13134. },
  13135. constraints
  13136. );
  13137. };
  13138. TraceablePeerConnection.prototype.createAnswer = function (successCallback, failureCallback, constraints) {
  13139. var self = this;
  13140. this.trace('createAnswer', JSON.stringify(constraints, null, ' '));
  13141. this.peerconnection.createAnswer(
  13142. function (answer) {
  13143. self.trace('createAnswerOnSuccess::preTransfom (Plan A)', dumpSDP(answer));
  13144. // if we're running on FF, transform to Plan A first.
  13145. if (navigator.mozGetUserMedia) {
  13146. answer = self.interop.toPlanB(answer);
  13147. } else {
  13148. answer = APP.simulcast.transformAnswer(answer);
  13149. }
  13150. self.trace('createAnswerOnSuccess::postTransfom (Plan B)', dumpSDP(answer));
  13151. successCallback(answer);
  13152. },
  13153. function(err) {
  13154. self.trace('createAnswerOnFailure', err);
  13155. failureCallback(err);
  13156. },
  13157. constraints
  13158. );
  13159. };
  13160. TraceablePeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) {
  13161. var self = this;
  13162. this.trace('addIceCandidate', JSON.stringify(candidate, null, ' '));
  13163. this.peerconnection.addIceCandidate(candidate);
  13164. /* maybe later
  13165. this.peerconnection.addIceCandidate(candidate,
  13166. function () {
  13167. self.trace('addIceCandidateOnSuccess');
  13168. successCallback();
  13169. },
  13170. function (err) {
  13171. self.trace('addIceCandidateOnFailure', err);
  13172. failureCallback(err);
  13173. }
  13174. );
  13175. */
  13176. };
  13177. TraceablePeerConnection.prototype.getStats = function(callback, errback) {
  13178. if (navigator.mozGetUserMedia) {
  13179. // ignore for now...
  13180. if(!errback)
  13181. errback = function () {
  13182. }
  13183. this.peerconnection.getStats(null,callback,errback);
  13184. } else {
  13185. this.peerconnection.getStats(callback);
  13186. }
  13187. };
  13188. module.exports = TraceablePeerConnection;
  13189. },{"sdp-interop":80}],53:[function(require,module,exports){
  13190. /* global $, $iq, APP, config, connection, UI, messageHandler,
  13191. roomName, sessionTerminated, Strophe, Util */
  13192. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  13193. var Settings = require("../settings/Settings");
  13194. var AuthenticationEvents
  13195. = require("../../service/authentication/AuthenticationEvents");
  13196. /**
  13197. * Contains logic responsible for enabling/disabling functionality available
  13198. * only to moderator users.
  13199. */
  13200. var connection = null;
  13201. var focusUserJid;
  13202. function createExpBackoffTimer(step) {
  13203. var count = 1;
  13204. return function (reset) {
  13205. // Reset call
  13206. if (reset) {
  13207. count = 1;
  13208. return;
  13209. }
  13210. // Calculate next timeout
  13211. var timeout = Math.pow(2, count - 1);
  13212. count += 1;
  13213. return timeout * step;
  13214. };
  13215. }
  13216. var getNextTimeout = createExpBackoffTimer(1000);
  13217. var getNextErrorTimeout = createExpBackoffTimer(1000);
  13218. // External authentication stuff
  13219. var externalAuthEnabled = false;
  13220. // Sip gateway can be enabled by configuring Jigasi host in config.js or
  13221. // it will be enabled automatically if focus detects the component through
  13222. // service discovery.
  13223. var sipGatewayEnabled = config.hosts.call_control !== undefined;
  13224. var eventEmitter = null;
  13225. var Moderator = {
  13226. isModerator: function () {
  13227. return connection && connection.emuc.isModerator();
  13228. },
  13229. isPeerModerator: function (peerJid) {
  13230. return connection &&
  13231. connection.emuc.getMemberRole(peerJid) === 'moderator';
  13232. },
  13233. isExternalAuthEnabled: function () {
  13234. return externalAuthEnabled;
  13235. },
  13236. isSipGatewayEnabled: function () {
  13237. return sipGatewayEnabled;
  13238. },
  13239. setConnection: function (con) {
  13240. connection = con;
  13241. },
  13242. init: function (xmpp, emitter) {
  13243. this.xmppService = xmpp;
  13244. eventEmitter = emitter;
  13245. // Message listener that talks to POPUP window
  13246. function listener(event) {
  13247. if (event.data && event.data.sessionId) {
  13248. if (event.origin !== window.location.origin) {
  13249. console.warn(
  13250. "Ignoring sessionId from different origin: " + event.origin);
  13251. return;
  13252. }
  13253. localStorage.setItem('sessionId', event.data.sessionId);
  13254. // After popup is closed we will authenticate
  13255. }
  13256. }
  13257. // Register
  13258. if (window.addEventListener) {
  13259. window.addEventListener("message", listener, false);
  13260. } else {
  13261. window.attachEvent("onmessage", listener);
  13262. }
  13263. },
  13264. onMucLeft: function (jid) {
  13265. console.info("Someone left is it focus ? " + jid);
  13266. var resource = Strophe.getResourceFromJid(jid);
  13267. if (resource === 'focus' && !this.xmppService.sessionTerminated) {
  13268. console.info(
  13269. "Focus has left the room - leaving conference");
  13270. //hangUp();
  13271. // We'd rather reload to have everything re-initialized
  13272. // FIXME: show some message before reload
  13273. location.reload();
  13274. }
  13275. },
  13276. setFocusUserJid: function (focusJid) {
  13277. if (!focusUserJid) {
  13278. focusUserJid = focusJid;
  13279. console.info("Focus jid set to: " + focusUserJid);
  13280. }
  13281. },
  13282. getFocusUserJid: function () {
  13283. return focusUserJid;
  13284. },
  13285. getFocusComponent: function () {
  13286. // Get focus component address
  13287. var focusComponent = config.hosts.focus;
  13288. // If not specified use default: 'focus.domain'
  13289. if (!focusComponent) {
  13290. focusComponent = 'focus.' + config.hosts.domain;
  13291. }
  13292. return focusComponent;
  13293. },
  13294. createConferenceIq: function (roomName) {
  13295. // Generate create conference IQ
  13296. var elem = $iq({to: Moderator.getFocusComponent(), type: 'set'});
  13297. // Session Id used for authentication
  13298. var sessionId = localStorage.getItem('sessionId');
  13299. var machineUID = Settings.getSettings().uid;
  13300. console.info(
  13301. "Session ID: " + sessionId + " machine UID: " + machineUID);
  13302. elem.c('conference', {
  13303. xmlns: 'http://jitsi.org/protocol/focus',
  13304. room: roomName,
  13305. 'machine-uid': machineUID
  13306. });
  13307. if (sessionId) {
  13308. elem.attrs({ 'session-id': sessionId});
  13309. }
  13310. if (config.hosts.bridge !== undefined) {
  13311. elem.c(
  13312. 'property',
  13313. { name: 'bridge', value: config.hosts.bridge})
  13314. .up();
  13315. }
  13316. // Tell the focus we have Jigasi configured
  13317. if (config.hosts.call_control !== undefined) {
  13318. elem.c(
  13319. 'property',
  13320. { name: 'call_control', value: config.hosts.call_control})
  13321. .up();
  13322. }
  13323. if (config.channelLastN !== undefined) {
  13324. elem.c(
  13325. 'property',
  13326. { name: 'channelLastN', value: config.channelLastN})
  13327. .up();
  13328. }
  13329. if (config.adaptiveLastN !== undefined) {
  13330. elem.c(
  13331. 'property',
  13332. { name: 'adaptiveLastN', value: config.adaptiveLastN})
  13333. .up();
  13334. }
  13335. if (config.adaptiveSimulcast !== undefined) {
  13336. elem.c(
  13337. 'property',
  13338. { name: 'adaptiveSimulcast', value: config.adaptiveSimulcast})
  13339. .up();
  13340. }
  13341. if (config.openSctp !== undefined) {
  13342. elem.c(
  13343. 'property',
  13344. { name: 'openSctp', value: config.openSctp})
  13345. .up();
  13346. }
  13347. var roomName = APP.UI.generateRoomName();
  13348. if (typeof roomName !== 'string') roomName = '';
  13349. if (config.enableFirefoxSupport !== undefined && roomName.indexOf('rembson@') === -1) {
  13350. elem.c(
  13351. 'property',
  13352. { name: 'enableFirefoxHacks',
  13353. value: config.enableFirefoxSupport})
  13354. .up();
  13355. }
  13356. elem.up();
  13357. return elem;
  13358. },
  13359. parseSessionId: function (resultIq) {
  13360. var sessionId = $(resultIq).find('conference').attr('session-id');
  13361. if (sessionId) {
  13362. console.info('Received sessionId: ' + sessionId);
  13363. localStorage.setItem('sessionId', sessionId);
  13364. }
  13365. },
  13366. parseConfigOptions: function (resultIq) {
  13367. Moderator.setFocusUserJid(
  13368. $(resultIq).find('conference').attr('focusjid'));
  13369. var authenticationEnabled
  13370. = $(resultIq).find(
  13371. '>conference>property' +
  13372. '[name=\'authentication\'][value=\'true\']').length > 0;
  13373. console.info("Authentication enabled: " + authenticationEnabled);
  13374. externalAuthEnabled
  13375. = $(resultIq).find(
  13376. '>conference>property' +
  13377. '[name=\'externalAuth\'][value=\'true\']').length > 0;
  13378. console.info('External authentication enabled: ' + externalAuthEnabled);
  13379. if (!externalAuthEnabled) {
  13380. // We expect to receive sessionId in 'internal' authentication mode
  13381. Moderator.parseSessionId(resultIq);
  13382. }
  13383. var authIdentity = $(resultIq).find('>conference').attr('identity');
  13384. eventEmitter.emit(AuthenticationEvents.IDENTITY_UPDATED,
  13385. authenticationEnabled, authIdentity);
  13386. // Check if focus has auto-detected Jigasi component(this will be also
  13387. // included if we have passed our host from the config)
  13388. if ($(resultIq).find(
  13389. '>conference>property' +
  13390. '[name=\'sipGatewayEnabled\'][value=\'true\']').length) {
  13391. sipGatewayEnabled = true;
  13392. }
  13393. console.info("Sip gateway enabled: " + sipGatewayEnabled);
  13394. },
  13395. // FIXME: we need to show the fact that we're waiting for the focus
  13396. // to the user(or that focus is not available)
  13397. allocateConferenceFocus: function (roomName, callback) {
  13398. // Try to use focus user JID from the config
  13399. Moderator.setFocusUserJid(config.focusUserJid);
  13400. // Send create conference IQ
  13401. var iq = Moderator.createConferenceIq(roomName);
  13402. var self = this;
  13403. connection.sendIQ(
  13404. iq,
  13405. function (result) {
  13406. // Setup config options
  13407. Moderator.parseConfigOptions(result);
  13408. if ('true' === $(result).find('conference').attr('ready')) {
  13409. // Reset both timers
  13410. getNextTimeout(true);
  13411. getNextErrorTimeout(true);
  13412. // Exec callback
  13413. callback();
  13414. } else {
  13415. var waitMs = getNextTimeout();
  13416. console.info("Waiting for the focus... " + waitMs);
  13417. // Reset error timeout
  13418. getNextErrorTimeout(true);
  13419. window.setTimeout(
  13420. function () {
  13421. Moderator.allocateConferenceFocus(
  13422. roomName, callback);
  13423. }, waitMs);
  13424. }
  13425. },
  13426. function (error) {
  13427. // Invalid session ? remove and try again
  13428. // without session ID to get a new one
  13429. var invalidSession
  13430. = $(error).find('>error>session-invalid').length;
  13431. if (invalidSession) {
  13432. console.info("Session expired! - removing");
  13433. localStorage.removeItem("sessionId");
  13434. }
  13435. if ($(error).find('>error>graceful-shutdown').length) {
  13436. eventEmitter.emit(XMPPEvents.GRACEFUL_SHUTDOWN);
  13437. return;
  13438. }
  13439. // Check for error returned by the reservation system
  13440. var reservationErr = $(error).find('>error>reservation-error');
  13441. if (reservationErr.length) {
  13442. // Trigger error event
  13443. var errorCode = reservationErr.attr('error-code');
  13444. var errorMsg;
  13445. if ($(error).find('>error>text')) {
  13446. errorMsg = $(error).find('>error>text').text();
  13447. }
  13448. eventEmitter.emit(
  13449. XMPPEvents.RESERVATION_ERROR, errorCode, errorMsg);
  13450. return;
  13451. }
  13452. // Not authorized to create new room
  13453. if ($(error).find('>error>not-authorized').length) {
  13454. console.warn("Unauthorized to start the conference", error);
  13455. var toDomain
  13456. = Strophe.getDomainFromJid(error.getAttribute('to'));
  13457. if (toDomain !== config.hosts.anonymousdomain) {
  13458. // FIXME: "is external" should come either from
  13459. // the focus or config.js
  13460. externalAuthEnabled = true;
  13461. }
  13462. eventEmitter.emit(
  13463. XMPPEvents.AUTHENTICATION_REQUIRED,
  13464. function () {
  13465. Moderator.allocateConferenceFocus(
  13466. roomName, callback);
  13467. });
  13468. return;
  13469. }
  13470. var waitMs = getNextErrorTimeout();
  13471. console.error("Focus error, retry after " + waitMs, error);
  13472. // Show message
  13473. var focusComponent = Moderator.getFocusComponent();
  13474. var retrySec = waitMs / 1000;
  13475. // FIXME: message is duplicated ?
  13476. // Do not show in case of session invalid
  13477. // which means just a retry
  13478. if (!invalidSession) {
  13479. APP.UI.messageHandler.notify(
  13480. null, "notify.focus",
  13481. 'disconnected', "notify.focusFail",
  13482. {component: focusComponent, ms: retrySec});
  13483. }
  13484. // Reset response timeout
  13485. getNextTimeout(true);
  13486. window.setTimeout(
  13487. function () {
  13488. Moderator.allocateConferenceFocus(roomName, callback);
  13489. }, waitMs);
  13490. }
  13491. );
  13492. },
  13493. getLoginUrl: function (roomName, urlCallback) {
  13494. var iq = $iq({to: Moderator.getFocusComponent(), type: 'get'});
  13495. iq.c('login-url', {
  13496. xmlns: 'http://jitsi.org/protocol/focus',
  13497. room: roomName,
  13498. 'machine-uid': Settings.getSettings().uid
  13499. });
  13500. connection.sendIQ(
  13501. iq,
  13502. function (result) {
  13503. var url = $(result).find('login-url').attr('url');
  13504. url = url = decodeURIComponent(url);
  13505. if (url) {
  13506. console.info("Got auth url: " + url);
  13507. urlCallback(url);
  13508. } else {
  13509. console.error(
  13510. "Failed to get auth url from the focus", result);
  13511. }
  13512. },
  13513. function (error) {
  13514. console.error("Get auth url error", error);
  13515. }
  13516. );
  13517. },
  13518. getPopupLoginUrl: function (roomName, urlCallback) {
  13519. var iq = $iq({to: Moderator.getFocusComponent(), type: 'get'});
  13520. iq.c('login-url', {
  13521. xmlns: 'http://jitsi.org/protocol/focus',
  13522. room: roomName,
  13523. 'machine-uid': Settings.getSettings().uid,
  13524. popup: true
  13525. });
  13526. connection.sendIQ(
  13527. iq,
  13528. function (result) {
  13529. var url = $(result).find('login-url').attr('url');
  13530. url = url = decodeURIComponent(url);
  13531. if (url) {
  13532. console.info("Got POPUP auth url: " + url);
  13533. urlCallback(url);
  13534. } else {
  13535. console.error(
  13536. "Failed to get POPUP auth url from the focus", result);
  13537. }
  13538. },
  13539. function (error) {
  13540. console.error('Get POPUP auth url error', error);
  13541. }
  13542. );
  13543. },
  13544. logout: function (callback) {
  13545. var iq = $iq({to: Moderator.getFocusComponent(), type: 'set'});
  13546. var sessionId = localStorage.getItem('sessionId');
  13547. if (!sessionId) {
  13548. callback();
  13549. return;
  13550. }
  13551. iq.c('logout', {
  13552. xmlns: 'http://jitsi.org/protocol/focus',
  13553. 'session-id': sessionId
  13554. });
  13555. connection.sendIQ(
  13556. iq,
  13557. function (result) {
  13558. var logoutUrl = $(result).find('logout').attr('logout-url');
  13559. if (logoutUrl) {
  13560. logoutUrl = decodeURIComponent(logoutUrl);
  13561. }
  13562. console.info("Log out OK, url: " + logoutUrl, result);
  13563. localStorage.removeItem('sessionId');
  13564. callback(logoutUrl);
  13565. },
  13566. function (error) {
  13567. console.error("Logout error", error);
  13568. }
  13569. );
  13570. }
  13571. };
  13572. module.exports = Moderator;
  13573. },{"../../service/authentication/AuthenticationEvents":93,"../../service/xmpp/XMPPEvents":97,"../settings/Settings":38}],54:[function(require,module,exports){
  13574. /* global $, $iq, config, connection, focusMucJid, messageHandler, Moderator,
  13575. Toolbar, Util */
  13576. var Moderator = require("./moderator");
  13577. var recordingToken = null;
  13578. var recordingEnabled;
  13579. /**
  13580. * Whether to use a jirecon component for recording, or use the videobridge
  13581. * through COLIBRI.
  13582. */
  13583. var useJirecon = (typeof config.hosts.jirecon != "undefined");
  13584. /**
  13585. * The ID of the jirecon recording session. Jirecon generates it when we
  13586. * initially start recording, and it needs to be used in subsequent requests
  13587. * to jirecon.
  13588. */
  13589. var jireconRid = null;
  13590. function setRecordingToken(token) {
  13591. recordingToken = token;
  13592. }
  13593. function setRecording(state, token, callback, connection) {
  13594. if (useJirecon){
  13595. setRecordingJirecon(state, token, callback, connection);
  13596. } else {
  13597. setRecordingColibri(state, token, callback, connection);
  13598. }
  13599. }
  13600. function setRecordingJirecon(state, token, callback, connection) {
  13601. if (state == recordingEnabled){
  13602. return;
  13603. }
  13604. var iq = $iq({to: config.hosts.jirecon, type: 'set'})
  13605. .c('recording', {xmlns: 'http://jitsi.org/protocol/jirecon',
  13606. action: state ? 'start' : 'stop',
  13607. mucjid: connection.emuc.roomjid});
  13608. if (!state){
  13609. iq.attrs({rid: jireconRid});
  13610. }
  13611. console.log('Start recording');
  13612. connection.sendIQ(
  13613. iq,
  13614. function (result) {
  13615. // TODO wait for an IQ with the real status, since this is
  13616. // provisional?
  13617. jireconRid = $(result).find('recording').attr('rid');
  13618. console.log('Recording ' + (state ? 'started' : 'stopped') +
  13619. '(jirecon)' + result);
  13620. recordingEnabled = state;
  13621. if (!state){
  13622. jireconRid = null;
  13623. }
  13624. callback(state);
  13625. },
  13626. function (error) {
  13627. console.log('Failed to start recording, error: ', error);
  13628. callback(recordingEnabled);
  13629. });
  13630. }
  13631. // Sends a COLIBRI message which enables or disables (according to 'state')
  13632. // the recording on the bridge. Waits for the result IQ and calls 'callback'
  13633. // with the new recording state, according to the IQ.
  13634. function setRecordingColibri(state, token, callback, connection) {
  13635. var elem = $iq({to: connection.emuc.focusMucJid, type: 'set'});
  13636. elem.c('conference', {
  13637. xmlns: 'http://jitsi.org/protocol/colibri'
  13638. });
  13639. elem.c('recording', {state: state, token: token});
  13640. connection.sendIQ(elem,
  13641. function (result) {
  13642. console.log('Set recording "', state, '". Result:', result);
  13643. var recordingElem = $(result).find('>conference>recording');
  13644. var newState = ('true' === recordingElem.attr('state'));
  13645. recordingEnabled = newState;
  13646. callback(newState);
  13647. },
  13648. function (error) {
  13649. console.warn(error);
  13650. callback(recordingEnabled);
  13651. }
  13652. );
  13653. }
  13654. var Recording = {
  13655. toggleRecording: function (tokenEmptyCallback,
  13656. startingCallback, startedCallback, connection) {
  13657. if (!Moderator.isModerator()) {
  13658. console.log(
  13659. 'non-focus, or conference not yet organized:' +
  13660. ' not enabling recording');
  13661. return;
  13662. }
  13663. var self = this;
  13664. // Jirecon does not (currently) support a token.
  13665. if (!recordingToken && !useJirecon) {
  13666. tokenEmptyCallback(function (value) {
  13667. setRecordingToken(value);
  13668. self.toggleRecording(tokenEmptyCallback,
  13669. startingCallback, startedCallback, connection);
  13670. });
  13671. return;
  13672. }
  13673. var oldState = recordingEnabled;
  13674. startingCallback(!oldState);
  13675. setRecording(!oldState,
  13676. recordingToken,
  13677. function (state) {
  13678. console.log("New recording state: ", state);
  13679. if (state === oldState) {
  13680. // FIXME: new focus:
  13681. // this will not work when moderator changes
  13682. // during active session. Then it will assume that
  13683. // recording status has changed to true, but it might have
  13684. // been already true(and we only received actual status from
  13685. // the focus).
  13686. //
  13687. // SO we start with status null, so that it is initialized
  13688. // here and will fail only after second click, so if invalid
  13689. // token was used we have to press the button twice before
  13690. // current status will be fetched and token will be reset.
  13691. //
  13692. // Reliable way would be to return authentication error.
  13693. // Or status update when moderator connects.
  13694. // Or we have to stop recording session when current
  13695. // moderator leaves the room.
  13696. // Failed to change, reset the token because it might
  13697. // have been wrong
  13698. setRecordingToken(null);
  13699. }
  13700. startedCallback(state);
  13701. },
  13702. connection
  13703. );
  13704. }
  13705. }
  13706. module.exports = Recording;
  13707. },{"./moderator":53}],55:[function(require,module,exports){
  13708. /* jshint -W117 */
  13709. /* a simple MUC connection plugin
  13710. * can only handle a single MUC room
  13711. */
  13712. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  13713. var Moderator = require("./moderator");
  13714. var JingleSession = require("./JingleSession");
  13715. var bridgeIsDown = false;
  13716. module.exports = function(XMPP, eventEmitter) {
  13717. Strophe.addConnectionPlugin('emuc', {
  13718. connection: null,
  13719. roomjid: null,
  13720. myroomjid: null,
  13721. members: {},
  13722. list_members: [], // so we can elect a new focus
  13723. presMap: {},
  13724. preziMap: {},
  13725. joined: false,
  13726. isOwner: false,
  13727. role: null,
  13728. focusMucJid: null,
  13729. ssrc2jid: {},
  13730. init: function (conn) {
  13731. this.connection = conn;
  13732. },
  13733. initPresenceMap: function (myroomjid) {
  13734. this.presMap['to'] = myroomjid;
  13735. this.presMap['xns'] = 'http://jabber.org/protocol/muc';
  13736. },
  13737. doJoin: function (jid, password) {
  13738. this.myroomjid = jid;
  13739. console.info("Joined MUC as " + this.myroomjid);
  13740. this.initPresenceMap(this.myroomjid);
  13741. if (!this.roomjid) {
  13742. this.roomjid = Strophe.getBareJidFromJid(jid);
  13743. // add handlers (just once)
  13744. this.connection.addHandler(this.onPresence.bind(this), null, 'presence', null, null, this.roomjid, {matchBare: true});
  13745. this.connection.addHandler(this.onPresenceUnavailable.bind(this), null, 'presence', 'unavailable', null, this.roomjid, {matchBare: true});
  13746. this.connection.addHandler(this.onPresenceError.bind(this), null, 'presence', 'error', null, this.roomjid, {matchBare: true});
  13747. this.connection.addHandler(this.onMessage.bind(this), null, 'message', null, null, this.roomjid, {matchBare: true});
  13748. }
  13749. if (password !== undefined) {
  13750. this.presMap['password'] = password;
  13751. }
  13752. this.sendPresence();
  13753. },
  13754. doLeave: function () {
  13755. console.log("do leave", this.myroomjid);
  13756. var pres = $pres({to: this.myroomjid, type: 'unavailable' });
  13757. this.presMap.length = 0;
  13758. this.connection.send(pres);
  13759. },
  13760. createNonAnonymousRoom: function () {
  13761. // http://xmpp.org/extensions/xep-0045.html#createroom-reserved
  13762. var getForm = $iq({type: 'get', to: this.roomjid})
  13763. .c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'})
  13764. .c('x', {xmlns: 'jabber:x:data', type: 'submit'});
  13765. var self = this;
  13766. this.connection.sendIQ(getForm, function (form) {
  13767. if (!$(form).find(
  13768. '>query>x[xmlns="jabber:x:data"]' +
  13769. '>field[var="muc#roomconfig_whois"]').length) {
  13770. console.error('non-anonymous rooms not supported');
  13771. return;
  13772. }
  13773. var formSubmit = $iq({to: this.roomjid, type: 'set'})
  13774. .c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'});
  13775. formSubmit.c('x', {xmlns: 'jabber:x:data', type: 'submit'});
  13776. formSubmit.c('field', {'var': 'FORM_TYPE'})
  13777. .c('value')
  13778. .t('http://jabber.org/protocol/muc#roomconfig').up().up();
  13779. formSubmit.c('field', {'var': 'muc#roomconfig_whois'})
  13780. .c('value').t('anyone').up().up();
  13781. self.connection.sendIQ(formSubmit);
  13782. }, function (error) {
  13783. console.error("Error getting room configuration form");
  13784. });
  13785. },
  13786. onPresence: function (pres) {
  13787. var from = pres.getAttribute('from');
  13788. // What is this for? A workaround for something?
  13789. if (pres.getAttribute('type')) {
  13790. return true;
  13791. }
  13792. // Parse etherpad tag.
  13793. var etherpad = $(pres).find('>etherpad');
  13794. if (etherpad.length) {
  13795. if (config.etherpad_base && !Moderator.isModerator()) {
  13796. eventEmitter.emit(XMPPEvents.ETHERPAD, etherpad.text());
  13797. }
  13798. }
  13799. // Parse prezi tag.
  13800. var presentation = $(pres).find('>prezi');
  13801. if (presentation.length) {
  13802. var url = presentation.attr('url');
  13803. var current = presentation.find('>current').text();
  13804. console.log('presentation info received from', from, url);
  13805. if (this.preziMap[from] == null) {
  13806. this.preziMap[from] = url;
  13807. $(document).trigger('presentationadded.muc', [from, url, current]);
  13808. }
  13809. else {
  13810. $(document).trigger('gotoslide.muc', [from, url, current]);
  13811. }
  13812. }
  13813. else if (this.preziMap[from] != null) {
  13814. var url = this.preziMap[from];
  13815. delete this.preziMap[from];
  13816. $(document).trigger('presentationremoved.muc', [from, url]);
  13817. }
  13818. // Parse audio info tag.
  13819. var audioMuted = $(pres).find('>audiomuted');
  13820. if (audioMuted.length) {
  13821. $(document).trigger('audiomuted.muc', [from, audioMuted.text()]);
  13822. }
  13823. // Parse video info tag.
  13824. var videoMuted = $(pres).find('>videomuted');
  13825. if (videoMuted.length) {
  13826. $(document).trigger('videomuted.muc', [from, videoMuted.text()]);
  13827. }
  13828. var devices = $(pres).find('>devices');
  13829. if(devices.length)
  13830. {
  13831. var audio = devices.find('>audio');
  13832. var video = devices.find('>video');
  13833. var devicesValues = {audio: false, video: false};
  13834. if(audio.length && audio.text() === "true")
  13835. {
  13836. devicesValues.audio = true;
  13837. }
  13838. if(video.length && video.text() === "true")
  13839. {
  13840. devicesValues.video = true;
  13841. }
  13842. eventEmitter.emit(XMPPEvents.DEVICE_AVAILABLE,
  13843. Strophe.getResourceFromJid(from), devicesValues);
  13844. }
  13845. var stats = $(pres).find('>stats');
  13846. if (stats.length) {
  13847. var statsObj = {};
  13848. Strophe.forEachChild(stats[0], "stat", function (el) {
  13849. statsObj[el.getAttribute("name")] = el.getAttribute("value");
  13850. });
  13851. eventEmitter.emit(XMPPEvents.REMOTE_STATS, from, statsObj);
  13852. }
  13853. // Parse status.
  13854. if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="201"]').length) {
  13855. this.isOwner = true;
  13856. this.createNonAnonymousRoom();
  13857. }
  13858. // Parse roles.
  13859. var member = {};
  13860. member.show = $(pres).find('>show').text();
  13861. member.status = $(pres).find('>status').text();
  13862. var tmp = $(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>item');
  13863. member.affiliation = tmp.attr('affiliation');
  13864. member.role = tmp.attr('role');
  13865. // Focus recognition
  13866. member.jid = tmp.attr('jid');
  13867. member.isFocus = false;
  13868. if (member.jid
  13869. && member.jid.indexOf(Moderator.getFocusUserJid() + "/") == 0) {
  13870. member.isFocus = true;
  13871. }
  13872. var nicktag = $(pres).find('>nick[xmlns="http://jabber.org/protocol/nick"]');
  13873. member.displayName = (nicktag.length > 0 ? nicktag.html() : null);
  13874. if (from == this.myroomjid) {
  13875. if (member.affiliation == 'owner') this.isOwner = true;
  13876. if (this.role !== member.role) {
  13877. this.role = member.role;
  13878. eventEmitter.emit(XMPPEvents.LOCALROLE_CHANGED,
  13879. from, member, pres, Moderator.isModerator());
  13880. }
  13881. if (!this.joined) {
  13882. this.joined = true;
  13883. eventEmitter.emit(XMPPEvents.MUC_JOINED, from, member);
  13884. this.list_members.push(from);
  13885. }
  13886. } else if (this.members[from] === undefined) {
  13887. // new participant
  13888. this.members[from] = member;
  13889. this.list_members.push(from);
  13890. console.log('entered', from, member);
  13891. if (member.isFocus) {
  13892. this.focusMucJid = from;
  13893. console.info("Ignore focus: " + from + ", real JID: " + member.jid);
  13894. }
  13895. else {
  13896. var id = $(pres).find('>userID').text();
  13897. var email = $(pres).find('>email');
  13898. if (email.length > 0) {
  13899. id = email.text();
  13900. }
  13901. eventEmitter.emit(XMPPEvents.MUC_ENTER, from, id, member.displayName);
  13902. }
  13903. } else {
  13904. // Presence update for existing participant
  13905. // Watch role change:
  13906. if (this.members[from].role != member.role) {
  13907. this.members[from].role = member.role;
  13908. eventEmitter.emit(XMPPEvents.MUC_ROLE_CHANGED,
  13909. member.role, member.displayName);
  13910. }
  13911. }
  13912. // Always trigger presence to update bindings
  13913. this.parsePresence(from, member, pres);
  13914. // Trigger status message update
  13915. if (member.status) {
  13916. eventEmitter.emit(XMPPEvents.PRESENCE_STATUS, from, member);
  13917. }
  13918. return true;
  13919. },
  13920. onPresenceUnavailable: function (pres) {
  13921. var from = pres.getAttribute('from');
  13922. // room destroyed ?
  13923. if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]' +
  13924. '>destroy').length) {
  13925. var reason;
  13926. var reasonSelect = $(pres).find(
  13927. '>x[xmlns="http://jabber.org/protocol/muc#user"]' +
  13928. '>destroy>reason');
  13929. if (reasonSelect.length) {
  13930. reason = reasonSelect.text();
  13931. }
  13932. XMPP.disposeConference(false);
  13933. eventEmitter.emit(XMPPEvents.MUC_DESTROYED, reason);
  13934. return true;
  13935. }
  13936. // Status code 110 indicates that this notification is "self-presence".
  13937. if (!$(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="110"]').length) {
  13938. delete this.members[from];
  13939. this.list_members.splice(this.list_members.indexOf(from), 1);
  13940. this.onParticipantLeft(from);
  13941. }
  13942. // If the status code is 110 this means we're leaving and we would like
  13943. // to remove everyone else from our view, so we trigger the event.
  13944. else if (this.list_members.length > 1) {
  13945. for (var i = 0; i < this.list_members.length; i++) {
  13946. var member = this.list_members[i];
  13947. delete this.members[i];
  13948. this.list_members.splice(i, 1);
  13949. this.onParticipantLeft(member);
  13950. }
  13951. }
  13952. if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="307"]').length) {
  13953. $(document).trigger('kicked.muc', [from]);
  13954. if (this.myroomjid === from) {
  13955. XMPP.disposeConference(false);
  13956. eventEmitter.emit(XMPPEvents.KICKED);
  13957. }
  13958. }
  13959. return true;
  13960. },
  13961. onPresenceError: function (pres) {
  13962. var from = pres.getAttribute('from');
  13963. if ($(pres).find('>error[type="auth"]>not-authorized[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]').length) {
  13964. console.log('on password required', from);
  13965. var self = this;
  13966. eventEmitter.emit(XMPPEvents.PASSWORD_REQUIRED, function (value) {
  13967. self.doJoin(from, value);
  13968. });
  13969. } else if ($(pres).find(
  13970. '>error[type="cancel"]>not-allowed[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]').length) {
  13971. var toDomain = Strophe.getDomainFromJid(pres.getAttribute('to'));
  13972. if (toDomain === config.hosts.anonymousdomain) {
  13973. // enter the room by replying with 'not-authorized'. This would
  13974. // result in reconnection from authorized domain.
  13975. // We're either missing Jicofo/Prosody config for anonymous
  13976. // domains or something is wrong.
  13977. // XMPP.promptLogin();
  13978. APP.UI.messageHandler.openReportDialog(null,
  13979. "dialog.joinError", pres);
  13980. } else {
  13981. console.warn('onPresError ', pres);
  13982. APP.UI.messageHandler.openReportDialog(null,
  13983. "dialog.connectError",
  13984. pres);
  13985. }
  13986. } else {
  13987. console.warn('onPresError ', pres);
  13988. APP.UI.messageHandler.openReportDialog(null,
  13989. "dialog.connectError",
  13990. pres);
  13991. }
  13992. return true;
  13993. },
  13994. sendMessage: function (body, nickname) {
  13995. var msg = $msg({to: this.roomjid, type: 'groupchat'});
  13996. msg.c('body', body).up();
  13997. if (nickname) {
  13998. msg.c('nick', {xmlns: 'http://jabber.org/protocol/nick'}).t(nickname).up().up();
  13999. }
  14000. this.connection.send(msg);
  14001. eventEmitter.emit(XMPPEvents.SENDING_CHAT_MESSAGE, body);
  14002. },
  14003. setSubject: function (subject) {
  14004. var msg = $msg({to: this.roomjid, type: 'groupchat'});
  14005. msg.c('subject', subject);
  14006. this.connection.send(msg);
  14007. console.log("topic changed to " + subject);
  14008. },
  14009. onMessage: function (msg) {
  14010. // FIXME: this is a hack. but jingle on muc makes nickchanges hard
  14011. var from = msg.getAttribute('from');
  14012. var nick =
  14013. $(msg).find('>nick[xmlns="http://jabber.org/protocol/nick"]')
  14014. .text() ||
  14015. Strophe.getResourceFromJid(from);
  14016. var txt = $(msg).find('>body').text();
  14017. var type = msg.getAttribute("type");
  14018. if (type == "error") {
  14019. eventEmitter.emit(XMPPEvents.CHAT_ERROR_RECEIVED,
  14020. $(msg).find('>text').text(), txt);
  14021. return true;
  14022. }
  14023. var subject = $(msg).find('>subject');
  14024. if (subject.length) {
  14025. var subjectText = subject.text();
  14026. if (subjectText || subjectText == "") {
  14027. eventEmitter.emit(XMPPEvents.SUBJECT_CHANGED, subjectText);
  14028. console.log("Subject is changed to " + subjectText);
  14029. }
  14030. }
  14031. if (txt) {
  14032. console.log('chat', nick, txt);
  14033. eventEmitter.emit(XMPPEvents.MESSAGE_RECEIVED,
  14034. from, nick, txt, this.myroomjid);
  14035. }
  14036. return true;
  14037. },
  14038. lockRoom: function (key, onSuccess, onError, onNotSupported) {
  14039. //http://xmpp.org/extensions/xep-0045.html#roomconfig
  14040. var ob = this;
  14041. this.connection.sendIQ($iq({to: this.roomjid, type: 'get'}).c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'}),
  14042. function (res) {
  14043. if ($(res).find('>query>x[xmlns="jabber:x:data"]>field[var="muc#roomconfig_roomsecret"]').length) {
  14044. var formsubmit = $iq({to: ob.roomjid, type: 'set'}).c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'});
  14045. formsubmit.c('x', {xmlns: 'jabber:x:data', type: 'submit'});
  14046. formsubmit.c('field', {'var': 'FORM_TYPE'}).c('value').t('http://jabber.org/protocol/muc#roomconfig').up().up();
  14047. formsubmit.c('field', {'var': 'muc#roomconfig_roomsecret'}).c('value').t(key).up().up();
  14048. // Fixes a bug in prosody 0.9.+ https://code.google.com/p/lxmppd/issues/detail?id=373
  14049. formsubmit.c('field', {'var': 'muc#roomconfig_whois'}).c('value').t('anyone').up().up();
  14050. // FIXME: is muc#roomconfig_passwordprotectedroom required?
  14051. ob.connection.sendIQ(formsubmit,
  14052. onSuccess,
  14053. onError);
  14054. } else {
  14055. onNotSupported();
  14056. }
  14057. }, onError);
  14058. },
  14059. kick: function (jid) {
  14060. var kickIQ = $iq({to: this.roomjid, type: 'set'})
  14061. .c('query', {xmlns: 'http://jabber.org/protocol/muc#admin'})
  14062. .c('item', {nick: Strophe.getResourceFromJid(jid), role: 'none'})
  14063. .c('reason').t('You have been kicked.').up().up().up();
  14064. this.connection.sendIQ(
  14065. kickIQ,
  14066. function (result) {
  14067. console.log('Kick participant with jid: ', jid, result);
  14068. },
  14069. function (error) {
  14070. console.log('Kick participant error: ', error);
  14071. });
  14072. },
  14073. sendPresence: function () {
  14074. var pres = $pres({to: this.presMap['to'] });
  14075. pres.c('x', {xmlns: this.presMap['xns']});
  14076. if (this.presMap['password']) {
  14077. pres.c('password').t(this.presMap['password']).up();
  14078. }
  14079. pres.up();
  14080. // Send XEP-0115 'c' stanza that contains our capabilities info
  14081. if (this.connection.caps) {
  14082. this.connection.caps.node = config.clientNode;
  14083. pres.c('c', this.connection.caps.generateCapsAttrs()).up();
  14084. }
  14085. pres.c('user-agent', {xmlns: 'http://jitsi.org/jitmeet/user-agent'})
  14086. .t(navigator.userAgent).up();
  14087. if (this.presMap['bridgeIsDown']) {
  14088. pres.c('bridgeIsDown').up();
  14089. }
  14090. if (this.presMap['email']) {
  14091. pres.c('email').t(this.presMap['email']).up();
  14092. }
  14093. if (this.presMap['userId']) {
  14094. pres.c('userId').t(this.presMap['userId']).up();
  14095. }
  14096. if (this.presMap['displayName']) {
  14097. // XEP-0172
  14098. pres.c('nick', {xmlns: 'http://jabber.org/protocol/nick'})
  14099. .t(this.presMap['displayName']).up();
  14100. }
  14101. if(this.presMap["devices"])
  14102. {
  14103. pres.c('devices').c('audio').t(this.presMap['devices'].audio).up()
  14104. .c('video').t(this.presMap['devices'].video).up().up();
  14105. }
  14106. if (this.presMap['audions']) {
  14107. pres.c('audiomuted', {xmlns: this.presMap['audions']})
  14108. .t(this.presMap['audiomuted']).up();
  14109. }
  14110. if (this.presMap['videons']) {
  14111. pres.c('videomuted', {xmlns: this.presMap['videons']})
  14112. .t(this.presMap['videomuted']).up();
  14113. }
  14114. if (this.presMap['statsns']) {
  14115. var stats = pres.c('stats', {xmlns: this.presMap['statsns']});
  14116. for (var stat in this.presMap["stats"])
  14117. if (this.presMap["stats"][stat] != null)
  14118. stats.c("stat", {name: stat, value: this.presMap["stats"][stat]}).up();
  14119. pres.up();
  14120. }
  14121. if (this.presMap['prezins']) {
  14122. pres.c('prezi',
  14123. {xmlns: this.presMap['prezins'],
  14124. 'url': this.presMap['preziurl']})
  14125. .c('current').t(this.presMap['prezicurrent']).up().up();
  14126. }
  14127. if (this.presMap['etherpadns']) {
  14128. pres.c('etherpad', {xmlns: this.presMap['etherpadns']})
  14129. .t(this.presMap['etherpadname']).up();
  14130. }
  14131. if (this.presMap['medians']) {
  14132. pres.c('media', {xmlns: this.presMap['medians']});
  14133. var sourceNumber = 0;
  14134. Object.keys(this.presMap).forEach(function (key) {
  14135. if (key.indexOf('source') >= 0) {
  14136. sourceNumber++;
  14137. }
  14138. });
  14139. if (sourceNumber > 0)
  14140. for (var i = 1; i <= sourceNumber / 3; i++) {
  14141. pres.c('source',
  14142. {type: this.presMap['source' + i + '_type'],
  14143. ssrc: this.presMap['source' + i + '_ssrc'],
  14144. direction: this.presMap['source' + i + '_direction']
  14145. || 'sendrecv' }
  14146. ).up();
  14147. }
  14148. }
  14149. pres.up();
  14150. this.connection.send(pres);
  14151. },
  14152. addDisplayNameToPresence: function (displayName) {
  14153. this.presMap['displayName'] = displayName;
  14154. },
  14155. addMediaToPresence: function (sourceNumber, mtype, ssrcs, direction) {
  14156. if (!this.presMap['medians'])
  14157. this.presMap['medians'] = 'http://estos.de/ns/mjs';
  14158. this.presMap['source' + sourceNumber + '_type'] = mtype;
  14159. this.presMap['source' + sourceNumber + '_ssrc'] = ssrcs;
  14160. this.presMap['source' + sourceNumber + '_direction'] = direction;
  14161. },
  14162. addDevicesToPresence: function (devices) {
  14163. this.presMap['devices'] = devices;
  14164. },
  14165. clearPresenceMedia: function () {
  14166. var self = this;
  14167. Object.keys(this.presMap).forEach(function (key) {
  14168. if (key.indexOf('source') != -1) {
  14169. delete self.presMap[key];
  14170. }
  14171. });
  14172. },
  14173. addPreziToPresence: function (url, currentSlide) {
  14174. this.presMap['prezins'] = 'http://jitsi.org/jitmeet/prezi';
  14175. this.presMap['preziurl'] = url;
  14176. this.presMap['prezicurrent'] = currentSlide;
  14177. },
  14178. removePreziFromPresence: function () {
  14179. delete this.presMap['prezins'];
  14180. delete this.presMap['preziurl'];
  14181. delete this.presMap['prezicurrent'];
  14182. },
  14183. addCurrentSlideToPresence: function (currentSlide) {
  14184. this.presMap['prezicurrent'] = currentSlide;
  14185. },
  14186. getPrezi: function (roomjid) {
  14187. return this.preziMap[roomjid];
  14188. },
  14189. addEtherpadToPresence: function (etherpadName) {
  14190. this.presMap['etherpadns'] = 'http://jitsi.org/jitmeet/etherpad';
  14191. this.presMap['etherpadname'] = etherpadName;
  14192. },
  14193. addAudioInfoToPresence: function (isMuted) {
  14194. this.presMap['audions'] = 'http://jitsi.org/jitmeet/audio';
  14195. this.presMap['audiomuted'] = isMuted.toString();
  14196. },
  14197. addVideoInfoToPresence: function (isMuted) {
  14198. this.presMap['videons'] = 'http://jitsi.org/jitmeet/video';
  14199. this.presMap['videomuted'] = isMuted.toString();
  14200. },
  14201. addConnectionInfoToPresence: function (stats) {
  14202. this.presMap['statsns'] = 'http://jitsi.org/jitmeet/stats';
  14203. this.presMap['stats'] = stats;
  14204. },
  14205. findJidFromResource: function (resourceJid) {
  14206. if (resourceJid &&
  14207. resourceJid === Strophe.getResourceFromJid(this.myroomjid)) {
  14208. return this.myroomjid;
  14209. }
  14210. var peerJid = null;
  14211. Object.keys(this.members).some(function (jid) {
  14212. peerJid = jid;
  14213. return Strophe.getResourceFromJid(jid) === resourceJid;
  14214. });
  14215. return peerJid;
  14216. },
  14217. addBridgeIsDownToPresence: function () {
  14218. this.presMap['bridgeIsDown'] = true;
  14219. },
  14220. addEmailToPresence: function (email) {
  14221. this.presMap['email'] = email;
  14222. },
  14223. addUserIdToPresence: function (userId) {
  14224. this.presMap['userId'] = userId;
  14225. },
  14226. isModerator: function () {
  14227. return this.role === 'moderator';
  14228. },
  14229. getMemberRole: function (peerJid) {
  14230. if (this.members[peerJid]) {
  14231. return this.members[peerJid].role;
  14232. }
  14233. return null;
  14234. },
  14235. onParticipantLeft: function (jid) {
  14236. eventEmitter.emit(XMPPEvents.MUC_LEFT, jid);
  14237. this.connection.jingle.terminateByJid(jid);
  14238. if (this.getPrezi(jid)) {
  14239. $(document).trigger('presentationremoved.muc',
  14240. [jid, this.getPrezi(jid)]);
  14241. }
  14242. Moderator.onMucLeft(jid);
  14243. },
  14244. parsePresence: function (from, memeber, pres) {
  14245. if($(pres).find(">bridgeIsDown").length > 0 && !bridgeIsDown) {
  14246. bridgeIsDown = true;
  14247. eventEmitter.emit(XMPPEvents.BRIDGE_DOWN);
  14248. }
  14249. if(memeber.isFocus)
  14250. return;
  14251. var self = this;
  14252. // Remove old ssrcs coming from the jid
  14253. Object.keys(this.ssrc2jid).forEach(function (ssrc) {
  14254. if (self.ssrc2jid[ssrc] == from) {
  14255. delete self.ssrc2jid[ssrc];
  14256. }
  14257. });
  14258. var changedStreams = [];
  14259. $(pres).find('>media[xmlns="http://estos.de/ns/mjs"]>source').each(function (idx, ssrc) {
  14260. //console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc'));
  14261. var ssrcV = ssrc.getAttribute('ssrc');
  14262. self.ssrc2jid[ssrcV] = from;
  14263. JingleSession.notReceivedSSRCs.push(ssrcV);
  14264. var type = ssrc.getAttribute('type');
  14265. var direction = ssrc.getAttribute('direction');
  14266. changedStreams.push({type: type, direction: direction});
  14267. });
  14268. eventEmitter.emit(XMPPEvents.CHANGED_STREAMS, from, changedStreams);
  14269. var displayName = !config.displayJids
  14270. ? memeber.displayName : Strophe.getResourceFromJid(from);
  14271. if (displayName && displayName.length > 0)
  14272. {
  14273. eventEmitter.emit(XMPPEvents.DISPLAY_NAME_CHANGED, from, displayName);
  14274. }
  14275. var id = $(pres).find('>userID').text();
  14276. var email = $(pres).find('>email');
  14277. if(email.length > 0) {
  14278. id = email.text();
  14279. }
  14280. eventEmitter.emit(XMPPEvents.USER_ID_CHANGED, from, id);
  14281. }
  14282. });
  14283. };
  14284. },{"../../service/xmpp/XMPPEvents":97,"./JingleSession":48,"./moderator":53}],56:[function(require,module,exports){
  14285. /* jshint -W117 */
  14286. var JingleSession = require("./JingleSession");
  14287. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  14288. module.exports = function(XMPP, eventEmitter)
  14289. {
  14290. function CallIncomingJingle(sid, connection) {
  14291. var sess = connection.jingle.sessions[sid];
  14292. // TODO: do we check activecall == null?
  14293. connection.jingle.activecall = sess;
  14294. eventEmitter.emit(XMPPEvents.CALL_INCOMING, sess);
  14295. // TODO: check affiliation and/or role
  14296. console.log('emuc data for', sess.peerjid, connection.emuc.members[sess.peerjid]);
  14297. sess.usedrip = true; // not-so-naive trickle ice
  14298. sess.sendAnswer();
  14299. sess.accept();
  14300. };
  14301. Strophe.addConnectionPlugin('jingle', {
  14302. connection: null,
  14303. sessions: {},
  14304. jid2session: {},
  14305. ice_config: {iceServers: []},
  14306. pc_constraints: {},
  14307. activecall: null,
  14308. media_constraints: {
  14309. mandatory: {
  14310. 'OfferToReceiveAudio': true,
  14311. 'OfferToReceiveVideo': true
  14312. }
  14313. // MozDontOfferDataChannel: true when this is firefox
  14314. },
  14315. init: function (conn) {
  14316. this.connection = conn;
  14317. if (this.connection.disco) {
  14318. // http://xmpp.org/extensions/xep-0167.html#support
  14319. // http://xmpp.org/extensions/xep-0176.html#support
  14320. this.connection.disco.addFeature('urn:xmpp:jingle:1');
  14321. this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:1');
  14322. this.connection.disco.addFeature('urn:xmpp:jingle:transports:ice-udp:1');
  14323. this.connection.disco.addFeature('urn:xmpp:jingle:transports:dtls-sctp:1');
  14324. this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:audio');
  14325. this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:video');
  14326. // this is dealt with by SDP O/A so we don't need to annouce this
  14327. //this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:rtcp-fb:0'); // XEP-0293
  14328. //this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'); // XEP-0294
  14329. if (config.useRtcpMux) {
  14330. this.connection.disco.addFeature('urn:ietf:rfc:5761'); // rtcp-mux
  14331. }
  14332. if (config.useBundle) {
  14333. this.connection.disco.addFeature('urn:ietf:rfc:5888'); // a=group, e.g. bundle
  14334. }
  14335. //this.connection.disco.addFeature('urn:ietf:rfc:5576'); // a=ssrc
  14336. }
  14337. this.connection.addHandler(this.onJingle.bind(this), 'urn:xmpp:jingle:1', 'iq', 'set', null, null);
  14338. },
  14339. onJingle: function (iq) {
  14340. var sid = $(iq).find('jingle').attr('sid');
  14341. var action = $(iq).find('jingle').attr('action');
  14342. var fromJid = iq.getAttribute('from');
  14343. // send ack first
  14344. var ack = $iq({type: 'result',
  14345. to: fromJid,
  14346. id: iq.getAttribute('id')
  14347. });
  14348. console.log('on jingle ' + action + ' from ' + fromJid, iq);
  14349. var sess = this.sessions[sid];
  14350. if ('session-initiate' != action) {
  14351. if (sess === null) {
  14352. ack.type = 'error';
  14353. ack.c('error', {type: 'cancel'})
  14354. .c('item-not-found', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up()
  14355. .c('unknown-session', {xmlns: 'urn:xmpp:jingle:errors:1'});
  14356. this.connection.send(ack);
  14357. return true;
  14358. }
  14359. // compare from to sess.peerjid (bare jid comparison for later compat with message-mode)
  14360. // local jid is not checked
  14361. if (Strophe.getBareJidFromJid(fromJid) != Strophe.getBareJidFromJid(sess.peerjid)) {
  14362. console.warn('jid mismatch for session id', sid, fromJid, sess.peerjid);
  14363. ack.type = 'error';
  14364. ack.c('error', {type: 'cancel'})
  14365. .c('item-not-found', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up()
  14366. .c('unknown-session', {xmlns: 'urn:xmpp:jingle:errors:1'});
  14367. this.connection.send(ack);
  14368. return true;
  14369. }
  14370. } else if (sess !== undefined) {
  14371. // existing session with same session id
  14372. // this might be out-of-order if the sess.peerjid is the same as from
  14373. ack.type = 'error';
  14374. ack.c('error', {type: 'cancel'})
  14375. .c('service-unavailable', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up();
  14376. console.warn('duplicate session id', sid);
  14377. this.connection.send(ack);
  14378. return true;
  14379. }
  14380. // FIXME: check for a defined action
  14381. this.connection.send(ack);
  14382. // see http://xmpp.org/extensions/xep-0166.html#concepts-session
  14383. switch (action) {
  14384. case 'session-initiate':
  14385. sess = new JingleSession(
  14386. $(iq).attr('to'), $(iq).find('jingle').attr('sid'),
  14387. this.connection, XMPP);
  14388. // configure session
  14389. sess.media_constraints = this.media_constraints;
  14390. sess.pc_constraints = this.pc_constraints;
  14391. sess.ice_config = this.ice_config;
  14392. sess.initiate(fromJid, false);
  14393. // FIXME: setRemoteDescription should only be done when this call is to be accepted
  14394. sess.setRemoteDescription($(iq).find('>jingle'), 'offer');
  14395. this.sessions[sess.sid] = sess;
  14396. this.jid2session[sess.peerjid] = sess;
  14397. // the callback should either
  14398. // .sendAnswer and .accept
  14399. // or .sendTerminate -- not necessarily synchronus
  14400. CallIncomingJingle(sess.sid, this.connection);
  14401. break;
  14402. case 'session-accept':
  14403. sess.setRemoteDescription($(iq).find('>jingle'), 'answer');
  14404. sess.accept();
  14405. $(document).trigger('callaccepted.jingle', [sess.sid]);
  14406. break;
  14407. case 'session-terminate':
  14408. // If this is not the focus sending the terminate, we have
  14409. // nothing more to do here.
  14410. if (Object.keys(this.sessions).length < 1
  14411. || !(this.sessions[Object.keys(this.sessions)[0]]
  14412. instanceof JingleSession))
  14413. {
  14414. break;
  14415. }
  14416. console.log('terminating...', sess.sid);
  14417. sess.terminate();
  14418. this.terminate(sess.sid);
  14419. if ($(iq).find('>jingle>reason').length) {
  14420. $(document).trigger('callterminated.jingle', [
  14421. sess.sid,
  14422. sess.peerjid,
  14423. $(iq).find('>jingle>reason>:first')[0].tagName,
  14424. $(iq).find('>jingle>reason>text').text()
  14425. ]);
  14426. } else {
  14427. $(document).trigger('callterminated.jingle',
  14428. [sess.sid, sess.peerjid]);
  14429. }
  14430. break;
  14431. case 'transport-info':
  14432. sess.addIceCandidate($(iq).find('>jingle>content'));
  14433. break;
  14434. case 'session-info':
  14435. var affected;
  14436. if ($(iq).find('>jingle>ringing[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
  14437. $(document).trigger('ringing.jingle', [sess.sid]);
  14438. } else if ($(iq).find('>jingle>mute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
  14439. affected = $(iq).find('>jingle>mute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').attr('name');
  14440. $(document).trigger('mute.jingle', [sess.sid, affected]);
  14441. } else if ($(iq).find('>jingle>unmute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
  14442. affected = $(iq).find('>jingle>unmute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').attr('name');
  14443. $(document).trigger('unmute.jingle', [sess.sid, affected]);
  14444. }
  14445. break;
  14446. case 'addsource': // FIXME: proprietary, un-jingleish
  14447. case 'source-add': // FIXME: proprietary
  14448. sess.addSource($(iq).find('>jingle>content'), fromJid);
  14449. break;
  14450. case 'removesource': // FIXME: proprietary, un-jingleish
  14451. case 'source-remove': // FIXME: proprietary
  14452. sess.removeSource($(iq).find('>jingle>content'), fromJid);
  14453. break;
  14454. default:
  14455. console.warn('jingle action not implemented', action);
  14456. break;
  14457. }
  14458. return true;
  14459. },
  14460. initiate: function (peerjid, myjid) { // initiate a new jinglesession to peerjid
  14461. var sess = new JingleSession(myjid || this.connection.jid,
  14462. Math.random().toString(36).substr(2, 12), // random string
  14463. this.connection, XMPP);
  14464. // configure session
  14465. sess.media_constraints = this.media_constraints;
  14466. sess.pc_constraints = this.pc_constraints;
  14467. sess.ice_config = this.ice_config;
  14468. sess.initiate(peerjid, true);
  14469. this.sessions[sess.sid] = sess;
  14470. this.jid2session[sess.peerjid] = sess;
  14471. sess.sendOffer();
  14472. return sess;
  14473. },
  14474. terminate: function (sid, reason, text) { // terminate by sessionid (or all sessions)
  14475. if (sid === null || sid === undefined) {
  14476. for (sid in this.sessions) {
  14477. if (this.sessions[sid].state != 'ended') {
  14478. this.sessions[sid].sendTerminate(reason || (!this.sessions[sid].active()) ? 'cancel' : null, text);
  14479. this.sessions[sid].terminate();
  14480. }
  14481. delete this.jid2session[this.sessions[sid].peerjid];
  14482. delete this.sessions[sid];
  14483. }
  14484. } else if (this.sessions.hasOwnProperty(sid)) {
  14485. if (this.sessions[sid].state != 'ended') {
  14486. this.sessions[sid].sendTerminate(reason || (!this.sessions[sid].active()) ? 'cancel' : null, text);
  14487. this.sessions[sid].terminate();
  14488. }
  14489. delete this.jid2session[this.sessions[sid].peerjid];
  14490. delete this.sessions[sid];
  14491. }
  14492. },
  14493. // Used to terminate a session when an unavailable presence is received.
  14494. terminateByJid: function (jid) {
  14495. if (this.jid2session.hasOwnProperty(jid)) {
  14496. var sess = this.jid2session[jid];
  14497. if (sess) {
  14498. sess.terminate();
  14499. console.log('peer went away silently', jid);
  14500. delete this.sessions[sess.sid];
  14501. delete this.jid2session[jid];
  14502. $(document).trigger('callterminated.jingle',
  14503. [sess.sid, jid], 'gone');
  14504. }
  14505. }
  14506. },
  14507. terminateRemoteByJid: function (jid, reason) {
  14508. if (this.jid2session.hasOwnProperty(jid)) {
  14509. var sess = this.jid2session[jid];
  14510. if (sess) {
  14511. sess.sendTerminate(reason || (!sess.active()) ? 'kick' : null);
  14512. sess.terminate();
  14513. console.log('terminate peer with jid', sess.sid, jid);
  14514. delete this.sessions[sess.sid];
  14515. delete this.jid2session[jid];
  14516. $(document).trigger('callterminated.jingle',
  14517. [sess.sid, jid, 'kicked']);
  14518. }
  14519. }
  14520. },
  14521. getStunAndTurnCredentials: function () {
  14522. // get stun and turn configuration from server via xep-0215
  14523. // uses time-limited credentials as described in
  14524. // http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
  14525. //
  14526. // see https://code.google.com/p/prosody-modules/source/browse/mod_turncredentials/mod_turncredentials.lua
  14527. // for a prosody module which implements this
  14528. //
  14529. // currently, this doesn't work with updateIce and therefore credentials with a long
  14530. // validity have to be fetched before creating the peerconnection
  14531. // TODO: implement refresh via updateIce as described in
  14532. // https://code.google.com/p/webrtc/issues/detail?id=1650
  14533. var self = this;
  14534. this.connection.sendIQ(
  14535. $iq({type: 'get', to: this.connection.domain})
  14536. .c('services', {xmlns: 'urn:xmpp:extdisco:1'}).c('service', {host: 'turn.' + this.connection.domain}),
  14537. function (res) {
  14538. var iceservers = [];
  14539. $(res).find('>services>service').each(function (idx, el) {
  14540. el = $(el);
  14541. var dict = {};
  14542. var type = el.attr('type');
  14543. switch (type) {
  14544. case 'stun':
  14545. dict.url = 'stun:' + el.attr('host');
  14546. if (el.attr('port')) {
  14547. dict.url += ':' + el.attr('port');
  14548. }
  14549. iceservers.push(dict);
  14550. break;
  14551. case 'turn':
  14552. case 'turns':
  14553. dict.url = type + ':';
  14554. if (el.attr('username')) { // https://code.google.com/p/webrtc/issues/detail?id=1508
  14555. if (navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./) && parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10) < 28) {
  14556. dict.url += el.attr('username') + '@';
  14557. } else {
  14558. dict.username = el.attr('username'); // only works in M28
  14559. }
  14560. }
  14561. dict.url += el.attr('host');
  14562. if (el.attr('port') && el.attr('port') != '3478') {
  14563. dict.url += ':' + el.attr('port');
  14564. }
  14565. if (el.attr('transport') && el.attr('transport') != 'udp') {
  14566. dict.url += '?transport=' + el.attr('transport');
  14567. }
  14568. if (el.attr('password')) {
  14569. dict.credential = el.attr('password');
  14570. }
  14571. iceservers.push(dict);
  14572. break;
  14573. }
  14574. });
  14575. self.ice_config.iceServers = iceservers;
  14576. },
  14577. function (err) {
  14578. console.warn('getting turn credentials failed', err);
  14579. console.warn('is mod_turncredentials or similar installed?');
  14580. }
  14581. );
  14582. // implement push?
  14583. },
  14584. /**
  14585. * Populates the log data
  14586. */
  14587. populateData: function () {
  14588. var data = {};
  14589. Object.keys(this.sessions).forEach(function (sid) {
  14590. var session = this.sessions[sid];
  14591. if (session.peerconnection && session.peerconnection.updateLog) {
  14592. // FIXME: should probably be a .dump call
  14593. data["jingle_" + session.sid] = {
  14594. updateLog: session.peerconnection.updateLog,
  14595. stats: session.peerconnection.stats,
  14596. url: window.location.href
  14597. };
  14598. }
  14599. });
  14600. return data;
  14601. }
  14602. });
  14603. };
  14604. },{"../../service/xmpp/XMPPEvents":97,"./JingleSession":48}],57:[function(require,module,exports){
  14605. /* global Strophe */
  14606. module.exports = function () {
  14607. Strophe.addConnectionPlugin('logger', {
  14608. // logs raw stanzas and makes them available for download as JSON
  14609. connection: null,
  14610. log: [],
  14611. init: function (conn) {
  14612. this.connection = conn;
  14613. this.connection.rawInput = this.log_incoming.bind(this);
  14614. this.connection.rawOutput = this.log_outgoing.bind(this);
  14615. },
  14616. log_incoming: function (stanza) {
  14617. this.log.push([new Date().getTime(), 'incoming', stanza]);
  14618. },
  14619. log_outgoing: function (stanza) {
  14620. this.log.push([new Date().getTime(), 'outgoing', stanza]);
  14621. }
  14622. });
  14623. };
  14624. },{}],58:[function(require,module,exports){
  14625. /* global $, $iq, config, connection, focusMucJid, forceMuted,
  14626. setAudioMuted, Strophe */
  14627. /**
  14628. * Moderate connection plugin.
  14629. */
  14630. module.exports = function (XMPP) {
  14631. Strophe.addConnectionPlugin('moderate', {
  14632. connection: null,
  14633. init: function (conn) {
  14634. this.connection = conn;
  14635. this.connection.addHandler(this.onMute.bind(this),
  14636. 'http://jitsi.org/jitmeet/audio',
  14637. 'iq',
  14638. 'set',
  14639. null,
  14640. null);
  14641. },
  14642. setMute: function (jid, mute) {
  14643. console.info("set mute", mute);
  14644. var iqToFocus = $iq({to: this.connection.emuc.focusMucJid, type: 'set'})
  14645. .c('mute', {
  14646. xmlns: 'http://jitsi.org/jitmeet/audio',
  14647. jid: jid
  14648. })
  14649. .t(mute.toString())
  14650. .up();
  14651. this.connection.sendIQ(
  14652. iqToFocus,
  14653. function (result) {
  14654. console.log('set mute', result);
  14655. },
  14656. function (error) {
  14657. console.log('set mute error', error);
  14658. });
  14659. },
  14660. onMute: function (iq) {
  14661. var from = iq.getAttribute('from');
  14662. if (from !== this.connection.emuc.focusMucJid) {
  14663. console.warn("Ignored mute from non focus peer");
  14664. return false;
  14665. }
  14666. var mute = $(iq).find('mute');
  14667. if (mute.length) {
  14668. var doMuteAudio = mute.text() === "true";
  14669. APP.UI.setAudioMuted(doMuteAudio);
  14670. XMPP.forceMuted = doMuteAudio;
  14671. }
  14672. return true;
  14673. },
  14674. eject: function (jid) {
  14675. // We're not the focus, so can't terminate
  14676. //connection.jingle.terminateRemoteByJid(jid, 'kick');
  14677. this.connection.emuc.kick(jid);
  14678. }
  14679. });
  14680. }
  14681. },{}],59:[function(require,module,exports){
  14682. /* jshint -W117 */
  14683. module.exports = function() {
  14684. Strophe.addConnectionPlugin('rayo',
  14685. {
  14686. RAYO_XMLNS: 'urn:xmpp:rayo:1',
  14687. connection: null,
  14688. init: function (conn) {
  14689. this.connection = conn;
  14690. if (this.connection.disco) {
  14691. this.connection.disco.addFeature('urn:xmpp:rayo:client:1');
  14692. }
  14693. this.connection.addHandler(
  14694. this.onRayo.bind(this), this.RAYO_XMLNS, 'iq', 'set', null, null);
  14695. },
  14696. onRayo: function (iq) {
  14697. console.info("Rayo IQ", iq);
  14698. },
  14699. dial: function (to, from, roomName, roomPass) {
  14700. var self = this;
  14701. var req = $iq(
  14702. {
  14703. type: 'set',
  14704. to: this.connection.emuc.focusMucJid
  14705. }
  14706. );
  14707. req.c('dial',
  14708. {
  14709. xmlns: this.RAYO_XMLNS,
  14710. to: to,
  14711. from: from
  14712. });
  14713. req.c('header',
  14714. {
  14715. name: 'JvbRoomName',
  14716. value: roomName
  14717. }).up();
  14718. if (roomPass !== null && roomPass.length) {
  14719. req.c('header',
  14720. {
  14721. name: 'JvbRoomPassword',
  14722. value: roomPass
  14723. }).up();
  14724. }
  14725. this.connection.sendIQ(
  14726. req,
  14727. function (result) {
  14728. console.info('Dial result ', result);
  14729. var resource = $(result).find('ref').attr('uri');
  14730. this.call_resource = resource.substr('xmpp:'.length);
  14731. console.info(
  14732. "Received call resource: " + this.call_resource);
  14733. },
  14734. function (error) {
  14735. console.info('Dial error ', error);
  14736. }
  14737. );
  14738. },
  14739. hang_up: function () {
  14740. if (!this.call_resource) {
  14741. console.warn("No call in progress");
  14742. return;
  14743. }
  14744. var self = this;
  14745. var req = $iq(
  14746. {
  14747. type: 'set',
  14748. to: this.call_resource
  14749. }
  14750. );
  14751. req.c('hangup',
  14752. {
  14753. xmlns: this.RAYO_XMLNS
  14754. });
  14755. this.connection.sendIQ(
  14756. req,
  14757. function (result) {
  14758. console.info('Hangup result ', result);
  14759. self.call_resource = null;
  14760. },
  14761. function (error) {
  14762. console.info('Hangup error ', error);
  14763. self.call_resource = null;
  14764. }
  14765. );
  14766. }
  14767. }
  14768. );
  14769. };
  14770. },{}],60:[function(require,module,exports){
  14771. /**
  14772. * Strophe logger implementation. Logs from level WARN and above.
  14773. */
  14774. module.exports = function () {
  14775. Strophe.log = function (level, msg) {
  14776. switch (level) {
  14777. case Strophe.LogLevel.WARN:
  14778. console.warn("Strophe: " + msg);
  14779. break;
  14780. case Strophe.LogLevel.ERROR:
  14781. case Strophe.LogLevel.FATAL:
  14782. console.error("Strophe: " + msg);
  14783. break;
  14784. }
  14785. };
  14786. Strophe.getStatusString = function (status) {
  14787. switch (status) {
  14788. case Strophe.Status.ERROR:
  14789. return "ERROR";
  14790. case Strophe.Status.CONNECTING:
  14791. return "CONNECTING";
  14792. case Strophe.Status.CONNFAIL:
  14793. return "CONNFAIL";
  14794. case Strophe.Status.AUTHENTICATING:
  14795. return "AUTHENTICATING";
  14796. case Strophe.Status.AUTHFAIL:
  14797. return "AUTHFAIL";
  14798. case Strophe.Status.CONNECTED:
  14799. return "CONNECTED";
  14800. case Strophe.Status.DISCONNECTED:
  14801. return "DISCONNECTED";
  14802. case Strophe.Status.DISCONNECTING:
  14803. return "DISCONNECTING";
  14804. case Strophe.Status.ATTACHED:
  14805. return "ATTACHED";
  14806. default:
  14807. return "unknown";
  14808. }
  14809. };
  14810. };
  14811. },{}],61:[function(require,module,exports){
  14812. /* global $, APP, config, Strophe*/
  14813. var Moderator = require("./moderator");
  14814. var EventEmitter = require("events");
  14815. var Recording = require("./recording");
  14816. var SDP = require("./SDP");
  14817. var Settings = require("../settings/Settings");
  14818. var Pako = require("pako");
  14819. var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
  14820. var RTCEvents = require("../../service/RTC/RTCEvents");
  14821. var UIEvents = require("../../service/UI/UIEvents");
  14822. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  14823. var eventEmitter = new EventEmitter();
  14824. var connection = null;
  14825. var authenticatedUser = false;
  14826. function connect(jid, password) {
  14827. connection = XMPP.createConnection();
  14828. Moderator.setConnection(connection);
  14829. if (connection.disco) {
  14830. // for chrome, add multistream cap
  14831. }
  14832. connection.jingle.pc_constraints = APP.RTC.getPCConstraints();
  14833. if (config.useIPv6) {
  14834. // https://code.google.com/p/webrtc/issues/detail?id=2828
  14835. if (!connection.jingle.pc_constraints.optional)
  14836. connection.jingle.pc_constraints.optional = [];
  14837. connection.jingle.pc_constraints.optional.push({googIPv6: true});
  14838. }
  14839. // Include user info in MUC presence
  14840. var settings = Settings.getSettings();
  14841. if (settings.email) {
  14842. connection.emuc.addEmailToPresence(settings.email);
  14843. }
  14844. if (settings.uid) {
  14845. connection.emuc.addUserIdToPresence(settings.uid);
  14846. }
  14847. if (settings.displayName) {
  14848. connection.emuc.addDisplayNameToPresence(settings.displayName);
  14849. }
  14850. var anonymousConnectionFailed = false;
  14851. connection.connect(jid, password, function (status, msg) {
  14852. console.log('Strophe status changed to',
  14853. Strophe.getStatusString(status));
  14854. if (status === Strophe.Status.CONNECTED) {
  14855. if (config.useStunTurn) {
  14856. connection.jingle.getStunAndTurnCredentials();
  14857. }
  14858. console.info("My Jabber ID: " + connection.jid);
  14859. if(password)
  14860. authenticatedUser = true;
  14861. maybeDoJoin();
  14862. } else if (status === Strophe.Status.CONNFAIL) {
  14863. if(msg === 'x-strophe-bad-non-anon-jid') {
  14864. anonymousConnectionFailed = true;
  14865. }
  14866. } else if (status === Strophe.Status.DISCONNECTED) {
  14867. if(anonymousConnectionFailed) {
  14868. // prompt user for username and password
  14869. XMPP.promptLogin();
  14870. }
  14871. } else if (status === Strophe.Status.AUTHFAIL) {
  14872. // wrong password or username, prompt user
  14873. XMPP.promptLogin();
  14874. }
  14875. });
  14876. }
  14877. function maybeDoJoin() {
  14878. if (connection && connection.connected &&
  14879. Strophe.getResourceFromJid(connection.jid)
  14880. && (APP.RTC.localAudio || APP.RTC.localVideo)) {
  14881. // .connected is true while connecting?
  14882. doJoin();
  14883. }
  14884. }
  14885. function doJoin() {
  14886. var roomName = APP.UI.generateRoomName();
  14887. Moderator.allocateConferenceFocus(
  14888. roomName, APP.UI.checkForNicknameAndJoin);
  14889. }
  14890. function initStrophePlugins()
  14891. {
  14892. require("./strophe.emuc")(XMPP, eventEmitter);
  14893. require("./strophe.jingle")(XMPP, eventEmitter);
  14894. require("./strophe.moderate")(XMPP);
  14895. require("./strophe.util")();
  14896. require("./strophe.rayo")();
  14897. require("./strophe.logger")();
  14898. }
  14899. function registerListeners() {
  14900. APP.RTC.addStreamListener(maybeDoJoin,
  14901. StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  14902. APP.RTC.addListener(RTCEvents.AVAILABLE_DEVICES_CHANGED, function (devices) {
  14903. XMPP.addToPresence("devices", devices);
  14904. })
  14905. APP.UI.addListener(UIEvents.NICKNAME_CHANGED, function (nickname) {
  14906. XMPP.addToPresence("displayName", nickname);
  14907. });
  14908. }
  14909. function setupEvents() {
  14910. $(window).bind('beforeunload', function () {
  14911. if (connection && connection.connected) {
  14912. // ensure signout
  14913. $.ajax({
  14914. type: 'POST',
  14915. url: config.bosh,
  14916. async: false,
  14917. cache: false,
  14918. contentType: 'application/xml',
  14919. data: "<body rid='" + (connection.rid || connection._proto.rid)
  14920. + "' xmlns='http://jabber.org/protocol/httpbind' sid='"
  14921. + (connection.sid || connection._proto.sid)
  14922. + "' type='terminate'>" +
  14923. "<presence xmlns='jabber:client' type='unavailable'/>" +
  14924. "</body>",
  14925. success: function (data) {
  14926. console.log('signed out');
  14927. console.log(data);
  14928. },
  14929. error: function (XMLHttpRequest, textStatus, errorThrown) {
  14930. console.log('signout error',
  14931. textStatus + ' (' + errorThrown + ')');
  14932. }
  14933. });
  14934. }
  14935. XMPP.disposeConference(true);
  14936. });
  14937. }
  14938. var XMPP = {
  14939. sessionTerminated: false,
  14940. /**
  14941. * XMPP connection status
  14942. */
  14943. Status: Strophe.Status,
  14944. /**
  14945. * Remembers if we were muted by the focus.
  14946. * @type {boolean}
  14947. */
  14948. forceMuted: false,
  14949. start: function () {
  14950. setupEvents();
  14951. initStrophePlugins();
  14952. registerListeners();
  14953. Moderator.init(this, eventEmitter);
  14954. var configDomain = config.hosts.anonymousdomain || config.hosts.domain;
  14955. // Force authenticated domain if room is appended with '?login=true'
  14956. if (config.hosts.anonymousdomain &&
  14957. window.location.search.indexOf("login=true") !== -1) {
  14958. configDomain = config.hosts.domain;
  14959. }
  14960. var jid = configDomain || window.location.hostname;
  14961. connect(jid, null);
  14962. },
  14963. createConnection: function () {
  14964. var bosh = config.bosh || '/http-bind';
  14965. return new Strophe.Connection(bosh);
  14966. },
  14967. getStatusString: function (status) {
  14968. return Strophe.getStatusString(status);
  14969. },
  14970. promptLogin: function () {
  14971. // FIXME: re-use LoginDialog which supports retries
  14972. APP.UI.showLoginPopup(connect);
  14973. },
  14974. joinRoom: function(roomName, useNicks, nick)
  14975. {
  14976. var roomjid;
  14977. roomjid = roomName;
  14978. if (useNicks) {
  14979. if (nick) {
  14980. roomjid += '/' + nick;
  14981. } else {
  14982. roomjid += '/' + Strophe.getNodeFromJid(connection.jid);
  14983. }
  14984. } else {
  14985. var tmpJid = Strophe.getNodeFromJid(connection.jid);
  14986. if(!authenticatedUser)
  14987. tmpJid = tmpJid.substr(0, 8);
  14988. roomjid += '/' + tmpJid;
  14989. }
  14990. connection.emuc.doJoin(roomjid);
  14991. },
  14992. myJid: function () {
  14993. if(!connection)
  14994. return null;
  14995. return connection.emuc.myroomjid;
  14996. },
  14997. myResource: function () {
  14998. if(!connection || ! connection.emuc.myroomjid)
  14999. return null;
  15000. return Strophe.getResourceFromJid(connection.emuc.myroomjid);
  15001. },
  15002. disposeConference: function (onUnload) {
  15003. eventEmitter.emit(XMPPEvents.DISPOSE_CONFERENCE, onUnload);
  15004. var handler = connection.jingle.activecall;
  15005. if (handler && handler.peerconnection) {
  15006. // FIXME: probably removing streams is not required and close() should
  15007. // be enough
  15008. if (APP.RTC.localAudio) {
  15009. handler.peerconnection.removeStream(
  15010. APP.RTC.localAudio.getOriginalStream(), onUnload);
  15011. }
  15012. if (APP.RTC.localVideo) {
  15013. handler.peerconnection.removeStream(
  15014. APP.RTC.localVideo.getOriginalStream(), onUnload);
  15015. }
  15016. handler.peerconnection.close();
  15017. }
  15018. connection.jingle.activecall = null;
  15019. if(!onUnload)
  15020. {
  15021. this.sessionTerminated = true;
  15022. connection.emuc.doLeave();
  15023. }
  15024. },
  15025. addListener: function(type, listener)
  15026. {
  15027. eventEmitter.on(type, listener);
  15028. },
  15029. removeListener: function (type, listener) {
  15030. eventEmitter.removeListener(type, listener);
  15031. },
  15032. allocateConferenceFocus: function(roomName, callback) {
  15033. Moderator.allocateConferenceFocus(roomName, callback);
  15034. },
  15035. getLoginUrl: function (roomName, callback) {
  15036. Moderator.getLoginUrl(roomName, callback);
  15037. },
  15038. getPopupLoginUrl: function (roomName, callback) {
  15039. Moderator.getPopupLoginUrl(roomName, callback);
  15040. },
  15041. isModerator: function () {
  15042. return Moderator.isModerator();
  15043. },
  15044. isSipGatewayEnabled: function () {
  15045. return Moderator.isSipGatewayEnabled();
  15046. },
  15047. isExternalAuthEnabled: function () {
  15048. return Moderator.isExternalAuthEnabled();
  15049. },
  15050. switchStreams: function (stream, oldStream, callback) {
  15051. if (connection && connection.jingle.activecall) {
  15052. // FIXME: will block switchInProgress on true value in case of exception
  15053. connection.jingle.activecall.switchStreams(stream, oldStream, callback);
  15054. } else {
  15055. // We are done immediately
  15056. console.warn("No conference handler or conference not started yet");
  15057. callback();
  15058. }
  15059. },
  15060. sendVideoInfoPresence: function (mute) {
  15061. connection.emuc.addVideoInfoToPresence(mute);
  15062. connection.emuc.sendPresence();
  15063. },
  15064. setVideoMute: function (mute, callback, options) {
  15065. if(!connection)
  15066. return;
  15067. var self = this;
  15068. var localCallback = function (mute) {
  15069. self.sendVideoInfoPresence(mute);
  15070. return callback(mute);
  15071. };
  15072. if(connection.jingle.activecall)
  15073. {
  15074. connection.jingle.activecall.setVideoMute(
  15075. mute, localCallback, options);
  15076. }
  15077. else {
  15078. localCallback(mute);
  15079. }
  15080. },
  15081. setAudioMute: function (mute, callback) {
  15082. if (!(connection && APP.RTC.localAudio)) {
  15083. return false;
  15084. }
  15085. if (this.forceMuted && !mute) {
  15086. console.info("Asking focus for unmute");
  15087. connection.moderate.setMute(connection.emuc.myroomjid, mute);
  15088. // FIXME: wait for result before resetting muted status
  15089. this.forceMuted = false;
  15090. }
  15091. if (mute == APP.RTC.localAudio.isMuted()) {
  15092. // Nothing to do
  15093. return true;
  15094. }
  15095. // It is not clear what is the right way to handle multiple tracks.
  15096. // So at least make sure that they are all muted or all unmuted and
  15097. // that we send presence just once.
  15098. APP.RTC.localAudio.mute();
  15099. // isMuted is the opposite of audioEnabled
  15100. connection.emuc.addAudioInfoToPresence(mute);
  15101. connection.emuc.sendPresence();
  15102. callback();
  15103. return true;
  15104. },
  15105. // Really mute video, i.e. dont even send black frames
  15106. muteVideo: function (pc, unmute) {
  15107. // FIXME: this probably needs another of those lovely state safeguards...
  15108. // which checks for iceconn == connected and sigstate == stable
  15109. pc.setRemoteDescription(pc.remoteDescription,
  15110. function () {
  15111. pc.createAnswer(
  15112. function (answer) {
  15113. var sdp = new SDP(answer.sdp);
  15114. if (sdp.media.length > 1) {
  15115. if (unmute)
  15116. sdp.media[1] = sdp.media[1].replace('a=recvonly', 'a=sendrecv');
  15117. else
  15118. sdp.media[1] = sdp.media[1].replace('a=sendrecv', 'a=recvonly');
  15119. sdp.raw = sdp.session + sdp.media.join('');
  15120. answer.sdp = sdp.raw;
  15121. }
  15122. pc.setLocalDescription(answer,
  15123. function () {
  15124. console.log('mute SLD ok');
  15125. },
  15126. function (error) {
  15127. console.log('mute SLD error');
  15128. APP.UI.messageHandler.showError("dialog.error",
  15129. "dialog.SLDFailure");
  15130. }
  15131. );
  15132. },
  15133. function (error) {
  15134. console.log(error);
  15135. APP.UI.messageHandler.showError();
  15136. }
  15137. );
  15138. },
  15139. function (error) {
  15140. console.log('muteVideo SRD error');
  15141. APP.UI.messageHandler.showError("dialog.error",
  15142. "dialog.SRDFailure");
  15143. }
  15144. );
  15145. },
  15146. toggleRecording: function (tokenEmptyCallback,
  15147. startingCallback, startedCallback) {
  15148. Recording.toggleRecording(tokenEmptyCallback,
  15149. startingCallback, startedCallback, connection);
  15150. },
  15151. addToPresence: function (name, value, dontSend) {
  15152. switch (name)
  15153. {
  15154. case "displayName":
  15155. connection.emuc.addDisplayNameToPresence(value);
  15156. break;
  15157. case "etherpad":
  15158. connection.emuc.addEtherpadToPresence(value);
  15159. break;
  15160. case "prezi":
  15161. connection.emuc.addPreziToPresence(value, 0);
  15162. break;
  15163. case "preziSlide":
  15164. connection.emuc.addCurrentSlideToPresence(value);
  15165. break;
  15166. case "connectionQuality":
  15167. connection.emuc.addConnectionInfoToPresence(value);
  15168. break;
  15169. case "email":
  15170. connection.emuc.addEmailToPresence(value);
  15171. break;
  15172. case "devices":
  15173. connection.emuc.addDevicesToPresence(value);
  15174. break;
  15175. default :
  15176. console.log("Unknown tag for presence: " + name);
  15177. return;
  15178. }
  15179. if (!dontSend)
  15180. connection.emuc.sendPresence();
  15181. },
  15182. /**
  15183. * Sends 'data' as a log message to the focus. Returns true iff a message
  15184. * was sent.
  15185. * @param data
  15186. * @returns {boolean} true iff a message was sent.
  15187. */
  15188. sendLogs: function (data) {
  15189. if(!connection.emuc.focusMucJid)
  15190. return false;
  15191. var deflate = true;
  15192. var content = JSON.stringify(data);
  15193. if (deflate) {
  15194. content = String.fromCharCode.apply(null, Pako.deflateRaw(content));
  15195. }
  15196. content = Base64.encode(content);
  15197. // XEP-0337-ish
  15198. var message = $msg({to: connection.emuc.focusMucJid, type: 'normal'});
  15199. message.c('log', { xmlns: 'urn:xmpp:eventlog',
  15200. id: 'PeerConnectionStats'});
  15201. message.c('message').t(content).up();
  15202. if (deflate) {
  15203. message.c('tag', {name: "deflated", value: "true"}).up();
  15204. }
  15205. message.up();
  15206. connection.send(message);
  15207. return true;
  15208. },
  15209. populateData: function () {
  15210. var data = {};
  15211. if (connection.jingle) {
  15212. data = connection.jingle.populateData();
  15213. }
  15214. return data;
  15215. },
  15216. getLogger: function () {
  15217. if(connection.logger)
  15218. return connection.logger.log;
  15219. return null;
  15220. },
  15221. getPrezi: function () {
  15222. return connection.emuc.getPrezi(this.myJid());
  15223. },
  15224. removePreziFromPresence: function () {
  15225. connection.emuc.removePreziFromPresence();
  15226. connection.emuc.sendPresence();
  15227. },
  15228. sendChatMessage: function (message, nickname) {
  15229. connection.emuc.sendMessage(message, nickname);
  15230. },
  15231. setSubject: function (topic) {
  15232. connection.emuc.setSubject(topic);
  15233. },
  15234. lockRoom: function (key, onSuccess, onError, onNotSupported) {
  15235. connection.emuc.lockRoom(key, onSuccess, onError, onNotSupported);
  15236. },
  15237. dial: function (to, from, roomName,roomPass) {
  15238. connection.rayo.dial(to, from, roomName,roomPass);
  15239. },
  15240. setMute: function (jid, mute) {
  15241. connection.moderate.setMute(jid, mute);
  15242. },
  15243. eject: function (jid) {
  15244. connection.moderate.eject(jid);
  15245. },
  15246. logout: function (callback) {
  15247. Moderator.logout(callback);
  15248. },
  15249. findJidFromResource: function (resource) {
  15250. return connection.emuc.findJidFromResource(resource);
  15251. },
  15252. getMembers: function () {
  15253. return connection.emuc.members;
  15254. },
  15255. getJidFromSSRC: function (ssrc) {
  15256. if(!connection)
  15257. return null;
  15258. return connection.emuc.ssrc2jid[ssrc];
  15259. },
  15260. getMUCJoined: function () {
  15261. return connection.emuc.joined;
  15262. },
  15263. getSessions: function () {
  15264. return connection.jingle.sessions;
  15265. },
  15266. removeStream: function (stream) {
  15267. if(!connection || !connection.jingle.activecall ||
  15268. !connection.jingle.activecall.peerconnection)
  15269. return;
  15270. connection.jingle.activecall.peerconnection.removeStream(stream);
  15271. }
  15272. };
  15273. module.exports = XMPP;
  15274. },{"../../service/RTC/RTCEvents":89,"../../service/RTC/StreamEventTypes":91,"../../service/UI/UIEvents":92,"../../service/xmpp/XMPPEvents":97,"../settings/Settings":38,"./SDP":49,"./moderator":53,"./recording":54,"./strophe.emuc":55,"./strophe.jingle":56,"./strophe.logger":57,"./strophe.moderate":58,"./strophe.rayo":59,"./strophe.util":60,"events":98,"pako":63}],62:[function(require,module,exports){
  15275. // i18next, v1.7.7
  15276. // Copyright (c)2014 Jan Mühlemann (jamuhl).
  15277. // Distributed under MIT license
  15278. // http://i18next.com
  15279. (function() {
  15280. // add indexOf to non ECMA-262 standard compliant browsers
  15281. if (!Array.prototype.indexOf) {
  15282. Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
  15283. "use strict";
  15284. if (this == null) {
  15285. throw new TypeError();
  15286. }
  15287. var t = Object(this);
  15288. var len = t.length >>> 0;
  15289. if (len === 0) {
  15290. return -1;
  15291. }
  15292. var n = 0;
  15293. if (arguments.length > 0) {
  15294. n = Number(arguments[1]);
  15295. if (n != n) { // shortcut for verifying if it's NaN
  15296. n = 0;
  15297. } else if (n != 0 && n != Infinity && n != -Infinity) {
  15298. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  15299. }
  15300. }
  15301. if (n >= len) {
  15302. return -1;
  15303. }
  15304. var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
  15305. for (; k < len; k++) {
  15306. if (k in t && t[k] === searchElement) {
  15307. return k;
  15308. }
  15309. }
  15310. return -1;
  15311. }
  15312. }
  15313. // add lastIndexOf to non ECMA-262 standard compliant browsers
  15314. if (!Array.prototype.lastIndexOf) {
  15315. Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
  15316. "use strict";
  15317. if (this == null) {
  15318. throw new TypeError();
  15319. }
  15320. var t = Object(this);
  15321. var len = t.length >>> 0;
  15322. if (len === 0) {
  15323. return -1;
  15324. }
  15325. var n = len;
  15326. if (arguments.length > 1) {
  15327. n = Number(arguments[1]);
  15328. if (n != n) {
  15329. n = 0;
  15330. } else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
  15331. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  15332. }
  15333. }
  15334. var k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n);
  15335. for (; k >= 0; k--) {
  15336. if (k in t && t[k] === searchElement) {
  15337. return k;
  15338. }
  15339. }
  15340. return -1;
  15341. };
  15342. }
  15343. // Add string trim for IE8.
  15344. if (typeof String.prototype.trim !== 'function') {
  15345. String.prototype.trim = function() {
  15346. return this.replace(/^\s+|\s+$/g, '');
  15347. }
  15348. }
  15349. var root = this
  15350. , $ = root.jQuery || root.Zepto
  15351. , i18n = {}
  15352. , resStore = {}
  15353. , currentLng
  15354. , replacementCounter = 0
  15355. , languages = []
  15356. , initialized = false
  15357. , sync = {};
  15358. // Export the i18next object for **CommonJS**.
  15359. // If we're not in CommonJS, add `i18n` to the
  15360. // global object or to jquery.
  15361. if (typeof module !== 'undefined' && module.exports) {
  15362. if (!$) {
  15363. try {
  15364. $ = require('jquery');
  15365. } catch(e) {
  15366. // just ignore
  15367. }
  15368. }
  15369. if ($) {
  15370. $.i18n = $.i18n || i18n;
  15371. }
  15372. module.exports = i18n;
  15373. } else {
  15374. if ($) {
  15375. $.i18n = $.i18n || i18n;
  15376. }
  15377. root.i18n = root.i18n || i18n;
  15378. }
  15379. sync = {
  15380. load: function(lngs, options, cb) {
  15381. if (options.useLocalStorage) {
  15382. sync._loadLocal(lngs, options, function(err, store) {
  15383. var missingLngs = [];
  15384. for (var i = 0, len = lngs.length; i < len; i++) {
  15385. if (!store[lngs[i]]) missingLngs.push(lngs[i]);
  15386. }
  15387. if (missingLngs.length > 0) {
  15388. sync._fetch(missingLngs, options, function(err, fetched) {
  15389. f.extend(store, fetched);
  15390. sync._storeLocal(fetched);
  15391. cb(null, store);
  15392. });
  15393. } else {
  15394. cb(null, store);
  15395. }
  15396. });
  15397. } else {
  15398. sync._fetch(lngs, options, function(err, store){
  15399. cb(null, store);
  15400. });
  15401. }
  15402. },
  15403. _loadLocal: function(lngs, options, cb) {
  15404. var store = {}
  15405. , nowMS = new Date().getTime();
  15406. if(window.localStorage) {
  15407. var todo = lngs.length;
  15408. f.each(lngs, function(key, lng) {
  15409. var local = window.localStorage.getItem('res_' + lng);
  15410. if (local) {
  15411. local = JSON.parse(local);
  15412. if (local.i18nStamp && local.i18nStamp + options.localStorageExpirationTime > nowMS) {
  15413. store[lng] = local;
  15414. }
  15415. }
  15416. todo--; // wait for all done befor callback
  15417. if (todo === 0) cb(null, store);
  15418. });
  15419. }
  15420. },
  15421. _storeLocal: function(store) {
  15422. if(window.localStorage) {
  15423. for (var m in store) {
  15424. store[m].i18nStamp = new Date().getTime();
  15425. f.localStorage.setItem('res_' + m, JSON.stringify(store[m]));
  15426. }
  15427. }
  15428. return;
  15429. },
  15430. _fetch: function(lngs, options, cb) {
  15431. var ns = options.ns
  15432. , store = {};
  15433. if (!options.dynamicLoad) {
  15434. var todo = ns.namespaces.length * lngs.length
  15435. , errors;
  15436. // load each file individual
  15437. f.each(ns.namespaces, function(nsIndex, nsValue) {
  15438. f.each(lngs, function(lngIndex, lngValue) {
  15439. // Call this once our translation has returned.
  15440. var loadComplete = function(err, data) {
  15441. if (err) {
  15442. errors = errors || [];
  15443. errors.push(err);
  15444. }
  15445. store[lngValue] = store[lngValue] || {};
  15446. store[lngValue][nsValue] = data;
  15447. todo--; // wait for all done befor callback
  15448. if (todo === 0) cb(errors, store);
  15449. };
  15450. if(typeof options.customLoad == 'function'){
  15451. // Use the specified custom callback.
  15452. options.customLoad(lngValue, nsValue, options, loadComplete);
  15453. } else {
  15454. //~ // Use our inbuilt sync.
  15455. sync._fetchOne(lngValue, nsValue, options, loadComplete);
  15456. }
  15457. });
  15458. });
  15459. } else {
  15460. // Call this once our translation has returned.
  15461. var loadComplete = function(err, data) {
  15462. cb(null, data);
  15463. };
  15464. if(typeof options.customLoad == 'function'){
  15465. // Use the specified custom callback.
  15466. options.customLoad(lngs, ns.namespaces, options, loadComplete);
  15467. } else {
  15468. var url = applyReplacement(options.resGetPath, { lng: lngs.join('+'), ns: ns.namespaces.join('+') });
  15469. // load all needed stuff once
  15470. f.ajax({
  15471. url: url,
  15472. success: function(data, status, xhr) {
  15473. f.log('loaded: ' + url);
  15474. loadComplete(null, data);
  15475. },
  15476. error : function(xhr, status, error) {
  15477. f.log('failed loading: ' + url);
  15478. loadComplete('failed loading resource.json error: ' + error);
  15479. },
  15480. dataType: "json",
  15481. async : options.getAsync
  15482. });
  15483. }
  15484. }
  15485. },
  15486. _fetchOne: function(lng, ns, options, done) {
  15487. var url = applyReplacement(options.resGetPath, { lng: lng, ns: ns });
  15488. f.ajax({
  15489. url: url,
  15490. success: function(data, status, xhr) {
  15491. f.log('loaded: ' + url);
  15492. done(null, data);
  15493. },
  15494. error : function(xhr, status, error) {
  15495. if ((status && status == 200) || (xhr && xhr.status && xhr.status == 200)) {
  15496. // file loaded but invalid json, stop waste time !
  15497. f.error('There is a typo in: ' + url);
  15498. } else if ((status && status == 404) || (xhr && xhr.status && xhr.status == 404)) {
  15499. f.log('Does not exist: ' + url);
  15500. } else {
  15501. var theStatus = status ? status : ((xhr && xhr.status) ? xhr.status : null);
  15502. f.log(theStatus + ' when loading ' + url);
  15503. }
  15504. done(error, {});
  15505. },
  15506. dataType: "json",
  15507. async : options.getAsync
  15508. });
  15509. },
  15510. postMissing: function(lng, ns, key, defaultValue, lngs) {
  15511. var payload = {};
  15512. payload[key] = defaultValue;
  15513. var urls = [];
  15514. if (o.sendMissingTo === 'fallback' && o.fallbackLng[0] !== false) {
  15515. for (var i = 0; i < o.fallbackLng.length; i++) {
  15516. urls.push({lng: o.fallbackLng[i], url: applyReplacement(o.resPostPath, { lng: o.fallbackLng[i], ns: ns })});
  15517. }
  15518. } else if (o.sendMissingTo === 'current' || (o.sendMissingTo === 'fallback' && o.fallbackLng[0] === false) ) {
  15519. urls.push({lng: lng, url: applyReplacement(o.resPostPath, { lng: lng, ns: ns })});
  15520. } else if (o.sendMissingTo === 'all') {
  15521. for (var i = 0, l = lngs.length; i < l; i++) {
  15522. urls.push({lng: lngs[i], url: applyReplacement(o.resPostPath, { lng: lngs[i], ns: ns })});
  15523. }
  15524. }
  15525. for (var y = 0, len = urls.length; y < len; y++) {
  15526. var item = urls[y];
  15527. f.ajax({
  15528. url: item.url,
  15529. type: o.sendType,
  15530. data: payload,
  15531. success: function(data, status, xhr) {
  15532. f.log('posted missing key \'' + key + '\' to: ' + item.url);
  15533. // add key to resStore
  15534. var keys = key.split('.');
  15535. var x = 0;
  15536. var value = resStore[item.lng][ns];
  15537. while (keys[x]) {
  15538. if (x === keys.length - 1) {
  15539. value = value[keys[x]] = defaultValue;
  15540. } else {
  15541. value = value[keys[x]] = value[keys[x]] || {};
  15542. }
  15543. x++;
  15544. }
  15545. },
  15546. error : function(xhr, status, error) {
  15547. f.log('failed posting missing key \'' + key + '\' to: ' + item.url);
  15548. },
  15549. dataType: "json",
  15550. async : o.postAsync
  15551. });
  15552. }
  15553. },
  15554. reload: reload
  15555. };
  15556. // defaults
  15557. var o = {
  15558. lng: undefined,
  15559. load: 'all',
  15560. preload: [],
  15561. lowerCaseLng: false,
  15562. returnObjectTrees: false,
  15563. fallbackLng: ['dev'],
  15564. fallbackNS: [],
  15565. detectLngQS: 'setLng',
  15566. detectLngFromLocalStorage: false,
  15567. ns: 'translation',
  15568. fallbackOnNull: true,
  15569. fallbackOnEmpty: false,
  15570. fallbackToDefaultNS: false,
  15571. nsseparator: ':',
  15572. keyseparator: '.',
  15573. selectorAttr: 'data-i18n',
  15574. debug: false,
  15575. resGetPath: 'locales/__lng__/__ns__.json',
  15576. resPostPath: 'locales/add/__lng__/__ns__',
  15577. getAsync: true,
  15578. postAsync: true,
  15579. resStore: undefined,
  15580. useLocalStorage: false,
  15581. localStorageExpirationTime: 7*24*60*60*1000,
  15582. dynamicLoad: false,
  15583. sendMissing: false,
  15584. sendMissingTo: 'fallback', // current | all
  15585. sendType: 'POST',
  15586. interpolationPrefix: '__',
  15587. interpolationSuffix: '__',
  15588. defaultVariables: false,
  15589. reusePrefix: '$t(',
  15590. reuseSuffix: ')',
  15591. pluralSuffix: '_plural',
  15592. pluralNotFound: ['plural_not_found', Math.random()].join(''),
  15593. contextNotFound: ['context_not_found', Math.random()].join(''),
  15594. escapeInterpolation: false,
  15595. indefiniteSuffix: '_indefinite',
  15596. indefiniteNotFound: ['indefinite_not_found', Math.random()].join(''),
  15597. setJqueryExt: true,
  15598. defaultValueFromContent: true,
  15599. useDataAttrOptions: false,
  15600. cookieExpirationTime: undefined,
  15601. useCookie: true,
  15602. cookieName: 'i18next',
  15603. cookieDomain: undefined,
  15604. objectTreeKeyHandler: undefined,
  15605. postProcess: undefined,
  15606. parseMissingKey: undefined,
  15607. missingKeyHandler: sync.postMissing,
  15608. shortcutFunction: 'sprintf' // or: defaultValue
  15609. };
  15610. function _extend(target, source) {
  15611. if (!source || typeof source === 'function') {
  15612. return target;
  15613. }
  15614. for (var attr in source) { target[attr] = source[attr]; }
  15615. return target;
  15616. }
  15617. function _deepExtend(target, source) {
  15618. for (var prop in source)
  15619. if (prop in target)
  15620. _deepExtend(target[prop], source[prop]);
  15621. else
  15622. target[prop] = source[prop];
  15623. return target;
  15624. }
  15625. function _each(object, callback, args) {
  15626. var name, i = 0,
  15627. length = object.length,
  15628. isObj = length === undefined || Object.prototype.toString.apply(object) !== '[object Array]' || typeof object === "function";
  15629. if (args) {
  15630. if (isObj) {
  15631. for (name in object) {
  15632. if (callback.apply(object[name], args) === false) {
  15633. break;
  15634. }
  15635. }
  15636. } else {
  15637. for ( ; i < length; ) {
  15638. if (callback.apply(object[i++], args) === false) {
  15639. break;
  15640. }
  15641. }
  15642. }
  15643. // A special, fast, case for the most common use of each
  15644. } else {
  15645. if (isObj) {
  15646. for (name in object) {
  15647. if (callback.call(object[name], name, object[name]) === false) {
  15648. break;
  15649. }
  15650. }
  15651. } else {
  15652. for ( ; i < length; ) {
  15653. if (callback.call(object[i], i, object[i++]) === false) {
  15654. break;
  15655. }
  15656. }
  15657. }
  15658. }
  15659. return object;
  15660. }
  15661. var _entityMap = {
  15662. "&": "&amp;",
  15663. "<": "&lt;",
  15664. ">": "&gt;",
  15665. '"': '&quot;',
  15666. "'": '&#39;',
  15667. "/": '&#x2F;'
  15668. };
  15669. function _escape(data) {
  15670. if (typeof data === 'string') {
  15671. return data.replace(/[&<>"'\/]/g, function (s) {
  15672. return _entityMap[s];
  15673. });
  15674. }else{
  15675. return data;
  15676. }
  15677. }
  15678. function _ajax(options) {
  15679. // v0.5.0 of https://github.com/goloroden/http.js
  15680. var getXhr = function (callback) {
  15681. // Use the native XHR object if the browser supports it.
  15682. if (window.XMLHttpRequest) {
  15683. return callback(null, new XMLHttpRequest());
  15684. } else if (window.ActiveXObject) {
  15685. // In Internet Explorer check for ActiveX versions of the XHR object.
  15686. try {
  15687. return callback(null, new ActiveXObject("Msxml2.XMLHTTP"));
  15688. } catch (e) {
  15689. return callback(null, new ActiveXObject("Microsoft.XMLHTTP"));
  15690. }
  15691. }
  15692. // If no XHR support was found, throw an error.
  15693. return callback(new Error());
  15694. };
  15695. var encodeUsingUrlEncoding = function (data) {
  15696. if(typeof data === 'string') {
  15697. return data;
  15698. }
  15699. var result = [];
  15700. for(var dataItem in data) {
  15701. if(data.hasOwnProperty(dataItem)) {
  15702. result.push(encodeURIComponent(dataItem) + '=' + encodeURIComponent(data[dataItem]));
  15703. }
  15704. }
  15705. return result.join('&');
  15706. };
  15707. var utf8 = function (text) {
  15708. text = text.replace(/\r\n/g, '\n');
  15709. var result = '';
  15710. for(var i = 0; i < text.length; i++) {
  15711. var c = text.charCodeAt(i);
  15712. if(c < 128) {
  15713. result += String.fromCharCode(c);
  15714. } else if((c > 127) && (c < 2048)) {
  15715. result += String.fromCharCode((c >> 6) | 192);
  15716. result += String.fromCharCode((c & 63) | 128);
  15717. } else {
  15718. result += String.fromCharCode((c >> 12) | 224);
  15719. result += String.fromCharCode(((c >> 6) & 63) | 128);
  15720. result += String.fromCharCode((c & 63) | 128);
  15721. }
  15722. }
  15723. return result;
  15724. };
  15725. var base64 = function (text) {
  15726. var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  15727. text = utf8(text);
  15728. var result = '',
  15729. chr1, chr2, chr3,
  15730. enc1, enc2, enc3, enc4,
  15731. i = 0;
  15732. do {
  15733. chr1 = text.charCodeAt(i++);
  15734. chr2 = text.charCodeAt(i++);
  15735. chr3 = text.charCodeAt(i++);
  15736. enc1 = chr1 >> 2;
  15737. enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  15738. enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  15739. enc4 = chr3 & 63;
  15740. if(isNaN(chr2)) {
  15741. enc3 = enc4 = 64;
  15742. } else if(isNaN(chr3)) {
  15743. enc4 = 64;
  15744. }
  15745. result +=
  15746. keyStr.charAt(enc1) +
  15747. keyStr.charAt(enc2) +
  15748. keyStr.charAt(enc3) +
  15749. keyStr.charAt(enc4);
  15750. chr1 = chr2 = chr3 = '';
  15751. enc1 = enc2 = enc3 = enc4 = '';
  15752. } while(i < text.length);
  15753. return result;
  15754. };
  15755. var mergeHeaders = function () {
  15756. // Use the first header object as base.
  15757. var result = arguments[0];
  15758. // Iterate through the remaining header objects and add them.
  15759. for(var i = 1; i < arguments.length; i++) {
  15760. var currentHeaders = arguments[i];
  15761. for(var header in currentHeaders) {
  15762. if(currentHeaders.hasOwnProperty(header)) {
  15763. result[header] = currentHeaders[header];
  15764. }
  15765. }
  15766. }
  15767. // Return the merged headers.
  15768. return result;
  15769. };
  15770. var ajax = function (method, url, options, callback) {
  15771. // Adjust parameters.
  15772. if(typeof options === 'function') {
  15773. callback = options;
  15774. options = {};
  15775. }
  15776. // Set default parameter values.
  15777. options.cache = options.cache || false;
  15778. options.data = options.data || {};
  15779. options.headers = options.headers || {};
  15780. options.jsonp = options.jsonp || false;
  15781. options.async = options.async === undefined ? true : options.async;
  15782. // Merge the various header objects.
  15783. var headers = mergeHeaders({
  15784. 'accept': '*/*',
  15785. 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
  15786. }, ajax.headers, options.headers);
  15787. // Encode the data according to the content-type.
  15788. var payload;
  15789. if (headers['content-type'] === 'application/json') {
  15790. payload = JSON.stringify(options.data);
  15791. } else {
  15792. payload = encodeUsingUrlEncoding(options.data);
  15793. }
  15794. // Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call
  15795. // if neccessary.
  15796. if(method === 'GET') {
  15797. // Setup the query string.
  15798. var queryString = [];
  15799. if(payload) {
  15800. queryString.push(payload);
  15801. payload = null;
  15802. }
  15803. // Handle caching.
  15804. if(!options.cache) {
  15805. queryString.push('_=' + (new Date()).getTime());
  15806. }
  15807. // If neccessary prepare the query string for a JSONP call.
  15808. if(options.jsonp) {
  15809. queryString.push('callback=' + options.jsonp);
  15810. queryString.push('jsonp=' + options.jsonp);
  15811. }
  15812. // Merge the query string and attach it to the url.
  15813. queryString = queryString.join('&');
  15814. if (queryString.length > 1) {
  15815. if (url.indexOf('?') > -1) {
  15816. url += '&' + queryString;
  15817. } else {
  15818. url += '?' + queryString;
  15819. }
  15820. }
  15821. // Make a JSONP call if neccessary.
  15822. if(options.jsonp) {
  15823. var head = document.getElementsByTagName('head')[0];
  15824. var script = document.createElement('script');
  15825. script.type = 'text/javascript';
  15826. script.src = url;
  15827. head.appendChild(script);
  15828. return;
  15829. }
  15830. }
  15831. // Since we got here, it is no JSONP request, so make a normal XHR request.
  15832. getXhr(function (err, xhr) {
  15833. if(err) return callback(err);
  15834. // Open the request.
  15835. xhr.open(method, url, options.async);
  15836. // Set the request headers.
  15837. for(var header in headers) {
  15838. if(headers.hasOwnProperty(header)) {
  15839. xhr.setRequestHeader(header, headers[header]);
  15840. }
  15841. }
  15842. // Handle the request events.
  15843. xhr.onreadystatechange = function () {
  15844. if(xhr.readyState === 4) {
  15845. var data = xhr.responseText || '';
  15846. // If no callback is given, return.
  15847. if(!callback) {
  15848. return;
  15849. }
  15850. // Return an object that provides access to the data as text and JSON.
  15851. callback(xhr.status, {
  15852. text: function () {
  15853. return data;
  15854. },
  15855. json: function () {
  15856. try {
  15857. return JSON.parse(data)
  15858. } catch (e) {
  15859. f.error('Can not parse JSON. URL: ' + url);
  15860. return {};
  15861. }
  15862. }
  15863. });
  15864. }
  15865. };
  15866. // Actually send the XHR request.
  15867. xhr.send(payload);
  15868. });
  15869. };
  15870. // Define the external interface.
  15871. var http = {
  15872. authBasic: function (username, password) {
  15873. ajax.headers['Authorization'] = 'Basic ' + base64(username + ':' + password);
  15874. },
  15875. connect: function (url, options, callback) {
  15876. return ajax('CONNECT', url, options, callback);
  15877. },
  15878. del: function (url, options, callback) {
  15879. return ajax('DELETE', url, options, callback);
  15880. },
  15881. get: function (url, options, callback) {
  15882. return ajax('GET', url, options, callback);
  15883. },
  15884. head: function (url, options, callback) {
  15885. return ajax('HEAD', url, options, callback);
  15886. },
  15887. headers: function (headers) {
  15888. ajax.headers = headers || {};
  15889. },
  15890. isAllowed: function (url, verb, callback) {
  15891. this.options(url, function (status, data) {
  15892. callback(data.text().indexOf(verb) !== -1);
  15893. });
  15894. },
  15895. options: function (url, options, callback) {
  15896. return ajax('OPTIONS', url, options, callback);
  15897. },
  15898. patch: function (url, options, callback) {
  15899. return ajax('PATCH', url, options, callback);
  15900. },
  15901. post: function (url, options, callback) {
  15902. return ajax('POST', url, options, callback);
  15903. },
  15904. put: function (url, options, callback) {
  15905. return ajax('PUT', url, options, callback);
  15906. },
  15907. trace: function (url, options, callback) {
  15908. return ajax('TRACE', url, options, callback);
  15909. }
  15910. };
  15911. var methode = options.type ? options.type.toLowerCase() : 'get';
  15912. http[methode](options.url, options, function (status, data) {
  15913. // file: protocol always gives status code 0, so check for data
  15914. if (status === 200 || (status === 0 && data.text())) {
  15915. options.success(data.json(), status, null);
  15916. } else {
  15917. options.error(data.text(), status, null);
  15918. }
  15919. });
  15920. }
  15921. var _cookie = {
  15922. create: function(name,value,minutes,domain) {
  15923. var expires;
  15924. if (minutes) {
  15925. var date = new Date();
  15926. date.setTime(date.getTime()+(minutes*60*1000));
  15927. expires = "; expires="+date.toGMTString();
  15928. }
  15929. else expires = "";
  15930. domain = (domain)? "domain="+domain+";" : "";
  15931. document.cookie = name+"="+value+expires+";"+domain+"path=/";
  15932. },
  15933. read: function(name) {
  15934. var nameEQ = name + "=";
  15935. var ca = document.cookie.split(';');
  15936. for(var i=0;i < ca.length;i++) {
  15937. var c = ca[i];
  15938. while (c.charAt(0)==' ') c = c.substring(1,c.length);
  15939. if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
  15940. }
  15941. return null;
  15942. },
  15943. remove: function(name) {
  15944. this.create(name,"",-1);
  15945. }
  15946. };
  15947. var cookie_noop = {
  15948. create: function(name,value,minutes,domain) {},
  15949. read: function(name) { return null; },
  15950. remove: function(name) {}
  15951. };
  15952. // move dependent functions to a container so that
  15953. // they can be overriden easier in no jquery environment (node.js)
  15954. var f = {
  15955. extend: $ ? $.extend : _extend,
  15956. deepExtend: _deepExtend,
  15957. each: $ ? $.each : _each,
  15958. ajax: $ ? $.ajax : (typeof document !== 'undefined' ? _ajax : function() {}),
  15959. cookie: typeof document !== 'undefined' ? _cookie : cookie_noop,
  15960. detectLanguage: detectLanguage,
  15961. escape: _escape,
  15962. log: function(str) {
  15963. if (o.debug && typeof console !== "undefined") console.log(str);
  15964. },
  15965. error: function(str) {
  15966. if (typeof console !== "undefined") console.error(str);
  15967. },
  15968. getCountyIndexOfLng: function(lng) {
  15969. var lng_index = 0;
  15970. if (lng === 'nb-NO' || lng === 'nn-NO' || lng === 'nb-no' || lng === 'nn-no') lng_index = 1;
  15971. return lng_index;
  15972. },
  15973. toLanguages: function(lng) {
  15974. var log = this.log;
  15975. function applyCase(l) {
  15976. var ret = l;
  15977. if (typeof l === 'string' && l.indexOf('-') > -1) {
  15978. var parts = l.split('-');
  15979. ret = o.lowerCaseLng ?
  15980. parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
  15981. parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
  15982. } else {
  15983. ret = o.lowerCaseLng ? l.toLowerCase() : l;
  15984. }
  15985. return ret;
  15986. }
  15987. var languages = [];
  15988. var whitelist = o.lngWhitelist || false;
  15989. var addLanguage = function(language){
  15990. //reject langs not whitelisted
  15991. if(!whitelist || whitelist.indexOf(language) > -1){
  15992. languages.push(language);
  15993. }else{
  15994. log('rejecting non-whitelisted language: ' + language);
  15995. }
  15996. };
  15997. if (typeof lng === 'string' && lng.indexOf('-') > -1) {
  15998. var parts = lng.split('-');
  15999. if (o.load !== 'unspecific') addLanguage(applyCase(lng));
  16000. if (o.load !== 'current') addLanguage(applyCase(parts[this.getCountyIndexOfLng(lng)]));
  16001. } else {
  16002. addLanguage(applyCase(lng));
  16003. }
  16004. for (var i = 0; i < o.fallbackLng.length; i++) {
  16005. if (languages.indexOf(o.fallbackLng[i]) === -1 && o.fallbackLng[i]) languages.push(applyCase(o.fallbackLng[i]));
  16006. }
  16007. return languages;
  16008. },
  16009. regexEscape: function(str) {
  16010. return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  16011. },
  16012. regexReplacementEscape: function(strOrFn) {
  16013. if (typeof strOrFn === 'string') {
  16014. return strOrFn.replace(/\$/g, "$$$$");
  16015. } else {
  16016. return strOrFn;
  16017. }
  16018. },
  16019. localStorage: {
  16020. setItem: function(key, value) {
  16021. if (window.localStorage) {
  16022. try {
  16023. window.localStorage.setItem(key, value);
  16024. } catch (e) {
  16025. f.log('failed to set value for key "' + key + '" to localStorage.');
  16026. }
  16027. }
  16028. }
  16029. }
  16030. };
  16031. function init(options, cb) {
  16032. if (typeof options === 'function') {
  16033. cb = options;
  16034. options = {};
  16035. }
  16036. options = options || {};
  16037. // override defaults with passed in options
  16038. f.extend(o, options);
  16039. delete o.fixLng; /* passed in each time */
  16040. // override functions: .log(), .detectLanguage(), etc
  16041. if (o.functions) {
  16042. delete o.functions;
  16043. f.extend(f, options.functions);
  16044. }
  16045. // create namespace object if namespace is passed in as string
  16046. if (typeof o.ns == 'string') {
  16047. o.ns = { namespaces: [o.ns], defaultNs: o.ns};
  16048. }
  16049. // fallback namespaces
  16050. if (typeof o.fallbackNS == 'string') {
  16051. o.fallbackNS = [o.fallbackNS];
  16052. }
  16053. // fallback languages
  16054. if (typeof o.fallbackLng == 'string' || typeof o.fallbackLng == 'boolean') {
  16055. o.fallbackLng = [o.fallbackLng];
  16056. }
  16057. // escape prefix/suffix
  16058. o.interpolationPrefixEscaped = f.regexEscape(o.interpolationPrefix);
  16059. o.interpolationSuffixEscaped = f.regexEscape(o.interpolationSuffix);
  16060. if (!o.lng) o.lng = f.detectLanguage();
  16061. languages = f.toLanguages(o.lng);
  16062. currentLng = languages[0];
  16063. f.log('currentLng set to: ' + currentLng);
  16064. if (o.useCookie && f.cookie.read(o.cookieName) !== currentLng){ //cookie is unset or invalid
  16065. f.cookie.create(o.cookieName, currentLng, o.cookieExpirationTime, o.cookieDomain);
  16066. }
  16067. if (o.detectLngFromLocalStorage && typeof document !== 'undefined' && window.localStorage) {
  16068. f.localStorage.setItem('i18next_lng', currentLng);
  16069. }
  16070. var lngTranslate = translate;
  16071. if (options.fixLng) {
  16072. lngTranslate = function(key, options) {
  16073. options = options || {};
  16074. options.lng = options.lng || lngTranslate.lng;
  16075. return translate(key, options);
  16076. };
  16077. lngTranslate.lng = currentLng;
  16078. }
  16079. pluralExtensions.setCurrentLng(currentLng);
  16080. // add JQuery extensions
  16081. if ($ && o.setJqueryExt) addJqueryFunct();
  16082. // jQuery deferred
  16083. var deferred;
  16084. if ($ && $.Deferred) {
  16085. deferred = $.Deferred();
  16086. }
  16087. // return immidiatly if res are passed in
  16088. if (o.resStore) {
  16089. resStore = o.resStore;
  16090. initialized = true;
  16091. if (cb) cb(lngTranslate);
  16092. if (deferred) deferred.resolve(lngTranslate);
  16093. if (deferred) return deferred.promise();
  16094. return;
  16095. }
  16096. // languages to load
  16097. var lngsToLoad = f.toLanguages(o.lng);
  16098. if (typeof o.preload === 'string') o.preload = [o.preload];
  16099. for (var i = 0, l = o.preload.length; i < l; i++) {
  16100. var pres = f.toLanguages(o.preload[i]);
  16101. for (var y = 0, len = pres.length; y < len; y++) {
  16102. if (lngsToLoad.indexOf(pres[y]) < 0) {
  16103. lngsToLoad.push(pres[y]);
  16104. }
  16105. }
  16106. }
  16107. // else load them
  16108. i18n.sync.load(lngsToLoad, o, function(err, store) {
  16109. resStore = store;
  16110. initialized = true;
  16111. if (cb) cb(lngTranslate);
  16112. if (deferred) deferred.resolve(lngTranslate);
  16113. });
  16114. if (deferred) return deferred.promise();
  16115. }
  16116. function preload(lngs, cb) {
  16117. if (typeof lngs === 'string') lngs = [lngs];
  16118. for (var i = 0, l = lngs.length; i < l; i++) {
  16119. if (o.preload.indexOf(lngs[i]) < 0) {
  16120. o.preload.push(lngs[i]);
  16121. }
  16122. }
  16123. return init(cb);
  16124. }
  16125. function addResourceBundle(lng, ns, resources, deep) {
  16126. if (typeof ns !== 'string') {
  16127. resources = ns;
  16128. ns = o.ns.defaultNs;
  16129. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  16130. o.ns.namespaces.push(ns);
  16131. }
  16132. resStore[lng] = resStore[lng] || {};
  16133. resStore[lng][ns] = resStore[lng][ns] || {};
  16134. if (deep) {
  16135. f.deepExtend(resStore[lng][ns], resources);
  16136. } else {
  16137. f.extend(resStore[lng][ns], resources);
  16138. }
  16139. }
  16140. function hasResourceBundle(lng, ns) {
  16141. if (typeof ns !== 'string') {
  16142. ns = o.ns.defaultNs;
  16143. }
  16144. resStore[lng] = resStore[lng] || {};
  16145. var res = resStore[lng][ns] || {};
  16146. var hasValues = false;
  16147. for(var prop in res) {
  16148. if (res.hasOwnProperty(prop)) {
  16149. hasValues = true;
  16150. }
  16151. }
  16152. return hasValues;
  16153. }
  16154. function removeResourceBundle(lng, ns) {
  16155. if (typeof ns !== 'string') {
  16156. ns = o.ns.defaultNs;
  16157. }
  16158. resStore[lng] = resStore[lng] || {};
  16159. resStore[lng][ns] = {};
  16160. }
  16161. function addResource(lng, ns, key, value) {
  16162. if (typeof ns !== 'string') {
  16163. resource = ns;
  16164. ns = o.ns.defaultNs;
  16165. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  16166. o.ns.namespaces.push(ns);
  16167. }
  16168. resStore[lng] = resStore[lng] || {};
  16169. resStore[lng][ns] = resStore[lng][ns] || {};
  16170. var keys = key.split(o.keyseparator);
  16171. var x = 0;
  16172. var node = resStore[lng][ns];
  16173. var origRef = node;
  16174. while (keys[x]) {
  16175. if (x == keys.length - 1)
  16176. node[keys[x]] = value;
  16177. else {
  16178. if (node[keys[x]] == null)
  16179. node[keys[x]] = {};
  16180. node = node[keys[x]];
  16181. }
  16182. x++;
  16183. }
  16184. }
  16185. function addResources(lng, ns, resources) {
  16186. if (typeof ns !== 'string') {
  16187. resource = ns;
  16188. ns = o.ns.defaultNs;
  16189. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  16190. o.ns.namespaces.push(ns);
  16191. }
  16192. for (var m in resources) {
  16193. if (typeof resources[m] === 'string') addResource(lng, ns, m, resources[m]);
  16194. }
  16195. }
  16196. function setDefaultNamespace(ns) {
  16197. o.ns.defaultNs = ns;
  16198. }
  16199. function loadNamespace(namespace, cb) {
  16200. loadNamespaces([namespace], cb);
  16201. }
  16202. function loadNamespaces(namespaces, cb) {
  16203. var opts = {
  16204. dynamicLoad: o.dynamicLoad,
  16205. resGetPath: o.resGetPath,
  16206. getAsync: o.getAsync,
  16207. customLoad: o.customLoad,
  16208. ns: { namespaces: namespaces, defaultNs: ''} /* new namespaces to load */
  16209. };
  16210. // languages to load
  16211. var lngsToLoad = f.toLanguages(o.lng);
  16212. if (typeof o.preload === 'string') o.preload = [o.preload];
  16213. for (var i = 0, l = o.preload.length; i < l; i++) {
  16214. var pres = f.toLanguages(o.preload[i]);
  16215. for (var y = 0, len = pres.length; y < len; y++) {
  16216. if (lngsToLoad.indexOf(pres[y]) < 0) {
  16217. lngsToLoad.push(pres[y]);
  16218. }
  16219. }
  16220. }
  16221. // check if we have to load
  16222. var lngNeedLoad = [];
  16223. for (var a = 0, lenA = lngsToLoad.length; a < lenA; a++) {
  16224. var needLoad = false;
  16225. var resSet = resStore[lngsToLoad[a]];
  16226. if (resSet) {
  16227. for (var b = 0, lenB = namespaces.length; b < lenB; b++) {
  16228. if (!resSet[namespaces[b]]) needLoad = true;
  16229. }
  16230. } else {
  16231. needLoad = true;
  16232. }
  16233. if (needLoad) lngNeedLoad.push(lngsToLoad[a]);
  16234. }
  16235. if (lngNeedLoad.length) {
  16236. i18n.sync._fetch(lngNeedLoad, opts, function(err, store) {
  16237. var todo = namespaces.length * lngNeedLoad.length;
  16238. // load each file individual
  16239. f.each(namespaces, function(nsIndex, nsValue) {
  16240. // append namespace to namespace array
  16241. if (o.ns.namespaces.indexOf(nsValue) < 0) {
  16242. o.ns.namespaces.push(nsValue);
  16243. }
  16244. f.each(lngNeedLoad, function(lngIndex, lngValue) {
  16245. resStore[lngValue] = resStore[lngValue] || {};
  16246. resStore[lngValue][nsValue] = store[lngValue][nsValue];
  16247. todo--; // wait for all done befor callback
  16248. if (todo === 0 && cb) {
  16249. if (o.useLocalStorage) i18n.sync._storeLocal(resStore);
  16250. cb();
  16251. }
  16252. });
  16253. });
  16254. });
  16255. } else {
  16256. if (cb) cb();
  16257. }
  16258. }
  16259. function setLng(lng, options, cb) {
  16260. if (typeof options === 'function') {
  16261. cb = options;
  16262. options = {};
  16263. } else if (!options) {
  16264. options = {};
  16265. }
  16266. options.lng = lng;
  16267. return init(options, cb);
  16268. }
  16269. function lng() {
  16270. return currentLng;
  16271. }
  16272. function reload(cb) {
  16273. resStore = {};
  16274. setLng(currentLng, cb);
  16275. }
  16276. function addJqueryFunct() {
  16277. // $.t shortcut
  16278. $.t = $.t || translate;
  16279. function parse(ele, key, options) {
  16280. if (key.length === 0) return;
  16281. var attr = 'text';
  16282. if (key.indexOf('[') === 0) {
  16283. var parts = key.split(']');
  16284. key = parts[1];
  16285. attr = parts[0].substr(1, parts[0].length-1);
  16286. }
  16287. if (key.indexOf(';') === key.length-1) {
  16288. key = key.substr(0, key.length-2);
  16289. }
  16290. var optionsToUse;
  16291. if (attr === 'html') {
  16292. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  16293. ele.html($.t(key, optionsToUse));
  16294. } else if (attr === 'text') {
  16295. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.text() }, options) : options;
  16296. ele.text($.t(key, optionsToUse));
  16297. } else if (attr === 'prepend') {
  16298. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  16299. ele.prepend($.t(key, optionsToUse));
  16300. } else if (attr === 'append') {
  16301. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  16302. ele.append($.t(key, optionsToUse));
  16303. } else if (attr.indexOf("data-") === 0) {
  16304. var dataAttr = attr.substr(("data-").length);
  16305. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.data(dataAttr) }, options) : options;
  16306. var translated = $.t(key, optionsToUse);
  16307. //we change into the data cache
  16308. ele.data(dataAttr, translated);
  16309. //we change into the dom
  16310. ele.attr(attr, translated);
  16311. } else {
  16312. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.attr(attr) }, options) : options;
  16313. ele.attr(attr, $.t(key, optionsToUse));
  16314. }
  16315. }
  16316. function localize(ele, options) {
  16317. var key = ele.attr(o.selectorAttr);
  16318. if (!key && typeof key !== 'undefined' && key !== false) key = ele.text() || ele.val();
  16319. if (!key) return;
  16320. var target = ele
  16321. , targetSelector = ele.data("i18n-target");
  16322. if (targetSelector) {
  16323. target = ele.find(targetSelector) || ele;
  16324. }
  16325. if (!options && o.useDataAttrOptions === true) {
  16326. options = ele.data("i18n-options");
  16327. }
  16328. options = options || {};
  16329. if (key.indexOf(';') >= 0) {
  16330. var keys = key.split(';');
  16331. $.each(keys, function(m, k) {
  16332. if (k !== '') parse(target, k, options);
  16333. });
  16334. } else {
  16335. parse(target, key, options);
  16336. }
  16337. if (o.useDataAttrOptions === true) ele.data("i18n-options", options);
  16338. }
  16339. // fn
  16340. $.fn.i18n = function (options) {
  16341. return this.each(function() {
  16342. // localize element itself
  16343. localize($(this), options);
  16344. // localize childs
  16345. var elements = $(this).find('[' + o.selectorAttr + ']');
  16346. elements.each(function() {
  16347. localize($(this), options);
  16348. });
  16349. });
  16350. };
  16351. }
  16352. function applyReplacement(str, replacementHash, nestedKey, options) {
  16353. if (!str) return str;
  16354. options = options || replacementHash; // first call uses replacement hash combined with options
  16355. if (str.indexOf(options.interpolationPrefix || o.interpolationPrefix) < 0) return str;
  16356. var prefix = options.interpolationPrefix ? f.regexEscape(options.interpolationPrefix) : o.interpolationPrefixEscaped
  16357. , suffix = options.interpolationSuffix ? f.regexEscape(options.interpolationSuffix) : o.interpolationSuffixEscaped
  16358. , unEscapingSuffix = 'HTML'+suffix;
  16359. var hash = replacementHash.replace && typeof replacementHash.replace === 'object' ? replacementHash.replace : replacementHash;
  16360. f.each(hash, function(key, value) {
  16361. var nextKey = nestedKey ? nestedKey + o.keyseparator + key : key;
  16362. if (typeof value === 'object' && value !== null) {
  16363. str = applyReplacement(str, value, nextKey, options);
  16364. } else {
  16365. if (options.escapeInterpolation || o.escapeInterpolation) {
  16366. str = str.replace(new RegExp([prefix, nextKey, unEscapingSuffix].join(''), 'g'), f.regexReplacementEscape(value));
  16367. str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.regexReplacementEscape(f.escape(value)));
  16368. } else {
  16369. str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.regexReplacementEscape(value));
  16370. }
  16371. // str = options.escapeInterpolation;
  16372. }
  16373. });
  16374. return str;
  16375. }
  16376. // append it to functions
  16377. f.applyReplacement = applyReplacement;
  16378. function applyReuse(translated, options) {
  16379. var comma = ',';
  16380. var options_open = '{';
  16381. var options_close = '}';
  16382. var opts = f.extend({}, options);
  16383. delete opts.postProcess;
  16384. while (translated.indexOf(o.reusePrefix) != -1) {
  16385. replacementCounter++;
  16386. if (replacementCounter > o.maxRecursion) { break; } // safety net for too much recursion
  16387. var index_of_opening = translated.lastIndexOf(o.reusePrefix);
  16388. var index_of_end_of_closing = translated.indexOf(o.reuseSuffix, index_of_opening) + o.reuseSuffix.length;
  16389. var token = translated.substring(index_of_opening, index_of_end_of_closing);
  16390. var token_without_symbols = token.replace(o.reusePrefix, '').replace(o.reuseSuffix, '');
  16391. if (index_of_end_of_closing <= index_of_opening) {
  16392. f.error('there is an missing closing in following translation value', translated);
  16393. return '';
  16394. }
  16395. if (token_without_symbols.indexOf(comma) != -1) {
  16396. var index_of_token_end_of_closing = token_without_symbols.indexOf(comma);
  16397. 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) {
  16398. var index_of_opts_opening = token_without_symbols.indexOf(options_open, index_of_token_end_of_closing);
  16399. var index_of_opts_end_of_closing = token_without_symbols.indexOf(options_close, index_of_opts_opening) + options_close.length;
  16400. try {
  16401. opts = f.extend(opts, JSON.parse(token_without_symbols.substring(index_of_opts_opening, index_of_opts_end_of_closing)));
  16402. token_without_symbols = token_without_symbols.substring(0, index_of_token_end_of_closing);
  16403. } catch (e) {
  16404. }
  16405. }
  16406. }
  16407. var translated_token = _translate(token_without_symbols, opts);
  16408. translated = translated.replace(token, f.regexReplacementEscape(translated_token));
  16409. }
  16410. return translated;
  16411. }
  16412. function hasContext(options) {
  16413. return (options.context && (typeof options.context == 'string' || typeof options.context == 'number'));
  16414. }
  16415. function needsPlural(options, lng) {
  16416. return (options.count !== undefined && typeof options.count != 'string'/* && pluralExtensions.needsPlural(lng, options.count)*/);
  16417. }
  16418. function needsIndefiniteArticle(options) {
  16419. return (options.indefinite_article !== undefined && typeof options.indefinite_article != 'string' && options.indefinite_article);
  16420. }
  16421. function exists(key, options) {
  16422. options = options || {};
  16423. var notFound = _getDefaultValue(key, options)
  16424. , found = _find(key, options);
  16425. return found !== undefined || found === notFound;
  16426. }
  16427. function translate(key, options) {
  16428. options = options || {};
  16429. if (!initialized) {
  16430. f.log('i18next not finished initialization. you might have called t function before loading resources finished.')
  16431. return options.defaultValue || '';
  16432. };
  16433. replacementCounter = 0;
  16434. return _translate.apply(null, arguments);
  16435. }
  16436. function _getDefaultValue(key, options) {
  16437. return (options.defaultValue !== undefined) ? options.defaultValue : key;
  16438. }
  16439. function _injectSprintfProcessor() {
  16440. var values = [];
  16441. // mh: build array from second argument onwards
  16442. for (var i = 1; i < arguments.length; i++) {
  16443. values.push(arguments[i]);
  16444. }
  16445. return {
  16446. postProcess: 'sprintf',
  16447. sprintf: values
  16448. };
  16449. }
  16450. function _translate(potentialKeys, options) {
  16451. if (options && typeof options !== 'object') {
  16452. if (o.shortcutFunction === 'sprintf') {
  16453. // mh: gettext like sprintf syntax found, automatically create sprintf processor
  16454. options = _injectSprintfProcessor.apply(null, arguments);
  16455. } else if (o.shortcutFunction === 'defaultValue') {
  16456. options = {
  16457. defaultValue: options
  16458. }
  16459. }
  16460. } else {
  16461. options = options || {};
  16462. }
  16463. if (typeof o.defaultVariables === 'object') {
  16464. options = f.extend({}, o.defaultVariables, options);
  16465. }
  16466. if (potentialKeys === undefined || potentialKeys === null || potentialKeys === '') return '';
  16467. if (typeof potentialKeys === 'string') {
  16468. potentialKeys = [potentialKeys];
  16469. }
  16470. var key = potentialKeys[0];
  16471. if (potentialKeys.length > 1) {
  16472. for (var i = 0; i < potentialKeys.length; i++) {
  16473. key = potentialKeys[i];
  16474. if (exists(key, options)) {
  16475. break;
  16476. }
  16477. }
  16478. }
  16479. var notFound = _getDefaultValue(key, options)
  16480. , found = _find(key, options)
  16481. , lngs = options.lng ? f.toLanguages(options.lng, options.fallbackLng) : languages
  16482. , ns = options.ns || o.ns.defaultNs
  16483. , parts;
  16484. // split ns and key
  16485. if (key.indexOf(o.nsseparator) > -1) {
  16486. parts = key.split(o.nsseparator);
  16487. ns = parts[0];
  16488. key = parts[1];
  16489. }
  16490. if (found === undefined && o.sendMissing && typeof o.missingKeyHandler === 'function') {
  16491. if (options.lng) {
  16492. o.missingKeyHandler(lngs[0], ns, key, notFound, lngs);
  16493. } else {
  16494. o.missingKeyHandler(o.lng, ns, key, notFound, lngs);
  16495. }
  16496. }
  16497. var postProcessor = options.postProcess || o.postProcess;
  16498. if (found !== undefined && postProcessor) {
  16499. if (postProcessors[postProcessor]) {
  16500. found = postProcessors[postProcessor](found, key, options);
  16501. }
  16502. }
  16503. // process notFound if function exists
  16504. var splitNotFound = notFound;
  16505. if (notFound.indexOf(o.nsseparator) > -1) {
  16506. parts = notFound.split(o.nsseparator);
  16507. splitNotFound = parts[1];
  16508. }
  16509. if (splitNotFound === key && o.parseMissingKey) {
  16510. notFound = o.parseMissingKey(notFound);
  16511. }
  16512. if (found === undefined) {
  16513. notFound = applyReplacement(notFound, options);
  16514. notFound = applyReuse(notFound, options);
  16515. if (postProcessor && postProcessors[postProcessor]) {
  16516. var val = _getDefaultValue(key, options);
  16517. found = postProcessors[postProcessor](val, key, options);
  16518. }
  16519. }
  16520. return (found !== undefined) ? found : notFound;
  16521. }
  16522. function _find(key, options) {
  16523. options = options || {};
  16524. var optionWithoutCount, translated
  16525. , notFound = _getDefaultValue(key, options)
  16526. , lngs = languages;
  16527. if (!resStore) { return notFound; } // no resStore to translate from
  16528. // CI mode
  16529. if (lngs[0].toLowerCase() === 'cimode') return notFound;
  16530. // passed in lng
  16531. if (options.lngs) lngs = options.lngs;
  16532. if (options.lng) {
  16533. lngs = f.toLanguages(options.lng, options.fallbackLng);
  16534. if (!resStore[lngs[0]]) {
  16535. var oldAsync = o.getAsync;
  16536. o.getAsync = false;
  16537. i18n.sync.load(lngs, o, function(err, store) {
  16538. f.extend(resStore, store);
  16539. o.getAsync = oldAsync;
  16540. });
  16541. }
  16542. }
  16543. var ns = options.ns || o.ns.defaultNs;
  16544. if (key.indexOf(o.nsseparator) > -1) {
  16545. var parts = key.split(o.nsseparator);
  16546. ns = parts[0];
  16547. key = parts[1];
  16548. }
  16549. if (hasContext(options)) {
  16550. optionWithoutCount = f.extend({}, options);
  16551. delete optionWithoutCount.context;
  16552. optionWithoutCount.defaultValue = o.contextNotFound;
  16553. var contextKey = ns + o.nsseparator + key + '_' + options.context;
  16554. translated = translate(contextKey, optionWithoutCount);
  16555. if (translated != o.contextNotFound) {
  16556. return applyReplacement(translated, { context: options.context }); // apply replacement for context only
  16557. } // else continue translation with original/nonContext key
  16558. }
  16559. if (needsPlural(options, lngs[0])) {
  16560. optionWithoutCount = f.extend({ lngs: [lngs[0]]}, options);
  16561. delete optionWithoutCount.count;
  16562. delete optionWithoutCount.lng;
  16563. optionWithoutCount.defaultValue = o.pluralNotFound;
  16564. var pluralKey;
  16565. if (!pluralExtensions.needsPlural(lngs[0], options.count)) {
  16566. pluralKey = ns + o.nsseparator + key;
  16567. } else {
  16568. pluralKey = ns + o.nsseparator + key + o.pluralSuffix;
  16569. var pluralExtension = pluralExtensions.get(lngs[0], options.count);
  16570. if (pluralExtension >= 0) {
  16571. pluralKey = pluralKey + '_' + pluralExtension;
  16572. } else if (pluralExtension === 1) {
  16573. pluralKey = ns + o.nsseparator + key; // singular
  16574. }
  16575. }
  16576. translated = translate(pluralKey, optionWithoutCount);
  16577. if (translated != o.pluralNotFound) {
  16578. return applyReplacement(translated, {
  16579. count: options.count,
  16580. interpolationPrefix: options.interpolationPrefix,
  16581. interpolationSuffix: options.interpolationSuffix
  16582. }); // apply replacement for count only
  16583. } else if (lngs.length > 1) {
  16584. // remove failed lng
  16585. var clone = lngs.slice();
  16586. clone.shift();
  16587. options = f.extend(options, { lngs: clone });
  16588. delete options.lng;
  16589. // retry with fallbacks
  16590. translated = translate(ns + o.nsseparator + key, options);
  16591. if (translated != o.pluralNotFound) return translated;
  16592. } else {
  16593. return translated;
  16594. }
  16595. }
  16596. if (needsIndefiniteArticle(options)) {
  16597. var optionsWithoutIndef = f.extend({}, options);
  16598. delete optionsWithoutIndef.indefinite_article;
  16599. optionsWithoutIndef.defaultValue = o.indefiniteNotFound;
  16600. // If we don't have a count, we want the indefinite, if we do have a count, and needsPlural is false
  16601. var indefiniteKey = ns + o.nsseparator + key + (((options.count && !needsPlural(options, lngs[0])) || !options.count) ? o.indefiniteSuffix : "");
  16602. translated = translate(indefiniteKey, optionsWithoutIndef);
  16603. if (translated != o.indefiniteNotFound) {
  16604. return translated;
  16605. }
  16606. }
  16607. var found;
  16608. var keys = key.split(o.keyseparator);
  16609. for (var i = 0, len = lngs.length; i < len; i++ ) {
  16610. if (found !== undefined) break;
  16611. var l = lngs[i];
  16612. var x = 0;
  16613. var value = resStore[l] && resStore[l][ns];
  16614. while (keys[x]) {
  16615. value = value && value[keys[x]];
  16616. x++;
  16617. }
  16618. if (value !== undefined) {
  16619. var valueType = Object.prototype.toString.apply(value);
  16620. if (typeof value === 'string') {
  16621. value = applyReplacement(value, options);
  16622. value = applyReuse(value, options);
  16623. } else if (valueType === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) {
  16624. value = value.join('\n');
  16625. value = applyReplacement(value, options);
  16626. value = applyReuse(value, options);
  16627. } else if (value === null && o.fallbackOnNull === true) {
  16628. value = undefined;
  16629. } else if (value !== null) {
  16630. if (!o.returnObjectTrees && !options.returnObjectTrees) {
  16631. if (o.objectTreeKeyHandler && typeof o.objectTreeKeyHandler == 'function') {
  16632. value = o.objectTreeKeyHandler(key, value, l, ns, options);
  16633. } else {
  16634. value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' +
  16635. 'returned an object instead of string.';
  16636. f.log(value);
  16637. }
  16638. } else if (valueType !== '[object Number]' && valueType !== '[object Function]' && valueType !== '[object RegExp]') {
  16639. var copy = (valueType === '[object Array]') ? [] : {}; // apply child translation on a copy
  16640. f.each(value, function(m) {
  16641. copy[m] = _translate(ns + o.nsseparator + key + o.keyseparator + m, options);
  16642. });
  16643. value = copy;
  16644. }
  16645. }
  16646. if (typeof value === 'string' && value.trim() === '' && o.fallbackOnEmpty === true)
  16647. value = undefined;
  16648. found = value;
  16649. }
  16650. }
  16651. if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) {
  16652. // set flag for fallback lookup - avoid recursion
  16653. options.isFallbackLookup = true;
  16654. if (o.fallbackNS.length) {
  16655. for (var y = 0, lenY = o.fallbackNS.length; y < lenY; y++) {
  16656. found = _find(o.fallbackNS[y] + o.nsseparator + key, options);
  16657. if (found || (found==="" && o.fallbackOnEmpty === false)) {
  16658. /* compare value without namespace */
  16659. var foundValue = found.indexOf(o.nsseparator) > -1 ? found.split(o.nsseparator)[1] : found
  16660. , notFoundValue = notFound.indexOf(o.nsseparator) > -1 ? notFound.split(o.nsseparator)[1] : notFound;
  16661. if (foundValue !== notFoundValue) break;
  16662. }
  16663. }
  16664. } else {
  16665. found = _find(key, options); // fallback to default NS
  16666. }
  16667. options.isFallbackLookup = false;
  16668. }
  16669. return found;
  16670. }
  16671. function detectLanguage() {
  16672. var detectedLng;
  16673. var whitelist = o.lngWhitelist || [];
  16674. var userLngChoices = [];
  16675. // get from qs
  16676. var qsParm = [];
  16677. if (typeof window !== 'undefined') {
  16678. (function() {
  16679. var query = window.location.search.substring(1);
  16680. var params = query.split('&');
  16681. for (var i=0; i<params.length; i++) {
  16682. var pos = params[i].indexOf('=');
  16683. if (pos > 0) {
  16684. var key = params[i].substring(0,pos);
  16685. if (key == o.detectLngQS) {
  16686. userLngChoices.push(params[i].substring(pos+1));
  16687. }
  16688. }
  16689. }
  16690. })();
  16691. }
  16692. // get from cookie
  16693. if (o.useCookie && typeof document !== 'undefined') {
  16694. var c = f.cookie.read(o.cookieName);
  16695. if (c) userLngChoices.push(c);
  16696. }
  16697. // get from localStorage
  16698. if (o.detectLngFromLocalStorage && typeof window !== 'undefined' && window.localStorage) {
  16699. userLngChoices.push(window.localStorage.getItem('i18next_lng'));
  16700. }
  16701. // get from navigator
  16702. if (typeof navigator !== 'undefined') {
  16703. if (navigator.languages) { // chrome only; not an array, so can't use .push.apply instead of iterating
  16704. for (var i=0;i<navigator.languages.length;i++) {
  16705. userLngChoices.push(navigator.languages[i]);
  16706. }
  16707. }
  16708. if (navigator.userLanguage) {
  16709. userLngChoices.push(navigator.userLanguage);
  16710. }
  16711. if (navigator.language) {
  16712. userLngChoices.push(navigator.language);
  16713. }
  16714. }
  16715. (function() {
  16716. for (var i=0;i<userLngChoices.length;i++) {
  16717. var lng = userLngChoices[i];
  16718. if (lng.indexOf('-') > -1) {
  16719. var parts = lng.split('-');
  16720. lng = o.lowerCaseLng ?
  16721. parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
  16722. parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
  16723. }
  16724. if (whitelist.length === 0 || whitelist.indexOf(lng) > -1) {
  16725. detectedLng = lng;
  16726. break;
  16727. }
  16728. }
  16729. })();
  16730. //fallback
  16731. if (!detectedLng){
  16732. detectedLng = o.fallbackLng[0];
  16733. }
  16734. return detectedLng;
  16735. }
  16736. // definition http://translate.sourceforge.net/wiki/l10n/pluralforms
  16737. /* [code, name, numbers, pluralsType] */
  16738. var _rules = [
  16739. ["ach", "Acholi", [1,2], 1],
  16740. ["af", "Afrikaans",[1,2], 2],
  16741. ["ak", "Akan", [1,2], 1],
  16742. ["am", "Amharic", [1,2], 1],
  16743. ["an", "Aragonese",[1,2], 2],
  16744. ["ar", "Arabic", [0,1,2,3,11,100],5],
  16745. ["arn", "Mapudungun",[1,2], 1],
  16746. ["ast", "Asturian", [1,2], 2],
  16747. ["ay", "Aymará", [1], 3],
  16748. ["az", "Azerbaijani",[1,2],2],
  16749. ["be", "Belarusian",[1,2,5],4],
  16750. ["bg", "Bulgarian",[1,2], 2],
  16751. ["bn", "Bengali", [1,2], 2],
  16752. ["bo", "Tibetan", [1], 3],
  16753. ["br", "Breton", [1,2], 1],
  16754. ["bs", "Bosnian", [1,2,5],4],
  16755. ["ca", "Catalan", [1,2], 2],
  16756. ["cgg", "Chiga", [1], 3],
  16757. ["cs", "Czech", [1,2,5],6],
  16758. ["csb", "Kashubian",[1,2,5],7],
  16759. ["cy", "Welsh", [1,2,3,8],8],
  16760. ["da", "Danish", [1,2], 2],
  16761. ["de", "German", [1,2], 2],
  16762. ["dev", "Development Fallback", [1,2], 2],
  16763. ["dz", "Dzongkha", [1], 3],
  16764. ["el", "Greek", [1,2], 2],
  16765. ["en", "English", [1,2], 2],
  16766. ["eo", "Esperanto",[1,2], 2],
  16767. ["es", "Spanish", [1,2], 2],
  16768. ["es_ar","Argentinean Spanish", [1,2], 2],
  16769. ["et", "Estonian", [1,2], 2],
  16770. ["eu", "Basque", [1,2], 2],
  16771. ["fa", "Persian", [1], 3],
  16772. ["fi", "Finnish", [1,2], 2],
  16773. ["fil", "Filipino", [1,2], 1],
  16774. ["fo", "Faroese", [1,2], 2],
  16775. ["fr", "French", [1,2], 9],
  16776. ["fur", "Friulian", [1,2], 2],
  16777. ["fy", "Frisian", [1,2], 2],
  16778. ["ga", "Irish", [1,2,3,7,11],10],
  16779. ["gd", "Scottish Gaelic",[1,2,3,20],11],
  16780. ["gl", "Galician", [1,2], 2],
  16781. ["gu", "Gujarati", [1,2], 2],
  16782. ["gun", "Gun", [1,2], 1],
  16783. ["ha", "Hausa", [1,2], 2],
  16784. ["he", "Hebrew", [1,2], 2],
  16785. ["hi", "Hindi", [1,2], 2],
  16786. ["hr", "Croatian", [1,2,5],4],
  16787. ["hu", "Hungarian",[1,2], 2],
  16788. ["hy", "Armenian", [1,2], 2],
  16789. ["ia", "Interlingua",[1,2],2],
  16790. ["id", "Indonesian",[1], 3],
  16791. ["is", "Icelandic",[1,2], 12],
  16792. ["it", "Italian", [1,2], 2],
  16793. ["ja", "Japanese", [1], 3],
  16794. ["jbo", "Lojban", [1], 3],
  16795. ["jv", "Javanese", [0,1], 13],
  16796. ["ka", "Georgian", [1], 3],
  16797. ["kk", "Kazakh", [1], 3],
  16798. ["km", "Khmer", [1], 3],
  16799. ["kn", "Kannada", [1,2], 2],
  16800. ["ko", "Korean", [1], 3],
  16801. ["ku", "Kurdish", [1,2], 2],
  16802. ["kw", "Cornish", [1,2,3,4],14],
  16803. ["ky", "Kyrgyz", [1], 3],
  16804. ["lb", "Letzeburgesch",[1,2],2],
  16805. ["ln", "Lingala", [1,2], 1],
  16806. ["lo", "Lao", [1], 3],
  16807. ["lt", "Lithuanian",[1,2,10],15],
  16808. ["lv", "Latvian", [1,2,0],16],
  16809. ["mai", "Maithili", [1,2], 2],
  16810. ["mfe", "Mauritian Creole",[1,2],1],
  16811. ["mg", "Malagasy", [1,2], 1],
  16812. ["mi", "Maori", [1,2], 1],
  16813. ["mk", "Macedonian",[1,2],17],
  16814. ["ml", "Malayalam",[1,2], 2],
  16815. ["mn", "Mongolian",[1,2], 2],
  16816. ["mnk", "Mandinka", [0,1,2],18],
  16817. ["mr", "Marathi", [1,2], 2],
  16818. ["ms", "Malay", [1], 3],
  16819. ["mt", "Maltese", [1,2,11,20],19],
  16820. ["nah", "Nahuatl", [1,2], 2],
  16821. ["nap", "Neapolitan",[1,2], 2],
  16822. ["nb", "Norwegian Bokmal",[1,2],2],
  16823. ["ne", "Nepali", [1,2], 2],
  16824. ["nl", "Dutch", [1,2], 2],
  16825. ["nn", "Norwegian Nynorsk",[1,2],2],
  16826. ["no", "Norwegian",[1,2], 2],
  16827. ["nso", "Northern Sotho",[1,2],2],
  16828. ["oc", "Occitan", [1,2], 1],
  16829. ["or", "Oriya", [2,1], 2],
  16830. ["pa", "Punjabi", [1,2], 2],
  16831. ["pap", "Papiamento",[1,2], 2],
  16832. ["pl", "Polish", [1,2,5],7],
  16833. ["pms", "Piemontese",[1,2], 2],
  16834. ["ps", "Pashto", [1,2], 2],
  16835. ["pt", "Portuguese",[1,2], 2],
  16836. ["pt_br","Brazilian Portuguese",[1,2], 2],
  16837. ["rm", "Romansh", [1,2], 2],
  16838. ["ro", "Romanian", [1,2,20],20],
  16839. ["ru", "Russian", [1,2,5],4],
  16840. ["sah", "Yakut", [1], 3],
  16841. ["sco", "Scots", [1,2], 2],
  16842. ["se", "Northern Sami",[1,2], 2],
  16843. ["si", "Sinhala", [1,2], 2],
  16844. ["sk", "Slovak", [1,2,5],6],
  16845. ["sl", "Slovenian",[5,1,2,3],21],
  16846. ["so", "Somali", [1,2], 2],
  16847. ["son", "Songhay", [1,2], 2],
  16848. ["sq", "Albanian", [1,2], 2],
  16849. ["sr", "Serbian", [1,2,5],4],
  16850. ["su", "Sundanese",[1], 3],
  16851. ["sv", "Swedish", [1,2], 2],
  16852. ["sw", "Swahili", [1,2], 2],
  16853. ["ta", "Tamil", [1,2], 2],
  16854. ["te", "Telugu", [1,2], 2],
  16855. ["tg", "Tajik", [1,2], 1],
  16856. ["th", "Thai", [1], 3],
  16857. ["ti", "Tigrinya", [1,2], 1],
  16858. ["tk", "Turkmen", [1,2], 2],
  16859. ["tr", "Turkish", [1,2], 1],
  16860. ["tt", "Tatar", [1], 3],
  16861. ["ug", "Uyghur", [1], 3],
  16862. ["uk", "Ukrainian",[1,2,5],4],
  16863. ["ur", "Urdu", [1,2], 2],
  16864. ["uz", "Uzbek", [1,2], 1],
  16865. ["vi", "Vietnamese",[1], 3],
  16866. ["wa", "Walloon", [1,2], 1],
  16867. ["wo", "Wolof", [1], 3],
  16868. ["yo", "Yoruba", [1,2], 2],
  16869. ["zh", "Chinese", [1], 3]
  16870. ];
  16871. var _rulesPluralsTypes = {
  16872. 1: function(n) {return Number(n > 1);},
  16873. 2: function(n) {return Number(n != 1);},
  16874. 3: function(n) {return 0;},
  16875. 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);},
  16876. 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);},
  16877. 6: function(n) {return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);},
  16878. 7: function(n) {return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);},
  16879. 8: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3);},
  16880. 9: function(n) {return Number(n >= 2);},
  16881. 10: function(n) {return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;},
  16882. 11: function(n) {return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3);},
  16883. 12: function(n) {return Number(n%10!=1 || n%100==11);},
  16884. 13: function(n) {return Number(n !== 0);},
  16885. 14: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3);},
  16886. 15: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);},
  16887. 16: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2);},
  16888. 17: function(n) {return Number(n==1 || n%10==1 ? 0 : 1);},
  16889. 18: function(n) {return Number(0 ? 0 : n==1 ? 1 : 2);},
  16890. 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);},
  16891. 20: function(n) {return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);},
  16892. 21: function(n) {return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); }
  16893. };
  16894. var pluralExtensions = {
  16895. rules: (function () {
  16896. var l, rules = {};
  16897. for (l=_rules.length; l-- ;) {
  16898. rules[_rules[l][0]] = {
  16899. name: _rules[l][1],
  16900. numbers: _rules[l][2],
  16901. plurals: _rulesPluralsTypes[_rules[l][3]]
  16902. }
  16903. }
  16904. return rules;
  16905. }()),
  16906. // you can add your own pluralExtensions
  16907. addRule: function(lng, obj) {
  16908. pluralExtensions.rules[lng] = obj;
  16909. },
  16910. setCurrentLng: function(lng) {
  16911. if (!pluralExtensions.currentRule || pluralExtensions.currentRule.lng !== lng) {
  16912. var parts = lng.split('-');
  16913. pluralExtensions.currentRule = {
  16914. lng: lng,
  16915. rule: pluralExtensions.rules[parts[0]]
  16916. };
  16917. }
  16918. },
  16919. needsPlural: function(lng, count) {
  16920. var parts = lng.split('-');
  16921. var ext;
  16922. if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
  16923. ext = pluralExtensions.currentRule.rule;
  16924. } else {
  16925. ext = pluralExtensions.rules[parts[f.getCountyIndexOfLng(lng)]];
  16926. }
  16927. if (ext && ext.numbers.length <= 1) {
  16928. return false;
  16929. } else {
  16930. return this.get(lng, count) !== 1;
  16931. }
  16932. },
  16933. get: function(lng, count) {
  16934. var parts = lng.split('-');
  16935. function getResult(l, c) {
  16936. var ext;
  16937. if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
  16938. ext = pluralExtensions.currentRule.rule;
  16939. } else {
  16940. ext = pluralExtensions.rules[l];
  16941. }
  16942. if (ext) {
  16943. var i;
  16944. if (ext.noAbs) {
  16945. i = ext.plurals(c);
  16946. } else {
  16947. i = ext.plurals(Math.abs(c));
  16948. }
  16949. var number = ext.numbers[i];
  16950. if (ext.numbers.length === 2 && ext.numbers[0] === 1) {
  16951. if (number === 2) {
  16952. number = -1; // regular plural
  16953. } else if (number === 1) {
  16954. number = 1; // singular
  16955. }
  16956. }//console.log(count + '-' + number);
  16957. return number;
  16958. } else {
  16959. return c === 1 ? '1' : '-1';
  16960. }
  16961. }
  16962. return getResult(parts[f.getCountyIndexOfLng(lng)], count);
  16963. }
  16964. };
  16965. var postProcessors = {};
  16966. var addPostProcessor = function(name, fc) {
  16967. postProcessors[name] = fc;
  16968. };
  16969. // sprintf support
  16970. var sprintf = (function() {
  16971. function get_type(variable) {
  16972. return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
  16973. }
  16974. function str_repeat(input, multiplier) {
  16975. for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
  16976. return output.join('');
  16977. }
  16978. var str_format = function() {
  16979. if (!str_format.cache.hasOwnProperty(arguments[0])) {
  16980. str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
  16981. }
  16982. return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
  16983. };
  16984. str_format.format = function(parse_tree, argv) {
  16985. var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
  16986. for (i = 0; i < tree_length; i++) {
  16987. node_type = get_type(parse_tree[i]);
  16988. if (node_type === 'string') {
  16989. output.push(parse_tree[i]);
  16990. }
  16991. else if (node_type === 'array') {
  16992. match = parse_tree[i]; // convenience purposes only
  16993. if (match[2]) { // keyword argument
  16994. arg = argv[cursor];
  16995. for (k = 0; k < match[2].length; k++) {
  16996. if (!arg.hasOwnProperty(match[2][k])) {
  16997. throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
  16998. }
  16999. arg = arg[match[2][k]];
  17000. }
  17001. }
  17002. else if (match[1]) { // positional argument (explicit)
  17003. arg = argv[match[1]];
  17004. }
  17005. else { // positional argument (implicit)
  17006. arg = argv[cursor++];
  17007. }
  17008. if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
  17009. throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
  17010. }
  17011. switch (match[8]) {
  17012. case 'b': arg = arg.toString(2); break;
  17013. case 'c': arg = String.fromCharCode(arg); break;
  17014. case 'd': arg = parseInt(arg, 10); break;
  17015. case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
  17016. case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
  17017. case 'o': arg = arg.toString(8); break;
  17018. case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
  17019. case 'u': arg = Math.abs(arg); break;
  17020. case 'x': arg = arg.toString(16); break;
  17021. case 'X': arg = arg.toString(16).toUpperCase(); break;
  17022. }
  17023. arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
  17024. pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
  17025. pad_length = match[6] - String(arg).length;
  17026. pad = match[6] ? str_repeat(pad_character, pad_length) : '';
  17027. output.push(match[5] ? arg + pad : pad + arg);
  17028. }
  17029. }
  17030. return output.join('');
  17031. };
  17032. str_format.cache = {};
  17033. str_format.parse = function(fmt) {
  17034. var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
  17035. while (_fmt) {
  17036. if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
  17037. parse_tree.push(match[0]);
  17038. }
  17039. else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
  17040. parse_tree.push('%');
  17041. }
  17042. else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
  17043. if (match[2]) {
  17044. arg_names |= 1;
  17045. var field_list = [], replacement_field = match[2], field_match = [];
  17046. if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
  17047. field_list.push(field_match[1]);
  17048. while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
  17049. if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
  17050. field_list.push(field_match[1]);
  17051. }
  17052. else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
  17053. field_list.push(field_match[1]);
  17054. }
  17055. else {
  17056. throw('[sprintf] huh?');
  17057. }
  17058. }
  17059. }
  17060. else {
  17061. throw('[sprintf] huh?');
  17062. }
  17063. match[2] = field_list;
  17064. }
  17065. else {
  17066. arg_names |= 2;
  17067. }
  17068. if (arg_names === 3) {
  17069. throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
  17070. }
  17071. parse_tree.push(match);
  17072. }
  17073. else {
  17074. throw('[sprintf] huh?');
  17075. }
  17076. _fmt = _fmt.substring(match[0].length);
  17077. }
  17078. return parse_tree;
  17079. };
  17080. return str_format;
  17081. })();
  17082. var vsprintf = function(fmt, argv) {
  17083. argv.unshift(fmt);
  17084. return sprintf.apply(null, argv);
  17085. };
  17086. addPostProcessor("sprintf", function(val, key, opts) {
  17087. if (!opts.sprintf) return val;
  17088. if (Object.prototype.toString.apply(opts.sprintf) === '[object Array]') {
  17089. return vsprintf(val, opts.sprintf);
  17090. } else if (typeof opts.sprintf === 'object') {
  17091. return sprintf(val, opts.sprintf);
  17092. }
  17093. return val;
  17094. });
  17095. // public api interface
  17096. i18n.init = init;
  17097. i18n.setLng = setLng;
  17098. i18n.preload = preload;
  17099. i18n.addResourceBundle = addResourceBundle;
  17100. i18n.hasResourceBundle = hasResourceBundle;
  17101. i18n.addResource = addResource;
  17102. i18n.addResources = addResources;
  17103. i18n.removeResourceBundle = removeResourceBundle;
  17104. i18n.loadNamespace = loadNamespace;
  17105. i18n.loadNamespaces = loadNamespaces;
  17106. i18n.setDefaultNamespace = setDefaultNamespace;
  17107. i18n.t = translate;
  17108. i18n.translate = translate;
  17109. i18n.exists = exists;
  17110. i18n.detectLanguage = f.detectLanguage;
  17111. i18n.pluralExtensions = pluralExtensions;
  17112. i18n.sync = sync;
  17113. i18n.functions = f;
  17114. i18n.lng = lng;
  17115. i18n.addPostProcessor = addPostProcessor;
  17116. i18n.options = o;
  17117. })();
  17118. },{"jquery":"jquery"}],63:[function(require,module,exports){
  17119. // Top level file is just a mixin of submodules & constants
  17120. 'use strict';
  17121. var assign = require('./lib/utils/common').assign;
  17122. var deflate = require('./lib/deflate');
  17123. var inflate = require('./lib/inflate');
  17124. var constants = require('./lib/zlib/constants');
  17125. var pako = {};
  17126. assign(pako, deflate, inflate, constants);
  17127. module.exports = pako;
  17128. },{"./lib/deflate":64,"./lib/inflate":65,"./lib/utils/common":66,"./lib/zlib/constants":69}],64:[function(require,module,exports){
  17129. 'use strict';
  17130. var zlib_deflate = require('./zlib/deflate.js');
  17131. var utils = require('./utils/common');
  17132. var strings = require('./utils/strings');
  17133. var msg = require('./zlib/messages');
  17134. var zstream = require('./zlib/zstream');
  17135. var toString = Object.prototype.toString;
  17136. /* Public constants ==========================================================*/
  17137. /* ===========================================================================*/
  17138. var Z_NO_FLUSH = 0;
  17139. var Z_FINISH = 4;
  17140. var Z_OK = 0;
  17141. var Z_STREAM_END = 1;
  17142. var Z_DEFAULT_COMPRESSION = -1;
  17143. var Z_DEFAULT_STRATEGY = 0;
  17144. var Z_DEFLATED = 8;
  17145. /* ===========================================================================*/
  17146. /**
  17147. * class Deflate
  17148. *
  17149. * Generic JS-style wrapper for zlib calls. If you don't need
  17150. * streaming behaviour - use more simple functions: [[deflate]],
  17151. * [[deflateRaw]] and [[gzip]].
  17152. **/
  17153. /* internal
  17154. * Deflate.chunks -> Array
  17155. *
  17156. * Chunks of output data, if [[Deflate#onData]] not overriden.
  17157. **/
  17158. /**
  17159. * Deflate.result -> Uint8Array|Array
  17160. *
  17161. * Compressed result, generated by default [[Deflate#onData]]
  17162. * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
  17163. * (call [[Deflate#push]] with `Z_FINISH` / `true` param).
  17164. **/
  17165. /**
  17166. * Deflate.err -> Number
  17167. *
  17168. * Error code after deflate finished. 0 (Z_OK) on success.
  17169. * You will not need it in real life, because deflate errors
  17170. * are possible only on wrong options or bad `onData` / `onEnd`
  17171. * custom handlers.
  17172. **/
  17173. /**
  17174. * Deflate.msg -> String
  17175. *
  17176. * Error message, if [[Deflate.err]] != 0
  17177. **/
  17178. /**
  17179. * new Deflate(options)
  17180. * - options (Object): zlib deflate options.
  17181. *
  17182. * Creates new deflator instance with specified params. Throws exception
  17183. * on bad params. Supported options:
  17184. *
  17185. * - `level`
  17186. * - `windowBits`
  17187. * - `memLevel`
  17188. * - `strategy`
  17189. *
  17190. * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
  17191. * for more information on these.
  17192. *
  17193. * Additional options, for internal needs:
  17194. *
  17195. * - `chunkSize` - size of generated data chunks (16K by default)
  17196. * - `raw` (Boolean) - do raw deflate
  17197. * - `gzip` (Boolean) - create gzip wrapper
  17198. * - `to` (String) - if equal to 'string', then result will be "binary string"
  17199. * (each char code [0..255])
  17200. * - `header` (Object) - custom header for gzip
  17201. * - `text` (Boolean) - true if compressed data believed to be text
  17202. * - `time` (Number) - modification time, unix timestamp
  17203. * - `os` (Number) - operation system code
  17204. * - `extra` (Array) - array of bytes with extra data (max 65536)
  17205. * - `name` (String) - file name (binary string)
  17206. * - `comment` (String) - comment (binary string)
  17207. * - `hcrc` (Boolean) - true if header crc should be added
  17208. *
  17209. * ##### Example:
  17210. *
  17211. * ```javascript
  17212. * var pako = require('pako')
  17213. * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
  17214. * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
  17215. *
  17216. * var deflate = new pako.Deflate({ level: 3});
  17217. *
  17218. * deflate.push(chunk1, false);
  17219. * deflate.push(chunk2, true); // true -> last chunk
  17220. *
  17221. * if (deflate.err) { throw new Error(deflate.err); }
  17222. *
  17223. * console.log(deflate.result);
  17224. * ```
  17225. **/
  17226. var Deflate = function(options) {
  17227. this.options = utils.assign({
  17228. level: Z_DEFAULT_COMPRESSION,
  17229. method: Z_DEFLATED,
  17230. chunkSize: 16384,
  17231. windowBits: 15,
  17232. memLevel: 8,
  17233. strategy: Z_DEFAULT_STRATEGY,
  17234. to: ''
  17235. }, options || {});
  17236. var opt = this.options;
  17237. if (opt.raw && (opt.windowBits > 0)) {
  17238. opt.windowBits = -opt.windowBits;
  17239. }
  17240. else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
  17241. opt.windowBits += 16;
  17242. }
  17243. this.err = 0; // error code, if happens (0 = Z_OK)
  17244. this.msg = ''; // error message
  17245. this.ended = false; // used to avoid multiple onEnd() calls
  17246. this.chunks = []; // chunks of compressed data
  17247. this.strm = new zstream();
  17248. this.strm.avail_out = 0;
  17249. var status = zlib_deflate.deflateInit2(
  17250. this.strm,
  17251. opt.level,
  17252. opt.method,
  17253. opt.windowBits,
  17254. opt.memLevel,
  17255. opt.strategy
  17256. );
  17257. if (status !== Z_OK) {
  17258. throw new Error(msg[status]);
  17259. }
  17260. if (opt.header) {
  17261. zlib_deflate.deflateSetHeader(this.strm, opt.header);
  17262. }
  17263. };
  17264. /**
  17265. * Deflate#push(data[, mode]) -> Boolean
  17266. * - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be
  17267. * converted to utf8 byte sequence.
  17268. * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
  17269. * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
  17270. *
  17271. * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
  17272. * new compressed chunks. Returns `true` on success. The last data block must have
  17273. * mode Z_FINISH (or `true`). That flush internal pending buffers and call
  17274. * [[Deflate#onEnd]].
  17275. *
  17276. * On fail call [[Deflate#onEnd]] with error code and return false.
  17277. *
  17278. * We strongly recommend to use `Uint8Array` on input for best speed (output
  17279. * array format is detected automatically). Also, don't skip last param and always
  17280. * use the same type in your code (boolean or number). That will improve JS speed.
  17281. *
  17282. * For regular `Array`-s make sure all elements are [0..255].
  17283. *
  17284. * ##### Example
  17285. *
  17286. * ```javascript
  17287. * push(chunk, false); // push one of data chunks
  17288. * ...
  17289. * push(chunk, true); // push last chunk
  17290. * ```
  17291. **/
  17292. Deflate.prototype.push = function(data, mode) {
  17293. var strm = this.strm;
  17294. var chunkSize = this.options.chunkSize;
  17295. var status, _mode;
  17296. if (this.ended) { return false; }
  17297. _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
  17298. // Convert data if needed
  17299. if (typeof data === 'string') {
  17300. // If we need to compress text, change encoding to utf8.
  17301. strm.input = strings.string2buf(data);
  17302. } else if (toString.call(data) === '[object ArrayBuffer]') {
  17303. strm.input = new Uint8Array(data);
  17304. } else {
  17305. strm.input = data;
  17306. }
  17307. strm.next_in = 0;
  17308. strm.avail_in = strm.input.length;
  17309. do {
  17310. if (strm.avail_out === 0) {
  17311. strm.output = new utils.Buf8(chunkSize);
  17312. strm.next_out = 0;
  17313. strm.avail_out = chunkSize;
  17314. }
  17315. status = zlib_deflate.deflate(strm, _mode); /* no bad return value */
  17316. if (status !== Z_STREAM_END && status !== Z_OK) {
  17317. this.onEnd(status);
  17318. this.ended = true;
  17319. return false;
  17320. }
  17321. if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) {
  17322. if (this.options.to === 'string') {
  17323. this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
  17324. } else {
  17325. this.onData(utils.shrinkBuf(strm.output, strm.next_out));
  17326. }
  17327. }
  17328. } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
  17329. // Finalize on the last chunk.
  17330. if (_mode === Z_FINISH) {
  17331. status = zlib_deflate.deflateEnd(this.strm);
  17332. this.onEnd(status);
  17333. this.ended = true;
  17334. return status === Z_OK;
  17335. }
  17336. return true;
  17337. };
  17338. /**
  17339. * Deflate#onData(chunk) -> Void
  17340. * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
  17341. * on js engine support. When string output requested, each chunk
  17342. * will be string.
  17343. *
  17344. * By default, stores data blocks in `chunks[]` property and glue
  17345. * those in `onEnd`. Override this handler, if you need another behaviour.
  17346. **/
  17347. Deflate.prototype.onData = function(chunk) {
  17348. this.chunks.push(chunk);
  17349. };
  17350. /**
  17351. * Deflate#onEnd(status) -> Void
  17352. * - status (Number): deflate status. 0 (Z_OK) on success,
  17353. * other if not.
  17354. *
  17355. * Called once after you tell deflate that input stream complete
  17356. * or error happenned. By default - join collected chunks,
  17357. * free memory and fill `results` / `err` properties.
  17358. **/
  17359. Deflate.prototype.onEnd = function(status) {
  17360. // On success - join
  17361. if (status === Z_OK) {
  17362. if (this.options.to === 'string') {
  17363. this.result = this.chunks.join('');
  17364. } else {
  17365. this.result = utils.flattenChunks(this.chunks);
  17366. }
  17367. }
  17368. this.chunks = [];
  17369. this.err = status;
  17370. this.msg = this.strm.msg;
  17371. };
  17372. /**
  17373. * deflate(data[, options]) -> Uint8Array|Array|String
  17374. * - data (Uint8Array|Array|String): input data to compress.
  17375. * - options (Object): zlib deflate options.
  17376. *
  17377. * Compress `data` with deflate alrorythm and `options`.
  17378. *
  17379. * Supported options are:
  17380. *
  17381. * - level
  17382. * - windowBits
  17383. * - memLevel
  17384. * - strategy
  17385. *
  17386. * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
  17387. * for more information on these.
  17388. *
  17389. * Sugar (options):
  17390. *
  17391. * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
  17392. * negative windowBits implicitly.
  17393. * - `to` (String) - if equal to 'string', then result will be "binary string"
  17394. * (each char code [0..255])
  17395. *
  17396. * ##### Example:
  17397. *
  17398. * ```javascript
  17399. * var pako = require('pako')
  17400. * , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
  17401. *
  17402. * console.log(pako.deflate(data));
  17403. * ```
  17404. **/
  17405. function deflate(input, options) {
  17406. var deflator = new Deflate(options);
  17407. deflator.push(input, true);
  17408. // That will never happens, if you don't cheat with options :)
  17409. if (deflator.err) { throw deflator.msg; }
  17410. return deflator.result;
  17411. }
  17412. /**
  17413. * deflateRaw(data[, options]) -> Uint8Array|Array|String
  17414. * - data (Uint8Array|Array|String): input data to compress.
  17415. * - options (Object): zlib deflate options.
  17416. *
  17417. * The same as [[deflate]], but creates raw data, without wrapper
  17418. * (header and adler32 crc).
  17419. **/
  17420. function deflateRaw(input, options) {
  17421. options = options || {};
  17422. options.raw = true;
  17423. return deflate(input, options);
  17424. }
  17425. /**
  17426. * gzip(data[, options]) -> Uint8Array|Array|String
  17427. * - data (Uint8Array|Array|String): input data to compress.
  17428. * - options (Object): zlib deflate options.
  17429. *
  17430. * The same as [[deflate]], but create gzip wrapper instead of
  17431. * deflate one.
  17432. **/
  17433. function gzip(input, options) {
  17434. options = options || {};
  17435. options.gzip = true;
  17436. return deflate(input, options);
  17437. }
  17438. exports.Deflate = Deflate;
  17439. exports.deflate = deflate;
  17440. exports.deflateRaw = deflateRaw;
  17441. exports.gzip = gzip;
  17442. },{"./utils/common":66,"./utils/strings":67,"./zlib/deflate.js":71,"./zlib/messages":76,"./zlib/zstream":78}],65:[function(require,module,exports){
  17443. 'use strict';
  17444. var zlib_inflate = require('./zlib/inflate.js');
  17445. var utils = require('./utils/common');
  17446. var strings = require('./utils/strings');
  17447. var c = require('./zlib/constants');
  17448. var msg = require('./zlib/messages');
  17449. var zstream = require('./zlib/zstream');
  17450. var gzheader = require('./zlib/gzheader');
  17451. var toString = Object.prototype.toString;
  17452. /**
  17453. * class Inflate
  17454. *
  17455. * Generic JS-style wrapper for zlib calls. If you don't need
  17456. * streaming behaviour - use more simple functions: [[inflate]]
  17457. * and [[inflateRaw]].
  17458. **/
  17459. /* internal
  17460. * inflate.chunks -> Array
  17461. *
  17462. * Chunks of output data, if [[Inflate#onData]] not overriden.
  17463. **/
  17464. /**
  17465. * Inflate.result -> Uint8Array|Array|String
  17466. *
  17467. * Uncompressed result, generated by default [[Inflate#onData]]
  17468. * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
  17469. * (call [[Inflate#push]] with `Z_FINISH` / `true` param).
  17470. **/
  17471. /**
  17472. * Inflate.err -> Number
  17473. *
  17474. * Error code after inflate finished. 0 (Z_OK) on success.
  17475. * Should be checked if broken data possible.
  17476. **/
  17477. /**
  17478. * Inflate.msg -> String
  17479. *
  17480. * Error message, if [[Inflate.err]] != 0
  17481. **/
  17482. /**
  17483. * new Inflate(options)
  17484. * - options (Object): zlib inflate options.
  17485. *
  17486. * Creates new inflator instance with specified params. Throws exception
  17487. * on bad params. Supported options:
  17488. *
  17489. * - `windowBits`
  17490. *
  17491. * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
  17492. * for more information on these.
  17493. *
  17494. * Additional options, for internal needs:
  17495. *
  17496. * - `chunkSize` - size of generated data chunks (16K by default)
  17497. * - `raw` (Boolean) - do raw inflate
  17498. * - `to` (String) - if equal to 'string', then result will be converted
  17499. * from utf8 to utf16 (javascript) string. When string output requested,
  17500. * chunk length can differ from `chunkSize`, depending on content.
  17501. *
  17502. * By default, when no options set, autodetect deflate/gzip data format via
  17503. * wrapper header.
  17504. *
  17505. * ##### Example:
  17506. *
  17507. * ```javascript
  17508. * var pako = require('pako')
  17509. * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
  17510. * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
  17511. *
  17512. * var inflate = new pako.Inflate({ level: 3});
  17513. *
  17514. * inflate.push(chunk1, false);
  17515. * inflate.push(chunk2, true); // true -> last chunk
  17516. *
  17517. * if (inflate.err) { throw new Error(inflate.err); }
  17518. *
  17519. * console.log(inflate.result);
  17520. * ```
  17521. **/
  17522. var Inflate = function(options) {
  17523. this.options = utils.assign({
  17524. chunkSize: 16384,
  17525. windowBits: 0,
  17526. to: ''
  17527. }, options || {});
  17528. var opt = this.options;
  17529. // Force window size for `raw` data, if not set directly,
  17530. // because we have no header for autodetect.
  17531. if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
  17532. opt.windowBits = -opt.windowBits;
  17533. if (opt.windowBits === 0) { opt.windowBits = -15; }
  17534. }
  17535. // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
  17536. if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
  17537. !(options && options.windowBits)) {
  17538. opt.windowBits += 32;
  17539. }
  17540. // Gzip header has no info about windows size, we can do autodetect only
  17541. // for deflate. So, if window size not set, force it to max when gzip possible
  17542. if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
  17543. // bit 3 (16) -> gzipped data
  17544. // bit 4 (32) -> autodetect gzip/deflate
  17545. if ((opt.windowBits & 15) === 0) {
  17546. opt.windowBits |= 15;
  17547. }
  17548. }
  17549. this.err = 0; // error code, if happens (0 = Z_OK)
  17550. this.msg = ''; // error message
  17551. this.ended = false; // used to avoid multiple onEnd() calls
  17552. this.chunks = []; // chunks of compressed data
  17553. this.strm = new zstream();
  17554. this.strm.avail_out = 0;
  17555. var status = zlib_inflate.inflateInit2(
  17556. this.strm,
  17557. opt.windowBits
  17558. );
  17559. if (status !== c.Z_OK) {
  17560. throw new Error(msg[status]);
  17561. }
  17562. this.header = new gzheader();
  17563. zlib_inflate.inflateGetHeader(this.strm, this.header);
  17564. };
  17565. /**
  17566. * Inflate#push(data[, mode]) -> Boolean
  17567. * - data (Uint8Array|Array|ArrayBuffer|String): input data
  17568. * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
  17569. * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
  17570. *
  17571. * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
  17572. * new output chunks. Returns `true` on success. The last data block must have
  17573. * mode Z_FINISH (or `true`). That flush internal pending buffers and call
  17574. * [[Inflate#onEnd]].
  17575. *
  17576. * On fail call [[Inflate#onEnd]] with error code and return false.
  17577. *
  17578. * We strongly recommend to use `Uint8Array` on input for best speed (output
  17579. * format is detected automatically). Also, don't skip last param and always
  17580. * use the same type in your code (boolean or number). That will improve JS speed.
  17581. *
  17582. * For regular `Array`-s make sure all elements are [0..255].
  17583. *
  17584. * ##### Example
  17585. *
  17586. * ```javascript
  17587. * push(chunk, false); // push one of data chunks
  17588. * ...
  17589. * push(chunk, true); // push last chunk
  17590. * ```
  17591. **/
  17592. Inflate.prototype.push = function(data, mode) {
  17593. var strm = this.strm;
  17594. var chunkSize = this.options.chunkSize;
  17595. var status, _mode;
  17596. var next_out_utf8, tail, utf8str;
  17597. if (this.ended) { return false; }
  17598. _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);
  17599. // Convert data if needed
  17600. if (typeof data === 'string') {
  17601. // Only binary strings can be decompressed on practice
  17602. strm.input = strings.binstring2buf(data);
  17603. } else if (toString.call(data) === '[object ArrayBuffer]') {
  17604. strm.input = new Uint8Array(data);
  17605. } else {
  17606. strm.input = data;
  17607. }
  17608. strm.next_in = 0;
  17609. strm.avail_in = strm.input.length;
  17610. do {
  17611. if (strm.avail_out === 0) {
  17612. strm.output = new utils.Buf8(chunkSize);
  17613. strm.next_out = 0;
  17614. strm.avail_out = chunkSize;
  17615. }
  17616. status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */
  17617. if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
  17618. this.onEnd(status);
  17619. this.ended = true;
  17620. return false;
  17621. }
  17622. if (strm.next_out) {
  17623. if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) {
  17624. if (this.options.to === 'string') {
  17625. next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
  17626. tail = strm.next_out - next_out_utf8;
  17627. utf8str = strings.buf2string(strm.output, next_out_utf8);
  17628. // move tail
  17629. strm.next_out = tail;
  17630. strm.avail_out = chunkSize - tail;
  17631. if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }
  17632. this.onData(utf8str);
  17633. } else {
  17634. this.onData(utils.shrinkBuf(strm.output, strm.next_out));
  17635. }
  17636. }
  17637. }
  17638. } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END);
  17639. if (status === c.Z_STREAM_END) {
  17640. _mode = c.Z_FINISH;
  17641. }
  17642. // Finalize on the last chunk.
  17643. if (_mode === c.Z_FINISH) {
  17644. status = zlib_inflate.inflateEnd(this.strm);
  17645. this.onEnd(status);
  17646. this.ended = true;
  17647. return status === c.Z_OK;
  17648. }
  17649. return true;
  17650. };
  17651. /**
  17652. * Inflate#onData(chunk) -> Void
  17653. * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
  17654. * on js engine support. When string output requested, each chunk
  17655. * will be string.
  17656. *
  17657. * By default, stores data blocks in `chunks[]` property and glue
  17658. * those in `onEnd`. Override this handler, if you need another behaviour.
  17659. **/
  17660. Inflate.prototype.onData = function(chunk) {
  17661. this.chunks.push(chunk);
  17662. };
  17663. /**
  17664. * Inflate#onEnd(status) -> Void
  17665. * - status (Number): inflate status. 0 (Z_OK) on success,
  17666. * other if not.
  17667. *
  17668. * Called once after you tell inflate that input stream complete
  17669. * or error happenned. By default - join collected chunks,
  17670. * free memory and fill `results` / `err` properties.
  17671. **/
  17672. Inflate.prototype.onEnd = function(status) {
  17673. // On success - join
  17674. if (status === c.Z_OK) {
  17675. if (this.options.to === 'string') {
  17676. // Glue & convert here, until we teach pako to send
  17677. // utf8 alligned strings to onData
  17678. this.result = this.chunks.join('');
  17679. } else {
  17680. this.result = utils.flattenChunks(this.chunks);
  17681. }
  17682. }
  17683. this.chunks = [];
  17684. this.err = status;
  17685. this.msg = this.strm.msg;
  17686. };
  17687. /**
  17688. * inflate(data[, options]) -> Uint8Array|Array|String
  17689. * - data (Uint8Array|Array|String): input data to decompress.
  17690. * - options (Object): zlib inflate options.
  17691. *
  17692. * Decompress `data` with inflate/ungzip and `options`. Autodetect
  17693. * format via wrapper header by default. That's why we don't provide
  17694. * separate `ungzip` method.
  17695. *
  17696. * Supported options are:
  17697. *
  17698. * - windowBits
  17699. *
  17700. * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
  17701. * for more information.
  17702. *
  17703. * Sugar (options):
  17704. *
  17705. * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
  17706. * negative windowBits implicitly.
  17707. * - `to` (String) - if equal to 'string', then result will be converted
  17708. * from utf8 to utf16 (javascript) string. When string output requested,
  17709. * chunk length can differ from `chunkSize`, depending on content.
  17710. *
  17711. *
  17712. * ##### Example:
  17713. *
  17714. * ```javascript
  17715. * var pako = require('pako')
  17716. * , input = pako.deflate([1,2,3,4,5,6,7,8,9])
  17717. * , output;
  17718. *
  17719. * try {
  17720. * output = pako.inflate(input);
  17721. * } catch (err)
  17722. * console.log(err);
  17723. * }
  17724. * ```
  17725. **/
  17726. function inflate(input, options) {
  17727. var inflator = new Inflate(options);
  17728. inflator.push(input, true);
  17729. // That will never happens, if you don't cheat with options :)
  17730. if (inflator.err) { throw inflator.msg; }
  17731. return inflator.result;
  17732. }
  17733. /**
  17734. * inflateRaw(data[, options]) -> Uint8Array|Array|String
  17735. * - data (Uint8Array|Array|String): input data to decompress.
  17736. * - options (Object): zlib inflate options.
  17737. *
  17738. * The same as [[inflate]], but creates raw data, without wrapper
  17739. * (header and adler32 crc).
  17740. **/
  17741. function inflateRaw(input, options) {
  17742. options = options || {};
  17743. options.raw = true;
  17744. return inflate(input, options);
  17745. }
  17746. /**
  17747. * ungzip(data[, options]) -> Uint8Array|Array|String
  17748. * - data (Uint8Array|Array|String): input data to decompress.
  17749. * - options (Object): zlib inflate options.
  17750. *
  17751. * Just shortcut to [[inflate]], because it autodetects format
  17752. * by header.content. Done for convenience.
  17753. **/
  17754. exports.Inflate = Inflate;
  17755. exports.inflate = inflate;
  17756. exports.inflateRaw = inflateRaw;
  17757. exports.ungzip = inflate;
  17758. },{"./utils/common":66,"./utils/strings":67,"./zlib/constants":69,"./zlib/gzheader":72,"./zlib/inflate.js":74,"./zlib/messages":76,"./zlib/zstream":78}],66:[function(require,module,exports){
  17759. 'use strict';
  17760. var TYPED_OK = (typeof Uint8Array !== 'undefined') &&
  17761. (typeof Uint16Array !== 'undefined') &&
  17762. (typeof Int32Array !== 'undefined');
  17763. exports.assign = function (obj /*from1, from2, from3, ...*/) {
  17764. var sources = Array.prototype.slice.call(arguments, 1);
  17765. while (sources.length) {
  17766. var source = sources.shift();
  17767. if (!source) { continue; }
  17768. if (typeof(source) !== 'object') {
  17769. throw new TypeError(source + 'must be non-object');
  17770. }
  17771. for (var p in source) {
  17772. if (source.hasOwnProperty(p)) {
  17773. obj[p] = source[p];
  17774. }
  17775. }
  17776. }
  17777. return obj;
  17778. };
  17779. // reduce buffer size, avoiding mem copy
  17780. exports.shrinkBuf = function (buf, size) {
  17781. if (buf.length === size) { return buf; }
  17782. if (buf.subarray) { return buf.subarray(0, size); }
  17783. buf.length = size;
  17784. return buf;
  17785. };
  17786. var fnTyped = {
  17787. arraySet: function (dest, src, src_offs, len, dest_offs) {
  17788. if (src.subarray && dest.subarray) {
  17789. dest.set(src.subarray(src_offs, src_offs+len), dest_offs);
  17790. return;
  17791. }
  17792. // Fallback to ordinary array
  17793. for(var i=0; i<len; i++) {
  17794. dest[dest_offs + i] = src[src_offs + i];
  17795. }
  17796. },
  17797. // Join array of chunks to single array.
  17798. flattenChunks: function(chunks) {
  17799. var i, l, len, pos, chunk, result;
  17800. // calculate data length
  17801. len = 0;
  17802. for (i=0, l=chunks.length; i<l; i++) {
  17803. len += chunks[i].length;
  17804. }
  17805. // join chunks
  17806. result = new Uint8Array(len);
  17807. pos = 0;
  17808. for (i=0, l=chunks.length; i<l; i++) {
  17809. chunk = chunks[i];
  17810. result.set(chunk, pos);
  17811. pos += chunk.length;
  17812. }
  17813. return result;
  17814. }
  17815. };
  17816. var fnUntyped = {
  17817. arraySet: function (dest, src, src_offs, len, dest_offs) {
  17818. for(var i=0; i<len; i++) {
  17819. dest[dest_offs + i] = src[src_offs + i];
  17820. }
  17821. },
  17822. // Join array of chunks to single array.
  17823. flattenChunks: function(chunks) {
  17824. return [].concat.apply([], chunks);
  17825. }
  17826. };
  17827. // Enable/Disable typed arrays use, for testing
  17828. //
  17829. exports.setTyped = function (on) {
  17830. if (on) {
  17831. exports.Buf8 = Uint8Array;
  17832. exports.Buf16 = Uint16Array;
  17833. exports.Buf32 = Int32Array;
  17834. exports.assign(exports, fnTyped);
  17835. } else {
  17836. exports.Buf8 = Array;
  17837. exports.Buf16 = Array;
  17838. exports.Buf32 = Array;
  17839. exports.assign(exports, fnUntyped);
  17840. }
  17841. };
  17842. exports.setTyped(TYPED_OK);
  17843. },{}],67:[function(require,module,exports){
  17844. // String encode/decode helpers
  17845. 'use strict';
  17846. var utils = require('./common');
  17847. // Quick check if we can use fast array to bin string conversion
  17848. //
  17849. // - apply(Array) can fail on Android 2.2
  17850. // - apply(Uint8Array) can fail on iOS 5.1 Safary
  17851. //
  17852. var STR_APPLY_OK = true;
  17853. var STR_APPLY_UIA_OK = true;
  17854. try { String.fromCharCode.apply(null, [0]); } catch(__) { STR_APPLY_OK = false; }
  17855. try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch(__) { STR_APPLY_UIA_OK = false; }
  17856. // Table with utf8 lengths (calculated by first byte of sequence)
  17857. // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
  17858. // because max possible codepoint is 0x10ffff
  17859. var _utf8len = new utils.Buf8(256);
  17860. for (var i=0; i<256; i++) {
  17861. _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);
  17862. }
  17863. _utf8len[254]=_utf8len[254]=1; // Invalid sequence start
  17864. // convert string to array (typed, when possible)
  17865. exports.string2buf = function (str) {
  17866. var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
  17867. // count binary size
  17868. for (m_pos = 0; m_pos < str_len; m_pos++) {
  17869. c = str.charCodeAt(m_pos);
  17870. if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
  17871. c2 = str.charCodeAt(m_pos+1);
  17872. if ((c2 & 0xfc00) === 0xdc00) {
  17873. c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
  17874. m_pos++;
  17875. }
  17876. }
  17877. buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
  17878. }
  17879. // allocate buffer
  17880. buf = new utils.Buf8(buf_len);
  17881. // convert
  17882. for (i=0, m_pos = 0; i < buf_len; m_pos++) {
  17883. c = str.charCodeAt(m_pos);
  17884. if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
  17885. c2 = str.charCodeAt(m_pos+1);
  17886. if ((c2 & 0xfc00) === 0xdc00) {
  17887. c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
  17888. m_pos++;
  17889. }
  17890. }
  17891. if (c < 0x80) {
  17892. /* one byte */
  17893. buf[i++] = c;
  17894. } else if (c < 0x800) {
  17895. /* two bytes */
  17896. buf[i++] = 0xC0 | (c >>> 6);
  17897. buf[i++] = 0x80 | (c & 0x3f);
  17898. } else if (c < 0x10000) {
  17899. /* three bytes */
  17900. buf[i++] = 0xE0 | (c >>> 12);
  17901. buf[i++] = 0x80 | (c >>> 6 & 0x3f);
  17902. buf[i++] = 0x80 | (c & 0x3f);
  17903. } else {
  17904. /* four bytes */
  17905. buf[i++] = 0xf0 | (c >>> 18);
  17906. buf[i++] = 0x80 | (c >>> 12 & 0x3f);
  17907. buf[i++] = 0x80 | (c >>> 6 & 0x3f);
  17908. buf[i++] = 0x80 | (c & 0x3f);
  17909. }
  17910. }
  17911. return buf;
  17912. };
  17913. // Helper (used in 2 places)
  17914. function buf2binstring(buf, len) {
  17915. // use fallback for big arrays to avoid stack overflow
  17916. if (len < 65537) {
  17917. if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {
  17918. return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
  17919. }
  17920. }
  17921. var result = '';
  17922. for(var i=0; i < len; i++) {
  17923. result += String.fromCharCode(buf[i]);
  17924. }
  17925. return result;
  17926. }
  17927. // Convert byte array to binary string
  17928. exports.buf2binstring = function(buf) {
  17929. return buf2binstring(buf, buf.length);
  17930. };
  17931. // Convert binary string (typed, when possible)
  17932. exports.binstring2buf = function(str) {
  17933. var buf = new utils.Buf8(str.length);
  17934. for(var i=0, len=buf.length; i < len; i++) {
  17935. buf[i] = str.charCodeAt(i);
  17936. }
  17937. return buf;
  17938. };
  17939. // convert array to string
  17940. exports.buf2string = function (buf, max) {
  17941. var i, out, c, c_len;
  17942. var len = max || buf.length;
  17943. // Reserve max possible length (2 words per char)
  17944. // NB: by unknown reasons, Array is significantly faster for
  17945. // String.fromCharCode.apply than Uint16Array.
  17946. var utf16buf = new Array(len*2);
  17947. for (out=0, i=0; i<len;) {
  17948. c = buf[i++];
  17949. // quick process ascii
  17950. if (c < 0x80) { utf16buf[out++] = c; continue; }
  17951. c_len = _utf8len[c];
  17952. // skip 5 & 6 byte codes
  17953. if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }
  17954. // apply mask on first byte
  17955. c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
  17956. // join the rest
  17957. while (c_len > 1 && i < len) {
  17958. c = (c << 6) | (buf[i++] & 0x3f);
  17959. c_len--;
  17960. }
  17961. // terminated by end of string?
  17962. if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
  17963. if (c < 0x10000) {
  17964. utf16buf[out++] = c;
  17965. } else {
  17966. c -= 0x10000;
  17967. utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
  17968. utf16buf[out++] = 0xdc00 | (c & 0x3ff);
  17969. }
  17970. }
  17971. return buf2binstring(utf16buf, out);
  17972. };
  17973. // Calculate max possible position in utf8 buffer,
  17974. // that will not break sequence. If that's not possible
  17975. // - (very small limits) return max size as is.
  17976. //
  17977. // buf[] - utf8 bytes array
  17978. // max - length limit (mandatory);
  17979. exports.utf8border = function(buf, max) {
  17980. var pos;
  17981. max = max || buf.length;
  17982. if (max > buf.length) { max = buf.length; }
  17983. // go back from last position, until start of sequence found
  17984. pos = max-1;
  17985. while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
  17986. // Fuckup - very small and broken sequence,
  17987. // return max, because we should return something anyway.
  17988. if (pos < 0) { return max; }
  17989. // If we came to start of buffer - that means vuffer is too small,
  17990. // return max too.
  17991. if (pos === 0) { return max; }
  17992. return (pos + _utf8len[buf[pos]] > max) ? pos : max;
  17993. };
  17994. },{"./common":66}],68:[function(require,module,exports){
  17995. 'use strict';
  17996. // Note: adler32 takes 12% for level 0 and 2% for level 6.
  17997. // It doesn't worth to make additional optimizationa as in original.
  17998. // Small size is preferable.
  17999. function adler32(adler, buf, len, pos) {
  18000. var s1 = (adler & 0xffff) |0
  18001. , s2 = ((adler >>> 16) & 0xffff) |0
  18002. , n = 0;
  18003. while (len !== 0) {
  18004. // Set limit ~ twice less than 5552, to keep
  18005. // s2 in 31-bits, because we force signed ints.
  18006. // in other case %= will fail.
  18007. n = len > 2000 ? 2000 : len;
  18008. len -= n;
  18009. do {
  18010. s1 = (s1 + buf[pos++]) |0;
  18011. s2 = (s2 + s1) |0;
  18012. } while (--n);
  18013. s1 %= 65521;
  18014. s2 %= 65521;
  18015. }
  18016. return (s1 | (s2 << 16)) |0;
  18017. }
  18018. module.exports = adler32;
  18019. },{}],69:[function(require,module,exports){
  18020. module.exports = {
  18021. /* Allowed flush values; see deflate() and inflate() below for details */
  18022. Z_NO_FLUSH: 0,
  18023. Z_PARTIAL_FLUSH: 1,
  18024. Z_SYNC_FLUSH: 2,
  18025. Z_FULL_FLUSH: 3,
  18026. Z_FINISH: 4,
  18027. Z_BLOCK: 5,
  18028. Z_TREES: 6,
  18029. /* Return codes for the compression/decompression functions. Negative values
  18030. * are errors, positive values are used for special but normal events.
  18031. */
  18032. Z_OK: 0,
  18033. Z_STREAM_END: 1,
  18034. Z_NEED_DICT: 2,
  18035. Z_ERRNO: -1,
  18036. Z_STREAM_ERROR: -2,
  18037. Z_DATA_ERROR: -3,
  18038. //Z_MEM_ERROR: -4,
  18039. Z_BUF_ERROR: -5,
  18040. //Z_VERSION_ERROR: -6,
  18041. /* compression levels */
  18042. Z_NO_COMPRESSION: 0,
  18043. Z_BEST_SPEED: 1,
  18044. Z_BEST_COMPRESSION: 9,
  18045. Z_DEFAULT_COMPRESSION: -1,
  18046. Z_FILTERED: 1,
  18047. Z_HUFFMAN_ONLY: 2,
  18048. Z_RLE: 3,
  18049. Z_FIXED: 4,
  18050. Z_DEFAULT_STRATEGY: 0,
  18051. /* Possible values of the data_type field (though see inflate()) */
  18052. Z_BINARY: 0,
  18053. Z_TEXT: 1,
  18054. //Z_ASCII: 1, // = Z_TEXT (deprecated)
  18055. Z_UNKNOWN: 2,
  18056. /* The deflate compression method */
  18057. Z_DEFLATED: 8
  18058. //Z_NULL: null // Use -1 or null inline, depending on var type
  18059. };
  18060. },{}],70:[function(require,module,exports){
  18061. 'use strict';
  18062. // Note: we can't get significant speed boost here.
  18063. // So write code to minimize size - no pregenerated tables
  18064. // and array tools dependencies.
  18065. // Use ordinary array, since untyped makes no boost here
  18066. function makeTable() {
  18067. var c, table = [];
  18068. for(var n =0; n < 256; n++){
  18069. c = n;
  18070. for(var k =0; k < 8; k++){
  18071. c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
  18072. }
  18073. table[n] = c;
  18074. }
  18075. return table;
  18076. }
  18077. // Create table on load. Just 255 signed longs. Not a problem.
  18078. var crcTable = makeTable();
  18079. function crc32(crc, buf, len, pos) {
  18080. var t = crcTable
  18081. , end = pos + len;
  18082. crc = crc ^ (-1);
  18083. for (var i = pos; i < end; i++ ) {
  18084. crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
  18085. }
  18086. return (crc ^ (-1)); // >>> 0;
  18087. }
  18088. module.exports = crc32;
  18089. },{}],71:[function(require,module,exports){
  18090. 'use strict';
  18091. var utils = require('../utils/common');
  18092. var trees = require('./trees');
  18093. var adler32 = require('./adler32');
  18094. var crc32 = require('./crc32');
  18095. var msg = require('./messages');
  18096. /* Public constants ==========================================================*/
  18097. /* ===========================================================================*/
  18098. /* Allowed flush values; see deflate() and inflate() below for details */
  18099. var Z_NO_FLUSH = 0;
  18100. var Z_PARTIAL_FLUSH = 1;
  18101. //var Z_SYNC_FLUSH = 2;
  18102. var Z_FULL_FLUSH = 3;
  18103. var Z_FINISH = 4;
  18104. var Z_BLOCK = 5;
  18105. //var Z_TREES = 6;
  18106. /* Return codes for the compression/decompression functions. Negative values
  18107. * are errors, positive values are used for special but normal events.
  18108. */
  18109. var Z_OK = 0;
  18110. var Z_STREAM_END = 1;
  18111. //var Z_NEED_DICT = 2;
  18112. //var Z_ERRNO = -1;
  18113. var Z_STREAM_ERROR = -2;
  18114. var Z_DATA_ERROR = -3;
  18115. //var Z_MEM_ERROR = -4;
  18116. var Z_BUF_ERROR = -5;
  18117. //var Z_VERSION_ERROR = -6;
  18118. /* compression levels */
  18119. //var Z_NO_COMPRESSION = 0;
  18120. //var Z_BEST_SPEED = 1;
  18121. //var Z_BEST_COMPRESSION = 9;
  18122. var Z_DEFAULT_COMPRESSION = -1;
  18123. var Z_FILTERED = 1;
  18124. var Z_HUFFMAN_ONLY = 2;
  18125. var Z_RLE = 3;
  18126. var Z_FIXED = 4;
  18127. var Z_DEFAULT_STRATEGY = 0;
  18128. /* Possible values of the data_type field (though see inflate()) */
  18129. //var Z_BINARY = 0;
  18130. //var Z_TEXT = 1;
  18131. //var Z_ASCII = 1; // = Z_TEXT
  18132. var Z_UNKNOWN = 2;
  18133. /* The deflate compression method */
  18134. var Z_DEFLATED = 8;
  18135. /*============================================================================*/
  18136. var MAX_MEM_LEVEL = 9;
  18137. /* Maximum value for memLevel in deflateInit2 */
  18138. var MAX_WBITS = 15;
  18139. /* 32K LZ77 window */
  18140. var DEF_MEM_LEVEL = 8;
  18141. var LENGTH_CODES = 29;
  18142. /* number of length codes, not counting the special END_BLOCK code */
  18143. var LITERALS = 256;
  18144. /* number of literal bytes 0..255 */
  18145. var L_CODES = LITERALS + 1 + LENGTH_CODES;
  18146. /* number of Literal or Length codes, including the END_BLOCK code */
  18147. var D_CODES = 30;
  18148. /* number of distance codes */
  18149. var BL_CODES = 19;
  18150. /* number of codes used to transfer the bit lengths */
  18151. var HEAP_SIZE = 2*L_CODES + 1;
  18152. /* maximum heap size */
  18153. var MAX_BITS = 15;
  18154. /* All codes must not exceed MAX_BITS bits */
  18155. var MIN_MATCH = 3;
  18156. var MAX_MATCH = 258;
  18157. var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
  18158. var PRESET_DICT = 0x20;
  18159. var INIT_STATE = 42;
  18160. var EXTRA_STATE = 69;
  18161. var NAME_STATE = 73;
  18162. var COMMENT_STATE = 91;
  18163. var HCRC_STATE = 103;
  18164. var BUSY_STATE = 113;
  18165. var FINISH_STATE = 666;
  18166. var BS_NEED_MORE = 1; /* block not completed, need more input or more output */
  18167. var BS_BLOCK_DONE = 2; /* block flush performed */
  18168. var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
  18169. var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */
  18170. var OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
  18171. function err(strm, errorCode) {
  18172. strm.msg = msg[errorCode];
  18173. return errorCode;
  18174. }
  18175. function rank(f) {
  18176. return ((f) << 1) - ((f) > 4 ? 9 : 0);
  18177. }
  18178. function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
  18179. /* =========================================================================
  18180. * Flush as much pending output as possible. All deflate() output goes
  18181. * through this function so some applications may wish to modify it
  18182. * to avoid allocating a large strm->output buffer and copying into it.
  18183. * (See also read_buf()).
  18184. */
  18185. function flush_pending(strm) {
  18186. var s = strm.state;
  18187. //_tr_flush_bits(s);
  18188. var len = s.pending;
  18189. if (len > strm.avail_out) {
  18190. len = strm.avail_out;
  18191. }
  18192. if (len === 0) { return; }
  18193. utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
  18194. strm.next_out += len;
  18195. s.pending_out += len;
  18196. strm.total_out += len;
  18197. strm.avail_out -= len;
  18198. s.pending -= len;
  18199. if (s.pending === 0) {
  18200. s.pending_out = 0;
  18201. }
  18202. }
  18203. function flush_block_only (s, last) {
  18204. trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
  18205. s.block_start = s.strstart;
  18206. flush_pending(s.strm);
  18207. }
  18208. function put_byte(s, b) {
  18209. s.pending_buf[s.pending++] = b;
  18210. }
  18211. /* =========================================================================
  18212. * Put a short in the pending buffer. The 16-bit value is put in MSB order.
  18213. * IN assertion: the stream state is correct and there is enough room in
  18214. * pending_buf.
  18215. */
  18216. function putShortMSB(s, b) {
  18217. // put_byte(s, (Byte)(b >> 8));
  18218. // put_byte(s, (Byte)(b & 0xff));
  18219. s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
  18220. s.pending_buf[s.pending++] = b & 0xff;
  18221. }
  18222. /* ===========================================================================
  18223. * Read a new buffer from the current input stream, update the adler32
  18224. * and total number of bytes read. All deflate() input goes through
  18225. * this function so some applications may wish to modify it to avoid
  18226. * allocating a large strm->input buffer and copying from it.
  18227. * (See also flush_pending()).
  18228. */
  18229. function read_buf(strm, buf, start, size) {
  18230. var len = strm.avail_in;
  18231. if (len > size) { len = size; }
  18232. if (len === 0) { return 0; }
  18233. strm.avail_in -= len;
  18234. utils.arraySet(buf, strm.input, strm.next_in, len, start);
  18235. if (strm.state.wrap === 1) {
  18236. strm.adler = adler32(strm.adler, buf, len, start);
  18237. }
  18238. else if (strm.state.wrap === 2) {
  18239. strm.adler = crc32(strm.adler, buf, len, start);
  18240. }
  18241. strm.next_in += len;
  18242. strm.total_in += len;
  18243. return len;
  18244. }
  18245. /* ===========================================================================
  18246. * Set match_start to the longest match starting at the given string and
  18247. * return its length. Matches shorter or equal to prev_length are discarded,
  18248. * in which case the result is equal to prev_length and match_start is
  18249. * garbage.
  18250. * IN assertions: cur_match is the head of the hash chain for the current
  18251. * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
  18252. * OUT assertion: the match length is not greater than s->lookahead.
  18253. */
  18254. function longest_match(s, cur_match) {
  18255. var chain_length = s.max_chain_length; /* max hash chain length */
  18256. var scan = s.strstart; /* current string */
  18257. var match; /* matched string */
  18258. var len; /* length of current match */
  18259. var best_len = s.prev_length; /* best match length so far */
  18260. var nice_match = s.nice_match; /* stop if match long enough */
  18261. var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
  18262. s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
  18263. var _win = s.window; // shortcut
  18264. var wmask = s.w_mask;
  18265. var prev = s.prev;
  18266. /* Stop when cur_match becomes <= limit. To simplify the code,
  18267. * we prevent matches with the string of window index 0.
  18268. */
  18269. var strend = s.strstart + MAX_MATCH;
  18270. var scan_end1 = _win[scan + best_len - 1];
  18271. var scan_end = _win[scan + best_len];
  18272. /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
  18273. * It is easy to get rid of this optimization if necessary.
  18274. */
  18275. // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
  18276. /* Do not waste too much time if we already have a good match: */
  18277. if (s.prev_length >= s.good_match) {
  18278. chain_length >>= 2;
  18279. }
  18280. /* Do not look for matches beyond the end of the input. This is necessary
  18281. * to make deflate deterministic.
  18282. */
  18283. if (nice_match > s.lookahead) { nice_match = s.lookahead; }
  18284. // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
  18285. do {
  18286. // Assert(cur_match < s->strstart, "no future");
  18287. match = cur_match;
  18288. /* Skip to next match if the match length cannot increase
  18289. * or if the match length is less than 2. Note that the checks below
  18290. * for insufficient lookahead only occur occasionally for performance
  18291. * reasons. Therefore uninitialized memory will be accessed, and
  18292. * conditional jumps will be made that depend on those values.
  18293. * However the length of the match is limited to the lookahead, so
  18294. * the output of deflate is not affected by the uninitialized values.
  18295. */
  18296. if (_win[match + best_len] !== scan_end ||
  18297. _win[match + best_len - 1] !== scan_end1 ||
  18298. _win[match] !== _win[scan] ||
  18299. _win[++match] !== _win[scan + 1]) {
  18300. continue;
  18301. }
  18302. /* The check at best_len-1 can be removed because it will be made
  18303. * again later. (This heuristic is not always a win.)
  18304. * It is not necessary to compare scan[2] and match[2] since they
  18305. * are always equal when the other bytes match, given that
  18306. * the hash keys are equal and that HASH_BITS >= 8.
  18307. */
  18308. scan += 2;
  18309. match++;
  18310. // Assert(*scan == *match, "match[2]?");
  18311. /* We check for insufficient lookahead only every 8th comparison;
  18312. * the 256th check will be made at strstart+258.
  18313. */
  18314. do {
  18315. /*jshint noempty:false*/
  18316. } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
  18317. _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
  18318. _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
  18319. _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
  18320. scan < strend);
  18321. // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
  18322. len = MAX_MATCH - (strend - scan);
  18323. scan = strend - MAX_MATCH;
  18324. if (len > best_len) {
  18325. s.match_start = cur_match;
  18326. best_len = len;
  18327. if (len >= nice_match) {
  18328. break;
  18329. }
  18330. scan_end1 = _win[scan + best_len - 1];
  18331. scan_end = _win[scan + best_len];
  18332. }
  18333. } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
  18334. if (best_len <= s.lookahead) {
  18335. return best_len;
  18336. }
  18337. return s.lookahead;
  18338. }
  18339. /* ===========================================================================
  18340. * Fill the window when the lookahead becomes insufficient.
  18341. * Updates strstart and lookahead.
  18342. *
  18343. * IN assertion: lookahead < MIN_LOOKAHEAD
  18344. * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
  18345. * At least one byte has been read, or avail_in == 0; reads are
  18346. * performed for at least two bytes (required for the zip translate_eol
  18347. * option -- not supported here).
  18348. */
  18349. function fill_window(s) {
  18350. var _w_size = s.w_size;
  18351. var p, n, m, more, str;
  18352. //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
  18353. do {
  18354. more = s.window_size - s.lookahead - s.strstart;
  18355. // JS ints have 32 bit, block below not needed
  18356. /* Deal with !@#$% 64K limit: */
  18357. //if (sizeof(int) <= 2) {
  18358. // if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
  18359. // more = wsize;
  18360. //
  18361. // } else if (more == (unsigned)(-1)) {
  18362. // /* Very unlikely, but possible on 16 bit machine if
  18363. // * strstart == 0 && lookahead == 1 (input done a byte at time)
  18364. // */
  18365. // more--;
  18366. // }
  18367. //}
  18368. /* If the window is almost full and there is insufficient lookahead,
  18369. * move the upper half to the lower one to make room in the upper half.
  18370. */
  18371. if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
  18372. utils.arraySet(s.window, s.window, _w_size, _w_size, 0);
  18373. s.match_start -= _w_size;
  18374. s.strstart -= _w_size;
  18375. /* we now have strstart >= MAX_DIST */
  18376. s.block_start -= _w_size;
  18377. /* Slide the hash table (could be avoided with 32 bit values
  18378. at the expense of memory usage). We slide even when level == 0
  18379. to keep the hash table consistent if we switch back to level > 0
  18380. later. (Using level 0 permanently is not an optimal usage of
  18381. zlib, so we don't care about this pathological case.)
  18382. */
  18383. n = s.hash_size;
  18384. p = n;
  18385. do {
  18386. m = s.head[--p];
  18387. s.head[p] = (m >= _w_size ? m - _w_size : 0);
  18388. } while (--n);
  18389. n = _w_size;
  18390. p = n;
  18391. do {
  18392. m = s.prev[--p];
  18393. s.prev[p] = (m >= _w_size ? m - _w_size : 0);
  18394. /* If n is not on any hash chain, prev[n] is garbage but
  18395. * its value will never be used.
  18396. */
  18397. } while (--n);
  18398. more += _w_size;
  18399. }
  18400. if (s.strm.avail_in === 0) {
  18401. break;
  18402. }
  18403. /* If there was no sliding:
  18404. * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
  18405. * more == window_size - lookahead - strstart
  18406. * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
  18407. * => more >= window_size - 2*WSIZE + 2
  18408. * In the BIG_MEM or MMAP case (not yet supported),
  18409. * window_size == input_size + MIN_LOOKAHEAD &&
  18410. * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
  18411. * Otherwise, window_size == 2*WSIZE so more >= 2.
  18412. * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
  18413. */
  18414. //Assert(more >= 2, "more < 2");
  18415. n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
  18416. s.lookahead += n;
  18417. /* Initialize the hash value now that we have some input: */
  18418. if (s.lookahead + s.insert >= MIN_MATCH) {
  18419. str = s.strstart - s.insert;
  18420. s.ins_h = s.window[str];
  18421. /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
  18422. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;
  18423. //#if MIN_MATCH != 3
  18424. // Call update_hash() MIN_MATCH-3 more times
  18425. //#endif
  18426. while (s.insert) {
  18427. /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
  18428. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask;
  18429. s.prev[str & s.w_mask] = s.head[s.ins_h];
  18430. s.head[s.ins_h] = str;
  18431. str++;
  18432. s.insert--;
  18433. if (s.lookahead + s.insert < MIN_MATCH) {
  18434. break;
  18435. }
  18436. }
  18437. }
  18438. /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
  18439. * but this is not important since only literal bytes will be emitted.
  18440. */
  18441. } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
  18442. /* If the WIN_INIT bytes after the end of the current data have never been
  18443. * written, then zero those bytes in order to avoid memory check reports of
  18444. * the use of uninitialized (or uninitialised as Julian writes) bytes by
  18445. * the longest match routines. Update the high water mark for the next
  18446. * time through here. WIN_INIT is set to MAX_MATCH since the longest match
  18447. * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
  18448. */
  18449. // if (s.high_water < s.window_size) {
  18450. // var curr = s.strstart + s.lookahead;
  18451. // var init = 0;
  18452. //
  18453. // if (s.high_water < curr) {
  18454. // /* Previous high water mark below current data -- zero WIN_INIT
  18455. // * bytes or up to end of window, whichever is less.
  18456. // */
  18457. // init = s.window_size - curr;
  18458. // if (init > WIN_INIT)
  18459. // init = WIN_INIT;
  18460. // zmemzero(s->window + curr, (unsigned)init);
  18461. // s->high_water = curr + init;
  18462. // }
  18463. // else if (s->high_water < (ulg)curr + WIN_INIT) {
  18464. // /* High water mark at or above current data, but below current data
  18465. // * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
  18466. // * to end of window, whichever is less.
  18467. // */
  18468. // init = (ulg)curr + WIN_INIT - s->high_water;
  18469. // if (init > s->window_size - s->high_water)
  18470. // init = s->window_size - s->high_water;
  18471. // zmemzero(s->window + s->high_water, (unsigned)init);
  18472. // s->high_water += init;
  18473. // }
  18474. // }
  18475. //
  18476. // Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
  18477. // "not enough room for search");
  18478. }
  18479. /* ===========================================================================
  18480. * Copy without compression as much as possible from the input stream, return
  18481. * the current block state.
  18482. * This function does not insert new strings in the dictionary since
  18483. * uncompressible data is probably not useful. This function is used
  18484. * only for the level=0 compression option.
  18485. * NOTE: this function should be optimized to avoid extra copying from
  18486. * window to pending_buf.
  18487. */
  18488. function deflate_stored(s, flush) {
  18489. /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
  18490. * to pending_buf_size, and each stored block has a 5 byte header:
  18491. */
  18492. var max_block_size = 0xffff;
  18493. if (max_block_size > s.pending_buf_size - 5) {
  18494. max_block_size = s.pending_buf_size - 5;
  18495. }
  18496. /* Copy as much as possible from input to output: */
  18497. for (;;) {
  18498. /* Fill the window as much as possible: */
  18499. if (s.lookahead <= 1) {
  18500. //Assert(s->strstart < s->w_size+MAX_DIST(s) ||
  18501. // s->block_start >= (long)s->w_size, "slide too late");
  18502. // if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
  18503. // s.block_start >= s.w_size)) {
  18504. // throw new Error("slide too late");
  18505. // }
  18506. fill_window(s);
  18507. if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
  18508. return BS_NEED_MORE;
  18509. }
  18510. if (s.lookahead === 0) {
  18511. break;
  18512. }
  18513. /* flush the current block */
  18514. }
  18515. //Assert(s->block_start >= 0L, "block gone");
  18516. // if (s.block_start < 0) throw new Error("block gone");
  18517. s.strstart += s.lookahead;
  18518. s.lookahead = 0;
  18519. /* Emit a stored block if pending_buf will be full: */
  18520. var max_start = s.block_start + max_block_size;
  18521. if (s.strstart === 0 || s.strstart >= max_start) {
  18522. /* strstart == 0 is possible when wraparound on 16-bit machine */
  18523. s.lookahead = s.strstart - max_start;
  18524. s.strstart = max_start;
  18525. /*** FLUSH_BLOCK(s, 0); ***/
  18526. flush_block_only(s, false);
  18527. if (s.strm.avail_out === 0) {
  18528. return BS_NEED_MORE;
  18529. }
  18530. /***/
  18531. }
  18532. /* Flush if we may have to slide, otherwise block_start may become
  18533. * negative and the data will be gone:
  18534. */
  18535. if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
  18536. /*** FLUSH_BLOCK(s, 0); ***/
  18537. flush_block_only(s, false);
  18538. if (s.strm.avail_out === 0) {
  18539. return BS_NEED_MORE;
  18540. }
  18541. /***/
  18542. }
  18543. }
  18544. s.insert = 0;
  18545. if (flush === Z_FINISH) {
  18546. /*** FLUSH_BLOCK(s, 1); ***/
  18547. flush_block_only(s, true);
  18548. if (s.strm.avail_out === 0) {
  18549. return BS_FINISH_STARTED;
  18550. }
  18551. /***/
  18552. return BS_FINISH_DONE;
  18553. }
  18554. if (s.strstart > s.block_start) {
  18555. /*** FLUSH_BLOCK(s, 0); ***/
  18556. flush_block_only(s, false);
  18557. if (s.strm.avail_out === 0) {
  18558. return BS_NEED_MORE;
  18559. }
  18560. /***/
  18561. }
  18562. return BS_NEED_MORE;
  18563. }
  18564. /* ===========================================================================
  18565. * Compress as much as possible from the input stream, return the current
  18566. * block state.
  18567. * This function does not perform lazy evaluation of matches and inserts
  18568. * new strings in the dictionary only for unmatched strings or for short
  18569. * matches. It is used only for the fast compression options.
  18570. */
  18571. function deflate_fast(s, flush) {
  18572. var hash_head; /* head of the hash chain */
  18573. var bflush; /* set if current block must be flushed */
  18574. for (;;) {
  18575. /* Make sure that we always have enough lookahead, except
  18576. * at the end of the input file. We need MAX_MATCH bytes
  18577. * for the next match, plus MIN_MATCH bytes to insert the
  18578. * string following the next match.
  18579. */
  18580. if (s.lookahead < MIN_LOOKAHEAD) {
  18581. fill_window(s);
  18582. if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
  18583. return BS_NEED_MORE;
  18584. }
  18585. if (s.lookahead === 0) {
  18586. break; /* flush the current block */
  18587. }
  18588. }
  18589. /* Insert the string window[strstart .. strstart+2] in the
  18590. * dictionary, and set hash_head to the head of the hash chain:
  18591. */
  18592. hash_head = 0/*NIL*/;
  18593. if (s.lookahead >= MIN_MATCH) {
  18594. /*** INSERT_STRING(s, s.strstart, hash_head); ***/
  18595. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
  18596. hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
  18597. s.head[s.ins_h] = s.strstart;
  18598. /***/
  18599. }
  18600. /* Find the longest match, discarding those <= prev_length.
  18601. * At this point we have always match_length < MIN_MATCH
  18602. */
  18603. if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
  18604. /* To simplify the code, we prevent matches with the string
  18605. * of window index 0 (in particular we have to avoid a match
  18606. * of the string with itself at the start of the input file).
  18607. */
  18608. s.match_length = longest_match(s, hash_head);
  18609. /* longest_match() sets match_start */
  18610. }
  18611. if (s.match_length >= MIN_MATCH) {
  18612. // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
  18613. /*** _tr_tally_dist(s, s.strstart - s.match_start,
  18614. s.match_length - MIN_MATCH, bflush); ***/
  18615. bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
  18616. s.lookahead -= s.match_length;
  18617. /* Insert new strings in the hash table only if the match length
  18618. * is not too large. This saves time but degrades compression.
  18619. */
  18620. if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
  18621. s.match_length--; /* string at strstart already in table */
  18622. do {
  18623. s.strstart++;
  18624. /*** INSERT_STRING(s, s.strstart, hash_head); ***/
  18625. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
  18626. hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
  18627. s.head[s.ins_h] = s.strstart;
  18628. /***/
  18629. /* strstart never exceeds WSIZE-MAX_MATCH, so there are
  18630. * always MIN_MATCH bytes ahead.
  18631. */
  18632. } while (--s.match_length !== 0);
  18633. s.strstart++;
  18634. } else
  18635. {
  18636. s.strstart += s.match_length;
  18637. s.match_length = 0;
  18638. s.ins_h = s.window[s.strstart];
  18639. /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
  18640. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;
  18641. //#if MIN_MATCH != 3
  18642. // Call UPDATE_HASH() MIN_MATCH-3 more times
  18643. //#endif
  18644. /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
  18645. * matter since it will be recomputed at next deflate call.
  18646. */
  18647. }
  18648. } else {
  18649. /* No match, output a literal byte */
  18650. //Tracevv((stderr,"%c", s.window[s.strstart]));
  18651. /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
  18652. bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
  18653. s.lookahead--;
  18654. s.strstart++;
  18655. }
  18656. if (bflush) {
  18657. /*** FLUSH_BLOCK(s, 0); ***/
  18658. flush_block_only(s, false);
  18659. if (s.strm.avail_out === 0) {
  18660. return BS_NEED_MORE;
  18661. }
  18662. /***/
  18663. }
  18664. }
  18665. s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1);
  18666. if (flush === Z_FINISH) {
  18667. /*** FLUSH_BLOCK(s, 1); ***/
  18668. flush_block_only(s, true);
  18669. if (s.strm.avail_out === 0) {
  18670. return BS_FINISH_STARTED;
  18671. }
  18672. /***/
  18673. return BS_FINISH_DONE;
  18674. }
  18675. if (s.last_lit) {
  18676. /*** FLUSH_BLOCK(s, 0); ***/
  18677. flush_block_only(s, false);
  18678. if (s.strm.avail_out === 0) {
  18679. return BS_NEED_MORE;
  18680. }
  18681. /***/
  18682. }
  18683. return BS_BLOCK_DONE;
  18684. }
  18685. /* ===========================================================================
  18686. * Same as above, but achieves better compression. We use a lazy
  18687. * evaluation for matches: a match is finally adopted only if there is
  18688. * no better match at the next window position.
  18689. */
  18690. function deflate_slow(s, flush) {
  18691. var hash_head; /* head of hash chain */
  18692. var bflush; /* set if current block must be flushed */
  18693. var max_insert;
  18694. /* Process the input block. */
  18695. for (;;) {
  18696. /* Make sure that we always have enough lookahead, except
  18697. * at the end of the input file. We need MAX_MATCH bytes
  18698. * for the next match, plus MIN_MATCH bytes to insert the
  18699. * string following the next match.
  18700. */
  18701. if (s.lookahead < MIN_LOOKAHEAD) {
  18702. fill_window(s);
  18703. if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
  18704. return BS_NEED_MORE;
  18705. }
  18706. if (s.lookahead === 0) { break; } /* flush the current block */
  18707. }
  18708. /* Insert the string window[strstart .. strstart+2] in the
  18709. * dictionary, and set hash_head to the head of the hash chain:
  18710. */
  18711. hash_head = 0/*NIL*/;
  18712. if (s.lookahead >= MIN_MATCH) {
  18713. /*** INSERT_STRING(s, s.strstart, hash_head); ***/
  18714. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
  18715. hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
  18716. s.head[s.ins_h] = s.strstart;
  18717. /***/
  18718. }
  18719. /* Find the longest match, discarding those <= prev_length.
  18720. */
  18721. s.prev_length = s.match_length;
  18722. s.prev_match = s.match_start;
  18723. s.match_length = MIN_MATCH-1;
  18724. if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
  18725. s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
  18726. /* To simplify the code, we prevent matches with the string
  18727. * of window index 0 (in particular we have to avoid a match
  18728. * of the string with itself at the start of the input file).
  18729. */
  18730. s.match_length = longest_match(s, hash_head);
  18731. /* longest_match() sets match_start */
  18732. if (s.match_length <= 5 &&
  18733. (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
  18734. /* If prev_match is also MIN_MATCH, match_start is garbage
  18735. * but we will ignore the current match anyway.
  18736. */
  18737. s.match_length = MIN_MATCH-1;
  18738. }
  18739. }
  18740. /* If there was a match at the previous step and the current
  18741. * match is not better, output the previous match:
  18742. */
  18743. if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
  18744. max_insert = s.strstart + s.lookahead - MIN_MATCH;
  18745. /* Do not insert strings in hash table beyond this. */
  18746. //check_match(s, s.strstart-1, s.prev_match, s.prev_length);
  18747. /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
  18748. s.prev_length - MIN_MATCH, bflush);***/
  18749. bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH);
  18750. /* Insert in hash table all strings up to the end of the match.
  18751. * strstart-1 and strstart are already inserted. If there is not
  18752. * enough lookahead, the last two strings are not inserted in
  18753. * the hash table.
  18754. */
  18755. s.lookahead -= s.prev_length-1;
  18756. s.prev_length -= 2;
  18757. do {
  18758. if (++s.strstart <= max_insert) {
  18759. /*** INSERT_STRING(s, s.strstart, hash_head); ***/
  18760. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
  18761. hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
  18762. s.head[s.ins_h] = s.strstart;
  18763. /***/
  18764. }
  18765. } while (--s.prev_length !== 0);
  18766. s.match_available = 0;
  18767. s.match_length = MIN_MATCH-1;
  18768. s.strstart++;
  18769. if (bflush) {
  18770. /*** FLUSH_BLOCK(s, 0); ***/
  18771. flush_block_only(s, false);
  18772. if (s.strm.avail_out === 0) {
  18773. return BS_NEED_MORE;
  18774. }
  18775. /***/
  18776. }
  18777. } else if (s.match_available) {
  18778. /* If there was no match at the previous position, output a
  18779. * single literal. If there was a match but the current match
  18780. * is longer, truncate the previous match to a single literal.
  18781. */
  18782. //Tracevv((stderr,"%c", s->window[s->strstart-1]));
  18783. /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
  18784. bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);
  18785. if (bflush) {
  18786. /*** FLUSH_BLOCK_ONLY(s, 0) ***/
  18787. flush_block_only(s, false);
  18788. /***/
  18789. }
  18790. s.strstart++;
  18791. s.lookahead--;
  18792. if (s.strm.avail_out === 0) {
  18793. return BS_NEED_MORE;
  18794. }
  18795. } else {
  18796. /* There is no previous match to compare with, wait for
  18797. * the next step to decide.
  18798. */
  18799. s.match_available = 1;
  18800. s.strstart++;
  18801. s.lookahead--;
  18802. }
  18803. }
  18804. //Assert (flush != Z_NO_FLUSH, "no flush?");
  18805. if (s.match_available) {
  18806. //Tracevv((stderr,"%c", s->window[s->strstart-1]));
  18807. /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
  18808. bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);
  18809. s.match_available = 0;
  18810. }
  18811. s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1;
  18812. if (flush === Z_FINISH) {
  18813. /*** FLUSH_BLOCK(s, 1); ***/
  18814. flush_block_only(s, true);
  18815. if (s.strm.avail_out === 0) {
  18816. return BS_FINISH_STARTED;
  18817. }
  18818. /***/
  18819. return BS_FINISH_DONE;
  18820. }
  18821. if (s.last_lit) {
  18822. /*** FLUSH_BLOCK(s, 0); ***/
  18823. flush_block_only(s, false);
  18824. if (s.strm.avail_out === 0) {
  18825. return BS_NEED_MORE;
  18826. }
  18827. /***/
  18828. }
  18829. return BS_BLOCK_DONE;
  18830. }
  18831. /* ===========================================================================
  18832. * For Z_RLE, simply look for runs of bytes, generate matches only of distance
  18833. * one. Do not maintain a hash table. (It will be regenerated if this run of
  18834. * deflate switches away from Z_RLE.)
  18835. */
  18836. function deflate_rle(s, flush) {
  18837. var bflush; /* set if current block must be flushed */
  18838. var prev; /* byte at distance one to match */
  18839. var scan, strend; /* scan goes up to strend for length of run */
  18840. var _win = s.window;
  18841. for (;;) {
  18842. /* Make sure that we always have enough lookahead, except
  18843. * at the end of the input file. We need MAX_MATCH bytes
  18844. * for the longest run, plus one for the unrolled loop.
  18845. */
  18846. if (s.lookahead <= MAX_MATCH) {
  18847. fill_window(s);
  18848. if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {
  18849. return BS_NEED_MORE;
  18850. }
  18851. if (s.lookahead === 0) { break; } /* flush the current block */
  18852. }
  18853. /* See how many times the previous byte repeats */
  18854. s.match_length = 0;
  18855. if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
  18856. scan = s.strstart - 1;
  18857. prev = _win[scan];
  18858. if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
  18859. strend = s.strstart + MAX_MATCH;
  18860. do {
  18861. /*jshint noempty:false*/
  18862. } while (prev === _win[++scan] && prev === _win[++scan] &&
  18863. prev === _win[++scan] && prev === _win[++scan] &&
  18864. prev === _win[++scan] && prev === _win[++scan] &&
  18865. prev === _win[++scan] && prev === _win[++scan] &&
  18866. scan < strend);
  18867. s.match_length = MAX_MATCH - (strend - scan);
  18868. if (s.match_length > s.lookahead) {
  18869. s.match_length = s.lookahead;
  18870. }
  18871. }
  18872. //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
  18873. }
  18874. /* Emit match if have run of MIN_MATCH or longer, else emit literal */
  18875. if (s.match_length >= MIN_MATCH) {
  18876. //check_match(s, s.strstart, s.strstart - 1, s.match_length);
  18877. /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
  18878. bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);
  18879. s.lookahead -= s.match_length;
  18880. s.strstart += s.match_length;
  18881. s.match_length = 0;
  18882. } else {
  18883. /* No match, output a literal byte */
  18884. //Tracevv((stderr,"%c", s->window[s->strstart]));
  18885. /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
  18886. bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
  18887. s.lookahead--;
  18888. s.strstart++;
  18889. }
  18890. if (bflush) {
  18891. /*** FLUSH_BLOCK(s, 0); ***/
  18892. flush_block_only(s, false);
  18893. if (s.strm.avail_out === 0) {
  18894. return BS_NEED_MORE;
  18895. }
  18896. /***/
  18897. }
  18898. }
  18899. s.insert = 0;
  18900. if (flush === Z_FINISH) {
  18901. /*** FLUSH_BLOCK(s, 1); ***/
  18902. flush_block_only(s, true);
  18903. if (s.strm.avail_out === 0) {
  18904. return BS_FINISH_STARTED;
  18905. }
  18906. /***/
  18907. return BS_FINISH_DONE;
  18908. }
  18909. if (s.last_lit) {
  18910. /*** FLUSH_BLOCK(s, 0); ***/
  18911. flush_block_only(s, false);
  18912. if (s.strm.avail_out === 0) {
  18913. return BS_NEED_MORE;
  18914. }
  18915. /***/
  18916. }
  18917. return BS_BLOCK_DONE;
  18918. }
  18919. /* ===========================================================================
  18920. * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
  18921. * (It will be regenerated if this run of deflate switches away from Huffman.)
  18922. */
  18923. function deflate_huff(s, flush) {
  18924. var bflush; /* set if current block must be flushed */
  18925. for (;;) {
  18926. /* Make sure that we have a literal to write. */
  18927. if (s.lookahead === 0) {
  18928. fill_window(s);
  18929. if (s.lookahead === 0) {
  18930. if (flush === Z_NO_FLUSH) {
  18931. return BS_NEED_MORE;
  18932. }
  18933. break; /* flush the current block */
  18934. }
  18935. }
  18936. /* Output a literal byte */
  18937. s.match_length = 0;
  18938. //Tracevv((stderr,"%c", s->window[s->strstart]));
  18939. /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
  18940. bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
  18941. s.lookahead--;
  18942. s.strstart++;
  18943. if (bflush) {
  18944. /*** FLUSH_BLOCK(s, 0); ***/
  18945. flush_block_only(s, false);
  18946. if (s.strm.avail_out === 0) {
  18947. return BS_NEED_MORE;
  18948. }
  18949. /***/
  18950. }
  18951. }
  18952. s.insert = 0;
  18953. if (flush === Z_FINISH) {
  18954. /*** FLUSH_BLOCK(s, 1); ***/
  18955. flush_block_only(s, true);
  18956. if (s.strm.avail_out === 0) {
  18957. return BS_FINISH_STARTED;
  18958. }
  18959. /***/
  18960. return BS_FINISH_DONE;
  18961. }
  18962. if (s.last_lit) {
  18963. /*** FLUSH_BLOCK(s, 0); ***/
  18964. flush_block_only(s, false);
  18965. if (s.strm.avail_out === 0) {
  18966. return BS_NEED_MORE;
  18967. }
  18968. /***/
  18969. }
  18970. return BS_BLOCK_DONE;
  18971. }
  18972. /* Values for max_lazy_match, good_match and max_chain_length, depending on
  18973. * the desired pack level (0..9). The values given below have been tuned to
  18974. * exclude worst case performance for pathological files. Better values may be
  18975. * found for specific files.
  18976. */
  18977. var Config = function (good_length, max_lazy, nice_length, max_chain, func) {
  18978. this.good_length = good_length;
  18979. this.max_lazy = max_lazy;
  18980. this.nice_length = nice_length;
  18981. this.max_chain = max_chain;
  18982. this.func = func;
  18983. };
  18984. var configuration_table;
  18985. configuration_table = [
  18986. /* good lazy nice chain */
  18987. new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */
  18988. new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */
  18989. new Config(4, 5, 16, 8, deflate_fast), /* 2 */
  18990. new Config(4, 6, 32, 32, deflate_fast), /* 3 */
  18991. new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */
  18992. new Config(8, 16, 32, 32, deflate_slow), /* 5 */
  18993. new Config(8, 16, 128, 128, deflate_slow), /* 6 */
  18994. new Config(8, 32, 128, 256, deflate_slow), /* 7 */
  18995. new Config(32, 128, 258, 1024, deflate_slow), /* 8 */
  18996. new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */
  18997. ];
  18998. /* ===========================================================================
  18999. * Initialize the "longest match" routines for a new zlib stream
  19000. */
  19001. function lm_init(s) {
  19002. s.window_size = 2 * s.w_size;
  19003. /*** CLEAR_HASH(s); ***/
  19004. zero(s.head); // Fill with NIL (= 0);
  19005. /* Set the default configuration parameters:
  19006. */
  19007. s.max_lazy_match = configuration_table[s.level].max_lazy;
  19008. s.good_match = configuration_table[s.level].good_length;
  19009. s.nice_match = configuration_table[s.level].nice_length;
  19010. s.max_chain_length = configuration_table[s.level].max_chain;
  19011. s.strstart = 0;
  19012. s.block_start = 0;
  19013. s.lookahead = 0;
  19014. s.insert = 0;
  19015. s.match_length = s.prev_length = MIN_MATCH - 1;
  19016. s.match_available = 0;
  19017. s.ins_h = 0;
  19018. }
  19019. function DeflateState() {
  19020. this.strm = null; /* pointer back to this zlib stream */
  19021. this.status = 0; /* as the name implies */
  19022. this.pending_buf = null; /* output still pending */
  19023. this.pending_buf_size = 0; /* size of pending_buf */
  19024. this.pending_out = 0; /* next pending byte to output to the stream */
  19025. this.pending = 0; /* nb of bytes in the pending buffer */
  19026. this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
  19027. this.gzhead = null; /* gzip header information to write */
  19028. this.gzindex = 0; /* where in extra, name, or comment */
  19029. this.method = Z_DEFLATED; /* can only be DEFLATED */
  19030. this.last_flush = -1; /* value of flush param for previous deflate call */
  19031. this.w_size = 0; /* LZ77 window size (32K by default) */
  19032. this.w_bits = 0; /* log2(w_size) (8..16) */
  19033. this.w_mask = 0; /* w_size - 1 */
  19034. this.window = null;
  19035. /* Sliding window. Input bytes are read into the second half of the window,
  19036. * and move to the first half later to keep a dictionary of at least wSize
  19037. * bytes. With this organization, matches are limited to a distance of
  19038. * wSize-MAX_MATCH bytes, but this ensures that IO is always
  19039. * performed with a length multiple of the block size.
  19040. */
  19041. this.window_size = 0;
  19042. /* Actual size of window: 2*wSize, except when the user input buffer
  19043. * is directly used as sliding window.
  19044. */
  19045. this.prev = null;
  19046. /* Link to older string with same hash index. To limit the size of this
  19047. * array to 64K, this link is maintained only for the last 32K strings.
  19048. * An index in this array is thus a window index modulo 32K.
  19049. */
  19050. this.head = null; /* Heads of the hash chains or NIL. */
  19051. this.ins_h = 0; /* hash index of string to be inserted */
  19052. this.hash_size = 0; /* number of elements in hash table */
  19053. this.hash_bits = 0; /* log2(hash_size) */
  19054. this.hash_mask = 0; /* hash_size-1 */
  19055. this.hash_shift = 0;
  19056. /* Number of bits by which ins_h must be shifted at each input
  19057. * step. It must be such that after MIN_MATCH steps, the oldest
  19058. * byte no longer takes part in the hash key, that is:
  19059. * hash_shift * MIN_MATCH >= hash_bits
  19060. */
  19061. this.block_start = 0;
  19062. /* Window position at the beginning of the current output block. Gets
  19063. * negative when the window is moved backwards.
  19064. */
  19065. this.match_length = 0; /* length of best match */
  19066. this.prev_match = 0; /* previous match */
  19067. this.match_available = 0; /* set if previous match exists */
  19068. this.strstart = 0; /* start of string to insert */
  19069. this.match_start = 0; /* start of matching string */
  19070. this.lookahead = 0; /* number of valid bytes ahead in window */
  19071. this.prev_length = 0;
  19072. /* Length of the best match at previous step. Matches not greater than this
  19073. * are discarded. This is used in the lazy match evaluation.
  19074. */
  19075. this.max_chain_length = 0;
  19076. /* To speed up deflation, hash chains are never searched beyond this
  19077. * length. A higher limit improves compression ratio but degrades the
  19078. * speed.
  19079. */
  19080. this.max_lazy_match = 0;
  19081. /* Attempt to find a better match only when the current match is strictly
  19082. * smaller than this value. This mechanism is used only for compression
  19083. * levels >= 4.
  19084. */
  19085. // That's alias to max_lazy_match, don't use directly
  19086. //this.max_insert_length = 0;
  19087. /* Insert new strings in the hash table only if the match length is not
  19088. * greater than this length. This saves time but degrades compression.
  19089. * max_insert_length is used only for compression levels <= 3.
  19090. */
  19091. this.level = 0; /* compression level (1..9) */
  19092. this.strategy = 0; /* favor or force Huffman coding*/
  19093. this.good_match = 0;
  19094. /* Use a faster search when the previous match is longer than this */
  19095. this.nice_match = 0; /* Stop searching when current match exceeds this */
  19096. /* used by trees.c: */
  19097. /* Didn't use ct_data typedef below to suppress compiler warning */
  19098. // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
  19099. // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
  19100. // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
  19101. // Use flat array of DOUBLE size, with interleaved fata,
  19102. // because JS does not support effective
  19103. this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2);
  19104. this.dyn_dtree = new utils.Buf16((2*D_CODES+1) * 2);
  19105. this.bl_tree = new utils.Buf16((2*BL_CODES+1) * 2);
  19106. zero(this.dyn_ltree);
  19107. zero(this.dyn_dtree);
  19108. zero(this.bl_tree);
  19109. this.l_desc = null; /* desc. for literal tree */
  19110. this.d_desc = null; /* desc. for distance tree */
  19111. this.bl_desc = null; /* desc. for bit length tree */
  19112. //ush bl_count[MAX_BITS+1];
  19113. this.bl_count = new utils.Buf16(MAX_BITS+1);
  19114. /* number of codes at each bit length for an optimal tree */
  19115. //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
  19116. this.heap = new utils.Buf16(2*L_CODES+1); /* heap used to build the Huffman trees */
  19117. zero(this.heap);
  19118. this.heap_len = 0; /* number of elements in the heap */
  19119. this.heap_max = 0; /* element of largest frequency */
  19120. /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
  19121. * The same heap array is used to build all trees.
  19122. */
  19123. this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1];
  19124. zero(this.depth);
  19125. /* Depth of each subtree used as tie breaker for trees of equal frequency
  19126. */
  19127. this.l_buf = 0; /* buffer index for literals or lengths */
  19128. this.lit_bufsize = 0;
  19129. /* Size of match buffer for literals/lengths. There are 4 reasons for
  19130. * limiting lit_bufsize to 64K:
  19131. * - frequencies can be kept in 16 bit counters
  19132. * - if compression is not successful for the first block, all input
  19133. * data is still in the window so we can still emit a stored block even
  19134. * when input comes from standard input. (This can also be done for
  19135. * all blocks if lit_bufsize is not greater than 32K.)
  19136. * - if compression is not successful for a file smaller than 64K, we can
  19137. * even emit a stored file instead of a stored block (saving 5 bytes).
  19138. * This is applicable only for zip (not gzip or zlib).
  19139. * - creating new Huffman trees less frequently may not provide fast
  19140. * adaptation to changes in the input data statistics. (Take for
  19141. * example a binary file with poorly compressible code followed by
  19142. * a highly compressible string table.) Smaller buffer sizes give
  19143. * fast adaptation but have of course the overhead of transmitting
  19144. * trees more frequently.
  19145. * - I can't count above 4
  19146. */
  19147. this.last_lit = 0; /* running index in l_buf */
  19148. this.d_buf = 0;
  19149. /* Buffer index for distances. To simplify the code, d_buf and l_buf have
  19150. * the same number of elements. To use different lengths, an extra flag
  19151. * array would be necessary.
  19152. */
  19153. this.opt_len = 0; /* bit length of current block with optimal trees */
  19154. this.static_len = 0; /* bit length of current block with static trees */
  19155. this.matches = 0; /* number of string matches in current block */
  19156. this.insert = 0; /* bytes at end of window left to insert */
  19157. this.bi_buf = 0;
  19158. /* Output buffer. bits are inserted starting at the bottom (least
  19159. * significant bits).
  19160. */
  19161. this.bi_valid = 0;
  19162. /* Number of valid bits in bi_buf. All bits above the last valid bit
  19163. * are always zero.
  19164. */
  19165. // Used for window memory init. We safely ignore it for JS. That makes
  19166. // sense only for pointers and memory check tools.
  19167. //this.high_water = 0;
  19168. /* High water mark offset in window for initialized bytes -- bytes above
  19169. * this are set to zero in order to avoid memory check warnings when
  19170. * longest match routines access bytes past the input. This is then
  19171. * updated to the new high water mark.
  19172. */
  19173. }
  19174. function deflateResetKeep(strm) {
  19175. var s;
  19176. if (!strm || !strm.state) {
  19177. return err(strm, Z_STREAM_ERROR);
  19178. }
  19179. strm.total_in = strm.total_out = 0;
  19180. strm.data_type = Z_UNKNOWN;
  19181. s = strm.state;
  19182. s.pending = 0;
  19183. s.pending_out = 0;
  19184. if (s.wrap < 0) {
  19185. s.wrap = -s.wrap;
  19186. /* was made negative by deflate(..., Z_FINISH); */
  19187. }
  19188. s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
  19189. strm.adler = (s.wrap === 2) ?
  19190. 0 // crc32(0, Z_NULL, 0)
  19191. :
  19192. 1; // adler32(0, Z_NULL, 0)
  19193. s.last_flush = Z_NO_FLUSH;
  19194. trees._tr_init(s);
  19195. return Z_OK;
  19196. }
  19197. function deflateReset(strm) {
  19198. var ret = deflateResetKeep(strm);
  19199. if (ret === Z_OK) {
  19200. lm_init(strm.state);
  19201. }
  19202. return ret;
  19203. }
  19204. function deflateSetHeader(strm, head) {
  19205. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  19206. if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
  19207. strm.state.gzhead = head;
  19208. return Z_OK;
  19209. }
  19210. function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
  19211. if (!strm) { // === Z_NULL
  19212. return Z_STREAM_ERROR;
  19213. }
  19214. var wrap = 1;
  19215. if (level === Z_DEFAULT_COMPRESSION) {
  19216. level = 6;
  19217. }
  19218. if (windowBits < 0) { /* suppress zlib wrapper */
  19219. wrap = 0;
  19220. windowBits = -windowBits;
  19221. }
  19222. else if (windowBits > 15) {
  19223. wrap = 2; /* write gzip wrapper instead */
  19224. windowBits -= 16;
  19225. }
  19226. if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
  19227. windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
  19228. strategy < 0 || strategy > Z_FIXED) {
  19229. return err(strm, Z_STREAM_ERROR);
  19230. }
  19231. if (windowBits === 8) {
  19232. windowBits = 9;
  19233. }
  19234. /* until 256-byte window bug fixed */
  19235. var s = new DeflateState();
  19236. strm.state = s;
  19237. s.strm = strm;
  19238. s.wrap = wrap;
  19239. s.gzhead = null;
  19240. s.w_bits = windowBits;
  19241. s.w_size = 1 << s.w_bits;
  19242. s.w_mask = s.w_size - 1;
  19243. s.hash_bits = memLevel + 7;
  19244. s.hash_size = 1 << s.hash_bits;
  19245. s.hash_mask = s.hash_size - 1;
  19246. s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
  19247. s.window = new utils.Buf8(s.w_size * 2);
  19248. s.head = new utils.Buf16(s.hash_size);
  19249. s.prev = new utils.Buf16(s.w_size);
  19250. // Don't need mem init magic for JS.
  19251. //s.high_water = 0; /* nothing written to s->window yet */
  19252. s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
  19253. s.pending_buf_size = s.lit_bufsize * 4;
  19254. s.pending_buf = new utils.Buf8(s.pending_buf_size);
  19255. s.d_buf = s.lit_bufsize >> 1;
  19256. s.l_buf = (1 + 2) * s.lit_bufsize;
  19257. s.level = level;
  19258. s.strategy = strategy;
  19259. s.method = method;
  19260. return deflateReset(strm);
  19261. }
  19262. function deflateInit(strm, level) {
  19263. return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
  19264. }
  19265. function deflate(strm, flush) {
  19266. var old_flush, s;
  19267. var beg, val; // for gzip header write only
  19268. if (!strm || !strm.state ||
  19269. flush > Z_BLOCK || flush < 0) {
  19270. return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
  19271. }
  19272. s = strm.state;
  19273. if (!strm.output ||
  19274. (!strm.input && strm.avail_in !== 0) ||
  19275. (s.status === FINISH_STATE && flush !== Z_FINISH)) {
  19276. return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
  19277. }
  19278. s.strm = strm; /* just in case */
  19279. old_flush = s.last_flush;
  19280. s.last_flush = flush;
  19281. /* Write the header */
  19282. if (s.status === INIT_STATE) {
  19283. if (s.wrap === 2) { // GZIP header
  19284. strm.adler = 0; //crc32(0L, Z_NULL, 0);
  19285. put_byte(s, 31);
  19286. put_byte(s, 139);
  19287. put_byte(s, 8);
  19288. if (!s.gzhead) { // s->gzhead == Z_NULL
  19289. put_byte(s, 0);
  19290. put_byte(s, 0);
  19291. put_byte(s, 0);
  19292. put_byte(s, 0);
  19293. put_byte(s, 0);
  19294. put_byte(s, s.level === 9 ? 2 :
  19295. (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
  19296. 4 : 0));
  19297. put_byte(s, OS_CODE);
  19298. s.status = BUSY_STATE;
  19299. }
  19300. else {
  19301. put_byte(s, (s.gzhead.text ? 1 : 0) +
  19302. (s.gzhead.hcrc ? 2 : 0) +
  19303. (!s.gzhead.extra ? 0 : 4) +
  19304. (!s.gzhead.name ? 0 : 8) +
  19305. (!s.gzhead.comment ? 0 : 16)
  19306. );
  19307. put_byte(s, s.gzhead.time & 0xff);
  19308. put_byte(s, (s.gzhead.time >> 8) & 0xff);
  19309. put_byte(s, (s.gzhead.time >> 16) & 0xff);
  19310. put_byte(s, (s.gzhead.time >> 24) & 0xff);
  19311. put_byte(s, s.level === 9 ? 2 :
  19312. (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
  19313. 4 : 0));
  19314. put_byte(s, s.gzhead.os & 0xff);
  19315. if (s.gzhead.extra && s.gzhead.extra.length) {
  19316. put_byte(s, s.gzhead.extra.length & 0xff);
  19317. put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
  19318. }
  19319. if (s.gzhead.hcrc) {
  19320. strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
  19321. }
  19322. s.gzindex = 0;
  19323. s.status = EXTRA_STATE;
  19324. }
  19325. }
  19326. else // DEFLATE header
  19327. {
  19328. var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
  19329. var level_flags = -1;
  19330. if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
  19331. level_flags = 0;
  19332. } else if (s.level < 6) {
  19333. level_flags = 1;
  19334. } else if (s.level === 6) {
  19335. level_flags = 2;
  19336. } else {
  19337. level_flags = 3;
  19338. }
  19339. header |= (level_flags << 6);
  19340. if (s.strstart !== 0) { header |= PRESET_DICT; }
  19341. header += 31 - (header % 31);
  19342. s.status = BUSY_STATE;
  19343. putShortMSB(s, header);
  19344. /* Save the adler32 of the preset dictionary: */
  19345. if (s.strstart !== 0) {
  19346. putShortMSB(s, strm.adler >>> 16);
  19347. putShortMSB(s, strm.adler & 0xffff);
  19348. }
  19349. strm.adler = 1; // adler32(0L, Z_NULL, 0);
  19350. }
  19351. }
  19352. //#ifdef GZIP
  19353. if (s.status === EXTRA_STATE) {
  19354. if (s.gzhead.extra/* != Z_NULL*/) {
  19355. beg = s.pending; /* start of bytes to update crc */
  19356. while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
  19357. if (s.pending === s.pending_buf_size) {
  19358. if (s.gzhead.hcrc && s.pending > beg) {
  19359. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  19360. }
  19361. flush_pending(strm);
  19362. beg = s.pending;
  19363. if (s.pending === s.pending_buf_size) {
  19364. break;
  19365. }
  19366. }
  19367. put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
  19368. s.gzindex++;
  19369. }
  19370. if (s.gzhead.hcrc && s.pending > beg) {
  19371. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  19372. }
  19373. if (s.gzindex === s.gzhead.extra.length) {
  19374. s.gzindex = 0;
  19375. s.status = NAME_STATE;
  19376. }
  19377. }
  19378. else {
  19379. s.status = NAME_STATE;
  19380. }
  19381. }
  19382. if (s.status === NAME_STATE) {
  19383. if (s.gzhead.name/* != Z_NULL*/) {
  19384. beg = s.pending; /* start of bytes to update crc */
  19385. //int val;
  19386. do {
  19387. if (s.pending === s.pending_buf_size) {
  19388. if (s.gzhead.hcrc && s.pending > beg) {
  19389. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  19390. }
  19391. flush_pending(strm);
  19392. beg = s.pending;
  19393. if (s.pending === s.pending_buf_size) {
  19394. val = 1;
  19395. break;
  19396. }
  19397. }
  19398. // JS specific: little magic to add zero terminator to end of string
  19399. if (s.gzindex < s.gzhead.name.length) {
  19400. val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
  19401. } else {
  19402. val = 0;
  19403. }
  19404. put_byte(s, val);
  19405. } while (val !== 0);
  19406. if (s.gzhead.hcrc && s.pending > beg){
  19407. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  19408. }
  19409. if (val === 0) {
  19410. s.gzindex = 0;
  19411. s.status = COMMENT_STATE;
  19412. }
  19413. }
  19414. else {
  19415. s.status = COMMENT_STATE;
  19416. }
  19417. }
  19418. if (s.status === COMMENT_STATE) {
  19419. if (s.gzhead.comment/* != Z_NULL*/) {
  19420. beg = s.pending; /* start of bytes to update crc */
  19421. //int val;
  19422. do {
  19423. if (s.pending === s.pending_buf_size) {
  19424. if (s.gzhead.hcrc && s.pending > beg) {
  19425. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  19426. }
  19427. flush_pending(strm);
  19428. beg = s.pending;
  19429. if (s.pending === s.pending_buf_size) {
  19430. val = 1;
  19431. break;
  19432. }
  19433. }
  19434. // JS specific: little magic to add zero terminator to end of string
  19435. if (s.gzindex < s.gzhead.comment.length) {
  19436. val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
  19437. } else {
  19438. val = 0;
  19439. }
  19440. put_byte(s, val);
  19441. } while (val !== 0);
  19442. if (s.gzhead.hcrc && s.pending > beg) {
  19443. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  19444. }
  19445. if (val === 0) {
  19446. s.status = HCRC_STATE;
  19447. }
  19448. }
  19449. else {
  19450. s.status = HCRC_STATE;
  19451. }
  19452. }
  19453. if (s.status === HCRC_STATE) {
  19454. if (s.gzhead.hcrc) {
  19455. if (s.pending + 2 > s.pending_buf_size) {
  19456. flush_pending(strm);
  19457. }
  19458. if (s.pending + 2 <= s.pending_buf_size) {
  19459. put_byte(s, strm.adler & 0xff);
  19460. put_byte(s, (strm.adler >> 8) & 0xff);
  19461. strm.adler = 0; //crc32(0L, Z_NULL, 0);
  19462. s.status = BUSY_STATE;
  19463. }
  19464. }
  19465. else {
  19466. s.status = BUSY_STATE;
  19467. }
  19468. }
  19469. //#endif
  19470. /* Flush as much pending output as possible */
  19471. if (s.pending !== 0) {
  19472. flush_pending(strm);
  19473. if (strm.avail_out === 0) {
  19474. /* Since avail_out is 0, deflate will be called again with
  19475. * more output space, but possibly with both pending and
  19476. * avail_in equal to zero. There won't be anything to do,
  19477. * but this is not an error situation so make sure we
  19478. * return OK instead of BUF_ERROR at next call of deflate:
  19479. */
  19480. s.last_flush = -1;
  19481. return Z_OK;
  19482. }
  19483. /* Make sure there is something to do and avoid duplicate consecutive
  19484. * flushes. For repeated and useless calls with Z_FINISH, we keep
  19485. * returning Z_STREAM_END instead of Z_BUF_ERROR.
  19486. */
  19487. } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
  19488. flush !== Z_FINISH) {
  19489. return err(strm, Z_BUF_ERROR);
  19490. }
  19491. /* User must not provide more input after the first FINISH: */
  19492. if (s.status === FINISH_STATE && strm.avail_in !== 0) {
  19493. return err(strm, Z_BUF_ERROR);
  19494. }
  19495. /* Start a new block or continue the current one.
  19496. */
  19497. if (strm.avail_in !== 0 || s.lookahead !== 0 ||
  19498. (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
  19499. var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
  19500. (s.strategy === Z_RLE ? deflate_rle(s, flush) :
  19501. configuration_table[s.level].func(s, flush));
  19502. if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
  19503. s.status = FINISH_STATE;
  19504. }
  19505. if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
  19506. if (strm.avail_out === 0) {
  19507. s.last_flush = -1;
  19508. /* avoid BUF_ERROR next call, see above */
  19509. }
  19510. return Z_OK;
  19511. /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
  19512. * of deflate should use the same flush parameter to make sure
  19513. * that the flush is complete. So we don't have to output an
  19514. * empty block here, this will be done at next call. This also
  19515. * ensures that for a very small output buffer, we emit at most
  19516. * one empty block.
  19517. */
  19518. }
  19519. if (bstate === BS_BLOCK_DONE) {
  19520. if (flush === Z_PARTIAL_FLUSH) {
  19521. trees._tr_align(s);
  19522. }
  19523. else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
  19524. trees._tr_stored_block(s, 0, 0, false);
  19525. /* For a full flush, this empty block will be recognized
  19526. * as a special marker by inflate_sync().
  19527. */
  19528. if (flush === Z_FULL_FLUSH) {
  19529. /*** CLEAR_HASH(s); ***/ /* forget history */
  19530. zero(s.head); // Fill with NIL (= 0);
  19531. if (s.lookahead === 0) {
  19532. s.strstart = 0;
  19533. s.block_start = 0;
  19534. s.insert = 0;
  19535. }
  19536. }
  19537. }
  19538. flush_pending(strm);
  19539. if (strm.avail_out === 0) {
  19540. s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
  19541. return Z_OK;
  19542. }
  19543. }
  19544. }
  19545. //Assert(strm->avail_out > 0, "bug2");
  19546. //if (strm.avail_out <= 0) { throw new Error("bug2");}
  19547. if (flush !== Z_FINISH) { return Z_OK; }
  19548. if (s.wrap <= 0) { return Z_STREAM_END; }
  19549. /* Write the trailer */
  19550. if (s.wrap === 2) {
  19551. put_byte(s, strm.adler & 0xff);
  19552. put_byte(s, (strm.adler >> 8) & 0xff);
  19553. put_byte(s, (strm.adler >> 16) & 0xff);
  19554. put_byte(s, (strm.adler >> 24) & 0xff);
  19555. put_byte(s, strm.total_in & 0xff);
  19556. put_byte(s, (strm.total_in >> 8) & 0xff);
  19557. put_byte(s, (strm.total_in >> 16) & 0xff);
  19558. put_byte(s, (strm.total_in >> 24) & 0xff);
  19559. }
  19560. else
  19561. {
  19562. putShortMSB(s, strm.adler >>> 16);
  19563. putShortMSB(s, strm.adler & 0xffff);
  19564. }
  19565. flush_pending(strm);
  19566. /* If avail_out is zero, the application will call deflate again
  19567. * to flush the rest.
  19568. */
  19569. if (s.wrap > 0) { s.wrap = -s.wrap; }
  19570. /* write the trailer only once! */
  19571. return s.pending !== 0 ? Z_OK : Z_STREAM_END;
  19572. }
  19573. function deflateEnd(strm) {
  19574. var status;
  19575. if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
  19576. return Z_STREAM_ERROR;
  19577. }
  19578. status = strm.state.status;
  19579. if (status !== INIT_STATE &&
  19580. status !== EXTRA_STATE &&
  19581. status !== NAME_STATE &&
  19582. status !== COMMENT_STATE &&
  19583. status !== HCRC_STATE &&
  19584. status !== BUSY_STATE &&
  19585. status !== FINISH_STATE
  19586. ) {
  19587. return err(strm, Z_STREAM_ERROR);
  19588. }
  19589. strm.state = null;
  19590. return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
  19591. }
  19592. /* =========================================================================
  19593. * Copy the source state to the destination state
  19594. */
  19595. //function deflateCopy(dest, source) {
  19596. //
  19597. //}
  19598. exports.deflateInit = deflateInit;
  19599. exports.deflateInit2 = deflateInit2;
  19600. exports.deflateReset = deflateReset;
  19601. exports.deflateResetKeep = deflateResetKeep;
  19602. exports.deflateSetHeader = deflateSetHeader;
  19603. exports.deflate = deflate;
  19604. exports.deflateEnd = deflateEnd;
  19605. exports.deflateInfo = 'pako deflate (from Nodeca project)';
  19606. /* Not implemented
  19607. exports.deflateBound = deflateBound;
  19608. exports.deflateCopy = deflateCopy;
  19609. exports.deflateSetDictionary = deflateSetDictionary;
  19610. exports.deflateParams = deflateParams;
  19611. exports.deflatePending = deflatePending;
  19612. exports.deflatePrime = deflatePrime;
  19613. exports.deflateTune = deflateTune;
  19614. */
  19615. },{"../utils/common":66,"./adler32":68,"./crc32":70,"./messages":76,"./trees":77}],72:[function(require,module,exports){
  19616. 'use strict';
  19617. function GZheader() {
  19618. /* true if compressed data believed to be text */
  19619. this.text = 0;
  19620. /* modification time */
  19621. this.time = 0;
  19622. /* extra flags (not used when writing a gzip file) */
  19623. this.xflags = 0;
  19624. /* operating system */
  19625. this.os = 0;
  19626. /* pointer to extra field or Z_NULL if none */
  19627. this.extra = null;
  19628. /* extra field length (valid if extra != Z_NULL) */
  19629. this.extra_len = 0; // Actually, we don't need it in JS,
  19630. // but leave for few code modifications
  19631. //
  19632. // Setup limits is not necessary because in js we should not preallocate memory
  19633. // for inflate use constant limit in 65536 bytes
  19634. //
  19635. /* space at extra (only when reading header) */
  19636. // this.extra_max = 0;
  19637. /* pointer to zero-terminated file name or Z_NULL */
  19638. this.name = '';
  19639. /* space at name (only when reading header) */
  19640. // this.name_max = 0;
  19641. /* pointer to zero-terminated comment or Z_NULL */
  19642. this.comment = '';
  19643. /* space at comment (only when reading header) */
  19644. // this.comm_max = 0;
  19645. /* true if there was or will be a header crc */
  19646. this.hcrc = 0;
  19647. /* true when done reading gzip header (not used when writing a gzip file) */
  19648. this.done = false;
  19649. }
  19650. module.exports = GZheader;
  19651. },{}],73:[function(require,module,exports){
  19652. 'use strict';
  19653. // See state defs from inflate.js
  19654. var BAD = 30; /* got a data error -- remain here until reset */
  19655. var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
  19656. /*
  19657. Decode literal, length, and distance codes and write out the resulting
  19658. literal and match bytes until either not enough input or output is
  19659. available, an end-of-block is encountered, or a data error is encountered.
  19660. When large enough input and output buffers are supplied to inflate(), for
  19661. example, a 16K input buffer and a 64K output buffer, more than 95% of the
  19662. inflate execution time is spent in this routine.
  19663. Entry assumptions:
  19664. state.mode === LEN
  19665. strm.avail_in >= 6
  19666. strm.avail_out >= 258
  19667. start >= strm.avail_out
  19668. state.bits < 8
  19669. On return, state.mode is one of:
  19670. LEN -- ran out of enough output space or enough available input
  19671. TYPE -- reached end of block code, inflate() to interpret next block
  19672. BAD -- error in block data
  19673. Notes:
  19674. - The maximum input bits used by a length/distance pair is 15 bits for the
  19675. length code, 5 bits for the length extra, 15 bits for the distance code,
  19676. and 13 bits for the distance extra. This totals 48 bits, or six bytes.
  19677. Therefore if strm.avail_in >= 6, then there is enough input to avoid
  19678. checking for available input while decoding.
  19679. - The maximum bytes that a single length/distance pair can output is 258
  19680. bytes, which is the maximum length that can be coded. inflate_fast()
  19681. requires strm.avail_out >= 258 for each loop to avoid checking for
  19682. output space.
  19683. */
  19684. module.exports = function inflate_fast(strm, start) {
  19685. var state;
  19686. var _in; /* local strm.input */
  19687. var last; /* have enough input while in < last */
  19688. var _out; /* local strm.output */
  19689. var beg; /* inflate()'s initial strm.output */
  19690. var end; /* while out < end, enough space available */
  19691. //#ifdef INFLATE_STRICT
  19692. var dmax; /* maximum distance from zlib header */
  19693. //#endif
  19694. var wsize; /* window size or zero if not using window */
  19695. var whave; /* valid bytes in the window */
  19696. var wnext; /* window write index */
  19697. var window; /* allocated sliding window, if wsize != 0 */
  19698. var hold; /* local strm.hold */
  19699. var bits; /* local strm.bits */
  19700. var lcode; /* local strm.lencode */
  19701. var dcode; /* local strm.distcode */
  19702. var lmask; /* mask for first level of length codes */
  19703. var dmask; /* mask for first level of distance codes */
  19704. var here; /* retrieved table entry */
  19705. var op; /* code bits, operation, extra bits, or */
  19706. /* window position, window bytes to copy */
  19707. var len; /* match length, unused bytes */
  19708. var dist; /* match distance */
  19709. var from; /* where to copy match from */
  19710. var from_source;
  19711. var input, output; // JS specific, because we have no pointers
  19712. /* copy state to local variables */
  19713. state = strm.state;
  19714. //here = state.here;
  19715. _in = strm.next_in;
  19716. input = strm.input;
  19717. last = _in + (strm.avail_in - 5);
  19718. _out = strm.next_out;
  19719. output = strm.output;
  19720. beg = _out - (start - strm.avail_out);
  19721. end = _out + (strm.avail_out - 257);
  19722. //#ifdef INFLATE_STRICT
  19723. dmax = state.dmax;
  19724. //#endif
  19725. wsize = state.wsize;
  19726. whave = state.whave;
  19727. wnext = state.wnext;
  19728. window = state.window;
  19729. hold = state.hold;
  19730. bits = state.bits;
  19731. lcode = state.lencode;
  19732. dcode = state.distcode;
  19733. lmask = (1 << state.lenbits) - 1;
  19734. dmask = (1 << state.distbits) - 1;
  19735. /* decode literals and length/distances until end-of-block or not enough
  19736. input data or output space */
  19737. top:
  19738. do {
  19739. if (bits < 15) {
  19740. hold += input[_in++] << bits;
  19741. bits += 8;
  19742. hold += input[_in++] << bits;
  19743. bits += 8;
  19744. }
  19745. here = lcode[hold & lmask];
  19746. dolen:
  19747. for (;;) { // Goto emulation
  19748. op = here >>> 24/*here.bits*/;
  19749. hold >>>= op;
  19750. bits -= op;
  19751. op = (here >>> 16) & 0xff/*here.op*/;
  19752. if (op === 0) { /* literal */
  19753. //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
  19754. // "inflate: literal '%c'\n" :
  19755. // "inflate: literal 0x%02x\n", here.val));
  19756. output[_out++] = here & 0xffff/*here.val*/;
  19757. }
  19758. else if (op & 16) { /* length base */
  19759. len = here & 0xffff/*here.val*/;
  19760. op &= 15; /* number of extra bits */
  19761. if (op) {
  19762. if (bits < op) {
  19763. hold += input[_in++] << bits;
  19764. bits += 8;
  19765. }
  19766. len += hold & ((1 << op) - 1);
  19767. hold >>>= op;
  19768. bits -= op;
  19769. }
  19770. //Tracevv((stderr, "inflate: length %u\n", len));
  19771. if (bits < 15) {
  19772. hold += input[_in++] << bits;
  19773. bits += 8;
  19774. hold += input[_in++] << bits;
  19775. bits += 8;
  19776. }
  19777. here = dcode[hold & dmask];
  19778. dodist:
  19779. for (;;) { // goto emulation
  19780. op = here >>> 24/*here.bits*/;
  19781. hold >>>= op;
  19782. bits -= op;
  19783. op = (here >>> 16) & 0xff/*here.op*/;
  19784. if (op & 16) { /* distance base */
  19785. dist = here & 0xffff/*here.val*/;
  19786. op &= 15; /* number of extra bits */
  19787. if (bits < op) {
  19788. hold += input[_in++] << bits;
  19789. bits += 8;
  19790. if (bits < op) {
  19791. hold += input[_in++] << bits;
  19792. bits += 8;
  19793. }
  19794. }
  19795. dist += hold & ((1 << op) - 1);
  19796. //#ifdef INFLATE_STRICT
  19797. if (dist > dmax) {
  19798. strm.msg = 'invalid distance too far back';
  19799. state.mode = BAD;
  19800. break top;
  19801. }
  19802. //#endif
  19803. hold >>>= op;
  19804. bits -= op;
  19805. //Tracevv((stderr, "inflate: distance %u\n", dist));
  19806. op = _out - beg; /* max distance in output */
  19807. if (dist > op) { /* see if copy from window */
  19808. op = dist - op; /* distance back in window */
  19809. if (op > whave) {
  19810. if (state.sane) {
  19811. strm.msg = 'invalid distance too far back';
  19812. state.mode = BAD;
  19813. break top;
  19814. }
  19815. // (!) This block is disabled in zlib defailts,
  19816. // don't enable it for binary compatibility
  19817. //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
  19818. // if (len <= op - whave) {
  19819. // do {
  19820. // output[_out++] = 0;
  19821. // } while (--len);
  19822. // continue top;
  19823. // }
  19824. // len -= op - whave;
  19825. // do {
  19826. // output[_out++] = 0;
  19827. // } while (--op > whave);
  19828. // if (op === 0) {
  19829. // from = _out - dist;
  19830. // do {
  19831. // output[_out++] = output[from++];
  19832. // } while (--len);
  19833. // continue top;
  19834. // }
  19835. //#endif
  19836. }
  19837. from = 0; // window index
  19838. from_source = window;
  19839. if (wnext === 0) { /* very common case */
  19840. from += wsize - op;
  19841. if (op < len) { /* some from window */
  19842. len -= op;
  19843. do {
  19844. output[_out++] = window[from++];
  19845. } while (--op);
  19846. from = _out - dist; /* rest from output */
  19847. from_source = output;
  19848. }
  19849. }
  19850. else if (wnext < op) { /* wrap around window */
  19851. from += wsize + wnext - op;
  19852. op -= wnext;
  19853. if (op < len) { /* some from end of window */
  19854. len -= op;
  19855. do {
  19856. output[_out++] = window[from++];
  19857. } while (--op);
  19858. from = 0;
  19859. if (wnext < len) { /* some from start of window */
  19860. op = wnext;
  19861. len -= op;
  19862. do {
  19863. output[_out++] = window[from++];
  19864. } while (--op);
  19865. from = _out - dist; /* rest from output */
  19866. from_source = output;
  19867. }
  19868. }
  19869. }
  19870. else { /* contiguous in window */
  19871. from += wnext - op;
  19872. if (op < len) { /* some from window */
  19873. len -= op;
  19874. do {
  19875. output[_out++] = window[from++];
  19876. } while (--op);
  19877. from = _out - dist; /* rest from output */
  19878. from_source = output;
  19879. }
  19880. }
  19881. while (len > 2) {
  19882. output[_out++] = from_source[from++];
  19883. output[_out++] = from_source[from++];
  19884. output[_out++] = from_source[from++];
  19885. len -= 3;
  19886. }
  19887. if (len) {
  19888. output[_out++] = from_source[from++];
  19889. if (len > 1) {
  19890. output[_out++] = from_source[from++];
  19891. }
  19892. }
  19893. }
  19894. else {
  19895. from = _out - dist; /* copy direct from output */
  19896. do { /* minimum length is three */
  19897. output[_out++] = output[from++];
  19898. output[_out++] = output[from++];
  19899. output[_out++] = output[from++];
  19900. len -= 3;
  19901. } while (len > 2);
  19902. if (len) {
  19903. output[_out++] = output[from++];
  19904. if (len > 1) {
  19905. output[_out++] = output[from++];
  19906. }
  19907. }
  19908. }
  19909. }
  19910. else if ((op & 64) === 0) { /* 2nd level distance code */
  19911. here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
  19912. continue dodist;
  19913. }
  19914. else {
  19915. strm.msg = 'invalid distance code';
  19916. state.mode = BAD;
  19917. break top;
  19918. }
  19919. break; // need to emulate goto via "continue"
  19920. }
  19921. }
  19922. else if ((op & 64) === 0) { /* 2nd level length code */
  19923. here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
  19924. continue dolen;
  19925. }
  19926. else if (op & 32) { /* end-of-block */
  19927. //Tracevv((stderr, "inflate: end of block\n"));
  19928. state.mode = TYPE;
  19929. break top;
  19930. }
  19931. else {
  19932. strm.msg = 'invalid literal/length code';
  19933. state.mode = BAD;
  19934. break top;
  19935. }
  19936. break; // need to emulate goto via "continue"
  19937. }
  19938. } while (_in < last && _out < end);
  19939. /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
  19940. len = bits >> 3;
  19941. _in -= len;
  19942. bits -= len << 3;
  19943. hold &= (1 << bits) - 1;
  19944. /* update state and return */
  19945. strm.next_in = _in;
  19946. strm.next_out = _out;
  19947. strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
  19948. strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
  19949. state.hold = hold;
  19950. state.bits = bits;
  19951. return;
  19952. };
  19953. },{}],74:[function(require,module,exports){
  19954. 'use strict';
  19955. var utils = require('../utils/common');
  19956. var adler32 = require('./adler32');
  19957. var crc32 = require('./crc32');
  19958. var inflate_fast = require('./inffast');
  19959. var inflate_table = require('./inftrees');
  19960. var CODES = 0;
  19961. var LENS = 1;
  19962. var DISTS = 2;
  19963. /* Public constants ==========================================================*/
  19964. /* ===========================================================================*/
  19965. /* Allowed flush values; see deflate() and inflate() below for details */
  19966. //var Z_NO_FLUSH = 0;
  19967. //var Z_PARTIAL_FLUSH = 1;
  19968. //var Z_SYNC_FLUSH = 2;
  19969. //var Z_FULL_FLUSH = 3;
  19970. var Z_FINISH = 4;
  19971. var Z_BLOCK = 5;
  19972. var Z_TREES = 6;
  19973. /* Return codes for the compression/decompression functions. Negative values
  19974. * are errors, positive values are used for special but normal events.
  19975. */
  19976. var Z_OK = 0;
  19977. var Z_STREAM_END = 1;
  19978. var Z_NEED_DICT = 2;
  19979. //var Z_ERRNO = -1;
  19980. var Z_STREAM_ERROR = -2;
  19981. var Z_DATA_ERROR = -3;
  19982. var Z_MEM_ERROR = -4;
  19983. var Z_BUF_ERROR = -5;
  19984. //var Z_VERSION_ERROR = -6;
  19985. /* The deflate compression method */
  19986. var Z_DEFLATED = 8;
  19987. /* STATES ====================================================================*/
  19988. /* ===========================================================================*/
  19989. var HEAD = 1; /* i: waiting for magic header */
  19990. var FLAGS = 2; /* i: waiting for method and flags (gzip) */
  19991. var TIME = 3; /* i: waiting for modification time (gzip) */
  19992. var OS = 4; /* i: waiting for extra flags and operating system (gzip) */
  19993. var EXLEN = 5; /* i: waiting for extra length (gzip) */
  19994. var EXTRA = 6; /* i: waiting for extra bytes (gzip) */
  19995. var NAME = 7; /* i: waiting for end of file name (gzip) */
  19996. var COMMENT = 8; /* i: waiting for end of comment (gzip) */
  19997. var HCRC = 9; /* i: waiting for header crc (gzip) */
  19998. var DICTID = 10; /* i: waiting for dictionary check value */
  19999. var DICT = 11; /* waiting for inflateSetDictionary() call */
  20000. var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
  20001. var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */
  20002. var STORED = 14; /* i: waiting for stored size (length and complement) */
  20003. var COPY_ = 15; /* i/o: same as COPY below, but only first time in */
  20004. var COPY = 16; /* i/o: waiting for input or output to copy stored block */
  20005. var TABLE = 17; /* i: waiting for dynamic block table lengths */
  20006. var LENLENS = 18; /* i: waiting for code length code lengths */
  20007. var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */
  20008. var LEN_ = 20; /* i: same as LEN below, but only first time in */
  20009. var LEN = 21; /* i: waiting for length/lit/eob code */
  20010. var LENEXT = 22; /* i: waiting for length extra bits */
  20011. var DIST = 23; /* i: waiting for distance code */
  20012. var DISTEXT = 24; /* i: waiting for distance extra bits */
  20013. var MATCH = 25; /* o: waiting for output space to copy string */
  20014. var LIT = 26; /* o: waiting for output space to write literal */
  20015. var CHECK = 27; /* i: waiting for 32-bit check value */
  20016. var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */
  20017. var DONE = 29; /* finished check, done -- remain here until reset */
  20018. var BAD = 30; /* got a data error -- remain here until reset */
  20019. var MEM = 31; /* got an inflate() memory error -- remain here until reset */
  20020. var SYNC = 32; /* looking for synchronization bytes to restart inflate() */
  20021. /* ===========================================================================*/
  20022. var ENOUGH_LENS = 852;
  20023. var ENOUGH_DISTS = 592;
  20024. //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
  20025. var MAX_WBITS = 15;
  20026. /* 32K LZ77 window */
  20027. var DEF_WBITS = MAX_WBITS;
  20028. function ZSWAP32(q) {
  20029. return (((q >>> 24) & 0xff) +
  20030. ((q >>> 8) & 0xff00) +
  20031. ((q & 0xff00) << 8) +
  20032. ((q & 0xff) << 24));
  20033. }
  20034. function InflateState() {
  20035. this.mode = 0; /* current inflate mode */
  20036. this.last = false; /* true if processing last block */
  20037. this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
  20038. this.havedict = false; /* true if dictionary provided */
  20039. this.flags = 0; /* gzip header method and flags (0 if zlib) */
  20040. this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
  20041. this.check = 0; /* protected copy of check value */
  20042. this.total = 0; /* protected copy of output count */
  20043. // TODO: may be {}
  20044. this.head = null; /* where to save gzip header information */
  20045. /* sliding window */
  20046. this.wbits = 0; /* log base 2 of requested window size */
  20047. this.wsize = 0; /* window size or zero if not using window */
  20048. this.whave = 0; /* valid bytes in the window */
  20049. this.wnext = 0; /* window write index */
  20050. this.window = null; /* allocated sliding window, if needed */
  20051. /* bit accumulator */
  20052. this.hold = 0; /* input bit accumulator */
  20053. this.bits = 0; /* number of bits in "in" */
  20054. /* for string and stored block copying */
  20055. this.length = 0; /* literal or length of data to copy */
  20056. this.offset = 0; /* distance back to copy string from */
  20057. /* for table and code decoding */
  20058. this.extra = 0; /* extra bits needed */
  20059. /* fixed and dynamic code tables */
  20060. this.lencode = null; /* starting table for length/literal codes */
  20061. this.distcode = null; /* starting table for distance codes */
  20062. this.lenbits = 0; /* index bits for lencode */
  20063. this.distbits = 0; /* index bits for distcode */
  20064. /* dynamic table building */
  20065. this.ncode = 0; /* number of code length code lengths */
  20066. this.nlen = 0; /* number of length code lengths */
  20067. this.ndist = 0; /* number of distance code lengths */
  20068. this.have = 0; /* number of code lengths in lens[] */
  20069. this.next = null; /* next available space in codes[] */
  20070. this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
  20071. this.work = new utils.Buf16(288); /* work area for code table building */
  20072. /*
  20073. because we don't have pointers in js, we use lencode and distcode directly
  20074. as buffers so we don't need codes
  20075. */
  20076. //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */
  20077. this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */
  20078. this.distdyn = null; /* dynamic table for distance codes (JS specific) */
  20079. this.sane = 0; /* if false, allow invalid distance too far */
  20080. this.back = 0; /* bits back of last unprocessed length/lit */
  20081. this.was = 0; /* initial length of match */
  20082. }
  20083. function inflateResetKeep(strm) {
  20084. var state;
  20085. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  20086. state = strm.state;
  20087. strm.total_in = strm.total_out = state.total = 0;
  20088. strm.msg = ''; /*Z_NULL*/
  20089. if (state.wrap) { /* to support ill-conceived Java test suite */
  20090. strm.adler = state.wrap & 1;
  20091. }
  20092. state.mode = HEAD;
  20093. state.last = 0;
  20094. state.havedict = 0;
  20095. state.dmax = 32768;
  20096. state.head = null/*Z_NULL*/;
  20097. state.hold = 0;
  20098. state.bits = 0;
  20099. //state.lencode = state.distcode = state.next = state.codes;
  20100. state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
  20101. state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);
  20102. state.sane = 1;
  20103. state.back = -1;
  20104. //Tracev((stderr, "inflate: reset\n"));
  20105. return Z_OK;
  20106. }
  20107. function inflateReset(strm) {
  20108. var state;
  20109. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  20110. state = strm.state;
  20111. state.wsize = 0;
  20112. state.whave = 0;
  20113. state.wnext = 0;
  20114. return inflateResetKeep(strm);
  20115. }
  20116. function inflateReset2(strm, windowBits) {
  20117. var wrap;
  20118. var state;
  20119. /* get the state */
  20120. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  20121. state = strm.state;
  20122. /* extract wrap request from windowBits parameter */
  20123. if (windowBits < 0) {
  20124. wrap = 0;
  20125. windowBits = -windowBits;
  20126. }
  20127. else {
  20128. wrap = (windowBits >> 4) + 1;
  20129. if (windowBits < 48) {
  20130. windowBits &= 15;
  20131. }
  20132. }
  20133. /* set number of window bits, free window if different */
  20134. if (windowBits && (windowBits < 8 || windowBits > 15)) {
  20135. return Z_STREAM_ERROR;
  20136. }
  20137. if (state.window !== null && state.wbits !== windowBits) {
  20138. state.window = null;
  20139. }
  20140. /* update state and reset the rest of it */
  20141. state.wrap = wrap;
  20142. state.wbits = windowBits;
  20143. return inflateReset(strm);
  20144. }
  20145. function inflateInit2(strm, windowBits) {
  20146. var ret;
  20147. var state;
  20148. if (!strm) { return Z_STREAM_ERROR; }
  20149. //strm.msg = Z_NULL; /* in case we return an error */
  20150. state = new InflateState();
  20151. //if (state === Z_NULL) return Z_MEM_ERROR;
  20152. //Tracev((stderr, "inflate: allocated\n"));
  20153. strm.state = state;
  20154. state.window = null/*Z_NULL*/;
  20155. ret = inflateReset2(strm, windowBits);
  20156. if (ret !== Z_OK) {
  20157. strm.state = null/*Z_NULL*/;
  20158. }
  20159. return ret;
  20160. }
  20161. function inflateInit(strm) {
  20162. return inflateInit2(strm, DEF_WBITS);
  20163. }
  20164. /*
  20165. Return state with length and distance decoding tables and index sizes set to
  20166. fixed code decoding. Normally this returns fixed tables from inffixed.h.
  20167. If BUILDFIXED is defined, then instead this routine builds the tables the
  20168. first time it's called, and returns those tables the first time and
  20169. thereafter. This reduces the size of the code by about 2K bytes, in
  20170. exchange for a little execution time. However, BUILDFIXED should not be
  20171. used for threaded applications, since the rewriting of the tables and virgin
  20172. may not be thread-safe.
  20173. */
  20174. var virgin = true;
  20175. var lenfix, distfix; // We have no pointers in JS, so keep tables separate
  20176. function fixedtables(state) {
  20177. /* build fixed huffman tables if first call (may not be thread safe) */
  20178. if (virgin) {
  20179. var sym;
  20180. lenfix = new utils.Buf32(512);
  20181. distfix = new utils.Buf32(32);
  20182. /* literal/length table */
  20183. sym = 0;
  20184. while (sym < 144) { state.lens[sym++] = 8; }
  20185. while (sym < 256) { state.lens[sym++] = 9; }
  20186. while (sym < 280) { state.lens[sym++] = 7; }
  20187. while (sym < 288) { state.lens[sym++] = 8; }
  20188. inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits: 9});
  20189. /* distance table */
  20190. sym = 0;
  20191. while (sym < 32) { state.lens[sym++] = 5; }
  20192. inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits: 5});
  20193. /* do this just once */
  20194. virgin = false;
  20195. }
  20196. state.lencode = lenfix;
  20197. state.lenbits = 9;
  20198. state.distcode = distfix;
  20199. state.distbits = 5;
  20200. }
  20201. /*
  20202. Update the window with the last wsize (normally 32K) bytes written before
  20203. returning. If window does not exist yet, create it. This is only called
  20204. when a window is already in use, or when output has been written during this
  20205. inflate call, but the end of the deflate stream has not been reached yet.
  20206. It is also called to create a window for dictionary data when a dictionary
  20207. is loaded.
  20208. Providing output buffers larger than 32K to inflate() should provide a speed
  20209. advantage, since only the last 32K of output is copied to the sliding window
  20210. upon return from inflate(), and since all distances after the first 32K of
  20211. output will fall in the output data, making match copies simpler and faster.
  20212. The advantage may be dependent on the size of the processor's data caches.
  20213. */
  20214. function updatewindow(strm, src, end, copy) {
  20215. var dist;
  20216. var state = strm.state;
  20217. /* if it hasn't been done already, allocate space for the window */
  20218. if (state.window === null) {
  20219. state.wsize = 1 << state.wbits;
  20220. state.wnext = 0;
  20221. state.whave = 0;
  20222. state.window = new utils.Buf8(state.wsize);
  20223. }
  20224. /* copy state->wsize or less output bytes into the circular window */
  20225. if (copy >= state.wsize) {
  20226. utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0);
  20227. state.wnext = 0;
  20228. state.whave = state.wsize;
  20229. }
  20230. else {
  20231. dist = state.wsize - state.wnext;
  20232. if (dist > copy) {
  20233. dist = copy;
  20234. }
  20235. //zmemcpy(state->window + state->wnext, end - copy, dist);
  20236. utils.arraySet(state.window,src, end - copy, dist, state.wnext);
  20237. copy -= dist;
  20238. if (copy) {
  20239. //zmemcpy(state->window, end - copy, copy);
  20240. utils.arraySet(state.window,src, end - copy, copy, 0);
  20241. state.wnext = copy;
  20242. state.whave = state.wsize;
  20243. }
  20244. else {
  20245. state.wnext += dist;
  20246. if (state.wnext === state.wsize) { state.wnext = 0; }
  20247. if (state.whave < state.wsize) { state.whave += dist; }
  20248. }
  20249. }
  20250. return 0;
  20251. }
  20252. function inflate(strm, flush) {
  20253. var state;
  20254. var input, output; // input/output buffers
  20255. var next; /* next input INDEX */
  20256. var put; /* next output INDEX */
  20257. var have, left; /* available input and output */
  20258. var hold; /* bit buffer */
  20259. var bits; /* bits in bit buffer */
  20260. var _in, _out; /* save starting available input and output */
  20261. var copy; /* number of stored or match bytes to copy */
  20262. var from; /* where to copy match bytes from */
  20263. var from_source;
  20264. var here = 0; /* current decoding table entry */
  20265. var here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
  20266. //var last; /* parent table entry */
  20267. var last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
  20268. var len; /* length to copy for repeats, bits to drop */
  20269. var ret; /* return code */
  20270. var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */
  20271. var opts;
  20272. var n; // temporary var for NEED_BITS
  20273. var order = /* permutation of code lengths */
  20274. [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
  20275. if (!strm || !strm.state || !strm.output ||
  20276. (!strm.input && strm.avail_in !== 0)) {
  20277. return Z_STREAM_ERROR;
  20278. }
  20279. state = strm.state;
  20280. if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */
  20281. //--- LOAD() ---
  20282. put = strm.next_out;
  20283. output = strm.output;
  20284. left = strm.avail_out;
  20285. next = strm.next_in;
  20286. input = strm.input;
  20287. have = strm.avail_in;
  20288. hold = state.hold;
  20289. bits = state.bits;
  20290. //---
  20291. _in = have;
  20292. _out = left;
  20293. ret = Z_OK;
  20294. inf_leave: // goto emulation
  20295. for (;;) {
  20296. switch (state.mode) {
  20297. case HEAD:
  20298. if (state.wrap === 0) {
  20299. state.mode = TYPEDO;
  20300. break;
  20301. }
  20302. //=== NEEDBITS(16);
  20303. while (bits < 16) {
  20304. if (have === 0) { break inf_leave; }
  20305. have--;
  20306. hold += input[next++] << bits;
  20307. bits += 8;
  20308. }
  20309. //===//
  20310. if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */
  20311. state.check = 0/*crc32(0L, Z_NULL, 0)*/;
  20312. //=== CRC2(state.check, hold);
  20313. hbuf[0] = hold & 0xff;
  20314. hbuf[1] = (hold >>> 8) & 0xff;
  20315. state.check = crc32(state.check, hbuf, 2, 0);
  20316. //===//
  20317. //=== INITBITS();
  20318. hold = 0;
  20319. bits = 0;
  20320. //===//
  20321. state.mode = FLAGS;
  20322. break;
  20323. }
  20324. state.flags = 0; /* expect zlib header */
  20325. if (state.head) {
  20326. state.head.done = false;
  20327. }
  20328. if (!(state.wrap & 1) || /* check if zlib header allowed */
  20329. (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
  20330. strm.msg = 'incorrect header check';
  20331. state.mode = BAD;
  20332. break;
  20333. }
  20334. if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
  20335. strm.msg = 'unknown compression method';
  20336. state.mode = BAD;
  20337. break;
  20338. }
  20339. //--- DROPBITS(4) ---//
  20340. hold >>>= 4;
  20341. bits -= 4;
  20342. //---//
  20343. len = (hold & 0x0f)/*BITS(4)*/ + 8;
  20344. if (state.wbits === 0) {
  20345. state.wbits = len;
  20346. }
  20347. else if (len > state.wbits) {
  20348. strm.msg = 'invalid window size';
  20349. state.mode = BAD;
  20350. break;
  20351. }
  20352. state.dmax = 1 << len;
  20353. //Tracev((stderr, "inflate: zlib header ok\n"));
  20354. strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
  20355. state.mode = hold & 0x200 ? DICTID : TYPE;
  20356. //=== INITBITS();
  20357. hold = 0;
  20358. bits = 0;
  20359. //===//
  20360. break;
  20361. case FLAGS:
  20362. //=== NEEDBITS(16); */
  20363. while (bits < 16) {
  20364. if (have === 0) { break inf_leave; }
  20365. have--;
  20366. hold += input[next++] << bits;
  20367. bits += 8;
  20368. }
  20369. //===//
  20370. state.flags = hold;
  20371. if ((state.flags & 0xff) !== Z_DEFLATED) {
  20372. strm.msg = 'unknown compression method';
  20373. state.mode = BAD;
  20374. break;
  20375. }
  20376. if (state.flags & 0xe000) {
  20377. strm.msg = 'unknown header flags set';
  20378. state.mode = BAD;
  20379. break;
  20380. }
  20381. if (state.head) {
  20382. state.head.text = ((hold >> 8) & 1);
  20383. }
  20384. if (state.flags & 0x0200) {
  20385. //=== CRC2(state.check, hold);
  20386. hbuf[0] = hold & 0xff;
  20387. hbuf[1] = (hold >>> 8) & 0xff;
  20388. state.check = crc32(state.check, hbuf, 2, 0);
  20389. //===//
  20390. }
  20391. //=== INITBITS();
  20392. hold = 0;
  20393. bits = 0;
  20394. //===//
  20395. state.mode = TIME;
  20396. /* falls through */
  20397. case TIME:
  20398. //=== NEEDBITS(32); */
  20399. while (bits < 32) {
  20400. if (have === 0) { break inf_leave; }
  20401. have--;
  20402. hold += input[next++] << bits;
  20403. bits += 8;
  20404. }
  20405. //===//
  20406. if (state.head) {
  20407. state.head.time = hold;
  20408. }
  20409. if (state.flags & 0x0200) {
  20410. //=== CRC4(state.check, hold)
  20411. hbuf[0] = hold & 0xff;
  20412. hbuf[1] = (hold >>> 8) & 0xff;
  20413. hbuf[2] = (hold >>> 16) & 0xff;
  20414. hbuf[3] = (hold >>> 24) & 0xff;
  20415. state.check = crc32(state.check, hbuf, 4, 0);
  20416. //===
  20417. }
  20418. //=== INITBITS();
  20419. hold = 0;
  20420. bits = 0;
  20421. //===//
  20422. state.mode = OS;
  20423. /* falls through */
  20424. case OS:
  20425. //=== NEEDBITS(16); */
  20426. while (bits < 16) {
  20427. if (have === 0) { break inf_leave; }
  20428. have--;
  20429. hold += input[next++] << bits;
  20430. bits += 8;
  20431. }
  20432. //===//
  20433. if (state.head) {
  20434. state.head.xflags = (hold & 0xff);
  20435. state.head.os = (hold >> 8);
  20436. }
  20437. if (state.flags & 0x0200) {
  20438. //=== CRC2(state.check, hold);
  20439. hbuf[0] = hold & 0xff;
  20440. hbuf[1] = (hold >>> 8) & 0xff;
  20441. state.check = crc32(state.check, hbuf, 2, 0);
  20442. //===//
  20443. }
  20444. //=== INITBITS();
  20445. hold = 0;
  20446. bits = 0;
  20447. //===//
  20448. state.mode = EXLEN;
  20449. /* falls through */
  20450. case EXLEN:
  20451. if (state.flags & 0x0400) {
  20452. //=== NEEDBITS(16); */
  20453. while (bits < 16) {
  20454. if (have === 0) { break inf_leave; }
  20455. have--;
  20456. hold += input[next++] << bits;
  20457. bits += 8;
  20458. }
  20459. //===//
  20460. state.length = hold;
  20461. if (state.head) {
  20462. state.head.extra_len = hold;
  20463. }
  20464. if (state.flags & 0x0200) {
  20465. //=== CRC2(state.check, hold);
  20466. hbuf[0] = hold & 0xff;
  20467. hbuf[1] = (hold >>> 8) & 0xff;
  20468. state.check = crc32(state.check, hbuf, 2, 0);
  20469. //===//
  20470. }
  20471. //=== INITBITS();
  20472. hold = 0;
  20473. bits = 0;
  20474. //===//
  20475. }
  20476. else if (state.head) {
  20477. state.head.extra = null/*Z_NULL*/;
  20478. }
  20479. state.mode = EXTRA;
  20480. /* falls through */
  20481. case EXTRA:
  20482. if (state.flags & 0x0400) {
  20483. copy = state.length;
  20484. if (copy > have) { copy = have; }
  20485. if (copy) {
  20486. if (state.head) {
  20487. len = state.head.extra_len - state.length;
  20488. if (!state.head.extra) {
  20489. // Use untyped array for more conveniend processing later
  20490. state.head.extra = new Array(state.head.extra_len);
  20491. }
  20492. utils.arraySet(
  20493. state.head.extra,
  20494. input,
  20495. next,
  20496. // extra field is limited to 65536 bytes
  20497. // - no need for additional size check
  20498. copy,
  20499. /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
  20500. len
  20501. );
  20502. //zmemcpy(state.head.extra + len, next,
  20503. // len + copy > state.head.extra_max ?
  20504. // state.head.extra_max - len : copy);
  20505. }
  20506. if (state.flags & 0x0200) {
  20507. state.check = crc32(state.check, input, copy, next);
  20508. }
  20509. have -= copy;
  20510. next += copy;
  20511. state.length -= copy;
  20512. }
  20513. if (state.length) { break inf_leave; }
  20514. }
  20515. state.length = 0;
  20516. state.mode = NAME;
  20517. /* falls through */
  20518. case NAME:
  20519. if (state.flags & 0x0800) {
  20520. if (have === 0) { break inf_leave; }
  20521. copy = 0;
  20522. do {
  20523. // TODO: 2 or 1 bytes?
  20524. len = input[next + copy++];
  20525. /* use constant limit because in js we should not preallocate memory */
  20526. if (state.head && len &&
  20527. (state.length < 65536 /*state.head.name_max*/)) {
  20528. state.head.name += String.fromCharCode(len);
  20529. }
  20530. } while (len && copy < have);
  20531. if (state.flags & 0x0200) {
  20532. state.check = crc32(state.check, input, copy, next);
  20533. }
  20534. have -= copy;
  20535. next += copy;
  20536. if (len) { break inf_leave; }
  20537. }
  20538. else if (state.head) {
  20539. state.head.name = null;
  20540. }
  20541. state.length = 0;
  20542. state.mode = COMMENT;
  20543. /* falls through */
  20544. case COMMENT:
  20545. if (state.flags & 0x1000) {
  20546. if (have === 0) { break inf_leave; }
  20547. copy = 0;
  20548. do {
  20549. len = input[next + copy++];
  20550. /* use constant limit because in js we should not preallocate memory */
  20551. if (state.head && len &&
  20552. (state.length < 65536 /*state.head.comm_max*/)) {
  20553. state.head.comment += String.fromCharCode(len);
  20554. }
  20555. } while (len && copy < have);
  20556. if (state.flags & 0x0200) {
  20557. state.check = crc32(state.check, input, copy, next);
  20558. }
  20559. have -= copy;
  20560. next += copy;
  20561. if (len) { break inf_leave; }
  20562. }
  20563. else if (state.head) {
  20564. state.head.comment = null;
  20565. }
  20566. state.mode = HCRC;
  20567. /* falls through */
  20568. case HCRC:
  20569. if (state.flags & 0x0200) {
  20570. //=== NEEDBITS(16); */
  20571. while (bits < 16) {
  20572. if (have === 0) { break inf_leave; }
  20573. have--;
  20574. hold += input[next++] << bits;
  20575. bits += 8;
  20576. }
  20577. //===//
  20578. if (hold !== (state.check & 0xffff)) {
  20579. strm.msg = 'header crc mismatch';
  20580. state.mode = BAD;
  20581. break;
  20582. }
  20583. //=== INITBITS();
  20584. hold = 0;
  20585. bits = 0;
  20586. //===//
  20587. }
  20588. if (state.head) {
  20589. state.head.hcrc = ((state.flags >> 9) & 1);
  20590. state.head.done = true;
  20591. }
  20592. strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/;
  20593. state.mode = TYPE;
  20594. break;
  20595. case DICTID:
  20596. //=== NEEDBITS(32); */
  20597. while (bits < 32) {
  20598. if (have === 0) { break inf_leave; }
  20599. have--;
  20600. hold += input[next++] << bits;
  20601. bits += 8;
  20602. }
  20603. //===//
  20604. strm.adler = state.check = ZSWAP32(hold);
  20605. //=== INITBITS();
  20606. hold = 0;
  20607. bits = 0;
  20608. //===//
  20609. state.mode = DICT;
  20610. /* falls through */
  20611. case DICT:
  20612. if (state.havedict === 0) {
  20613. //--- RESTORE() ---
  20614. strm.next_out = put;
  20615. strm.avail_out = left;
  20616. strm.next_in = next;
  20617. strm.avail_in = have;
  20618. state.hold = hold;
  20619. state.bits = bits;
  20620. //---
  20621. return Z_NEED_DICT;
  20622. }
  20623. strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
  20624. state.mode = TYPE;
  20625. /* falls through */
  20626. case TYPE:
  20627. if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
  20628. /* falls through */
  20629. case TYPEDO:
  20630. if (state.last) {
  20631. //--- BYTEBITS() ---//
  20632. hold >>>= bits & 7;
  20633. bits -= bits & 7;
  20634. //---//
  20635. state.mode = CHECK;
  20636. break;
  20637. }
  20638. //=== NEEDBITS(3); */
  20639. while (bits < 3) {
  20640. if (have === 0) { break inf_leave; }
  20641. have--;
  20642. hold += input[next++] << bits;
  20643. bits += 8;
  20644. }
  20645. //===//
  20646. state.last = (hold & 0x01)/*BITS(1)*/;
  20647. //--- DROPBITS(1) ---//
  20648. hold >>>= 1;
  20649. bits -= 1;
  20650. //---//
  20651. switch ((hold & 0x03)/*BITS(2)*/) {
  20652. case 0: /* stored block */
  20653. //Tracev((stderr, "inflate: stored block%s\n",
  20654. // state.last ? " (last)" : ""));
  20655. state.mode = STORED;
  20656. break;
  20657. case 1: /* fixed block */
  20658. fixedtables(state);
  20659. //Tracev((stderr, "inflate: fixed codes block%s\n",
  20660. // state.last ? " (last)" : ""));
  20661. state.mode = LEN_; /* decode codes */
  20662. if (flush === Z_TREES) {
  20663. //--- DROPBITS(2) ---//
  20664. hold >>>= 2;
  20665. bits -= 2;
  20666. //---//
  20667. break inf_leave;
  20668. }
  20669. break;
  20670. case 2: /* dynamic block */
  20671. //Tracev((stderr, "inflate: dynamic codes block%s\n",
  20672. // state.last ? " (last)" : ""));
  20673. state.mode = TABLE;
  20674. break;
  20675. case 3:
  20676. strm.msg = 'invalid block type';
  20677. state.mode = BAD;
  20678. }
  20679. //--- DROPBITS(2) ---//
  20680. hold >>>= 2;
  20681. bits -= 2;
  20682. //---//
  20683. break;
  20684. case STORED:
  20685. //--- BYTEBITS() ---// /* go to byte boundary */
  20686. hold >>>= bits & 7;
  20687. bits -= bits & 7;
  20688. //---//
  20689. //=== NEEDBITS(32); */
  20690. while (bits < 32) {
  20691. if (have === 0) { break inf_leave; }
  20692. have--;
  20693. hold += input[next++] << bits;
  20694. bits += 8;
  20695. }
  20696. //===//
  20697. if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
  20698. strm.msg = 'invalid stored block lengths';
  20699. state.mode = BAD;
  20700. break;
  20701. }
  20702. state.length = hold & 0xffff;
  20703. //Tracev((stderr, "inflate: stored length %u\n",
  20704. // state.length));
  20705. //=== INITBITS();
  20706. hold = 0;
  20707. bits = 0;
  20708. //===//
  20709. state.mode = COPY_;
  20710. if (flush === Z_TREES) { break inf_leave; }
  20711. /* falls through */
  20712. case COPY_:
  20713. state.mode = COPY;
  20714. /* falls through */
  20715. case COPY:
  20716. copy = state.length;
  20717. if (copy) {
  20718. if (copy > have) { copy = have; }
  20719. if (copy > left) { copy = left; }
  20720. if (copy === 0) { break inf_leave; }
  20721. //--- zmemcpy(put, next, copy); ---
  20722. utils.arraySet(output, input, next, copy, put);
  20723. //---//
  20724. have -= copy;
  20725. next += copy;
  20726. left -= copy;
  20727. put += copy;
  20728. state.length -= copy;
  20729. break;
  20730. }
  20731. //Tracev((stderr, "inflate: stored end\n"));
  20732. state.mode = TYPE;
  20733. break;
  20734. case TABLE:
  20735. //=== NEEDBITS(14); */
  20736. while (bits < 14) {
  20737. if (have === 0) { break inf_leave; }
  20738. have--;
  20739. hold += input[next++] << bits;
  20740. bits += 8;
  20741. }
  20742. //===//
  20743. state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
  20744. //--- DROPBITS(5) ---//
  20745. hold >>>= 5;
  20746. bits -= 5;
  20747. //---//
  20748. state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
  20749. //--- DROPBITS(5) ---//
  20750. hold >>>= 5;
  20751. bits -= 5;
  20752. //---//
  20753. state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
  20754. //--- DROPBITS(4) ---//
  20755. hold >>>= 4;
  20756. bits -= 4;
  20757. //---//
  20758. //#ifndef PKZIP_BUG_WORKAROUND
  20759. if (state.nlen > 286 || state.ndist > 30) {
  20760. strm.msg = 'too many length or distance symbols';
  20761. state.mode = BAD;
  20762. break;
  20763. }
  20764. //#endif
  20765. //Tracev((stderr, "inflate: table sizes ok\n"));
  20766. state.have = 0;
  20767. state.mode = LENLENS;
  20768. /* falls through */
  20769. case LENLENS:
  20770. while (state.have < state.ncode) {
  20771. //=== NEEDBITS(3);
  20772. while (bits < 3) {
  20773. if (have === 0) { break inf_leave; }
  20774. have--;
  20775. hold += input[next++] << bits;
  20776. bits += 8;
  20777. }
  20778. //===//
  20779. state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
  20780. //--- DROPBITS(3) ---//
  20781. hold >>>= 3;
  20782. bits -= 3;
  20783. //---//
  20784. }
  20785. while (state.have < 19) {
  20786. state.lens[order[state.have++]] = 0;
  20787. }
  20788. // We have separate tables & no pointers. 2 commented lines below not needed.
  20789. //state.next = state.codes;
  20790. //state.lencode = state.next;
  20791. // Switch to use dynamic table
  20792. state.lencode = state.lendyn;
  20793. state.lenbits = 7;
  20794. opts = {bits: state.lenbits};
  20795. ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
  20796. state.lenbits = opts.bits;
  20797. if (ret) {
  20798. strm.msg = 'invalid code lengths set';
  20799. state.mode = BAD;
  20800. break;
  20801. }
  20802. //Tracev((stderr, "inflate: code lengths ok\n"));
  20803. state.have = 0;
  20804. state.mode = CODELENS;
  20805. /* falls through */
  20806. case CODELENS:
  20807. while (state.have < state.nlen + state.ndist) {
  20808. for (;;) {
  20809. here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
  20810. here_bits = here >>> 24;
  20811. here_op = (here >>> 16) & 0xff;
  20812. here_val = here & 0xffff;
  20813. if ((here_bits) <= bits) { break; }
  20814. //--- PULLBYTE() ---//
  20815. if (have === 0) { break inf_leave; }
  20816. have--;
  20817. hold += input[next++] << bits;
  20818. bits += 8;
  20819. //---//
  20820. }
  20821. if (here_val < 16) {
  20822. //--- DROPBITS(here.bits) ---//
  20823. hold >>>= here_bits;
  20824. bits -= here_bits;
  20825. //---//
  20826. state.lens[state.have++] = here_val;
  20827. }
  20828. else {
  20829. if (here_val === 16) {
  20830. //=== NEEDBITS(here.bits + 2);
  20831. n = here_bits + 2;
  20832. while (bits < n) {
  20833. if (have === 0) { break inf_leave; }
  20834. have--;
  20835. hold += input[next++] << bits;
  20836. bits += 8;
  20837. }
  20838. //===//
  20839. //--- DROPBITS(here.bits) ---//
  20840. hold >>>= here_bits;
  20841. bits -= here_bits;
  20842. //---//
  20843. if (state.have === 0) {
  20844. strm.msg = 'invalid bit length repeat';
  20845. state.mode = BAD;
  20846. break;
  20847. }
  20848. len = state.lens[state.have - 1];
  20849. copy = 3 + (hold & 0x03);//BITS(2);
  20850. //--- DROPBITS(2) ---//
  20851. hold >>>= 2;
  20852. bits -= 2;
  20853. //---//
  20854. }
  20855. else if (here_val === 17) {
  20856. //=== NEEDBITS(here.bits + 3);
  20857. n = here_bits + 3;
  20858. while (bits < n) {
  20859. if (have === 0) { break inf_leave; }
  20860. have--;
  20861. hold += input[next++] << bits;
  20862. bits += 8;
  20863. }
  20864. //===//
  20865. //--- DROPBITS(here.bits) ---//
  20866. hold >>>= here_bits;
  20867. bits -= here_bits;
  20868. //---//
  20869. len = 0;
  20870. copy = 3 + (hold & 0x07);//BITS(3);
  20871. //--- DROPBITS(3) ---//
  20872. hold >>>= 3;
  20873. bits -= 3;
  20874. //---//
  20875. }
  20876. else {
  20877. //=== NEEDBITS(here.bits + 7);
  20878. n = here_bits + 7;
  20879. while (bits < n) {
  20880. if (have === 0) { break inf_leave; }
  20881. have--;
  20882. hold += input[next++] << bits;
  20883. bits += 8;
  20884. }
  20885. //===//
  20886. //--- DROPBITS(here.bits) ---//
  20887. hold >>>= here_bits;
  20888. bits -= here_bits;
  20889. //---//
  20890. len = 0;
  20891. copy = 11 + (hold & 0x7f);//BITS(7);
  20892. //--- DROPBITS(7) ---//
  20893. hold >>>= 7;
  20894. bits -= 7;
  20895. //---//
  20896. }
  20897. if (state.have + copy > state.nlen + state.ndist) {
  20898. strm.msg = 'invalid bit length repeat';
  20899. state.mode = BAD;
  20900. break;
  20901. }
  20902. while (copy--) {
  20903. state.lens[state.have++] = len;
  20904. }
  20905. }
  20906. }
  20907. /* handle error breaks in while */
  20908. if (state.mode === BAD) { break; }
  20909. /* check for end-of-block code (better have one) */
  20910. if (state.lens[256] === 0) {
  20911. strm.msg = 'invalid code -- missing end-of-block';
  20912. state.mode = BAD;
  20913. break;
  20914. }
  20915. /* build code tables -- note: do not change the lenbits or distbits
  20916. values here (9 and 6) without reading the comments in inftrees.h
  20917. concerning the ENOUGH constants, which depend on those values */
  20918. state.lenbits = 9;
  20919. opts = {bits: state.lenbits};
  20920. ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
  20921. // We have separate tables & no pointers. 2 commented lines below not needed.
  20922. // state.next_index = opts.table_index;
  20923. state.lenbits = opts.bits;
  20924. // state.lencode = state.next;
  20925. if (ret) {
  20926. strm.msg = 'invalid literal/lengths set';
  20927. state.mode = BAD;
  20928. break;
  20929. }
  20930. state.distbits = 6;
  20931. //state.distcode.copy(state.codes);
  20932. // Switch to use dynamic table
  20933. state.distcode = state.distdyn;
  20934. opts = {bits: state.distbits};
  20935. ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
  20936. // We have separate tables & no pointers. 2 commented lines below not needed.
  20937. // state.next_index = opts.table_index;
  20938. state.distbits = opts.bits;
  20939. // state.distcode = state.next;
  20940. if (ret) {
  20941. strm.msg = 'invalid distances set';
  20942. state.mode = BAD;
  20943. break;
  20944. }
  20945. //Tracev((stderr, 'inflate: codes ok\n'));
  20946. state.mode = LEN_;
  20947. if (flush === Z_TREES) { break inf_leave; }
  20948. /* falls through */
  20949. case LEN_:
  20950. state.mode = LEN;
  20951. /* falls through */
  20952. case LEN:
  20953. if (have >= 6 && left >= 258) {
  20954. //--- RESTORE() ---
  20955. strm.next_out = put;
  20956. strm.avail_out = left;
  20957. strm.next_in = next;
  20958. strm.avail_in = have;
  20959. state.hold = hold;
  20960. state.bits = bits;
  20961. //---
  20962. inflate_fast(strm, _out);
  20963. //--- LOAD() ---
  20964. put = strm.next_out;
  20965. output = strm.output;
  20966. left = strm.avail_out;
  20967. next = strm.next_in;
  20968. input = strm.input;
  20969. have = strm.avail_in;
  20970. hold = state.hold;
  20971. bits = state.bits;
  20972. //---
  20973. if (state.mode === TYPE) {
  20974. state.back = -1;
  20975. }
  20976. break;
  20977. }
  20978. state.back = 0;
  20979. for (;;) {
  20980. here = state.lencode[hold & ((1 << state.lenbits) -1)]; /*BITS(state.lenbits)*/
  20981. here_bits = here >>> 24;
  20982. here_op = (here >>> 16) & 0xff;
  20983. here_val = here & 0xffff;
  20984. if (here_bits <= bits) { break; }
  20985. //--- PULLBYTE() ---//
  20986. if (have === 0) { break inf_leave; }
  20987. have--;
  20988. hold += input[next++] << bits;
  20989. bits += 8;
  20990. //---//
  20991. }
  20992. if (here_op && (here_op & 0xf0) === 0) {
  20993. last_bits = here_bits;
  20994. last_op = here_op;
  20995. last_val = here_val;
  20996. for (;;) {
  20997. here = state.lencode[last_val +
  20998. ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
  20999. here_bits = here >>> 24;
  21000. here_op = (here >>> 16) & 0xff;
  21001. here_val = here & 0xffff;
  21002. if ((last_bits + here_bits) <= bits) { break; }
  21003. //--- PULLBYTE() ---//
  21004. if (have === 0) { break inf_leave; }
  21005. have--;
  21006. hold += input[next++] << bits;
  21007. bits += 8;
  21008. //---//
  21009. }
  21010. //--- DROPBITS(last.bits) ---//
  21011. hold >>>= last_bits;
  21012. bits -= last_bits;
  21013. //---//
  21014. state.back += last_bits;
  21015. }
  21016. //--- DROPBITS(here.bits) ---//
  21017. hold >>>= here_bits;
  21018. bits -= here_bits;
  21019. //---//
  21020. state.back += here_bits;
  21021. state.length = here_val;
  21022. if (here_op === 0) {
  21023. //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
  21024. // "inflate: literal '%c'\n" :
  21025. // "inflate: literal 0x%02x\n", here.val));
  21026. state.mode = LIT;
  21027. break;
  21028. }
  21029. if (here_op & 32) {
  21030. //Tracevv((stderr, "inflate: end of block\n"));
  21031. state.back = -1;
  21032. state.mode = TYPE;
  21033. break;
  21034. }
  21035. if (here_op & 64) {
  21036. strm.msg = 'invalid literal/length code';
  21037. state.mode = BAD;
  21038. break;
  21039. }
  21040. state.extra = here_op & 15;
  21041. state.mode = LENEXT;
  21042. /* falls through */
  21043. case LENEXT:
  21044. if (state.extra) {
  21045. //=== NEEDBITS(state.extra);
  21046. n = state.extra;
  21047. while (bits < n) {
  21048. if (have === 0) { break inf_leave; }
  21049. have--;
  21050. hold += input[next++] << bits;
  21051. bits += 8;
  21052. }
  21053. //===//
  21054. state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
  21055. //--- DROPBITS(state.extra) ---//
  21056. hold >>>= state.extra;
  21057. bits -= state.extra;
  21058. //---//
  21059. state.back += state.extra;
  21060. }
  21061. //Tracevv((stderr, "inflate: length %u\n", state.length));
  21062. state.was = state.length;
  21063. state.mode = DIST;
  21064. /* falls through */
  21065. case DIST:
  21066. for (;;) {
  21067. here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/
  21068. here_bits = here >>> 24;
  21069. here_op = (here >>> 16) & 0xff;
  21070. here_val = here & 0xffff;
  21071. if ((here_bits) <= bits) { break; }
  21072. //--- PULLBYTE() ---//
  21073. if (have === 0) { break inf_leave; }
  21074. have--;
  21075. hold += input[next++] << bits;
  21076. bits += 8;
  21077. //---//
  21078. }
  21079. if ((here_op & 0xf0) === 0) {
  21080. last_bits = here_bits;
  21081. last_op = here_op;
  21082. last_val = here_val;
  21083. for (;;) {
  21084. here = state.distcode[last_val +
  21085. ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
  21086. here_bits = here >>> 24;
  21087. here_op = (here >>> 16) & 0xff;
  21088. here_val = here & 0xffff;
  21089. if ((last_bits + here_bits) <= bits) { break; }
  21090. //--- PULLBYTE() ---//
  21091. if (have === 0) { break inf_leave; }
  21092. have--;
  21093. hold += input[next++] << bits;
  21094. bits += 8;
  21095. //---//
  21096. }
  21097. //--- DROPBITS(last.bits) ---//
  21098. hold >>>= last_bits;
  21099. bits -= last_bits;
  21100. //---//
  21101. state.back += last_bits;
  21102. }
  21103. //--- DROPBITS(here.bits) ---//
  21104. hold >>>= here_bits;
  21105. bits -= here_bits;
  21106. //---//
  21107. state.back += here_bits;
  21108. if (here_op & 64) {
  21109. strm.msg = 'invalid distance code';
  21110. state.mode = BAD;
  21111. break;
  21112. }
  21113. state.offset = here_val;
  21114. state.extra = (here_op) & 15;
  21115. state.mode = DISTEXT;
  21116. /* falls through */
  21117. case DISTEXT:
  21118. if (state.extra) {
  21119. //=== NEEDBITS(state.extra);
  21120. n = state.extra;
  21121. while (bits < n) {
  21122. if (have === 0) { break inf_leave; }
  21123. have--;
  21124. hold += input[next++] << bits;
  21125. bits += 8;
  21126. }
  21127. //===//
  21128. state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
  21129. //--- DROPBITS(state.extra) ---//
  21130. hold >>>= state.extra;
  21131. bits -= state.extra;
  21132. //---//
  21133. state.back += state.extra;
  21134. }
  21135. //#ifdef INFLATE_STRICT
  21136. if (state.offset > state.dmax) {
  21137. strm.msg = 'invalid distance too far back';
  21138. state.mode = BAD;
  21139. break;
  21140. }
  21141. //#endif
  21142. //Tracevv((stderr, "inflate: distance %u\n", state.offset));
  21143. state.mode = MATCH;
  21144. /* falls through */
  21145. case MATCH:
  21146. if (left === 0) { break inf_leave; }
  21147. copy = _out - left;
  21148. if (state.offset > copy) { /* copy from window */
  21149. copy = state.offset - copy;
  21150. if (copy > state.whave) {
  21151. if (state.sane) {
  21152. strm.msg = 'invalid distance too far back';
  21153. state.mode = BAD;
  21154. break;
  21155. }
  21156. // (!) This block is disabled in zlib defailts,
  21157. // don't enable it for binary compatibility
  21158. //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
  21159. // Trace((stderr, "inflate.c too far\n"));
  21160. // copy -= state.whave;
  21161. // if (copy > state.length) { copy = state.length; }
  21162. // if (copy > left) { copy = left; }
  21163. // left -= copy;
  21164. // state.length -= copy;
  21165. // do {
  21166. // output[put++] = 0;
  21167. // } while (--copy);
  21168. // if (state.length === 0) { state.mode = LEN; }
  21169. // break;
  21170. //#endif
  21171. }
  21172. if (copy > state.wnext) {
  21173. copy -= state.wnext;
  21174. from = state.wsize - copy;
  21175. }
  21176. else {
  21177. from = state.wnext - copy;
  21178. }
  21179. if (copy > state.length) { copy = state.length; }
  21180. from_source = state.window;
  21181. }
  21182. else { /* copy from output */
  21183. from_source = output;
  21184. from = put - state.offset;
  21185. copy = state.length;
  21186. }
  21187. if (copy > left) { copy = left; }
  21188. left -= copy;
  21189. state.length -= copy;
  21190. do {
  21191. output[put++] = from_source[from++];
  21192. } while (--copy);
  21193. if (state.length === 0) { state.mode = LEN; }
  21194. break;
  21195. case LIT:
  21196. if (left === 0) { break inf_leave; }
  21197. output[put++] = state.length;
  21198. left--;
  21199. state.mode = LEN;
  21200. break;
  21201. case CHECK:
  21202. if (state.wrap) {
  21203. //=== NEEDBITS(32);
  21204. while (bits < 32) {
  21205. if (have === 0) { break inf_leave; }
  21206. have--;
  21207. // Use '|' insdead of '+' to make sure that result is signed
  21208. hold |= input[next++] << bits;
  21209. bits += 8;
  21210. }
  21211. //===//
  21212. _out -= left;
  21213. strm.total_out += _out;
  21214. state.total += _out;
  21215. if (_out) {
  21216. strm.adler = state.check =
  21217. /*UPDATE(state.check, put - _out, _out);*/
  21218. (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));
  21219. }
  21220. _out = left;
  21221. // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too
  21222. if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) {
  21223. strm.msg = 'incorrect data check';
  21224. state.mode = BAD;
  21225. break;
  21226. }
  21227. //=== INITBITS();
  21228. hold = 0;
  21229. bits = 0;
  21230. //===//
  21231. //Tracev((stderr, "inflate: check matches trailer\n"));
  21232. }
  21233. state.mode = LENGTH;
  21234. /* falls through */
  21235. case LENGTH:
  21236. if (state.wrap && state.flags) {
  21237. //=== NEEDBITS(32);
  21238. while (bits < 32) {
  21239. if (have === 0) { break inf_leave; }
  21240. have--;
  21241. hold += input[next++] << bits;
  21242. bits += 8;
  21243. }
  21244. //===//
  21245. if (hold !== (state.total & 0xffffffff)) {
  21246. strm.msg = 'incorrect length check';
  21247. state.mode = BAD;
  21248. break;
  21249. }
  21250. //=== INITBITS();
  21251. hold = 0;
  21252. bits = 0;
  21253. //===//
  21254. //Tracev((stderr, "inflate: length matches trailer\n"));
  21255. }
  21256. state.mode = DONE;
  21257. /* falls through */
  21258. case DONE:
  21259. ret = Z_STREAM_END;
  21260. break inf_leave;
  21261. case BAD:
  21262. ret = Z_DATA_ERROR;
  21263. break inf_leave;
  21264. case MEM:
  21265. return Z_MEM_ERROR;
  21266. case SYNC:
  21267. /* falls through */
  21268. default:
  21269. return Z_STREAM_ERROR;
  21270. }
  21271. }
  21272. // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
  21273. /*
  21274. Return from inflate(), updating the total counts and the check value.
  21275. If there was no progress during the inflate() call, return a buffer
  21276. error. Call updatewindow() to create and/or update the window state.
  21277. Note: a memory error from inflate() is non-recoverable.
  21278. */
  21279. //--- RESTORE() ---
  21280. strm.next_out = put;
  21281. strm.avail_out = left;
  21282. strm.next_in = next;
  21283. strm.avail_in = have;
  21284. state.hold = hold;
  21285. state.bits = bits;
  21286. //---
  21287. if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
  21288. (state.mode < CHECK || flush !== Z_FINISH))) {
  21289. if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
  21290. state.mode = MEM;
  21291. return Z_MEM_ERROR;
  21292. }
  21293. }
  21294. _in -= strm.avail_in;
  21295. _out -= strm.avail_out;
  21296. strm.total_in += _in;
  21297. strm.total_out += _out;
  21298. state.total += _out;
  21299. if (state.wrap && _out) {
  21300. strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
  21301. (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
  21302. }
  21303. strm.data_type = state.bits + (state.last ? 64 : 0) +
  21304. (state.mode === TYPE ? 128 : 0) +
  21305. (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
  21306. if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
  21307. ret = Z_BUF_ERROR;
  21308. }
  21309. return ret;
  21310. }
  21311. function inflateEnd(strm) {
  21312. if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
  21313. return Z_STREAM_ERROR;
  21314. }
  21315. var state = strm.state;
  21316. if (state.window) {
  21317. state.window = null;
  21318. }
  21319. strm.state = null;
  21320. return Z_OK;
  21321. }
  21322. function inflateGetHeader(strm, head) {
  21323. var state;
  21324. /* check state */
  21325. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  21326. state = strm.state;
  21327. if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }
  21328. /* save header structure */
  21329. state.head = head;
  21330. head.done = false;
  21331. return Z_OK;
  21332. }
  21333. exports.inflateReset = inflateReset;
  21334. exports.inflateReset2 = inflateReset2;
  21335. exports.inflateResetKeep = inflateResetKeep;
  21336. exports.inflateInit = inflateInit;
  21337. exports.inflateInit2 = inflateInit2;
  21338. exports.inflate = inflate;
  21339. exports.inflateEnd = inflateEnd;
  21340. exports.inflateGetHeader = inflateGetHeader;
  21341. exports.inflateInfo = 'pako inflate (from Nodeca project)';
  21342. /* Not implemented
  21343. exports.inflateCopy = inflateCopy;
  21344. exports.inflateGetDictionary = inflateGetDictionary;
  21345. exports.inflateMark = inflateMark;
  21346. exports.inflatePrime = inflatePrime;
  21347. exports.inflateSetDictionary = inflateSetDictionary;
  21348. exports.inflateSync = inflateSync;
  21349. exports.inflateSyncPoint = inflateSyncPoint;
  21350. exports.inflateUndermine = inflateUndermine;
  21351. */
  21352. },{"../utils/common":66,"./adler32":68,"./crc32":70,"./inffast":73,"./inftrees":75}],75:[function(require,module,exports){
  21353. 'use strict';
  21354. var utils = require('../utils/common');
  21355. var MAXBITS = 15;
  21356. var ENOUGH_LENS = 852;
  21357. var ENOUGH_DISTS = 592;
  21358. //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
  21359. var CODES = 0;
  21360. var LENS = 1;
  21361. var DISTS = 2;
  21362. var lbase = [ /* Length codes 257..285 base */
  21363. 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
  21364. 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
  21365. ];
  21366. var lext = [ /* Length codes 257..285 extra */
  21367. 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
  21368. 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
  21369. ];
  21370. var dbase = [ /* Distance codes 0..29 base */
  21371. 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
  21372. 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
  21373. 8193, 12289, 16385, 24577, 0, 0
  21374. ];
  21375. var dext = [ /* Distance codes 0..29 extra */
  21376. 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
  21377. 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
  21378. 28, 28, 29, 29, 64, 64
  21379. ];
  21380. module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)
  21381. {
  21382. var bits = opts.bits;
  21383. //here = opts.here; /* table entry for duplication */
  21384. var len = 0; /* a code's length in bits */
  21385. var sym = 0; /* index of code symbols */
  21386. var min = 0, max = 0; /* minimum and maximum code lengths */
  21387. var root = 0; /* number of index bits for root table */
  21388. var curr = 0; /* number of index bits for current table */
  21389. var drop = 0; /* code bits to drop for sub-table */
  21390. var left = 0; /* number of prefix codes available */
  21391. var used = 0; /* code entries in table used */
  21392. var huff = 0; /* Huffman code */
  21393. var incr; /* for incrementing code, index */
  21394. var fill; /* index for replicating entries */
  21395. var low; /* low bits for current root entry */
  21396. var mask; /* mask for low root bits */
  21397. var next; /* next available space in table */
  21398. var base = null; /* base value table to use */
  21399. var base_index = 0;
  21400. // var shoextra; /* extra bits table to use */
  21401. var end; /* use base and extra for symbol > end */
  21402. var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */
  21403. var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */
  21404. var extra = null;
  21405. var extra_index = 0;
  21406. var here_bits, here_op, here_val;
  21407. /*
  21408. Process a set of code lengths to create a canonical Huffman code. The
  21409. code lengths are lens[0..codes-1]. Each length corresponds to the
  21410. symbols 0..codes-1. The Huffman code is generated by first sorting the
  21411. symbols by length from short to long, and retaining the symbol order
  21412. for codes with equal lengths. Then the code starts with all zero bits
  21413. for the first code of the shortest length, and the codes are integer
  21414. increments for the same length, and zeros are appended as the length
  21415. increases. For the deflate format, these bits are stored backwards
  21416. from their more natural integer increment ordering, and so when the
  21417. decoding tables are built in the large loop below, the integer codes
  21418. are incremented backwards.
  21419. This routine assumes, but does not check, that all of the entries in
  21420. lens[] are in the range 0..MAXBITS. The caller must assure this.
  21421. 1..MAXBITS is interpreted as that code length. zero means that that
  21422. symbol does not occur in this code.
  21423. The codes are sorted by computing a count of codes for each length,
  21424. creating from that a table of starting indices for each length in the
  21425. sorted table, and then entering the symbols in order in the sorted
  21426. table. The sorted table is work[], with that space being provided by
  21427. the caller.
  21428. The length counts are used for other purposes as well, i.e. finding
  21429. the minimum and maximum length codes, determining if there are any
  21430. codes at all, checking for a valid set of lengths, and looking ahead
  21431. at length counts to determine sub-table sizes when building the
  21432. decoding tables.
  21433. */
  21434. /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
  21435. for (len = 0; len <= MAXBITS; len++) {
  21436. count[len] = 0;
  21437. }
  21438. for (sym = 0; sym < codes; sym++) {
  21439. count[lens[lens_index + sym]]++;
  21440. }
  21441. /* bound code lengths, force root to be within code lengths */
  21442. root = bits;
  21443. for (max = MAXBITS; max >= 1; max--) {
  21444. if (count[max] !== 0) { break; }
  21445. }
  21446. if (root > max) {
  21447. root = max;
  21448. }
  21449. if (max === 0) { /* no symbols to code at all */
  21450. //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
  21451. //table.bits[opts.table_index] = 1; //here.bits = (var char)1;
  21452. //table.val[opts.table_index++] = 0; //here.val = (var short)0;
  21453. table[table_index++] = (1 << 24) | (64 << 16) | 0;
  21454. //table.op[opts.table_index] = 64;
  21455. //table.bits[opts.table_index] = 1;
  21456. //table.val[opts.table_index++] = 0;
  21457. table[table_index++] = (1 << 24) | (64 << 16) | 0;
  21458. opts.bits = 1;
  21459. return 0; /* no symbols, but wait for decoding to report error */
  21460. }
  21461. for (min = 1; min < max; min++) {
  21462. if (count[min] !== 0) { break; }
  21463. }
  21464. if (root < min) {
  21465. root = min;
  21466. }
  21467. /* check for an over-subscribed or incomplete set of lengths */
  21468. left = 1;
  21469. for (len = 1; len <= MAXBITS; len++) {
  21470. left <<= 1;
  21471. left -= count[len];
  21472. if (left < 0) {
  21473. return -1;
  21474. } /* over-subscribed */
  21475. }
  21476. if (left > 0 && (type === CODES || max !== 1)) {
  21477. return -1; /* incomplete set */
  21478. }
  21479. /* generate offsets into symbol table for each length for sorting */
  21480. offs[1] = 0;
  21481. for (len = 1; len < MAXBITS; len++) {
  21482. offs[len + 1] = offs[len] + count[len];
  21483. }
  21484. /* sort symbols by length, by symbol order within each length */
  21485. for (sym = 0; sym < codes; sym++) {
  21486. if (lens[lens_index + sym] !== 0) {
  21487. work[offs[lens[lens_index + sym]]++] = sym;
  21488. }
  21489. }
  21490. /*
  21491. Create and fill in decoding tables. In this loop, the table being
  21492. filled is at next and has curr index bits. The code being used is huff
  21493. with length len. That code is converted to an index by dropping drop
  21494. bits off of the bottom. For codes where len is less than drop + curr,
  21495. those top drop + curr - len bits are incremented through all values to
  21496. fill the table with replicated entries.
  21497. root is the number of index bits for the root table. When len exceeds
  21498. root, sub-tables are created pointed to by the root entry with an index
  21499. of the low root bits of huff. This is saved in low to check for when a
  21500. new sub-table should be started. drop is zero when the root table is
  21501. being filled, and drop is root when sub-tables are being filled.
  21502. When a new sub-table is needed, it is necessary to look ahead in the
  21503. code lengths to determine what size sub-table is needed. The length
  21504. counts are used for this, and so count[] is decremented as codes are
  21505. entered in the tables.
  21506. used keeps track of how many table entries have been allocated from the
  21507. provided *table space. It is checked for LENS and DIST tables against
  21508. the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
  21509. the initial root table size constants. See the comments in inftrees.h
  21510. for more information.
  21511. sym increments through all symbols, and the loop terminates when
  21512. all codes of length max, i.e. all codes, have been processed. This
  21513. routine permits incomplete codes, so another loop after this one fills
  21514. in the rest of the decoding tables with invalid code markers.
  21515. */
  21516. /* set up for code type */
  21517. // poor man optimization - use if-else instead of switch,
  21518. // to avoid deopts in old v8
  21519. if (type === CODES) {
  21520. base = extra = work; /* dummy value--not used */
  21521. end = 19;
  21522. } else if (type === LENS) {
  21523. base = lbase;
  21524. base_index -= 257;
  21525. extra = lext;
  21526. extra_index -= 257;
  21527. end = 256;
  21528. } else { /* DISTS */
  21529. base = dbase;
  21530. extra = dext;
  21531. end = -1;
  21532. }
  21533. /* initialize opts for loop */
  21534. huff = 0; /* starting code */
  21535. sym = 0; /* starting code symbol */
  21536. len = min; /* starting code length */
  21537. next = table_index; /* current table to fill in */
  21538. curr = root; /* current table index bits */
  21539. drop = 0; /* current bits to drop from code for index */
  21540. low = -1; /* trigger new sub-table when len > root */
  21541. used = 1 << root; /* use root table entries */
  21542. mask = used - 1; /* mask for comparing low */
  21543. /* check available table space */
  21544. if ((type === LENS && used > ENOUGH_LENS) ||
  21545. (type === DISTS && used > ENOUGH_DISTS)) {
  21546. return 1;
  21547. }
  21548. var i=0;
  21549. /* process all codes and make table entries */
  21550. for (;;) {
  21551. i++;
  21552. /* create table entry */
  21553. here_bits = len - drop;
  21554. if (work[sym] < end) {
  21555. here_op = 0;
  21556. here_val = work[sym];
  21557. }
  21558. else if (work[sym] > end) {
  21559. here_op = extra[extra_index + work[sym]];
  21560. here_val = base[base_index + work[sym]];
  21561. }
  21562. else {
  21563. here_op = 32 + 64; /* end of block */
  21564. here_val = 0;
  21565. }
  21566. /* replicate for those indices with low len bits equal to huff */
  21567. incr = 1 << (len - drop);
  21568. fill = 1 << curr;
  21569. min = fill; /* save offset to next table */
  21570. do {
  21571. fill -= incr;
  21572. table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
  21573. } while (fill !== 0);
  21574. /* backwards increment the len-bit code huff */
  21575. incr = 1 << (len - 1);
  21576. while (huff & incr) {
  21577. incr >>= 1;
  21578. }
  21579. if (incr !== 0) {
  21580. huff &= incr - 1;
  21581. huff += incr;
  21582. } else {
  21583. huff = 0;
  21584. }
  21585. /* go to next symbol, update count, len */
  21586. sym++;
  21587. if (--count[len] === 0) {
  21588. if (len === max) { break; }
  21589. len = lens[lens_index + work[sym]];
  21590. }
  21591. /* create new sub-table if needed */
  21592. if (len > root && (huff & mask) !== low) {
  21593. /* if first time, transition to sub-tables */
  21594. if (drop === 0) {
  21595. drop = root;
  21596. }
  21597. /* increment past last table */
  21598. next += min; /* here min is 1 << curr */
  21599. /* determine length of next table */
  21600. curr = len - drop;
  21601. left = 1 << curr;
  21602. while (curr + drop < max) {
  21603. left -= count[curr + drop];
  21604. if (left <= 0) { break; }
  21605. curr++;
  21606. left <<= 1;
  21607. }
  21608. /* check for enough space */
  21609. used += 1 << curr;
  21610. if ((type === LENS && used > ENOUGH_LENS) ||
  21611. (type === DISTS && used > ENOUGH_DISTS)) {
  21612. return 1;
  21613. }
  21614. /* point entry in root table to sub-table */
  21615. low = huff & mask;
  21616. /*table.op[low] = curr;
  21617. table.bits[low] = root;
  21618. table.val[low] = next - opts.table_index;*/
  21619. table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
  21620. }
  21621. }
  21622. /* fill in remaining table entry if code is incomplete (guaranteed to have
  21623. at most one remaining entry, since if the code is incomplete, the
  21624. maximum code length that was allowed to get this far is one bit) */
  21625. if (huff !== 0) {
  21626. //table.op[next + huff] = 64; /* invalid code marker */
  21627. //table.bits[next + huff] = len - drop;
  21628. //table.val[next + huff] = 0;
  21629. table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
  21630. }
  21631. /* set return parameters */
  21632. //opts.table_index += used;
  21633. opts.bits = root;
  21634. return 0;
  21635. };
  21636. },{"../utils/common":66}],76:[function(require,module,exports){
  21637. 'use strict';
  21638. module.exports = {
  21639. '2': 'need dictionary', /* Z_NEED_DICT 2 */
  21640. '1': 'stream end', /* Z_STREAM_END 1 */
  21641. '0': '', /* Z_OK 0 */
  21642. '-1': 'file error', /* Z_ERRNO (-1) */
  21643. '-2': 'stream error', /* Z_STREAM_ERROR (-2) */
  21644. '-3': 'data error', /* Z_DATA_ERROR (-3) */
  21645. '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */
  21646. '-5': 'buffer error', /* Z_BUF_ERROR (-5) */
  21647. '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
  21648. };
  21649. },{}],77:[function(require,module,exports){
  21650. 'use strict';
  21651. var utils = require('../utils/common');
  21652. /* Public constants ==========================================================*/
  21653. /* ===========================================================================*/
  21654. //var Z_FILTERED = 1;
  21655. //var Z_HUFFMAN_ONLY = 2;
  21656. //var Z_RLE = 3;
  21657. var Z_FIXED = 4;
  21658. //var Z_DEFAULT_STRATEGY = 0;
  21659. /* Possible values of the data_type field (though see inflate()) */
  21660. var Z_BINARY = 0;
  21661. var Z_TEXT = 1;
  21662. //var Z_ASCII = 1; // = Z_TEXT
  21663. var Z_UNKNOWN = 2;
  21664. /*============================================================================*/
  21665. function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
  21666. // From zutil.h
  21667. var STORED_BLOCK = 0;
  21668. var STATIC_TREES = 1;
  21669. var DYN_TREES = 2;
  21670. /* The three kinds of block type */
  21671. var MIN_MATCH = 3;
  21672. var MAX_MATCH = 258;
  21673. /* The minimum and maximum match lengths */
  21674. // From deflate.h
  21675. /* ===========================================================================
  21676. * Internal compression state.
  21677. */
  21678. var LENGTH_CODES = 29;
  21679. /* number of length codes, not counting the special END_BLOCK code */
  21680. var LITERALS = 256;
  21681. /* number of literal bytes 0..255 */
  21682. var L_CODES = LITERALS + 1 + LENGTH_CODES;
  21683. /* number of Literal or Length codes, including the END_BLOCK code */
  21684. var D_CODES = 30;
  21685. /* number of distance codes */
  21686. var BL_CODES = 19;
  21687. /* number of codes used to transfer the bit lengths */
  21688. var HEAP_SIZE = 2*L_CODES + 1;
  21689. /* maximum heap size */
  21690. var MAX_BITS = 15;
  21691. /* All codes must not exceed MAX_BITS bits */
  21692. var Buf_size = 16;
  21693. /* size of bit buffer in bi_buf */
  21694. /* ===========================================================================
  21695. * Constants
  21696. */
  21697. var MAX_BL_BITS = 7;
  21698. /* Bit length codes must not exceed MAX_BL_BITS bits */
  21699. var END_BLOCK = 256;
  21700. /* end of block literal code */
  21701. var REP_3_6 = 16;
  21702. /* repeat previous bit length 3-6 times (2 bits of repeat count) */
  21703. var REPZ_3_10 = 17;
  21704. /* repeat a zero length 3-10 times (3 bits of repeat count) */
  21705. var REPZ_11_138 = 18;
  21706. /* repeat a zero length 11-138 times (7 bits of repeat count) */
  21707. var extra_lbits = /* extra bits for each length code */
  21708. [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];
  21709. var extra_dbits = /* extra bits for each distance code */
  21710. [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];
  21711. var extra_blbits = /* extra bits for each bit length code */
  21712. [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
  21713. var bl_order =
  21714. [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
  21715. /* The lengths of the bit length codes are sent in order of decreasing
  21716. * probability, to avoid transmitting the lengths for unused bit length codes.
  21717. */
  21718. /* ===========================================================================
  21719. * Local data. These are initialized only once.
  21720. */
  21721. // We pre-fill arrays with 0 to avoid uninitialized gaps
  21722. var DIST_CODE_LEN = 512; /* see definition of array dist_code below */
  21723. // !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1
  21724. var static_ltree = new Array((L_CODES+2) * 2);
  21725. zero(static_ltree);
  21726. /* The static literal tree. Since the bit lengths are imposed, there is no
  21727. * need for the L_CODES extra codes used during heap construction. However
  21728. * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
  21729. * below).
  21730. */
  21731. var static_dtree = new Array(D_CODES * 2);
  21732. zero(static_dtree);
  21733. /* The static distance tree. (Actually a trivial tree since all codes use
  21734. * 5 bits.)
  21735. */
  21736. var _dist_code = new Array(DIST_CODE_LEN);
  21737. zero(_dist_code);
  21738. /* Distance codes. The first 256 values correspond to the distances
  21739. * 3 .. 258, the last 256 values correspond to the top 8 bits of
  21740. * the 15 bit distances.
  21741. */
  21742. var _length_code = new Array(MAX_MATCH-MIN_MATCH+1);
  21743. zero(_length_code);
  21744. /* length code for each normalized match length (0 == MIN_MATCH) */
  21745. var base_length = new Array(LENGTH_CODES);
  21746. zero(base_length);
  21747. /* First normalized length for each code (0 = MIN_MATCH) */
  21748. var base_dist = new Array(D_CODES);
  21749. zero(base_dist);
  21750. /* First normalized distance for each code (0 = distance of 1) */
  21751. var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) {
  21752. this.static_tree = static_tree; /* static tree or NULL */
  21753. this.extra_bits = extra_bits; /* extra bits for each code or NULL */
  21754. this.extra_base = extra_base; /* base index for extra_bits */
  21755. this.elems = elems; /* max number of elements in the tree */
  21756. this.max_length = max_length; /* max bit length for the codes */
  21757. // show if `static_tree` has data or dummy - needed for monomorphic objects
  21758. this.has_stree = static_tree && static_tree.length;
  21759. };
  21760. var static_l_desc;
  21761. var static_d_desc;
  21762. var static_bl_desc;
  21763. var TreeDesc = function(dyn_tree, stat_desc) {
  21764. this.dyn_tree = dyn_tree; /* the dynamic tree */
  21765. this.max_code = 0; /* largest code with non zero frequency */
  21766. this.stat_desc = stat_desc; /* the corresponding static tree */
  21767. };
  21768. function d_code(dist) {
  21769. return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
  21770. }
  21771. /* ===========================================================================
  21772. * Output a short LSB first on the stream.
  21773. * IN assertion: there is enough room in pendingBuf.
  21774. */
  21775. function put_short (s, w) {
  21776. // put_byte(s, (uch)((w) & 0xff));
  21777. // put_byte(s, (uch)((ush)(w) >> 8));
  21778. s.pending_buf[s.pending++] = (w) & 0xff;
  21779. s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
  21780. }
  21781. /* ===========================================================================
  21782. * Send a value on a given number of bits.
  21783. * IN assertion: length <= 16 and value fits in length bits.
  21784. */
  21785. function send_bits(s, value, length) {
  21786. if (s.bi_valid > (Buf_size - length)) {
  21787. s.bi_buf |= (value << s.bi_valid) & 0xffff;
  21788. put_short(s, s.bi_buf);
  21789. s.bi_buf = value >> (Buf_size - s.bi_valid);
  21790. s.bi_valid += length - Buf_size;
  21791. } else {
  21792. s.bi_buf |= (value << s.bi_valid) & 0xffff;
  21793. s.bi_valid += length;
  21794. }
  21795. }
  21796. function send_code(s, c, tree) {
  21797. send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/);
  21798. }
  21799. /* ===========================================================================
  21800. * Reverse the first len bits of a code, using straightforward code (a faster
  21801. * method would use a table)
  21802. * IN assertion: 1 <= len <= 15
  21803. */
  21804. function bi_reverse(code, len) {
  21805. var res = 0;
  21806. do {
  21807. res |= code & 1;
  21808. code >>>= 1;
  21809. res <<= 1;
  21810. } while (--len > 0);
  21811. return res >>> 1;
  21812. }
  21813. /* ===========================================================================
  21814. * Flush the bit buffer, keeping at most 7 bits in it.
  21815. */
  21816. function bi_flush(s) {
  21817. if (s.bi_valid === 16) {
  21818. put_short(s, s.bi_buf);
  21819. s.bi_buf = 0;
  21820. s.bi_valid = 0;
  21821. } else if (s.bi_valid >= 8) {
  21822. s.pending_buf[s.pending++] = s.bi_buf & 0xff;
  21823. s.bi_buf >>= 8;
  21824. s.bi_valid -= 8;
  21825. }
  21826. }
  21827. /* ===========================================================================
  21828. * Compute the optimal bit lengths for a tree and update the total bit length
  21829. * for the current block.
  21830. * IN assertion: the fields freq and dad are set, heap[heap_max] and
  21831. * above are the tree nodes sorted by increasing frequency.
  21832. * OUT assertions: the field len is set to the optimal bit length, the
  21833. * array bl_count contains the frequencies for each bit length.
  21834. * The length opt_len is updated; static_len is also updated if stree is
  21835. * not null.
  21836. */
  21837. function gen_bitlen(s, desc)
  21838. // deflate_state *s;
  21839. // tree_desc *desc; /* the tree descriptor */
  21840. {
  21841. var tree = desc.dyn_tree;
  21842. var max_code = desc.max_code;
  21843. var stree = desc.stat_desc.static_tree;
  21844. var has_stree = desc.stat_desc.has_stree;
  21845. var extra = desc.stat_desc.extra_bits;
  21846. var base = desc.stat_desc.extra_base;
  21847. var max_length = desc.stat_desc.max_length;
  21848. var h; /* heap index */
  21849. var n, m; /* iterate over the tree elements */
  21850. var bits; /* bit length */
  21851. var xbits; /* extra bits */
  21852. var f; /* frequency */
  21853. var overflow = 0; /* number of elements with bit length too large */
  21854. for (bits = 0; bits <= MAX_BITS; bits++) {
  21855. s.bl_count[bits] = 0;
  21856. }
  21857. /* In a first pass, compute the optimal bit lengths (which may
  21858. * overflow in the case of the bit length tree).
  21859. */
  21860. tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */
  21861. for (h = s.heap_max+1; h < HEAP_SIZE; h++) {
  21862. n = s.heap[h];
  21863. bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
  21864. if (bits > max_length) {
  21865. bits = max_length;
  21866. overflow++;
  21867. }
  21868. tree[n*2 + 1]/*.Len*/ = bits;
  21869. /* We overwrite tree[n].Dad which is no longer needed */
  21870. if (n > max_code) { continue; } /* not a leaf node */
  21871. s.bl_count[bits]++;
  21872. xbits = 0;
  21873. if (n >= base) {
  21874. xbits = extra[n-base];
  21875. }
  21876. f = tree[n * 2]/*.Freq*/;
  21877. s.opt_len += f * (bits + xbits);
  21878. if (has_stree) {
  21879. s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits);
  21880. }
  21881. }
  21882. if (overflow === 0) { return; }
  21883. // Trace((stderr,"\nbit length overflow\n"));
  21884. /* This happens for example on obj2 and pic of the Calgary corpus */
  21885. /* Find the first bit length which could increase: */
  21886. do {
  21887. bits = max_length-1;
  21888. while (s.bl_count[bits] === 0) { bits--; }
  21889. s.bl_count[bits]--; /* move one leaf down the tree */
  21890. s.bl_count[bits+1] += 2; /* move one overflow item as its brother */
  21891. s.bl_count[max_length]--;
  21892. /* The brother of the overflow item also moves one step up,
  21893. * but this does not affect bl_count[max_length]
  21894. */
  21895. overflow -= 2;
  21896. } while (overflow > 0);
  21897. /* Now recompute all bit lengths, scanning in increasing frequency.
  21898. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
  21899. * lengths instead of fixing only the wrong ones. This idea is taken
  21900. * from 'ar' written by Haruhiko Okumura.)
  21901. */
  21902. for (bits = max_length; bits !== 0; bits--) {
  21903. n = s.bl_count[bits];
  21904. while (n !== 0) {
  21905. m = s.heap[--h];
  21906. if (m > max_code) { continue; }
  21907. if (tree[m*2 + 1]/*.Len*/ !== bits) {
  21908. // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
  21909. s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/;
  21910. tree[m*2 + 1]/*.Len*/ = bits;
  21911. }
  21912. n--;
  21913. }
  21914. }
  21915. }
  21916. /* ===========================================================================
  21917. * Generate the codes for a given tree and bit counts (which need not be
  21918. * optimal).
  21919. * IN assertion: the array bl_count contains the bit length statistics for
  21920. * the given tree and the field len is set for all tree elements.
  21921. * OUT assertion: the field code is set for all tree elements of non
  21922. * zero code length.
  21923. */
  21924. function gen_codes(tree, max_code, bl_count)
  21925. // ct_data *tree; /* the tree to decorate */
  21926. // int max_code; /* largest code with non zero frequency */
  21927. // ushf *bl_count; /* number of codes at each bit length */
  21928. {
  21929. var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */
  21930. var code = 0; /* running code value */
  21931. var bits; /* bit index */
  21932. var n; /* code index */
  21933. /* The distribution counts are first used to generate the code values
  21934. * without bit reversal.
  21935. */
  21936. for (bits = 1; bits <= MAX_BITS; bits++) {
  21937. next_code[bits] = code = (code + bl_count[bits-1]) << 1;
  21938. }
  21939. /* Check that the bit counts in bl_count are consistent. The last code
  21940. * must be all ones.
  21941. */
  21942. //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
  21943. // "inconsistent bit counts");
  21944. //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
  21945. for (n = 0; n <= max_code; n++) {
  21946. var len = tree[n*2 + 1]/*.Len*/;
  21947. if (len === 0) { continue; }
  21948. /* Now reverse the bits */
  21949. tree[n*2]/*.Code*/ = bi_reverse(next_code[len]++, len);
  21950. //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
  21951. // n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
  21952. }
  21953. }
  21954. /* ===========================================================================
  21955. * Initialize the various 'constant' tables.
  21956. */
  21957. function tr_static_init() {
  21958. var n; /* iterates over tree elements */
  21959. var bits; /* bit counter */
  21960. var length; /* length value */
  21961. var code; /* code value */
  21962. var dist; /* distance index */
  21963. var bl_count = new Array(MAX_BITS+1);
  21964. /* number of codes at each bit length for an optimal tree */
  21965. // do check in _tr_init()
  21966. //if (static_init_done) return;
  21967. /* For some embedded targets, global variables are not initialized: */
  21968. /*#ifdef NO_INIT_GLOBAL_POINTERS
  21969. static_l_desc.static_tree = static_ltree;
  21970. static_l_desc.extra_bits = extra_lbits;
  21971. static_d_desc.static_tree = static_dtree;
  21972. static_d_desc.extra_bits = extra_dbits;
  21973. static_bl_desc.extra_bits = extra_blbits;
  21974. #endif*/
  21975. /* Initialize the mapping length (0..255) -> length code (0..28) */
  21976. length = 0;
  21977. for (code = 0; code < LENGTH_CODES-1; code++) {
  21978. base_length[code] = length;
  21979. for (n = 0; n < (1<<extra_lbits[code]); n++) {
  21980. _length_code[length++] = code;
  21981. }
  21982. }
  21983. //Assert (length == 256, "tr_static_init: length != 256");
  21984. /* Note that the length 255 (match length 258) can be represented
  21985. * in two different ways: code 284 + 5 bits or code 285, so we
  21986. * overwrite length_code[255] to use the best encoding:
  21987. */
  21988. _length_code[length-1] = code;
  21989. /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
  21990. dist = 0;
  21991. for (code = 0 ; code < 16; code++) {
  21992. base_dist[code] = dist;
  21993. for (n = 0; n < (1<<extra_dbits[code]); n++) {
  21994. _dist_code[dist++] = code;
  21995. }
  21996. }
  21997. //Assert (dist == 256, "tr_static_init: dist != 256");
  21998. dist >>= 7; /* from now on, all distances are divided by 128 */
  21999. for ( ; code < D_CODES; code++) {
  22000. base_dist[code] = dist << 7;
  22001. for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
  22002. _dist_code[256 + dist++] = code;
  22003. }
  22004. }
  22005. //Assert (dist == 256, "tr_static_init: 256+dist != 512");
  22006. /* Construct the codes of the static literal tree */
  22007. for (bits = 0; bits <= MAX_BITS; bits++) {
  22008. bl_count[bits] = 0;
  22009. }
  22010. n = 0;
  22011. while (n <= 143) {
  22012. static_ltree[n*2 + 1]/*.Len*/ = 8;
  22013. n++;
  22014. bl_count[8]++;
  22015. }
  22016. while (n <= 255) {
  22017. static_ltree[n*2 + 1]/*.Len*/ = 9;
  22018. n++;
  22019. bl_count[9]++;
  22020. }
  22021. while (n <= 279) {
  22022. static_ltree[n*2 + 1]/*.Len*/ = 7;
  22023. n++;
  22024. bl_count[7]++;
  22025. }
  22026. while (n <= 287) {
  22027. static_ltree[n*2 + 1]/*.Len*/ = 8;
  22028. n++;
  22029. bl_count[8]++;
  22030. }
  22031. /* Codes 286 and 287 do not exist, but we must include them in the
  22032. * tree construction to get a canonical Huffman tree (longest code
  22033. * all ones)
  22034. */
  22035. gen_codes(static_ltree, L_CODES+1, bl_count);
  22036. /* The static distance tree is trivial: */
  22037. for (n = 0; n < D_CODES; n++) {
  22038. static_dtree[n*2 + 1]/*.Len*/ = 5;
  22039. static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5);
  22040. }
  22041. // Now data ready and we can init static trees
  22042. static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS);
  22043. static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS);
  22044. static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS);
  22045. //static_init_done = true;
  22046. }
  22047. /* ===========================================================================
  22048. * Initialize a new block.
  22049. */
  22050. function init_block(s) {
  22051. var n; /* iterates over tree elements */
  22052. /* Initialize the trees. */
  22053. for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; }
  22054. for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; }
  22055. for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; }
  22056. s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1;
  22057. s.opt_len = s.static_len = 0;
  22058. s.last_lit = s.matches = 0;
  22059. }
  22060. /* ===========================================================================
  22061. * Flush the bit buffer and align the output on a byte boundary
  22062. */
  22063. function bi_windup(s)
  22064. {
  22065. if (s.bi_valid > 8) {
  22066. put_short(s, s.bi_buf);
  22067. } else if (s.bi_valid > 0) {
  22068. //put_byte(s, (Byte)s->bi_buf);
  22069. s.pending_buf[s.pending++] = s.bi_buf;
  22070. }
  22071. s.bi_buf = 0;
  22072. s.bi_valid = 0;
  22073. }
  22074. /* ===========================================================================
  22075. * Copy a stored block, storing first the length and its
  22076. * one's complement if requested.
  22077. */
  22078. function copy_block(s, buf, len, header)
  22079. //DeflateState *s;
  22080. //charf *buf; /* the input data */
  22081. //unsigned len; /* its length */
  22082. //int header; /* true if block header must be written */
  22083. {
  22084. bi_windup(s); /* align on byte boundary */
  22085. if (header) {
  22086. put_short(s, len);
  22087. put_short(s, ~len);
  22088. }
  22089. // while (len--) {
  22090. // put_byte(s, *buf++);
  22091. // }
  22092. utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);
  22093. s.pending += len;
  22094. }
  22095. /* ===========================================================================
  22096. * Compares to subtrees, using the tree depth as tie breaker when
  22097. * the subtrees have equal frequency. This minimizes the worst case length.
  22098. */
  22099. function smaller(tree, n, m, depth) {
  22100. var _n2 = n*2;
  22101. var _m2 = m*2;
  22102. return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
  22103. (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
  22104. }
  22105. /* ===========================================================================
  22106. * Restore the heap property by moving down the tree starting at node k,
  22107. * exchanging a node with the smallest of its two sons if necessary, stopping
  22108. * when the heap property is re-established (each father smaller than its
  22109. * two sons).
  22110. */
  22111. function pqdownheap(s, tree, k)
  22112. // deflate_state *s;
  22113. // ct_data *tree; /* the tree to restore */
  22114. // int k; /* node to move down */
  22115. {
  22116. var v = s.heap[k];
  22117. var j = k << 1; /* left son of k */
  22118. while (j <= s.heap_len) {
  22119. /* Set j to the smallest of the two sons: */
  22120. if (j < s.heap_len &&
  22121. smaller(tree, s.heap[j+1], s.heap[j], s.depth)) {
  22122. j++;
  22123. }
  22124. /* Exit if v is smaller than both sons */
  22125. if (smaller(tree, v, s.heap[j], s.depth)) { break; }
  22126. /* Exchange v with the smallest son */
  22127. s.heap[k] = s.heap[j];
  22128. k = j;
  22129. /* And continue down the tree, setting j to the left son of k */
  22130. j <<= 1;
  22131. }
  22132. s.heap[k] = v;
  22133. }
  22134. // inlined manually
  22135. // var SMALLEST = 1;
  22136. /* ===========================================================================
  22137. * Send the block data compressed using the given Huffman trees
  22138. */
  22139. function compress_block(s, ltree, dtree)
  22140. // deflate_state *s;
  22141. // const ct_data *ltree; /* literal tree */
  22142. // const ct_data *dtree; /* distance tree */
  22143. {
  22144. var dist; /* distance of matched string */
  22145. var lc; /* match length or unmatched char (if dist == 0) */
  22146. var lx = 0; /* running index in l_buf */
  22147. var code; /* the code to send */
  22148. var extra; /* number of extra bits to send */
  22149. if (s.last_lit !== 0) {
  22150. do {
  22151. dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]);
  22152. lc = s.pending_buf[s.l_buf + lx];
  22153. lx++;
  22154. if (dist === 0) {
  22155. send_code(s, lc, ltree); /* send a literal byte */
  22156. //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
  22157. } else {
  22158. /* Here, lc is the match length - MIN_MATCH */
  22159. code = _length_code[lc];
  22160. send_code(s, code+LITERALS+1, ltree); /* send the length code */
  22161. extra = extra_lbits[code];
  22162. if (extra !== 0) {
  22163. lc -= base_length[code];
  22164. send_bits(s, lc, extra); /* send the extra length bits */
  22165. }
  22166. dist--; /* dist is now the match distance - 1 */
  22167. code = d_code(dist);
  22168. //Assert (code < D_CODES, "bad d_code");
  22169. send_code(s, code, dtree); /* send the distance code */
  22170. extra = extra_dbits[code];
  22171. if (extra !== 0) {
  22172. dist -= base_dist[code];
  22173. send_bits(s, dist, extra); /* send the extra distance bits */
  22174. }
  22175. } /* literal or match pair ? */
  22176. /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
  22177. //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
  22178. // "pendingBuf overflow");
  22179. } while (lx < s.last_lit);
  22180. }
  22181. send_code(s, END_BLOCK, ltree);
  22182. }
  22183. /* ===========================================================================
  22184. * Construct one Huffman tree and assigns the code bit strings and lengths.
  22185. * Update the total bit length for the current block.
  22186. * IN assertion: the field freq is set for all tree elements.
  22187. * OUT assertions: the fields len and code are set to the optimal bit length
  22188. * and corresponding code. The length opt_len is updated; static_len is
  22189. * also updated if stree is not null. The field max_code is set.
  22190. */
  22191. function build_tree(s, desc)
  22192. // deflate_state *s;
  22193. // tree_desc *desc; /* the tree descriptor */
  22194. {
  22195. var tree = desc.dyn_tree;
  22196. var stree = desc.stat_desc.static_tree;
  22197. var has_stree = desc.stat_desc.has_stree;
  22198. var elems = desc.stat_desc.elems;
  22199. var n, m; /* iterate over heap elements */
  22200. var max_code = -1; /* largest code with non zero frequency */
  22201. var node; /* new node being created */
  22202. /* Construct the initial heap, with least frequent element in
  22203. * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
  22204. * heap[0] is not used.
  22205. */
  22206. s.heap_len = 0;
  22207. s.heap_max = HEAP_SIZE;
  22208. for (n = 0; n < elems; n++) {
  22209. if (tree[n * 2]/*.Freq*/ !== 0) {
  22210. s.heap[++s.heap_len] = max_code = n;
  22211. s.depth[n] = 0;
  22212. } else {
  22213. tree[n*2 + 1]/*.Len*/ = 0;
  22214. }
  22215. }
  22216. /* The pkzip format requires that at least one distance code exists,
  22217. * and that at least one bit should be sent even if there is only one
  22218. * possible code. So to avoid special checks later on we force at least
  22219. * two codes of non zero frequency.
  22220. */
  22221. while (s.heap_len < 2) {
  22222. node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
  22223. tree[node * 2]/*.Freq*/ = 1;
  22224. s.depth[node] = 0;
  22225. s.opt_len--;
  22226. if (has_stree) {
  22227. s.static_len -= stree[node*2 + 1]/*.Len*/;
  22228. }
  22229. /* node is 0 or 1 so it does not have extra bits */
  22230. }
  22231. desc.max_code = max_code;
  22232. /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
  22233. * establish sub-heaps of increasing lengths:
  22234. */
  22235. for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
  22236. /* Construct the Huffman tree by repeatedly combining the least two
  22237. * frequent nodes.
  22238. */
  22239. node = elems; /* next internal node of the tree */
  22240. do {
  22241. //pqremove(s, tree, n); /* n = node of least frequency */
  22242. /*** pqremove ***/
  22243. n = s.heap[1/*SMALLEST*/];
  22244. s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
  22245. pqdownheap(s, tree, 1/*SMALLEST*/);
  22246. /***/
  22247. m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
  22248. s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
  22249. s.heap[--s.heap_max] = m;
  22250. /* Create a new node father of n and m */
  22251. tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
  22252. s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
  22253. tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node;
  22254. /* and insert the new node in the heap */
  22255. s.heap[1/*SMALLEST*/] = node++;
  22256. pqdownheap(s, tree, 1/*SMALLEST*/);
  22257. } while (s.heap_len >= 2);
  22258. s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
  22259. /* At this point, the fields freq and dad are set. We can now
  22260. * generate the bit lengths.
  22261. */
  22262. gen_bitlen(s, desc);
  22263. /* The field len is now set, we can generate the bit codes */
  22264. gen_codes(tree, max_code, s.bl_count);
  22265. }
  22266. /* ===========================================================================
  22267. * Scan a literal or distance tree to determine the frequencies of the codes
  22268. * in the bit length tree.
  22269. */
  22270. function scan_tree(s, tree, max_code)
  22271. // deflate_state *s;
  22272. // ct_data *tree; /* the tree to be scanned */
  22273. // int max_code; /* and its largest code of non zero frequency */
  22274. {
  22275. var n; /* iterates over all tree elements */
  22276. var prevlen = -1; /* last emitted length */
  22277. var curlen; /* length of current code */
  22278. var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */
  22279. var count = 0; /* repeat count of the current code */
  22280. var max_count = 7; /* max repeat count */
  22281. var min_count = 4; /* min repeat count */
  22282. if (nextlen === 0) {
  22283. max_count = 138;
  22284. min_count = 3;
  22285. }
  22286. tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */
  22287. for (n = 0; n <= max_code; n++) {
  22288. curlen = nextlen;
  22289. nextlen = tree[(n+1)*2 + 1]/*.Len*/;
  22290. if (++count < max_count && curlen === nextlen) {
  22291. continue;
  22292. } else if (count < min_count) {
  22293. s.bl_tree[curlen * 2]/*.Freq*/ += count;
  22294. } else if (curlen !== 0) {
  22295. if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
  22296. s.bl_tree[REP_3_6*2]/*.Freq*/++;
  22297. } else if (count <= 10) {
  22298. s.bl_tree[REPZ_3_10*2]/*.Freq*/++;
  22299. } else {
  22300. s.bl_tree[REPZ_11_138*2]/*.Freq*/++;
  22301. }
  22302. count = 0;
  22303. prevlen = curlen;
  22304. if (nextlen === 0) {
  22305. max_count = 138;
  22306. min_count = 3;
  22307. } else if (curlen === nextlen) {
  22308. max_count = 6;
  22309. min_count = 3;
  22310. } else {
  22311. max_count = 7;
  22312. min_count = 4;
  22313. }
  22314. }
  22315. }
  22316. /* ===========================================================================
  22317. * Send a literal or distance tree in compressed form, using the codes in
  22318. * bl_tree.
  22319. */
  22320. function send_tree(s, tree, max_code)
  22321. // deflate_state *s;
  22322. // ct_data *tree; /* the tree to be scanned */
  22323. // int max_code; /* and its largest code of non zero frequency */
  22324. {
  22325. var n; /* iterates over all tree elements */
  22326. var prevlen = -1; /* last emitted length */
  22327. var curlen; /* length of current code */
  22328. var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */
  22329. var count = 0; /* repeat count of the current code */
  22330. var max_count = 7; /* max repeat count */
  22331. var min_count = 4; /* min repeat count */
  22332. /* tree[max_code+1].Len = -1; */ /* guard already set */
  22333. if (nextlen === 0) {
  22334. max_count = 138;
  22335. min_count = 3;
  22336. }
  22337. for (n = 0; n <= max_code; n++) {
  22338. curlen = nextlen;
  22339. nextlen = tree[(n+1)*2 + 1]/*.Len*/;
  22340. if (++count < max_count && curlen === nextlen) {
  22341. continue;
  22342. } else if (count < min_count) {
  22343. do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
  22344. } else if (curlen !== 0) {
  22345. if (curlen !== prevlen) {
  22346. send_code(s, curlen, s.bl_tree);
  22347. count--;
  22348. }
  22349. //Assert(count >= 3 && count <= 6, " 3_6?");
  22350. send_code(s, REP_3_6, s.bl_tree);
  22351. send_bits(s, count-3, 2);
  22352. } else if (count <= 10) {
  22353. send_code(s, REPZ_3_10, s.bl_tree);
  22354. send_bits(s, count-3, 3);
  22355. } else {
  22356. send_code(s, REPZ_11_138, s.bl_tree);
  22357. send_bits(s, count-11, 7);
  22358. }
  22359. count = 0;
  22360. prevlen = curlen;
  22361. if (nextlen === 0) {
  22362. max_count = 138;
  22363. min_count = 3;
  22364. } else if (curlen === nextlen) {
  22365. max_count = 6;
  22366. min_count = 3;
  22367. } else {
  22368. max_count = 7;
  22369. min_count = 4;
  22370. }
  22371. }
  22372. }
  22373. /* ===========================================================================
  22374. * Construct the Huffman tree for the bit lengths and return the index in
  22375. * bl_order of the last bit length code to send.
  22376. */
  22377. function build_bl_tree(s) {
  22378. var max_blindex; /* index of last bit length code of non zero freq */
  22379. /* Determine the bit length frequencies for literal and distance trees */
  22380. scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
  22381. scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
  22382. /* Build the bit length tree: */
  22383. build_tree(s, s.bl_desc);
  22384. /* opt_len now includes the length of the tree representations, except
  22385. * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
  22386. */
  22387. /* Determine the number of bit length codes to send. The pkzip format
  22388. * requires that at least 4 bit length codes be sent. (appnote.txt says
  22389. * 3 but the actual value used is 4.)
  22390. */
  22391. for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
  22392. if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) {
  22393. break;
  22394. }
  22395. }
  22396. /* Update opt_len to include the bit length tree and counts */
  22397. s.opt_len += 3*(max_blindex+1) + 5+5+4;
  22398. //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
  22399. // s->opt_len, s->static_len));
  22400. return max_blindex;
  22401. }
  22402. /* ===========================================================================
  22403. * Send the header for a block using dynamic Huffman trees: the counts, the
  22404. * lengths of the bit length codes, the literal tree and the distance tree.
  22405. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
  22406. */
  22407. function send_all_trees(s, lcodes, dcodes, blcodes)
  22408. // deflate_state *s;
  22409. // int lcodes, dcodes, blcodes; /* number of codes for each tree */
  22410. {
  22411. var rank; /* index in bl_order */
  22412. //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
  22413. //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
  22414. // "too many codes");
  22415. //Tracev((stderr, "\nbl counts: "));
  22416. send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
  22417. send_bits(s, dcodes-1, 5);
  22418. send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
  22419. for (rank = 0; rank < blcodes; rank++) {
  22420. //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
  22421. send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3);
  22422. }
  22423. //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
  22424. send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */
  22425. //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
  22426. send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */
  22427. //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
  22428. }
  22429. /* ===========================================================================
  22430. * Check if the data type is TEXT or BINARY, using the following algorithm:
  22431. * - TEXT if the two conditions below are satisfied:
  22432. * a) There are no non-portable control characters belonging to the
  22433. * "black list" (0..6, 14..25, 28..31).
  22434. * b) There is at least one printable character belonging to the
  22435. * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
  22436. * - BINARY otherwise.
  22437. * - The following partially-portable control characters form a
  22438. * "gray list" that is ignored in this detection algorithm:
  22439. * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
  22440. * IN assertion: the fields Freq of dyn_ltree are set.
  22441. */
  22442. function detect_data_type(s) {
  22443. /* black_mask is the bit mask of black-listed bytes
  22444. * set bits 0..6, 14..25, and 28..31
  22445. * 0xf3ffc07f = binary 11110011111111111100000001111111
  22446. */
  22447. var black_mask = 0xf3ffc07f;
  22448. var n;
  22449. /* Check for non-textual ("black-listed") bytes. */
  22450. for (n = 0; n <= 31; n++, black_mask >>>= 1) {
  22451. if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) {
  22452. return Z_BINARY;
  22453. }
  22454. }
  22455. /* Check for textual ("white-listed") bytes. */
  22456. if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
  22457. s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
  22458. return Z_TEXT;
  22459. }
  22460. for (n = 32; n < LITERALS; n++) {
  22461. if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
  22462. return Z_TEXT;
  22463. }
  22464. }
  22465. /* There are no "black-listed" or "white-listed" bytes:
  22466. * this stream either is empty or has tolerated ("gray-listed") bytes only.
  22467. */
  22468. return Z_BINARY;
  22469. }
  22470. var static_init_done = false;
  22471. /* ===========================================================================
  22472. * Initialize the tree data structures for a new zlib stream.
  22473. */
  22474. function _tr_init(s)
  22475. {
  22476. if (!static_init_done) {
  22477. tr_static_init();
  22478. static_init_done = true;
  22479. }
  22480. s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc);
  22481. s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc);
  22482. s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
  22483. s.bi_buf = 0;
  22484. s.bi_valid = 0;
  22485. /* Initialize the first block of the first file: */
  22486. init_block(s);
  22487. }
  22488. /* ===========================================================================
  22489. * Send a stored block
  22490. */
  22491. function _tr_stored_block(s, buf, stored_len, last)
  22492. //DeflateState *s;
  22493. //charf *buf; /* input block */
  22494. //ulg stored_len; /* length of input block */
  22495. //int last; /* one if this is the last block for a file */
  22496. {
  22497. send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3); /* send block type */
  22498. copy_block(s, buf, stored_len, true); /* with header */
  22499. }
  22500. /* ===========================================================================
  22501. * Send one empty static block to give enough lookahead for inflate.
  22502. * This takes 10 bits, of which 7 may remain in the bit buffer.
  22503. */
  22504. function _tr_align(s) {
  22505. send_bits(s, STATIC_TREES<<1, 3);
  22506. send_code(s, END_BLOCK, static_ltree);
  22507. bi_flush(s);
  22508. }
  22509. /* ===========================================================================
  22510. * Determine the best encoding for the current block: dynamic trees, static
  22511. * trees or store, and output the encoded block to the zip file.
  22512. */
  22513. function _tr_flush_block(s, buf, stored_len, last)
  22514. //DeflateState *s;
  22515. //charf *buf; /* input block, or NULL if too old */
  22516. //ulg stored_len; /* length of input block */
  22517. //int last; /* one if this is the last block for a file */
  22518. {
  22519. var opt_lenb, static_lenb; /* opt_len and static_len in bytes */
  22520. var max_blindex = 0; /* index of last bit length code of non zero freq */
  22521. /* Build the Huffman trees unless a stored block is forced */
  22522. if (s.level > 0) {
  22523. /* Check if the file is binary or text */
  22524. if (s.strm.data_type === Z_UNKNOWN) {
  22525. s.strm.data_type = detect_data_type(s);
  22526. }
  22527. /* Construct the literal and distance trees */
  22528. build_tree(s, s.l_desc);
  22529. // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
  22530. // s->static_len));
  22531. build_tree(s, s.d_desc);
  22532. // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
  22533. // s->static_len));
  22534. /* At this point, opt_len and static_len are the total bit lengths of
  22535. * the compressed block data, excluding the tree representations.
  22536. */
  22537. /* Build the bit length tree for the above two trees, and get the index
  22538. * in bl_order of the last bit length code to send.
  22539. */
  22540. max_blindex = build_bl_tree(s);
  22541. /* Determine the best encoding. Compute the block lengths in bytes. */
  22542. opt_lenb = (s.opt_len+3+7) >>> 3;
  22543. static_lenb = (s.static_len+3+7) >>> 3;
  22544. // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
  22545. // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
  22546. // s->last_lit));
  22547. if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
  22548. } else {
  22549. // Assert(buf != (char*)0, "lost buf");
  22550. opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
  22551. }
  22552. if ((stored_len+4 <= opt_lenb) && (buf !== -1)) {
  22553. /* 4: two words for the lengths */
  22554. /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
  22555. * Otherwise we can't have processed more than WSIZE input bytes since
  22556. * the last block flush, because compression would have been
  22557. * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
  22558. * transform a block into a stored block.
  22559. */
  22560. _tr_stored_block(s, buf, stored_len, last);
  22561. } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {
  22562. send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3);
  22563. compress_block(s, static_ltree, static_dtree);
  22564. } else {
  22565. send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3);
  22566. send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1);
  22567. compress_block(s, s.dyn_ltree, s.dyn_dtree);
  22568. }
  22569. // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
  22570. /* The above check is made mod 2^32, for files larger than 512 MB
  22571. * and uLong implemented on 32 bits.
  22572. */
  22573. init_block(s);
  22574. if (last) {
  22575. bi_windup(s);
  22576. }
  22577. // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
  22578. // s->compressed_len-7*last));
  22579. }
  22580. /* ===========================================================================
  22581. * Save the match info and tally the frequency counts. Return true if
  22582. * the current block must be flushed.
  22583. */
  22584. function _tr_tally(s, dist, lc)
  22585. // deflate_state *s;
  22586. // unsigned dist; /* distance of matched string */
  22587. // unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
  22588. {
  22589. //var out_length, in_length, dcode;
  22590. s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff;
  22591. s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;
  22592. s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
  22593. s.last_lit++;
  22594. if (dist === 0) {
  22595. /* lc is the unmatched char */
  22596. s.dyn_ltree[lc*2]/*.Freq*/++;
  22597. } else {
  22598. s.matches++;
  22599. /* Here, lc is the match length - MIN_MATCH */
  22600. dist--; /* dist = match distance - 1 */
  22601. //Assert((ush)dist < (ush)MAX_DIST(s) &&
  22602. // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
  22603. // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
  22604. s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++;
  22605. s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
  22606. }
  22607. // (!) This block is disabled in zlib defailts,
  22608. // don't enable it for binary compatibility
  22609. //#ifdef TRUNCATE_BLOCK
  22610. // /* Try to guess if it is profitable to stop the current block here */
  22611. // if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
  22612. // /* Compute an upper bound for the compressed length */
  22613. // out_length = s.last_lit*8;
  22614. // in_length = s.strstart - s.block_start;
  22615. //
  22616. // for (dcode = 0; dcode < D_CODES; dcode++) {
  22617. // out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
  22618. // }
  22619. // out_length >>>= 3;
  22620. // //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
  22621. // // s->last_lit, in_length, out_length,
  22622. // // 100L - out_length*100L/in_length));
  22623. // if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
  22624. // return true;
  22625. // }
  22626. // }
  22627. //#endif
  22628. return (s.last_lit === s.lit_bufsize-1);
  22629. /* We avoid equality with lit_bufsize because of wraparound at 64K
  22630. * on 16 bit machines and because stored blocks are restricted to
  22631. * 64K-1 bytes.
  22632. */
  22633. }
  22634. exports._tr_init = _tr_init;
  22635. exports._tr_stored_block = _tr_stored_block;
  22636. exports._tr_flush_block = _tr_flush_block;
  22637. exports._tr_tally = _tr_tally;
  22638. exports._tr_align = _tr_align;
  22639. },{"../utils/common":66}],78:[function(require,module,exports){
  22640. 'use strict';
  22641. function ZStream() {
  22642. /* next input byte */
  22643. this.input = null; // JS specific, because we have no pointers
  22644. this.next_in = 0;
  22645. /* number of bytes available at input */
  22646. this.avail_in = 0;
  22647. /* total number of input bytes read so far */
  22648. this.total_in = 0;
  22649. /* next output byte should be put there */
  22650. this.output = null; // JS specific, because we have no pointers
  22651. this.next_out = 0;
  22652. /* remaining free space at output */
  22653. this.avail_out = 0;
  22654. /* total number of bytes output so far */
  22655. this.total_out = 0;
  22656. /* last error message, NULL if no error */
  22657. this.msg = ''/*Z_NULL*/;
  22658. /* not visible by applications */
  22659. this.state = null;
  22660. /* best guess about the data type: binary or text */
  22661. this.data_type = 2/*Z_UNKNOWN*/;
  22662. /* adler32 value of the uncompressed data */
  22663. this.adler = 0;
  22664. }
  22665. module.exports = ZStream;
  22666. },{}],79:[function(require,module,exports){
  22667. module.exports = function arrayEquals(array) {
  22668. // if the other array is a falsy value, return
  22669. if (!array)
  22670. return false;
  22671. // compare lengths - can save a lot of time
  22672. if (this.length != array.length)
  22673. return false;
  22674. for (var i = 0, l = this.length; i < l; i++) {
  22675. // Check if we have nested arrays
  22676. if (this[i] instanceof Array && array[i] instanceof Array) {
  22677. // recurse into the nested arrays
  22678. if (!arrayEquals.apply(this[i], [array[i]]))
  22679. return false;
  22680. } else if (this[i] != array[i]) {
  22681. // Warning - two different object instances will never be equal:
  22682. // {x:20} != {x:20}
  22683. return false;
  22684. }
  22685. }
  22686. return true;
  22687. }
  22688. },{}],80:[function(require,module,exports){
  22689. exports.Interop = require('./interop');
  22690. },{"./interop":81}],81:[function(require,module,exports){
  22691. var transform = require('./transform');
  22692. var arrayEquals = require('./array-equals');
  22693. function Interop() { }
  22694. module.exports = Interop;
  22695. /**
  22696. * This map holds the most recent Plan A offer/answer SDP that was converted
  22697. * to Plan B, with the SDP type ('offer' or 'answer') as keys and the SDP
  22698. * string as values.
  22699. *
  22700. * @type {{}}
  22701. */
  22702. var cache = {};
  22703. /**
  22704. * This method transforms a Plan A SDP to an equivalent Plan B SDP. A
  22705. * PeerConnection wrapper transforms the SDP to Plan B before passing it to the
  22706. * application.
  22707. *
  22708. * @param desc
  22709. * @returns {*}
  22710. */
  22711. Interop.prototype.toPlanB = function(desc) {
  22712. //#region Preliminary input validation.
  22713. if (typeof desc !== 'object' || desc === null ||
  22714. typeof desc.sdp !== 'string') {
  22715. console.warn('An empty description was passed as an argument.');
  22716. return desc;
  22717. }
  22718. // Objectify the SDP for easier manipulation.
  22719. var session = transform.parse(desc.sdp);
  22720. // If the SDP contains no media, there's nothing to transform.
  22721. if (typeof session.media === 'undefined' ||
  22722. !Array.isArray(session.media) || session.media.length === 0) {
  22723. console.warn('The description has no media.');
  22724. return desc;
  22725. }
  22726. // Try some heuristics to "make sure" this is a Plan A SDP. Plan B SDP has
  22727. // a video, an audio and a data "channel" at most.
  22728. if (session.media.length <= 3 && session.media.every(function(m) {
  22729. return ['video', 'audio', 'data'].indexOf(m.mid) !== -1;
  22730. })) {
  22731. console.warn('This description does not look like Plan A.');
  22732. return desc;
  22733. }
  22734. //#endregion
  22735. // Plan A SDP is our "precious". Cache it for later use in the Plan B ->
  22736. // Plan A transformation.
  22737. cache[desc.type] = desc.sdp;
  22738. //#region Convert from Plan A to Plan B.
  22739. // We rebuild the session.media array.
  22740. var media = session.media;
  22741. session.media = [];
  22742. // Associative array that maps channel types to channel objects for fast
  22743. // access to channel objects by their type, e.g. channels['audio']->channel
  22744. // obj.
  22745. var channels = {};
  22746. // Used to build the group:BUNDLE value after the channels construction
  22747. // loop.
  22748. var types = [];
  22749. // Implode the Plan A m-lines/tracks into Plan B "channels".
  22750. media.forEach(function(mLine) {
  22751. // rtcp-mux is required in the Plan B SDP.
  22752. if (typeof mLine.rtcpMux !== 'string' ||
  22753. mLine.rtcpMux !== 'rtcp-mux') {
  22754. throw new Error('Cannot convert to Plan B because m-lines ' +
  22755. 'without the rtcp-mux attribute were found.');
  22756. }
  22757. // If we don't have a channel for this mLine.type, then use this mLine
  22758. // as the channel basis.
  22759. if (typeof channels[mLine.type] === 'undefined') {
  22760. channels[mLine.type] = mLine;
  22761. }
  22762. // Add sources to the channel and handle a=msid.
  22763. if (typeof mLine.sources === 'object') {
  22764. Object.keys(mLine.sources).forEach(function(ssrc) {
  22765. // Assign the sources to the channel.
  22766. channels[mLine.type].sources[ssrc] = mLine.sources[ssrc];
  22767. // In Plan B the msid is an SSRC attribute. Also, we don't care
  22768. // about the obsolete label and mslabel attributes.
  22769. channels[mLine.type].sources[ssrc].msid = mLine.msid;
  22770. // NOTE ssrcs in ssrc groups will share msids, as
  22771. // draft-uberti-rtcweb-plan-00 mandates.
  22772. });
  22773. }
  22774. // Add ssrc groups to the channel.
  22775. if (typeof mLine.ssrcGroups !== 'undefined' &&
  22776. Array.isArray(mLine.ssrcGroups)) {
  22777. // Create the ssrcGroups array, if it's not defined.
  22778. if (typeof channel.ssrcGroups === 'undefined' ||
  22779. !Array.isArray(channel.ssrcGroups)) {
  22780. channel.ssrcGroups = [];
  22781. }
  22782. channel.ssrcGroups = channel.ssrcGroups.concat(mLine.ssrcGroups);
  22783. }
  22784. if (channels[mLine.type] === mLine) {
  22785. // Copy ICE related stuff from the principal media line.
  22786. mLine.candidates = media[0].candidates;
  22787. mLine.iceUfrag = media[0].iceUfrag;
  22788. mLine.icePwd = media[0].icePwd;
  22789. mLine.fingerprint = media[0].fingerprint;
  22790. // Plan B mids are in ['audio', 'video', 'data']
  22791. mLine.mid = mLine.type;
  22792. // Plan B doesn't support/need the bundle-only attribute.
  22793. delete mLine.bundleOnly;
  22794. // In Plan B the msid is an SSRC attribute.
  22795. delete mLine.msid;
  22796. // Used to build the group:BUNDLE value after this loop.
  22797. types.push(mLine.type);
  22798. // Add the channel to the new media array.
  22799. session.media.push(mLine);
  22800. }
  22801. });
  22802. // We regenerate the BUNDLE group with the new mids.
  22803. session.groups.every(function(group) {
  22804. if (group.type === 'BUNDLE') {
  22805. group.mids = types.join(' ');
  22806. return false;
  22807. } else {
  22808. return true;
  22809. }
  22810. });
  22811. // msid semantic
  22812. session.msidSemantic = {
  22813. semantic: 'WMS',
  22814. token: '*'
  22815. };
  22816. var resStr = transform.write(session);
  22817. return new RTCSessionDescription({
  22818. type: desc.type,
  22819. sdp: resStr
  22820. });
  22821. //#endregion
  22822. };
  22823. /**
  22824. * This method transforms a Plan B SDP to an equivalent Plan A SDP. A
  22825. * PeerConnection wrapper transforms the SDP to Plan A before passing it to FF.
  22826. *
  22827. * @param desc
  22828. * @returns {*}
  22829. */
  22830. Interop.prototype.toPlanA = function(desc) {
  22831. //#region Preliminary input validation.
  22832. if (typeof desc !== 'object' || desc === null ||
  22833. typeof desc.sdp !== 'string') {
  22834. console.warn('An empty description was passed as an argument.');
  22835. return desc;
  22836. }
  22837. var session = transform.parse(desc.sdp);
  22838. // If the SDP contains no media, there's nothing to transform.
  22839. if (typeof session.media === 'undefined' ||
  22840. !Array.isArray(session.media) || session.media.length === 0) {
  22841. console.warn('The description has no media.');
  22842. return desc;
  22843. }
  22844. // Try some heuristics to "make sure" this is a Plan B SDP. Plan B SDP has
  22845. // a video, an audio and a data "channel" at most.
  22846. if (session.media.length > 3 || !session.media.every(function(m) {
  22847. return ['video', 'audio', 'data'].indexOf(m.mid) !== -1;
  22848. })) {
  22849. console.warn('This description does not look like Plan B.');
  22850. return desc;
  22851. }
  22852. // Make sure this Plan B SDP can be converted to a Plan A SDP.
  22853. var mids = [];
  22854. session.media.forEach(function(m) {
  22855. mids.push(m.mid);
  22856. });
  22857. var hasBundle = false;
  22858. if (typeof session.groups !== 'undefined' &&
  22859. Array.isArray(session.groups)) {
  22860. hasBundle = session.groups.every(function(g) {
  22861. return g.type !== 'BUNDLE' ||
  22862. arrayEquals.apply(g.mids.sort(), [mids.sort()]);
  22863. });
  22864. }
  22865. if (!hasBundle) {
  22866. throw new Error("Cannot convert to Plan A because m-lines that are " +
  22867. "not bundled were found.");
  22868. }
  22869. //#endregion
  22870. //#region Convert from Plan B to Plan A.
  22871. // Unfortunately, a Plan B offer/answer doesn't have enough information to
  22872. // rebuild an equivalent Plan A offer/answer.
  22873. //
  22874. // For example, if this is a local answer (in Plan A style) that we convert
  22875. // to Plan B prior to handing it over to the application (the
  22876. // PeerConnection wrapper called us, for instance, after a successful
  22877. // createAnswer), we want to remember the m-line at which we've seen the
  22878. // (local) SSRC. That's because when the application wants to do call the
  22879. // SLD method, forcing us to do the inverse transformation (from Plan B to
  22880. // Plan A), we need to know to which m-line to assign the (local) SSRC. We
  22881. // also need to know all the other m-lines that the original answer had and
  22882. // include them in the transformed answer as well.
  22883. //
  22884. // Another example is if this is a remote offer that we convert to Plan B
  22885. // prior to giving it to the application, we want to remember the mid at
  22886. // which we've seen the (remote) SSRC.
  22887. //
  22888. // In the iteration that follows, we use the cached Plan A (if it exists)
  22889. // to assign mids to ssrcs.
  22890. var cached;
  22891. if (typeof cache[desc.type] !== 'undefined') {
  22892. cached = transform.parse(cache[desc.type]);
  22893. }
  22894. // A helper map that sends mids to m-line objects. We use it later to
  22895. // rebuild the Plan A style session.media array.
  22896. var media = {};
  22897. session.media.forEach(function(channel) {
  22898. if (typeof channel.rtcpMux !== 'string' ||
  22899. channel.rtcpMux !== 'rtcp-mux') {
  22900. throw new Error("Cannot convert to Plan A because m-lines " +
  22901. "without the rtcp-mux attribute were found.");
  22902. }
  22903. // With rtcp-mux and bundle all the channels should have the same ICE
  22904. // stuff.
  22905. var sources = channel.sources;
  22906. var ssrcGroups = channel.ssrcGroups;
  22907. var candidates = channel.candidates;
  22908. var iceUfrag = channel.iceUfrag;
  22909. var icePwd = channel.icePwd;
  22910. var fingerprint = channel.fingerprint;
  22911. var port = channel.port;
  22912. // We'll use the "channel" object as a prototype for each new "mLine"
  22913. // that we create, but first we need to clean it up a bit.
  22914. delete channel.sources;
  22915. delete channel.ssrcGroups;
  22916. delete channel.candidates;
  22917. delete channel.iceUfrag;
  22918. delete channel.icePwd;
  22919. delete channel.fingerprint;
  22920. delete channel.port;
  22921. delete channel.mid;
  22922. // inverted ssrc group map
  22923. var invertedGroups = {};
  22924. if (typeof ssrcGroups !== 'undefined' && Array.isArray(ssrcGroups)) {
  22925. ssrcGroups.forEach(function (ssrcGroup) {
  22926. // TODO(gp) find out how to receive simulcast with FF. For the
  22927. // time being, hide it.
  22928. if (ssrcGroup.semantics === 'SIM') {
  22929. return;
  22930. }
  22931. if (typeof ssrcGroup.ssrcs !== 'undefined' &&
  22932. Array.isArray(ssrcGroup.ssrcs)) {
  22933. ssrcGroup.ssrcs.forEach(function (ssrc) {
  22934. if (typeof invertedGroups[ssrc] === 'undefined') {
  22935. invertedGroups[ssrc] = [];
  22936. }
  22937. invertedGroups[ssrc].push(ssrcGroup);
  22938. });
  22939. }
  22940. });
  22941. }
  22942. // ssrc to m-line index.
  22943. var mLines = {};
  22944. if (typeof sources === 'object') {
  22945. // Explode the Plan B channel sources with one m-line per source.
  22946. Object.keys(sources).forEach(function(ssrc) {
  22947. var mLine;
  22948. if (typeof invertedGroups[ssrc] !== 'undefined' &&
  22949. Array.isArray(invertedGroups[ssrc])) {
  22950. invertedGroups[ssrc].every(function (ssrcGroup) {
  22951. // ssrcGroup.ssrcs *is* an Array, no need to check
  22952. // again here.
  22953. return ssrcGroup.ssrcs.every(function (related) {
  22954. if (typeof mLines[related] === 'object') {
  22955. mLine = mLines[related];
  22956. return false;
  22957. } else {
  22958. return true;
  22959. }
  22960. });
  22961. });
  22962. }
  22963. if (typeof mLine === 'object') {
  22964. // the m-line already exists. Just add the source.
  22965. mLine.sources[ssrc] = sources[ssrc];
  22966. delete sources[ssrc].msid;
  22967. } else {
  22968. // Use the "channel" as a prototype for the "mLine".
  22969. mLine = Object.create(channel);
  22970. mLines[ssrc] = mLine;
  22971. // Assign the msid of the source to the m-line.
  22972. mLine.msid = sources[ssrc].msid;
  22973. delete sources[ssrc].msid;
  22974. // We assign one SSRC per media line.
  22975. mLine.sources = {};
  22976. mLine.sources[ssrc] = sources[ssrc];
  22977. mLine.ssrcGroups = invertedGroups[ssrc];
  22978. // Use the cached Plan A SDP (if it exists) to assign SSRCs to
  22979. // mids.
  22980. if (typeof cached !== 'undefined' &&
  22981. typeof cached.media !== 'undefined' &&
  22982. Array.isArray(cached.media)) {
  22983. cached.media.forEach(function(m) {
  22984. if (typeof m.sources === 'object') {
  22985. Object.keys(m.sources).forEach(function(s) {
  22986. if (s === ssrc) {
  22987. mLine.mid = m.mid;
  22988. }
  22989. });
  22990. }
  22991. });
  22992. }
  22993. if (typeof mLine.mid === 'undefined') {
  22994. // If this is an SSRC that we see for the first time assign
  22995. // it a new mid. This is typically the case when this
  22996. // method is called to transform a remote description for
  22997. // the first time or when there is a new SSRC in the remote
  22998. // description because a new peer has joined the
  22999. // conference. Local SSRCs should have already been added
  23000. // to the map in the toPlanB method.
  23001. //
  23002. // Because FF generates answers in Plan A style, we MUST
  23003. // already have a cached answer with all the local SSRCs
  23004. // mapped to some mLine/mid.
  23005. if (desc.type === 'answer') {
  23006. throw new Error("An unmapped SSRC was found.");
  23007. }
  23008. mLine.mid = [channel.type, '-', ssrc].join('');
  23009. }
  23010. // Include the candidates in the 1st media line.
  23011. mLine.candidates = candidates;
  23012. mLine.iceUfrag = iceUfrag;
  23013. mLine.icePwd = icePwd;
  23014. mLine.fingerprint = fingerprint;
  23015. mLine.port = port;
  23016. media[mLine.mid] = mLine;
  23017. }
  23018. });
  23019. }
  23020. });
  23021. // Rebuild the media array in the right order and add the missing mLines
  23022. // (missing from the Plan B SDP).
  23023. session.media = [];
  23024. mids = []; // reuse
  23025. if (desc.type === 'answer') {
  23026. // The media lines in the answer must match the media lines in the
  23027. // offer. The order is important too. Here we use the cached offer to
  23028. // find the m-lines that are missing (from the converted answer), and
  23029. // use the cached answer to complete the converted answer.
  23030. if (typeof cache['offer'] === 'undefined') {
  23031. throw new Error("An answer is being processed but we couldn't " +
  23032. "find a cached offer.");
  23033. }
  23034. var cachedOffer = transform.parse(cache['offer']);
  23035. if (typeof cachedOffer === 'undefined' ||
  23036. typeof cachedOffer.media === 'undefined' ||
  23037. !Array.isArray(cachedOffer.media)) {
  23038. // FIXME(gp) is this really a problem in the general case?
  23039. throw new Error("The cached offer has no media.");
  23040. }
  23041. cachedOffer.media.forEach(function(mo) {
  23042. var mLine;
  23043. if (typeof media[mo.mid] === 'undefined') {
  23044. // This is probably an m-line containing a remote track only.
  23045. // It MUST exist in the cached answer as a remote track only
  23046. // mLine.
  23047. cached.media.every(function(ma) {
  23048. if (mo.mid == ma.mid) {
  23049. mLine = ma;
  23050. return false;
  23051. } else {
  23052. return true;
  23053. }
  23054. });
  23055. } else {
  23056. mLine = media[mo.mid];
  23057. }
  23058. if (typeof mLine === 'undefined') {
  23059. throw new Error("The cached offer contains an m-line that " +
  23060. "doesn't exist neither in the cached answer nor in " +
  23061. "the converted answer.");
  23062. }
  23063. session.media.push(mLine);
  23064. mids.push(mLine.mid);
  23065. });
  23066. } else {
  23067. // SDP offer/answer (and the JSEP spec) forbids removing an m-section
  23068. // under any circumstances. If we are no longer interested in sending a
  23069. // track, we just remove the msid and ssrc attributes and set it to
  23070. // either a=recvonly (as the reofferer, we must use recvonly if the
  23071. // other side was previously sending on the m-section, but we can also
  23072. // leave the possibility open if it wasn't previously in use), or
  23073. // a=inacive.
  23074. if (typeof cached !== 'undefined' &&
  23075. typeof cached.media !== 'undefined' &&
  23076. Array.isArray(cached.media)) {
  23077. cached.media.forEach(function(pm) {
  23078. mids.push(pm.mid);
  23079. if (typeof media[pm.mid] !== 'undefined') {
  23080. session.media.push(media[pm.mid]);
  23081. } else {
  23082. delete pm.msid;
  23083. delete pm.sources;
  23084. delete pm.ssrcGroups;
  23085. pm.direction = 'recvonly';
  23086. session.media.push(pm);
  23087. }
  23088. });
  23089. }
  23090. // Add all the remaining (new) m-lines of the transformed SDP.
  23091. Object.keys(media).forEach(function(mid) {
  23092. if (mids.indexOf(mid) === -1) {
  23093. mids.push(mid);
  23094. session.media.push(media[mid]);
  23095. }
  23096. });
  23097. }
  23098. // We regenerate the BUNDLE group (since we regenerated the mids)
  23099. session.groups.every(function(group) {
  23100. if (group.type === 'BUNDLE') {
  23101. group.mids = mids.join(' ');
  23102. return false;
  23103. } else {
  23104. return true;
  23105. }
  23106. });
  23107. // msid semantic
  23108. session.msidSemantic = {
  23109. semantic: 'WMS',
  23110. token: '*'
  23111. };
  23112. var resStr = transform.write(session);
  23113. // Cache the transformed SDP (Plan A) for later re-use in this function.
  23114. cache[desc.type] = resStr;
  23115. return new RTCSessionDescription({
  23116. type: desc.type,
  23117. sdp: resStr
  23118. });
  23119. //#endregion
  23120. };
  23121. },{"./array-equals":79,"./transform":82}],82:[function(require,module,exports){
  23122. var transform = require('sdp-transform');
  23123. exports.write = function(session, opts) {
  23124. if (typeof session !== 'undefined' &&
  23125. typeof session.media !== 'undefined' &&
  23126. Array.isArray(session.media)) {
  23127. session.media.forEach(function (mLine) {
  23128. // expand sources to ssrcs
  23129. if (typeof mLine.sources !== 'undefined' &&
  23130. Object.keys(mLine.sources).length !== 0) {
  23131. mLine.ssrcs = [];
  23132. Object.keys(mLine.sources).forEach(function (ssrc) {
  23133. var source = mLine.sources[ssrc];
  23134. Object.keys(source).forEach(function (attribute) {
  23135. mLine.ssrcs.push({
  23136. id: ssrc,
  23137. attribute: attribute,
  23138. value: source[attribute]
  23139. });
  23140. });
  23141. });
  23142. delete mLine.sources;
  23143. }
  23144. // join ssrcs in ssrc groups
  23145. if (typeof mLine.ssrcGroups !== 'undefined' &&
  23146. Array.isArray(mLine.ssrcGroups)) {
  23147. mLine.ssrcGroups.forEach(function (ssrcGroup) {
  23148. if (typeof ssrcGroup.ssrcs !== 'undefined' &&
  23149. Array.isArray(ssrcGroup.ssrcs)) {
  23150. ssrcGroup.ssrcs = ssrcGroup.ssrcs.join(' ');
  23151. }
  23152. });
  23153. }
  23154. });
  23155. }
  23156. // join group mids
  23157. if (typeof session !== 'undefined' &&
  23158. typeof session.groups !== 'undefined' && Array.isArray(session.groups)) {
  23159. session.groups.forEach(function (g) {
  23160. if (typeof g.mids !== 'undefined' && Array.isArray(g.mids)) {
  23161. g.mids = g.mids.join(' ');
  23162. }
  23163. });
  23164. }
  23165. return transform.write(session, opts);
  23166. };
  23167. exports.parse = function(sdp) {
  23168. var session = transform.parse(sdp);
  23169. if (typeof session !== 'undefined' && typeof session.media !== 'undefined' &&
  23170. Array.isArray(session.media)) {
  23171. session.media.forEach(function (mLine) {
  23172. // group sources attributes by ssrc
  23173. if (typeof mLine.ssrcs !== 'undefined' && Array.isArray(mLine.ssrcs)) {
  23174. mLine.sources = {};
  23175. mLine.ssrcs.forEach(function (ssrc) {
  23176. if (!mLine.sources[ssrc.id])
  23177. mLine.sources[ssrc.id] = {};
  23178. mLine.sources[ssrc.id][ssrc.attribute] = ssrc.value;
  23179. });
  23180. delete mLine.ssrcs;
  23181. }
  23182. // split ssrcs in ssrc groups
  23183. if (typeof mLine.ssrcGroups !== 'undefined' &&
  23184. Array.isArray(mLine.ssrcGroups)) {
  23185. mLine.ssrcGroups.forEach(function (ssrcGroup) {
  23186. if (typeof ssrcGroup.ssrcs === 'string') {
  23187. ssrcGroup.ssrcs = ssrcGroup.ssrcs.split(' ');
  23188. }
  23189. });
  23190. }
  23191. });
  23192. }
  23193. // split group mids
  23194. if (typeof session !== 'undefined' &&
  23195. typeof session.groups !== 'undefined' && Array.isArray(session.groups)) {
  23196. session.groups.forEach(function (g) {
  23197. if (typeof g.mids === 'string') {
  23198. g.mids = g.mids.split(' ');
  23199. }
  23200. });
  23201. }
  23202. return session;
  23203. };
  23204. },{"sdp-transform":84}],83:[function(require,module,exports){
  23205. var grammar = module.exports = {
  23206. v: [{
  23207. name: 'version',
  23208. reg: /^(\d*)$/
  23209. }],
  23210. o: [{ //o=- 20518 0 IN IP4 203.0.113.1
  23211. // NB: sessionId will be a String in most cases because it is huge
  23212. name: 'origin',
  23213. reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
  23214. names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
  23215. format: "%s %s %d %s IP%d %s"
  23216. }],
  23217. // default parsing of these only (though some of these feel outdated)
  23218. s: [{ name: 'name' }],
  23219. i: [{ name: 'description' }],
  23220. u: [{ name: 'uri' }],
  23221. e: [{ name: 'email' }],
  23222. p: [{ name: 'phone' }],
  23223. z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
  23224. r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
  23225. //k: [{}], // outdated thing ignored
  23226. t: [{ //t=0 0
  23227. name: 'timing',
  23228. reg: /^(\d*) (\d*)/,
  23229. names: ['start', 'stop'],
  23230. format: "%d %d"
  23231. }],
  23232. c: [{ //c=IN IP4 10.47.197.26
  23233. name: 'connection',
  23234. reg: /^IN IP(\d) (\S*)/,
  23235. names: ['version', 'ip'],
  23236. format: "IN IP%d %s"
  23237. }],
  23238. b: [{ //b=AS:4000
  23239. push: 'bandwidth',
  23240. reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
  23241. names: ['type', 'limit'],
  23242. format: "%s:%s"
  23243. }],
  23244. m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
  23245. // NB: special - pushes to session
  23246. // TODO: rtp/fmtp should be filtered by the payloads found here?
  23247. reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
  23248. names: ['type', 'port', 'protocol', 'payloads'],
  23249. format: "%s %d %s %s"
  23250. }],
  23251. a: [
  23252. { //a=rtpmap:110 opus/48000/2
  23253. push: 'rtp',
  23254. reg: /^rtpmap:(\d*) ([\w\-]*)\/(\d*)(?:\s*\/(\S*))?/,
  23255. names: ['payload', 'codec', 'rate', 'encoding'],
  23256. format: function (o) {
  23257. return (o.encoding) ?
  23258. "rtpmap:%d %s/%s/%s":
  23259. "rtpmap:%d %s/%s";
  23260. }
  23261. },
  23262. { //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
  23263. push: 'fmtp',
  23264. reg: /^fmtp:(\d*) (\S*)/,
  23265. names: ['payload', 'config'],
  23266. format: "fmtp:%d %s"
  23267. },
  23268. { //a=control:streamid=0
  23269. name: 'control',
  23270. reg: /^control:(.*)/,
  23271. format: "control:%s"
  23272. },
  23273. { //a=rtcp:65179 IN IP4 193.84.77.194
  23274. name: 'rtcp',
  23275. reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
  23276. names: ['port', 'netType', 'ipVer', 'address'],
  23277. format: function (o) {
  23278. return (o.address != null) ?
  23279. "rtcp:%d %s IP%d %s":
  23280. "rtcp:%d";
  23281. }
  23282. },
  23283. { //a=rtcp-fb:98 trr-int 100
  23284. push: 'rtcpFbTrrInt',
  23285. reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
  23286. names: ['payload', 'value'],
  23287. format: "rtcp-fb:%d trr-int %d"
  23288. },
  23289. { //a=rtcp-fb:98 nack rpsi
  23290. push: 'rtcpFb',
  23291. reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
  23292. names: ['payload', 'type', 'subtype'],
  23293. format: function (o) {
  23294. return (o.subtype != null) ?
  23295. "rtcp-fb:%s %s %s":
  23296. "rtcp-fb:%s %s";
  23297. }
  23298. },
  23299. { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
  23300. //a=extmap:1/recvonly URI-gps-string
  23301. push: 'ext',
  23302. reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
  23303. names: ['value', 'uri', 'config'], // value may include "/direction" suffix
  23304. format: function (o) {
  23305. return (o.config != null) ?
  23306. "extmap:%s %s %s":
  23307. "extmap:%s %s";
  23308. }
  23309. },
  23310. {
  23311. //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
  23312. push: 'crypto',
  23313. reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
  23314. names: ['id', 'suite', 'config', 'sessionConfig'],
  23315. format: function (o) {
  23316. return (o.sessionConfig != null) ?
  23317. "crypto:%d %s %s %s":
  23318. "crypto:%d %s %s";
  23319. }
  23320. },
  23321. { //a=setup:actpass
  23322. name: 'setup',
  23323. reg: /^setup:(\w*)/,
  23324. format: "setup:%s"
  23325. },
  23326. { //a=mid:1
  23327. name: 'mid',
  23328. reg: /^mid:([^\s]*)/,
  23329. format: "mid:%s"
  23330. },
  23331. { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
  23332. name: 'msid',
  23333. reg: /^msid:(.*)/,
  23334. format: "msid:%s"
  23335. },
  23336. { //a=ptime:20
  23337. name: 'ptime',
  23338. reg: /^ptime:(\d*)/,
  23339. format: "ptime:%d"
  23340. },
  23341. { //a=maxptime:60
  23342. name: 'maxptime',
  23343. reg: /^maxptime:(\d*)/,
  23344. format: "maxptime:%d"
  23345. },
  23346. { //a=sendrecv
  23347. name: 'direction',
  23348. reg: /^(sendrecv|recvonly|sendonly|inactive)/
  23349. },
  23350. { //a=ice-lite
  23351. name: 'icelite',
  23352. reg: /^(ice-lite)/
  23353. },
  23354. { //a=ice-ufrag:F7gI
  23355. name: 'iceUfrag',
  23356. reg: /^ice-ufrag:(\S*)/,
  23357. format: "ice-ufrag:%s"
  23358. },
  23359. { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
  23360. name: 'icePwd',
  23361. reg: /^ice-pwd:(\S*)/,
  23362. format: "ice-pwd:%s"
  23363. },
  23364. { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
  23365. name: 'fingerprint',
  23366. reg: /^fingerprint:(\S*) (\S*)/,
  23367. names: ['type', 'hash'],
  23368. format: "fingerprint:%s %s"
  23369. },
  23370. {
  23371. //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
  23372. //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
  23373. //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
  23374. push:'candidates',
  23375. reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: generation (\d*))?/,
  23376. names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'generation'],
  23377. format: function (o) {
  23378. var str = "candidate:%s %d %s %d %s %d typ %s";
  23379. // NB: candidate has two optional chunks, so %void middle one if it's missing
  23380. str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
  23381. if (o.generation != null) {
  23382. str += " generation %d";
  23383. }
  23384. return str;
  23385. }
  23386. },
  23387. { //a=end-of-candidates (keep after the candidates line for readability)
  23388. name: 'endOfCandidates',
  23389. reg: /^(end-of-candidates)/
  23390. },
  23391. { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
  23392. name: 'remoteCandidates',
  23393. reg: /^remote-candidates:(.*)/,
  23394. format: "remote-candidates:%s"
  23395. },
  23396. { //a=ice-options:google-ice
  23397. name: 'iceOptions',
  23398. reg: /^ice-options:(\S*)/,
  23399. format: "ice-options:%s"
  23400. },
  23401. { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
  23402. push: "ssrcs",
  23403. reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
  23404. names: ['id', 'attribute', 'value'],
  23405. format: "ssrc:%d %s:%s"
  23406. },
  23407. { //a=ssrc-group:FEC 1 2
  23408. push: "ssrcGroups",
  23409. reg: /^ssrc-group:(\w*) (.*)/,
  23410. names: ['semantics', 'ssrcs'],
  23411. format: "ssrc-group:%s %s"
  23412. },
  23413. { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
  23414. name: "msidSemantic",
  23415. reg: /^msid-semantic:\s?(\w*) (\S*)/,
  23416. names: ['semantic', 'token'],
  23417. format: "msid-semantic: %s %s" // space after ":" is not accidental
  23418. },
  23419. { //a=group:BUNDLE audio video
  23420. push: 'groups',
  23421. reg: /^group:(\w*) (.*)/,
  23422. names: ['type', 'mids'],
  23423. format: "group:%s %s"
  23424. },
  23425. { //a=rtcp-mux
  23426. name: 'rtcpMux',
  23427. reg: /^(rtcp-mux)/
  23428. },
  23429. { // any a= that we don't understand is kepts verbatim on media.invalid
  23430. push: 'invalid',
  23431. names: ["value"]
  23432. }
  23433. ]
  23434. };
  23435. // set sensible defaults to avoid polluting the grammar with boring details
  23436. Object.keys(grammar).forEach(function (key) {
  23437. var objs = grammar[key];
  23438. objs.forEach(function (obj) {
  23439. if (!obj.reg) {
  23440. obj.reg = /(.*)/;
  23441. }
  23442. if (!obj.format) {
  23443. obj.format = "%s";
  23444. }
  23445. });
  23446. });
  23447. },{}],84:[function(require,module,exports){
  23448. var parser = require('./parser');
  23449. var writer = require('./writer');
  23450. exports.write = writer;
  23451. exports.parse = parser.parse;
  23452. exports.parseFmtpConfig = parser.parseFmtpConfig;
  23453. exports.parsePayloads = parser.parsePayloads;
  23454. exports.parseRemoteCandidates = parser.parseRemoteCandidates;
  23455. },{"./parser":85,"./writer":86}],85:[function(require,module,exports){
  23456. var toIntIfInt = function (v) {
  23457. return String(Number(v)) === v ? Number(v) : v;
  23458. };
  23459. var attachProperties = function (match, location, names, rawName) {
  23460. if (rawName && !names) {
  23461. location[rawName] = toIntIfInt(match[1]);
  23462. }
  23463. else {
  23464. for (var i = 0; i < names.length; i += 1) {
  23465. if (match[i+1] != null) {
  23466. location[names[i]] = toIntIfInt(match[i+1]);
  23467. }
  23468. }
  23469. }
  23470. };
  23471. var parseReg = function (obj, location, content) {
  23472. var needsBlank = obj.name && obj.names;
  23473. if (obj.push && !location[obj.push]) {
  23474. location[obj.push] = [];
  23475. }
  23476. else if (needsBlank && !location[obj.name]) {
  23477. location[obj.name] = {};
  23478. }
  23479. var keyLocation = obj.push ?
  23480. {} : // blank object that will be pushed
  23481. needsBlank ? location[obj.name] : location; // otherwise, named location or root
  23482. attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
  23483. if (obj.push) {
  23484. location[obj.push].push(keyLocation);
  23485. }
  23486. };
  23487. var grammar = require('./grammar');
  23488. var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
  23489. exports.parse = function (sdp) {
  23490. var session = {}
  23491. , media = []
  23492. , location = session; // points at where properties go under (one of the above)
  23493. // parse lines we understand
  23494. sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
  23495. var type = l[0];
  23496. var content = l.slice(2);
  23497. if (type === 'm') {
  23498. media.push({rtp: [], fmtp: []});
  23499. location = media[media.length-1]; // point at latest media line
  23500. }
  23501. for (var j = 0; j < (grammar[type] || []).length; j += 1) {
  23502. var obj = grammar[type][j];
  23503. if (obj.reg.test(content)) {
  23504. return parseReg(obj, location, content);
  23505. }
  23506. }
  23507. });
  23508. session.media = media; // link it up
  23509. return session;
  23510. };
  23511. var fmtpReducer = function (acc, expr) {
  23512. var s = expr.split('=');
  23513. if (s.length === 2) {
  23514. acc[s[0]] = toIntIfInt(s[1]);
  23515. }
  23516. return acc;
  23517. };
  23518. exports.parseFmtpConfig = function (str) {
  23519. return str.split(';').reduce(fmtpReducer, {});
  23520. };
  23521. exports.parsePayloads = function (str) {
  23522. return str.split(' ').map(Number);
  23523. };
  23524. exports.parseRemoteCandidates = function (str) {
  23525. var candidates = [];
  23526. var parts = str.split(' ').map(toIntIfInt);
  23527. for (var i = 0; i < parts.length; i += 3) {
  23528. candidates.push({
  23529. component: parts[i],
  23530. ip: parts[i + 1],
  23531. port: parts[i + 2]
  23532. });
  23533. }
  23534. return candidates;
  23535. };
  23536. },{"./grammar":83}],86:[function(require,module,exports){
  23537. var grammar = require('./grammar');
  23538. // customized util.format - discards excess arguments and can void middle ones
  23539. var formatRegExp = /%[sdv%]/g;
  23540. var format = function (formatStr) {
  23541. var i = 1;
  23542. var args = arguments;
  23543. var len = args.length;
  23544. return formatStr.replace(formatRegExp, function (x) {
  23545. if (i >= len) {
  23546. return x; // missing argument
  23547. }
  23548. var arg = args[i];
  23549. i += 1;
  23550. switch (x) {
  23551. case '%%':
  23552. return '%';
  23553. case '%s':
  23554. return String(arg);
  23555. case '%d':
  23556. return Number(arg);
  23557. case '%v':
  23558. return '';
  23559. }
  23560. });
  23561. // NB: we discard excess arguments - they are typically undefined from makeLine
  23562. };
  23563. var makeLine = function (type, obj, location) {
  23564. var str = obj.format instanceof Function ?
  23565. (obj.format(obj.push ? location : location[obj.name])) :
  23566. obj.format;
  23567. var args = [type + '=' + str];
  23568. if (obj.names) {
  23569. for (var i = 0; i < obj.names.length; i += 1) {
  23570. var n = obj.names[i];
  23571. if (obj.name) {
  23572. args.push(location[obj.name][n]);
  23573. }
  23574. else { // for mLine and push attributes
  23575. args.push(location[obj.names[i]]);
  23576. }
  23577. }
  23578. }
  23579. else {
  23580. args.push(location[obj.name]);
  23581. }
  23582. return format.apply(null, args);
  23583. };
  23584. // RFC specified order
  23585. // TODO: extend this with all the rest
  23586. var defaultOuterOrder = [
  23587. 'v', 'o', 's', 'i',
  23588. 'u', 'e', 'p', 'c',
  23589. 'b', 't', 'r', 'z', 'a'
  23590. ];
  23591. var defaultInnerOrder = ['i', 'c', 'b', 'a'];
  23592. module.exports = function (session, opts) {
  23593. opts = opts || {};
  23594. // ensure certain properties exist
  23595. if (session.version == null) {
  23596. session.version = 0; // "v=0" must be there (only defined version atm)
  23597. }
  23598. if (session.name == null) {
  23599. session.name = " "; // "s= " must be there if no meaningful name set
  23600. }
  23601. session.media.forEach(function (mLine) {
  23602. if (mLine.payloads == null) {
  23603. mLine.payloads = "";
  23604. }
  23605. });
  23606. var outerOrder = opts.outerOrder || defaultOuterOrder;
  23607. var innerOrder = opts.innerOrder || defaultInnerOrder;
  23608. var sdp = [];
  23609. // loop through outerOrder for matching properties on session
  23610. outerOrder.forEach(function (type) {
  23611. grammar[type].forEach(function (obj) {
  23612. if (obj.name in session && session[obj.name] != null) {
  23613. sdp.push(makeLine(type, obj, session));
  23614. }
  23615. else if (obj.push in session && session[obj.push] != null) {
  23616. session[obj.push].forEach(function (el) {
  23617. sdp.push(makeLine(type, obj, el));
  23618. });
  23619. }
  23620. });
  23621. });
  23622. // then for each media line, follow the innerOrder
  23623. session.media.forEach(function (mLine) {
  23624. sdp.push(makeLine('m', grammar.m[0], mLine));
  23625. innerOrder.forEach(function (type) {
  23626. grammar[type].forEach(function (obj) {
  23627. if (obj.name in mLine && mLine[obj.name] != null) {
  23628. sdp.push(makeLine(type, obj, mLine));
  23629. }
  23630. else if (obj.push in mLine && mLine[obj.push] != null) {
  23631. mLine[obj.push].forEach(function (el) {
  23632. sdp.push(makeLine(type, obj, el));
  23633. });
  23634. }
  23635. });
  23636. });
  23637. });
  23638. return sdp.join('\r\n') + '\r\n';
  23639. };
  23640. },{"./grammar":83}],87:[function(require,module,exports){
  23641. var MediaStreamType = {
  23642. VIDEO_TYPE: "Video",
  23643. AUDIO_TYPE: "Audio"
  23644. };
  23645. module.exports = MediaStreamType;
  23646. },{}],88:[function(require,module,exports){
  23647. var RTCBrowserType = {
  23648. RTC_BROWSER_CHROME: "rtc_browser.chrome",
  23649. RTC_BROWSER_FIREFOX: "rtc_browser.firefox"
  23650. };
  23651. module.exports = RTCBrowserType;
  23652. },{}],89:[function(require,module,exports){
  23653. var RTCEvents = {
  23654. LASTN_CHANGED: "rtc.lastn_changed",
  23655. DOMINANTSPEAKER_CHANGED: "rtc.dominantspeaker_changed",
  23656. LASTN_ENDPOINT_CHANGED: "rtc.lastn_endpoint_changed",
  23657. SIMULCAST_LAYER_CHANGED: "rtc.simulcast_layer_changed",
  23658. SIMULCAST_LAYER_CHANGING: "rtc.simulcast_layer_changing",
  23659. SIMULCAST_START: "rtc.simlcast_start",
  23660. SIMULCAST_STOP: "rtc.simlcast_stop",
  23661. AVAILABLE_DEVICES_CHANGED: "rtc.available_devices_changed"
  23662. };
  23663. module.exports = RTCEvents;
  23664. },{}],90:[function(require,module,exports){
  23665. var Resolutions = {
  23666. "1080": {
  23667. width: 1920,
  23668. height: 1080,
  23669. order: 7
  23670. },
  23671. "fullhd": {
  23672. width: 1920,
  23673. height: 1080,
  23674. order: 7
  23675. },
  23676. "720": {
  23677. width: 1280,
  23678. height: 720,
  23679. order: 6
  23680. },
  23681. "hd": {
  23682. width: 1280,
  23683. height: 720,
  23684. order: 6
  23685. },
  23686. "960": {
  23687. width: 960,
  23688. height: 720,
  23689. order: 5
  23690. },
  23691. "640": {
  23692. width: 640,
  23693. height: 480,
  23694. order: 4
  23695. },
  23696. "vga": {
  23697. width: 640,
  23698. height: 480,
  23699. order: 4
  23700. },
  23701. "360": {
  23702. width: 640,
  23703. height: 360,
  23704. order: 3
  23705. },
  23706. "320": {
  23707. width: 320,
  23708. height: 240,
  23709. order: 2
  23710. },
  23711. "180": {
  23712. width: 320,
  23713. height: 180,
  23714. order: 1
  23715. }
  23716. };
  23717. module.exports = Resolutions;
  23718. },{}],91:[function(require,module,exports){
  23719. var StreamEventTypes = {
  23720. EVENT_TYPE_LOCAL_CREATED: "stream.local_created",
  23721. EVENT_TYPE_LOCAL_CHANGED: "stream.local_changed",
  23722. EVENT_TYPE_LOCAL_ENDED: "stream.local_ended",
  23723. EVENT_TYPE_REMOTE_CREATED: "stream.remote_created",
  23724. EVENT_TYPE_REMOTE_ENDED: "stream.remote_ended",
  23725. EVENT_TYPE_REMOTE_CHANGED: "stream.changed"
  23726. };
  23727. module.exports = StreamEventTypes;
  23728. },{}],92:[function(require,module,exports){
  23729. var UIEvents = {
  23730. NICKNAME_CHANGED: "UI.nickname_changed",
  23731. SELECTED_ENDPOINT: "UI.selected_endpoint",
  23732. PINNED_ENDPOINT: "UI.pinned_endpoint"
  23733. };
  23734. module.exports = UIEvents;
  23735. },{}],93:[function(require,module,exports){
  23736. var AuthenticationEvents = {
  23737. /**
  23738. * Event callback arguments:
  23739. * function(authenticationEnabled, userIdentity)
  23740. * authenticationEnabled - indicates whether authentication has been enabled
  23741. * in this session
  23742. * userIdentity - if user has been logged in then it contains user name. If
  23743. * contains 'null' or 'undefined' then user is not logged in.
  23744. */
  23745. IDENTITY_UPDATED: "authentication.identity_updated"
  23746. };
  23747. module.exports = AuthenticationEvents;
  23748. },{}],94:[function(require,module,exports){
  23749. var CQEvents = {
  23750. LOCALSTATS_UPDATED: "cq.localstats_updated",
  23751. REMOTESTATS_UPDATED: "cq.remotestats_updated",
  23752. STOP: "cq.stop"
  23753. };
  23754. module.exports = CQEvents;
  23755. },{}],95:[function(require,module,exports){
  23756. var DesktopSharingEventTypes = {
  23757. INIT: "ds.init",
  23758. SWITCHING_DONE: "ds.switching_done",
  23759. NEW_STREAM_CREATED: "ds.new_stream_created"
  23760. };
  23761. module.exports = DesktopSharingEventTypes;
  23762. },{}],96:[function(require,module,exports){
  23763. module.exports = {
  23764. getLanguages : function () {
  23765. var languages = [];
  23766. for(var lang in this)
  23767. {
  23768. if(typeof this[lang] === "string")
  23769. languages.push(this[lang]);
  23770. }
  23771. return languages;
  23772. },
  23773. EN: "en",
  23774. BG: "bg",
  23775. DE: "de",
  23776. TR: "tr"
  23777. }
  23778. },{}],97:[function(require,module,exports){
  23779. var XMPPEvents = {
  23780. CONFERENCE_CERATED: "xmpp.conferenceCreated.jingle",
  23781. CALL_TERMINATED: "xmpp.callterminated.jingle",
  23782. CALL_INCOMING: "xmpp.callincoming.jingle",
  23783. DISPOSE_CONFERENCE: "xmpp.dispoce_confernce",
  23784. GRACEFUL_SHUTDOWN: "xmpp.graceful_shutdown",
  23785. KICKED: "xmpp.kicked",
  23786. BRIDGE_DOWN: "xmpp.bridge_down",
  23787. USER_ID_CHANGED: "xmpp.user_id_changed",
  23788. CHANGED_STREAMS: "xmpp.changed_streams",
  23789. MUC_JOINED: "xmpp.muc_joined",
  23790. MUC_ENTER: "xmpp.muc_enter",
  23791. MUC_ROLE_CHANGED: "xmpp.muc_role_changed",
  23792. MUC_LEFT: "xmpp.muc_left",
  23793. MUC_DESTROYED: "xmpp.muc_destroyed",
  23794. DISPLAY_NAME_CHANGED: "xmpp.display_name_changed",
  23795. REMOTE_STATS: "xmpp.remote_stats",
  23796. LOCALROLE_CHANGED: "xmpp.localrole_changed",
  23797. PRESENCE_STATUS: "xmpp.presence_status",
  23798. RESERVATION_ERROR: "xmpp.room_reservation_error",
  23799. SUBJECT_CHANGED: "xmpp.subject_changed",
  23800. MESSAGE_RECEIVED: "xmpp.message_received",
  23801. SENDING_CHAT_MESSAGE: "xmpp.sending_chat_message",
  23802. PASSWORD_REQUIRED: "xmpp.password_required",
  23803. AUTHENTICATION_REQUIRED: "xmpp.authentication_required",
  23804. CHAT_ERROR_RECEIVED: "xmpp.chat_error_received",
  23805. ETHERPAD: "xmpp.etherpad",
  23806. DEVICE_AVAILABLE: "xmpp.device_available"
  23807. };
  23808. module.exports = XMPPEvents;
  23809. },{}],98:[function(require,module,exports){
  23810. // Copyright Joyent, Inc. and other Node contributors.
  23811. //
  23812. // Permission is hereby granted, free of charge, to any person obtaining a
  23813. // copy of this software and associated documentation files (the
  23814. // "Software"), to deal in the Software without restriction, including
  23815. // without limitation the rights to use, copy, modify, merge, publish,
  23816. // distribute, sublicense, and/or sell copies of the Software, and to permit
  23817. // persons to whom the Software is furnished to do so, subject to the
  23818. // following conditions:
  23819. //
  23820. // The above copyright notice and this permission notice shall be included
  23821. // in all copies or substantial portions of the Software.
  23822. //
  23823. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  23824. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23825. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  23826. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  23827. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23828. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  23829. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  23830. function EventEmitter() {
  23831. this._events = this._events || {};
  23832. this._maxListeners = this._maxListeners || undefined;
  23833. }
  23834. module.exports = EventEmitter;
  23835. // Backwards-compat with node 0.10.x
  23836. EventEmitter.EventEmitter = EventEmitter;
  23837. EventEmitter.prototype._events = undefined;
  23838. EventEmitter.prototype._maxListeners = undefined;
  23839. // By default EventEmitters will print a warning if more than 10 listeners are
  23840. // added to it. This is a useful default which helps finding memory leaks.
  23841. EventEmitter.defaultMaxListeners = 10;
  23842. // Obviously not all Emitters should be limited to 10. This function allows
  23843. // that to be increased. Set to zero for unlimited.
  23844. EventEmitter.prototype.setMaxListeners = function(n) {
  23845. if (!isNumber(n) || n < 0 || isNaN(n))
  23846. throw TypeError('n must be a positive number');
  23847. this._maxListeners = n;
  23848. return this;
  23849. };
  23850. EventEmitter.prototype.emit = function(type) {
  23851. var er, handler, len, args, i, listeners;
  23852. if (!this._events)
  23853. this._events = {};
  23854. // If there is no 'error' event listener then throw.
  23855. if (type === 'error') {
  23856. if (!this._events.error ||
  23857. (isObject(this._events.error) && !this._events.error.length)) {
  23858. er = arguments[1];
  23859. if (er instanceof Error) {
  23860. throw er; // Unhandled 'error' event
  23861. }
  23862. throw TypeError('Uncaught, unspecified "error" event.');
  23863. }
  23864. }
  23865. handler = this._events[type];
  23866. if (isUndefined(handler))
  23867. return false;
  23868. if (isFunction(handler)) {
  23869. switch (arguments.length) {
  23870. // fast cases
  23871. case 1:
  23872. handler.call(this);
  23873. break;
  23874. case 2:
  23875. handler.call(this, arguments[1]);
  23876. break;
  23877. case 3:
  23878. handler.call(this, arguments[1], arguments[2]);
  23879. break;
  23880. // slower
  23881. default:
  23882. len = arguments.length;
  23883. args = new Array(len - 1);
  23884. for (i = 1; i < len; i++)
  23885. args[i - 1] = arguments[i];
  23886. handler.apply(this, args);
  23887. }
  23888. } else if (isObject(handler)) {
  23889. len = arguments.length;
  23890. args = new Array(len - 1);
  23891. for (i = 1; i < len; i++)
  23892. args[i - 1] = arguments[i];
  23893. listeners = handler.slice();
  23894. len = listeners.length;
  23895. for (i = 0; i < len; i++)
  23896. listeners[i].apply(this, args);
  23897. }
  23898. return true;
  23899. };
  23900. EventEmitter.prototype.addListener = function(type, listener) {
  23901. var m;
  23902. if (!isFunction(listener))
  23903. throw TypeError('listener must be a function');
  23904. if (!this._events)
  23905. this._events = {};
  23906. // To avoid recursion in the case that type === "newListener"! Before
  23907. // adding it to the listeners, first emit "newListener".
  23908. if (this._events.newListener)
  23909. this.emit('newListener', type,
  23910. isFunction(listener.listener) ?
  23911. listener.listener : listener);
  23912. if (!this._events[type])
  23913. // Optimize the case of one listener. Don't need the extra array object.
  23914. this._events[type] = listener;
  23915. else if (isObject(this._events[type]))
  23916. // If we've already got an array, just append.
  23917. this._events[type].push(listener);
  23918. else
  23919. // Adding the second element, need to change to array.
  23920. this._events[type] = [this._events[type], listener];
  23921. // Check for listener leak
  23922. if (isObject(this._events[type]) && !this._events[type].warned) {
  23923. var m;
  23924. if (!isUndefined(this._maxListeners)) {
  23925. m = this._maxListeners;
  23926. } else {
  23927. m = EventEmitter.defaultMaxListeners;
  23928. }
  23929. if (m && m > 0 && this._events[type].length > m) {
  23930. this._events[type].warned = true;
  23931. console.error('(node) warning: possible EventEmitter memory ' +
  23932. 'leak detected. %d listeners added. ' +
  23933. 'Use emitter.setMaxListeners() to increase limit.',
  23934. this._events[type].length);
  23935. if (typeof console.trace === 'function') {
  23936. // not supported in IE 10
  23937. console.trace();
  23938. }
  23939. }
  23940. }
  23941. return this;
  23942. };
  23943. EventEmitter.prototype.on = EventEmitter.prototype.addListener;
  23944. EventEmitter.prototype.once = function(type, listener) {
  23945. if (!isFunction(listener))
  23946. throw TypeError('listener must be a function');
  23947. var fired = false;
  23948. function g() {
  23949. this.removeListener(type, g);
  23950. if (!fired) {
  23951. fired = true;
  23952. listener.apply(this, arguments);
  23953. }
  23954. }
  23955. g.listener = listener;
  23956. this.on(type, g);
  23957. return this;
  23958. };
  23959. // emits a 'removeListener' event iff the listener was removed
  23960. EventEmitter.prototype.removeListener = function(type, listener) {
  23961. var list, position, length, i;
  23962. if (!isFunction(listener))
  23963. throw TypeError('listener must be a function');
  23964. if (!this._events || !this._events[type])
  23965. return this;
  23966. list = this._events[type];
  23967. length = list.length;
  23968. position = -1;
  23969. if (list === listener ||
  23970. (isFunction(list.listener) && list.listener === listener)) {
  23971. delete this._events[type];
  23972. if (this._events.removeListener)
  23973. this.emit('removeListener', type, listener);
  23974. } else if (isObject(list)) {
  23975. for (i = length; i-- > 0;) {
  23976. if (list[i] === listener ||
  23977. (list[i].listener && list[i].listener === listener)) {
  23978. position = i;
  23979. break;
  23980. }
  23981. }
  23982. if (position < 0)
  23983. return this;
  23984. if (list.length === 1) {
  23985. list.length = 0;
  23986. delete this._events[type];
  23987. } else {
  23988. list.splice(position, 1);
  23989. }
  23990. if (this._events.removeListener)
  23991. this.emit('removeListener', type, listener);
  23992. }
  23993. return this;
  23994. };
  23995. EventEmitter.prototype.removeAllListeners = function(type) {
  23996. var key, listeners;
  23997. if (!this._events)
  23998. return this;
  23999. // not listening for removeListener, no need to emit
  24000. if (!this._events.removeListener) {
  24001. if (arguments.length === 0)
  24002. this._events = {};
  24003. else if (this._events[type])
  24004. delete this._events[type];
  24005. return this;
  24006. }
  24007. // emit removeListener for all listeners on all events
  24008. if (arguments.length === 0) {
  24009. for (key in this._events) {
  24010. if (key === 'removeListener') continue;
  24011. this.removeAllListeners(key);
  24012. }
  24013. this.removeAllListeners('removeListener');
  24014. this._events = {};
  24015. return this;
  24016. }
  24017. listeners = this._events[type];
  24018. if (isFunction(listeners)) {
  24019. this.removeListener(type, listeners);
  24020. } else {
  24021. // LIFO order
  24022. while (listeners.length)
  24023. this.removeListener(type, listeners[listeners.length - 1]);
  24024. }
  24025. delete this._events[type];
  24026. return this;
  24027. };
  24028. EventEmitter.prototype.listeners = function(type) {
  24029. var ret;
  24030. if (!this._events || !this._events[type])
  24031. ret = [];
  24032. else if (isFunction(this._events[type]))
  24033. ret = [this._events[type]];
  24034. else
  24035. ret = this._events[type].slice();
  24036. return ret;
  24037. };
  24038. EventEmitter.listenerCount = function(emitter, type) {
  24039. var ret;
  24040. if (!emitter._events || !emitter._events[type])
  24041. ret = 0;
  24042. else if (isFunction(emitter._events[type]))
  24043. ret = 1;
  24044. else
  24045. ret = emitter._events[type].length;
  24046. return ret;
  24047. };
  24048. function isFunction(arg) {
  24049. return typeof arg === 'function';
  24050. }
  24051. function isNumber(arg) {
  24052. return typeof arg === 'number';
  24053. }
  24054. function isObject(arg) {
  24055. return typeof arg === 'object' && arg !== null;
  24056. }
  24057. function isUndefined(arg) {
  24058. return arg === void 0;
  24059. }
  24060. },{}]},{},[1])(1)
  24061. });
  24062. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImFwcC5qcyIsIm1vZHVsZXMvQVBJL0FQSS5qcyIsIm1vZHVsZXMvUlRDL0RhdGFDaGFubmVscy5qcyIsIm1vZHVsZXMvUlRDL0xvY2FsU3RyZWFtLmpzIiwibW9kdWxlcy9SVEMvTWVkaWFTdHJlYW0uanMiLCJtb2R1bGVzL1JUQy9SVEMuanMiLCJtb2R1bGVzL1JUQy9SVENVdGlscy5qcyIsIm1vZHVsZXMvVUkvVUkuanMiLCJtb2R1bGVzL1VJL2F1ZGlvX2xldmVscy9BdWRpb0xldmVscy5qcyIsIm1vZHVsZXMvVUkvYXVkaW9fbGV2ZWxzL0NhbnZhc1V0aWxzLmpzIiwibW9kdWxlcy9VSS9hdXRoZW50aWNhdGlvbi9BdXRoZW50aWNhdGlvbi5qcyIsIm1vZHVsZXMvVUkvYXV0aGVudGljYXRpb24vTG9naW5EaWFsb2cuanMiLCJtb2R1bGVzL1VJL2F2YXRhci9BdmF0YXIuanMiLCJtb2R1bGVzL1VJL2V0aGVycGFkL0V0aGVycGFkLmpzIiwibW9kdWxlcy9VSS9wcmV6aS9QcmV6aS5qcyIsIm1vZHVsZXMvVUkvcHJlemkvUHJlemlQbGF5ZXIuanMiLCJtb2R1bGVzL1VJL3NpZGVfcGFubmVscy9TaWRlUGFuZWxUb2dnbGVyLmpzIiwibW9kdWxlcy9VSS9zaWRlX3Bhbm5lbHMvY2hhdC9DaGF0LmpzIiwibW9kdWxlcy9VSS9zaWRlX3Bhbm5lbHMvY2hhdC9Db21tYW5kcy5qcyIsIm1vZHVsZXMvVUkvc2lkZV9wYW5uZWxzL2NoYXQvUmVwbGFjZW1lbnQuanMiLCJtb2R1bGVzL1VJL3NpZGVfcGFubmVscy9jaGF0L3NtaWxleXMuanNvbiIsIm1vZHVsZXMvVUkvc2lkZV9wYW5uZWxzL2NvbnRhY3RsaXN0L0NvbnRhY3RMaXN0LmpzIiwibW9kdWxlcy9VSS9zaWRlX3Bhbm5lbHMvc2V0dGluZ3MvU2V0dGluZ3NNZW51LmpzIiwibW9kdWxlcy9VSS90b29sYmFycy9Cb3R0b21Ub29sYmFyLmpzIiwibW9kdWxlcy9VSS90b29sYmFycy9Ub29sYmFyLmpzIiwibW9kdWxlcy9VSS90b29sYmFycy9Ub29sYmFyVG9nZ2xlci5qcyIsIm1vZHVsZXMvVUkvdXRpbC9KaXRzaVBvcG92ZXIuanMiLCJtb2R1bGVzL1VJL3V0aWwvTWVzc2FnZUhhbmRsZXIuanMiLCJtb2R1bGVzL1VJL3V0aWwvTmlja25hbWVIYW5kbGVyLmpzIiwibW9kdWxlcy9VSS91dGlsL1VJVXRpbC5qcyIsIm1vZHVsZXMvVUkvdmlkZW9sYXlvdXQvQ29ubmVjdGlvbkluZGljYXRvci5qcyIsIm1vZHVsZXMvVUkvdmlkZW9sYXlvdXQvVmlkZW9MYXlvdXQuanMiLCJtb2R1bGVzL1VJL3dlbGNvbWVfcGFnZS9Sb29tbmFtZUdlbmVyYXRvci5qcyIsIm1vZHVsZXMvVUkvd2VsY29tZV9wYWdlL1dlbGNvbWVQYWdlLmpzIiwibW9kdWxlcy9jb25uZWN0aW9ucXVhbGl0eS9jb25uZWN0aW9ucXVhbGl0eS5qcyIsIm1vZHVsZXMvZGVza3RvcHNoYXJpbmcvZGVza3RvcHNoYXJpbmcuanMiLCJtb2R1bGVzL2tleWJvYXJkc2hvcnRjdXQva2V5Ym9hcmRzaG9ydGN1dC5qcyIsIm1vZHVsZXMvc2V0dGluZ3MvU2V0dGluZ3MuanMiLCJtb2R1bGVzL3NpbXVsY2FzdC9TaW11bGNhc3RMb2dnZXIuanMiLCJtb2R1bGVzL3NpbXVsY2FzdC9TaW11bGNhc3RSZWNlaXZlci5qcyIsIm1vZHVsZXMvc2ltdWxjYXN0L1NpbXVsY2FzdFNlbmRlci5qcyIsIm1vZHVsZXMvc2ltdWxjYXN0L1NpbXVsY2FzdFV0aWxzLmpzIiwibW9kdWxlcy9zaW11bGNhc3Qvc2ltdWxjYXN0LmpzIiwibW9kdWxlcy9zdGF0aXN0aWNzL0xvY2FsU3RhdHNDb2xsZWN0b3IuanMiLCJtb2R1bGVzL3N0YXRpc3RpY3MvUlRQU3RhdHNDb2xsZWN0b3IuanMiLCJtb2R1bGVzL3N0YXRpc3RpY3Mvc3RhdGlzdGljcy5qcyIsIm1vZHVsZXMvdHJhbnNsYXRpb24vdHJhbnNsYXRpb24uanMiLCJtb2R1bGVzL3htcHAvSmluZ2xlU2Vzc2lvbi5qcyIsIm1vZHVsZXMveG1wcC9TRFAuanMiLCJtb2R1bGVzL3htcHAvU0RQRGlmZmVyLmpzIiwibW9kdWxlcy94bXBwL1NEUFV0aWwuanMiLCJtb2R1bGVzL3htcHAvVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24uanMiLCJtb2R1bGVzL3htcHAvbW9kZXJhdG9yLmpzIiwibW9kdWxlcy94bXBwL3JlY29yZGluZy5qcyIsIm1vZHVsZXMveG1wcC9zdHJvcGhlLmVtdWMuanMiLCJtb2R1bGVzL3htcHAvc3Ryb3BoZS5qaW5nbGUuanMiLCJtb2R1bGVzL3htcHAvc3Ryb3BoZS5sb2dnZXIuanMiLCJtb2R1bGVzL3htcHAvc3Ryb3BoZS5tb2RlcmF0ZS5qcyIsIm1vZHVsZXMveG1wcC9zdHJvcGhlLnJheW8uanMiLCJtb2R1bGVzL3htcHAvc3Ryb3BoZS51dGlsLmpzIiwibW9kdWxlcy94bXBwL3htcHAuanMiLCJub2RlX21vZHVsZXMvaTE4bmV4dC1jbGllbnQvaTE4bmV4dC5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL3Bha28vbGliL2RlZmxhdGUuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvaW5mbGF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi91dGlscy9jb21tb24uanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvdXRpbHMvc3RyaW5ncy5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi96bGliL2FkbGVyMzIuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9jb25zdGFudHMuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9jcmMzMi5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi96bGliL2RlZmxhdGUuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9nemhlYWRlci5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi96bGliL2luZmZhc3QuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9pbmZsYXRlLmpzIiwibm9kZV9tb2R1bGVzL3Bha28vbGliL3psaWIvaW5mdHJlZXMuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9tZXNzYWdlcy5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi96bGliL3RyZWVzLmpzIiwibm9kZV9tb2R1bGVzL3Bha28vbGliL3psaWIvenN0cmVhbS5qcyIsIm5vZGVfbW9kdWxlcy9zZHAtaW50ZXJvcC9saWIvYXJyYXktZXF1YWxzLmpzIiwibm9kZV9tb2R1bGVzL3NkcC1pbnRlcm9wL2xpYi9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9zZHAtaW50ZXJvcC9saWIvaW50ZXJvcC5qcyIsIm5vZGVfbW9kdWxlcy9zZHAtaW50ZXJvcC9saWIvdHJhbnNmb3JtLmpzIiwibm9kZV9tb2R1bGVzL3NkcC1pbnRlcm9wL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNmb3JtL2xpYi9ncmFtbWFyLmpzIiwibm9kZV9tb2R1bGVzL3NkcC1pbnRlcm9wL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNmb3JtL2xpYi9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9zZHAtaW50ZXJvcC9ub2RlX21vZHVsZXMvc2RwLXRyYW5zZm9ybS9saWIvcGFyc2VyLmpzIiwibm9kZV9tb2R1bGVzL3NkcC1pbnRlcm9wL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNmb3JtL2xpYi93cml0ZXIuanMiLCJzZXJ2aWNlL1JUQy9NZWRpYVN0cmVhbVR5cGVzLmpzIiwic2VydmljZS9SVEMvUlRDQnJvd3NlclR5cGUuanMiLCJzZXJ2aWNlL1JUQy9SVENFdmVudHMuanMiLCJzZXJ2aWNlL1JUQy9SZXNvbHV0aW9ucy5qcyIsInNlcnZpY2UvUlRDL1N0cmVhbUV2ZW50VHlwZXMuanMiLCJzZXJ2aWNlL1VJL1VJRXZlbnRzLmpzIiwic2VydmljZS9hdXRoZW50aWNhdGlvbi9BdXRoZW50aWNhdGlvbkV2ZW50cy5qcyIsInNlcnZpY2UvY29ubmVjdGlvbnF1YWxpdHkvQ1FFdmVudHMuanMiLCJzZXJ2aWNlL2Rlc2t0b3BzaGFyaW5nL0Rlc2t0b3BTaGFyaW5nRXZlbnRUeXBlcy5qcyIsInNlcnZpY2UvdHJhbnNsYXRpb24vbGFuZ3VhZ2VzLmpzIiwic2VydmljZS94bXBwL1hNUFBFdmVudHMuanMiLCIuLi8uLi8uLi8uLi8uLi91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9ldmVudHMvZXZlbnRzLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDclBBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ252QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25PQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbE1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0WEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdFNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9QQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcFdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOU1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxYUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4dkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNySUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOVdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM1FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6Z0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNudUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNW1CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5VEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3phQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVvQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDemtFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNXQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9XQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcHVEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyVUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzk5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyVUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5cUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hCQTtBQUNBOztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6Z0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25QQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyoganNoaW50IC1XMTE3ICovXG4vKiBhcHBsaWNhdGlvbiBzcGVjaWZpYyBsb2dpYyAqL1xuXG52YXIgQVBQID1cbntcbiAgICBpbml0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuVUkgPSByZXF1aXJlKFwiLi9tb2R1bGVzL1VJL1VJXCIpO1xuICAgICAgICB0aGlzLkFQSSA9IHJlcXVpcmUoXCIuL21vZHVsZXMvQVBJL0FQSVwiKTtcbiAgICAgICAgdGhpcy5jb25uZWN0aW9ucXVhbGl0eSA9IHJlcXVpcmUoXCIuL21vZHVsZXMvY29ubmVjdGlvbnF1YWxpdHkvY29ubmVjdGlvbnF1YWxpdHlcIik7XG4gICAgICAgIHRoaXMuc3RhdGlzdGljcyA9IHJlcXVpcmUoXCIuL21vZHVsZXMvc3RhdGlzdGljcy9zdGF0aXN0aWNzXCIpO1xuICAgICAgICB0aGlzLlJUQyA9IHJlcXVpcmUoXCIuL21vZHVsZXMvUlRDL1JUQ1wiKTtcbiAgICAgICAgdGhpcy5zaW11bGNhc3QgPSByZXF1aXJlKFwiLi9tb2R1bGVzL3NpbXVsY2FzdC9zaW11bGNhc3RcIik7XG4gICAgICAgIHRoaXMuZGVza3RvcHNoYXJpbmcgPSByZXF1aXJlKFwiLi9tb2R1bGVzL2Rlc2t0b3BzaGFyaW5nL2Rlc2t0b3BzaGFyaW5nXCIpO1xuICAgICAgICB0aGlzLnhtcHAgPSByZXF1aXJlKFwiLi9tb2R1bGVzL3htcHAveG1wcFwiKTtcbiAgICAgICAgdGhpcy5rZXlib2FyZHNob3J0Y3V0ID0gcmVxdWlyZShcIi4vbW9kdWxlcy9rZXlib2FyZHNob3J0Y3V0L2tleWJvYXJkc2hvcnRjdXRcIik7XG4gICAgICAgIHRoaXMudHJhbnNsYXRpb24gPSByZXF1aXJlKFwiLi9tb2R1bGVzL3RyYW5zbGF0aW9uL3RyYW5zbGF0aW9uXCIpO1xuICAgICAgICB0aGlzLnNldHRpbmdzID0gcmVxdWlyZShcIi4vbW9kdWxlcy9zZXR0aW5ncy9TZXR0aW5nc1wiKTtcbiAgICB9XG59O1xuXG5mdW5jdGlvbiBpbml0KCkge1xuXG4gICAgQVBQLlJUQy5zdGFydCgpO1xuICAgIEFQUC54bXBwLnN0YXJ0KCk7XG4gICAgQVBQLnN0YXRpc3RpY3Muc3RhcnQoKTtcbiAgICBBUFAuY29ubmVjdGlvbnF1YWxpdHkuaW5pdCgpO1xuXG4gICAgLy8gU2V0IGRlZmF1bHQgZGVza3RvcCBzaGFyaW5nIG1ldGhvZFxuICAgIEFQUC5kZXNrdG9wc2hhcmluZy5pbml0KCk7XG5cbiAgICBBUFAua2V5Ym9hcmRzaG9ydGN1dC5pbml0KCk7XG59XG5cblxuJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24gKCkge1xuXG4gICAgQVBQLmluaXQoKTtcblxuICAgIEFQUC50cmFuc2xhdGlvbi5pbml0KCk7XG5cbiAgICBpZihBUFAuQVBJLmlzRW5hYmxlZCgpKVxuICAgICAgICBBUFAuQVBJLmluaXQoKTtcblxuICAgIEFQUC5VSS5zdGFydChpbml0KTtcblxufSk7XG5cbiQod2luZG93KS5iaW5kKCdiZWZvcmV1bmxvYWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgaWYoQVBQLkFQSS5pc0VuYWJsZWQoKSlcbiAgICAgICAgQVBQLkFQSS5kaXNwb3NlKCk7XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBBUFA7XG5cbiIsIi8qKlxuICogSW1wbGVtZW50cyBBUEkgY2xhc3MgdGhhdCBjb21tdW5pY2F0ZXMgd2l0aCBleHRlcm5hbCBhcGkgY2xhc3NcbiAqIGFuZCBwcm92aWRlcyBpbnRlcmZhY2UgdG8gYWNjZXNzIEppdHNpIE1lZXQgZmVhdHVyZXMgYnkgZXh0ZXJuYWxcbiAqIGFwcGxpY2F0aW9ucyB0aGF0IGVtYmVkIEppdHNpIE1lZXRcbiAqL1xuXG52YXIgWE1QUEV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL3htcHAvWE1QUEV2ZW50c1wiKTtcblxuLyoqXG4gKiBMaXN0IG9mIHRoZSBhdmFpbGFibGUgY29tbWFuZHMuXG4gKiBAdHlwZSB7e1xuICogICAgICAgICAgICAgIGRpc3BsYXlOYW1lOiBpbnB1dERpc3BsYXlOYW1lSGFuZGxlcixcbiAqICAgICAgICAgICAgICBtdXRlQXVkaW86IHRvZ2dsZUF1ZGlvLFxuICogICAgICAgICAgICAgIG11dGVWaWRlbzogdG9nZ2xlVmlkZW8sXG4gKiAgICAgICAgICAgICAgZmlsbVN0cmlwOiB0b2dnbGVGaWxtU3RyaXBcbiAqICAgICAgICAgIH19XG4gKi9cbnZhciBjb21tYW5kcyA9XG57XG4gICAgZGlzcGxheU5hbWU6IEFQUC5VSS5pbnB1dERpc3BsYXlOYW1lSGFuZGxlcixcbiAgICBtdXRlQXVkaW86IEFQUC5VSS50b2dnbGVBdWRpbyxcbiAgICBtdXRlVmlkZW86IEFQUC5VSS50b2dnbGVWaWRlbyxcbiAgICB0b2dnbGVGaWxtU3RyaXA6IEFQUC5VSS50b2dnbGVGaWxtU3RyaXAsXG4gICAgdG9nZ2xlQ2hhdDogQVBQLlVJLnRvZ2dsZUNoYXQsXG4gICAgdG9nZ2xlQ29udGFjdExpc3Q6IEFQUC5VSS50b2dnbGVDb250YWN0TGlzdFxufTtcblxuXG4vKipcbiAqIE1hcHMgdGhlIHN1cHBvcnRlZCBldmVudHMgYW5kIHRoZWlyIHN0YXR1c1xuICogKHRydWUgaXQgdGhlIGV2ZW50IGlzIGVuYWJsZWQgYW5kIGZhbHNlIGlmIGl0IGlzIGRpc2FibGVkKVxuICogQHR5cGUge3tcbiAqICAgICAgICAgICAgICBpbmNvbWluZ01lc3NhZ2U6IGJvb2xlYW4sXG4gKiAgICAgICAgICAgICAgb3V0Z29pbmdNZXNzYWdlOiBib29sZWFuLFxuICogICAgICAgICAgICAgIGRpc3BsYXlOYW1lQ2hhbmdlOiBib29sZWFuLFxuICogICAgICAgICAgICAgIHBhcnRpY2lwYW50Sm9pbmVkOiBib29sZWFuLFxuICogICAgICAgICAgICAgIHBhcnRpY2lwYW50TGVmdDogYm9vbGVhblxuICogICAgICB9fVxuICovXG52YXIgZXZlbnRzID1cbntcbiAgICBpbmNvbWluZ01lc3NhZ2U6IGZhbHNlLFxuICAgIG91dGdvaW5nTWVzc2FnZTpmYWxzZSxcbiAgICBkaXNwbGF5TmFtZUNoYW5nZTogZmFsc2UsXG4gICAgcGFydGljaXBhbnRKb2luZWQ6IGZhbHNlLFxuICAgIHBhcnRpY2lwYW50TGVmdDogZmFsc2Vcbn07XG5cbnZhciBkaXNwbGF5TmFtZSA9IHt9O1xuXG4vKipcbiAqIFByb2Nlc3NlcyBjb21tYW5kcyBmcm9tIGV4dGVybmFsIGFwcGxpY2FpdG9uLlxuICogQHBhcmFtIG1lc3NhZ2UgdGhlIG9iamVjdCB3aXRoIHRoZSBjb21tYW5kXG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NDb21tYW5kKG1lc3NhZ2UpXG57XG4gICAgaWYobWVzc2FnZS5hY3Rpb24gIT0gXCJleGVjdXRlXCIpXG4gICAge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiVW5rbm93biBhY3Rpb24gb2YgdGhlIG1lc3NhZ2VcIik7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZm9yKHZhciBrZXkgaW4gbWVzc2FnZSlcbiAgICB7XG4gICAgICAgIGlmKGNvbW1hbmRzW2tleV0pXG4gICAgICAgICAgICBjb21tYW5kc1trZXldLmFwcGx5KG51bGwsIG1lc3NhZ2Vba2V5XSk7XG4gICAgfVxufVxuXG4vKipcbiAqIFByb2Nlc3NlcyBldmVudHMgb2JqZWN0cyBmcm9tIGV4dGVybmFsIGFwcGxpY2F0aW9uc1xuICogQHBhcmFtIGV2ZW50IHRoZSBldmVudFxuICovXG5mdW5jdGlvbiBwcm9jZXNzRXZlbnQoZXZlbnQpIHtcbiAgICBpZighZXZlbnQuYWN0aW9uKVxuICAgIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkV2ZW50IHdpdGggbm8gYWN0aW9uIGlzIHJlY2VpdmVkLlwiKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBpID0gMDtcbiAgICBzd2l0Y2goZXZlbnQuYWN0aW9uKVxuICAgIHtcbiAgICAgICAgY2FzZSBcImFkZFwiOlxuICAgICAgICAgICAgZm9yKDsgaSA8IGV2ZW50LmV2ZW50cy5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBldmVudHNbZXZlbnQuZXZlbnRzW2ldXSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcInJlbW92ZVwiOlxuICAgICAgICAgICAgZm9yKDsgaSA8IGV2ZW50LmV2ZW50cy5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBldmVudHNbZXZlbnQuZXZlbnRzW2ldXSA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiVW5rbm93biBhY3Rpb24gZm9yIGV2ZW50LlwiKTtcbiAgICB9XG5cbn1cblxuLyoqXG4gKiBTZW5kcyBtZXNzYWdlIHRvIHRoZSBleHRlcm5hbCBhcHBsaWNhdGlvbi5cbiAqIEBwYXJhbSBvYmplY3RcbiAqL1xuZnVuY3Rpb24gc2VuZE1lc3NhZ2Uob2JqZWN0KSB7XG4gICAgd2luZG93LnBhcmVudC5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShvYmplY3QpLCBcIipcIik7XG59XG5cbi8qKlxuICogUHJvY2Vzc2VzIGEgbWVzc2FnZSBldmVudCBmcm9tIHRoZSBleHRlcm5hbCBhcHBsaWNhdGlvblxuICogQHBhcmFtIGV2ZW50IHRoZSBtZXNzYWdlIGV2ZW50XG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NNZXNzYWdlKGV2ZW50KVxue1xuICAgIHZhciBtZXNzYWdlO1xuICAgIHRyeSB7XG4gICAgICAgIG1lc3NhZ2UgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG5cbiAgICBpZighbWVzc2FnZS50eXBlKVxuICAgICAgICByZXR1cm47XG4gICAgc3dpdGNoIChtZXNzYWdlLnR5cGUpXG4gICAge1xuICAgICAgICBjYXNlIFwiY29tbWFuZFwiOlxuICAgICAgICAgICAgcHJvY2Vzc0NvbW1hbmQobWVzc2FnZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcImV2ZW50XCI6XG4gICAgICAgICAgICBwcm9jZXNzRXZlbnQobWVzc2FnZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJVbmtub3duIHR5cGUgb2YgdGhlIG1lc3NhZ2VcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgfVxuXG59XG5cbmZ1bmN0aW9uIHNldHVwTGlzdGVuZXJzKCkge1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTVVDX0VOVEVSLCBmdW5jdGlvbiAoZnJvbSkge1xuICAgICAgICBBUEkudHJpZ2dlckV2ZW50KFwicGFydGljaXBhbnRKb2luZWRcIiwge2ppZDogZnJvbX0pO1xuICAgIH0pO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTUVTU0FHRV9SRUNFSVZFRCwgZnVuY3Rpb24gKGZyb20sIG5pY2ssIHR4dCwgbXlqaWQpIHtcbiAgICAgICAgaWYgKGZyb20gIT0gbXlqaWQpXG4gICAgICAgICAgICBBUEkudHJpZ2dlckV2ZW50KFwiaW5jb21pbmdNZXNzYWdlXCIsXG4gICAgICAgICAgICAgICAge1wiZnJvbVwiOiBmcm9tLCBcIm5pY2tcIjogbmljaywgXCJtZXNzYWdlXCI6IHR4dH0pO1xuICAgIH0pO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTVVDX0xFRlQsIGZ1bmN0aW9uIChqaWQpIHtcbiAgICAgICAgQVBJLnRyaWdnZXJFdmVudChcInBhcnRpY2lwYW50TGVmdFwiLCB7amlkOiBqaWR9KTtcbiAgICB9KTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLkRJU1BMQVlfTkFNRV9DSEFOR0VELCBmdW5jdGlvbiAoamlkLCBuZXdEaXNwbGF5TmFtZSkge1xuICAgICAgICBuYW1lID0gZGlzcGxheU5hbWVbamlkXTtcbiAgICAgICAgaWYoIW5hbWUgfHwgbmFtZSAhPSBuZXdEaXNwbGF5TmFtZSkge1xuICAgICAgICAgICAgQVBJLnRyaWdnZXJFdmVudChcImRpc3BsYXlOYW1lQ2hhbmdlXCIsIHtqaWQ6IGppZCwgZGlzcGxheW5hbWU6IG5ld0Rpc3BsYXlOYW1lfSk7XG4gICAgICAgICAgICBkaXNwbGF5TmFtZVtqaWRdID0gbmV3RGlzcGxheU5hbWU7XG4gICAgICAgIH1cbiAgICB9KTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLlNFTkRJTkdfQ0hBVF9NRVNTQUdFLCBmdW5jdGlvbiAoYm9keSkge1xuICAgICAgICBBUFAuQVBJLnRyaWdnZXJFdmVudChcIm91dGdvaW5nTWVzc2FnZVwiLCB7XCJtZXNzYWdlXCI6IGJvZHl9KTtcbiAgICB9KTtcbn1cblxudmFyIEFQSSA9IHtcbiAgICAvKipcbiAgICAgKiBDaGVjayB3aGV0aGVyIHRoZSBBUEkgc2hvdWxkIGJlIGVuYWJsZWQgb3Igbm90LlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgICAqL1xuICAgIGlzRW5hYmxlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgaGFzaCA9IGxvY2F0aW9uLmhhc2g7XG4gICAgICAgIGlmKGhhc2ggJiYgaGFzaC5pbmRleE9mKFwiZXh0ZXJuYWxcIikgPiAtMSAmJiB3aW5kb3cucG9zdE1lc3NhZ2UpXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0sXG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZXMgdGhlIEFQSUNvbm5lY3Rvci4gU2V0dXBzIG1lc3NhZ2UgZXZlbnQgbGlzdGVuZXJzIHRoYXQgd2lsbFxuICAgICAqIHJlY2VpdmUgaW5mb3JtYXRpb24gZnJvbSBleHRlcm5hbCBhcHBsaWNhdGlvbnMgdGhhdCBlbWJlZCBKaXRzaSBNZWV0LlxuICAgICAqIEl0IGFsc28gc2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBleHRlcm5hbCBhcHBsaWNhdGlvbiB0aGF0IEFQSUNvbm5lY3RvclxuICAgICAqIGlzIGluaXRpYWxpemVkLlxuICAgICAqL1xuICAgIGluaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKVxuICAgICAgICB7XG4gICAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsXG4gICAgICAgICAgICAgICAgcHJvY2Vzc01lc3NhZ2UsIGZhbHNlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHdpbmRvdy5hdHRhY2hFdmVudCgnb25tZXNzYWdlJywgcHJvY2Vzc01lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICAgIHNlbmRNZXNzYWdlKHt0eXBlOiBcInN5c3RlbVwiLCBsb2FkZWQ6IHRydWV9KTtcbiAgICAgICAgc2V0dXBMaXN0ZW5lcnMoKTtcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIHRoZSBldmVudCBpcyBlbmFibGVkIG90IG5vdC5cbiAgICAgKiBAcGFyYW0gbmFtZSB0aGUgbmFtZSBvZiB0aGUgZXZlbnQuXG4gICAgICogQHJldHVybnMgeyp9XG4gICAgICovXG4gICAgaXNFdmVudEVuYWJsZWQ6IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIHJldHVybiBldmVudHNbbmFtZV07XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFNlbmRzIGV2ZW50IG9iamVjdCB0byB0aGUgZXh0ZXJuYWwgYXBwbGljYXRpb24gdGhhdCBoYXMgYmVlbiBzdWJzY3JpYmVkXG4gICAgICogZm9yIHRoYXQgZXZlbnQuXG4gICAgICogQHBhcmFtIG5hbWUgdGhlIG5hbWUgZXZlbnRcbiAgICAgKiBAcGFyYW0gb2JqZWN0IGRhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBldmVudFxuICAgICAqL1xuICAgIHRyaWdnZXJFdmVudDogZnVuY3Rpb24gKG5hbWUsIG9iamVjdCkge1xuICAgICAgICBpZih0aGlzLmlzRW5hYmxlZCgpICYmIHRoaXMuaXNFdmVudEVuYWJsZWQobmFtZSkpXG4gICAgICAgICAgICBzZW5kTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgdHlwZTogXCJldmVudFwiLCBhY3Rpb246IFwicmVzdWx0XCIsIGV2ZW50OiBuYW1lLCByZXN1bHQ6IG9iamVjdH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIHRoZSBsaXN0ZW5lcnMuXG4gICAgICovXG4gICAgZGlzcG9zZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZih3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcilcbiAgICAgICAge1xuICAgICAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsXG4gICAgICAgICAgICAgICAgcHJvY2Vzc01lc3NhZ2UsIGZhbHNlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHdpbmRvdy5kZXRhY2hFdmVudCgnb25tZXNzYWdlJywgcHJvY2Vzc01lc3NhZ2UpO1xuICAgICAgICB9XG5cbiAgICB9XG5cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBUEk7IiwiLyogZ2xvYmFsIFN0cm9waGUsIGZvY3VzZWRWaWRlb1NyYyovXG5cbi8vIGNhY2hlIGRhdGFjaGFubmVscyB0byBhdm9pZCBnYXJiYWdlIGNvbGxlY3Rpb25cbi8vIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00MDU1NDVcbnZhciBSVENFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvUlRDRXZlbnRzXCIpO1xuXG52YXIgX2RhdGFDaGFubmVscyA9IFtdO1xudmFyIGV2ZW50RW1pdHRlciA9IG51bGw7XG5cblxuXG5cbnZhciBEYXRhQ2hhbm5lbHMgPVxue1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGJhY2sgdHJpZ2dlcmVkIGJ5IFBlZXJDb25uZWN0aW9uIHdoZW4gbmV3IGRhdGEgY2hhbm5lbCBpcyBvcGVuZWRcbiAgICAgKiBvbiB0aGUgYnJpZGdlLlxuICAgICAqIEBwYXJhbSBldmVudCB0aGUgZXZlbnQgaW5mbyBvYmplY3QuXG4gICAgICovXG5cbiAgICBvbkRhdGFDaGFubmVsOiBmdW5jdGlvbiAoZXZlbnQpXG4gICAge1xuICAgICAgICB2YXIgZGF0YUNoYW5uZWwgPSBldmVudC5jaGFubmVsO1xuXG4gICAgICAgIGRhdGFDaGFubmVsLm9ub3BlbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkRhdGEgY2hhbm5lbCBvcGVuZWQgYnkgdGhlIFZpZGVvYnJpZGdlIVwiLCBkYXRhQ2hhbm5lbCk7XG5cbiAgICAgICAgICAgIC8vIENvZGUgc2FtcGxlIGZvciBzZW5kaW5nIHN0cmluZyBhbmQvb3IgYmluYXJ5IGRhdGFcbiAgICAgICAgICAgIC8vIFNlbmRzIFN0cmluZyBtZXNzYWdlIHRvIHRoZSBicmlkZ2VcbiAgICAgICAgICAgIC8vZGF0YUNoYW5uZWwuc2VuZChcIkhlbGxvIGJyaWRnZSFcIik7XG4gICAgICAgICAgICAvLyBTZW5kcyAxMiBieXRlcyBiaW5hcnkgbWVzc2FnZSB0byB0aGUgYnJpZGdlXG4gICAgICAgICAgICAvL2RhdGFDaGFubmVsLnNlbmQobmV3IEFycmF5QnVmZmVyKDEyKSk7XG5cbiAgICAgICAgICAgIC8vIHdoZW4gdGhlIGRhdGEgY2hhbm5lbCBiZWNvbWVzIGF2YWlsYWJsZSwgdGVsbCB0aGUgYnJpZGdlIGFib3V0IHZpZGVvXG4gICAgICAgICAgICAvLyBzZWxlY3Rpb25zIHNvIHRoYXQgaXQgY2FuIGRvIGFkYXB0aXZlIHNpbXVsY2FzdCxcbiAgICAgICAgICAgIC8vIHdlIHdhbnQgdGhlIG5vdGlmaWNhdGlvbiB0byB0cmlnZ2VyIGV2ZW4gaWYgdXNlckppZCBpcyB1bmRlZmluZWQsXG4gICAgICAgICAgICAvLyBvciBudWxsLlxuICAgICAgICAgICAgdmFyIHVzZXJKaWQgPSBBUFAuVUkuZ2V0TGFyZ2VWaWRlb1N0YXRlKCkudXNlclJlc291cmNlSmlkO1xuICAgICAgICAgICAgLy8gd2Ugd2FudCB0aGUgbm90aWZpY2F0aW9uIHRvIHRyaWdnZXIgZXZlbiBpZiB1c2VySmlkIGlzIHVuZGVmaW5lZCxcbiAgICAgICAgICAgIC8vIG9yIG51bGwuXG4gICAgICAgICAgICBvblNlbGVjdGVkRW5kcG9pbnRDaGFuZ2VkKHVzZXJKaWQpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGRhdGFDaGFubmVsLm9uZXJyb3IgPSBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJEYXRhIENoYW5uZWwgRXJyb3I6XCIsIGVycm9yLCBkYXRhQ2hhbm5lbCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgZGF0YUNoYW5uZWwub25tZXNzYWdlID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICB2YXIgZGF0YSA9IGV2ZW50LmRhdGE7XG4gICAgICAgICAgICAvLyBKU09OXG4gICAgICAgICAgICB2YXIgb2JqO1xuXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIG9iaiA9IEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIFwiRmFpbGVkIHRvIHBhcnNlIGRhdGEgY2hhbm5lbCBtZXNzYWdlIGFzIEpTT046IFwiLFxuICAgICAgICAgICAgICAgICAgICBkYXRhLFxuICAgICAgICAgICAgICAgICAgICBkYXRhQ2hhbm5lbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoKCd1bmRlZmluZWQnICE9PSB0eXBlb2Yob2JqKSkgJiYgKG51bGwgIT09IG9iaikpIHtcbiAgICAgICAgICAgICAgICB2YXIgY29saWJyaUNsYXNzID0gb2JqLmNvbGlicmlDbGFzcztcblxuICAgICAgICAgICAgICAgIGlmIChcIkRvbWluYW50U3BlYWtlckVuZHBvaW50Q2hhbmdlRXZlbnRcIiA9PT0gY29saWJyaUNsYXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEVuZHBvaW50IElEIGZyb20gdGhlIFZpZGVvYnJpZGdlLlxuICAgICAgICAgICAgICAgICAgICB2YXIgZG9taW5hbnRTcGVha2VyRW5kcG9pbnQgPSBvYmouZG9taW5hbnRTcGVha2VyRW5kcG9pbnQ7XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJEYXRhIGNoYW5uZWwgbmV3IGRvbWluYW50IHNwZWFrZXIgZXZlbnQ6IFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgZG9taW5hbnRTcGVha2VyRW5kcG9pbnQpO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChSVENFdmVudHMuRE9NSU5BTlRTUEVBS0VSX0NIQU5HRUQsIGRvbWluYW50U3BlYWtlckVuZHBvaW50KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoXCJJbkxhc3ROQ2hhbmdlRXZlbnRcIiA9PT0gY29saWJyaUNsYXNzKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZFZhbHVlID0gb2JqLm9sZFZhbHVlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgbmV3VmFsdWUgPSBvYmoubmV3VmFsdWU7XG4gICAgICAgICAgICAgICAgICAgIC8vIE1ha2Ugc3VyZSB0aGF0IG9sZFZhbHVlIGFuZCBuZXdWYWx1ZSBhcmUgb2YgdHlwZSBib29sZWFuLlxuICAgICAgICAgICAgICAgICAgICB2YXIgdHlwZTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoKHR5cGUgPSB0eXBlb2Ygb2xkVmFsdWUpICE9PSAnYm9vbGVhbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFZhbHVlID0gKG9sZFZhbHVlID09IFwidHJ1ZVwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkVmFsdWUgPSBuZXcgQm9vbGVhbihvbGRWYWx1ZSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmICgodHlwZSA9IHR5cGVvZiBuZXdWYWx1ZSkgIT09ICdib29sZWFuJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3VmFsdWUgPSAobmV3VmFsdWUgPT0gXCJ0cnVlXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdWYWx1ZSA9IG5ldyBCb29sZWFuKG5ld1ZhbHVlKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChSVENFdmVudHMuTEFTVE5fQ0hBTkdFRCwgb2xkVmFsdWUsIG5ld1ZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoXCJMYXN0TkVuZHBvaW50c0NoYW5nZUV2ZW50XCIgPT09IGNvbGlicmlDbGFzcylcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZSBuZXcvbGF0ZXN0IGxpc3Qgb2YgbGFzdC1uIGVuZHBvaW50IElEcy5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGxhc3RORW5kcG9pbnRzID0gb2JqLmxhc3RORW5kcG9pbnRzO1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGUgbGlzdCBvZiBlbmRwb2ludCBJRHMgd2hpY2ggYXJlIGVudGVyaW5nIHRoZSBsaXN0IG9mXG4gICAgICAgICAgICAgICAgICAgIC8vIGxhc3QtbiBhdCB0aGlzIHRpbWUgaS5lLiB3ZXJlIG5vdCBpbiB0aGUgb2xkIGxpc3Qgb2YgbGFzdC1uXG4gICAgICAgICAgICAgICAgICAgIC8vIGVuZHBvaW50IElEcy5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGVuZHBvaW50c0VudGVyaW5nTGFzdE4gPSBvYmouZW5kcG9pbnRzRW50ZXJpbmdMYXN0TjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHN0cmVhbSA9IG9iai5zdHJlYW07XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgICAgICAgICBcIkRhdGEgY2hhbm5lbCBuZXcgbGFzdC1uIGV2ZW50OiBcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RORW5kcG9pbnRzLCBlbmRwb2ludHNFbnRlcmluZ0xhc3ROLCBvYmopO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChSVENFdmVudHMuTEFTVE5fRU5EUE9JTlRfQ0hBTkdFRCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RORW5kcG9pbnRzLCBlbmRwb2ludHNFbnRlcmluZ0xhc3ROLCBvYmopO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChcIlNpbXVsY2FzdExheWVyc0NoYW5nZWRFdmVudFwiID09PSBjb2xpYnJpQ2xhc3MpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChSVENFdmVudHMuU0lNVUxDQVNUX0xBWUVSX0NIQU5HRUQsXG4gICAgICAgICAgICAgICAgICAgICAgICBvYmouZW5kcG9pbnRTaW11bGNhc3RMYXllcnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChcIlNpbXVsY2FzdExheWVyc0NoYW5naW5nRXZlbnRcIiA9PT0gY29saWJyaUNsYXNzKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoUlRDRXZlbnRzLlNJTVVMQ0FTVF9MQVlFUl9DSEFOR0lORyxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9iai5lbmRwb2ludFNpbXVsY2FzdExheWVycyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKFwiU3RhcnRTaW11bGNhc3RMYXllckV2ZW50XCIgPT09IGNvbGlicmlDbGFzcylcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFJUQ0V2ZW50cy5TSU1VTENBU1RfU1RBUlQsIG9iai5zaW11bGNhc3RMYXllcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKFwiU3RvcFNpbXVsY2FzdExheWVyRXZlbnRcIiA9PT0gY29saWJyaUNsYXNzKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoUlRDRXZlbnRzLlNJTVVMQ0FTVF9TVE9QLCBvYmouc2ltdWxjYXN0TGF5ZXIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmRlYnVnKFwiRGF0YSBjaGFubmVsIEpTT04tZm9ybWF0dGVkIG1lc3NhZ2U6IFwiLCBvYmopO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBkYXRhQ2hhbm5lbC5vbmNsb3NlID0gZnVuY3Rpb24gKClcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiVGhlIERhdGEgQ2hhbm5lbCBjbG9zZWRcIiwgZGF0YUNoYW5uZWwpO1xuICAgICAgICAgICAgdmFyIGlkeCA9IF9kYXRhQ2hhbm5lbHMuaW5kZXhPZihkYXRhQ2hhbm5lbCk7XG4gICAgICAgICAgICBpZiAoaWR4ID4gLTEpXG4gICAgICAgICAgICAgICAgX2RhdGFDaGFubmVscyA9IF9kYXRhQ2hhbm5lbHMuc3BsaWNlKGlkeCwgMSk7XG4gICAgICAgIH07XG4gICAgICAgIF9kYXRhQ2hhbm5lbHMucHVzaChkYXRhQ2hhbm5lbCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEJpbmRzIFwib25kYXRhY2hhbm5lbFwiIGV2ZW50IGxpc3RlbmVyIHRvIGdpdmVuIFBlZXJDb25uZWN0aW9uIGluc3RhbmNlLlxuICAgICAqIEBwYXJhbSBwZWVyQ29ubmVjdGlvbiBXZWJSVEMgcGVlciBjb25uZWN0aW9uIGluc3RhbmNlLlxuICAgICAqL1xuICAgIGluaXQ6IGZ1bmN0aW9uIChwZWVyQ29ubmVjdGlvbiwgZW1pdHRlcikge1xuICAgICAgICBpZighY29uZmlnLm9wZW5TY3RwKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHBlZXJDb25uZWN0aW9uLm9uZGF0YWNoYW5uZWwgPSB0aGlzLm9uRGF0YUNoYW5uZWw7XG4gICAgICAgIGV2ZW50RW1pdHRlciA9IGVtaXR0ZXI7XG5cbiAgICAgICAgLy8gU2FtcGxlIGNvZGUgZm9yIG9wZW5pbmcgbmV3IGRhdGEgY2hhbm5lbCBmcm9tIEppdHNpIE1lZXQgdG8gdGhlIGJyaWRnZS5cbiAgICAgICAgLy8gQWx0aG91Z2ggaXQncyBub3QgYSByZXF1aXJlbWVudCB0byBvcGVuIHNlcGFyYXRlIGNoYW5uZWxzIGZyb20gYm90aCBicmlkZ2VcbiAgICAgICAgLy8gYW5kIHBlZXIgYXMgc2luZ2xlIGNoYW5uZWwgY2FuIGJlIHVzZWQgZm9yIHNlbmRpbmcgYW5kIHJlY2VpdmluZyBkYXRhLlxuICAgICAgICAvLyBTbyBlaXRoZXIgY2hhbm5lbCBvcGVuZWQgYnkgdGhlIGJyaWRnZSBvciB0aGUgb25lIG9wZW5lZCBoZXJlIGlzIGVub3VnaFxuICAgICAgICAvLyBmb3IgY29tbXVuaWNhdGlvbiB3aXRoIHRoZSBicmlkZ2UuXG4gICAgICAgIC8qdmFyIGRhdGFDaGFubmVsT3B0aW9ucyA9XG4gICAgICAgICB7XG4gICAgICAgICByZWxpYWJsZTogdHJ1ZVxuICAgICAgICAgfTtcbiAgICAgICAgIHZhciBkYXRhQ2hhbm5lbFxuICAgICAgICAgPSBwZWVyQ29ubmVjdGlvbi5jcmVhdGVEYXRhQ2hhbm5lbChcIm15Q2hhbm5lbFwiLCBkYXRhQ2hhbm5lbE9wdGlvbnMpO1xuXG4gICAgICAgICAvLyBDYW4gYmUgdXNlZCBvbmx5IHdoZW4gaXMgaW4gb3BlbiBzdGF0ZVxuICAgICAgICAgZGF0YUNoYW5uZWwub25vcGVuID0gZnVuY3Rpb24gKClcbiAgICAgICAgIHtcbiAgICAgICAgIGRhdGFDaGFubmVsLnNlbmQoXCJNeSBjaGFubmVsICEhIVwiKTtcbiAgICAgICAgIH07XG4gICAgICAgICBkYXRhQ2hhbm5lbC5vbm1lc3NhZ2UgPSBmdW5jdGlvbiAoZXZlbnQpXG4gICAgICAgICB7XG4gICAgICAgICB2YXIgbXNnRGF0YSA9IGV2ZW50LmRhdGE7XG4gICAgICAgICBjb25zb2xlLmluZm8oXCJHb3QgTXkgRGF0YSBDaGFubmVsIE1lc3NhZ2U6XCIsIG1zZ0RhdGEsIGRhdGFDaGFubmVsKTtcbiAgICAgICAgIH07Ki9cbiAgICB9LFxuICAgIGhhbmRsZVNlbGVjdGVkRW5kcG9pbnRFdmVudDogb25TZWxlY3RlZEVuZHBvaW50Q2hhbmdlZCxcbiAgICBoYW5kbGVQaW5uZWRFbmRwb2ludEV2ZW50OiBvblBpbm5lZEVuZHBvaW50Q2hhbmdlZFxuXG59O1xuXG5mdW5jdGlvbiBvblNlbGVjdGVkRW5kcG9pbnRDaGFuZ2VkKHVzZXJSZXNvdXJjZSlcbntcbiAgICBjb25zb2xlLmxvZygnc2VsZWN0ZWQgZW5kcG9pbnQgY2hhbmdlZDogJywgdXNlclJlc291cmNlKTtcbiAgICBpZiAoX2RhdGFDaGFubmVscyAmJiBfZGF0YUNoYW5uZWxzLmxlbmd0aCAhPSAwKVxuICAgIHtcbiAgICAgICAgX2RhdGFDaGFubmVscy5zb21lKGZ1bmN0aW9uIChkYXRhQ2hhbm5lbCkge1xuICAgICAgICAgICAgaWYgKGRhdGFDaGFubmVsLnJlYWR5U3RhdGUgPT0gJ29wZW4nKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzZW5kaW5nIHNlbGVjdGVkIGVuZHBvaW50IGNoYW5nZWQgJyBcbiAgICAgICAgICAgICAgICAgICAgKyAnbm90aWZpY2F0aW9uIHRvIHRoZSBicmlkZ2U6ICcsIHVzZXJSZXNvdXJjZSk7XG4gICAgICAgICAgICAgICAgZGF0YUNoYW5uZWwuc2VuZChKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgICAgICdjb2xpYnJpQ2xhc3MnOiAnU2VsZWN0ZWRFbmRwb2ludENoYW5nZWRFdmVudCcsXG4gICAgICAgICAgICAgICAgICAgICdzZWxlY3RlZEVuZHBvaW50JzpcbiAgICAgICAgICAgICAgICAgICAgICAgICghdXNlclJlc291cmNlIHx8IHVzZXJSZXNvdXJjZSA9PT0gbnVsbCk/XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVsbCA6IHVzZXJSZXNvdXJjZVxuICAgICAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIG9uUGlubmVkRW5kcG9pbnRDaGFuZ2VkKHVzZXJSZXNvdXJjZSlcbntcbiAgICBjb25zb2xlLmxvZygncGlubmVkIGVuZHBvaW50IGNoYW5nZWQ6ICcsIHVzZXJSZXNvdXJjZSk7XG4gICAgaWYgKF9kYXRhQ2hhbm5lbHMgJiYgX2RhdGFDaGFubmVscy5sZW5ndGggIT0gMClcbiAgICB7XG4gICAgICAgIF9kYXRhQ2hhbm5lbHMuc29tZShmdW5jdGlvbiAoZGF0YUNoYW5uZWwpIHtcbiAgICAgICAgICAgIGlmIChkYXRhQ2hhbm5lbC5yZWFkeVN0YXRlID09ICdvcGVuJylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBkYXRhQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgJ2NvbGlicmlDbGFzcyc6ICdQaW5uZWRFbmRwb2ludENoYW5nZWRFdmVudCcsXG4gICAgICAgICAgICAgICAgICAgICdwaW5uZWRFbmRwb2ludCc6XG4gICAgICAgICAgICAgICAgICAgICAgICAoIXVzZXJSZXNvdXJjZSB8fCB1c2VyUmVzb3VyY2UgPT0gbnVsbCk/XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVsbCA6IHVzZXJSZXNvdXJjZVxuICAgICAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gRGF0YUNoYW5uZWxzO1xuXG4iLCJ2YXIgU3RyZWFtRXZlbnRUeXBlcyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9TdHJlYW1FdmVudFR5cGVzLmpzXCIpO1xuXG5cbmZ1bmN0aW9uIExvY2FsU3RyZWFtKHN0cmVhbSwgdHlwZSwgZXZlbnRFbWl0dGVyLCB2aWRlb1R5cGUpXG57XG4gICAgdGhpcy5zdHJlYW0gPSBzdHJlYW07XG4gICAgdGhpcy5ldmVudEVtaXR0ZXIgPSBldmVudEVtaXR0ZXI7XG4gICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICB0aGlzLnZpZGVvVHlwZSA9IHZpZGVvVHlwZTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgaWYodHlwZSA9PSBcImF1ZGlvXCIpXG4gICAge1xuICAgICAgICB0aGlzLmdldFRyYWNrcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZWxmLnN0cmVhbS5nZXRBdWRpb1RyYWNrcygpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgICB0aGlzLmdldFRyYWNrcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZWxmLnN0cmVhbS5nZXRWaWRlb1RyYWNrcygpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHRoaXMuc3RyZWFtLm9uZW5kZWQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICBzZWxmLnN0cmVhbUVuZGVkKCk7XG4gICAgfTtcbn1cblxuTG9jYWxTdHJlYW0ucHJvdG90eXBlLnN0cmVhbUVuZGVkID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZXZlbnRFbWl0dGVyLmVtaXQoU3RyZWFtRXZlbnRUeXBlcy5FVkVOVF9UWVBFX0xPQ0FMX0VOREVELCB0aGlzKTtcbn1cblxuTG9jYWxTdHJlYW0ucHJvdG90eXBlLmdldE9yaWdpbmFsU3RyZWFtID0gZnVuY3Rpb24oKVxue1xuICAgIHJldHVybiB0aGlzLnN0cmVhbTtcbn1cblxuTG9jYWxTdHJlYW0ucHJvdG90eXBlLmlzQXVkaW9TdHJlYW0gPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICh0aGlzLnN0cmVhbS5nZXRBdWRpb1RyYWNrcygpICYmIHRoaXMuc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkubGVuZ3RoID4gMCk7XG59O1xuXG5Mb2NhbFN0cmVhbS5wcm90b3R5cGUubXV0ZSA9IGZ1bmN0aW9uKClcbntcbiAgICB2YXIgaXNtdXRlZCA9IGZhbHNlO1xuICAgIHZhciB0cmFja3MgPSB0aGlzLmdldFRyYWNrcygpO1xuXG4gICAgZm9yICh2YXIgaWR4ID0gMDsgaWR4IDwgdHJhY2tzLmxlbmd0aDsgaWR4KyspIHtcbiAgICAgICAgaXNtdXRlZCA9ICF0cmFja3NbaWR4XS5lbmFibGVkO1xuICAgICAgICB0cmFja3NbaWR4XS5lbmFibGVkID0gaXNtdXRlZDtcbiAgICB9XG4gICAgcmV0dXJuIGlzbXV0ZWQ7XG59O1xuXG5Mb2NhbFN0cmVhbS5wcm90b3R5cGUuc2V0TXV0ZSA9IGZ1bmN0aW9uKG11dGUpXG57XG5cbiAgICBpZih3aW5kb3cubG9jYXRpb24ucHJvdG9jb2wgIT0gXCJodHRwczpcIiB8fFxuICAgICAgICB0aGlzLmlzQXVkaW9TdHJlYW0oKSB8fCB0aGlzLnZpZGVvVHlwZSA9PT0gXCJzY3JlZW5cIilcbiAgICB7XG4gICAgICAgIHZhciB0cmFja3MgPSB0aGlzLmdldFRyYWNrcygpO1xuXG4gICAgICAgIGZvciAodmFyIGlkeCA9IDA7IGlkeCA8IHRyYWNrcy5sZW5ndGg7IGlkeCsrKSB7XG4gICAgICAgICAgICB0cmFja3NbaWR4XS5lbmFibGVkID0gbXV0ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgICBpZihtdXRlID09PSBmYWxzZSkge1xuICAgICAgICAgICAgQVBQLnhtcHAucmVtb3ZlU3RyZWFtKHRoaXMuc3RyZWFtKTtcbiAgICAgICAgICAgIHRoaXMuc3RyZWFtLnN0b3AoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIEFQUC5SVEMucnRjVXRpbHMub2J0YWluQXVkaW9BbmRWaWRlb1Blcm1pc3Npb25zKFtcInZpZGVvXCJdLFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5jaGFuZ2VMb2NhbFZpZGVvKHN0cmVhbSwgZmFsc2UsIGZ1bmN0aW9uICgpIHt9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbkxvY2FsU3RyZWFtLnByb3RvdHlwZS5pc011dGVkID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciB0cmFja3MgPSBbXTtcbiAgICBpZih0aGlzLnR5cGUgPT0gXCJhdWRpb1wiKVxuICAgIHtcbiAgICAgICAgdHJhY2tzID0gdGhpcy5zdHJlYW0uZ2V0QXVkaW9UcmFja3MoKTtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgaWYodGhpcy5zdHJlYW0uZW5kZWQpXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgdHJhY2tzID0gdGhpcy5zdHJlYW0uZ2V0VmlkZW9UcmFja3MoKTtcbiAgICB9XG4gICAgZm9yICh2YXIgaWR4ID0gMDsgaWR4IDwgdHJhY2tzLmxlbmd0aDsgaWR4KyspIHtcbiAgICAgICAgaWYodHJhY2tzW2lkeF0uZW5hYmxlZClcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5cbkxvY2FsU3RyZWFtLnByb3RvdHlwZS5nZXRJZCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdHJlYW0uZ2V0VHJhY2tzKClbMF0uaWQ7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTG9jYWxTdHJlYW07XG4iLCIvLy8vVGhlc2UgbGluZXMgc2hvdWxkIGJlIHVuY29tbWVudGVkIHdoZW4gcmVxdWlyZSB3b3JrcyBpbiBhcHAuanNcbnZhciBNZWRpYVN0cmVhbVR5cGUgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvTWVkaWFTdHJlYW1UeXBlc1wiKTtcbnZhciBTdHJlYW1FdmVudFR5cGUgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvU3RyZWFtRXZlbnRUeXBlc1wiKTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgTWVkaWFTdHJlYW0gb2JqZWN0IGZvciB0aGUgZ2l2ZW4gZGF0YSwgc2Vzc2lvbiBpZCBhbmQgc3NyYy5cbiAqIEl0IGlzIGEgd3JhcHBlciBjbGFzcyBmb3IgdGhlIE1lZGlhU3RyZWFtLlxuICpcbiAqIEBwYXJhbSBkYXRhIHRoZSBkYXRhIG9iamVjdCBmcm9tIHdoaWNoIHdlIG9idGFpbiB0aGUgc3RyZWFtLFxuICogdGhlIHBlZXJqaWQsIGV0Yy5cbiAqIEBwYXJhbSBzaWQgdGhlIHNlc3Npb24gaWRcbiAqIEBwYXJhbSBzc3JjIHRoZSBzc3JjIGNvcnJlc3BvbmRpbmcgdG8gdGhpcyBNZWRpYVN0cmVhbVxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBNZWRpYVN0cmVhbShkYXRhLCBzaWQsIHNzcmMsIGJyb3dzZXIsIGV2ZW50RW1pdHRlcikge1xuXG4gICAgLy8gWFhYKGdwKSB0byBtaW5pbWl6ZSBoZWFkYWNoZXMgaW4gdGhlIGZ1dHVyZSwgd2Ugc2hvdWxkIGJ1aWxkIG91clxuICAgIC8vIGFic3RyYWN0aW9ucyBhcm91bmQgdHJhY2tzIGFuZCBub3Qgc3RyZWFtcy4gT1JUQyBpcyB0cmFjayBiYXNlZCBBUEkuXG4gICAgLy8gTW96aWxsYSBleHBlY3RzIG0tbGluZXMgdG8gcmVwcmVzZW50IG1lZGlhIHRyYWNrcy5cbiAgICAvL1xuICAgIC8vIFByYWN0aWNhbGx5LCB3aGF0IEknbSBzYXlpbmcgaXMgdGhhdCB3ZSBzaG91bGQgaGF2ZSBhIE1lZGlhVHJhY2sgY2xhc3NcbiAgICAvLyBhbmQgbm90IGEgTWVkaWFTdHJlYW0gY2xhc3MuXG4gICAgLy9cbiAgICAvLyBBbHNvLCB3ZSBzaG91bGQgYmUgYWJsZSB0byBhc3NvY2lhdGUgbXVsdGlwbGUgU1NSQ3Mgd2l0aCBhIE1lZGlhVHJhY2sgYXNcbiAgICAvLyBhIHRyYWNrIG1pZ2h0IGhhdmUgYW4gYXNzb2NpYXRlZCBSVFggYW5kIEZFQyBzb3VyY2VzLlxuXG4gICAgdGhpcy5zaWQgPSBzaWQ7XG4gICAgdGhpcy5zdHJlYW0gPSBkYXRhLnN0cmVhbTtcbiAgICB0aGlzLnBlZXJqaWQgPSBkYXRhLnBlZXJqaWQ7XG4gICAgdGhpcy5zc3JjID0gc3NyYztcbiAgICB0aGlzLnR5cGUgPSAodGhpcy5zdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGggPiAwKT9cbiAgICAgICAgTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEUgOiBNZWRpYVN0cmVhbVR5cGUuQVVESU9fVFlQRTtcbiAgICB0aGlzLnZpZGVvVHlwZSA9IG51bGw7XG4gICAgdGhpcy5tdXRlZCA9IGZhbHNlO1xuICAgIHRoaXMuZXZlbnRFbWl0dGVyID0gZXZlbnRFbWl0dGVyO1xufVxuXG5cbk1lZGlhU3RyZWFtLnByb3RvdHlwZS5nZXRPcmlnaW5hbFN0cmVhbSA9IGZ1bmN0aW9uKClcbntcbiAgICByZXR1cm4gdGhpcy5zdHJlYW07XG59O1xuXG5NZWRpYVN0cmVhbS5wcm90b3R5cGUuc2V0TXV0ZSA9IGZ1bmN0aW9uICh2YWx1ZSlcbntcbiAgICB0aGlzLnN0cmVhbS5tdXRlZCA9IHZhbHVlO1xuICAgIHRoaXMubXV0ZWQgPSB2YWx1ZTtcbn07XG5cbk1lZGlhU3RyZWFtLnByb3RvdHlwZS5zZXRWaWRlb1R5cGUgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICBpZih0aGlzLnZpZGVvVHlwZSA9PT0gdmFsdWUpXG4gICAgICAgIHJldHVybjtcbiAgICB0aGlzLnZpZGVvVHlwZSA9IHZhbHVlO1xuICAgIHRoaXMuZXZlbnRFbWl0dGVyLmVtaXQoU3RyZWFtRXZlbnRUeXBlLkVWRU5UX1RZUEVfUkVNT1RFX0NIQU5HRUQsXG4gICAgICAgIHRoaXMucGVlcmppZCk7XG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gTWVkaWFTdHJlYW07XG4iLCJ2YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcImV2ZW50c1wiKTtcbnZhciBSVENVdGlscyA9IHJlcXVpcmUoXCIuL1JUQ1V0aWxzLmpzXCIpO1xudmFyIExvY2FsU3RyZWFtID0gcmVxdWlyZShcIi4vTG9jYWxTdHJlYW0uanNcIik7XG52YXIgRGF0YUNoYW5uZWxzID0gcmVxdWlyZShcIi4vRGF0YUNoYW5uZWxzXCIpO1xudmFyIE1lZGlhU3RyZWFtID0gcmVxdWlyZShcIi4vTWVkaWFTdHJlYW0uanNcIik7XG52YXIgRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzXG4gICAgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9kZXNrdG9wc2hhcmluZy9EZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXNcIik7XG52YXIgTWVkaWFTdHJlYW1UeXBlID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL01lZGlhU3RyZWFtVHlwZXNcIik7XG52YXIgU3RyZWFtRXZlbnRUeXBlcyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9TdHJlYW1FdmVudFR5cGVzLmpzXCIpO1xudmFyIFJUQ0V2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9SVENFdmVudHMuanNcIik7XG52YXIgWE1QUEV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL3htcHAvWE1QUEV2ZW50c1wiKTtcbnZhciBVSUV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1VJL1VJRXZlbnRzXCIpO1xuXG52YXIgZXZlbnRFbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG52YXIgUlRDID0ge1xuICAgIHJ0Y1V0aWxzOiBudWxsLFxuICAgIGRldmljZXM6IHtcbiAgICAgICAgYXVkaW86IGZhbHNlLFxuICAgICAgICB2aWRlbzogZmFsc2VcbiAgICB9LFxuICAgIGxvY2FsU3RyZWFtczogW10sXG4gICAgcmVtb3RlU3RyZWFtczoge30sXG4gICAgbG9jYWxBdWRpbzogbnVsbCxcbiAgICBsb2NhbFZpZGVvOiBudWxsLFxuICAgIGFkZFN0cmVhbUxpc3RlbmVyOiBmdW5jdGlvbiAobGlzdGVuZXIsIGV2ZW50VHlwZSkge1xuICAgICAgICBldmVudEVtaXR0ZXIub24oZXZlbnRUeXBlLCBsaXN0ZW5lcik7XG4gICAgfSxcbiAgICBhZGRMaXN0ZW5lcjogZnVuY3Rpb24gKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5vbih0eXBlLCBsaXN0ZW5lcik7XG4gICAgfSxcbiAgICByZW1vdmVTdHJlYW1MaXN0ZW5lcjogZnVuY3Rpb24gKGxpc3RlbmVyLCBldmVudFR5cGUpIHtcbiAgICAgICAgaWYoIShldmVudFR5cGUgaW5zdGFuY2VvZiBTdHJlYW1FdmVudFR5cGVzKSlcbiAgICAgICAgICAgIHRocm93IFwiSWxsZWdhbCBhcmd1bWVudFwiO1xuXG4gICAgICAgIGV2ZW50RW1pdHRlci5yZW1vdmVMaXN0ZW5lcihldmVudFR5cGUsIGxpc3RlbmVyKTtcbiAgICB9LFxuICAgIGNyZWF0ZUxvY2FsU3RyZWFtOiBmdW5jdGlvbiAoc3RyZWFtLCB0eXBlLCBjaGFuZ2UsIHZpZGVvVHlwZSkge1xuXG4gICAgICAgIHZhciBsb2NhbFN0cmVhbSA9ICBuZXcgTG9jYWxTdHJlYW0oc3RyZWFtLCB0eXBlLCBldmVudEVtaXR0ZXIsIHZpZGVvVHlwZSk7XG4gICAgICAgIC8vaW4gZmlyZWZveCB3ZSBoYXZlIG9ubHkgb25lIHN0cmVhbSBvYmplY3RcbiAgICAgICAgaWYodGhpcy5sb2NhbFN0cmVhbXMubGVuZ3RoID09IDAgfHxcbiAgICAgICAgICAgIHRoaXMubG9jYWxTdHJlYW1zWzBdLmdldE9yaWdpbmFsU3RyZWFtKCkgIT0gc3RyZWFtKVxuICAgICAgICAgICAgdGhpcy5sb2NhbFN0cmVhbXMucHVzaChsb2NhbFN0cmVhbSk7XG5cbiAgICAgICAgaWYodHlwZSA9PSBcImF1ZGlvXCIpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMubG9jYWxBdWRpbyA9IGxvY2FsU3RyZWFtO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgdGhpcy5sb2NhbFZpZGVvID0gbG9jYWxTdHJlYW07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGV2ZW50VHlwZSA9IFN0cmVhbUV2ZW50VHlwZXMuRVZFTlRfVFlQRV9MT0NBTF9DUkVBVEVEO1xuICAgICAgICBpZihjaGFuZ2UpXG4gICAgICAgICAgICBldmVudFR5cGUgPSBTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfTE9DQUxfQ0hBTkdFRDtcblxuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChldmVudFR5cGUsIGxvY2FsU3RyZWFtKTtcbiAgICAgICAgcmV0dXJuIGxvY2FsU3RyZWFtO1xuICAgIH0sXG4gICAgcmVtb3ZlTG9jYWxTdHJlYW06IGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgZm9yKHZhciBpID0gMDsgaSA8IHRoaXMubG9jYWxTdHJlYW1zLmxlbmd0aDsgaSsrKVxuICAgICAgICB7XG4gICAgICAgICAgICBpZih0aGlzLmxvY2FsU3RyZWFtc1tpXS5nZXRPcmlnaW5hbFN0cmVhbSgpID09PSBzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5sb2NhbFN0cmVhbXNbaV07XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICBjcmVhdGVSZW1vdGVTdHJlYW06IGZ1bmN0aW9uIChkYXRhLCBzaWQsIHRoZXNzcmMpIHtcbiAgICAgICAgdmFyIHJlbW90ZVN0cmVhbSA9IG5ldyBNZWRpYVN0cmVhbShkYXRhLCBzaWQsIHRoZXNzcmMsXG4gICAgICAgICAgICB0aGlzLmdldEJyb3dzZXJUeXBlKCksIGV2ZW50RW1pdHRlcik7XG4gICAgICAgIHZhciBqaWQgPSBkYXRhLnBlZXJqaWQgfHwgQVBQLnhtcHAubXlKaWQoKTtcbiAgICAgICAgaWYoIXRoaXMucmVtb3RlU3RyZWFtc1tqaWRdKSB7XG4gICAgICAgICAgICB0aGlzLnJlbW90ZVN0cmVhbXNbamlkXSA9IHt9O1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucmVtb3RlU3RyZWFtc1tqaWRdW3JlbW90ZVN0cmVhbS50eXBlXT0gcmVtb3RlU3RyZWFtO1xuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfUkVNT1RFX0NSRUFURUQsIHJlbW90ZVN0cmVhbSk7XG4gICAgICAgIHJldHVybiByZW1vdGVTdHJlYW07XG4gICAgfSxcbiAgICBnZXRCcm93c2VyVHlwZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5ydGNVdGlscy5icm93c2VyO1xuICAgIH0sXG4gICAgZ2V0UENDb25zdHJhaW50czogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5ydGNVdGlscy5wY19jb25zdHJhaW50cztcbiAgICB9LFxuICAgIGdldFVzZXJNZWRpYVdpdGhDb25zdHJhaW50czpmdW5jdGlvbih1bSwgc3VjY2Vzc19jYWxsYmFjayxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFpbHVyZV9jYWxsYmFjaywgcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFuZHdpZHRoLCBmcHMsIGRlc2t0b3BTdHJlYW0pXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5ydGNVdGlscy5nZXRVc2VyTWVkaWFXaXRoQ29uc3RyYWludHModW0sIHN1Y2Nlc3NfY2FsbGJhY2ssXG4gICAgICAgICAgICBmYWlsdXJlX2NhbGxiYWNrLCByZXNvbHV0aW9uLCBiYW5kd2lkdGgsIGZwcywgZGVza3RvcFN0cmVhbSk7XG4gICAgfSxcbiAgICBhdHRhY2hNZWRpYVN0cmVhbTogIGZ1bmN0aW9uIChlbGVtZW50LCBzdHJlYW0pIHtcbiAgICAgICAgdGhpcy5ydGNVdGlscy5hdHRhY2hNZWRpYVN0cmVhbShlbGVtZW50LCBzdHJlYW0pO1xuICAgIH0sXG4gICAgZ2V0U3RyZWFtSUQ6ICBmdW5jdGlvbiAoc3RyZWFtKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ0Y1V0aWxzLmdldFN0cmVhbUlEKHN0cmVhbSk7XG4gICAgfSxcbiAgICBnZXRWaWRlb1NyYzogZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnRjVXRpbHMuZ2V0VmlkZW9TcmMoZWxlbWVudCk7XG4gICAgfSxcbiAgICBzZXRWaWRlb1NyYzogZnVuY3Rpb24gKGVsZW1lbnQsIHNyYykge1xuICAgICAgICB0aGlzLnJ0Y1V0aWxzLnNldFZpZGVvU3JjKGVsZW1lbnQsIHNyYyk7XG4gICAgfSxcbiAgICBkaXNwb3NlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKHRoaXMucnRjVXRpbHMpIHtcbiAgICAgICAgICAgIHRoaXMucnRjVXRpbHMgPSBudWxsO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzdG9wOiAgZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmRpc3Bvc2UoKTtcbiAgICB9LFxuICAgIHN0YXJ0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgQVBQLmRlc2t0b3BzaGFyaW5nLmFkZExpc3RlbmVyKFxuICAgICAgICAgICAgZnVuY3Rpb24gKHN0cmVhbSwgaXNVc2luZ1NjcmVlblN0cmVhbSwgY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICBzZWxmLmNoYW5nZUxvY2FsVmlkZW8oc3RyZWFtLCBpc1VzaW5nU2NyZWVuU3RyZWFtLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9LCBEZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXMuTkVXX1NUUkVBTV9DUkVBVEVEKTtcbiAgICAgICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5DSEFOR0VEX1NUUkVBTVMsIGZ1bmN0aW9uIChqaWQsIGNoYW5nZWRTdHJlYW1zKSB7XG4gICAgICAgICAgICBmb3IodmFyIGkgPSAwOyBpIDwgY2hhbmdlZFN0cmVhbXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgdHlwZSA9IGNoYW5nZWRTdHJlYW1zW2ldLnR5cGU7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGUgIT0gXCJhdWRpb1wiKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwZWVyU3RyZWFtcyA9IHNlbGYucmVtb3RlU3RyZWFtc1tqaWRdO1xuICAgICAgICAgICAgICAgICAgICBpZighcGVlclN0cmVhbXMpXG4gICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZpZGVvU3RyZWFtID0gcGVlclN0cmVhbXNbTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdO1xuICAgICAgICAgICAgICAgICAgICBpZighdmlkZW9TdHJlYW0pXG4gICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICAgICAgdmlkZW9TdHJlYW0uc2V0VmlkZW9UeXBlKGNoYW5nZWRTdHJlYW1zW2ldLnR5cGUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuQ0FMTF9JTkNPTUlORywgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAgICAgICAgIERhdGFDaGFubmVscy5pbml0KGV2ZW50LnBlZXJjb25uZWN0aW9uLCBldmVudEVtaXR0ZXIpO1xuICAgICAgICB9KTtcbiAgICAgICAgQVBQLlVJLmFkZExpc3RlbmVyKFVJRXZlbnRzLlNFTEVDVEVEX0VORFBPSU5ULFxuICAgICAgICAgICAgRGF0YUNoYW5uZWxzLmhhbmRsZVNlbGVjdGVkRW5kcG9pbnRFdmVudCk7XG4gICAgICAgIEFQUC5VSS5hZGRMaXN0ZW5lcihVSUV2ZW50cy5QSU5ORURfRU5EUE9JTlQsXG4gICAgICAgICAgICBEYXRhQ2hhbm5lbHMuaGFuZGxlUGlubmVkRW5kcG9pbnRFdmVudCk7XG4gICAgICAgIHRoaXMucnRjVXRpbHMgPSBuZXcgUlRDVXRpbHModGhpcyk7XG4gICAgICAgIHRoaXMucnRjVXRpbHMub2J0YWluQXVkaW9BbmRWaWRlb1Blcm1pc3Npb25zKCk7XG4gICAgfSxcbiAgICBtdXRlUmVtb3RlVmlkZW9TdHJlYW06IGZ1bmN0aW9uIChqaWQsIHZhbHVlKSB7XG4gICAgICAgIHZhciBzdHJlYW07XG5cbiAgICAgICAgaWYodGhpcy5yZW1vdGVTdHJlYW1zW2ppZF0gJiZcbiAgICAgICAgICAgIHRoaXMucmVtb3RlU3RyZWFtc1tqaWRdW01lZGlhU3RyZWFtVHlwZS5WSURFT19UWVBFXSlcbiAgICAgICAge1xuICAgICAgICAgICAgc3RyZWFtID0gdGhpcy5yZW1vdGVTdHJlYW1zW2ppZF1bTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYoIXN0cmVhbSlcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuXG4gICAgICAgIGlmICh2YWx1ZSAhPSBzdHJlYW0ubXV0ZWQpIHtcbiAgICAgICAgICAgIHN0cmVhbS5zZXRNdXRlKHZhbHVlKTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9LFxuICAgIHN3aXRjaFZpZGVvU3RyZWFtczogZnVuY3Rpb24gKG5ld19zdHJlYW0pIHtcbiAgICAgICAgdGhpcy5sb2NhbFZpZGVvLnN0cmVhbSA9IG5ld19zdHJlYW07XG5cbiAgICAgICAgdGhpcy5sb2NhbFN0cmVhbXMgPSBbXTtcblxuICAgICAgICAvL2luIGZpcmVmb3ggd2UgaGF2ZSBvbmx5IG9uZSBzdHJlYW0gb2JqZWN0XG4gICAgICAgIGlmICh0aGlzLmxvY2FsQXVkaW8uZ2V0T3JpZ2luYWxTdHJlYW0oKSAhPSBuZXdfc3RyZWFtKVxuICAgICAgICAgICAgdGhpcy5sb2NhbFN0cmVhbXMucHVzaCh0aGlzLmxvY2FsQXVkaW8pO1xuICAgICAgICB0aGlzLmxvY2FsU3RyZWFtcy5wdXNoKHRoaXMubG9jYWxWaWRlbyk7XG4gICAgfSxcbiAgICBjaGFuZ2VMb2NhbFZpZGVvOiBmdW5jdGlvbiAoc3RyZWFtLCBpc1VzaW5nU2NyZWVuU3RyZWFtLCBjYWxsYmFjaykge1xuICAgICAgICB2YXIgb2xkU3RyZWFtID0gdGhpcy5sb2NhbFZpZGVvLmdldE9yaWdpbmFsU3RyZWFtKCk7XG4gICAgICAgIHZhciB0eXBlID0gKGlzVXNpbmdTY3JlZW5TdHJlYW0/IFwic2NyZWVuXCIgOiBcInZpZGVvXCIpO1xuICAgICAgICB2YXIgbG9jYWxDYWxsYmFjayA9IGNhbGxiYWNrO1xuICAgICAgICBpZih0aGlzLmxvY2FsVmlkZW8uaXNNdXRlZCgpICYmIHRoaXMubG9jYWxWaWRlby52aWRlb1R5cGUgIT09IHR5cGUpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGxvY2FsQ2FsbGJhY2sgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICBBUFAueG1wcC5zZXRWaWRlb011dGUoZmFsc2UsIEFQUC5VSS5zZXRWaWRlb011dGVCdXR0b25zU3RhdGUpO1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHZhciB2aWRlb1N0cmVhbSA9IHRoaXMucnRjVXRpbHMuY3JlYXRlVmlkZW9TdHJlYW0oc3RyZWFtKTtcbiAgICAgICAgdGhpcy5sb2NhbFZpZGVvID0gdGhpcy5jcmVhdGVMb2NhbFN0cmVhbSh2aWRlb1N0cmVhbSwgXCJ2aWRlb1wiLCB0cnVlLCB0eXBlKTtcbiAgICAgICAgLy8gU3RvcCB0aGUgc3RyZWFtIHRvIHRyaWdnZXIgb25lbmRlZCBldmVudCBmb3Igb2xkIHN0cmVhbVxuICAgICAgICBvbGRTdHJlYW0uc3RvcCgpO1xuICAgICAgICBBUFAueG1wcC5zd2l0Y2hTdHJlYW1zKHZpZGVvU3RyZWFtLCBvbGRTdHJlYW0sbG9jYWxDYWxsYmFjayk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgdmlkZW8gaWRlbnRpZmllZCBieSBnaXZlbiBzcmMgaXMgZGVza3RvcCBzdHJlYW0uXG4gICAgICogQHBhcmFtIHZpZGVvU3JjIGVnLlxuICAgICAqIGJsb2I6aHR0cHMlM0EvL3Bhd2VsLmppdHNpLm5ldC85YTQ2ZTBiZC0xMzFlLTRkMTgtOWMxNC1hOTI2NGU4ZGIzOTVcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICBpc1ZpZGVvU3JjRGVza3RvcDogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBpZighamlkKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB2YXIgaXNEZXNrdG9wID0gZmFsc2U7XG4gICAgICAgIHZhciBzdHJlYW0gPSBudWxsO1xuICAgICAgICBpZiAoQVBQLnhtcHAubXlKaWQoKSA9PT0gamlkKSB7XG4gICAgICAgICAgICAvLyBsb2NhbCB2aWRlb1xuICAgICAgICAgICAgc3RyZWFtID0gdGhpcy5sb2NhbFZpZGVvO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdmFyIHBlZXJTdHJlYW1zID0gdGhpcy5yZW1vdGVTdHJlYW1zW2ppZF07XG4gICAgICAgICAgICBpZighcGVlclN0cmVhbXMpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgc3RyZWFtID0gcGVlclN0cmVhbXNbTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYoc3RyZWFtKVxuICAgICAgICAgICAgaXNEZXNrdG9wID0gKHN0cmVhbS52aWRlb1R5cGUgPT09IFwic2NyZWVuXCIpO1xuXG4gICAgICAgIHJldHVybiBpc0Rlc2t0b3A7XG4gICAgfSxcbiAgICBzZXRWaWRlb011dGU6IGZ1bmN0aW9uKG11dGUsIGNhbGxiYWNrLCBvcHRpb25zKSB7XG4gICAgICAgIGlmKCF0aGlzLmxvY2FsVmlkZW8pXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgaWYgKG11dGUgPT0gQVBQLlJUQy5sb2NhbFZpZGVvLmlzTXV0ZWQoKSlcbiAgICAgICAge1xuICAgICAgICAgICAgQVBQLnhtcHAuc2VuZFZpZGVvSW5mb1ByZXNlbmNlKG11dGUpO1xuICAgICAgICAgICAgaWYoY2FsbGJhY2spXG4gICAgICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIEFQUC5SVEMubG9jYWxWaWRlby5zZXRNdXRlKCFtdXRlKTtcbiAgICAgICAgICAgIEFQUC54bXBwLnNldFZpZGVvTXV0ZShcbiAgICAgICAgICAgICAgICBtdXRlLFxuICAgICAgICAgICAgICAgIGNhbGxiYWNrLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzZXREZXZpY2VBdmFpbGFiaWxpdHk6IGZ1bmN0aW9uIChkZXZpY2VzKSB7XG4gICAgICAgIGlmKCFkZXZpY2VzKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICBpZihkZXZpY2VzLmF1ZGlvID09PSB0cnVlIHx8IGRldmljZXMuYXVkaW8gPT09IGZhbHNlKVxuICAgICAgICAgICAgdGhpcy5kZXZpY2VzLmF1ZGlvID0gZGV2aWNlcy5hdWRpbztcbiAgICAgICAgaWYoZGV2aWNlcy52aWRlbyA9PT0gdHJ1ZSB8fCBkZXZpY2VzLnZpZGVvID09PSBmYWxzZSlcbiAgICAgICAgICAgIHRoaXMuZGV2aWNlcy52aWRlbyA9IGRldmljZXMudmlkZW87XG4gICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFJUQ0V2ZW50cy5BVkFJTEFCTEVfREVWSUNFU19DSEFOR0VELCB0aGlzLmRldmljZXMpO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUlRDO1xuIiwidmFyIFJUQ0Jyb3dzZXJUeXBlID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL1JUQ0Jyb3dzZXJUeXBlLmpzXCIpO1xudmFyIFJlc29sdXRpb25zID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL1Jlc29sdXRpb25zXCIpO1xuXG52YXIgY3VycmVudFJlc29sdXRpb24gPSBudWxsO1xuXG5mdW5jdGlvbiBnZXRQcmV2aW91c1Jlc29sdXRpb24ocmVzb2x1dGlvbikge1xuICAgIGlmKCFSZXNvbHV0aW9uc1tyZXNvbHV0aW9uXSlcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgdmFyIG9yZGVyID0gUmVzb2x1dGlvbnNbcmVzb2x1dGlvbl0ub3JkZXI7XG4gICAgdmFyIHJlcyA9IG51bGw7XG4gICAgdmFyIHJlc05hbWUgPSBudWxsO1xuICAgIGZvcih2YXIgaSBpbiBSZXNvbHV0aW9ucylcbiAgICB7XG4gICAgICAgIHZhciB0bXAgPSBSZXNvbHV0aW9uc1tpXTtcbiAgICAgICAgaWYocmVzID09IG51bGwgfHwgKHJlcy5vcmRlciA8IHRtcC5vcmRlciAmJiB0bXAub3JkZXIgPCBvcmRlcikpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHJlc05hbWUgPSBpO1xuICAgICAgICAgICAgcmVzID0gdG1wO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXNOYW1lO1xufVxuXG5mdW5jdGlvbiBzZXRSZXNvbHV0aW9uQ29uc3RyYWludHMoY29uc3RyYWludHMsIHJlc29sdXRpb24sIGlzQW5kcm9pZClcbntcbiAgICBpZiAocmVzb2x1dGlvbiAmJiAhY29uc3RyYWludHMudmlkZW8gfHwgaXNBbmRyb2lkKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0geyBtYW5kYXRvcnk6IHt9LCBvcHRpb25hbDogW10gfTsvLyBzYW1lIGJlaGF2aW91ciBhcyB0cnVlXG4gICAgfVxuXG4gICAgaWYoUmVzb2x1dGlvbnNbcmVzb2x1dGlvbl0pXG4gICAge1xuICAgICAgICBjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWluV2lkdGggPSBSZXNvbHV0aW9uc1tyZXNvbHV0aW9uXS53aWR0aDtcbiAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkhlaWdodCA9IFJlc29sdXRpb25zW3Jlc29sdXRpb25dLmhlaWdodDtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgaWYgKGlzQW5kcm9pZCkge1xuICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbldpZHRoID0gMzIwO1xuICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkhlaWdodCA9IDI0MDtcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5tYXhGcmFtZVJhdGUgPSAxNTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWluV2lkdGgpXG4gICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5tYXhXaWR0aCA9IGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5XaWR0aDtcbiAgICBpZiAoY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkhlaWdodClcbiAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1heEhlaWdodCA9IGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5IZWlnaHQ7XG59XG5cbmZ1bmN0aW9uIGdldENvbnN0cmFpbnRzKHVtLCByZXNvbHV0aW9uLCBiYW5kd2lkdGgsIGZwcywgZGVza3RvcFN0cmVhbSwgaXNBbmRyb2lkKVxue1xuICAgIHZhciBjb25zdHJhaW50cyA9IHthdWRpbzogZmFsc2UsIHZpZGVvOiBmYWxzZX07XG5cbiAgICBpZiAodW0uaW5kZXhPZigndmlkZW8nKSA+PSAwKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0geyBtYW5kYXRvcnk6IHt9LCBvcHRpb25hbDogW10gfTsvLyBzYW1lIGJlaGF2aW91ciBhcyB0cnVlXG4gICAgfVxuICAgIGlmICh1bS5pbmRleE9mKCdhdWRpbycpID49IDApIHtcbiAgICAgICAgY29uc3RyYWludHMuYXVkaW8gPSB7IG1hbmRhdG9yeToge30sIG9wdGlvbmFsOiBbXX07Ly8gc2FtZSBiZWhhdmlvdXIgYXMgdHJ1ZVxuICAgIH1cbiAgICBpZiAodW0uaW5kZXhPZignc2NyZWVuJykgPj0gMCkge1xuICAgICAgICBjb25zdHJhaW50cy52aWRlbyA9IHtcbiAgICAgICAgICAgIG1hbmRhdG9yeToge1xuICAgICAgICAgICAgICAgIGNocm9tZU1lZGlhU291cmNlOiBcInNjcmVlblwiLFxuICAgICAgICAgICAgICAgIGdvb2dMZWFreUJ1Y2tldDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBtYXhXaWR0aDogd2luZG93LnNjcmVlbi53aWR0aCxcbiAgICAgICAgICAgICAgICBtYXhIZWlnaHQ6IHdpbmRvdy5zY3JlZW4uaGVpZ2h0LFxuICAgICAgICAgICAgICAgIG1heEZyYW1lUmF0ZTogM1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9wdGlvbmFsOiBbXVxuICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAodW0uaW5kZXhPZignZGVza3RvcCcpID49IDApIHtcbiAgICAgICAgY29uc3RyYWludHMudmlkZW8gPSB7XG4gICAgICAgICAgICBtYW5kYXRvcnk6IHtcbiAgICAgICAgICAgICAgICBjaHJvbWVNZWRpYVNvdXJjZTogXCJkZXNrdG9wXCIsXG4gICAgICAgICAgICAgICAgY2hyb21lTWVkaWFTb3VyY2VJZDogZGVza3RvcFN0cmVhbSxcbiAgICAgICAgICAgICAgICBnb29nTGVha3lCdWNrZXQ6IHRydWUsXG4gICAgICAgICAgICAgICAgbWF4V2lkdGg6IHdpbmRvdy5zY3JlZW4ud2lkdGgsXG4gICAgICAgICAgICAgICAgbWF4SGVpZ2h0OiB3aW5kb3cuc2NyZWVuLmhlaWdodCxcbiAgICAgICAgICAgICAgICBtYXhGcmFtZVJhdGU6IDNcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvcHRpb25hbDogW11cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAoY29uc3RyYWludHMuYXVkaW8pIHtcbiAgICAgICAgLy8gaWYgaXQgaXMgZ29vZCBlbm91Z2ggZm9yIGhhbmdvdXRzLi4uXG4gICAgICAgIGNvbnN0cmFpbnRzLmF1ZGlvLm9wdGlvbmFsLnB1c2goXG4gICAgICAgICAgICB7Z29vZ0VjaG9DYW5jZWxsYXRpb246IHRydWV9LFxuICAgICAgICAgICAge2dvb2dBdXRvR2FpbkNvbnRyb2w6IHRydWV9LFxuICAgICAgICAgICAge2dvb2dOb2lzZVN1cHJlc3Npb246IHRydWV9LFxuICAgICAgICAgICAge2dvb2dIaWdocGFzc0ZpbHRlcjogdHJ1ZX0sXG4gICAgICAgICAgICB7Z29vZ05vaXNlc3VwcHJlc3Npb24yOiB0cnVlfSxcbiAgICAgICAgICAgIHtnb29nRWNob0NhbmNlbGxhdGlvbjI6IHRydWV9LFxuICAgICAgICAgICAge2dvb2dBdXRvR2FpbkNvbnRyb2wyOiB0cnVlfVxuICAgICAgICApO1xuICAgIH1cbiAgICBpZiAoY29uc3RyYWludHMudmlkZW8pIHtcbiAgICAgICAgY29uc3RyYWludHMudmlkZW8ub3B0aW9uYWwucHVzaChcbiAgICAgICAgICAgIHtnb29nTm9pc2VSZWR1Y3Rpb246IGZhbHNlfSAvLyBjaHJvbWUgMzcgd29ya2Fyb3VuZCBmb3IgaXNzdWUgMzgwNywgcmVlbmFibGUgaW4gTTM4XG4gICAgICAgICk7XG4gICAgICAgIGlmICh1bS5pbmRleE9mKCd2aWRlbycpID49IDApIHtcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm9wdGlvbmFsLnB1c2goXG4gICAgICAgICAgICAgICAge2dvb2dMZWFreUJ1Y2tldDogdHJ1ZX1cbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodW0uaW5kZXhPZigndmlkZW8nKSA+PSAwKSB7XG4gICAgICAgIHNldFJlc29sdXRpb25Db25zdHJhaW50cyhjb25zdHJhaW50cywgcmVzb2x1dGlvbiwgaXNBbmRyb2lkKTtcbiAgICB9XG5cbiAgICBpZiAoYmFuZHdpZHRoKSB7IC8vIGRvZXNuJ3Qgd29yayBjdXJyZW50bHksIHNlZSB3ZWJydGMgaXNzdWUgMTg0NlxuICAgICAgICBpZiAoIWNvbnN0cmFpbnRzLnZpZGVvKSBjb25zdHJhaW50cy52aWRlbyA9IHttYW5kYXRvcnk6IHt9LCBvcHRpb25hbDogW119Oy8vc2FtZSBiZWhhdmlvdXIgYXMgdHJ1ZVxuICAgICAgICBjb25zdHJhaW50cy52aWRlby5vcHRpb25hbC5wdXNoKHtiYW5kd2lkdGg6IGJhbmR3aWR0aH0pO1xuICAgIH1cbiAgICBpZiAoZnBzKSB7IC8vIGZvciBzb21lIGNhbWVyYXMgaXQgbWlnaHQgYmUgbmVjZXNzYXJ5IHRvIHJlcXVlc3QgMzBmcHNcbiAgICAgICAgLy8gc28gdGhleSBjaG9vc2UgMzBmcHMgbWpwZyBvdmVyIDEwZnBzIHl1eTJcbiAgICAgICAgaWYgKCFjb25zdHJhaW50cy52aWRlbykgY29uc3RyYWludHMudmlkZW8gPSB7bWFuZGF0b3J5OiB7fSwgb3B0aW9uYWw6IFtdfTsvLyBzYW1lIGJlaGF2aW91ciBhcyB0cnVlO1xuICAgICAgICBjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWluRnJhbWVSYXRlID0gZnBzO1xuICAgIH1cblxuICAgIHJldHVybiBjb25zdHJhaW50cztcbn1cblxuXG5mdW5jdGlvbiBSVENVdGlscyhSVENTZXJ2aWNlKVxue1xuICAgIHRoaXMuc2VydmljZSA9IFJUQ1NlcnZpY2U7XG4gICAgaWYgKG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ1RoaXMgYXBwZWFycyB0byBiZSBGaXJlZm94Jyk7XG4gICAgICAgIHZhciB2ZXJzaW9uID0gcGFyc2VJbnQobmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvRmlyZWZveFxcLyhbMC05XSspXFwuLylbMV0sIDEwKTtcbiAgICAgICAgaWYgKHZlcnNpb24gPj0gMzkpIHtcbiAgICAgICAgICAgIHRoaXMucGVlcmNvbm5lY3Rpb24gPSBtb3pSVENQZWVyQ29ubmVjdGlvbjtcbiAgICAgICAgICAgIHRoaXMuYnJvd3NlciA9IFJUQ0Jyb3dzZXJUeXBlLlJUQ19CUk9XU0VSX0ZJUkVGT1g7XG4gICAgICAgICAgICB0aGlzLmdldFVzZXJNZWRpYSA9IG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEuYmluZChuYXZpZ2F0b3IpO1xuICAgICAgICAgICAgdGhpcy5wY19jb25zdHJhaW50cyA9IHt9O1xuICAgICAgICAgICAgdGhpcy5hdHRhY2hNZWRpYVN0cmVhbSA9ICBmdW5jdGlvbiAoZWxlbWVudCwgc3RyZWFtKSB7XG4gICAgICAgICAgICAgICAgLy8gIHNyY09iamVjdCBpcyBiZWluZyBzdGFuZGFyZGl6ZWQgYW5kIEZGIHdpbGwgZXZlbnR1YWxseVxuICAgICAgICAgICAgICAgIC8vICBzdXBwb3J0IHRoYXQgdW5wcmVmaXhlZC4gRkYgYWxzbyBzdXBwb3J0cyB0aGVcbiAgICAgICAgICAgICAgICAvLyAgXCJlbGVtZW50LnNyYyA9IFVSTC5jcmVhdGVPYmplY3RVUkwoLi4uKVwiIGNvbWJvLCBidXQgdGhhdFxuICAgICAgICAgICAgICAgIC8vICB3aWxsIGJlIGRlcHJlY2F0ZWQgaW4gZmF2b3VyIG9mIHNyY09iamVjdC5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vZ3JvdXBzLmdvb2dsZS5jb20vZm9ydW0vIyF0b3BpYy9tb3ppbGxhLmRldi5tZWRpYS9wS09paW9Yb25KZ1xuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS93ZWJydGMvc2FtcGxlcy9pc3N1ZXMvMzAyXG4gICAgICAgICAgICAgICAgZWxlbWVudFswXS5tb3pTcmNPYmplY3QgPSBzdHJlYW07XG4gICAgICAgICAgICAgICAgZWxlbWVudFswXS5wbGF5KCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdGhpcy5nZXRTdHJlYW1JRCA9ICBmdW5jdGlvbiAoc3RyZWFtKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRyYWNrcyA9IHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpO1xuICAgICAgICAgICAgICAgIGlmKCF0cmFja3MgfHwgdHJhY2tzLmxlbmd0aCA9PSAwKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHJhY2tzID0gc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0cmFja3NbMF0uaWQucmVwbGFjZSgvW1xceyxcXH1dL2csXCJcIik7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdGhpcy5nZXRWaWRlb1NyYyA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGVsZW1lbnQubW96U3JjT2JqZWN0O1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHRoaXMuc2V0VmlkZW9TcmMgPSBmdW5jdGlvbiAoZWxlbWVudCwgc3JjKSB7XG4gICAgICAgICAgICAgICAgZWxlbWVudC5tb3pTcmNPYmplY3QgPSBzcmM7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uID0gbW96UlRDU2Vzc2lvbkRlc2NyaXB0aW9uO1xuICAgICAgICAgICAgUlRDSWNlQ2FuZGlkYXRlID0gbW96UlRDSWNlQ2FuZGlkYXRlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSAndW5zdXBwb3J0ZWRfYnJvd3Nlci5odG1sJztcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgfSBlbHNlIGlmIChuYXZpZ2F0b3Iud2Via2l0R2V0VXNlck1lZGlhKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdUaGlzIGFwcGVhcnMgdG8gYmUgQ2hyb21lJyk7XG4gICAgICAgIHRoaXMucGVlcmNvbm5lY3Rpb24gPSB3ZWJraXRSVENQZWVyQ29ubmVjdGlvbjtcbiAgICAgICAgdGhpcy5icm93c2VyID0gUlRDQnJvd3NlclR5cGUuUlRDX0JST1dTRVJfQ0hST01FO1xuICAgICAgICB0aGlzLmdldFVzZXJNZWRpYSA9IG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEuYmluZChuYXZpZ2F0b3IpO1xuICAgICAgICB0aGlzLmF0dGFjaE1lZGlhU3RyZWFtID0gZnVuY3Rpb24gKGVsZW1lbnQsIHN0cmVhbSkge1xuICAgICAgICAgICAgZWxlbWVudC5hdHRyKCdzcmMnLCB3ZWJraXRVUkwuY3JlYXRlT2JqZWN0VVJMKHN0cmVhbSkpO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLmdldFN0cmVhbUlEID0gZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICAgICAgLy8gc3RyZWFtcyBmcm9tIEZGIGVuZHBvaW50cyBoYXZlIHRoZSBjaGFyYWN0ZXJzICd7JyBhbmQgJ30nXG4gICAgICAgICAgICAvLyB0aGF0IG1ha2UgalF1ZXJ5IGNob2tlLlxuICAgICAgICAgICAgcmV0dXJuIHN0cmVhbS5pZC5yZXBsYWNlKC9bXFx7LFxcfV0vZyxcIlwiKTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5nZXRWaWRlb1NyYyA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gICAgICAgICAgICByZXR1cm4gZWxlbWVudC5nZXRBdHRyaWJ1dGUoXCJzcmNcIik7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuc2V0VmlkZW9TcmMgPSBmdW5jdGlvbiAoZWxlbWVudCwgc3JjKSB7XG4gICAgICAgICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZShcInNyY1wiLCBzcmMpO1xuICAgICAgICB9O1xuICAgICAgICAvLyBEVExTIHNob3VsZCBub3cgYmUgZW5hYmxlZCBieSBkZWZhdWx0IGJ1dC4uXG4gICAgICAgIHRoaXMucGNfY29uc3RyYWludHMgPSB7J29wdGlvbmFsJzogW3snRHRsc1NydHBLZXlBZ3JlZW1lbnQnOiAndHJ1ZSd9XX07XG4gICAgICAgIGlmIChuYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YoJ0FuZHJvaWQnKSAhPSAtMSkge1xuICAgICAgICAgICAgdGhpcy5wY19jb25zdHJhaW50cyA9IHt9OyAvLyBkaXNhYmxlIERUTFMgb24gQW5kcm9pZFxuICAgICAgICB9XG4gICAgICAgIGlmICghd2Via2l0TWVkaWFTdHJlYW0ucHJvdG90eXBlLmdldFZpZGVvVHJhY2tzKSB7XG4gICAgICAgICAgICB3ZWJraXRNZWRpYVN0cmVhbS5wcm90b3R5cGUuZ2V0VmlkZW9UcmFja3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMudmlkZW9UcmFja3M7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICghd2Via2l0TWVkaWFTdHJlYW0ucHJvdG90eXBlLmdldEF1ZGlvVHJhY2tzKSB7XG4gICAgICAgICAgICB3ZWJraXRNZWRpYVN0cmVhbS5wcm90b3R5cGUuZ2V0QXVkaW9UcmFja3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYXVkaW9UcmFja3M7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIHRyeSB7IGNvbnNvbGUubG9nKCdCcm93c2VyIGRvZXMgbm90IGFwcGVhciB0byBiZSBXZWJSVEMtY2FwYWJsZScpOyB9IGNhdGNoIChlKSB7IH1cblxuICAgICAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9ICd1bnN1cHBvcnRlZF9icm93c2VyLmh0bWwnO1xuICAgICAgICByZXR1cm47XG4gICAgfVxufVxuXG5cblJUQ1V0aWxzLnByb3RvdHlwZS5nZXRVc2VyTWVkaWFXaXRoQ29uc3RyYWludHMgPSBmdW5jdGlvbihcbiAgICB1bSwgc3VjY2Vzc19jYWxsYmFjaywgZmFpbHVyZV9jYWxsYmFjaywgcmVzb2x1dGlvbixiYW5kd2lkdGgsIGZwcyxcbiAgICBkZXNrdG9wU3RyZWFtKVxue1xuICAgIGN1cnJlbnRSZXNvbHV0aW9uID0gcmVzb2x1dGlvbjtcbiAgICAvLyBDaGVjayBpZiB3ZSBhcmUgcnVubmluZyBvbiBBbmRyb2lkIGRldmljZVxuICAgIHZhciBpc0FuZHJvaWQgPSBuYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YoJ0FuZHJvaWQnKSAhPSAtMTtcblxuICAgIHZhciBjb25zdHJhaW50cyA9IGdldENvbnN0cmFpbnRzKFxuICAgICAgICB1bSwgcmVzb2x1dGlvbiwgYmFuZHdpZHRoLCBmcHMsIGRlc2t0b3BTdHJlYW0sIGlzQW5kcm9pZCk7XG5cbiAgICB2YXIgaXNGRiA9IG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5pbmRleE9mKCdmaXJlZm94JykgPiAtMTtcblxuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIHRyeSB7XG4gICAgICAgIGlmIChjb25maWcuZW5hYmxlU2ltdWxjYXN0XG4gICAgICAgICAgICAmJiBjb25zdHJhaW50cy52aWRlb1xuICAgICAgICAgICAgJiYgY29uc3RyYWludHMudmlkZW8uY2hyb21lTWVkaWFTb3VyY2UgIT09ICdzY3JlZW4nXG4gICAgICAgICAgICAmJiBjb25zdHJhaW50cy52aWRlby5jaHJvbWVNZWRpYVNvdXJjZSAhPT0gJ2Rlc2t0b3AnXG4gICAgICAgICAgICAmJiAhaXNBbmRyb2lkXG5cbiAgICAgICAgICAgIC8vIFdlIGN1cnJlbnRseSBkbyBub3Qgc3VwcG9ydCBGRiwgYXMgaXQgZG9lc24ndCBoYXZlIG11bHRpc3RyZWFtIHN1cHBvcnQuXG4gICAgICAgICAgICAmJiAhaXNGRikge1xuICAgICAgICAgICAgQVBQLnNpbXVsY2FzdC5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMsIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ29uVXNlck1lZGlhU3VjY2VzcycpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnNldEF2YWlsYWJsZURldmljZXModW0sIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzX2NhbGxiYWNrKHN0cmVhbSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdGYWlsZWQgdG8gZ2V0IGFjY2VzcyB0byBsb2NhbCBtZWRpYS4gRXJyb3IgJywgZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnNldEF2YWlsYWJsZURldmljZXModW0sIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGZhaWx1cmVfY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZhaWx1cmVfY2FsbGJhY2soZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgIHRoaXMuZ2V0VXNlck1lZGlhKGNvbnN0cmFpbnRzLFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ29uVXNlck1lZGlhU3VjY2VzcycpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnNldEF2YWlsYWJsZURldmljZXModW0sIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzX2NhbGxiYWNrKHN0cmVhbSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5zZXRBdmFpbGFibGVEZXZpY2VzKHVtLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignRmFpbGVkIHRvIGdldCBhY2Nlc3MgdG8gbG9jYWwgbWVkaWEuIEVycm9yICcsXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvciwgY29uc3RyYWludHMpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZmFpbHVyZV9jYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZmFpbHVyZV9jYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdHVU0gZmFpbGVkOiAnLCBlKTtcbiAgICAgICAgaWYoZmFpbHVyZV9jYWxsYmFjaykge1xuICAgICAgICAgICAgZmFpbHVyZV9jYWxsYmFjayhlKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cblJUQ1V0aWxzLnByb3RvdHlwZS5zZXRBdmFpbGFibGVEZXZpY2VzID0gZnVuY3Rpb24gKHVtLCBhdmFpbGFibGUpIHtcbiAgICB2YXIgZGV2aWNlcyA9IHt9O1xuICAgIGlmKHVtLmluZGV4T2YoXCJ2aWRlb1wiKSAhPSAtMSlcbiAgICB7XG4gICAgICAgIGRldmljZXMudmlkZW8gPSBhdmFpbGFibGU7XG4gICAgfVxuICAgIGlmKHVtLmluZGV4T2YoXCJhdWRpb1wiKSAhPSAtMSlcbiAgICB7XG4gICAgICAgIGRldmljZXMuYXVkaW8gPSBhdmFpbGFibGU7XG4gICAgfVxuICAgIHRoaXMuc2VydmljZS5zZXREZXZpY2VBdmFpbGFiaWxpdHkoZGV2aWNlcyk7XG59XG5cbi8qKlxuICogV2UgYXNrIGZvciBhdWRpbyBhbmQgdmlkZW8gY29tYmluZWQgc3RyZWFtIGluIG9yZGVyIHRvIGdldCBwZXJtaXNzaW9ucyBhbmRcbiAqIG5vdCB0byBhc2sgdHdpY2UuXG4gKi9cblJUQ1V0aWxzLnByb3RvdHlwZS5vYnRhaW5BdWRpb0FuZFZpZGVvUGVybWlzc2lvbnMgPSBmdW5jdGlvbihkZXZpY2VzLCBjYWxsYmFjaykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAvLyBHZXQgQVZcblxuICAgIGlmKCFkZXZpY2VzKVxuICAgICAgICBkZXZpY2VzID0gWydhdWRpbycsICd2aWRlbyddO1xuXG4gICAgdGhpcy5nZXRVc2VyTWVkaWFXaXRoQ29uc3RyYWludHMoXG4gICAgICAgIGRldmljZXMsXG4gICAgICAgIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgIGlmKGNhbGxiYWNrKVxuICAgICAgICAgICAgICAgIGNhbGxiYWNrKHN0cmVhbSk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgc2VsZi5zdWNjZXNzQ2FsbGJhY2soc3RyZWFtKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICBzZWxmLmVycm9yQ2FsbGJhY2soZXJyb3IpO1xuICAgICAgICB9LFxuICAgICAgICBjb25maWcucmVzb2x1dGlvbiB8fCAnMzYwJyk7XG59XG5cblJUQ1V0aWxzLnByb3RvdHlwZS5zdWNjZXNzQ2FsbGJhY2sgPSBmdW5jdGlvbiAoc3RyZWFtKSB7XG4gICAgaWYoc3RyZWFtKVxuICAgICAgICBjb25zb2xlLmxvZygnZ290Jywgc3RyZWFtLCBzdHJlYW0uZ2V0QXVkaW9UcmFja3MoKS5sZW5ndGgsXG4gICAgICAgICAgICBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGgpO1xuICAgIHRoaXMuaGFuZGxlTG9jYWxTdHJlYW0oc3RyZWFtKTtcbn07XG5cblJUQ1V0aWxzLnByb3RvdHlwZS5lcnJvckNhbGxiYWNrID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGNvbnNvbGUuZXJyb3IoJ2ZhaWxlZCB0byBvYnRhaW4gYXVkaW8vdmlkZW8gc3RyZWFtIC0gdHJ5aW5nIGF1ZGlvIG9ubHknLCBlcnJvcik7XG4gICAgdmFyIHJlc29sdXRpb24gPSBnZXRQcmV2aW91c1Jlc29sdXRpb24oY3VycmVudFJlc29sdXRpb24pO1xuICAgIGlmKHR5cGVvZiBlcnJvciA9PSBcIm9iamVjdFwiICYmIGVycm9yLmNvbnN0cmFpbnROYW1lICYmIGVycm9yLm5hbWVcbiAgICAgICAgJiYgKGVycm9yLm5hbWUgPT0gXCJDb25zdHJhaW50Tm90U2F0aXNmaWVkRXJyb3JcIiB8fFxuICAgICAgICAgICAgZXJyb3IubmFtZSA9PSBcIk92ZXJjb25zdHJhaW5lZEVycm9yXCIpICYmXG4gICAgICAgIChlcnJvci5jb25zdHJhaW50TmFtZSA9PSBcIm1pbldpZHRoXCIgfHwgZXJyb3IuY29uc3RyYWludE5hbWUgPT0gXCJtYXhXaWR0aFwiIHx8XG4gICAgICAgICAgICBlcnJvci5jb25zdHJhaW50TmFtZSA9PSBcIm1pbkhlaWdodFwiIHx8IGVycm9yLmNvbnN0cmFpbnROYW1lID09IFwibWF4SGVpZ2h0XCIpXG4gICAgICAgICYmIHJlc29sdXRpb24gIT0gbnVsbClcbiAgICB7XG4gICAgICAgIHNlbGYuZ2V0VXNlck1lZGlhV2l0aENvbnN0cmFpbnRzKFsnYXVkaW8nLCAndmlkZW8nXSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zdWNjZXNzQ2FsbGJhY2soc3RyZWFtKTtcbiAgICAgICAgICAgIH0sIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgIHJldHVybiBzZWxmLmVycm9yQ2FsbGJhY2soZXJyb3IpO1xuICAgICAgICAgICAgfSwgcmVzb2x1dGlvbik7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIHNlbGYuZ2V0VXNlck1lZGlhV2l0aENvbnN0cmFpbnRzKFxuICAgICAgICAgICAgWydhdWRpbyddLFxuICAgICAgICAgICAgZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzZWxmLnN1Y2Nlc3NDYWxsYmFjayhzdHJlYW0pO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ2ZhaWxlZCB0byBvYnRhaW4gYXVkaW8vdmlkZW8gc3RyZWFtIC0gc3RvcCcsXG4gICAgICAgICAgICAgICAgICAgIGVycm9yKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zdWNjZXNzQ2FsbGJhY2sobnVsbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfVxuXG59XG5cblJUQ1V0aWxzLnByb3RvdHlwZS5oYW5kbGVMb2NhbFN0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSlcbntcbiAgICBpZih3aW5kb3cud2Via2l0TWVkaWFTdHJlYW0pXG4gICAge1xuICAgICAgICB2YXIgYXVkaW9TdHJlYW0gPSBuZXcgd2Via2l0TWVkaWFTdHJlYW0oKTtcbiAgICAgICAgdmFyIHZpZGVvU3RyZWFtID0gbmV3IHdlYmtpdE1lZGlhU3RyZWFtKCk7XG4gICAgICAgIGlmKHN0cmVhbSkge1xuICAgICAgICAgICAgdmFyIGF1ZGlvVHJhY2tzID0gc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCk7XG5cbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXVkaW9UcmFja3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBhdWRpb1N0cmVhbS5hZGRUcmFjayhhdWRpb1RyYWNrc1tpXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciB2aWRlb1RyYWNrcyA9IHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpO1xuXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdmlkZW9UcmFja3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2aWRlb1N0cmVhbS5hZGRUcmFjayh2aWRlb1RyYWNrc1tpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNlcnZpY2UuY3JlYXRlTG9jYWxTdHJlYW0oYXVkaW9TdHJlYW0sIFwiYXVkaW9cIik7XG5cbiAgICAgICAgdGhpcy5zZXJ2aWNlLmNyZWF0ZUxvY2FsU3RyZWFtKHZpZGVvU3RyZWFtLCBcInZpZGVvXCIpO1xuICAgIH1cbiAgICBlbHNlXG4gICAgey8vZmlyZWZveFxuICAgICAgICB0aGlzLnNlcnZpY2UuY3JlYXRlTG9jYWxTdHJlYW0oc3RyZWFtLCBcInN0cmVhbVwiKTtcbiAgICB9XG5cbn07XG5cblJUQ1V0aWxzLnByb3RvdHlwZS5jcmVhdGVWaWRlb1N0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSlcbntcbiAgICB2YXIgdmlkZW9TdHJlYW0gPSBudWxsO1xuICAgIGlmKHdpbmRvdy53ZWJraXRNZWRpYVN0cmVhbSlcbiAgICB7XG4gICAgICAgIHZpZGVvU3RyZWFtID0gbmV3IHdlYmtpdE1lZGlhU3RyZWFtKCk7XG4gICAgICAgIGlmKHN0cmVhbSlcbiAgICAgICAge1xuICAgICAgICAgICAgdmFyIHZpZGVvVHJhY2tzID0gc3RyZWFtLmdldFZpZGVvVHJhY2tzKCk7XG5cbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCB2aWRlb1RyYWNrcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHZpZGVvU3RyZWFtLmFkZFRyYWNrKHZpZGVvVHJhY2tzW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgfVxuICAgIGVsc2VcbiAgICAgICAgdmlkZW9TdHJlYW0gPSBzdHJlYW07XG5cbiAgICByZXR1cm4gdmlkZW9TdHJlYW07XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJUQ1V0aWxzO1xuIiwidmFyIFVJID0ge307XG5cbnZhciBWaWRlb0xheW91dCA9IHJlcXVpcmUoXCIuL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0LmpzXCIpO1xudmFyIEF1ZGlvTGV2ZWxzID0gcmVxdWlyZShcIi4vYXVkaW9fbGV2ZWxzL0F1ZGlvTGV2ZWxzLmpzXCIpO1xudmFyIFByZXppID0gcmVxdWlyZShcIi4vcHJlemkvUHJlemkuanNcIik7XG52YXIgRXRoZXJwYWQgPSByZXF1aXJlKFwiLi9ldGhlcnBhZC9FdGhlcnBhZC5qc1wiKTtcbnZhciBDaGF0ID0gcmVxdWlyZShcIi4vc2lkZV9wYW5uZWxzL2NoYXQvQ2hhdC5qc1wiKTtcbnZhciBUb29sYmFyID0gcmVxdWlyZShcIi4vdG9vbGJhcnMvVG9vbGJhclwiKTtcbnZhciBUb29sYmFyVG9nZ2xlciA9IHJlcXVpcmUoXCIuL3Rvb2xiYXJzL1Rvb2xiYXJUb2dnbGVyXCIpO1xudmFyIEJvdHRvbVRvb2xiYXIgPSByZXF1aXJlKFwiLi90b29sYmFycy9Cb3R0b21Ub29sYmFyXCIpO1xudmFyIENvbnRhY3RMaXN0ID0gcmVxdWlyZShcIi4vc2lkZV9wYW5uZWxzL2NvbnRhY3RsaXN0L0NvbnRhY3RMaXN0XCIpO1xudmFyIEF2YXRhciA9IHJlcXVpcmUoXCIuL2F2YXRhci9BdmF0YXJcIik7XG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcImV2ZW50c1wiKTtcbnZhciBTZXR0aW5nc01lbnUgPSByZXF1aXJlKFwiLi9zaWRlX3Bhbm5lbHMvc2V0dGluZ3MvU2V0dGluZ3NNZW51XCIpO1xudmFyIFNldHRpbmdzID0gcmVxdWlyZShcIi4vLi4vc2V0dGluZ3MvU2V0dGluZ3NcIik7XG52YXIgUGFuZWxUb2dnbGVyID0gcmVxdWlyZShcIi4vc2lkZV9wYW5uZWxzL1NpZGVQYW5lbFRvZ2dsZXJcIik7XG52YXIgUm9vbU5hbWVHZW5lcmF0b3IgPSByZXF1aXJlKFwiLi93ZWxjb21lX3BhZ2UvUm9vbW5hbWVHZW5lcmF0b3JcIik7XG5VSS5tZXNzYWdlSGFuZGxlciA9IHJlcXVpcmUoXCIuL3V0aWwvTWVzc2FnZUhhbmRsZXJcIik7XG52YXIgbWVzc2FnZUhhbmRsZXIgPSBVSS5tZXNzYWdlSGFuZGxlcjtcbnZhciBBdXRoZW50aWNhdGlvbiAgPSByZXF1aXJlKFwiLi9hdXRoZW50aWNhdGlvbi9BdXRoZW50aWNhdGlvblwiKTtcbnZhciBVSVV0aWwgPSByZXF1aXJlKFwiLi91dGlsL1VJVXRpbFwiKTtcbnZhciBOaWNrbmFtZUhhbmRsZXIgPSByZXF1aXJlKFwiLi91dGlsL05pY2tuYW1lSGFuZGxlclwiKTtcbnZhciBDUUV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL2Nvbm5lY3Rpb25xdWFsaXR5L0NRRXZlbnRzXCIpO1xudmFyIERlc2t0b3BTaGFyaW5nRXZlbnRUeXBlc1xuICAgID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvZGVza3RvcHNoYXJpbmcvRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzXCIpO1xudmFyIFJUQ0V2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9SVENFdmVudHNcIik7XG52YXIgU3RyZWFtRXZlbnRUeXBlcyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9TdHJlYW1FdmVudFR5cGVzXCIpO1xudmFyIFhNUFBFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS94bXBwL1hNUFBFdmVudHNcIik7XG5cbnZhciBldmVudEVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG52YXIgcm9vbU5hbWUgPSBudWxsO1xuXG5cbmZ1bmN0aW9uIHNldHVwUHJlemkoKVxue1xuICAgICQoXCIjcmVsb2FkUHJlc2VudGF0aW9uTGlua1wiKS5jbGljayhmdW5jdGlvbigpXG4gICAge1xuICAgICAgICBQcmV6aS5yZWxvYWRQcmVzZW50YXRpb24oKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gc2V0dXBDaGF0KClcbntcbiAgICBDaGF0LmluaXQoKTtcbiAgICAkKFwiI3RvZ2dsZV9zbWlsZXlzXCIpLmNsaWNrKGZ1bmN0aW9uKCkge1xuICAgICAgICBDaGF0LnRvZ2dsZVNtaWxleXMoKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gc2V0dXBUb29sYmFycygpIHtcbiAgICBUb29sYmFyLmluaXQoVUkpO1xuICAgIFRvb2xiYXIuc2V0dXBCdXR0b25zRnJvbUNvbmZpZygpO1xuICAgIEJvdHRvbVRvb2xiYXIuaW5pdCgpO1xufVxuXG5mdW5jdGlvbiBzdHJlYW1IYW5kbGVyKHN0cmVhbSkge1xuICAgIHN3aXRjaCAoc3RyZWFtLnR5cGUpXG4gICAge1xuICAgICAgICBjYXNlIFwiYXVkaW9cIjpcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNoYW5nZUxvY2FsQXVkaW8oc3RyZWFtKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwidmlkZW9cIjpcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNoYW5nZUxvY2FsVmlkZW8oc3RyZWFtKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwic3RyZWFtXCI6XG4gICAgICAgICAgICBWaWRlb0xheW91dC5jaGFuZ2VMb2NhbFN0cmVhbShzdHJlYW0pO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBvbkRpc3Bvc2VDb25mZXJlbmNlKHVubG9hZCkge1xuICAgIFRvb2xiYXIuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbihmYWxzZSk7XG59O1xuXG5mdW5jdGlvbiBvbkRpc3BsYXlOYW1lQ2hhbmdlZChqaWQsIGRpc3BsYXlOYW1lKSB7XG4gICAgQ29udGFjdExpc3Qub25EaXNwbGF5TmFtZUNoYW5nZShqaWQsIGRpc3BsYXlOYW1lKTtcbiAgICBTZXR0aW5nc01lbnUub25EaXNwbGF5TmFtZUNoYW5nZShqaWQsIGRpc3BsYXlOYW1lKTtcbiAgICBWaWRlb0xheW91dC5vbkRpc3BsYXlOYW1lQ2hhbmdlZChqaWQsIGRpc3BsYXlOYW1lKTtcbn1cblxuZnVuY3Rpb24gcmVnaXN0ZXJMaXN0ZW5lcnMoKSB7XG4gICAgQVBQLlJUQy5hZGRTdHJlYW1MaXN0ZW5lcihzdHJlYW1IYW5kbGVyLCBTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfTE9DQUxfQ1JFQVRFRCk7XG5cbiAgICBBUFAuUlRDLmFkZFN0cmVhbUxpc3RlbmVyKHN0cmVhbUhhbmRsZXIsIFN0cmVhbUV2ZW50VHlwZXMuRVZFTlRfVFlQRV9MT0NBTF9DSEFOR0VEKTtcbiAgICBBUFAuUlRDLmFkZFN0cmVhbUxpc3RlbmVyKGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgVmlkZW9MYXlvdXQub25SZW1vdGVTdHJlYW1BZGRlZChzdHJlYW0pO1xuICAgIH0sIFN0cmVhbUV2ZW50VHlwZXMuRVZFTlRfVFlQRV9SRU1PVEVfQ1JFQVRFRCk7XG4gICAgQVBQLlJUQy5hZGRTdHJlYW1MaXN0ZW5lcihmdW5jdGlvbiAoamlkKSB7XG4gICAgICAgIFZpZGVvTGF5b3V0Lm9uVmlkZW9UeXBlQ2hhbmdlZChqaWQpO1xuICAgIH0sIFN0cmVhbUV2ZW50VHlwZXMuRVZFTlRfVFlQRV9SRU1PVEVfQ0hBTkdFRCk7XG4gICAgQVBQLlJUQy5hZGRMaXN0ZW5lcihSVENFdmVudHMuTEFTVE5fQ0hBTkdFRCwgb25MYXN0TkNoYW5nZWQpO1xuICAgIEFQUC5SVEMuYWRkTGlzdGVuZXIoUlRDRXZlbnRzLkRPTUlOQU5UU1BFQUtFUl9DSEFOR0VELCBmdW5jdGlvbiAocmVzb3VyY2VKaWQpIHtcbiAgICAgICAgVmlkZW9MYXlvdXQub25Eb21pbmFudFNwZWFrZXJDaGFuZ2VkKHJlc291cmNlSmlkKTtcbiAgICB9KTtcbiAgICBBUFAuUlRDLmFkZExpc3RlbmVyKFJUQ0V2ZW50cy5MQVNUTl9FTkRQT0lOVF9DSEFOR0VELFxuICAgICAgICBmdW5jdGlvbiAobGFzdE5FbmRwb2ludHMsIGVuZHBvaW50c0VudGVyaW5nTGFzdE4sIHN0cmVhbSkge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQub25MYXN0TkVuZHBvaW50c0NoYW5nZWQobGFzdE5FbmRwb2ludHMsXG4gICAgICAgICAgICAgICAgZW5kcG9pbnRzRW50ZXJpbmdMYXN0Tiwgc3RyZWFtKTtcbiAgICAgICAgfSk7XG4gICAgQVBQLlJUQy5hZGRMaXN0ZW5lcihSVENFdmVudHMuU0lNVUxDQVNUX0xBWUVSX0NIQU5HRUQsXG4gICAgICAgIGZ1bmN0aW9uIChlbmRwb2ludFNpbXVsY2FzdExheWVycykge1xuICAgICAgICAgICBWaWRlb0xheW91dC5vblNpbXVsY2FzdExheWVyc0NoYW5nZWQoZW5kcG9pbnRTaW11bGNhc3RMYXllcnMpO1xuICAgICAgICB9KTtcbiAgICBBUFAuUlRDLmFkZExpc3RlbmVyKFJUQ0V2ZW50cy5TSU1VTENBU1RfTEFZRVJfQ0hBTkdJTkcsXG4gICAgICAgIGZ1bmN0aW9uIChlbmRwb2ludFNpbXVsY2FzdExheWVycykge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQub25TaW11bGNhc3RMYXllcnNDaGFuZ2luZyhlbmRwb2ludFNpbXVsY2FzdExheWVycyk7XG4gICAgICAgIH0pO1xuICAgIEFQUC5SVEMuYWRkTGlzdGVuZXIoUlRDRXZlbnRzLkFWQUlMQUJMRV9ERVZJQ0VTX0NIQU5HRUQsXG4gICAgICAgIGZ1bmN0aW9uIChkZXZpY2VzKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5zZXREZXZpY2VBdmFpbGFiaWxpdHlJY29ucyhudWxsLCBkZXZpY2VzKTtcbiAgICAgICAgfSlcbiAgICBBUFAuc3RhdGlzdGljcy5hZGRBdWRpb0xldmVsTGlzdGVuZXIoZnVuY3Rpb24oamlkLCBhdWRpb0xldmVsKVxuICAgIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkO1xuICAgICAgICBpZihqaWQgPT09IEFQUC5zdGF0aXN0aWNzLkxPQ0FMX0pJRClcbiAgICAgICAge1xuICAgICAgICAgICAgcmVzb3VyY2VKaWQgPSBBdWRpb0xldmVscy5MT0NBTF9MRVZFTDtcbiAgICAgICAgICAgIGlmKEFQUC5SVEMubG9jYWxBdWRpby5pc011dGVkKCkpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYXVkaW9MZXZlbCA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIH1cblxuICAgICAgICBBdWRpb0xldmVscy51cGRhdGVBdWRpb0xldmVsKHJlc291cmNlSmlkLCBhdWRpb0xldmVsLFxuICAgICAgICAgICAgVUkuZ2V0TGFyZ2VWaWRlb1N0YXRlKCkudXNlclJlc291cmNlSmlkKTtcbiAgICB9KTtcbiAgICBBUFAuZGVza3RvcHNoYXJpbmcuYWRkTGlzdGVuZXIoZnVuY3Rpb24gKCkge1xuICAgICAgICBUb29sYmFyVG9nZ2xlci5zaG93RGVza3RvcFNoYXJpbmdCdXR0b24oKTtcbiAgICB9LCBEZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXMuSU5JVCk7XG4gICAgQVBQLmRlc2t0b3BzaGFyaW5nLmFkZExpc3RlbmVyKFxuICAgICAgICBUb29sYmFyLmNoYW5nZURlc2t0b3BTaGFyaW5nQnV0dG9uU3RhdGUsXG4gICAgICAgIERlc2t0b3BTaGFyaW5nRXZlbnRUeXBlcy5TV0lUQ0hJTkdfRE9ORSk7XG4gICAgQVBQLmNvbm5lY3Rpb25xdWFsaXR5LmFkZExpc3RlbmVyKENRRXZlbnRzLkxPQ0FMU1RBVFNfVVBEQVRFRCxcbiAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlTG9jYWxDb25uZWN0aW9uU3RhdHMpO1xuICAgIEFQUC5jb25uZWN0aW9ucXVhbGl0eS5hZGRMaXN0ZW5lcihDUUV2ZW50cy5SRU1PVEVTVEFUU19VUERBVEVELFxuICAgICAgICBWaWRlb0xheW91dC51cGRhdGVDb25uZWN0aW9uU3RhdHMpO1xuICAgIEFQUC5jb25uZWN0aW9ucXVhbGl0eS5hZGRMaXN0ZW5lcihDUUV2ZW50cy5TVE9QLFxuICAgICAgICBWaWRlb0xheW91dC5vblN0YXRzU3RvcCk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5ESVNQT1NFX0NPTkZFUkVOQ0UsIG9uRGlzcG9zZUNvbmZlcmVuY2UpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuR1JBQ0VGVUxfU0hVVERPV04sIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbWVzc2FnZUhhbmRsZXIub3Blbk1lc3NhZ2VEaWFsb2coXG4gICAgICAgICAgICAnZGlhbG9nLnNlcnZpY2VVbmF2YWlsYWJsZScsXG4gICAgICAgICAgICAnZGlhbG9nLmdyYWNlZnVsU2h1dGRvd24nXG4gICAgICAgICk7XG4gICAgfSk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5SRVNFUlZBVElPTl9FUlJPUiwgZnVuY3Rpb24gKGNvZGUsIG1zZykge1xuICAgICAgICB2YXIgdGl0bGUgPSBBUFAudHJhbnNsYXRpb24uZ2VuZXJhdGVUcmFuc2xhdG9uSFRNTChcbiAgICAgICAgICAgIFwiZGlhbG9nLnJlc2VydmF0aW9uRXJyb3JcIik7XG4gICAgICAgIHZhciBtZXNzYWdlID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXG4gICAgICAgICAgICBcImRpYWxvZy5yZXNlcnZhdGlvbkVycm9yTXNnXCIsIHtjb2RlOiBjb2RlLCBtc2c6IG1zZ30pO1xuICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuRGlhbG9nKFxuICAgICAgICAgICAgdGl0bGUsXG4gICAgICAgICAgICBtZXNzYWdlLFxuICAgICAgICAgICAgdHJ1ZSwge30sXG4gICAgICAgICAgICBmdW5jdGlvbiAoZXZlbnQsIHZhbHVlLCBtZXNzYWdlLCBmb3JtVmFscylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfSk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5LSUNLRUQsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbWVzc2FnZUhhbmRsZXIub3Blbk1lc3NhZ2VEaWFsb2coXCJkaWFsb2cuc2Vzc1Rlcm1pbmF0ZWRcIixcbiAgICAgICAgICAgIFwiZGlhbG9nLmtpY2tNZXNzYWdlXCIpO1xuICAgIH0pO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTVVDX0RFU1RST1lFRCwgZnVuY3Rpb24gKHJlYXNvbikge1xuICAgICAgICAvL0ZJWE1FOiB1c2UgU2Vzc2lvbiBUZXJtaW5hdGVkIGZyb20gdHJhbnNsYXRpb24sIGJ1dFxuICAgICAgICAvLyAncmVhc29uJyB0ZXh0IGNvbWVzIGZyb20gWE1QUCBwYWNrZXQgYW5kIGlzIG5vdCB0cmFuc2xhdGVkXG4gICAgICAgIHZhciB0aXRsZSA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFwiZGlhbG9nLnNlc3NUZXJtaW5hdGVkXCIpO1xuICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuRGlhbG9nKFxuICAgICAgICAgICAgdGl0bGUsIHJlYXNvbiwgdHJ1ZSwge30sXG4gICAgICAgICAgICBmdW5jdGlvbiAoZXZlbnQsIHZhbHVlLCBtZXNzYWdlLCBmb3JtVmFscylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfSk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5CUklER0VfRE9XTiwgZnVuY3Rpb24gKCkge1xuICAgICAgICBtZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoXCJkaWFsb2cuZXJyb3JcIixcbiAgICAgICAgICAgIFwiZGlhbG9nLmJyaWRnZVVuYXZhaWxhYmxlXCIpO1xuICAgIH0pO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuVVNFUl9JRF9DSEFOR0VELCBmdW5jdGlvbiAoZnJvbSwgaWQpIHtcbiAgICAgICAgQXZhdGFyLnNldFVzZXJBdmF0YXIoZnJvbSwgaWQpO1xuICAgIH0pO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuQ0hBTkdFRF9TVFJFQU1TLCBmdW5jdGlvbiAoamlkLCBjaGFuZ2VkU3RyZWFtcykge1xuICAgICAgICBmb3Ioc3RyZWFtIGluIGNoYW5nZWRTdHJlYW1zKVxuICAgICAgICB7XG4gICAgICAgICAgICAvLyBtaWdodCBuZWVkIHRvIHVwZGF0ZSB0aGUgZGlyZWN0aW9uIGlmIHBhcnRpY2lwYW50IGp1c3Qgd2VudCBmcm9tIHNlbmRyZWN2IHRvIHJlY3Zvbmx5XG4gICAgICAgICAgICBpZiAoc3RyZWFtLnR5cGUgPT09ICd2aWRlbycgfHwgc3RyZWFtLnR5cGUgPT09ICdzY3JlZW4nKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVsID0gJCgnI3BhcnRpY2lwYW50XycgICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSArICc+dmlkZW8nKTtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHN0cmVhbS5kaXJlY3Rpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAnc2VuZHJlY3YnOlxuICAgICAgICAgICAgICAgICAgICAgICAgZWwuc2hvdygpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgJ3JlY3Zvbmx5JzpcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsLmhpZGUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBDaGVjayBpZiB3ZSBoYXZlIHRvIGNoYW5nZSBsYXJnZSB2aWRlb1xuICAgICAgICAgICAgICAgICAgICAgICAgLy9WaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKGVsKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgfSk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5ESVNQTEFZX05BTUVfQ0hBTkdFRCwgb25EaXNwbGF5TmFtZUNoYW5nZWQpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTVVDX0pPSU5FRCwgb25NdWNKb2luZWQpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTE9DQUxST0xFX0NIQU5HRUQsIG9uTG9jYWxSb2xlQ2hhbmdlKTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLk1VQ19FTlRFUiwgb25NdWNFbnRlcmVkKTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLk1VQ19ST0xFX0NIQU5HRUQsIG9uTXVjUm9sZUNoYW5nZWQpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuUFJFU0VOQ0VfU1RBVFVTLCBvbk11Y1ByZXNlbmNlU3RhdHVzKTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLlNVQkpFQ1RfQ0hBTkdFRCwgY2hhdFNldFN1YmplY3QpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTUVTU0FHRV9SRUNFSVZFRCwgdXBkYXRlQ2hhdENvbnZlcnNhdGlvbik7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5NVUNfTEVGVCwgb25NdWNMZWZ0KTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLlBBU1NXT1JEX1JFUVVJUkVELCBvblBhc3N3b3JkUmVxaXVyZWQpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuQ0hBVF9FUlJPUl9SRUNFSVZFRCwgY2hhdEFkZEVycm9yKTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLkVUSEVSUEFELCBpbml0RXRoZXJwYWQpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuQVVUSEVOVElDQVRJT05fUkVRVUlSRUQsXG4gICAgICAgIG9uQXV0aGVudGljYXRpb25SZXF1aXJlZCk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5ERVZJQ0VfQVZBSUxBQkxFLFxuICAgICAgICBmdW5jdGlvbiAocmVzb3VyY2UsIGRldmljZXMpIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNldERldmljZUF2YWlsYWJpbGl0eUljb25zKHJlc291cmNlLCBkZXZpY2VzKTtcbiAgICAgICAgfSk7XG5cbn1cblxuXG4vKipcbiAqIE11dGVzL3VubXV0ZXMgdGhlIGxvY2FsIHZpZGVvLlxuICpcbiAqIEBwYXJhbSBtdXRlIDx0dD50cnVlPC90dD4gdG8gbXV0ZSB0aGUgbG9jYWwgdmlkZW87IG90aGVyd2lzZSwgPHR0PmZhbHNlPC90dD5cbiAqIEBwYXJhbSBvcHRpb25zIGFuIG9iamVjdCB3aGljaCBzcGVjaWZpZXMgb3B0aW9uYWwgYXJndW1lbnRzIHN1Y2ggYXMgdGhlXG4gKiA8dHQ+Ym9vbGVhbjwvdHQ+IGtleSA8dHQ+YnlVc2VyPC90dD4gd2l0aCBkZWZhdWx0IHZhbHVlIDx0dD50cnVlPC90dD4gd2hpY2hcbiAqIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBtZXRob2Qgd2FzIGluaXRpYXRlZCBpbiByZXNwb25zZSB0byBhIHVzZXIgY29tbWFuZCAoaW5cbiAqIGNvbnRyYXN0IHRvIGFuIGF1dG9tYXRpYyBkZWNpc2lvbiB0YWtlbiBieSB0aGUgYXBwbGljYXRpb24gbG9naWMpXG4gKi9cbmZ1bmN0aW9uIHNldFZpZGVvTXV0ZShtdXRlLCBvcHRpb25zKSB7XG4gICAgQVBQLlJUQy5zZXRWaWRlb011dGUobXV0ZSxcbiAgICAgICAgVUkuc2V0VmlkZW9NdXRlQnV0dG9uc1N0YXRlLFxuICAgICAgICBvcHRpb25zKTtcbn1cblxuXG5mdW5jdGlvbiBiaW5kRXZlbnRzKClcbntcbiAgICAvKipcbiAgICAgKiBSZXNpemVzIGFuZCByZXBvc2l0aW9ucyB2aWRlb3MgaW4gZnVsbCBzY3JlZW4gbW9kZS5cbiAgICAgKi9cbiAgICAkKGRvY3VtZW50KS5vbignd2Via2l0ZnVsbHNjcmVlbmNoYW5nZSBtb3pmdWxsc2NyZWVuY2hhbmdlIGZ1bGxzY3JlZW5jaGFuZ2UnLFxuICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5yZXNpemVMYXJnZVZpZGVvQ29udGFpbmVyKCk7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5wb3NpdGlvbkxhcmdlKCk7XG4gICAgICAgIH1cbiAgICApO1xuXG4gICAgJCh3aW5kb3cpLnJlc2l6ZShmdW5jdGlvbiAoKSB7XG4gICAgICAgIFZpZGVvTGF5b3V0LnJlc2l6ZUxhcmdlVmlkZW9Db250YWluZXIoKTtcbiAgICAgICAgVmlkZW9MYXlvdXQucG9zaXRpb25MYXJnZSgpO1xuICAgIH0pO1xufVxuXG5VSS5zdGFydCA9IGZ1bmN0aW9uIChpbml0KSB7XG4gICAgZG9jdW1lbnQudGl0bGUgPSBpbnRlcmZhY2VDb25maWcuQVBQX05BTUU7XG4gICAgaWYoY29uZmlnLmVuYWJsZVdlbGNvbWVQYWdlICYmIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSA9PSBcIi9cIiAmJlxuICAgICAgICAoIXdpbmRvdy5sb2NhbFN0b3JhZ2Uud2VsY29tZVBhZ2VEaXNhYmxlZCB8fCB3aW5kb3cubG9jYWxTdG9yYWdlLndlbGNvbWVQYWdlRGlzYWJsZWQgPT0gXCJmYWxzZVwiKSlcbiAgICB7XG4gICAgICAgICQoXCIjdmlkZW9jb25mZXJlbmNlX3BhZ2VcIikuaGlkZSgpO1xuICAgICAgICB2YXIgc2V0dXBXZWxjb21lUGFnZSA9IHJlcXVpcmUoXCIuL3dlbGNvbWVfcGFnZS9XZWxjb21lUGFnZVwiKTtcbiAgICAgICAgc2V0dXBXZWxjb21lUGFnZSgpO1xuXG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoaW50ZXJmYWNlQ29uZmlnLlNIT1dfSklUU0lfV0FURVJNQVJLKSB7XG4gICAgICAgIHZhciBsZWZ0V2F0ZXJtYXJrRGl2XG4gICAgICAgICAgICA9ICQoXCIjbGFyZ2VWaWRlb0NvbnRhaW5lciBkaXZbY2xhc3M9J3dhdGVybWFyayBsZWZ0d2F0ZXJtYXJrJ11cIik7XG5cbiAgICAgICAgbGVmdFdhdGVybWFya0Rpdi5jc3Moe2Rpc3BsYXk6ICdibG9jayd9KTtcbiAgICAgICAgbGVmdFdhdGVybWFya0Rpdi5wYXJlbnQoKS5nZXQoMCkuaHJlZlxuICAgICAgICAgICAgPSBpbnRlcmZhY2VDb25maWcuSklUU0lfV0FURVJNQVJLX0xJTks7XG4gICAgfVxuXG4gICAgaWYgKGludGVyZmFjZUNvbmZpZy5TSE9XX0JSQU5EX1dBVEVSTUFSSykge1xuICAgICAgICB2YXIgcmlnaHRXYXRlcm1hcmtEaXZcbiAgICAgICAgICAgID0gJChcIiNsYXJnZVZpZGVvQ29udGFpbmVyIGRpdltjbGFzcz0nd2F0ZXJtYXJrIHJpZ2h0d2F0ZXJtYXJrJ11cIik7XG5cbiAgICAgICAgcmlnaHRXYXRlcm1hcmtEaXYuY3NzKHtkaXNwbGF5OiAnYmxvY2snfSk7XG4gICAgICAgIHJpZ2h0V2F0ZXJtYXJrRGl2LnBhcmVudCgpLmdldCgwKS5ocmVmXG4gICAgICAgICAgICA9IGludGVyZmFjZUNvbmZpZy5CUkFORF9XQVRFUk1BUktfTElOSztcbiAgICAgICAgcmlnaHRXYXRlcm1hcmtEaXYuZ2V0KDApLnN0eWxlLmJhY2tncm91bmRJbWFnZVxuICAgICAgICAgICAgPSBcInVybChpbWFnZXMvcmlnaHR3YXRlcm1hcmsucG5nKVwiO1xuICAgIH1cblxuICAgIGlmIChpbnRlcmZhY2VDb25maWcuU0hPV19QT1dFUkVEX0JZKSB7XG4gICAgICAgICQoXCIjbGFyZ2VWaWRlb0NvbnRhaW5lcj5hW2NsYXNzPSdwb3dlcmVkYnknXVwiKS5jc3Moe2Rpc3BsYXk6ICdibG9jayd9KTtcbiAgICB9XG5cbiAgICAkKFwiI3dlbGNvbWVfcGFnZVwiKS5oaWRlKCk7XG5cbiAgICBWaWRlb0xheW91dC5yZXNpemVMYXJnZVZpZGVvQ29udGFpbmVyKCk7XG4gICAgJChcIiN2aWRlb3NwYWNlXCIpLm1vdXNlbW92ZShmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBUb29sYmFyVG9nZ2xlci5zaG93VG9vbGJhcigpO1xuICAgIH0pO1xuICAgIC8vIFNldCB0aGUgZGVmYXVsdHMgZm9yIHByb21wdCBkaWFsb2dzLlxuICAgIGpRdWVyeS5wcm9tcHQuc2V0RGVmYXVsdHMoe3BlcnNpc3RlbnQ6IGZhbHNlfSk7XG5cbiAgICBWaWRlb0xheW91dC5pbml0KGV2ZW50RW1pdHRlcik7XG4gICAgQXVkaW9MZXZlbHMuaW5pdCgpO1xuICAgIE5pY2tuYW1lSGFuZGxlci5pbml0KGV2ZW50RW1pdHRlcik7XG4gICAgcmVnaXN0ZXJMaXN0ZW5lcnMoKTtcbiAgICBiaW5kRXZlbnRzKCk7XG4gICAgc2V0dXBQcmV6aSgpO1xuICAgIHNldHVwVG9vbGJhcnMoKTtcbiAgICBzZXR1cENoYXQoKTtcblxuXG4gICAgZG9jdW1lbnQudGl0bGUgPSBpbnRlcmZhY2VDb25maWcuQVBQX05BTUU7XG5cbiAgICAkKFwiI2Rvd25sb2FkbG9nXCIpLmNsaWNrKGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBkdW1wKGV2ZW50LnRhcmdldCk7XG4gICAgfSk7XG5cbiAgICBpZihjb25maWcuZW5hYmxlV2VsY29tZVBhZ2UgJiYgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lID09IFwiL1wiICYmXG4gICAgICAgICghd2luZG93LmxvY2FsU3RvcmFnZS53ZWxjb21lUGFnZURpc2FibGVkIHx8IHdpbmRvdy5sb2NhbFN0b3JhZ2Uud2VsY29tZVBhZ2VEaXNhYmxlZCA9PSBcImZhbHNlXCIpKVxuICAgIHtcbiAgICAgICAgJChcIiN2aWRlb2NvbmZlcmVuY2VfcGFnZVwiKS5oaWRlKCk7XG4gICAgICAgIHZhciBzZXR1cFdlbGNvbWVQYWdlID0gcmVxdWlyZShcIi4vd2VsY29tZV9wYWdlL1dlbGNvbWVQYWdlXCIpO1xuICAgICAgICBzZXR1cFdlbGNvbWVQYWdlKCk7XG5cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgICQoXCIjd2VsY29tZV9wYWdlXCIpLmhpZGUoKTtcblxuICAgIC8vIERpc3BsYXkgbm90aWNlIG1lc3NhZ2UgYXQgdGhlIHRvcCBvZiB0aGUgdG9vbGJhclxuICAgIGlmIChjb25maWcubm90aWNlTWVzc2FnZSkge1xuICAgICAgICAkKCcjbm90aWNlVGV4dCcpLnRleHQoY29uZmlnLm5vdGljZU1lc3NhZ2UpO1xuICAgICAgICAkKCcjbm90aWNlJykuY3NzKHtkaXNwbGF5OiAnYmxvY2snfSk7XG4gICAgfVxuXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xhcmdlVmlkZW8nKS52b2x1bWUgPSAwO1xuXG4gICAgaWYgKCEkKCcjc2V0dGluZ3MnKS5pcygnOnZpc2libGUnKSkge1xuICAgICAgICBjb25zb2xlLmxvZygnaW5pdCcpO1xuICAgICAgICBpbml0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbG9naW5JbmZvLm9uc3VibWl0ID0gZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGlmIChlLnByZXZlbnREZWZhdWx0KSBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAkKCcjc2V0dGluZ3MnKS5oaWRlKCk7XG4gICAgICAgICAgICBpbml0KCk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdG9hc3RyLm9wdGlvbnMgPSB7XG4gICAgICAgIFwiY2xvc2VCdXR0b25cIjogdHJ1ZSxcbiAgICAgICAgXCJkZWJ1Z1wiOiBmYWxzZSxcbiAgICAgICAgXCJwb3NpdGlvbkNsYXNzXCI6IFwibm90aWZpY2F0aW9uLWJvdHRvbS1yaWdodFwiLFxuICAgICAgICBcIm9uY2xpY2tcIjogbnVsbCxcbiAgICAgICAgXCJzaG93RHVyYXRpb25cIjogXCIzMDBcIixcbiAgICAgICAgXCJoaWRlRHVyYXRpb25cIjogXCIxMDAwXCIsXG4gICAgICAgIFwidGltZU91dFwiOiBcIjIwMDBcIixcbiAgICAgICAgXCJleHRlbmRlZFRpbWVPdXRcIjogXCIxMDAwXCIsXG4gICAgICAgIFwic2hvd0Vhc2luZ1wiOiBcInN3aW5nXCIsXG4gICAgICAgIFwiaGlkZUVhc2luZ1wiOiBcImxpbmVhclwiLFxuICAgICAgICBcInNob3dNZXRob2RcIjogXCJmYWRlSW5cIixcbiAgICAgICAgXCJoaWRlTWV0aG9kXCI6IFwiZmFkZU91dFwiLFxuICAgICAgICBcInJlcG9zaXRpb25cIjogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBpZihQYW5lbFRvZ2dsZXIuaXNWaXNpYmxlKCkpIHtcbiAgICAgICAgICAgICAgICAkKFwiI3RvYXN0LWNvbnRhaW5lclwiKS5hZGRDbGFzcyhcIm5vdGlmaWNhdGlvbi1ib3R0b20tcmlnaHQtY2VudGVyXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAkKFwiI3RvYXN0LWNvbnRhaW5lclwiKS5yZW1vdmVDbGFzcyhcIm5vdGlmaWNhdGlvbi1ib3R0b20tcmlnaHQtY2VudGVyXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBcIm5ld2VzdE9uVG9wXCI6IGZhbHNlXG4gICAgfTtcblxuICAgIFNldHRpbmdzTWVudS5pbml0KCk7XG5cbn07XG5cbmZ1bmN0aW9uIGNoYXRBZGRFcnJvcihlcnJvck1lc3NhZ2UsIG9yaWdpbmFsVGV4dClcbntcbiAgICByZXR1cm4gQ2hhdC5jaGF0QWRkRXJyb3IoZXJyb3JNZXNzYWdlLCBvcmlnaW5hbFRleHQpO1xufTtcblxuZnVuY3Rpb24gY2hhdFNldFN1YmplY3QodGV4dClcbntcbiAgICByZXR1cm4gQ2hhdC5jaGF0U2V0U3ViamVjdCh0ZXh0KTtcbn07XG5cbmZ1bmN0aW9uIHVwZGF0ZUNoYXRDb252ZXJzYXRpb24oZnJvbSwgZGlzcGxheU5hbWUsIG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gQ2hhdC51cGRhdGVDaGF0Q29udmVyc2F0aW9uKGZyb20sIGRpc3BsYXlOYW1lLCBtZXNzYWdlKTtcbn07XG5cbmZ1bmN0aW9uIG9uTXVjSm9pbmVkKGppZCwgaW5mbykge1xuICAgIFRvb2xiYXIudXBkYXRlUm9vbVVybCh3aW5kb3cubG9jYXRpb24uaHJlZik7XG4gICAgdmFyIG1lSFRNTCA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFwibWVcIik7XG4gICAgJChcIiNsb2NhbE5pY2tcIikuaHRtbChTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpICsgXCIgKFwiICsgbWVIVE1MICsgXCIpXCIpO1xuXG4gICAgdmFyIHNldHRpbmdzID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbiAgICAvLyBBZGQgbXlzZWxmIHRvIHRoZSBjb250YWN0IGxpc3QuXG4gICAgQ29udGFjdExpc3QuYWRkQ29udGFjdChqaWQsIHNldHRpbmdzLmVtYWlsIHx8IHNldHRpbmdzLnVpZCk7XG5cbiAgICAvLyBPbmNlIHdlJ3ZlIGpvaW5lZCB0aGUgbXVjIHNob3cgdGhlIHRvb2xiYXJcbiAgICBUb29sYmFyVG9nZ2xlci5zaG93VG9vbGJhcigpO1xuXG4gICAgdmFyIGRpc3BsYXlOYW1lID0gIWNvbmZpZy5kaXNwbGF5Smlkc1xuICAgICAgICA/IGluZm8uZGlzcGxheU5hbWUgOiBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuXG4gICAgaWYgKGRpc3BsYXlOYW1lKVxuICAgICAgICBvbkRpc3BsYXlOYW1lQ2hhbmdlZCgnbG9jYWxWaWRlb0NvbnRhaW5lcicsIGRpc3BsYXlOYW1lKTtcbn1cblxuZnVuY3Rpb24gaW5pdEV0aGVycGFkKG5hbWUpIHtcbiAgICBFdGhlcnBhZC5pbml0KG5hbWUpO1xufTtcblxuZnVuY3Rpb24gb25NdWNMZWZ0KGppZCkge1xuICAgIGNvbnNvbGUubG9nKCdsZWZ0Lm11YycsIGppZCk7XG4gICAgdmFyIGRpc3BsYXlOYW1lID0gJCgnI3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpICtcbiAgICAgICAgJz4uZGlzcGxheW5hbWUnKS5odG1sKCk7XG4gICAgbWVzc2FnZUhhbmRsZXIubm90aWZ5KGRpc3BsYXlOYW1lLCdub3RpZnkuc29tZWJvZHknLFxuICAgICAgICAnZGlzY29ubmVjdGVkJyxcbiAgICAgICAgJ25vdGlmeS5kaXNjb25uZWN0ZWQnKTtcbiAgICAvLyBOZWVkIHRvIGNhbGwgdGhpcyB3aXRoIGEgc2xpZ2h0IGRlbGF5LCBvdGhlcndpc2UgdGhlIGVsZW1lbnQgY291bGRuJ3QgYmVcbiAgICAvLyBmb3VuZCBmb3Igc29tZSByZWFzb24uXG4gICAgLy8gWFhYKGdwKSBpdCB3b3JrcyBmaW5lIHdpdGhvdXQgdGhlIHRpbWVvdXQgZm9yIG1lICh3aXRoIENocm9tZSAzOCkuXG4gICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgY29udGFpbmVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXG4gICAgICAgICAgICAgICAgJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpKTtcbiAgICAgICAgaWYgKGNvbnRhaW5lcikge1xuICAgICAgICAgICAgQ29udGFjdExpc3QucmVtb3ZlQ29udGFjdChqaWQpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVtb3ZlQ29ubmVjdGlvbkluZGljYXRvcihqaWQpO1xuICAgICAgICAgICAgLy8gaGlkZSBoZXJlLCB3YWl0IGZvciB2aWRlbyB0byBjbG9zZSBiZWZvcmUgcmVtb3ZpbmdcbiAgICAgICAgICAgICQoY29udGFpbmVyKS5oaWRlKCk7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5yZXNpemVUaHVtYm5haWxzKCk7XG4gICAgICAgIH1cbiAgICB9LCAxMCk7XG5cbiAgICBWaWRlb0xheW91dC5wYXJ0aWNpcGFudExlZnQoamlkKTtcblxufTtcblxuXG5mdW5jdGlvbiBvbkxvY2FsUm9sZUNoYW5nZShqaWQsIGluZm8sIHByZXMsIGlzTW9kZXJhdG9yKVxue1xuXG4gICAgY29uc29sZS5pbmZvKFwiTXkgcm9sZSBjaGFuZ2VkLCBuZXcgcm9sZTogXCIgKyBpbmZvLnJvbGUpO1xuICAgIG9uTW9kZXJhdG9yU3RhdHVzQ2hhbmdlZChpc01vZGVyYXRvcik7XG4gICAgVmlkZW9MYXlvdXQuc2hvd01vZGVyYXRvckluZGljYXRvcigpO1xuXG4gICAgaWYgKGlzTW9kZXJhdG9yKSB7XG4gICAgICAgIEF1dGhlbnRpY2F0aW9uLmNsb3NlQXV0aGVudGljYXRpb25XaW5kb3coKTtcbiAgICAgICAgbWVzc2FnZUhhbmRsZXIubm90aWZ5KG51bGwsIFwibm90aWZ5Lm1lXCIsXG4gICAgICAgICAgICAnY29ubmVjdGVkJywgXCJub3RpZnkubW9kZXJhdG9yXCIpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gb25Nb2RlcmF0b3JTdGF0dXNDaGFuZ2VkKGlzTW9kZXJhdG9yKSB7XG5cbiAgICBUb29sYmFyLnNob3dTaXBDYWxsQnV0dG9uKGlzTW9kZXJhdG9yKTtcbiAgICBUb29sYmFyLnNob3dSZWNvcmRpbmdCdXR0b24oXG4gICAgICAgIGlzTW9kZXJhdG9yKTsgLy8mJlxuICAgIC8vIEZJWE1FOlxuICAgIC8vIFJlY29yZGluZyB2aXNpYmxlIGlmXG4gICAgLy8gdGhlcmUgYXJlIGF0IGxlYXN0IDIoKyAxIGZvY3VzKSBwYXJ0aWNpcGFudHNcbiAgICAvL09iamVjdC5rZXlzKGNvbm5lY3Rpb24uZW11Yy5tZW1iZXJzKS5sZW5ndGggPj0gMyk7XG5cbiAgICBpZiAoaXNNb2RlcmF0b3IgJiYgY29uZmlnLmV0aGVycGFkX2Jhc2UpIHtcbiAgICAgICAgRXRoZXJwYWQuaW5pdCgpO1xuICAgIH1cbn07XG5cbmZ1bmN0aW9uIG9uUGFzc3dvcmRSZXFpdXJlZChjYWxsYmFjaykge1xuICAgIC8vIHBhc3N3b3JkIGlzIHJlcXVpcmVkXG4gICAgVG9vbGJhci5sb2NrTG9ja0J1dHRvbigpO1xuICAgIHZhciBtZXNzYWdlID0gJzxoMiBkYXRhLWkxOG49XCJkaWFsb2cucGFzc3dvcmRSZXF1aXJlZFwiPic7XG4gICAgbWVzc2FnZSArPSBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nKFxuICAgICAgICBcImRpYWxvZy5wYXNzd29yZFJlcXVpcmVkXCIpO1xuICAgIG1lc3NhZ2UgKz0gJzwvaDI+JyArXG4gICAgICAgICc8aW5wdXQgbmFtZT1cImxvY2tLZXlcIiB0eXBlPVwidGV4dFwiIGRhdGEtaTE4bj0nICtcbiAgICAgICAgJ1wiW3BsYWNlaG9sZGVyXWRpYWxvZy5wYXNzd29yZFwiIHBsYWNlaG9sZGVyPVwiJyArXG4gICAgICAgIEFQUC50cmFuc2xhdGlvbi50cmFuc2xhdGVTdHJpbmcoXCJkaWFsb2cucGFzc3dvcmRcIikgK1xuICAgICAgICAnXCIgYXV0b2ZvY3VzPic7XG5cbiAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKG51bGwsIG51bGwsIG51bGwsIG1lc3NhZ2UsXG4gICAgICAgIHRydWUsXG4gICAgICAgIFwiZGlhbG9nLk9rXCIsXG4gICAgICAgIGZ1bmN0aW9uIChlLCB2LCBtLCBmKSB7fSxcbiAgICAgICAgbnVsbCxcbiAgICAgICAgZnVuY3Rpb24gKGUsIHYsIG0sIGYpIHtcbiAgICAgICAgICAgIGlmICh2KSB7XG4gICAgICAgICAgICAgICAgdmFyIGxvY2tLZXkgPSBmLmxvY2tLZXk7XG4gICAgICAgICAgICAgICAgaWYgKGxvY2tLZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgVG9vbGJhci5zZXRTaGFyZWRLZXkobG9ja0tleSk7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKGxvY2tLZXkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgJzppbnB1dDpmaXJzdCdcbiAgICApO1xufVxuZnVuY3Rpb24gb25NdWNFbnRlcmVkKGppZCwgaWQsIGRpc3BsYXlOYW1lKSB7XG4gICAgbWVzc2FnZUhhbmRsZXIubm90aWZ5KGRpc3BsYXlOYW1lLCdub3RpZnkuc29tZWJvZHknLFxuICAgICAgICAnY29ubmVjdGVkJyxcbiAgICAgICAgJ25vdGlmeS5jb25uZWN0ZWQnKTtcblxuICAgIC8vIEFkZCBQZWVyJ3MgY29udGFpbmVyXG4gICAgVmlkZW9MYXlvdXQuZW5zdXJlUGVlckNvbnRhaW5lckV4aXN0cyhqaWQsaWQpO1xufVxuXG5mdW5jdGlvbiBvbk11Y1ByZXNlbmNlU3RhdHVzKCBqaWQsIGluZm8pIHtcbiAgICBWaWRlb0xheW91dC5zZXRQcmVzZW5jZVN0YXR1cyhcbiAgICAgICAgICAgICdwYXJ0aWNpcGFudF8nICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSwgaW5mby5zdGF0dXMpO1xufVxuXG5mdW5jdGlvbiBvbk11Y1JvbGVDaGFuZ2VkKHJvbGUsIGRpc3BsYXlOYW1lKSB7XG4gICAgVmlkZW9MYXlvdXQuc2hvd01vZGVyYXRvckluZGljYXRvcigpO1xuXG4gICAgaWYgKHJvbGUgPT09ICdtb2RlcmF0b3InKSB7XG4gICAgICAgIHZhciBtZXNzYWdlS2V5LCBtZXNzYWdlT3B0aW9ucyA9IHt9O1xuICAgICAgICBpZiAoIWRpc3BsYXlOYW1lKSB7XG4gICAgICAgICAgICBtZXNzYWdlS2V5ID0gXCJub3RpZnkuZ3JhbnRlZFRvVW5rbm93blwiO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgbWVzc2FnZUtleSA9IFwibm90aWZ5LmdyYW50ZWRUb1wiO1xuICAgICAgICAgICAgbWVzc2FnZU9wdGlvbnMgPSB7dG86IGRpc3BsYXlOYW1lfTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdlSGFuZGxlci5ub3RpZnkoXG4gICAgICAgICAgICBkaXNwbGF5TmFtZSwnbm90aWZ5LnNvbWVib2R5JyxcbiAgICAgICAgICAgICdjb25uZWN0ZWQnLCBtZXNzYWdlS2V5LFxuICAgICAgICAgICAgbWVzc2FnZU9wdGlvbnMpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gb25BdXRoZW50aWNhdGlvblJlcXVpcmVkKGludGVydmFsQ2FsbGJhY2spIHtcbiAgICBBdXRoZW50aWNhdGlvbi5vcGVuQXV0aGVudGljYXRpb25EaWFsb2coXG4gICAgICAgIHJvb21OYW1lLCBpbnRlcnZhbENhbGxiYWNrLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBUb29sYmFyLmF1dGhlbnRpY2F0ZUNsaWNrZWQoKTtcbiAgICAgICAgfSk7XG59O1xuXG5cbmZ1bmN0aW9uIG9uTGFzdE5DaGFuZ2VkKG9sZFZhbHVlLCBuZXdWYWx1ZSkge1xuICAgIGlmIChjb25maWcubXV0ZUxvY2FsVmlkZW9JZk5vdEluTGFzdE4pIHtcbiAgICAgICAgc2V0VmlkZW9NdXRlKCFuZXdWYWx1ZSwgeyAnYnlVc2VyJzogZmFsc2UgfSk7XG4gICAgfVxufVxuXG5cblVJLnRvZ2dsZVNtaWxleXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgQ2hhdC50b2dnbGVTbWlsZXlzKCk7XG59O1xuXG5VSS5nZXRTZXR0aW5ncyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbn07XG5cblVJLnRvZ2dsZUZpbG1TdHJpcCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gQm90dG9tVG9vbGJhci50b2dnbGVGaWxtU3RyaXAoKTtcbn07XG5cblVJLnRvZ2dsZUNoYXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIEJvdHRvbVRvb2xiYXIudG9nZ2xlQ2hhdCgpO1xufTtcblxuVUkudG9nZ2xlQ29udGFjdExpc3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIEJvdHRvbVRvb2xiYXIudG9nZ2xlQ29udGFjdExpc3QoKTtcbn07XG5cblVJLmlucHV0RGlzcGxheU5hbWVIYW5kbGVyID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgVmlkZW9MYXlvdXQuaW5wdXREaXNwbGF5TmFtZUhhbmRsZXIodmFsdWUpO1xufTtcblxuXG5VSS5nZXRMYXJnZVZpZGVvU3RhdGUgPSBmdW5jdGlvbigpXG57XG4gICAgcmV0dXJuIFZpZGVvTGF5b3V0LmdldExhcmdlVmlkZW9TdGF0ZSgpO1xufTtcblxuVUkuZ2VuZXJhdGVSb29tTmFtZSA9IGZ1bmN0aW9uKCkge1xuICAgIGlmKHJvb21OYW1lKVxuICAgICAgICByZXR1cm4gcm9vbU5hbWU7XG4gICAgdmFyIHJvb21ub2RlID0gbnVsbDtcbiAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZTtcblxuICAgIC8vIGRldGVybWluZGUgdGhlIHJvb20gbm9kZSBmcm9tIHRoZSB1cmxcbiAgICAvLyBUT0RPOiBqdXN0IHRoZSByb29tbm9kZSBvciB0aGUgd2hvbGUgYmFyZSBqaWQ/XG4gICAgaWYgKGNvbmZpZy5nZXRyb29tbm9kZSAmJiB0eXBlb2YgY29uZmlnLmdldHJvb21ub2RlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIC8vIGN1c3RvbSBmdW5jdGlvbiBtaWdodCBiZSByZXNwb25zaWJsZSBmb3IgZG9pbmcgdGhlIHB1c2hzdGF0ZVxuICAgICAgICByb29tbm9kZSA9IGNvbmZpZy5nZXRyb29tbm9kZShwYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICAvKiBmYWxsIGJhY2sgdG8gZGVmYXVsdCBzdHJhdGVneVxuICAgICAgICAgKiB0aGlzIGlzIG1ha2luZyBhc3N1bXB0aW9ucyBhYm91dCBob3cgdGhlIFVSTC0+cm9vbSBtYXBwaW5nIGhhcHBlbnMuXG4gICAgICAgICAqIEl0IGN1cnJlbnRseSBhc3N1bWVzIGRlcGxveW1lbnQgYXQgcm9vdCwgd2l0aCBhIHJld3JpdGUgbGlrZSB0aGVcbiAgICAgICAgICogZm9sbG93aW5nIG9uZSAoZm9yIG5naW54KTpcbiAgICAgICAgIGxvY2F0aW9uIH4gXi8oW2EtekEtWjAtOV0rKSQge1xuICAgICAgICAgcmV3cml0ZSBeLyguKikkIC8gYnJlYWs7XG4gICAgICAgICB9XG4gICAgICAgICAqL1xuICAgICAgICBpZiAocGF0aC5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICByb29tbm9kZSA9IHBhdGguc3Vic3RyKDEpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgd29yZCA9IFJvb21OYW1lR2VuZXJhdG9yLmdlbmVyYXRlUm9vbVdpdGhvdXRTZXBhcmF0b3IoKTtcbiAgICAgICAgICAgIHJvb21ub2RlID0gd29yZC50b0xvd2VyQ2FzZSgpO1xuXG4gICAgICAgICAgICB3aW5kb3cuaGlzdG9yeS5wdXNoU3RhdGUoJ1ZpZGVvQ2hhdCcsXG4gICAgICAgICAgICAgICAgICAgICdSb29tOiAnICsgd29yZCwgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lICsgd29yZCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByb29tTmFtZSA9IHJvb21ub2RlICsgJ0AnICsgY29uZmlnLmhvc3RzLm11YztcbiAgICByZXR1cm4gcm9vbU5hbWU7XG59O1xuXG5cblVJLmNvbm5lY3Rpb25JbmRpY2F0b3JTaG93TW9yZSA9IGZ1bmN0aW9uKGlkKVxue1xuICAgIHJldHVybiBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tpZF0uc2hvd01vcmUoKTtcbn07XG5cblVJLnNob3dMb2dpblBvcHVwID0gZnVuY3Rpb24oY2FsbGJhY2spXG57XG4gICAgY29uc29sZS5sb2coJ3Bhc3N3b3JkIGlzIHJlcXVpcmVkJyk7XG4gICAgdmFyIG1lc3NhZ2UgPSAnPGgyIGRhdGEtaTE4bj1cImRpYWxvZy5wYXNzd29yZFJlcXVpcmVkXCI+JztcbiAgICBtZXNzYWdlICs9IEFQUC50cmFuc2xhdGlvbi50cmFuc2xhdGVTdHJpbmcoXG4gICAgICAgIFwiZGlhbG9nLnBhc3N3b3JkUmVxdWlyZWRcIik7XG4gICAgbWVzc2FnZSArPSAnPC9oMj4nICtcbiAgICAgICAgJzxpbnB1dCBuYW1lPVwidXNlcm5hbWVcIiB0eXBlPVwidGV4dFwiICcgK1xuICAgICAgICAncGxhY2Vob2xkZXI9XCJ1c2VyQGRvbWFpbi5uZXRcIiBhdXRvZm9jdXM+JyArXG4gICAgICAgICc8aW5wdXQgbmFtZT1cInBhc3N3b3JkXCIgJyArXG4gICAgICAgICd0eXBlPVwicGFzc3dvcmRcIiBkYXRhLWkxOG49XCJbcGxhY2Vob2xkZXJdZGlhbG9nLnVzZXJQYXNzd29yZFwiJyArXG4gICAgICAgICcgcGxhY2Vob2xkZXI9XCJ1c2VyIHBhc3N3b3JkXCI+JztcbiAgICBVSS5tZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKG51bGwsIG51bGwsIG51bGwsIG1lc3NhZ2UsXG4gICAgICAgIHRydWUsXG4gICAgICAgIFwiZGlhbG9nLk9rXCIsXG4gICAgICAgIGZ1bmN0aW9uIChlLCB2LCBtLCBmKSB7XG4gICAgICAgICAgICBpZiAodikge1xuICAgICAgICAgICAgICAgIGlmIChmLnVzZXJuYW1lICE9PSBudWxsICYmIGYucGFzc3dvcmQgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayhmLnVzZXJuYW1lLCBmLnBhc3N3b3JkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIG51bGwsIG51bGwsICc6aW5wdXQ6Zmlyc3QnXG5cbiAgICApO1xufVxuXG5VSS5jaGVja0Zvck5pY2tuYW1lQW5kSm9pbiA9IGZ1bmN0aW9uICgpIHtcblxuICAgIEF1dGhlbnRpY2F0aW9uLmNsb3NlQXV0aGVudGljYXRpb25EaWFsb2coKTtcbiAgICBBdXRoZW50aWNhdGlvbi5zdG9wSW50ZXJ2YWwoKTtcblxuICAgIHZhciBuaWNrID0gbnVsbDtcbiAgICBpZiAoY29uZmlnLnVzZU5pY2tzKSB7XG4gICAgICAgIG5pY2sgPSB3aW5kb3cucHJvbXB0KCdZb3VyIG5pY2tuYW1lIChvcHRpb25hbCknKTtcbiAgICB9XG4gICAgQVBQLnhtcHAuam9pblJvb20ocm9vbU5hbWUsIGNvbmZpZy51c2VOaWNrcywgbmljayk7XG59O1xuXG5cbmZ1bmN0aW9uIGR1bXAoZWxlbSwgZmlsZW5hbWUpIHtcbiAgICBlbGVtID0gZWxlbS5wYXJlbnROb2RlO1xuICAgIGVsZW0uZG93bmxvYWQgPSBmaWxlbmFtZSB8fCAnbWVldGxvZy5qc29uJztcbiAgICBlbGVtLmhyZWYgPSAnZGF0YTphcHBsaWNhdGlvbi9qc29uO2NoYXJzZXQ9dXRmLTgsXFxuJztcbiAgICB2YXIgZGF0YSA9IEFQUC54bXBwLnBvcHVsYXRlRGF0YSgpO1xuICAgIHZhciBtZXRhZGF0YSA9IHt9O1xuICAgIG1ldGFkYXRhLnRpbWUgPSBuZXcgRGF0ZSgpO1xuICAgIG1ldGFkYXRhLnVybCA9IHdpbmRvdy5sb2NhdGlvbi5ocmVmO1xuICAgIG1ldGFkYXRhLnVhID0gbmF2aWdhdG9yLnVzZXJBZ2VudDtcbiAgICB2YXIgbG9nID0gQVBQLnhtcHAuZ2V0TG9nZ2VyKCk7XG4gICAgaWYgKGxvZykge1xuICAgICAgICBtZXRhZGF0YS54bXBwID0gbG9nO1xuICAgIH1cbiAgICBkYXRhLm1ldGFkYXRhID0gbWV0YWRhdGE7XG4gICAgZWxlbS5ocmVmICs9IGVuY29kZVVSSUNvbXBvbmVudChKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAnICAnKSk7XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuXG5VSS5nZXRSb29tTmFtZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gcm9vbU5hbWU7XG59O1xuXG4vKipcbiAqIE11dGVzL3VubXV0ZXMgdGhlIGxvY2FsIHZpZGVvLlxuICovXG5VSS50b2dnbGVWaWRlbyA9IGZ1bmN0aW9uICgpIHtcbiAgICBzZXRWaWRlb011dGUoIUFQUC5SVEMubG9jYWxWaWRlby5pc011dGVkKCkpO1xufTtcblxuLyoqXG4gKiBNdXRlcyAvIHVubXV0ZXMgYXVkaW8gZm9yIHRoZSBsb2NhbCBwYXJ0aWNpcGFudC5cbiAqL1xuVUkudG9nZ2xlQXVkaW8gPSBmdW5jdGlvbigpIHtcbiAgICBVSS5zZXRBdWRpb011dGVkKCFBUFAuUlRDLmxvY2FsQXVkaW8uaXNNdXRlZCgpKTtcbn07XG5cbi8qKlxuICogU2V0cyBtdXRlZCBhdWRpbyBzdGF0ZSBmb3IgdGhlIGxvY2FsIHBhcnRpY2lwYW50LlxuICovXG5VSS5zZXRBdWRpb011dGVkID0gZnVuY3Rpb24gKG11dGUpIHtcblxuICAgIGlmKCFBUFAueG1wcC5zZXRBdWRpb011dGUobXV0ZSwgZnVuY3Rpb24gKCkge1xuICAgICAgICBWaWRlb0xheW91dC5zaG93TG9jYWxBdWRpb0luZGljYXRvcihtdXRlKTtcblxuICAgICAgICBVSVV0aWwuYnV0dG9uQ2xpY2soXCIjbXV0ZVwiLCBcImljb24tbWljcm9waG9uZSBpY29uLW1pYy1kaXNhYmxlZFwiKTtcbiAgICB9KSlcbiAgICB7XG4gICAgICAgIC8vIFdlIHN0aWxsIGNsaWNrIHRoZSBidXR0b24uXG4gICAgICAgIFVJVXRpbC5idXR0b25DbGljayhcIiNtdXRlXCIsIFwiaWNvbi1taWNyb3Bob25lIGljb24tbWljLWRpc2FibGVkXCIpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG59XG5cblVJLmFkZExpc3RlbmVyID0gZnVuY3Rpb24gKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgZXZlbnRFbWl0dGVyLm9uKHR5cGUsIGxpc3RlbmVyKTtcbn1cblxuVUkuY2xpY2tPblZpZGVvID0gZnVuY3Rpb24gKHZpZGVvTnVtYmVyKSB7XG4gICAgdmFyIHJlbW90ZVZpZGVvcyA9ICQoXCIudmlkZW9jb250YWluZXI6bm90KCNtaXhlZHN0cmVhbSlcIik7XG4gICAgaWYgKHJlbW90ZVZpZGVvcy5sZW5ndGggPiB2aWRlb051bWJlcikge1xuICAgICAgICByZW1vdGVWaWRlb3NbdmlkZW9OdW1iZXJdLmNsaWNrKCk7XG4gICAgfVxufVxuXG4vL1VzZWQgYnkgdG9ydHVyZVxuVUkuc2hvd1Rvb2xiYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIFRvb2xiYXJUb2dnbGVyLnNob3dUb29sYmFyKCk7XG59XG5cbi8vVXNlZCBieSB0b3J0dXJlXG5VSS5kb2NrVG9vbGJhciA9IGZ1bmN0aW9uIChpc0RvY2spIHtcbiAgICByZXR1cm4gVG9vbGJhclRvZ2dsZXIuZG9ja1Rvb2xiYXIoaXNEb2NrKTtcbn1cblxuVUkuc2V0VmlkZW9NdXRlQnV0dG9uc1N0YXRlID0gZnVuY3Rpb24gKG11dGUpIHtcbiAgICB2YXIgdmlkZW8gPSAkKCcjdmlkZW8nKTtcbiAgICB2YXIgY29tbXVuaWNhdGl2ZUNsYXNzID0gXCJpY29uLWNhbWVyYVwiO1xuICAgIHZhciBtdXRlQ2xhc3MgPSBcImljb24tY2FtZXJhIGljb24tY2FtZXJhLWRpc2FibGVkXCI7XG5cbiAgICBpZiAobXV0ZSkge1xuICAgICAgICB2aWRlby5yZW1vdmVDbGFzcyhjb21tdW5pY2F0aXZlQ2xhc3MpO1xuICAgICAgICB2aWRlby5hZGRDbGFzcyhtdXRlQ2xhc3MpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHZpZGVvLnJlbW92ZUNsYXNzKG11dGVDbGFzcyk7XG4gICAgICAgIHZpZGVvLmFkZENsYXNzKGNvbW11bmljYXRpdmVDbGFzcyk7XG4gICAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFVJO1xuXG4iLCJ2YXIgQ2FudmFzVXRpbCA9IHJlcXVpcmUoXCIuL0NhbnZhc1V0aWxzXCIpO1xuXG52YXIgQVNEcmF3Q29udGV4dCA9ICQoJyNhY3RpdmVTcGVha2VyQXVkaW9MZXZlbCcpWzBdLmdldENvbnRleHQoJzJkJyk7XG5cbmZ1bmN0aW9uIGluaXRBY3RpdmVTcGVha2VyQXVkaW9MZXZlbHMoKSB7XG4gICAgdmFyIEFTUmFkaXVzID0gaW50ZXJmYWNlQ29uZmlnLkFDVElWRV9TUEVBS0VSX0FWQVRBUl9TSVpFIC8gMjtcbiAgICB2YXIgQVNDZW50ZXIgPSAoaW50ZXJmYWNlQ29uZmlnLkFDVElWRV9TUEVBS0VSX0FWQVRBUl9TSVpFICsgQVNSYWRpdXMpIC8gMjtcblxuLy8gRHJhdyBhIGNpcmNsZS5cbiAgICBBU0RyYXdDb250ZXh0LmFyYyhBU0NlbnRlciwgQVNDZW50ZXIsIEFTUmFkaXVzLCAwLCAyICogTWF0aC5QSSk7XG5cbi8vIEFkZCBhIHNoYWRvdyBhcm91bmQgdGhlIGNpcmNsZVxuICAgIEFTRHJhd0NvbnRleHQuc2hhZG93Q29sb3IgPSBpbnRlcmZhY2VDb25maWcuU0hBRE9XX0NPTE9SO1xuICAgIEFTRHJhd0NvbnRleHQuc2hhZG93T2Zmc2V0WCA9IDA7XG4gICAgQVNEcmF3Q29udGV4dC5zaGFkb3dPZmZzZXRZID0gMDtcbn1cblxuLyoqXG4gKiBUaGUgYXVkaW8gTGV2ZWxzIHBsdWdpbi5cbiAqL1xudmFyIEF1ZGlvTGV2ZWxzID0gKGZ1bmN0aW9uKG15KSB7XG4gICAgdmFyIGF1ZGlvTGV2ZWxDYW52YXNDYWNoZSA9IHt9O1xuXG4gICAgbXkuTE9DQUxfTEVWRUwgPSAnbG9jYWwnO1xuXG4gICAgbXkuaW5pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaW5pdEFjdGl2ZVNwZWFrZXJBdWRpb0xldmVscygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIGF1ZGlvIGxldmVsIGNhbnZhcyBmb3IgdGhlIGdpdmVuIHBlZXJKaWQuIElmIHRoZSBjYW52YXNcbiAgICAgKiBkaWRuJ3QgZXhpc3Qgd2UgY3JlYXRlIGl0LlxuICAgICAqL1xuICAgIG15LnVwZGF0ZUF1ZGlvTGV2ZWxDYW52YXMgPSBmdW5jdGlvbiAocGVlckppZCwgVmlkZW9MYXlvdXQpIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gbnVsbDtcbiAgICAgICAgdmFyIHZpZGVvU3BhbklkID0gbnVsbDtcbiAgICAgICAgaWYgKCFwZWVySmlkKVxuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAnbG9jYWxWaWRlb0NvbnRhaW5lcic7XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChwZWVySmlkKTtcblxuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHZpZGVvU3BhbiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHZpZGVvU3BhbklkKTtcblxuICAgICAgICBpZiAoIXZpZGVvU3Bhbikge1xuICAgICAgICAgICAgaWYgKHJlc291cmNlSmlkKVxuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJObyB2aWRlbyBlbGVtZW50IGZvciBqaWRcIiwgcmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJObyB2aWRlbyBlbGVtZW50IGZvciBsb2NhbCB2aWRlby5cIik7XG5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBhdWRpb0xldmVsQ2FudmFzID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+Y2FudmFzJyk7XG5cbiAgICAgICAgdmFyIHZpZGVvU3BhY2VXaWR0aCA9ICQoJyNyZW1vdGVWaWRlb3MnKS53aWR0aCgpO1xuICAgICAgICB2YXIgdGh1bWJuYWlsU2l6ZSA9IFZpZGVvTGF5b3V0LmNhbGN1bGF0ZVRodW1ibmFpbFNpemUodmlkZW9TcGFjZVdpZHRoKTtcbiAgICAgICAgdmFyIHRodW1ibmFpbFdpZHRoID0gdGh1bWJuYWlsU2l6ZVswXTtcbiAgICAgICAgdmFyIHRodW1ibmFpbEhlaWdodCA9IHRodW1ibmFpbFNpemVbMV07XG5cbiAgICAgICAgaWYgKCFhdWRpb0xldmVsQ2FudmFzIHx8IGF1ZGlvTGV2ZWxDYW52YXMubGVuZ3RoID09PSAwKSB7XG5cbiAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXMuY2xhc3NOYW1lID0gXCJhdWRpb2xldmVsXCI7XG4gICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzLnN0eWxlLmJvdHRvbSA9IFwiLVwiICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQS8yICsgXCJweFwiO1xuICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhcy5zdHlsZS5sZWZ0ID0gXCItXCIgKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLzIgKyBcInB4XCI7XG4gICAgICAgICAgICByZXNpemVBdWRpb0xldmVsQ2FudmFzKCBhdWRpb0xldmVsQ2FudmFzLFxuICAgICAgICAgICAgICAgICAgICB0aHVtYm5haWxXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgdGh1bWJuYWlsSGVpZ2h0KTtcblxuICAgICAgICAgICAgdmlkZW9TcGFuLmFwcGVuZENoaWxkKGF1ZGlvTGV2ZWxDYW52YXMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhcyA9IGF1ZGlvTGV2ZWxDYW52YXMuZ2V0KDApO1xuXG4gICAgICAgICAgICByZXNpemVBdWRpb0xldmVsQ2FudmFzKCBhdWRpb0xldmVsQ2FudmFzLFxuICAgICAgICAgICAgICAgICAgICB0aHVtYm5haWxXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgdGh1bWJuYWlsSGVpZ2h0KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBhdWRpbyBsZXZlbCBVSSBmb3IgdGhlIGdpdmVuIHJlc291cmNlSmlkLlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc291cmNlSmlkIHRoZSByZXNvdXJjZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZWxlbWVudCBmb3JcbiAgICAgKiB3aGljaCB3ZSBkcmF3IHRoZSBhdWRpbyBsZXZlbFxuICAgICAqIEBwYXJhbSBhdWRpb0xldmVsIHRoZSBuZXdBdWRpbyBsZXZlbCB0byByZW5kZXJcbiAgICAgKi9cbiAgICBteS51cGRhdGVBdWRpb0xldmVsID0gZnVuY3Rpb24gKHJlc291cmNlSmlkLCBhdWRpb0xldmVsLCBsYXJnZVZpZGVvUmVzb3VyY2VKaWQpIHtcbiAgICAgICAgZHJhd0F1ZGlvTGV2ZWxDYW52YXMocmVzb3VyY2VKaWQsIGF1ZGlvTGV2ZWwpO1xuXG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9IGdldFZpZGVvU3BhbklkKHJlc291cmNlSmlkKTtcblxuICAgICAgICB2YXIgYXVkaW9MZXZlbENhbnZhcyA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPmNhbnZhcycpLmdldCgwKTtcblxuICAgICAgICBpZiAoIWF1ZGlvTGV2ZWxDYW52YXMpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdmFyIGRyYXdDb250ZXh0ID0gYXVkaW9MZXZlbENhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuXG4gICAgICAgIHZhciBjYW52YXNDYWNoZSA9IGF1ZGlvTGV2ZWxDYW52YXNDYWNoZVtyZXNvdXJjZUppZF07XG5cbiAgICAgICAgZHJhd0NvbnRleHQuY2xlYXJSZWN0ICgwLCAwLFxuICAgICAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXMud2lkdGgsIGF1ZGlvTGV2ZWxDYW52YXMuaGVpZ2h0KTtcbiAgICAgICAgZHJhd0NvbnRleHQuZHJhd0ltYWdlKGNhbnZhc0NhY2hlLCAwLCAwKTtcblxuICAgICAgICBpZihyZXNvdXJjZUppZCA9PT0gQXVkaW9MZXZlbHMuTE9DQUxfTEVWRUwpIHtcbiAgICAgICAgICAgIGlmKCFBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzb3VyY2VKaWQgPSBBUFAueG1wcC5teVJlc291cmNlKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZihyZXNvdXJjZUppZCAgPT09IGxhcmdlVmlkZW9SZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgQXVkaW9MZXZlbHMudXBkYXRlQWN0aXZlU3BlYWtlckF1ZGlvTGV2ZWwoYXVkaW9MZXZlbCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBteS51cGRhdGVBY3RpdmVTcGVha2VyQXVkaW9MZXZlbCA9IGZ1bmN0aW9uKGF1ZGlvTGV2ZWwpIHtcbiAgICAgICAgaWYoJChcIiNhY3RpdmVTcGVha2VyXCIpLmNzcyhcInZpc2liaWxpdHlcIikgPT0gXCJoaWRkZW5cIilcbiAgICAgICAgICAgIHJldHVybjtcblxuXG4gICAgICAgIEFTRHJhd0NvbnRleHQuY2xlYXJSZWN0KDAsIDAsIDMwMCwgMzAwKTtcbiAgICAgICAgaWYoYXVkaW9MZXZlbCA9PSAwKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIEFTRHJhd0NvbnRleHQuc2hhZG93Qmx1ciA9IGdldFNoYWRvd0xldmVsKGF1ZGlvTGV2ZWwpO1xuXG5cbiAgICAgICAgLy8gRmlsbCB0aGUgc2hhcGUuXG4gICAgICAgIEFTRHJhd0NvbnRleHQuZmlsbCgpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXNpemVzIHRoZSBnaXZlbiBhdWRpbyBsZXZlbCBjYW52YXMgdG8gbWF0Y2ggdGhlIGdpdmVuIHRodW1ibmFpbCBzaXplLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHJlc2l6ZUF1ZGlvTGV2ZWxDYW52YXMoYXVkaW9MZXZlbENhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRodW1ibmFpbFdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGh1bWJuYWlsSGVpZ2h0KSB7XG4gICAgICAgIGF1ZGlvTGV2ZWxDYW52YXMud2lkdGggPSB0aHVtYm5haWxXaWR0aCArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkE7XG4gICAgICAgIGF1ZGlvTGV2ZWxDYW52YXMuaGVpZ2h0ID0gdGh1bWJuYWlsSGVpZ2h0ICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEcmF3cyB0aGUgYXVkaW8gbGV2ZWwgY2FudmFzIGludG8gdGhlIGNhY2hlZCBjYW52YXMgb2JqZWN0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc291cmNlSmlkIHRoZSByZXNvdXJjZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZWxlbWVudCBmb3JcbiAgICAgKiB3aGljaCB3ZSBkcmF3IHRoZSBhdWRpbyBsZXZlbFxuICAgICAqIEBwYXJhbSBhdWRpb0xldmVsIHRoZSBuZXdBdWRpbyBsZXZlbCB0byByZW5kZXJcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBkcmF3QXVkaW9MZXZlbENhbnZhcyhyZXNvdXJjZUppZCwgYXVkaW9MZXZlbCkge1xuICAgICAgICBpZiAoIWF1ZGlvTGV2ZWxDYW52YXNDYWNoZVtyZXNvdXJjZUppZF0pIHtcblxuICAgICAgICAgICAgdmFyIHZpZGVvU3BhbklkID0gZ2V0VmlkZW9TcGFuSWQocmVzb3VyY2VKaWQpO1xuXG4gICAgICAgICAgICB2YXIgYXVkaW9MZXZlbENhbnZhc09yaWcgPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5jYW52YXMnKS5nZXQoMCk7XG5cbiAgICAgICAgICAgIC8qXG4gICAgICAgICAgICAgKiBGSVhNRSBUZXN0aW5nIGhhcyBzaG93biB0aGF0IGF1ZGlvTGV2ZWxDYW52YXNPcmlnIG1heSBub3QgZXhpc3QuXG4gICAgICAgICAgICAgKiBJbiBzdWNoIGEgY2FzZSwgdGhlIG1ldGhvZCBDYW52YXNVdGlsLmNsb25lQ2FudmFzIG1heSB0aHJvdyBhblxuICAgICAgICAgICAgICogZXJyb3IuIFNpbmNlIGF1ZGlvIGxldmVscyBhcmUgZnJlcXVlbnRseSB1cGRhdGVkLCB0aGUgZXJyb3JzIGhhdmVcbiAgICAgICAgICAgICAqIGJlZW4gb2JzZXJ2ZWQgdG8gcGlsZSBpbnRvIHRoZSBjb25zb2xlLCBzdHJhaW4gdGhlIENQVS5cbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgaWYgKGF1ZGlvTGV2ZWxDYW52YXNPcmlnKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXNDYWNoZVtyZXNvdXJjZUppZF1cbiAgICAgICAgICAgICAgICAgICAgPSBDYW52YXNVdGlsLmNsb25lQ2FudmFzKGF1ZGlvTGV2ZWxDYW52YXNPcmlnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjYW52YXMgPSBhdWRpb0xldmVsQ2FudmFzQ2FjaGVbcmVzb3VyY2VKaWRdO1xuXG4gICAgICAgIGlmICghY2FudmFzKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHZhciBkcmF3Q29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuXG4gICAgICAgIGRyYXdDb250ZXh0LmNsZWFyUmVjdCgwLCAwLCBjYW52YXMud2lkdGgsIGNhbnZhcy5oZWlnaHQpO1xuXG4gICAgICAgIHZhciBzaGFkb3dMZXZlbCA9IGdldFNoYWRvd0xldmVsKGF1ZGlvTGV2ZWwpO1xuXG4gICAgICAgIGlmIChzaGFkb3dMZXZlbCA+IDApXG4gICAgICAgICAgICAvLyBkcmF3Q29udGV4dCwgeCwgeSwgdywgaCwgciwgc2hhZG93Q29sb3IsIHNoYWRvd0xldmVsXG4gICAgICAgICAgICBDYW52YXNVdGlsLmRyYXdSb3VuZFJlY3RHbG93KCAgIGRyYXdDb250ZXh0LFxuICAgICAgICAgICAgICAgIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEvMiwgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQS8yLFxuICAgICAgICAgICAgICAgIGNhbnZhcy53aWR0aCAtIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEsXG4gICAgICAgICAgICAgICAgY2FudmFzLmhlaWdodCAtIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEsXG4gICAgICAgICAgICAgICAgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19SQURJVVMsXG4gICAgICAgICAgICAgICAgaW50ZXJmYWNlQ29uZmlnLlNIQURPV19DT0xPUixcbiAgICAgICAgICAgICAgICBzaGFkb3dMZXZlbCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgc2hhZG93L2dsb3cgbGV2ZWwgZm9yIHRoZSBnaXZlbiBhdWRpbyBsZXZlbC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBhdWRpb0xldmVsIHRoZSBhdWRpbyBsZXZlbCBmcm9tIHdoaWNoIHdlIGRldGVybWluZSB0aGUgc2hhZG93XG4gICAgICogbGV2ZWxcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRTaGFkb3dMZXZlbCAoYXVkaW9MZXZlbCkge1xuICAgICAgICB2YXIgc2hhZG93TGV2ZWwgPSAwO1xuXG4gICAgICAgIGlmIChhdWRpb0xldmVsIDw9IDAuMykge1xuICAgICAgICAgICAgc2hhZG93TGV2ZWwgPSBNYXRoLnJvdW5kKGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEvMiooYXVkaW9MZXZlbC8wLjMpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChhdWRpb0xldmVsIDw9IDAuNikge1xuICAgICAgICAgICAgc2hhZG93TGV2ZWwgPSBNYXRoLnJvdW5kKGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEvMiooKGF1ZGlvTGV2ZWwgLSAwLjMpIC8gMC4zKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzaGFkb3dMZXZlbCA9IE1hdGgucm91bmQoaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQS8yKigoYXVkaW9MZXZlbCAtIDAuNikgLyAwLjQpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2hhZG93TGV2ZWw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgdmlkZW8gc3BhbiBpZCBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiByZXNvdXJjZUppZCBvciBsb2NhbFxuICAgICAqIHVzZXIuXG4gICAgICovXG4gICAgZnVuY3Rpb24gZ2V0VmlkZW9TcGFuSWQocmVzb3VyY2VKaWQpIHtcbiAgICAgICAgdmFyIHZpZGVvU3BhbklkID0gbnVsbDtcbiAgICAgICAgaWYgKHJlc291cmNlSmlkID09PSBBdWRpb0xldmVscy5MT0NBTF9MRVZFTFxuICAgICAgICAgICAgICAgIHx8IChBUFAueG1wcC5teVJlc291cmNlKCkgJiYgcmVzb3VyY2VKaWRcbiAgICAgICAgICAgICAgICAgICAgPT09IEFQUC54bXBwLm15UmVzb3VyY2UoKSkpXG4gICAgICAgICAgICB2aWRlb1NwYW5JZCA9ICdsb2NhbFZpZGVvQ29udGFpbmVyJztcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkO1xuXG4gICAgICAgIHJldHVybiB2aWRlb1NwYW5JZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgdGhhdCB0aGUgcmVtb3RlIHZpZGVvIGhhcyBiZWVuIHJlc2l6ZWQuXG4gICAgICovXG4gICAgJChkb2N1bWVudCkuYmluZCgncmVtb3RldmlkZW8ucmVzaXplZCcsIGZ1bmN0aW9uIChldmVudCwgd2lkdGgsIGhlaWdodCkge1xuICAgICAgICB2YXIgcmVzaXplZCA9IGZhbHNlO1xuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zPnNwYW4+Y2FudmFzJykuZWFjaChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBjYW52YXMgPSAkKHRoaXMpLmdldCgwKTtcbiAgICAgICAgICAgIGlmIChjYW52YXMud2lkdGggIT09IHdpZHRoICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQSkge1xuICAgICAgICAgICAgICAgIGNhbnZhcy53aWR0aCA9IHdpZHRoICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQTtcbiAgICAgICAgICAgICAgICByZXNpemVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGNhbnZhcy5oZWlnaCAhPT0gaGVpZ2h0ICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQSkge1xuICAgICAgICAgICAgICAgIGNhbnZhcy5oZWlnaHQgPSBoZWlnaHQgKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBO1xuICAgICAgICAgICAgICAgIHJlc2l6ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAocmVzaXplZClcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKGF1ZGlvTGV2ZWxDYW52YXNDYWNoZSkuZm9yRWFjaChmdW5jdGlvbiAocmVzb3VyY2VKaWQpIHtcbiAgICAgICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzQ2FjaGVbcmVzb3VyY2VKaWRdLndpZHRoXG4gICAgICAgICAgICAgICAgICAgID0gd2lkdGggKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBO1xuICAgICAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXNDYWNoZVtyZXNvdXJjZUppZF0uaGVpZ2h0XG4gICAgICAgICAgICAgICAgICAgID0gaGVpZ2h0ICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQTtcbiAgICAgICAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIG15O1xuXG59KShBdWRpb0xldmVscyB8fCB7fSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQXVkaW9MZXZlbHM7IiwiLyoqXG4gKiBVdGlsaXR5IGNsYXNzIGZvciBkcmF3aW5nIGNhbnZhcyBzaGFwZXMuXG4gKi9cbnZhciBDYW52YXNVdGlsID0gKGZ1bmN0aW9uKG15KSB7XG5cbiAgICAvKipcbiAgICAgKiBEcmF3cyBhIHJvdW5kIHJlY3RhbmdsZSB3aXRoIGEgZ2xvdy4gVGhlIGdsb3dXaWR0aCBpbmRpY2F0ZXMgdGhlIGRlcHRoXG4gICAgICogb2YgdGhlIGdsb3cuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZHJhd0NvbnRleHQgdGhlIGNvbnRleHQgb2YgdGhlIGNhbnZhcyB0byBkcmF3IHRvXG4gICAgICogQHBhcmFtIHggdGhlIHggY29vcmRpbmF0ZSBvZiB0aGUgcm91bmQgcmVjdGFuZ2xlXG4gICAgICogQHBhcmFtIHkgdGhlIHkgY29vcmRpbmF0ZSBvZiB0aGUgcm91bmQgcmVjdGFuZ2xlXG4gICAgICogQHBhcmFtIHcgdGhlIHdpZHRoIG9mIHRoZSByb3VuZCByZWN0YW5nbGVcbiAgICAgKiBAcGFyYW0gaCB0aGUgaGVpZ2h0IG9mIHRoZSByb3VuZCByZWN0YW5nbGVcbiAgICAgKiBAcGFyYW0gZ2xvd0NvbG9yIHRoZSBjb2xvciBvZiB0aGUgZ2xvd1xuICAgICAqIEBwYXJhbSBnbG93V2lkdGggdGhlIHdpZHRoIG9mIHRoZSBnbG93XG4gICAgICovXG4gICAgbXkuZHJhd1JvdW5kUmVjdEdsb3dcbiAgICAgICAgPSBmdW5jdGlvbihkcmF3Q29udGV4dCwgeCwgeSwgdywgaCwgciwgZ2xvd0NvbG9yLCBnbG93V2lkdGgpIHtcblxuICAgICAgICAvLyBTYXZlIHRoZSBwcmV2aW91cyBzdGF0ZSBvZiB0aGUgY29udGV4dC5cbiAgICAgICAgZHJhd0NvbnRleHQuc2F2ZSgpO1xuXG4gICAgICAgIGlmICh3IDwgMiAqIHIpIHIgPSB3IC8gMjtcbiAgICAgICAgaWYgKGggPCAyICogcikgciA9IGggLyAyO1xuXG4gICAgICAgIC8vIERyYXcgYSByb3VuZCByZWN0YW5nbGUuXG4gICAgICAgIGRyYXdDb250ZXh0LmJlZ2luUGF0aCgpO1xuICAgICAgICBkcmF3Q29udGV4dC5tb3ZlVG8oeCtyLCB5KTtcbiAgICAgICAgZHJhd0NvbnRleHQuYXJjVG8oeCt3LCB5LCAgIHgrdywgeStoLCByKTtcbiAgICAgICAgZHJhd0NvbnRleHQuYXJjVG8oeCt3LCB5K2gsIHgsICAgeStoLCByKTtcbiAgICAgICAgZHJhd0NvbnRleHQuYXJjVG8oeCwgICB5K2gsIHgsICAgeSwgICByKTtcbiAgICAgICAgZHJhd0NvbnRleHQuYXJjVG8oeCwgICB5LCAgIHgrdywgeSwgICByKTtcbiAgICAgICAgZHJhd0NvbnRleHQuY2xvc2VQYXRoKCk7XG5cbiAgICAgICAgLy8gQWRkIGEgc2hhZG93IGFyb3VuZCB0aGUgcmVjdGFuZ2xlXG4gICAgICAgIGRyYXdDb250ZXh0LnNoYWRvd0NvbG9yID0gZ2xvd0NvbG9yO1xuICAgICAgICBkcmF3Q29udGV4dC5zaGFkb3dCbHVyID0gZ2xvd1dpZHRoO1xuICAgICAgICBkcmF3Q29udGV4dC5zaGFkb3dPZmZzZXRYID0gMDtcbiAgICAgICAgZHJhd0NvbnRleHQuc2hhZG93T2Zmc2V0WSA9IDA7XG5cbiAgICAgICAgLy8gRmlsbCB0aGUgc2hhcGUuXG4gICAgICAgIGRyYXdDb250ZXh0LmZpbGwoKTtcblxuICAgICAgICBkcmF3Q29udGV4dC5zYXZlKCk7XG5cbiAgICAgICAgZHJhd0NvbnRleHQucmVzdG9yZSgpO1xuXG4vLyAgICAgIDEpIFVuY29tbWVudCB0aGlzIGxpbmUgdG8gdXNlIENvbXBvc2l0ZSBPcGVyYXRpb24sIHdoaWNoIGlzIGRvaW5nIHRoZVxuLy8gICAgICBzYW1lIGFzIHRoZSBjbGlwIGZ1bmN0aW9uIGJlbG93IGFuZCBpcyBhbHNvIGFudGlhbGlhc2luZyB0aGUgcm91bmRcbi8vICAgICAgYm9yZGVyLCBidXQgaXMgc2FpZCB0byBiZSBsZXNzIGZhc3QgcGVyZm9ybWFuY2Ugd2lzZS5cblxuLy8gICAgICBkcmF3Q29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb249J2Rlc3RpbmF0aW9uLW91dCc7XG5cbiAgICAgICAgZHJhd0NvbnRleHQuYmVnaW5QYXRoKCk7XG4gICAgICAgIGRyYXdDb250ZXh0Lm1vdmVUbyh4K3IsIHkpO1xuICAgICAgICBkcmF3Q29udGV4dC5hcmNUbyh4K3csIHksICAgeCt3LCB5K2gsIHIpO1xuICAgICAgICBkcmF3Q29udGV4dC5hcmNUbyh4K3csIHkraCwgeCwgICB5K2gsIHIpO1xuICAgICAgICBkcmF3Q29udGV4dC5hcmNUbyh4LCAgIHkraCwgeCwgICB5LCAgIHIpO1xuICAgICAgICBkcmF3Q29udGV4dC5hcmNUbyh4LCAgIHksICAgeCt3LCB5LCAgIHIpO1xuICAgICAgICBkcmF3Q29udGV4dC5jbG9zZVBhdGgoKTtcblxuLy8gICAgICAyKSBVbmNvbW1lbnQgdGhpcyBsaW5lIHRvIHVzZSBDb21wb3NpdGUgT3BlcmF0aW9uLCB3aGljaCBpcyBkb2luZyB0aGVcbi8vICAgICAgc2FtZSBhcyB0aGUgY2xpcCBmdW5jdGlvbiBiZWxvdyBhbmQgaXMgYWxzbyBhbnRpYWxpYXNpbmcgdGhlIHJvdW5kXG4vLyAgICAgIGJvcmRlciwgYnV0IGlzIHNhaWQgdG8gYmUgbGVzcyBmYXN0IHBlcmZvcm1hbmNlIHdpc2UuXG5cbi8vICAgICAgZHJhd0NvbnRleHQuZmlsbCgpO1xuXG4gICAgICAgIC8vIENvbW1lbnQgdGhlc2UgdHdvIGxpbmVzIGlmIGNob29zaW5nIHRvIGRvIHRoZSBzYW1lIHdpdGggY29tcG9zaXRlXG4gICAgICAgIC8vIG9wZXJhdGlvbiBhYm92ZSAxIGFuZCAyLlxuICAgICAgICBkcmF3Q29udGV4dC5jbGlwKCk7XG4gICAgICAgIGRyYXdDb250ZXh0LmNsZWFyUmVjdCgwLCAwLCAyNzcsIDIwMCk7XG5cbiAgICAgICAgLy8gUmVzdG9yZSB0aGUgcHJldmlvdXMgY29udGV4dCBzdGF0ZS5cbiAgICAgICAgZHJhd0NvbnRleHQucmVzdG9yZSgpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDbG9uZXMgdGhlIGdpdmVuIGNhbnZhcy5cbiAgICAgKlxuICAgICAqIEByZXR1cm4gdGhlIG5ldyBjbG9uZWQgY2FudmFzLlxuICAgICAqL1xuICAgIG15LmNsb25lQ2FudmFzID0gZnVuY3Rpb24gKG9sZENhbnZhcykge1xuICAgICAgICAvKlxuICAgICAgICAgKiBGSVhNRSBUZXN0aW5nIGhhcyBzaG93biB0aGF0IG9sZENhbnZhcyBtYXkgbm90IGV4aXN0LiBJbiBzdWNoIGEgY2FzZSxcbiAgICAgICAgICogdGhlIG1ldGhvZCBDYW52YXNVdGlsLmNsb25lQ2FudmFzIG1heSB0aHJvdyBhbiBlcnJvci4gU2luY2UgYXVkaW9cbiAgICAgICAgICogbGV2ZWxzIGFyZSBmcmVxdWVudGx5IHVwZGF0ZWQsIHRoZSBlcnJvcnMgaGF2ZSBiZWVuIG9ic2VydmVkIHRvIHBpbGVcbiAgICAgICAgICogaW50byB0aGUgY29uc29sZSwgc3RyYWluIHRoZSBDUFUuXG4gICAgICAgICAqL1xuICAgICAgICBpZiAoIW9sZENhbnZhcylcbiAgICAgICAgICAgIHJldHVybiBvbGRDYW52YXM7XG5cbiAgICAgICAgLy9jcmVhdGUgYSBuZXcgY2FudmFzXG4gICAgICAgIHZhciBuZXdDYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICAgICAgdmFyIGNvbnRleHQgPSBuZXdDYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcblxuICAgICAgICAvL3NldCBkaW1lbnNpb25zXG4gICAgICAgIG5ld0NhbnZhcy53aWR0aCA9IG9sZENhbnZhcy53aWR0aDtcbiAgICAgICAgbmV3Q2FudmFzLmhlaWdodCA9IG9sZENhbnZhcy5oZWlnaHQ7XG5cbiAgICAgICAgLy9hcHBseSB0aGUgb2xkIGNhbnZhcyB0byB0aGUgbmV3IG9uZVxuICAgICAgICBjb250ZXh0LmRyYXdJbWFnZShvbGRDYW52YXMsIDAsIDApO1xuXG4gICAgICAgIC8vcmV0dXJuIHRoZSBuZXcgY2FudmFzXG4gICAgICAgIHJldHVybiBuZXdDYW52YXM7XG4gICAgfTtcblxuICAgIHJldHVybiBteTtcbn0pKENhbnZhc1V0aWwgfHwge30pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENhbnZhc1V0aWw7IiwiLyogZ2xvYmFsICQsIEFQUCovXG5cbnZhciBMb2dpbkRpYWxvZyA9IHJlcXVpcmUoJy4vTG9naW5EaWFsb2cnKTtcbnZhciBNb2RlcmF0b3IgPSByZXF1aXJlKCcuLi8uLi94bXBwL21vZGVyYXRvcicpO1xuXG4vKiBJbml0aWFsIFwiYXV0aGVudGljYXRpb24gcmVxdWlyZWRcIiBkaWFsb2cgKi9cbnZhciBhdXRoRGlhbG9nID0gbnVsbDtcbi8qIExvb3AgcmV0cnkgSUQgdGhhdCB3aXRzIGZvciBvdGhlciB1c2VyIHRvIGNyZWF0ZSB0aGUgcm9vbSAqL1xudmFyIGF1dGhSZXRyeUlkID0gbnVsbDtcbnZhciBhdXRoZW50aWNhdGlvbldpbmRvdyA9IG51bGw7XG5cbnZhciBBdXRoZW50aWNhdGlvbiA9IHtcbiAgICBvcGVuQXV0aGVudGljYXRpb25EaWFsb2c6IGZ1bmN0aW9uIChyb29tTmFtZSwgaW50ZXJ2YWxDYWxsYmFjaywgY2FsbGJhY2spIHtcbiAgICAgICAgLy8gVGhpcyBpcyB0aGUgbG9vcCB0aGF0IHdpbGwgd2FpdCBmb3IgdGhlIHJvb20gdG8gYmUgY3JlYXRlZCBieVxuICAgICAgICAvLyBzb21lb25lIGVsc2UuICdhdXRoX3JlcXVpcmVkLm1vZGVyYXRvcicgd2lsbCBicmluZyB1cyBiYWNrIGhlcmUuXG4gICAgICAgIGF1dGhSZXRyeUlkID0gd2luZG93LnNldFRpbWVvdXQoaW50ZXJ2YWxDYWxsYmFjaywgNTAwMCk7XG4gICAgICAgIC8vIFNob3cgcHJvbXB0IG9ubHkgaWYgaXQncyBub3Qgb3BlblxuICAgICAgICBpZiAoYXV0aERpYWxvZyAhPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIGV4dHJhY3Qgcm9vbSBuYW1lIGZyb20gJ3Jvb21AbXVjLnNlcnZlci5uZXQnXG4gICAgICAgIHZhciByb29tID0gcm9vbU5hbWUuc3Vic3RyKDAsIHJvb21OYW1lLmluZGV4T2YoJ0AnKSk7XG5cbiAgICAgICAgdmFyIHRpdGxlID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXCJkaWFsb2cuU3RvcFwiKTtcbiAgICAgICAgdmFyIG1zZyA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFwiZGlhbG9nLkF1dGhNc2dcIixcbiAgICAgICAgICAgIHtyb29tOiByb29tfSk7XG5cbiAgICAgICAgdmFyIGJ1dHRvblR4dFxuICAgICAgICAgICAgPSBBUFAudHJhbnNsYXRpb24uZ2VuZXJhdGVUcmFuc2xhdG9uSFRNTChcImRpYWxvZy5BdXRoZW50aWNhdGVcIik7XG4gICAgICAgIHZhciBidXR0b25zID0gW107XG4gICAgICAgIGJ1dHRvbnMucHVzaCh7dGl0bGU6IGJ1dHRvblR4dCwgdmFsdWU6IFwiYXV0aE5vd1wifSk7XG5cbiAgICAgICAgYXV0aERpYWxvZyA9IEFQUC5VSS5tZXNzYWdlSGFuZGxlci5vcGVuRGlhbG9nKFxuICAgICAgICAgICAgdGl0bGUsXG4gICAgICAgICAgICBtc2csXG4gICAgICAgICAgICB0cnVlLFxuICAgICAgICAgICAgYnV0dG9ucyxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChvblN1Ym1pdEV2ZW50LCBzdWJtaXRWYWx1ZSkge1xuXG4gICAgICAgICAgICAgICAgLy8gRG8gbm90IGNsb3NlIHRoZSBkaWFsb2cgeWV0XG4gICAgICAgICAgICAgICAgb25TdWJtaXRFdmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgICAgICAgICAgLy8gT3BlbiBsb2dpbiBwb3B1cFxuICAgICAgICAgICAgICAgIGlmIChzdWJtaXRWYWx1ZSA9PT0gJ2F1dGhOb3cnKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH0sXG4gICAgY2xvc2VBdXRoZW50aWNhdGlvbldpbmRvdzogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoYXV0aGVudGljYXRpb25XaW5kb3cpIHtcbiAgICAgICAgICAgIGF1dGhlbnRpY2F0aW9uV2luZG93LmNsb3NlKCk7XG4gICAgICAgICAgICBhdXRoZW50aWNhdGlvbldpbmRvdyA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHhtcHBBdXRoZW50aWNhdGU6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgbG9naW5EaWFsb2cgPSBMb2dpbkRpYWxvZy5zaG93KFxuICAgICAgICAgICAgZnVuY3Rpb24gKGNvbm5lY3Rpb24sIHN0YXRlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFzdGF0ZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBVc2VyIGNhbmNlbGxlZFxuICAgICAgICAgICAgICAgICAgICBsb2dpbkRpYWxvZy5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChzdGF0ZSA9PSBBUFAueG1wcC5TdGF0dXMuQ09OTkVDVEVEKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgbG9naW5EaWFsb2cuY2xvc2UoKTtcblxuICAgICAgICAgICAgICAgICAgICBBdXRoZW50aWNhdGlvbi5zdG9wSW50ZXJ2YWwoKTtcbiAgICAgICAgICAgICAgICAgICAgQXV0aGVudGljYXRpb24uY2xvc2VBdXRoZW50aWNhdGlvbkRpYWxvZygpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIENsb3NlIHRoZSBjb25uZWN0aW9uIGFzIGFub255bW91cyBvbmUgd2lsbCBiZSB1c2VkXG4gICAgICAgICAgICAgICAgICAgIC8vIHRvIGNyZWF0ZSB0aGUgY29uZmVyZW5jZS4gU2Vzc2lvbi1pZCB3aWxsIGF1dGhvcml6ZVxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgcmVxdWVzdC5cbiAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbi5kaXNjb25uZWN0KCk7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIHJvb21OYW1lID0gQVBQLlVJLmdlbmVyYXRlUm9vbU5hbWUoKTtcbiAgICAgICAgICAgICAgICAgICAgTW9kZXJhdG9yLmFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzKHJvb21OYW1lLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBpdCdzIG5vdCBcIm9uIHRoZSBmbHlcIiBhdXRoZW50aWNhdGlvbiBub3cgam9pblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIGNvbmZlcmVuY2Ugcm9vbVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFBUFAueG1wcC5nZXRNVUNKb2luZWQoKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFQUC5VSS5jaGVja0Zvck5pY2tuYW1lQW5kSm9pbigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCB0cnVlKTtcbiAgICB9LFxuICAgIGZvY3VzQXV0aGVudGljYXRpb25XaW5kb3c6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gSWYgYXV0aCB3aW5kb3cgZXhpc3RzIGp1c3QgYnJpbmcgaXQgdG8gdGhlIGZyb250XG4gICAgICAgIGlmIChhdXRoZW50aWNhdGlvbldpbmRvdykge1xuICAgICAgICAgICAgYXV0aGVudGljYXRpb25XaW5kb3cuZm9jdXMoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgY2xvc2VBdXRoZW50aWNhdGlvbkRpYWxvZzogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBDbG9zZSBhdXRoZW50aWNhdGlvbiBkaWFsb2cgaWYgb3BlbmVkXG4gICAgICAgIGlmIChhdXRoRGlhbG9nKSB7XG4gICAgICAgICAgICBhdXRoRGlhbG9nLmNsb3NlKCk7XG4gICAgICAgICAgICBhdXRoRGlhbG9nID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgY3JlYXRlQXV0aGVudGljYXRpb25XaW5kb3c6IGZ1bmN0aW9uIChjYWxsYmFjaywgdXJsKSB7XG4gICAgICAgIGF1dGhlbnRpY2F0aW9uV2luZG93ID0gQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLm9wZW5DZW50ZXJlZFBvcHVwKFxuICAgICAgICAgICAgdXJsLCA5MTAsIDY2MCxcbiAgICAgICAgICAgIC8vIE9uIGNsb3NlZFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIC8vIENsb3NlIGF1dGhlbnRpY2F0aW9uIGRpYWxvZyBpZiBvcGVuZWRcbiAgICAgICAgICAgICAgICBBdXRoZW50aWNhdGlvbi5jbG9zZUF1dGhlbnRpY2F0aW9uRGlhbG9nKCk7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgICAgICAgICBhdXRoZW50aWNhdGlvbldpbmRvdyA9IG51bGw7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGF1dGhlbnRpY2F0aW9uV2luZG93O1xuICAgIH0sXG4gICAgc3RvcEludGVydmFsOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIENsZWFyIHJldHJ5IGludGVydmFsLCBzbyB0aGF0IHdlIGRvbid0IGNhbGwgJ2RvSm9pbkFmdGVyRm9jdXMnIHR3aWNlXG4gICAgICAgIGlmIChhdXRoUmV0cnlJZCkge1xuICAgICAgICAgICAgd2luZG93LmNsZWFyVGltZW91dChhdXRoUmV0cnlJZCk7XG4gICAgICAgICAgICBhdXRoUmV0cnlJZCA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhlbnRpY2F0aW9uOyIsIi8qIGdsb2JhbCAkLCBBUFAsIGNvbmZpZyovXG5cbnZhciBYTVBQID0gcmVxdWlyZSgnLi4vLi4veG1wcC94bXBwJyk7XG52YXIgTW9kZXJhdG9yID0gcmVxdWlyZSgnLi4vLi4veG1wcC9tb2RlcmF0b3InKTtcblxuLy9GSVhNRTogdXNlIExvZ2luRGlhbG9nIHRvIGFkZCByZXRyaWVzIHRvIFhNUFAuY29ubmVjdCBtZXRob2QgdXNlZCB3aGVuXG4vLyBhbm9ueW1vdXMgZG9tYWluIGlzIG5vdCBlbmFibGVkXG5cbi8qKlxuICogQ3JlYXRlcyBuZXcgPHR0PkRpYWxvZzwvdHQ+IGluc3RhbmNlLlxuICogQHBhcmFtIGNhbGxiYWNrIDx0dD5mdW5jdGlvbihTdHJvcGhlLkNvbm5lY3Rpb24sIFN0cm9waGUuU3RhdHVzKTwvdHQ+IGNhbGxlZFxuICogICAgICAgIHdoZW4gd2UgZWl0aGVyIGZhaWwgdG8gY29ubmVjdCBvciBzdWNjZWVkKGNoZWNrIFN0cm9waGUuU3RhdHVzKS5cbiAqIEBwYXJhbSBvYnRhaW5TZXNzaW9uIDx0dD50cnVlPC90dD4gaWYgd2Ugd2FudCB0byBzZW5kIENvbmZlcmVuY2VJUSB0byBKaWNvZm9cbiAqICAgICAgICBpbiBvcmRlciB0byBjcmVhdGUgc2Vzc2lvbi1pZCBhZnRlciB0aGUgY29ubmVjdGlvbiBpcyBlc3RhYmxpc2hlZC5cbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBEaWFsb2coY2FsbGJhY2ssIG9idGFpblNlc3Npb24pIHtcblxuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIHZhciBzdG9wID0gZmFsc2U7XG5cbiAgICB2YXIgY29ubmVjdGlvbiA9IEFQUC54bXBwLmNyZWF0ZUNvbm5lY3Rpb24oKTtcblxuICAgIHZhciBtZXNzYWdlID0gJzxoMiBkYXRhLWkxOG49XCJkaWFsb2cucGFzc3dvcmRSZXF1aXJlZFwiPic7XG4gICAgbWVzc2FnZSArPSBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nKFwiZGlhbG9nLnBhc3N3b3JkUmVxdWlyZWRcIik7XG4gICAgbWVzc2FnZSArPSAnPC9oMj4nICtcbiAgICAgICAgJzxpbnB1dCBuYW1lPVwidXNlcm5hbWVcIiB0eXBlPVwidGV4dFwiICcgK1xuICAgICAgICAncGxhY2Vob2xkZXI9XCJ1c2VyQGRvbWFpbi5uZXRcIiBhdXRvZm9jdXM+JyArXG4gICAgICAgICc8aW5wdXQgbmFtZT1cInBhc3N3b3JkXCIgJyArXG4gICAgICAgICd0eXBlPVwicGFzc3dvcmRcIiBkYXRhLWkxOG49XCJbcGxhY2Vob2xkZXJdZGlhbG9nLnVzZXJQYXNzd29yZFwiJyArXG4gICAgICAgICcgcGxhY2Vob2xkZXI9XCJ1c2VyIHBhc3N3b3JkXCI+JztcblxuICAgIHZhciBva0J1dHRvbiA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFwiZGlhbG9nLk9rXCIpO1xuXG4gICAgdmFyIGNhbmNlbEJ1dHRvbiA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFwiZGlhbG9nLkNhbmNlbFwiKTtcblxuICAgIHZhciBzdGF0ZXMgPSB7XG4gICAgICAgIGxvZ2luOiB7XG4gICAgICAgICAgICBodG1sOiBtZXNzYWdlLFxuICAgICAgICAgICAgYnV0dG9uczogW1xuICAgICAgICAgICAgICAgIHsgdGl0bGU6IG9rQnV0dG9uLCB2YWx1ZTogdHJ1ZX0sXG4gICAgICAgICAgICAgICAgeyB0aXRsZTogY2FuY2VsQnV0dG9uLCB2YWx1ZTogZmFsc2V9XG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgZm9jdXM6ICc6aW5wdXQ6Zmlyc3QnLFxuICAgICAgICAgICAgc3VibWl0OiBmdW5jdGlvbiAoZSwgdiwgbSwgZikge1xuICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICBpZiAodikge1xuICAgICAgICAgICAgICAgICAgICB2YXIgamlkID0gZi51c2VybmFtZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhc3N3b3JkID0gZi5wYXNzd29yZDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGppZCAmJiBwYXNzd29yZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbi5yZXNldCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29ubkRpYWxvZy5nb1RvU3RhdGUoJ2Nvbm5lY3RpbmcnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uY29ubmVjdChqaWQsIHBhc3N3b3JkLCBzdGF0ZUhhbmRsZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVXNlciBjYW5jZWxsZWRcbiAgICAgICAgICAgICAgICAgICAgc3RvcCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBjb25uZWN0aW5nOiB7XG4gICAgICAgICAgICB0aXRsZTogQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZygnZGlhbG9nLmNvbm5lY3RpbmcnKSxcbiAgICAgICAgICAgIGh0bWw6ICAgJzxkaXYgaWQ9XCJjb25uZWN0aW9uU3RhdHVzXCI+PC9kaXY+JyxcbiAgICAgICAgICAgIGJ1dHRvbnM6IFtdLFxuICAgICAgICAgICAgZGVmYXVsdEJ1dHRvbjogMFxuICAgICAgICB9LFxuICAgICAgICBmaW5pc2hlZDoge1xuICAgICAgICAgICAgdGl0bGU6IEFQUC50cmFuc2xhdGlvbi50cmFuc2xhdGVTdHJpbmcoJ2RpYWxvZy5lcnJvcicpLFxuICAgICAgICAgICAgaHRtbDogICAnPGRpdiBpZD1cImVycm9yTWVzc2FnZVwiPjwvZGl2PicsXG4gICAgICAgICAgICBidXR0b25zOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aXRsZTogQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZygnZGlhbG9nLnJldHJ5JyksXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiAncmV0cnknXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHRpdGxlOiBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nKCdkaWFsb2cuQ2FuY2VsJyksXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiAnY2FuY2VsJ1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgZGVmYXVsdEJ1dHRvbjogMCxcbiAgICAgICAgICAgIHN1Ym1pdDogZnVuY3Rpb24gKGUsIHYsIG0sIGYpIHtcbiAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgaWYgKHYgPT09ICdyZXRyeScpXG4gICAgICAgICAgICAgICAgICAgIGNvbm5EaWFsb2cuZ29Ub1N0YXRlKCdsb2dpbicpO1xuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgY29ubkRpYWxvZ1xuICAgICAgICA9IEFQUC5VSS5tZXNzYWdlSGFuZGxlci5vcGVuRGlhbG9nV2l0aFN0YXRlcyhzdGF0ZXMsXG4gICAgICAgICAgICAgICAgeyBwZXJzaXN0ZW50OiB0cnVlLCBjbG9zZVRleHQ6ICcnIH0sIG51bGwpO1xuXG4gICAgdmFyIHN0YXRlSGFuZGxlciA9IGZ1bmN0aW9uIChzdGF0dXMsIG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKHN0b3ApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB0cmFuc2xhdGVLZXkgPSBcImNvbm5lY3Rpb24uXCIgKyBYTVBQLmdldFN0YXR1c1N0cmluZyhzdGF0dXMpO1xuICAgICAgICB2YXIgc3RhdHVzU3RyID0gQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyh0cmFuc2xhdGVLZXkpO1xuXG4gICAgICAgIC8vIERpc3BsYXkgY3VycmVudCBzdGF0ZVxuICAgICAgICB2YXIgY29ubmVjdGlvblN0YXR1cyA9XG4gICAgICAgICAgICBjb25uRGlhbG9nLmdldFN0YXRlKCdjb25uZWN0aW5nJykuZmluZCgnI2Nvbm5lY3Rpb25TdGF0dXMnKTtcblxuICAgICAgICBjb25uZWN0aW9uU3RhdHVzLnRleHQoc3RhdHVzU3RyKTtcblxuICAgICAgICBzd2l0Y2ggKHN0YXR1cykge1xuICAgICAgICAgICAgY2FzZSBYTVBQLlN0YXR1cy5DT05ORUNURUQ6XG5cbiAgICAgICAgICAgICAgICBzdG9wID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBpZiAoIW9idGFpblNlc3Npb24pIHtcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2soY29ubmVjdGlvbiwgc3RhdHVzKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBPYnRhaW5pbmcgc2Vzc2lvbi1pZCBzdGF0dXNcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uU3RhdHVzLnRleHQoXG4gICAgICAgICAgICAgICAgICAgIEFQUC50cmFuc2xhdGlvbi50cmFuc2xhdGVTdHJpbmcoXG4gICAgICAgICAgICAgICAgICAgICAgICAnY29ubmVjdGlvbi5GRVRDSF9TRVNTSU9OX0lEJykpO1xuXG4gICAgICAgICAgICAgICAgLy8gQXV0aGVudGljYXRlIHdpdGggSmljb2ZvIGFuZCBvYnRhaW4gc2Vzc2lvbi1pZFxuICAgICAgICAgICAgICAgIHZhciByb29tTmFtZSA9IEFQUC5VSS5nZW5lcmF0ZVJvb21OYW1lKCk7XG5cbiAgICAgICAgICAgICAgICAvLyBKaWNvZm8gd2lsbCByZXR1cm4gbmV3IHNlc3Npb24taWQgd2hlbiBjb25uZWN0ZWRcbiAgICAgICAgICAgICAgICAvLyBmcm9tIGF1dGhlbnRpY2F0ZWQgZG9tYWluXG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5zZW5kSVEoXG4gICAgICAgICAgICAgICAgICAgIE1vZGVyYXRvci5jcmVhdGVDb25mZXJlbmNlSXEocm9vbU5hbWUpLFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVzdWx0KSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25TdGF0dXMudGV4dChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnY29ubmVjdGlvbi5HT1RfU0VTU0lPTl9JRCcpKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBhcnNlIHNlc3Npb24taWRcbiAgICAgICAgICAgICAgICAgICAgICAgIE1vZGVyYXRvci5wYXJzZVNlc3Npb25JZChyZXN1bHQpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayhjb25uZWN0aW9uLCBzdGF0dXMpO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJBdXRoIG9uIHRoZSBmbHkgZmFpbGVkXCIsIGVycm9yKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBlcnJvck1zZyA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2Nvbm5lY3Rpb24uR0VUX1NFU1NJT05fSURfRVJST1InKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoZXJyb3IpLmZpbmQoJz5lcnJvcicpLmF0dHIoJ2NvZGUnKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5kaXNwbGF5RXJyb3IoZXJyb3JNc2cpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmRpc2Nvbm5lY3QoKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgWE1QUC5TdGF0dXMuQVVUSEZBSUw6XG4gICAgICAgICAgICBjYXNlIFhNUFAuU3RhdHVzLkNPTk5GQUlMOlxuICAgICAgICAgICAgY2FzZSBYTVBQLlN0YXR1cy5ESVNDT05ORUNURUQ6XG5cbiAgICAgICAgICAgICAgICBzdG9wID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGNvbm5lY3Rpb24sIHN0YXR1cyk7XG5cbiAgICAgICAgICAgICAgICB2YXIgZXJyb3JNZXNzYWdlID0gc3RhdHVzU3RyO1xuXG4gICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2UgKz0gJzogJyArIG1lc3NhZ2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHNlbGYuZGlzcGxheUVycm9yKGVycm9yTWVzc2FnZSk7XG5cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRGlzcGxheXMgZXJyb3IgbWVzc2FnZSBpbiAnZmluaXNoZWQnIHN0YXRlIHdoaWNoIGFsbG93cyBlaXRoZXIgdG8gY2FuY2VsXG4gICAgICogb3IgcmV0cnkuXG4gICAgICogQHBhcmFtIG1lc3NhZ2UgdGhlIGZpbmFsIG1lc3NhZ2UgdG8gYmUgZGlzcGxheWVkLlxuICAgICAqL1xuICAgIHRoaXMuZGlzcGxheUVycm9yID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcblxuICAgICAgICB2YXIgZmluaXNoZWRTdGF0ZSA9IGNvbm5EaWFsb2cuZ2V0U3RhdGUoJ2ZpbmlzaGVkJyk7XG5cbiAgICAgICAgdmFyIGVycm9yTWVzc2FnZUVsZW0gPSBmaW5pc2hlZFN0YXRlLmZpbmQoJyNlcnJvck1lc3NhZ2UnKTtcbiAgICAgICAgZXJyb3JNZXNzYWdlRWxlbS50ZXh0KG1lc3NhZ2UpO1xuXG4gICAgICAgIGNvbm5EaWFsb2cuZ29Ub1N0YXRlKCdmaW5pc2hlZCcpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDbG9zZXMgTG9naW5EaWFsb2cuXG4gICAgICovXG4gICAgdGhpcy5jbG9zZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc3RvcCA9IHRydWU7XG4gICAgICAgIGNvbm5EaWFsb2cuY2xvc2UoKTtcbiAgICB9O1xufVxuXG52YXIgTG9naW5EaWFsb2cgPSB7XG5cbiAgICAvKipcbiAgICAgKiBEaXNwbGF5cyBsb2dpbiBwcm9tcHQgdXNlZCB0byBlc3RhYmxpc2ggbmV3IFhNUFAgY29ubmVjdGlvbi4gR2l2ZW5cbiAgICAgKiA8dHQ+Y2FsbGJhY2soU3Ryb3BoZS5Db25uZWN0aW9uLCBTdHJvcGhlLlN0YXR1cyk8L3R0PiBmdW5jdGlvbiB3aWxsIGJlXG4gICAgICogY2FsbGVkIHdoZW4gd2UgY29ubmVjdCBzdWNjZXNzZnVsbHkoc3RhdHVzID09PSBDT05ORUNURUQpIG9yIHdoZW4gd2UgZmFpbFxuICAgICAqIHRvIGRvIHNvLiBPbiBjb25uZWN0aW9uIGZhaWx1cmUgcHJvZ3JhbSBjYW4gY2FsbCBEaWFsb2cuY2xvc2UoKSBtZXRob2QgaW5cbiAgICAgKiBvcmRlciB0byBjYW5jZWwgb3IgZG8gbm90aGluZyB0byBsZXQgdGhlIHVzZXIgcmV0cnkuXG4gICAgICogQHBhcmFtIGNhbGxiYWNrIDx0dD5mdW5jdGlvbihTdHJvcGhlLkNvbm5lY3Rpb24sIFN0cm9waGUuU3RhdHVzKTwvdHQ+XG4gICAgICogICAgICAgIGNhbGxlZCB3aGVuIHdlIGVpdGhlciBmYWlsIHRvIGNvbm5lY3Qgb3Igc3VjY2VlZChjaGVja1xuICAgICAqICAgICAgICBTdHJvcGhlLlN0YXR1cykuXG4gICAgICogQHBhcmFtIG9idGFpblNlc3Npb24gPHR0PnRydWU8L3R0PiBpZiB3ZSB3YW50IHRvIHNlbmQgQ29uZmVyZW5jZUlRIHRvXG4gICAgICogICAgICAgIEppY29mbyBpbiBvcmRlciB0byBjcmVhdGUgc2Vzc2lvbi1pZCBhZnRlciB0aGUgY29ubmVjdGlvbiBpc1xuICAgICAqICAgICAgICBlc3RhYmxpc2hlZC5cbiAgICAgKiBAcmV0dXJucyB7RGlhbG9nfVxuICAgICAqL1xuICAgIHNob3c6IGZ1bmN0aW9uIChjYWxsYmFjaywgb2J0YWluU2Vzc2lvbikge1xuICAgICAgICByZXR1cm4gbmV3IERpYWxvZyhjYWxsYmFjaywgb2J0YWluU2Vzc2lvbik7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBMb2dpbkRpYWxvZzsiLCJ2YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi4vLi4vc2V0dGluZ3MvU2V0dGluZ3NcIik7XG52YXIgTWVkaWFTdHJlYW1UeXBlID0gcmVxdWlyZShcIi4uLy4uLy4uL3NlcnZpY2UvUlRDL01lZGlhU3RyZWFtVHlwZXNcIik7XG5cbnZhciB1c2VycyA9IHt9O1xudmFyIGFjdGl2ZVNwZWFrZXJKaWQ7XG5cbmZ1bmN0aW9uIHNldFZpc2liaWxpdHkoc2VsZWN0b3IsIHNob3cpIHtcbiAgICBpZiAoc2VsZWN0b3IgJiYgc2VsZWN0b3IubGVuZ3RoID4gMCkge1xuICAgICAgICBzZWxlY3Rvci5jc3MoXCJ2aXNpYmlsaXR5XCIsIHNob3cgPyBcInZpc2libGVcIiA6IFwiaGlkZGVuXCIpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gaXNVc2VyTXV0ZWQoamlkKSB7XG4gICAgLy8gWFhYKGdwKSB3ZSBtYXkgd2FudCB0byByZW5hbWUgdGhpcyBtZXRob2QgdG8gc29tZXRoaW5nIGxpa2VcbiAgICAvLyBpc1VzZXJTdHJlYW1pbmcsIGZvciBleGFtcGxlLlxuICAgIGlmIChqaWQgJiYgamlkICE9IEFQUC54bXBwLm15SmlkKCkpIHtcbiAgICAgICAgdmFyIHJlc291cmNlID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgaWYgKCFyZXF1aXJlKFwiLi4vdmlkZW9sYXlvdXQvVmlkZW9MYXlvdXRcIikuaXNJbkxhc3ROKHJlc291cmNlKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIUFQUC5SVEMucmVtb3RlU3RyZWFtc1tqaWRdIHx8ICFBUFAuUlRDLnJlbW90ZVN0cmVhbXNbamlkXVtNZWRpYVN0cmVhbVR5cGUuVklERU9fVFlQRV0pIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHJldHVybiBBUFAuUlRDLnJlbW90ZVN0cmVhbXNbamlkXVtNZWRpYVN0cmVhbVR5cGUuVklERU9fVFlQRV0ubXV0ZWQ7XG59XG5cbmZ1bmN0aW9uIGdldEdyYXZhdGFyVXJsKGlkLCBzaXplKSB7XG4gICAgaWYoaWQgPT09IEFQUC54bXBwLm15SmlkKCkgfHwgIWlkKSB7XG4gICAgICAgIGlkID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKS51aWQ7XG4gICAgfVxuICAgIHJldHVybiAnaHR0cHM6Ly93d3cuZ3JhdmF0YXIuY29tL2F2YXRhci8nICtcbiAgICAgICAgTUQ1LmhleGRpZ2VzdChpZC50cmltKCkudG9Mb3dlckNhc2UoKSkgK1xuICAgICAgICBcIj9kPXdhdmF0YXImc2l6ZT1cIiArIChzaXplIHx8IFwiMzBcIik7XG59XG5cbnZhciBBdmF0YXIgPSB7XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSB1c2VyJ3MgYXZhdGFyIGluIHRoZSBzZXR0aW5ncyBtZW51KGlmIGxvY2FsIHVzZXIpLCBjb250YWN0IGxpc3RcbiAgICAgKiBhbmQgdGh1bWJuYWlsXG4gICAgICogQHBhcmFtIGppZCBqaWQgb2YgdGhlIHVzZXJcbiAgICAgKiBAcGFyYW0gaWQgZW1haWwgb3IgdXNlcklEIHRvIGJlIHVzZWQgYXMgYSBoYXNoXG4gICAgICovXG4gICAgc2V0VXNlckF2YXRhcjogZnVuY3Rpb24gKGppZCwgaWQpIHtcbiAgICAgICAgaWYgKGlkKSB7XG4gICAgICAgICAgICBpZiAodXNlcnNbamlkXSA9PT0gaWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB1c2Vyc1tqaWRdID0gaWQ7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHRodW1iVXJsID0gZ2V0R3JhdmF0YXJVcmwodXNlcnNbamlkXSB8fCBqaWQsIDEwMCk7XG4gICAgICAgIHZhciBjb250YWN0TGlzdFVybCA9IGdldEdyYXZhdGFyVXJsKHVzZXJzW2ppZF0gfHwgamlkKTtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgdmFyIHRodW1ibmFpbCA9ICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQpO1xuICAgICAgICB2YXIgYXZhdGFyID0gJCgnI2F2YXRhcl8nICsgcmVzb3VyY2VKaWQpO1xuXG4gICAgICAgIC8vIHNldCB0aGUgYXZhdGFyIGluIHRoZSBzZXR0aW5ncyBtZW51IGlmIGl0IGlzIGxvY2FsIHVzZXIgYW5kIGdldCB0aGVcbiAgICAgICAgLy8gbG9jYWwgdmlkZW8gY29udGFpbmVyXG4gICAgICAgIGlmIChqaWQgPT09IEFQUC54bXBwLm15SmlkKCkpIHtcbiAgICAgICAgICAgICQoJyNhdmF0YXInKS5nZXQoMCkuc3JjID0gdGh1bWJVcmw7XG4gICAgICAgICAgICB0aHVtYm5haWwgPSAkKCcjbG9jYWxWaWRlb0NvbnRhaW5lcicpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc2V0IHRoZSBhdmF0YXIgaW4gdGhlIGNvbnRhY3QgbGlzdFxuICAgICAgICB2YXIgY29udGFjdCA9ICQoJyMnICsgcmVzb3VyY2VKaWQgKyAnPmltZycpO1xuICAgICAgICBpZiAoY29udGFjdCAmJiBjb250YWN0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnRhY3QuZ2V0KDApLnNyYyA9IGNvbnRhY3RMaXN0VXJsO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc2V0IHRoZSBhdmF0YXIgaW4gdGhlIHRodW1ibmFpbFxuICAgICAgICBpZiAoYXZhdGFyICYmIGF2YXRhci5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBhdmF0YXJbMF0uc3JjID0gdGh1bWJVcmw7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodGh1bWJuYWlsICYmIHRodW1ibmFpbC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgYXZhdGFyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW1nJyk7XG4gICAgICAgICAgICAgICAgYXZhdGFyLmlkID0gJ2F2YXRhcl8nICsgcmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICAgICAgYXZhdGFyLmNsYXNzTmFtZSA9ICd1c2VyQXZhdGFyJztcbiAgICAgICAgICAgICAgICBhdmF0YXIuc3JjID0gdGh1bWJVcmw7XG4gICAgICAgICAgICAgICAgdGh1bWJuYWlsLmFwcGVuZChhdmF0YXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy9pZiB0aGUgdXNlciBpcyB0aGUgY3VycmVudCBhY3RpdmUgc3BlYWtlciAtIHVwZGF0ZSB0aGUgYWN0aXZlIHNwZWFrZXJcbiAgICAgICAgLy8gYXZhdGFyXG4gICAgICAgIGlmIChqaWQgPT09IGFjdGl2ZVNwZWFrZXJKaWQpIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlQWN0aXZlU3BlYWtlckF2YXRhclNyYyhqaWQpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEhpZGVzIG9yIHNob3dzIHRoZSB1c2VyJ3MgYXZhdGFyXG4gICAgICogQHBhcmFtIGppZCBqaWQgb2YgdGhlIHVzZXJcbiAgICAgKiBAcGFyYW0gc2hvdyB3aGV0aGVyIHdlIHNob3VsZCBzaG93IHRoZSBhdmF0YXIgb3Igbm90XG4gICAgICogdmlkZW8gYmVjYXVzZSB0aGVyZSBpcyBubyBkb21pbmFudCBzcGVha2VyIGFuZCBubyBmb2N1c2VkIHNwZWFrZXJcbiAgICAgKi9cbiAgICBzaG93VXNlckF2YXRhcjogZnVuY3Rpb24gKGppZCwgc2hvdykge1xuICAgICAgICBpZiAodXNlcnNbamlkXSkge1xuICAgICAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgICAgIHZhciB2aWRlbyA9ICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQgKyAnPnZpZGVvJyk7XG4gICAgICAgICAgICB2YXIgYXZhdGFyID0gJCgnI2F2YXRhcl8nICsgcmVzb3VyY2VKaWQpO1xuXG4gICAgICAgICAgICBpZiAoamlkID09PSBBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgICAgICAgICAgdmlkZW8gPSAkKCcjbG9jYWxWaWRlb1dyYXBwZXI+dmlkZW8nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzaG93ID09PSB1bmRlZmluZWQgfHwgc2hvdyA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHNob3cgPSBpc1VzZXJNdXRlZChqaWQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvL2lmIHRoZSB1c2VyIGlzIHRoZSBjdXJyZW50bHkgZm9jdXNlZCwgdGhlIGRvbWluYW50IHNwZWFrZXIgb3IgaWZcbiAgICAgICAgICAgIC8vdGhlcmUgaXMgbm8gZm9jdXNlZCBhbmQgbm8gZG9taW5hbnQgc3BlYWtlciBhbmQgdGhlIGxhcmdlIHZpZGVvIGlzXG4gICAgICAgICAgICAvL2N1cnJlbnRseSBzaG93blxuICAgICAgICAgICAgaWYgKGFjdGl2ZVNwZWFrZXJKaWQgPT09IGppZCAmJiByZXF1aXJlKFwiLi4vdmlkZW9sYXlvdXQvVmlkZW9MYXlvdXRcIikuaXNMYXJnZVZpZGVvT25Ub3AoKSkge1xuICAgICAgICAgICAgICAgIHNldFZpc2liaWxpdHkoJChcIiNsYXJnZVZpZGVvXCIpLCAhc2hvdyk7XG4gICAgICAgICAgICAgICAgc2V0VmlzaWJpbGl0eSgkKCcjYWN0aXZlU3BlYWtlcicpLCBzaG93KTtcbiAgICAgICAgICAgICAgICBzZXRWaXNpYmlsaXR5KGF2YXRhciwgZmFsc2UpO1xuICAgICAgICAgICAgICAgIHNldFZpc2liaWxpdHkodmlkZW8sIGZhbHNlKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYgKHZpZGVvICYmIHZpZGVvLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgc2V0VmlzaWJpbGl0eSh2aWRlbywgIXNob3cpO1xuICAgICAgICAgICAgICAgICAgICBzZXRWaXNpYmlsaXR5KGF2YXRhciwgc2hvdyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIHNyYyBvZiB0aGUgYWN0aXZlIHNwZWFrZXIgYXZhdGFyXG4gICAgICogQHBhcmFtIGppZCBvZiB0aGUgY3VycmVudCBhY3RpdmUgc3BlYWtlclxuICAgICAqL1xuICAgIHVwZGF0ZUFjdGl2ZVNwZWFrZXJBdmF0YXJTcmM6IGZ1bmN0aW9uIChqaWQpIHtcbiAgICAgICAgaWYgKCFqaWQpIHtcbiAgICAgICAgICAgIGppZCA9IEFQUC54bXBwLmZpbmRKaWRGcm9tUmVzb3VyY2UoXG4gICAgICAgICAgICAgICAgcmVxdWlyZShcIi4uL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0XCIpLmdldExhcmdlVmlkZW9TdGF0ZSgpLnVzZXJSZXNvdXJjZUppZCk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGF2YXRhciA9ICQoXCIjYWN0aXZlU3BlYWtlckF2YXRhclwiKVswXTtcbiAgICAgICAgdmFyIHVybCA9IGdldEdyYXZhdGFyVXJsKHVzZXJzW2ppZF0sXG4gICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuQUNUSVZFX1NQRUFLRVJfQVZBVEFSX1NJWkUpO1xuICAgICAgICBpZiAoamlkID09PSBhY3RpdmVTcGVha2VySmlkICYmIGF2YXRhci5zcmMgPT09IHVybCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGFjdGl2ZVNwZWFrZXJKaWQgPSBqaWQ7XG4gICAgICAgIHZhciBpc011dGVkID0gaXNVc2VyTXV0ZWQoamlkKTtcbiAgICAgICAgaWYgKGppZCAmJiBpc011dGVkICE9PSBudWxsKSB7XG4gICAgICAgICAgICBhdmF0YXIuc3JjID0gdXJsO1xuICAgICAgICAgICAgc2V0VmlzaWJpbGl0eSgkKFwiI2xhcmdlVmlkZW9cIiksICFpc011dGVkKTtcbiAgICAgICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihqaWQsIGlzTXV0ZWQpO1xuICAgICAgICB9XG4gICAgfVxuXG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gQXZhdGFyOyIsIi8qIGdsb2JhbCAkLCBjb25maWcsXG4gICBzZXRMYXJnZVZpZGVvVmlzaWJsZSwgVXRpbCAqL1xuXG52YXIgVmlkZW9MYXlvdXQgPSByZXF1aXJlKFwiLi4vdmlkZW9sYXlvdXQvVmlkZW9MYXlvdXRcIik7XG52YXIgUHJlemkgPSByZXF1aXJlKFwiLi4vcHJlemkvUHJlemlcIik7XG52YXIgVUlVdGlsID0gcmVxdWlyZShcIi4uL3V0aWwvVUlVdGlsXCIpO1xuXG52YXIgZXRoZXJwYWROYW1lID0gbnVsbDtcbnZhciBldGhlcnBhZElGcmFtZSA9IG51bGw7XG52YXIgZG9tYWluID0gbnVsbDtcbnZhciBvcHRpb25zID0gXCI/c2hvd0NvbnRyb2xzPXRydWUmc2hvd0NoYXQ9ZmFsc2Umc2hvd0xpbmVOdW1iZXJzPXRydWUmdXNlTW9ub3NwYWNlRm9udD1mYWxzZVwiO1xuXG5cbi8qKlxuICogUmVzaXplcyB0aGUgZXRoZXJwYWQuXG4gKi9cbmZ1bmN0aW9uIHJlc2l6ZSgpIHtcbiAgICBpZiAoJCgnI2V0aGVycGFkPmlmcmFtZScpLmxlbmd0aCkge1xuICAgICAgICB2YXIgcmVtb3RlVmlkZW9zID0gJCgnI3JlbW90ZVZpZGVvcycpO1xuICAgICAgICB2YXIgYXZhaWxhYmxlSGVpZ2h0XG4gICAgICAgICAgICA9IHdpbmRvdy5pbm5lckhlaWdodCAtIHJlbW90ZVZpZGVvcy5vdXRlckhlaWdodCgpO1xuICAgICAgICB2YXIgYXZhaWxhYmxlV2lkdGggPSBVSVV0aWwuZ2V0QXZhaWxhYmxlVmlkZW9XaWR0aCgpO1xuXG4gICAgICAgICQoJyNldGhlcnBhZD5pZnJhbWUnKS53aWR0aChhdmFpbGFibGVXaWR0aCk7XG4gICAgICAgICQoJyNldGhlcnBhZD5pZnJhbWUnKS5oZWlnaHQoYXZhaWxhYmxlSGVpZ2h0KTtcbiAgICB9XG59XG5cbi8qKlxuICogU2hhcmVzIHRoZSBFdGhlcnBhZCBuYW1lIHdpdGggb3RoZXIgcGFydGljaXBhbnRzLlxuICovXG5mdW5jdGlvbiBzaGFyZUV0aGVycGFkKCkge1xuICAgIEFQUC54bXBwLmFkZFRvUHJlc2VuY2UoXCJldGhlcnBhZFwiLCBldGhlcnBhZE5hbWUpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIEV0aGVycGFkIGJ1dHRvbiBhbmQgYWRkcyBpdCB0byB0aGUgdG9vbGJhci5cbiAqL1xuZnVuY3Rpb24gZW5hYmxlRXRoZXJwYWRCdXR0b24oKSB7XG4gICAgaWYgKCEkKCcjZXRoZXJwYWRCdXR0b24nKS5pcyhcIjp2aXNpYmxlXCIpKVxuICAgICAgICAkKCcjZXRoZXJwYWRCdXR0b24nKS5jc3Moe2Rpc3BsYXk6ICdpbmxpbmUtYmxvY2snfSk7XG59XG5cbi8qKlxuICogQ3JlYXRlcyB0aGUgSUZyYW1lIGZvciB0aGUgZXRoZXJwYWQuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUlGcmFtZSgpIHtcbiAgICBldGhlcnBhZElGcmFtZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lmcmFtZScpO1xuICAgIGV0aGVycGFkSUZyYW1lLnNyYyA9IGRvbWFpbiArIGV0aGVycGFkTmFtZSArIG9wdGlvbnM7XG4gICAgZXRoZXJwYWRJRnJhbWUuZnJhbWVCb3JkZXIgPSAwO1xuICAgIGV0aGVycGFkSUZyYW1lLnNjcm9sbGluZyA9IFwibm9cIjtcbiAgICBldGhlcnBhZElGcmFtZS53aWR0aCA9ICQoJyNsYXJnZVZpZGVvQ29udGFpbmVyJykud2lkdGgoKSB8fCA2NDA7XG4gICAgZXRoZXJwYWRJRnJhbWUuaGVpZ2h0ID0gJCgnI2xhcmdlVmlkZW9Db250YWluZXInKS5oZWlnaHQoKSB8fCA0ODA7XG4gICAgZXRoZXJwYWRJRnJhbWUuc2V0QXR0cmlidXRlKCdzdHlsZScsICd2aXNpYmlsaXR5OiBoaWRkZW47Jyk7XG5cbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZXRoZXJwYWQnKS5hcHBlbmRDaGlsZChldGhlcnBhZElGcmFtZSk7XG5cbiAgICBldGhlcnBhZElGcmFtZS5vbmxvYWQgPSBmdW5jdGlvbigpIHtcblxuICAgICAgICBkb2N1bWVudC5kb21haW4gPSBkb2N1bWVudC5kb21haW47XG4gICAgICAgIGJ1YmJsZUlmcmFtZU1vdXNlTW92ZShldGhlcnBhZElGcmFtZSk7XG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAvLyB0aGUgaWZyYW1lcyBpbnNpZGUgb2YgdGhlIGV0aGVycGFkIGFyZVxuICAgICAgICAgICAgLy8gbm90IHlldCBsb2FkZWQgd2hlbiB0aGUgZXRoZXJwYWQgaWZyYW1lIGlzIGxvYWRlZFxuICAgICAgICAgICAgdmFyIG91dGVyID0gZXRoZXJwYWRJRnJhbWUuXG4gICAgICAgICAgICAgICAgY29udGVudERvY3VtZW50LmdldEVsZW1lbnRzQnlOYW1lKFwiYWNlX291dGVyXCIpWzBdO1xuICAgICAgICAgICAgYnViYmxlSWZyYW1lTW91c2VNb3ZlKG91dGVyKTtcbiAgICAgICAgICAgIHZhciBpbm5lciA9IG91dGVyLlxuICAgICAgICAgICAgICAgIGNvbnRlbnREb2N1bWVudC5nZXRFbGVtZW50c0J5TmFtZShcImFjZV9pbm5lclwiKVswXTtcbiAgICAgICAgICAgIGJ1YmJsZUlmcmFtZU1vdXNlTW92ZShpbm5lcik7XG4gICAgICAgIH0sIDIwMDApO1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIGJ1YmJsZUlmcmFtZU1vdXNlTW92ZShpZnJhbWUpe1xuICAgIHZhciBleGlzdGluZ09uTW91c2VNb3ZlID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cub25tb3VzZW1vdmU7XG4gICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cub25tb3VzZW1vdmUgPSBmdW5jdGlvbihlKXtcbiAgICAgICAgaWYoZXhpc3RpbmdPbk1vdXNlTW92ZSkgZXhpc3RpbmdPbk1vdXNlTW92ZShlKTtcbiAgICAgICAgdmFyIGV2dCA9IGRvY3VtZW50LmNyZWF0ZUV2ZW50KFwiTW91c2VFdmVudHNcIik7XG4gICAgICAgIHZhciBib3VuZGluZ0NsaWVudFJlY3QgPSBpZnJhbWUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIGV2dC5pbml0TW91c2VFdmVudChcbiAgICAgICAgICAgIFwibW91c2Vtb3ZlXCIsXG4gICAgICAgICAgICB0cnVlLCAvLyBidWJibGVzXG4gICAgICAgICAgICBmYWxzZSwgLy8gbm90IGNhbmNlbGFibGVcbiAgICAgICAgICAgIHdpbmRvdyxcbiAgICAgICAgICAgIGUuZGV0YWlsLFxuICAgICAgICAgICAgZS5zY3JlZW5YLFxuICAgICAgICAgICAgZS5zY3JlZW5ZLFxuICAgICAgICAgICAgICAgIGUuY2xpZW50WCArIGJvdW5kaW5nQ2xpZW50UmVjdC5sZWZ0LFxuICAgICAgICAgICAgICAgIGUuY2xpZW50WSArIGJvdW5kaW5nQ2xpZW50UmVjdC50b3AsXG4gICAgICAgICAgICBlLmN0cmxLZXksXG4gICAgICAgICAgICBlLmFsdEtleSxcbiAgICAgICAgICAgIGUuc2hpZnRLZXksXG4gICAgICAgICAgICBlLm1ldGFLZXksXG4gICAgICAgICAgICBlLmJ1dHRvbixcbiAgICAgICAgICAgIG51bGwgLy8gbm8gcmVsYXRlZCBlbGVtZW50XG4gICAgICAgICk7XG4gICAgICAgIGlmcmFtZS5kaXNwYXRjaEV2ZW50KGV2dCk7XG4gICAgfTtcbn1cblxuXG4vKipcbiAqIE9uIHZpZGVvIHNlbGVjdGVkIGV2ZW50LlxuICovXG4kKGRvY3VtZW50KS5iaW5kKCd2aWRlby5zZWxlY3RlZCcsIGZ1bmN0aW9uIChldmVudCwgaXNQcmVzZW50YXRpb24pIHtcbiAgICBpZiAoY29uZmlnLmV0aGVycGFkX2Jhc2UgJiYgZXRoZXJwYWRJRnJhbWUgJiYgZXRoZXJwYWRJRnJhbWUuc3R5bGUudmlzaWJpbGl0eSAhPT0gJ2hpZGRlbicpXG4gICAgICAgIEV0aGVycGFkLnRvZ2dsZUV0aGVycGFkKGlzUHJlc2VudGF0aW9uKTtcbn0pO1xuXG5cbnZhciBFdGhlcnBhZCA9IHtcbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplcyB0aGUgZXRoZXJwYWQuXG4gICAgICovXG4gICAgaW5pdDogZnVuY3Rpb24gKG5hbWUpIHtcblxuICAgICAgICBpZiAoY29uZmlnLmV0aGVycGFkX2Jhc2UgJiYgIWV0aGVycGFkTmFtZSkge1xuXG4gICAgICAgICAgICBkb21haW4gPSBjb25maWcuZXRoZXJwYWRfYmFzZTtcblxuICAgICAgICAgICAgaWYgKCFuYW1lKSB7XG4gICAgICAgICAgICAgICAgLy8gSW4gY2FzZSB3ZSdyZSB0aGUgZm9jdXMgd2UgZ2VuZXJhdGUgdGhlIG5hbWUuXG4gICAgICAgICAgICAgICAgZXRoZXJwYWROYW1lID0gTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyaW5nKDcpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ18nICsgKG5ldyBEYXRlKCkuZ2V0VGltZSgpKS50b1N0cmluZygpO1xuICAgICAgICAgICAgICAgIHNoYXJlRXRoZXJwYWQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBldGhlcnBhZE5hbWUgPSBuYW1lO1xuXG4gICAgICAgICAgICBlbmFibGVFdGhlcnBhZEJ1dHRvbigpO1xuXG4gICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAqIFJlc2l6ZXMgdGhlIGV0aGVycGFkLCB3aGVuIHRoZSB3aW5kb3cgaXMgcmVzaXplZC5cbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgJCh3aW5kb3cpLnJlc2l6ZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmVzaXplKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBPcGVucy9oaWRlcyB0aGUgRXRoZXJwYWQuXG4gICAgICovXG4gICAgdG9nZ2xlRXRoZXJwYWQ6IGZ1bmN0aW9uIChpc1ByZXNlbnRhdGlvbikge1xuICAgICAgICBpZiAoIWV0aGVycGFkSUZyYW1lKVxuICAgICAgICAgICAgY3JlYXRlSUZyYW1lKCk7XG5cbiAgICAgICAgdmFyIGxhcmdlVmlkZW8gPSBudWxsO1xuICAgICAgICBpZiAoUHJlemkuaXNQcmVzZW50YXRpb25WaXNpYmxlKCkpXG4gICAgICAgICAgICBsYXJnZVZpZGVvID0gJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgbGFyZ2VWaWRlbyA9ICQoJyNsYXJnZVZpZGVvJyk7XG5cbiAgICAgICAgaWYgKCQoJyNldGhlcnBhZD5pZnJhbWUnKS5jc3MoJ3Zpc2liaWxpdHknKSA9PT0gJ2hpZGRlbicpIHtcbiAgICAgICAgICAgICQoJyNhY3RpdmVTcGVha2VyJykuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuICAgICAgICAgICAgbGFyZ2VWaWRlby5mYWRlT3V0KDMwMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGlmIChQcmV6aS5pc1ByZXNlbnRhdGlvblZpc2libGUoKSkge1xuICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvLmNzcyh7b3BhY2l0eTogJzAnfSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2V0TGFyZ2VWaWRlb1Zpc2libGUoZmFsc2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAkKCcjZXRoZXJwYWQ+aWZyYW1lJykuZmFkZUluKDMwMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuYmFja2dyb3VuZCA9ICcjZWVlZWVlJztcbiAgICAgICAgICAgICAgICAkKCcjZXRoZXJwYWQ+aWZyYW1lJykuY3NzKHt2aXNpYmlsaXR5OiAndmlzaWJsZSd9KTtcbiAgICAgICAgICAgICAgICAkKCcjZXRoZXJwYWQnKS5jc3Moe3pJbmRleDogMn0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoJCgnI2V0aGVycGFkPmlmcmFtZScpKSB7XG4gICAgICAgICAgICAkKCcjZXRoZXJwYWQ+aWZyYW1lJykuZmFkZU91dCgzMDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAkKCcjZXRoZXJwYWQ+aWZyYW1lJykuY3NzKHt2aXNpYmlsaXR5OiAnaGlkZGVuJ30pO1xuICAgICAgICAgICAgICAgICQoJyNldGhlcnBhZCcpLmNzcyh7ekluZGV4OiAwfSk7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kID0gJ2JsYWNrJztcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBpZiAoIWlzUHJlc2VudGF0aW9uKSB7XG4gICAgICAgICAgICAgICAgJCgnI2xhcmdlVmlkZW8nKS5mYWRlSW4oMzAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNldExhcmdlVmlkZW9WaXNpYmxlKHRydWUpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJlc2l6ZSgpO1xuICAgIH0sXG5cbiAgICBpc1Zpc2libGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgZXRoZXJwYWRJZnJhbWUgPSAkKCcjZXRoZXJwYWQ+aWZyYW1lJyk7XG4gICAgICAgIHJldHVybiBldGhlcnBhZElmcmFtZSAmJiBldGhlcnBhZElmcmFtZS5pcygnOnZpc2libGUnKTtcbiAgICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRXRoZXJwYWQ7XG4iLCJ2YXIgVG9vbGJhclRvZ2dsZXIgPSByZXF1aXJlKFwiLi4vdG9vbGJhcnMvVG9vbGJhclRvZ2dsZXJcIik7XG52YXIgVUlVdGlsID0gcmVxdWlyZShcIi4uL3V0aWwvVUlVdGlsXCIpO1xudmFyIFZpZGVvTGF5b3V0ID0gcmVxdWlyZShcIi4uL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0XCIpO1xudmFyIG1lc3NhZ2VIYW5kbGVyID0gcmVxdWlyZShcIi4uL3V0aWwvTWVzc2FnZUhhbmRsZXJcIik7XG52YXIgUHJlemlQbGF5ZXIgPSByZXF1aXJlKFwiLi9QcmV6aVBsYXllclwiKTtcblxudmFyIHByZXppUGxheWVyID0gbnVsbDtcblxudmFyIFByZXppID0ge1xuXG5cbiAgICAvKipcbiAgICAgKiBSZWxvYWRzIHRoZSBjdXJyZW50IHByZXNlbnRhdGlvbi5cbiAgICAgKi9cbiAgICByZWxvYWRQcmVzZW50YXRpb246IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgaWZyYW1lID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocHJlemlQbGF5ZXIub3B0aW9ucy5wcmV6aUlkKTtcbiAgICAgICAgaWZyYW1lLnNyYyA9IGlmcmFtZS5zcmM7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgPHR0PnRydWU8L3R0PiBpZiB0aGUgcHJlc2VudGF0aW9uIGlzIHZpc2libGUsIDx0dD5mYWxzZTwvdHQ+IC1cbiAgICAgKiBvdGhlcndpc2UuXG4gICAgICovXG4gICAgaXNQcmVzZW50YXRpb25WaXNpYmxlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAoJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKSAhPSBudWxsXG4gICAgICAgICAgICAgICAgJiYgJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS5jc3MoJ29wYWNpdHknKSA9PSAxKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogT3BlbnMgdGhlIFByZXppIGRpYWxvZywgZnJvbSB3aGljaCB0aGUgdXNlciBjb3VsZCBjaG9vc2UgYSBwcmVzZW50YXRpb25cbiAgICAgKiB0byBsb2FkLlxuICAgICAqL1xuICAgIG9wZW5QcmV6aURpYWxvZzogZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBteXByZXppID0gQVBQLnhtcHAuZ2V0UHJlemkoKTtcbiAgICAgICAgaWYgKG15cHJlemkpIHtcbiAgICAgICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2coXCJkaWFsb2cucmVtb3ZlUHJlemlUaXRsZVwiLFxuICAgICAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICAgICAgXCJkaWFsb2cucmVtb3ZlUHJlemlNc2dcIixcbiAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgIFwiZGlhbG9nLlJlbW92ZVwiLFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGUsdixtLGYpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYodikge1xuICAgICAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAucmVtb3ZlUHJlemlGcm9tUHJlc2VuY2UoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocHJlemlQbGF5ZXIgIT0gbnVsbCkge1xuICAgICAgICAgICAgbWVzc2FnZUhhbmRsZXIub3BlblR3b0J1dHRvbkRpYWxvZyhcImRpYWxvZy5zaGFyZVByZXppVGl0bGVcIixcbiAgICAgICAgICAgICAgICBudWxsLCBcImRpYWxvZy5zaGFyZVByZXppTXNnXCIsXG4gICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICBcImRpYWxvZy5Pa1wiLFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGUsdixtLGYpIHtcbiAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIGh0bWwgPSBBUFAudHJhbnNsYXRpb24uZ2VuZXJhdGVUcmFuc2xhdG9uSFRNTChcbiAgICAgICAgICAgICAgICBcImRpYWxvZy5zaGFyZVByZXppVGl0bGVcIik7XG4gICAgICAgICAgICB2YXIgY2FuY2VsQnV0dG9uID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXG4gICAgICAgICAgICAgICAgXCJkaWFsb2cuQ2FuY2VsXCIpO1xuICAgICAgICAgICAgdmFyIHNoYXJlQnV0dG9uID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXG4gICAgICAgICAgICAgICAgXCJkaWFsb2cuU2hhcmVcIik7XG4gICAgICAgICAgICB2YXIgYmFja0J1dHRvbiA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFxuICAgICAgICAgICAgICAgIFwiZGlhbG9nLkJhY2tcIik7XG4gICAgICAgICAgICB2YXIgYnV0dG9ucyA9IFtdO1xuICAgICAgICAgICAgdmFyIGJ1dHRvbnMxID0gW107XG4gICAgICAgICAgICAvLyBDYW5jZWwgYnV0dG9uIHRvIGJvdGggc3RhdGVzXG4gICAgICAgICAgICBidXR0b25zLnB1c2goe3RpdGxlOiBjYW5jZWxCdXR0b24sIHZhbHVlOiBmYWxzZX0pO1xuICAgICAgICAgICAgYnV0dG9uczEucHVzaCh7dGl0bGU6IGNhbmNlbEJ1dHRvbiwgdmFsdWU6IGZhbHNlfSk7XG4gICAgICAgICAgICAvLyBTaGFyZSBidXR0b25cbiAgICAgICAgICAgIGJ1dHRvbnMucHVzaCh7dGl0bGU6IHNoYXJlQnV0dG9uLCB2YWx1ZTogdHJ1ZX0pO1xuICAgICAgICAgICAgLy8gQmFjayBidXR0b25cbiAgICAgICAgICAgIGJ1dHRvbnMxLnB1c2goe3RpdGxlOiBiYWNrQnV0dG9uLCB2YWx1ZTogdHJ1ZX0pO1xuICAgICAgICAgICAgdmFyIGxpbmtFcnJvciA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFxuICAgICAgICAgICAgICAgIFwiZGlhbG9nLnByZXppTGlua0Vycm9yXCIpO1xuICAgICAgICAgICAgdmFyIGRlZmF1bHRVcmwgPSBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nKFwiZGVmYXVsdFByZXppTGlua1wiLFxuICAgICAgICAgICAgICAgIHt1cmw6IFwiaHR0cDovL3ByZXppLmNvbS93ejd2aGp5Y2w3ZTYvbXktcHJlemlcIn0pO1xuICAgICAgICAgICAgdmFyIG9wZW5QcmV6aVN0YXRlID0ge1xuICAgICAgICAgICAgICAgIHN0YXRlMDoge1xuICAgICAgICAgICAgICAgICAgICBodG1sOiAgICc8aDI+JyArIGh0bWwgKyAnPC9oMj4nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGlucHV0IG5hbWU9XCJwcmV6aVVybFwiIHR5cGU9XCJ0ZXh0XCIgJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2RhdGEtaTE4bj1cIltwbGFjZWhvbGRlcl1kZWZhdWx0UHJlemlMaW5rXCIgZGF0YS1pMThuLW9wdGlvbnM9XFwnJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoe1widXJsXCI6IFwiaHR0cDovL3ByZXppLmNvbS93ejd2aGp5Y2w3ZTYvbXktcHJlemlcIn0pICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnXFwnIHBsYWNlaG9sZGVyPVwiJyArIGRlZmF1bHRVcmwgKyAnXCIgYXV0b2ZvY3VzPicsXG4gICAgICAgICAgICAgICAgICAgIHBlcnNpc3RlbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBidXR0b25zOiBidXR0b25zLFxuICAgICAgICAgICAgICAgICAgICBmb2N1czogJzppbnB1dDpmaXJzdCcsXG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHRCdXR0b246IDAsXG4gICAgICAgICAgICAgICAgICAgIHN1Ym1pdDogZnVuY3Rpb24gKGUsIHYsIG0sIGYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmKHYpXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHByZXppVXJsID0gZi5wcmV6aVVybDtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwcmV6aVVybClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciB1cmxWYWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPSBlbmNvZGVVUkkoVUlVdGlsLmVzY2FwZUh0bWwocHJlemlVcmwpKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodXJsVmFsdWUuaW5kZXhPZignaHR0cDovL3ByZXppLmNvbS8nKSAhPSAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiB1cmxWYWx1ZS5pbmRleE9mKCdodHRwczovL3ByZXppLmNvbS8nKSAhPSAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5nb1RvU3RhdGUoJ3N0YXRlMScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHByZXNJZFRtcCA9IHVybFZhbHVlLnN1YnN0cmluZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXJsVmFsdWUuaW5kZXhPZihcInByZXppLmNvbS9cIikgKyAxMCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzQWxwaGFudW1lcmljKHByZXNJZFRtcClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfHwgcHJlc0lkVG1wLmluZGV4T2YoJy8nKSA8IDIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5nb1RvU3RhdGUoJ3N0YXRlMScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFQUC54bXBwLmFkZFRvUHJlc2VuY2UoXCJwcmV6aVwiLCB1cmxWYWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBzdGF0ZTE6IHtcbiAgICAgICAgICAgICAgICAgICAgaHRtbDogICAnPGgyPicgKyBodG1sICsgJzwvaDI+JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlua0Vycm9yLFxuICAgICAgICAgICAgICAgICAgICBwZXJzaXN0ZW50OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgYnV0dG9uczogYnV0dG9uczEsXG4gICAgICAgICAgICAgICAgICAgIGZvY3VzOiAnOmlucHV0OmZpcnN0JyxcbiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdEJ1dHRvbjogMSxcbiAgICAgICAgICAgICAgICAgICAgc3VibWl0OiBmdW5jdGlvbiAoZSwgdiwgbSwgZikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHYgPT09IDApXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5nb1RvU3RhdGUoJ3N0YXRlMCcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5EaWFsb2dXaXRoU3RhdGVzKG9wZW5QcmV6aVN0YXRlKTtcbiAgICAgICAgfVxuICAgIH1cblxufTtcblxuLyoqXG4gKiBBIG5ldyBwcmVzZW50YXRpb24gaGFzIGJlZW4gYWRkZWQuXG4gKlxuICogQHBhcmFtIGV2ZW50IHRoZSBldmVudCBpbmRpY2F0aW5nIHRoZSBhZGQgb2YgYSBwcmVzZW50YXRpb25cbiAqIEBwYXJhbSBqaWQgdGhlIGppZCBmcm9tIHdoaWNoIHRoZSBwcmVzZW50YXRpb24gd2FzIGFkZGVkXG4gKiBAcGFyYW0gcHJlc1VybCB1cmwgb2YgdGhlIHByZXNlbnRhdGlvblxuICogQHBhcmFtIGN1cnJlbnRTbGlkZSB0aGUgY3VycmVudCBzbGlkZSB0byB3aGljaCB3ZSBzaG91bGQgbW92ZVxuICovXG5mdW5jdGlvbiBwcmVzZW50YXRpb25BZGRlZChldmVudCwgamlkLCBwcmVzVXJsLCBjdXJyZW50U2xpZGUpIHtcbiAgICBjb25zb2xlLmxvZyhcInByZXNlbnRhdGlvbiBhZGRlZFwiLCBwcmVzVXJsKTtcblxuICAgIHZhciBwcmVzSWQgPSBnZXRQcmVzZW50YXRpb25JZChwcmVzVXJsKTtcblxuICAgIHZhciBlbGVtZW50SWQgPSAncGFydGljaXBhbnRfJ1xuICAgICAgICArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZClcbiAgICAgICAgKyAnXycgKyBwcmVzSWQ7XG5cbiAgICAvLyBXZSBleHBsaWNpdGx5IGRvbid0IHNwZWNpZnkgdGhlIHBlZXIgamlkIGhlcmUsIGJlY2F1c2Ugd2UgZG9uJ3Qgd2FudFxuICAgIC8vIHRoaXMgdmlkZW8gdG8gYmUgZGVhbHQgd2l0aCBhcyBhIHBlZXIgcmVsYXRlZCBvbmUgKGZvciBleGFtcGxlIHdlXG4gICAgLy8gZG9uJ3Qgd2FudCB0byBzaG93IGEgbXV0ZS9raWNrIG1lbnUgZm9yIHRoaXMgb25lLCBldGMuKS5cbiAgICBWaWRlb0xheW91dC5hZGRSZW1vdGVWaWRlb0NvbnRhaW5lcihudWxsLCBlbGVtZW50SWQpO1xuICAgIFZpZGVvTGF5b3V0LnJlc2l6ZVRodW1ibmFpbHMoKTtcblxuICAgIHZhciBjb250cm9sc0VuYWJsZWQgPSBmYWxzZTtcbiAgICBpZiAoamlkID09PSBBUFAueG1wcC5teUppZCgpKVxuICAgICAgICBjb250cm9sc0VuYWJsZWQgPSB0cnVlO1xuXG4gICAgc2V0UHJlc2VudGF0aW9uVmlzaWJsZSh0cnVlKTtcbiAgICAkKCcjbGFyZ2VWaWRlb0NvbnRhaW5lcicpLmhvdmVyKFxuICAgICAgICBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChQcmV6aS5pc1ByZXNlbnRhdGlvblZpc2libGUoKSkge1xuICAgICAgICAgICAgICAgIHZhciByZWxvYWRCdXR0b25SaWdodCA9IHdpbmRvdy5pbm5lcldpZHRoXG4gICAgICAgICAgICAgICAgICAgIC0gJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS5vZmZzZXQoKS5sZWZ0XG4gICAgICAgICAgICAgICAgICAgIC0gJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS53aWR0aCgpO1xuXG4gICAgICAgICAgICAgICAgJCgnI3JlbG9hZFByZXNlbnRhdGlvbicpLmNzcyh7ICByaWdodDogcmVsb2FkQnV0dG9uUmlnaHQsXG4gICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6J2lubGluZS1ibG9jayd9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICBpZiAoIVByZXppLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpKVxuICAgICAgICAgICAgICAgICQoJyNyZWxvYWRQcmVzZW50YXRpb24nKS5jc3Moe2Rpc3BsYXk6J25vbmUnfSk7XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgZSA9IGV2ZW50LnRvRWxlbWVudCB8fCBldmVudC5yZWxhdGVkVGFyZ2V0O1xuXG4gICAgICAgICAgICAgICAgaWYgKGUgJiYgZS5pZCAhPSAncmVsb2FkUHJlc2VudGF0aW9uJyAmJiBlLmlkICE9ICdoZWFkZXInKVxuICAgICAgICAgICAgICAgICAgICAkKCcjcmVsb2FkUHJlc2VudGF0aW9uJykuY3NzKHtkaXNwbGF5Oidub25lJ30pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgIHByZXppUGxheWVyID0gbmV3IFByZXppUGxheWVyKFxuICAgICAgICAncHJlc2VudGF0aW9uJyxcbiAgICAgICAge3ByZXppSWQ6IHByZXNJZCxcbiAgICAgICAgICAgIHdpZHRoOiBnZXRQcmVzZW50YXRpb25XaWR0aCgpLFxuICAgICAgICAgICAgaGVpZ2h0OiBnZXRQcmVzZW50YXRpb25IZWloZ3QoKSxcbiAgICAgICAgICAgIGNvbnRyb2xzOiBjb250cm9sc0VuYWJsZWQsXG4gICAgICAgICAgICBkZWJ1ZzogdHJ1ZVxuICAgICAgICB9KTtcblxuICAgICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykuYXR0cignaWQnLCBwcmV6aVBsYXllci5vcHRpb25zLnByZXppSWQpO1xuXG4gICAgcHJlemlQbGF5ZXIub24oUHJlemlQbGF5ZXIuRVZFTlRfU1RBVFVTLCBmdW5jdGlvbihldmVudCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcInByZXppIHN0YXR1c1wiLCBldmVudC52YWx1ZSk7XG4gICAgICAgIGlmIChldmVudC52YWx1ZSA9PSBQcmV6aVBsYXllci5TVEFUVVNfQ09OVEVOVF9SRUFEWSkge1xuICAgICAgICAgICAgaWYgKGppZCAhPSBBUFAueG1wcC5teUppZCgpKVxuICAgICAgICAgICAgICAgIHByZXppUGxheWVyLmZseVRvU3RlcChjdXJyZW50U2xpZGUpO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICBwcmV6aVBsYXllci5vbihQcmV6aVBsYXllci5FVkVOVF9DVVJSRU5UX1NURVAsIGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiZXZlbnQgdmFsdWVcIiwgZXZlbnQudmFsdWUpO1xuICAgICAgICBBUFAueG1wcC5hZGRUb1ByZXNlbmNlKFwicHJlemlTbGlkZVwiLCBldmVudC52YWx1ZSk7XG4gICAgfSk7XG5cbiAgICAkKFwiI1wiICsgZWxlbWVudElkKS5jc3MoICdiYWNrZ3JvdW5kLWltYWdlJyxcbiAgICAgICAgJ3VybCguLi9pbWFnZXMvYXZhdGFycHJlemkucG5nKScpO1xuICAgICQoXCIjXCIgKyBlbGVtZW50SWQpLmNsaWNrKFxuICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBzZXRQcmVzZW50YXRpb25WaXNpYmxlKHRydWUpO1xuICAgICAgICB9XG4gICAgKTtcbn07XG5cbi8qKlxuICogQSBwcmVzZW50YXRpb24gaGFzIGJlZW4gcmVtb3ZlZC5cbiAqXG4gKiBAcGFyYW0gZXZlbnQgdGhlIGV2ZW50IGluZGljYXRpbmcgdGhlIHJlbW92ZSBvZiBhIHByZXNlbnRhdGlvblxuICogQHBhcmFtIGppZCB0aGUgamlkIGZvciB3aGljaCB0aGUgcHJlc2VudGF0aW9uIHdhcyByZW1vdmVkXG4gKiBAcGFyYW0gdGhlIHVybCBvZiB0aGUgcHJlc2VudGF0aW9uXG4gKi9cbmZ1bmN0aW9uIHByZXNlbnRhdGlvblJlbW92ZWQoZXZlbnQsIGppZCwgcHJlc1VybCkge1xuICAgIGNvbnNvbGUubG9nKCdwcmVzZW50YXRpb24gcmVtb3ZlZCcsIHByZXNVcmwpO1xuICAgIHZhciBwcmVzSWQgPSBnZXRQcmVzZW50YXRpb25JZChwcmVzVXJsKTtcbiAgICBzZXRQcmVzZW50YXRpb25WaXNpYmxlKGZhbHNlKTtcbiAgICAkKCcjcGFydGljaXBhbnRfJ1xuICAgICAgICArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZClcbiAgICAgICAgKyAnXycgKyBwcmVzSWQpLnJlbW92ZSgpO1xuICAgICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykucmVtb3ZlKCk7XG4gICAgaWYgKHByZXppUGxheWVyICE9IG51bGwpIHtcbiAgICAgICAgcHJlemlQbGF5ZXIuZGVzdHJveSgpO1xuICAgICAgICBwcmV6aVBsYXllciA9IG51bGw7XG4gICAgfVxufTtcblxuLyoqXG4gKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBhbiBhbHBoYW51bWVyaWMgc3RyaW5nLlxuICogTm90ZSB0aGF0IHNvbWUgc3BlY2lhbCBjaGFyYWN0ZXJzIGFyZSBhbHNvIGFsbG93ZWQgKC0sIF8gLCAvLCAmLCA/LCA9LCA7KSBmb3IgdGhlXG4gKiBwdXJwb3NlIG9mIGNoZWNraW5nIFVSSXMuXG4gKi9cbmZ1bmN0aW9uIGlzQWxwaGFudW1lcmljKHVuc2FmZVRleHQpIHtcbiAgICB2YXIgcmVnZXggPSAvXlthLXowLTktX1xcLyZcXD89O10rJC9pO1xuICAgIHJldHVybiByZWdleC50ZXN0KHVuc2FmZVRleHQpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHByZXNlbnRhdGlvbiBpZCBmcm9tIHRoZSBnaXZlbiB1cmwuXG4gKi9cbmZ1bmN0aW9uIGdldFByZXNlbnRhdGlvbklkIChwcmVzVXJsKSB7XG4gICAgdmFyIHByZXNJZFRtcCA9IHByZXNVcmwuc3Vic3RyaW5nKHByZXNVcmwuaW5kZXhPZihcInByZXppLmNvbS9cIikgKyAxMCk7XG4gICAgcmV0dXJuIHByZXNJZFRtcC5zdWJzdHJpbmcoMCwgcHJlc0lkVG1wLmluZGV4T2YoJy8nKSk7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgcHJlc2VudGF0aW9uIHdpZHRoLlxuICovXG5mdW5jdGlvbiBnZXRQcmVzZW50YXRpb25XaWR0aCgpIHtcbiAgICB2YXIgYXZhaWxhYmxlV2lkdGggPSBVSVV0aWwuZ2V0QXZhaWxhYmxlVmlkZW9XaWR0aCgpO1xuICAgIHZhciBhdmFpbGFibGVIZWlnaHQgPSBnZXRQcmVzZW50YXRpb25IZWloZ3QoKTtcblxuICAgIHZhciBhc3BlY3RSYXRpbyA9IDE2LjAgLyA5LjA7XG4gICAgaWYgKGF2YWlsYWJsZUhlaWdodCA8IGF2YWlsYWJsZVdpZHRoIC8gYXNwZWN0UmF0aW8pIHtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSBNYXRoLmZsb29yKGF2YWlsYWJsZUhlaWdodCAqIGFzcGVjdFJhdGlvKTtcbiAgICB9XG4gICAgcmV0dXJuIGF2YWlsYWJsZVdpZHRoO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHByZXNlbnRhdGlvbiBoZWlnaHQuXG4gKi9cbmZ1bmN0aW9uIGdldFByZXNlbnRhdGlvbkhlaWhndCgpIHtcbiAgICB2YXIgcmVtb3RlVmlkZW9zID0gJCgnI3JlbW90ZVZpZGVvcycpO1xuICAgIHJldHVybiB3aW5kb3cuaW5uZXJIZWlnaHQgLSByZW1vdGVWaWRlb3Mub3V0ZXJIZWlnaHQoKTtcbn1cblxuLyoqXG4gKiBSZXNpemVzIHRoZSBwcmVzZW50YXRpb24gaWZyYW1lLlxuICovXG5mdW5jdGlvbiByZXNpemUoKSB7XG4gICAgaWYgKCQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykpIHtcbiAgICAgICAgJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS53aWR0aChnZXRQcmVzZW50YXRpb25XaWR0aCgpKTtcbiAgICAgICAgJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS5oZWlnaHQoZ2V0UHJlc2VudGF0aW9uSGVpaGd0KCkpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBTaG93cy9oaWRlcyBhIHByZXNlbnRhdGlvbi5cbiAqL1xuZnVuY3Rpb24gc2V0UHJlc2VudGF0aW9uVmlzaWJsZSh2aXNpYmxlKSB7XG4gICAgdmFyIHByZXppID0gJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKTtcbiAgICBpZiAodmlzaWJsZSkge1xuICAgICAgICAvLyBUcmlnZ2VyIHRoZSB2aWRlby5zZWxlY3RlZCBldmVudCB0byBpbmRpY2F0ZSBhIGNoYW5nZSBpbiB0aGVcbiAgICAgICAgLy8gbGFyZ2UgdmlkZW8uXG4gICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoXCJ2aWRlby5zZWxlY3RlZFwiLCBbdHJ1ZV0pO1xuXG4gICAgICAgICQoJyNsYXJnZVZpZGVvJykuZmFkZU91dCgzMDApO1xuICAgICAgICBwcmV6aS5mYWRlSW4oMzAwLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHByZXppLmNzcyh7b3BhY2l0eTonMSd9KTtcbiAgICAgICAgICAgIFRvb2xiYXJUb2dnbGVyLmRvY2tUb29sYmFyKHRydWUpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2V0TGFyZ2VWaWRlb1Zpc2libGUoZmFsc2UpO1xuICAgICAgICB9KTtcbiAgICAgICAgJCgnI2FjdGl2ZVNwZWFrZXInKS5jc3MoJ3Zpc2liaWxpdHknLCAnaGlkZGVuJyk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBpZiAocHJlemkuY3NzKCdvcGFjaXR5JykgPT0gJzEnKSB7XG4gICAgICAgICAgICBwcmV6aS5mYWRlT3V0KDMwMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHByZXppLmNzcyh7b3BhY2l0eTonMCd9KTtcbiAgICAgICAgICAgICAgICAkKCcjcmVsb2FkUHJlc2VudGF0aW9uJykuY3NzKHtkaXNwbGF5Oidub25lJ30pO1xuICAgICAgICAgICAgICAgICQoJyNsYXJnZVZpZGVvJykuZmFkZUluKDMwMCwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNldExhcmdlVmlkZW9WaXNpYmxlKHRydWUpO1xuICAgICAgICAgICAgICAgICAgICBUb29sYmFyVG9nZ2xlci5kb2NrVG9vbGJhcihmYWxzZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLyoqXG4gKiBQcmVzZW50YXRpb24gaGFzIGJlZW4gcmVtb3ZlZC5cbiAqL1xuJChkb2N1bWVudCkuYmluZCgncHJlc2VudGF0aW9ucmVtb3ZlZC5tdWMnLCBwcmVzZW50YXRpb25SZW1vdmVkKTtcblxuLyoqXG4gKiBQcmVzZW50YXRpb24gaGFzIGJlZW4gYWRkZWQuXG4gKi9cbiQoZG9jdW1lbnQpLmJpbmQoJ3ByZXNlbnRhdGlvbmFkZGVkLm11YycsIHByZXNlbnRhdGlvbkFkZGVkKTtcblxuLypcbiAqIEluZGljYXRlcyBwcmVzZW50YXRpb24gc2xpZGUgY2hhbmdlLlxuICovXG4kKGRvY3VtZW50KS5iaW5kKCdnb3Rvc2xpZGUubXVjJywgZnVuY3Rpb24gKGV2ZW50LCBqaWQsIHByZXNVcmwsIGN1cnJlbnQpIHtcbiAgICBpZiAocHJlemlQbGF5ZXIgJiYgcHJlemlQbGF5ZXIuZ2V0Q3VycmVudFN0ZXAoKSAhPSBjdXJyZW50KSB7XG4gICAgICAgIHByZXppUGxheWVyLmZseVRvU3RlcChjdXJyZW50KTtcblxuICAgICAgICB2YXIgYW5pbWF0aW9uU3RlcHNBcnJheSA9IHByZXppUGxheWVyLmdldEFuaW1hdGlvbkNvdW50T25TdGVwcygpO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBhcnNlSW50KGFuaW1hdGlvblN0ZXBzQXJyYXlbY3VycmVudF0pOyBpKyspIHtcbiAgICAgICAgICAgIHByZXppUGxheWVyLmZseVRvU3RlcChjdXJyZW50LCBpKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIE9uIHZpZGVvIHNlbGVjdGVkIGV2ZW50LlxuICovXG4kKGRvY3VtZW50KS5iaW5kKCd2aWRlby5zZWxlY3RlZCcsIGZ1bmN0aW9uIChldmVudCwgaXNQcmVzZW50YXRpb24pIHtcbiAgICBpZiAoIWlzUHJlc2VudGF0aW9uICYmICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykpIHtcbiAgICAgICAgc2V0UHJlc2VudGF0aW9uVmlzaWJsZShmYWxzZSk7XG4gICAgfVxufSk7XG5cbiQod2luZG93KS5yZXNpemUoZnVuY3Rpb24gKCkge1xuICAgIHJlc2l6ZSgpO1xufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUHJlemk7XG4iLCIoZnVuY3Rpb24oKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG4gICAgdmFyIF9fYmluZCA9IGZ1bmN0aW9uKGZuLCBtZSl7IHJldHVybiBmdW5jdGlvbigpeyByZXR1cm4gZm4uYXBwbHkobWUsIGFyZ3VtZW50cyk7IH07IH07XG5cbiAgICB3aW5kb3cuUHJlemlQbGF5ZXIgPSAoZnVuY3Rpb24oKSB7XG5cbiAgICAgICAgUHJlemlQbGF5ZXIuQVBJX1ZFUlNJT04gPSAxO1xuICAgICAgICBQcmV6aVBsYXllci5DVVJSRU5UX1NURVAgPSAnY3VycmVudFN0ZXAnO1xuICAgICAgICBQcmV6aVBsYXllci5DVVJSRU5UX0FOSU1BVElPTl9TVEVQID0gJ2N1cnJlbnRBbmltYXRpb25TdGVwJztcbiAgICAgICAgUHJlemlQbGF5ZXIuQ1VSUkVOVF9PQkpFQ1QgPSAnY3VycmVudE9iamVjdCc7XG4gICAgICAgIFByZXppUGxheWVyLlNUQVRVU19MT0FESU5HID0gJ2xvYWRpbmcnO1xuICAgICAgICBQcmV6aVBsYXllci5TVEFUVVNfUkVBRFkgPSAncmVhZHknO1xuICAgICAgICBQcmV6aVBsYXllci5TVEFUVVNfQ09OVEVOVF9SRUFEWSA9ICdjb250ZW50cmVhZHknO1xuICAgICAgICBQcmV6aVBsYXllci5FVkVOVF9DVVJSRU5UX1NURVAgPSBcImN1cnJlbnRTdGVwQ2hhbmdlXCI7XG4gICAgICAgIFByZXppUGxheWVyLkVWRU5UX0NVUlJFTlRfQU5JTUFUSU9OX1NURVAgPSBcImN1cnJlbnRBbmltYXRpb25TdGVwQ2hhbmdlXCI7XG4gICAgICAgIFByZXppUGxheWVyLkVWRU5UX0NVUlJFTlRfT0JKRUNUID0gXCJjdXJyZW50T2JqZWN0Q2hhbmdlXCI7XG4gICAgICAgIFByZXppUGxheWVyLkVWRU5UX1NUQVRVUyA9IFwic3RhdHVzQ2hhbmdlXCI7XG4gICAgICAgIFByZXppUGxheWVyLkVWRU5UX1BMQVlJTkcgPSBcImlzQXV0b1BsYXlpbmdDaGFuZ2VcIjtcbiAgICAgICAgUHJlemlQbGF5ZXIuRVZFTlRfSVNfTU9WSU5HID0gXCJpc01vdmluZ0NoYW5nZVwiO1xuICAgICAgICBQcmV6aVBsYXllci5kb21haW4gPSBcImh0dHBzOi8vcHJlemkuY29tXCI7XG4gICAgICAgIFByZXppUGxheWVyLnBhdGggPSBcIi9wbGF5ZXIvXCI7XG4gICAgICAgIFByZXppUGxheWVyLnBsYXllcnMgPSB7fTtcbiAgICAgICAgUHJlemlQbGF5ZXIuYmluZGVkX21ldGhvZHMgPSBbJ2NoYW5nZXNIYW5kbGVyJ107XG5cbiAgICAgICAgUHJlemlQbGF5ZXIuY3JlYXRlTXVsdGlwbGVQbGF5ZXJzID0gZnVuY3Rpb24ob3B0aW9uQXJyYXkpe1xuICAgICAgICAgICAgZm9yKHZhciBpPTA7IGk8b3B0aW9uQXJyYXkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgb3B0aW9uU2V0ID0gb3B0aW9uQXJyYXlbaV07XG4gICAgICAgICAgICAgICAgbmV3IFByZXppUGxheWVyKG9wdGlvblNldC5pZCwgb3B0aW9uU2V0KTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIubWVzc2FnZVJlY2VpdmVkID0gZnVuY3Rpb24oZXZlbnQpe1xuICAgICAgICAgICAgdmFyIG1lc3NhZ2UsIGl0ZW0sIHBsYXllcjtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZSA9IEpTT04ucGFyc2UoZXZlbnQuZGF0YSk7XG4gICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UuaWQgJiYgKHBsYXllciA9IFByZXppUGxheWVyLnBsYXllcnNbbWVzc2FnZS5pZF0pKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChwbGF5ZXIub3B0aW9ucy5kZWJ1ZyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbnNvbGUgJiYgY29uc29sZS5sb2cpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3JlY2VpdmVkJywgbWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJjaGFuZ2VzXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBsYXllci5jaGFuZ2VzSGFuZGxlcihtZXNzYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBsYXllci5jYWxsYmFja3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW0gPSBwbGF5ZXIuY2FsbGJhY2tzW2ldO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0gJiYgbWVzc2FnZS50eXBlID09PSBpdGVtLmV2ZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS5jYWxsYmFjayhtZXNzYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHsgfVxuICAgICAgICB9O1xuXG4gICAgICAgIGZ1bmN0aW9uIFByZXppUGxheWVyKGlkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGFyYW1zLCBwYXJhbVN0cmluZyA9IFwiXCIsIF90aGlzID0gdGhpcztcbiAgICAgICAgICAgIGlmIChQcmV6aVBsYXllci5wbGF5ZXJzW2lkXSl7XG4gICAgICAgICAgICAgICAgUHJlemlQbGF5ZXIucGxheWVyc1tpZF0uZGVzdHJveSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yKHZhciBpPTA7IGk8UHJlemlQbGF5ZXIuYmluZGVkX21ldGhvZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgbWV0aG9kX25hbWUgPSBQcmV6aVBsYXllci5iaW5kZWRfbWV0aG9kc1tpXTtcbiAgICAgICAgICAgICAgICBfdGhpc1ttZXRob2RfbmFtZV0gPSBfX2JpbmQoX3RoaXNbbWV0aG9kX25hbWVdLCBfdGhpcyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgdGhpcy52YWx1ZXMgPSB7J3N0YXR1cyc6IFByZXppUGxheWVyLlNUQVRVU19MT0FESU5HfTtcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW1ByZXppUGxheWVyLkNVUlJFTlRfU1RFUF0gPSAwO1xuICAgICAgICAgICAgdGhpcy52YWx1ZXNbUHJlemlQbGF5ZXIuQ1VSUkVOVF9BTklNQVRJT05fU1RFUF0gPSAwO1xuICAgICAgICAgICAgdGhpcy52YWx1ZXNbUHJlemlQbGF5ZXIuQ1VSUkVOVF9PQkpFQ1RdID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tzID0gW107XG4gICAgICAgICAgICB0aGlzLmlkID0gaWQ7XG4gICAgICAgICAgICB0aGlzLmVtYmVkVG8gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZW1iZWRUbykge1xuICAgICAgICAgICAgICAgIHRocm93IFwiVGhlIGVsZW1lbnQgaWQgaXMgbm90IGF2YWlsYWJsZS5cIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuaWZyYW1lID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaWZyYW1lJyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBbXG4gICAgICAgICAgICAgICAgeyBuYW1lOiAnb2lkJywgdmFsdWU6IG9wdGlvbnMucHJlemlJZCB9LFxuICAgICAgICAgICAgICAgIHsgbmFtZTogJ2V4cGxvcmFibGUnLCB2YWx1ZTogb3B0aW9ucy5leHBsb3JhYmxlID8gMSA6IDAgfSxcbiAgICAgICAgICAgICAgICB7IG5hbWU6ICdjb250cm9scycsIHZhbHVlOiBvcHRpb25zLmNvbnRyb2xzID8gMSA6IDAgfVxuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIGZvcih2YXIgaT0wOyBpPHBhcmFtcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHZhciBwYXJhbSA9IHBhcmFtc1tpXTtcbiAgICAgICAgICAgICAgICBwYXJhbVN0cmluZyArPSAoaT09PTAgPyBcIj9cIiA6IFwiJlwiKSArIHBhcmFtLm5hbWUgKyBcIj1cIiArIHBhcmFtLnZhbHVlO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHRoaXMuaWZyYW1lLnNyYyA9IFByZXppUGxheWVyLmRvbWFpbiArIFByZXppUGxheWVyLnBhdGggKyBwYXJhbVN0cmluZztcbiAgICAgICAgICAgIHRoaXMuaWZyYW1lLmZyYW1lQm9yZGVyID0gMDtcbiAgICAgICAgICAgIHRoaXMuaWZyYW1lLnNjcm9sbGluZyA9IFwibm9cIjtcbiAgICAgICAgICAgIHRoaXMuaWZyYW1lLndpZHRoID0gb3B0aW9ucy53aWR0aCB8fCA2NDA7XG4gICAgICAgICAgICB0aGlzLmlmcmFtZS5oZWlnaHQgPSBvcHRpb25zLmhlaWdodCB8fCA0ODA7XG4gICAgICAgICAgICB0aGlzLmVtYmVkVG8uaW5uZXJIVE1MID0gJyc7XG4gICAgICAgICAgICAvLyBKSVRTSTogSU4gQ0FTRSBTT01FVEhJTkcgR09FUyBXUk9ORy5cbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWJlZFRvLmFwcGVuZENoaWxkKHRoaXMuaWZyYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIkNBVENIIEVSUk9SXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBKSVRTSTogSW5jcmVhc2UgaW50ZXJ2YWwgZnJvbSAyMDAgdG8gNTAwLCB3aGljaCBmaXhlcyBwcmV6aVxuICAgICAgICAgICAgLy8gY3Jhc2hlcyBmb3IgdXMuXG4gICAgICAgICAgICB0aGlzLmluaXRQb2xsSW50ZXJ2YWwgPSBzZXRJbnRlcnZhbChmdW5jdGlvbigpe1xuICAgICAgICAgICAgICAgIF90aGlzLnNlbmRNZXNzYWdlKHsnYWN0aW9uJzogJ2luaXQnfSk7XG4gICAgICAgICAgICB9LCA1MDApO1xuICAgICAgICAgICAgUHJlemlQbGF5ZXIucGxheWVyc1tpZF0gPSB0aGlzO1xuICAgICAgICB9XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmNoYW5nZXNIYW5kbGVyID0gZnVuY3Rpb24obWVzc2FnZSkge1xuICAgICAgICAgICAgdmFyIGtleSwgdmFsdWUsIGosIGl0ZW07XG4gICAgICAgICAgICBpZiAodGhpcy5pbml0UG9sbEludGVydmFsKSB7XG4gICAgICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmluaXRQb2xsSW50ZXJ2YWwpO1xuICAgICAgICAgICAgICAgIHRoaXMuaW5pdFBvbGxJbnRlcnZhbCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChrZXkgaW4gbWVzc2FnZS5kYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UuZGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpKXtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBtZXNzYWdlLmRhdGFba2V5XTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGo9MDsgajx0aGlzLmNhbGxiYWNrcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbSA9IHRoaXMuY2FsbGJhY2tzW2pdO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0gJiYgaXRlbS5ldmVudCA9PT0ga2V5ICsgXCJDaGFuZ2VcIil7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS5jYWxsYmFjayh7dHlwZTogaXRlbS5ldmVudCwgdmFsdWU6IHZhbHVlfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmluaXRQb2xsSW50ZXJ2YWwpIHtcbiAgICAgICAgICAgICAgICBjbGVhckludGVydmFsKHRoaXMuaW5pdFBvbGxJbnRlcnZhbCk7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0UG9sbEludGVydmFsID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmVtYmVkVG8uaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLnNlbmRNZXNzYWdlID0gZnVuY3Rpb24obWVzc2FnZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5kZWJ1ZyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIGlmIChjb25zb2xlICYmIGNvbnNvbGUubG9nKSBjb25zb2xlLmxvZygnc2VudCcsIG1lc3NhZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbWVzc2FnZS52ZXJzaW9uID0gUHJlemlQbGF5ZXIuQVBJX1ZFUlNJT047XG4gICAgICAgICAgICBtZXNzYWdlLmlkID0gdGhpcy5pZDtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpLCAnKicpO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5uZXh0U3RlcCA9IC8qIG5leHRTdGVwIGlzIERFUFJFQ0FURUQgKi9cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmZseVRvTmV4dFN0ZXAgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNlbmRNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAnYWN0aW9uJzogJ3ByZXNlbnQnLFxuICAgICAgICAgICAgICAgICdkYXRhJzogWydtb3ZlVG9OZXh0U3RlcCddXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUucHJldmlvdXNTdGVwID0gLyogcHJldmlvdXNTdGVwIGlzIERFUFJFQ0FURUQgKi9cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmZseVRvUHJldmlvdXNTdGVwID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZW5kTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgJ2FjdGlvbic6ICdwcmVzZW50JyxcbiAgICAgICAgICAgICAgICAnZGF0YSc6IFsnbW92ZVRvUHJldlN0ZXAnXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLnRvU3RlcCA9IC8qIHRvU3RlcCBpcyBERVBSRUNBVEVEICovXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5mbHlUb1N0ZXAgPSBmdW5jdGlvbihzdGVwLCBhbmltYXRpb25fc3RlcCkge1xuICAgICAgICAgICAgdmFyIG9iaiA9IHRoaXM7XG4gICAgICAgICAgICAvLyBjaGVjayBhbmltYXRpb25fc3RlcFxuICAgICAgICAgICAgaWYgKGFuaW1hdGlvbl9zdGVwID4gMCAmJlxuICAgICAgICAgICAgICAgIG9iai52YWx1ZXMuYW5pbWF0aW9uQ291bnRPblN0ZXBzICYmXG4gICAgICAgICAgICAgICAgb2JqLnZhbHVlcy5hbmltYXRpb25Db3VudE9uU3RlcHNbc3RlcF0gPD0gYW5pbWF0aW9uX3N0ZXApIHtcbiAgICAgICAgICAgICAgICBhbmltYXRpb25fc3RlcCA9IG9iai52YWx1ZXMuYW5pbWF0aW9uQ291bnRPblN0ZXBzW3N0ZXBdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8ganVtcCB0byBhbmltYXRpb24gc3RlcHMgYnkgY2FsbGluZyBmbHlUb05leHRTdGVwKClcbiAgICAgICAgICAgIGZ1bmN0aW9uIGRvQW5pbWF0aW9uU3RlcHMoKSB7XG4gICAgICAgICAgICAgICAgaWYgKG9iai52YWx1ZXMuaXNNb3ZpbmcgPT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGRvQW5pbWF0aW9uU3RlcHMsIDEwMCk7IC8vIHdhaXQgdW50aWwgdGhlIGZsaWdodCBlbmRzXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgd2hpbGUgKGFuaW1hdGlvbl9zdGVwLS0gPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIG9iai5mbHlUb05leHRTdGVwKCk7IC8vIGRvIHRoZSBhbmltYXRpb24gc3RlcHNcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzZXRUaW1lb3V0KGRvQW5pbWF0aW9uU3RlcHMsIDIwMCk7IC8vIDIwMG1zIGlzIHRoZSBpbnRlcm5hbCBcInJlcG9ydGluZ1wiIHRpbWVcbiAgICAgICAgICAgIC8vIGp1bXAgdG8gdGhlIHN0ZXBcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNlbmRNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAnYWN0aW9uJzogJ3ByZXNlbnQnLFxuICAgICAgICAgICAgICAgICdkYXRhJzogWydtb3ZlVG9TdGVwJywgc3RlcF1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS50b09iamVjdCA9IC8qIHRvT2JqZWN0IGlzIERFUFJFQ0FURUQgKi9cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmZseVRvT2JqZWN0ID0gZnVuY3Rpb24ob2JqZWN0SWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNlbmRNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAnYWN0aW9uJzogJ3ByZXNlbnQnLFxuICAgICAgICAgICAgICAgICdkYXRhJzogWydtb3ZlVG9PYmplY3QnLCBvYmplY3RJZF1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5wbGF5ID0gZnVuY3Rpb24oZGVmYXVsdERlbGF5KSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZW5kTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgJ2FjdGlvbic6ICdwcmVzZW50JyxcbiAgICAgICAgICAgICAgICAnZGF0YSc6IFsnc3RhcnRBdXRvUGxheScsIGRlZmF1bHREZWxheV1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZW5kTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgJ2FjdGlvbic6ICdwcmVzZW50JyxcbiAgICAgICAgICAgICAgICAnZGF0YSc6IFsnc3RvcEF1dG9QbGF5J11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5wYXVzZSA9IGZ1bmN0aW9uKGRlZmF1bHREZWxheSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2VuZE1lc3NhZ2Uoe1xuICAgICAgICAgICAgICAgICdhY3Rpb24nOiAncHJlc2VudCcsXG4gICAgICAgICAgICAgICAgJ2RhdGEnOiBbJ3BhdXNlQXV0b1BsYXknLCBkZWZhdWx0RGVsYXldXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0Q3VycmVudFN0ZXAgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnZhbHVlcy5jdXJyZW50U3RlcDtcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0Q3VycmVudEFuaW1hdGlvblN0ZXAgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnZhbHVlcy5jdXJyZW50QW5pbWF0aW9uU3RlcDtcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0Q3VycmVudE9iamVjdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzLmN1cnJlbnRPYmplY3Q7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmdldFN0YXR1cyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzLnN0YXR1cztcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuaXNQbGF5aW5nID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXMuaXNBdXRvUGxheWluZztcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0U3RlcENvdW50ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXMuc3RlcENvdW50O1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5nZXRBbmltYXRpb25Db3VudE9uU3RlcHMgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnZhbHVlcy5hbmltYXRpb25Db3VudE9uU3RlcHM7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmdldFRpdGxlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXMudGl0bGU7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLnNldERpbWVuc2lvbnMgPSBmdW5jdGlvbihkaW1zKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBwYXJhbWV0ZXIgaW4gZGltcykge1xuICAgICAgICAgICAgICAgIHRoaXMuaWZyYW1lW3BhcmFtZXRlcl0gPSBkaW1zW3BhcmFtZXRlcl07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0RGltZW5zaW9ucyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB3aWR0aDogcGFyc2VJbnQodGhpcy5pZnJhbWUud2lkdGgsIDEwKSxcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IHBhcnNlSW50KHRoaXMuaWZyYW1lLmhlaWdodCwgMTApXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldmVudCwgY2FsbGJhY2spIHtcbiAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tzLnB1c2goe1xuICAgICAgICAgICAgICAgIGV2ZW50OiBldmVudCxcbiAgICAgICAgICAgICAgICBjYWxsYmFjazogY2FsbGJhY2tcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5vZmYgPSBmdW5jdGlvbihldmVudCwgY2FsbGJhY2spIHtcbiAgICAgICAgICAgIHZhciBqLCBpdGVtO1xuICAgICAgICAgICAgaWYgKGV2ZW50ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrcyA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaiA9IHRoaXMuY2FsbGJhY2tzLmxlbmd0aDtcbiAgICAgICAgICAgIHdoaWxlIChqLS0pIHtcbiAgICAgICAgICAgICAgICBpdGVtID0gdGhpcy5jYWxsYmFja3Nbal07XG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0gJiYgaXRlbS5ldmVudCA9PT0gZXZlbnQgJiYgKGNhbGxiYWNrID09PSB1bmRlZmluZWQgfHwgaXRlbS5jYWxsYmFjayA9PT0gY2FsbGJhY2spKXtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja3Muc3BsaWNlKGosIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBpZiAod2luZG93LmFkZEV2ZW50TGlzdGVuZXIpIHtcbiAgICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgUHJlemlQbGF5ZXIubWVzc2FnZVJlY2VpdmVkLCBmYWxzZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB3aW5kb3cuYXR0YWNoRXZlbnQoJ29ubWVzc2FnZScsIFByZXppUGxheWVyLm1lc3NhZ2VSZWNlaXZlZCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gUHJlemlQbGF5ZXI7XG5cbiAgICB9KSgpO1xuXG59KSgpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFByZXppUGxheWVyO1xuIiwidmFyIENoYXQgPSByZXF1aXJlKFwiLi9jaGF0L0NoYXRcIik7XG52YXIgQ29udGFjdExpc3QgPSByZXF1aXJlKFwiLi9jb250YWN0bGlzdC9Db250YWN0TGlzdFwiKTtcbnZhciBTZXR0aW5ncyA9IHJlcXVpcmUoXCIuLy4uLy4uL3NldHRpbmdzL1NldHRpbmdzXCIpO1xudmFyIFNldHRpbmdzTWVudSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzL1NldHRpbmdzTWVudVwiKTtcbnZhciBWaWRlb0xheW91dCA9IHJlcXVpcmUoXCIuLi92aWRlb2xheW91dC9WaWRlb0xheW91dFwiKTtcbnZhciBUb29sYmFyVG9nZ2xlciA9IHJlcXVpcmUoXCIuLi90b29sYmFycy9Ub29sYmFyVG9nZ2xlclwiKTtcbnZhciBVSVV0aWwgPSByZXF1aXJlKFwiLi4vdXRpbC9VSVV0aWxcIik7XG5cbi8qKlxuICogVG9nZ2xlciBmb3IgdGhlIGNoYXQsIGNvbnRhY3QgbGlzdCwgc2V0dGluZ3MgbWVudSwgZXRjLi5cbiAqL1xudmFyIFBhbmVsVG9nZ2xlciA9IChmdW5jdGlvbihteSkge1xuXG4gICAgdmFyIGN1cnJlbnRseU9wZW4gPSBudWxsO1xuICAgIHZhciBidXR0b25zID0ge1xuICAgICAgICAnI2NoYXRzcGFjZSc6ICcjY2hhdEJvdHRvbUJ1dHRvbicsXG4gICAgICAgICcjY29udGFjdGxpc3QnOiAnI2NvbnRhY3RMaXN0QnV0dG9uJyxcbiAgICAgICAgJyNzZXR0aW5nc21lbnUnOiAnI3NldHRpbmdzQnV0dG9uJ1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXNpemVzIHRoZSB2aWRlbyBhcmVhXG4gICAgICogQHBhcmFtIGlzQ2xvc2luZyB3aGV0aGVyIHRoZSBzaWRlIHBhbmVsIGlzIGdvaW5nIHRvIGJlIGNsb3NlZCBvciBpcyBnb2luZyB0byBvcGVuIC8gcmVtYWluIG9wZW5lZFxuICAgICAqIEBwYXJhbSBjb21wbGV0ZUZ1bmN0aW9uIGEgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIHZpZGVvIHNwYWNlIGlzIHJlc2l6ZWRcbiAgICAgKi9cbiAgICB2YXIgcmVzaXplVmlkZW9BcmVhID0gZnVuY3Rpb24oaXNDbG9zaW5nLCBjb21wbGV0ZUZ1bmN0aW9uKSB7XG4gICAgICAgIHZhciB2aWRlb3NwYWNlID0gJCgnI3ZpZGVvc3BhY2UnKTtcblxuICAgICAgICB2YXIgcGFuZWxTaXplID0gaXNDbG9zaW5nID8gWzAsIDBdIDogUGFuZWxUb2dnbGVyLmdldFBhbmVsU2l6ZSgpO1xuICAgICAgICB2YXIgdmlkZW9zcGFjZVdpZHRoID0gd2luZG93LmlubmVyV2lkdGggLSBwYW5lbFNpemVbMF07XG4gICAgICAgIHZhciB2aWRlb3NwYWNlSGVpZ2h0ID0gd2luZG93LmlubmVySGVpZ2h0O1xuICAgICAgICB2YXIgdmlkZW9TaXplXG4gICAgICAgICAgICA9IFZpZGVvTGF5b3V0LmdldFZpZGVvU2l6ZShudWxsLCBudWxsLCB2aWRlb3NwYWNlV2lkdGgsIHZpZGVvc3BhY2VIZWlnaHQpO1xuICAgICAgICB2YXIgdmlkZW9XaWR0aCA9IHZpZGVvU2l6ZVswXTtcbiAgICAgICAgdmFyIHZpZGVvSGVpZ2h0ID0gdmlkZW9TaXplWzFdO1xuICAgICAgICB2YXIgdmlkZW9Qb3NpdGlvbiA9IFZpZGVvTGF5b3V0LmdldFZpZGVvUG9zaXRpb24odmlkZW9XaWR0aCxcbiAgICAgICAgICAgIHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgdmlkZW9zcGFjZVdpZHRoLFxuICAgICAgICAgICAgdmlkZW9zcGFjZUhlaWdodCk7XG4gICAgICAgIHZhciBob3Jpem9udGFsSW5kZW50ID0gdmlkZW9Qb3NpdGlvblswXTtcbiAgICAgICAgdmFyIHZlcnRpY2FsSW5kZW50ID0gdmlkZW9Qb3NpdGlvblsxXTtcblxuICAgICAgICB2YXIgdGh1bWJuYWlsU2l6ZSA9IFZpZGVvTGF5b3V0LmNhbGN1bGF0ZVRodW1ibmFpbFNpemUodmlkZW9zcGFjZVdpZHRoKTtcbiAgICAgICAgdmFyIHRodW1ibmFpbHNXaWR0aCA9IHRodW1ibmFpbFNpemVbMF07XG4gICAgICAgIHZhciB0aHVtYm5haWxzSGVpZ2h0ID0gdGh1bWJuYWlsU2l6ZVsxXTtcbiAgICAgICAgLy9mb3IgY2hhdFxuXG4gICAgICAgIHZpZGVvc3BhY2UuYW5pbWF0ZSh7XG4gICAgICAgICAgICAgICAgcmlnaHQ6IHBhbmVsU2l6ZVswXSxcbiAgICAgICAgICAgICAgICB3aWR0aDogdmlkZW9zcGFjZVdpZHRoLFxuICAgICAgICAgICAgICAgIGhlaWdodDogdmlkZW9zcGFjZUhlaWdodFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDUwMCxcbiAgICAgICAgICAgICAgICBjb21wbGV0ZTogY29tcGxldGVGdW5jdGlvblxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgJCgnI3JlbW90ZVZpZGVvcycpLmFuaW1hdGUoe1xuICAgICAgICAgICAgICAgIGhlaWdodDogdGh1bWJuYWlsc0hlaWdodFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDUwMFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgJCgnI3JlbW90ZVZpZGVvcz5zcGFuJykuYW5pbWF0ZSh7XG4gICAgICAgICAgICAgICAgaGVpZ2h0OiB0aHVtYm5haWxzSGVpZ2h0LFxuICAgICAgICAgICAgICAgIHdpZHRoOiB0aHVtYm5haWxzV2lkdGhcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiA1MDAsXG4gICAgICAgICAgICAgICAgY29tcGxldGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcihcbiAgICAgICAgICAgICAgICAgICAgICAgIFwicmVtb3RldmlkZW8ucmVzaXplZFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgW3RodW1ibmFpbHNXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHVtYm5haWxzSGVpZ2h0XSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgJCgnI2xhcmdlVmlkZW9Db250YWluZXInKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICB3aWR0aDogdmlkZW9zcGFjZVdpZHRoLFxuICAgICAgICAgICAgICAgIGhlaWdodDogdmlkZW9zcGFjZUhlaWdodFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDUwMFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgJCgnI2xhcmdlVmlkZW8nKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICB3aWR0aDogdmlkZW9XaWR0aCxcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgIHRvcDogdmVydGljYWxJbmRlbnQsXG4gICAgICAgICAgICAgICAgYm90dG9tOiB2ZXJ0aWNhbEluZGVudCxcbiAgICAgICAgICAgICAgICBsZWZ0OiBob3Jpem9udGFsSW5kZW50LFxuICAgICAgICAgICAgICAgIHJpZ2h0OiBob3Jpem9udGFsSW5kZW50XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVG9nZ2xlcyB0aGUgd2luZG93cyBpbiB0aGUgc2lkZSBwYW5lbFxuICAgICAqIEBwYXJhbSBvYmplY3QgdGhlIHdpbmRvdyB0aGF0IHNob3VsZCBiZSBzaG93blxuICAgICAqIEBwYXJhbSBzZWxlY3RvciB0aGUgc2VsZWN0b3IgZm9yIHRoZSBlbGVtZW50IGNvbnRhaW5pbmcgdGhlIHBhbmVsXG4gICAgICogQHBhcmFtIG9uT3BlbkNvbXBsZXRlIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBwYW5lbCBpcyBvcGVuZWRcbiAgICAgKiBAcGFyYW0gb25PcGVuIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBpZiB0aGUgd2luZG93IGlzIGdvaW5nIHRvIGJlIG9wZW5lZFxuICAgICAqIEBwYXJhbSBvbkNsb3NlIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBpZiB0aGUgd2luZG93IGlzIGdvaW5nIHRvIGJlIGNsb3NlZFxuICAgICAqL1xuICAgIHZhciB0b2dnbGUgPSBmdW5jdGlvbihvYmplY3QsIHNlbGVjdG9yLCBvbk9wZW5Db21wbGV0ZSwgb25PcGVuLCBvbkNsb3NlKSB7XG4gICAgICAgIFVJVXRpbC5idXR0b25DbGljayhidXR0b25zW3NlbGVjdG9yXSwgXCJhY3RpdmVcIik7XG5cbiAgICAgICAgaWYgKG9iamVjdC5pc1Zpc2libGUoKSkge1xuICAgICAgICAgICAgJChcIiN0b2FzdC1jb250YWluZXJcIikuYW5pbWF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHJpZ2h0OiAnNXB4J1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiA1MDBcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICQoc2VsZWN0b3IpLmhpZGUoXCJzbGlkZVwiLCB7XG4gICAgICAgICAgICAgICAgZGlyZWN0aW9uOiBcInJpZ2h0XCIsXG4gICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiA1MDBcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYodHlwZW9mIG9uQ2xvc2UgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgIG9uQ2xvc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY3VycmVudGx5T3BlbiA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBVbmRvY2sgdGhlIHRvb2xiYXIgd2hlbiB0aGUgY2hhdCBpcyBzaG93biBhbmQgaWYgd2UncmUgaW4gYVxuICAgICAgICAgICAgLy8gdmlkZW8gbW9kZS5cbiAgICAgICAgICAgIGlmIChWaWRlb0xheW91dC5pc0xhcmdlVmlkZW9WaXNpYmxlKCkpIHtcbiAgICAgICAgICAgICAgICBUb29sYmFyVG9nZ2xlci5kb2NrVG9vbGJhcihmYWxzZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmKGN1cnJlbnRseU9wZW4pIHtcbiAgICAgICAgICAgICAgICB2YXIgY3VycmVudCA9ICQoY3VycmVudGx5T3Blbik7XG4gICAgICAgICAgICAgICAgVUlVdGlsLmJ1dHRvbkNsaWNrKGJ1dHRvbnNbY3VycmVudGx5T3Blbl0sIFwiYWN0aXZlXCIpO1xuICAgICAgICAgICAgICAgIGN1cnJlbnQuY3NzKCd6LWluZGV4JywgNCk7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY3NzKCdkaXNwbGF5JywgJ25vbmUnKTtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudC5jc3MoJ3otaW5kZXgnLCA1KTtcbiAgICAgICAgICAgICAgICB9LCA1MDApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAkKFwiI3RvYXN0LWNvbnRhaW5lclwiKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICAgICAgcmlnaHQ6IChQYW5lbFRvZ2dsZXIuZ2V0UGFuZWxTaXplKClbMF0gKyA1KSArICdweCdcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAkKHNlbGVjdG9yKS5zaG93KFwic2xpZGVcIiwge1xuICAgICAgICAgICAgICAgIGRpcmVjdGlvbjogXCJyaWdodFwiLFxuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBvbk9wZW5Db21wbGV0ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZih0eXBlb2Ygb25PcGVuID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICBvbk9wZW4oKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY3VycmVudGx5T3BlbiA9IHNlbGVjdG9yO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIE9wZW5zIC8gY2xvc2VzIHRoZSBjaGF0IGFyZWEuXG4gICAgICovXG4gICAgbXkudG9nZ2xlQ2hhdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgY2hhdENvbXBsZXRlRnVuY3Rpb24gPSBDaGF0LmlzVmlzaWJsZSgpID9cbiAgICAgICAgICAgIGZ1bmN0aW9uKCkge30gOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBDaGF0LnNjcm9sbENoYXRUb0JvdHRvbSgpO1xuICAgICAgICAgICAgJCgnI2NoYXRzcGFjZScpLnRyaWdnZXIoJ3Nob3duJyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmVzaXplVmlkZW9BcmVhKENoYXQuaXNWaXNpYmxlKCksIGNoYXRDb21wbGV0ZUZ1bmN0aW9uKTtcblxuICAgICAgICB0b2dnbGUoQ2hhdCxcbiAgICAgICAgICAgICcjY2hhdHNwYWNlJyxcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBSZXF1ZXN0IHRoZSBmb2N1cyBpbiB0aGUgbmlja25hbWUgZmllbGQgb3IgdGhlIGNoYXQgaW5wdXQgZmllbGQuXG4gICAgICAgICAgICAgICAgaWYgKCQoJyNuaWNrbmFtZScpLmNzcygndmlzaWJpbGl0eScpID09PSAndmlzaWJsZScpIHtcbiAgICAgICAgICAgICAgICAgICAgJCgnI25pY2tpbnB1dCcpLmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgJCgnI3VzZXJtc2cnKS5mb2N1cygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgQ2hhdC5yZXNpemVDaGF0LFxuICAgICAgICAgICAgbnVsbCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIE9wZW5zIC8gY2xvc2VzIHRoZSBjb250YWN0IGxpc3QgYXJlYS5cbiAgICAgKi9cbiAgICBteS50b2dnbGVDb250YWN0TGlzdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNvbXBsZXRlRnVuY3Rpb24gPSBDb250YWN0TGlzdC5pc1Zpc2libGUoKSA/XG4gICAgICAgICAgICBmdW5jdGlvbigpIHt9IDogZnVuY3Rpb24gKCkgeyAkKCcjY29udGFjdGxpc3QnKS50cmlnZ2VyKCdzaG93bicpO307XG4gICAgICAgIHJlc2l6ZVZpZGVvQXJlYShDb250YWN0TGlzdC5pc1Zpc2libGUoKSwgY29tcGxldGVGdW5jdGlvbik7XG5cbiAgICAgICAgdG9nZ2xlKENvbnRhY3RMaXN0LFxuICAgICAgICAgICAgJyNjb250YWN0bGlzdCcsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgQ29udGFjdExpc3Quc2V0VmlzdWFsTm90aWZpY2F0aW9uKGZhbHNlKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogT3BlbnMgLyBjbG9zZXMgdGhlIHNldHRpbmdzIG1lbnVcbiAgICAgKi9cbiAgICBteS50b2dnbGVTZXR0aW5nc01lbnUgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmVzaXplVmlkZW9BcmVhKFNldHRpbmdzTWVudS5pc1Zpc2libGUoKSwgZnVuY3Rpb24gKCl7fSk7XG4gICAgICAgIHRvZ2dsZShTZXR0aW5nc01lbnUsXG4gICAgICAgICAgICAnI3NldHRpbmdzbWVudScsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNldHRpbmdzID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbiAgICAgICAgICAgICAgICAkKCcjc2V0RGlzcGxheU5hbWUnKS5nZXQoMCkudmFsdWUgPSBzZXR0aW5ncy5kaXNwbGF5TmFtZTtcbiAgICAgICAgICAgICAgICAkKCcjc2V0RW1haWwnKS5nZXQoMCkudmFsdWUgPSBzZXR0aW5ncy5lbWFpbDtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgc2l6ZSBvZiB0aGUgc2lkZSBwYW5lbC5cbiAgICAgKi9cbiAgICBteS5nZXRQYW5lbFNpemUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhdmFpbGFibGVIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoO1xuXG4gICAgICAgIHZhciBwYW5lbFdpZHRoID0gMjAwO1xuICAgICAgICBpZiAoYXZhaWxhYmxlV2lkdGggKiAwLjIgPCAyMDApIHtcbiAgICAgICAgICAgIHBhbmVsV2lkdGggPSBhdmFpbGFibGVXaWR0aCAqIDAuMjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbcGFuZWxXaWR0aCwgYXZhaWxhYmxlSGVpZ2h0XTtcbiAgICB9O1xuXG4gICAgbXkuaXNWaXNpYmxlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiAoQ2hhdC5pc1Zpc2libGUoKSB8fCBDb250YWN0TGlzdC5pc1Zpc2libGUoKSB8fCBTZXR0aW5nc01lbnUuaXNWaXNpYmxlKCkpO1xuICAgIH07XG5cbiAgICByZXR1cm4gbXk7XG5cbn0oUGFuZWxUb2dnbGVyIHx8IHt9KSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUGFuZWxUb2dnbGVyOyIsIi8qIGdsb2JhbCAkLCBVdGlsLCBuaWNrbmFtZTp0cnVlICovXG52YXIgUmVwbGFjZW1lbnQgPSByZXF1aXJlKFwiLi9SZXBsYWNlbWVudFwiKTtcbnZhciBDb21tYW5kc1Byb2Nlc3NvciA9IHJlcXVpcmUoXCIuL0NvbW1hbmRzXCIpO1xudmFyIFRvb2xiYXJUb2dnbGVyID0gcmVxdWlyZShcIi4uLy4uL3Rvb2xiYXJzL1Rvb2xiYXJUb2dnbGVyXCIpO1xudmFyIHNtaWxleXMgPSByZXF1aXJlKFwiLi9zbWlsZXlzLmpzb25cIikuc21pbGV5cztcbnZhciBOaWNrbmFtZUhhbmRsZXIgPSByZXF1aXJlKFwiLi4vLi4vdXRpbC9OaWNrbmFtZUhhbmRsZXJcIik7XG52YXIgVUlVdGlsID0gcmVxdWlyZShcIi4uLy4uL3V0aWwvVUlVdGlsXCIpO1xudmFyIFVJRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uLy4uLy4uL3NlcnZpY2UvVUkvVUlFdmVudHNcIik7XG5cbnZhciBub3RpZmljYXRpb25JbnRlcnZhbCA9IGZhbHNlO1xudmFyIHVucmVhZE1lc3NhZ2VzID0gMDtcblxuXG4vKipcbiAqIFNob3dzL2hpZGVzIGEgdmlzdWFsIG5vdGlmaWNhdGlvbiwgaW5kaWNhdGluZyB0aGF0IGEgbWVzc2FnZSBoYXMgYXJyaXZlZC5cbiAqL1xuZnVuY3Rpb24gc2V0VmlzdWFsTm90aWZpY2F0aW9uKHNob3cpIHtcbiAgICB2YXIgdW5yZWFkTXNnRWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd1bnJlYWRNZXNzYWdlcycpO1xuICAgIHZhciB1bnJlYWRNc2dCb3R0b21FbGVtZW50XG4gICAgICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JvdHRvbVVucmVhZE1lc3NhZ2VzJyk7XG5cbiAgICB2YXIgZ2xvd2VyID0gJCgnI2NoYXRCdXR0b24nKTtcbiAgICB2YXIgYm90dG9tR2xvd2VyID0gJCgnI2NoYXRCb3R0b21CdXR0b24nKTtcblxuICAgIGlmICh1bnJlYWRNZXNzYWdlcykge1xuICAgICAgICB1bnJlYWRNc2dFbGVtZW50LmlubmVySFRNTCA9IHVucmVhZE1lc3NhZ2VzLnRvU3RyaW5nKCk7XG4gICAgICAgIHVucmVhZE1zZ0JvdHRvbUVsZW1lbnQuaW5uZXJIVE1MID0gdW5yZWFkTWVzc2FnZXMudG9TdHJpbmcoKTtcblxuICAgICAgICBUb29sYmFyVG9nZ2xlci5kb2NrVG9vbGJhcih0cnVlKTtcblxuICAgICAgICB2YXIgY2hhdEJ1dHRvbkVsZW1lbnRcbiAgICAgICAgICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXRCdXR0b24nKS5wYXJlbnROb2RlO1xuICAgICAgICB2YXIgbGVmdEluZGVudCA9IChVSVV0aWwuZ2V0VGV4dFdpZHRoKGNoYXRCdXR0b25FbGVtZW50KSAtXG4gICAgICAgICAgICBVSVV0aWwuZ2V0VGV4dFdpZHRoKHVucmVhZE1zZ0VsZW1lbnQpKSAvIDI7XG4gICAgICAgIHZhciB0b3BJbmRlbnQgPSAoVUlVdGlsLmdldFRleHRIZWlnaHQoY2hhdEJ1dHRvbkVsZW1lbnQpIC1cbiAgICAgICAgICAgIFVJVXRpbC5nZXRUZXh0SGVpZ2h0KHVucmVhZE1zZ0VsZW1lbnQpKSAvIDIgLSAzO1xuXG4gICAgICAgIHVucmVhZE1zZ0VsZW1lbnQuc2V0QXR0cmlidXRlKFxuICAgICAgICAgICAgJ3N0eWxlJyxcbiAgICAgICAgICAgICAgICAndG9wOicgKyB0b3BJbmRlbnQgK1xuICAgICAgICAgICAgICAgICc7IGxlZnQ6JyArIGxlZnRJbmRlbnQgKyAnOycpO1xuXG4gICAgICAgIHZhciBjaGF0Qm90dG9tQnV0dG9uRWxlbWVudFxuICAgICAgICAgICAgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY2hhdEJvdHRvbUJ1dHRvbicpLnBhcmVudE5vZGU7XG4gICAgICAgIHZhciBib3R0b21MZWZ0SW5kZW50ID0gKFVJVXRpbC5nZXRUZXh0V2lkdGgoY2hhdEJvdHRvbUJ1dHRvbkVsZW1lbnQpIC1cbiAgICAgICAgICAgIFVJVXRpbC5nZXRUZXh0V2lkdGgodW5yZWFkTXNnQm90dG9tRWxlbWVudCkpIC8gMjtcbiAgICAgICAgdmFyIGJvdHRvbVRvcEluZGVudCA9IChVSVV0aWwuZ2V0VGV4dEhlaWdodChjaGF0Qm90dG9tQnV0dG9uRWxlbWVudCkgLVxuICAgICAgICAgICAgVUlVdGlsLmdldFRleHRIZWlnaHQodW5yZWFkTXNnQm90dG9tRWxlbWVudCkpIC8gMiAtIDI7XG5cbiAgICAgICAgdW5yZWFkTXNnQm90dG9tRWxlbWVudC5zZXRBdHRyaWJ1dGUoXG4gICAgICAgICAgICAnc3R5bGUnLFxuICAgICAgICAgICAgICAgICd0b3A6JyArIGJvdHRvbVRvcEluZGVudCArXG4gICAgICAgICAgICAgICAgJzsgbGVmdDonICsgYm90dG9tTGVmdEluZGVudCArICc7Jyk7XG5cblxuICAgICAgICBpZiAoIWdsb3dlci5oYXNDbGFzcygnaWNvbi1jaGF0LXNpbXBsZScpKSB7XG4gICAgICAgICAgICBnbG93ZXIucmVtb3ZlQ2xhc3MoJ2ljb24tY2hhdCcpO1xuICAgICAgICAgICAgZ2xvd2VyLmFkZENsYXNzKCdpY29uLWNoYXQtc2ltcGxlJyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHVucmVhZE1zZ0VsZW1lbnQuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIHVucmVhZE1zZ0JvdHRvbUVsZW1lbnQuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIGdsb3dlci5yZW1vdmVDbGFzcygnaWNvbi1jaGF0LXNpbXBsZScpO1xuICAgICAgICBnbG93ZXIuYWRkQ2xhc3MoJ2ljb24tY2hhdCcpO1xuICAgIH1cblxuICAgIGlmIChzaG93ICYmICFub3RpZmljYXRpb25JbnRlcnZhbCkge1xuICAgICAgICBub3RpZmljYXRpb25JbnRlcnZhbCA9IHdpbmRvdy5zZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBnbG93ZXIudG9nZ2xlQ2xhc3MoJ2FjdGl2ZScpO1xuICAgICAgICAgICAgYm90dG9tR2xvd2VyLnRvZ2dsZUNsYXNzKCdhY3RpdmUgZ2xvd2luZycpO1xuICAgICAgICB9LCA4MDApO1xuICAgIH1cbiAgICBlbHNlIGlmICghc2hvdyAmJiBub3RpZmljYXRpb25JbnRlcnZhbCkge1xuICAgICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbChub3RpZmljYXRpb25JbnRlcnZhbCk7XG4gICAgICAgIG5vdGlmaWNhdGlvbkludGVydmFsID0gZmFsc2U7XG4gICAgICAgIGdsb3dlci5yZW1vdmVDbGFzcygnYWN0aXZlJyk7XG4gICAgICAgIGJvdHRvbUdsb3dlci5yZW1vdmVDbGFzcygnZ2xvd2luZycpO1xuICAgICAgICBib3R0b21HbG93ZXIuYWRkQ2xhc3MoJ2FjdGl2ZScpO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGN1cnJlbnQgdGltZSBpbiB0aGUgZm9ybWF0IGl0IGlzIHNob3duIHRvIHRoZSB1c2VyXG4gKiBAcmV0dXJucyB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBnZXRDdXJyZW50VGltZSgpIHtcbiAgICB2YXIgbm93ICAgICA9IG5ldyBEYXRlKCk7XG4gICAgdmFyIGhvdXIgICAgPSBub3cuZ2V0SG91cnMoKTtcbiAgICB2YXIgbWludXRlICA9IG5vdy5nZXRNaW51dGVzKCk7XG4gICAgdmFyIHNlY29uZCAgPSBub3cuZ2V0U2Vjb25kcygpO1xuICAgIGlmKGhvdXIudG9TdHJpbmcoKS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgaG91ciA9ICcwJytob3VyO1xuICAgIH1cbiAgICBpZihtaW51dGUudG9TdHJpbmcoKS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgbWludXRlID0gJzAnK21pbnV0ZTtcbiAgICB9XG4gICAgaWYoc2Vjb25kLnRvU3RyaW5nKCkubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHNlY29uZCA9ICcwJytzZWNvbmQ7XG4gICAgfVxuICAgIHJldHVybiBob3VyKyc6JyttaW51dGUrJzonK3NlY29uZDtcbn1cblxuZnVuY3Rpb24gdG9nZ2xlU21pbGV5cygpXG57XG4gICAgdmFyIHNtaWxleXMgPSAkKCcjc21pbGV5c0NvbnRhaW5lcicpO1xuICAgIGlmKCFzbWlsZXlzLmlzKCc6dmlzaWJsZScpKSB7XG4gICAgICAgIHNtaWxleXMuc2hvdyhcInNsaWRlXCIsIHsgZGlyZWN0aW9uOiBcImRvd25cIiwgZHVyYXRpb246IDMwMH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHNtaWxleXMuaGlkZShcInNsaWRlXCIsIHsgZGlyZWN0aW9uOiBcImRvd25cIiwgZHVyYXRpb246IDMwMH0pO1xuICAgIH1cbiAgICAkKCcjdXNlcm1zZycpLmZvY3VzKCk7XG59XG5cbmZ1bmN0aW9uIGFkZENsaWNrRnVuY3Rpb24oc21pbGV5LCBudW1iZXIpIHtcbiAgICBzbWlsZXkub25jbGljayA9IGZ1bmN0aW9uIGFkZFNtaWxleVRvTWVzc2FnZSgpIHtcbiAgICAgICAgdmFyIHVzZXJtc2cgPSAkKCcjdXNlcm1zZycpO1xuICAgICAgICB2YXIgbWVzc2FnZSA9IHVzZXJtc2cudmFsKCk7XG4gICAgICAgIG1lc3NhZ2UgKz0gc21pbGV5c1snc21pbGV5JyArIG51bWJlcl07XG4gICAgICAgIHVzZXJtc2cudmFsKG1lc3NhZ2UpO1xuICAgICAgICB1c2VybXNnLmdldCgwKS5zZXRTZWxlY3Rpb25SYW5nZShtZXNzYWdlLmxlbmd0aCwgbWVzc2FnZS5sZW5ndGgpO1xuICAgICAgICB0b2dnbGVTbWlsZXlzKCk7XG4gICAgICAgIHVzZXJtc2cuZm9jdXMoKTtcbiAgICB9O1xufVxuXG4vKipcbiAqIEFkZHMgdGhlIHNtaWxleXMgY29udGFpbmVyIHRvIHRoZSBjaGF0XG4gKi9cbmZ1bmN0aW9uIGFkZFNtaWxleXMoKSB7XG4gICAgdmFyIHNtaWxleXNDb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBzbWlsZXlzQ29udGFpbmVyLmlkID0gJ3NtaWxleXNDb250YWluZXInO1xuICAgIGZvcih2YXIgaSA9IDE7IGkgPD0gMjE7IGkrKykge1xuICAgICAgICB2YXIgc21pbGV5Q29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICAgIHNtaWxleUNvbnRhaW5lci5pZCA9ICdzbWlsZXknICsgaTtcbiAgICAgICAgc21pbGV5Q29udGFpbmVyLmNsYXNzTmFtZSA9ICdzbWlsZXlDb250YWluZXInO1xuICAgICAgICB2YXIgc21pbGV5ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW1nJyk7XG4gICAgICAgIHNtaWxleS5zcmMgPSAnaW1hZ2VzL3NtaWxleXMvc21pbGV5JyArIGkgKyAnLnN2Zyc7XG4gICAgICAgIHNtaWxleS5jbGFzc05hbWUgPSAgJ3NtaWxleSc7XG4gICAgICAgIGFkZENsaWNrRnVuY3Rpb24oc21pbGV5LCBpKTtcbiAgICAgICAgc21pbGV5Q29udGFpbmVyLmFwcGVuZENoaWxkKHNtaWxleSk7XG4gICAgICAgIHNtaWxleXNDb250YWluZXIuYXBwZW5kQ2hpbGQoc21pbGV5Q29udGFpbmVyKTtcbiAgICB9XG5cbiAgICAkKFwiI2NoYXRzcGFjZVwiKS5hcHBlbmQoc21pbGV5c0NvbnRhaW5lcik7XG59XG5cbi8qKlxuICogUmVzaXplcyB0aGUgY2hhdCBjb252ZXJzYXRpb24uXG4gKi9cbmZ1bmN0aW9uIHJlc2l6ZUNoYXRDb252ZXJzYXRpb24oKSB7XG4gICAgdmFyIG1zZ2FyZWFIZWlnaHQgPSAkKCcjdXNlcm1zZycpLm91dGVySGVpZ2h0KCk7XG4gICAgdmFyIGNoYXRzcGFjZSA9ICQoJyNjaGF0c3BhY2UnKTtcbiAgICB2YXIgd2lkdGggPSBjaGF0c3BhY2Uud2lkdGgoKTtcbiAgICB2YXIgY2hhdCA9ICQoJyNjaGF0Y29udmVyc2F0aW9uJyk7XG4gICAgdmFyIHNtaWxleXMgPSAkKCcjc21pbGV5c2FyZWEnKTtcblxuICAgIHNtaWxleXMuaGVpZ2h0KG1zZ2FyZWFIZWlnaHQpO1xuICAgICQoXCIjc21pbGV5c1wiKS5jc3MoJ2JvdHRvbScsIChtc2dhcmVhSGVpZ2h0IC0gMjYpIC8gMik7XG4gICAgJCgnI3NtaWxleXNDb250YWluZXInKS5jc3MoJ2JvdHRvbScsIG1zZ2FyZWFIZWlnaHQpO1xuICAgIGNoYXQud2lkdGgod2lkdGggLSAxMCk7XG4gICAgY2hhdC5oZWlnaHQod2luZG93LmlubmVySGVpZ2h0IC0gMTUgLSBtc2dhcmVhSGVpZ2h0KTtcbn1cblxuLyoqXG4gKiBDaGF0IHJlbGF0ZWQgdXNlciBpbnRlcmZhY2UuXG4gKi9cbnZhciBDaGF0ID0gKGZ1bmN0aW9uIChteSkge1xuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemVzIGNoYXQgcmVsYXRlZCBpbnRlcmZhY2UuXG4gICAgICovXG4gICAgbXkuaW5pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYoTmlja25hbWVIYW5kbGVyLmdldE5pY2tuYW1lKCkpXG4gICAgICAgICAgICBDaGF0LnNldENoYXRDb252ZXJzYXRpb25Nb2RlKHRydWUpO1xuICAgICAgICBOaWNrbmFtZUhhbmRsZXIuYWRkTGlzdGVuZXIoVUlFdmVudHMuTklDS05BTUVfQ0hBTkdFRCxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChuaWNrbmFtZSkge1xuICAgICAgICAgICAgICAgIENoYXQuc2V0Q2hhdENvbnZlcnNhdGlvbk1vZGUodHJ1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAkKCcjbmlja2lucHV0Jykua2V5ZG93bihmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5rZXlDb2RlID09PSAxMykge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdmFyIHZhbCA9IFVJVXRpbC5lc2NhcGVIdG1sKHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWUgPSAnJztcbiAgICAgICAgICAgICAgICBpZiAoIU5pY2tuYW1lSGFuZGxlci5nZXROaWNrbmFtZSgpKSB7XG4gICAgICAgICAgICAgICAgICAgIE5pY2tuYW1lSGFuZGxlci5zZXROaWNrbmFtZSh2YWwpO1xuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgICQoJyN1c2VybXNnJykua2V5ZG93bihmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5rZXlDb2RlID09PSAxMykge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gdGhpcy52YWx1ZTtcbiAgICAgICAgICAgICAgICAkKCcjdXNlcm1zZycpLnZhbCgnJykudHJpZ2dlcignYXV0b3NpemUucmVzaXplJyk7XG4gICAgICAgICAgICAgICAgdGhpcy5mb2N1cygpO1xuICAgICAgICAgICAgICAgIHZhciBjb21tYW5kID0gbmV3IENvbW1hbmRzUHJvY2Vzc29yKHZhbHVlKTtcbiAgICAgICAgICAgICAgICBpZihjb21tYW5kLmlzQ29tbWFuZCgpKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgY29tbWFuZC5wcm9jZXNzQ29tbWFuZCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB2YXIgbWVzc2FnZSA9IFVJVXRpbC5lc2NhcGVIdG1sKHZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAuc2VuZENoYXRNZXNzYWdlKG1lc3NhZ2UsIE5pY2tuYW1lSGFuZGxlci5nZXROaWNrbmFtZSgpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHZhciBvblRleHRBcmVhUmVzaXplID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmVzaXplQ2hhdENvbnZlcnNhdGlvbigpO1xuICAgICAgICAgICAgQ2hhdC5zY3JvbGxDaGF0VG9Cb3R0b20oKTtcbiAgICAgICAgfTtcbiAgICAgICAgJCgnI3VzZXJtc2cnKS5hdXRvc2l6ZSh7Y2FsbGJhY2s6IG9uVGV4dEFyZWFSZXNpemV9KTtcblxuICAgICAgICAkKFwiI2NoYXRzcGFjZVwiKS5iaW5kKFwic2hvd25cIixcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB1bnJlYWRNZXNzYWdlcyA9IDA7XG4gICAgICAgICAgICAgICAgc2V0VmlzdWFsTm90aWZpY2F0aW9uKGZhbHNlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIGFkZFNtaWxleXMoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQXBwZW5kcyB0aGUgZ2l2ZW4gbWVzc2FnZSB0byB0aGUgY2hhdCBjb252ZXJzYXRpb24uXG4gICAgICovXG4gICAgbXkudXBkYXRlQ2hhdENvbnZlcnNhdGlvbiA9IGZ1bmN0aW9uIChmcm9tLCBkaXNwbGF5TmFtZSwgbWVzc2FnZSkge1xuICAgICAgICB2YXIgZGl2Q2xhc3NOYW1lID0gJyc7XG5cbiAgICAgICAgaWYgKEFQUC54bXBwLm15SmlkKCkgPT09IGZyb20pIHtcbiAgICAgICAgICAgIGRpdkNsYXNzTmFtZSA9IFwibG9jYWx1c2VyXCI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBkaXZDbGFzc05hbWUgPSBcInJlbW90ZXVzZXJcIjtcblxuICAgICAgICAgICAgaWYgKCFDaGF0LmlzVmlzaWJsZSgpKSB7XG4gICAgICAgICAgICAgICAgdW5yZWFkTWVzc2FnZXMrKztcbiAgICAgICAgICAgICAgICBVSVV0aWwucGxheVNvdW5kTm90aWZpY2F0aW9uKCdjaGF0Tm90aWZpY2F0aW9uJyk7XG4gICAgICAgICAgICAgICAgc2V0VmlzdWFsTm90aWZpY2F0aW9uKHRydWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gcmVwbGFjZSBsaW5rcyBhbmQgc21pbGV5c1xuICAgICAgICAvLyBTdHJvcGhlIGFscmVhZHkgZXNjYXBlcyBzcGVjaWFsIHN5bWJvbHMgb24gc2VuZGluZyxcbiAgICAgICAgLy8gc28gd2UgZXNjYXBlIGhlcmUgb25seSB0YWdzIHRvIGF2b2lkIGRvdWJsZSAmYW1wO1xuICAgICAgICB2YXIgZXNjTWVzc2FnZSA9IG1lc3NhZ2UucmVwbGFjZSgvPC9nLCAnJmx0OycpLlxuICAgICAgICAgICAgcmVwbGFjZSgvPi9nLCAnJmd0OycpLnJlcGxhY2UoL1xcbi9nLCAnPGJyLz4nKTtcbiAgICAgICAgdmFyIGVzY0Rpc3BsYXlOYW1lID0gVUlVdGlsLmVzY2FwZUh0bWwoZGlzcGxheU5hbWUpO1xuICAgICAgICBtZXNzYWdlID0gUmVwbGFjZW1lbnQucHJvY2Vzc1JlcGxhY2VtZW50cyhlc2NNZXNzYWdlKTtcblxuICAgICAgICB2YXIgbWVzc2FnZUNvbnRhaW5lciA9XG4gICAgICAgICAgICAnPGRpdiBjbGFzcz1cImNoYXRtZXNzYWdlXCI+JytcbiAgICAgICAgICAgICAgICAnPGltZyBzcmM9XCIuLi9pbWFnZXMvY2hhdEFycm93LnN2Z1wiIGNsYXNzPVwiY2hhdEFycm93XCI+JyArXG4gICAgICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJ1c2VybmFtZSAnICsgZGl2Q2xhc3NOYW1lICsnXCI+JyArIGVzY0Rpc3BsYXlOYW1lICtcbiAgICAgICAgICAgICAgICAnPC9kaXY+JyArICc8ZGl2IGNsYXNzPVwidGltZXN0YW1wXCI+JyArIGdldEN1cnJlbnRUaW1lKCkgK1xuICAgICAgICAgICAgICAgICc8L2Rpdj4nICsgJzxkaXYgY2xhc3M9XCJ1c2VybWVzc2FnZVwiPicgKyBtZXNzYWdlICsgJzwvZGl2PicgK1xuICAgICAgICAgICAgJzwvZGl2Pic7XG5cbiAgICAgICAgJCgnI2NoYXRjb252ZXJzYXRpb24nKS5hcHBlbmQobWVzc2FnZUNvbnRhaW5lcik7XG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYW5pbWF0ZShcbiAgICAgICAgICAgICAgICB7IHNjcm9sbFRvcDogJCgnI2NoYXRjb252ZXJzYXRpb24nKVswXS5zY3JvbGxIZWlnaHR9LCAxMDAwKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQXBwZW5kcyBlcnJvciBtZXNzYWdlIHRvIHRoZSBjb252ZXJzYXRpb25cbiAgICAgKiBAcGFyYW0gZXJyb3JNZXNzYWdlIHRoZSByZWNlaXZlZCBlcnJvciBtZXNzYWdlLlxuICAgICAqIEBwYXJhbSBvcmlnaW5hbFRleHQgdGhlIG9yaWdpbmFsIG1lc3NhZ2UuXG4gICAgICovXG4gICAgbXkuY2hhdEFkZEVycm9yID0gZnVuY3Rpb24oZXJyb3JNZXNzYWdlLCBvcmlnaW5hbFRleHQpXG4gICAge1xuICAgICAgICBlcnJvck1lc3NhZ2UgPSBVSVV0aWwuZXNjYXBlSHRtbChlcnJvck1lc3NhZ2UpO1xuICAgICAgICBvcmlnaW5hbFRleHQgPSBVSVV0aWwuZXNjYXBlSHRtbChvcmlnaW5hbFRleHQpO1xuXG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYXBwZW5kKFxuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJlcnJvck1lc3NhZ2VcIj48Yj5FcnJvcjogPC9iPicgKyAnWW91ciBtZXNzYWdlJyArXG4gICAgICAgICAgICAob3JpZ2luYWxUZXh0PyAoJyBcXFwiJysgb3JpZ2luYWxUZXh0ICsgJ1xcXCInKSA6IFwiXCIpICtcbiAgICAgICAgICAgICcgd2FzIG5vdCBzZW50LicgK1xuICAgICAgICAgICAgKGVycm9yTWVzc2FnZT8gKCcgUmVhc29uOiAnICsgZXJyb3JNZXNzYWdlKSA6ICcnKSArICAnPC9kaXY+Jyk7XG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYW5pbWF0ZShcbiAgICAgICAgICAgIHsgc2Nyb2xsVG9wOiAkKCcjY2hhdGNvbnZlcnNhdGlvbicpWzBdLnNjcm9sbEhlaWdodH0sIDEwMDApO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdWJqZWN0IHRvIHRoZSBVSVxuICAgICAqIEBwYXJhbSBzdWJqZWN0IHRoZSBzdWJqZWN0XG4gICAgICovXG4gICAgbXkuY2hhdFNldFN1YmplY3QgPSBmdW5jdGlvbihzdWJqZWN0KVxuICAgIHtcbiAgICAgICAgaWYoc3ViamVjdClcbiAgICAgICAgICAgIHN1YmplY3QgPSBzdWJqZWN0LnRyaW0oKTtcbiAgICAgICAgJCgnI3N1YmplY3QnKS5odG1sKFJlcGxhY2VtZW50LmxpbmtpZnkoVUlVdGlsLmVzY2FwZUh0bWwoc3ViamVjdCkpKTtcbiAgICAgICAgaWYoc3ViamVjdCA9PT0gXCJcIilcbiAgICAgICAge1xuICAgICAgICAgICAgJChcIiNzdWJqZWN0XCIpLmNzcyh7ZGlzcGxheTogXCJub25lXCJ9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgICQoXCIjc3ViamVjdFwiKS5jc3Moe2Rpc3BsYXk6IFwiYmxvY2tcIn0pO1xuICAgICAgICB9XG4gICAgfTtcblxuXG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBjaGF0IGNvbnZlcnNhdGlvbiBtb2RlLlxuICAgICAqL1xuICAgIG15LnNldENoYXRDb252ZXJzYXRpb25Nb2RlID0gZnVuY3Rpb24gKGlzQ29udmVyc2F0aW9uTW9kZSkge1xuICAgICAgICBpZiAoaXNDb252ZXJzYXRpb25Nb2RlKSB7XG4gICAgICAgICAgICAkKCcjbmlja25hbWUnKS5jc3Moe3Zpc2liaWxpdHk6ICdoaWRkZW4nfSk7XG4gICAgICAgICAgICAkKCcjY2hhdGNvbnZlcnNhdGlvbicpLmNzcyh7dmlzaWJpbGl0eTogJ3Zpc2libGUnfSk7XG4gICAgICAgICAgICAkKCcjdXNlcm1zZycpLmNzcyh7dmlzaWJpbGl0eTogJ3Zpc2libGUnfSk7XG4gICAgICAgICAgICAkKCcjc21pbGV5c2FyZWEnKS5jc3Moe3Zpc2liaWxpdHk6ICd2aXNpYmxlJ30pO1xuICAgICAgICAgICAgJCgnI3VzZXJtc2cnKS5mb2N1cygpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGhlIGNoYXQgYXJlYS5cbiAgICAgKi9cbiAgICBteS5yZXNpemVDaGF0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgY2hhdFNpemUgPSByZXF1aXJlKFwiLi4vU2lkZVBhbmVsVG9nZ2xlclwiKS5nZXRQYW5lbFNpemUoKTtcblxuICAgICAgICAkKCcjY2hhdHNwYWNlJykud2lkdGgoY2hhdFNpemVbMF0pO1xuICAgICAgICAkKCcjY2hhdHNwYWNlJykuaGVpZ2h0KGNoYXRTaXplWzFdKTtcblxuICAgICAgICByZXNpemVDaGF0Q29udmVyc2F0aW9uKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEluZGljYXRlcyBpZiB0aGUgY2hhdCBpcyBjdXJyZW50bHkgdmlzaWJsZS5cbiAgICAgKi9cbiAgICBteS5pc1Zpc2libGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAkKCcjY2hhdHNwYWNlJykuaXMoXCI6dmlzaWJsZVwiKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFNob3dzIGFuZCBoaWRlcyB0aGUgd2luZG93IHdpdGggdGhlIHNtaWxleXNcbiAgICAgKi9cbiAgICBteS50b2dnbGVTbWlsZXlzID0gdG9nZ2xlU21pbGV5cztcblxuICAgIC8qKlxuICAgICAqIFNjcm9sbHMgY2hhdCB0byB0aGUgYm90dG9tLlxuICAgICAqL1xuICAgIG15LnNjcm9sbENoYXRUb0JvdHRvbSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuc2Nyb2xsVG9wKFxuICAgICAgICAgICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJylbMF0uc2Nyb2xsSGVpZ2h0KTtcbiAgICAgICAgfSwgNSk7XG4gICAgfTtcblxuXG4gICAgcmV0dXJuIG15O1xufShDaGF0IHx8IHt9KSk7XG5tb2R1bGUuZXhwb3J0cyA9IENoYXQ7IiwidmFyIFVJVXRpbCA9IHJlcXVpcmUoXCIuLi8uLi91dGlsL1VJVXRpbFwiKTtcblxuLyoqXG4gKiBMaXN0IHdpdGggc3VwcG9ydGVkIGNvbW1hbmRzLiBUaGUga2V5cyBhcmUgdGhlIG5hbWVzIG9mIHRoZSBjb21tYW5kcyBhbmRcbiAqIHRoZSB2YWx1ZSBpcyB0aGUgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgdGhlIG1lc3NhZ2UuXG4gKiBAdHlwZSB7e1N0cmluZzogZnVuY3Rpb259fVxuICovXG52YXIgY29tbWFuZHMgPSB7XG4gICAgXCJ0b3BpY1wiIDogcHJvY2Vzc1RvcGljXG59O1xuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSBjb21tYW5kIGZyb20gdGhlIG1lc3NhZ2UuXG4gKiBAcGFyYW0gbWVzc2FnZSB0aGUgcmVjZWl2ZWQgbWVzc2FnZVxuICogQHJldHVybnMge3N0cmluZ30gdGhlIGNvbW1hbmRcbiAqL1xuZnVuY3Rpb24gZ2V0Q29tbWFuZChtZXNzYWdlKVxue1xuICAgIGlmKG1lc3NhZ2UpXG4gICAge1xuICAgICAgICBmb3IodmFyIGNvbW1hbmQgaW4gY29tbWFuZHMpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGlmKG1lc3NhZ2UuaW5kZXhPZihcIi9cIiArIGNvbW1hbmQpID09IDApXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbW1hbmQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFwiXCI7XG59O1xuXG4vKipcbiAqIFByb2Nlc3NlcyB0aGUgZGF0YSBmb3IgdG9waWMgY29tbWFuZC5cbiAqIEBwYXJhbSBjb21tYW5kQXJndW1lbnRzIHRoZSBhcmd1bWVudHMgb2YgdGhlIHRvcGljIGNvbW1hbmQuXG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NUb3BpYyhjb21tYW5kQXJndW1lbnRzKVxue1xuICAgIHZhciB0b3BpYyA9IFVJVXRpbC5lc2NhcGVIdG1sKGNvbW1hbmRBcmd1bWVudHMpO1xuICAgIEFQUC54bXBwLnNldFN1YmplY3QodG9waWMpO1xufVxuXG4vKipcbiAqIENvbnN0cnVjdHMgbmV3IENvbW1hbmRQcm9jY2Vzc29yIGluc3RhbmNlIGZyb20gYSBtZXNzYWdlIHRoYXRcbiAqIGhhbmRsZXMgY29tbWFuZHMgcmVjZWl2ZWQgdmlhIGNoYXQgbWVzc2FnZXMuXG4gKiBAcGFyYW0gbWVzc2FnZSB0aGUgbWVzc2FnZVxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIENvbW1hbmRzUHJvY2Vzc29yKG1lc3NhZ2UpXG57XG5cblxuICAgIHZhciBjb21tYW5kID0gZ2V0Q29tbWFuZChtZXNzYWdlKTtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhlIGNvbW1hbmQuXG4gICAgICogQHJldHVybnMge1N0cmluZ30gdGhlIGNvbW1hbmRcbiAgICAgKi9cbiAgICB0aGlzLmdldENvbW1hbmQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICByZXR1cm4gY29tbWFuZDtcbiAgICB9O1xuXG5cbiAgICB2YXIgbWVzc2FnZUFyZ3VtZW50ID0gbWVzc2FnZS5zdWJzdHIoY29tbWFuZC5sZW5ndGggKyAyKTtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGFyZ3VtZW50cyBvZiB0aGUgY29tbWFuZC5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgICAqL1xuICAgIHRoaXMuZ2V0QXJndW1lbnQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICByZXR1cm4gbWVzc2FnZUFyZ3VtZW50O1xuICAgIH07XG59XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhpcyBpbnN0YW5jZSBpcyB2YWxpZCBjb21tYW5kIG9yIG5vdC5cbiAqIEByZXR1cm5zIHtib29sZWFufVxuICovXG5Db21tYW5kc1Byb2Nlc3Nvci5wcm90b3R5cGUuaXNDb21tYW5kID0gZnVuY3Rpb24oKVxue1xuICAgIGlmKHRoaXMuZ2V0Q29tbWFuZCgpKVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gZmFsc2U7XG59O1xuXG4vKipcbiAqIFByb2Nlc3NlcyB0aGUgY29tbWFuZC5cbiAqL1xuQ29tbWFuZHNQcm9jZXNzb3IucHJvdG90eXBlLnByb2Nlc3NDb21tYW5kID0gZnVuY3Rpb24oKVxue1xuICAgIGlmKCF0aGlzLmlzQ29tbWFuZCgpKVxuICAgICAgICByZXR1cm47XG5cbiAgICBjb21tYW5kc1t0aGlzLmdldENvbW1hbmQoKV0odGhpcy5nZXRBcmd1bWVudCgpKTtcblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb21tYW5kc1Byb2Nlc3NvcjsiLCJ2YXIgU21pbGV5cyA9IHJlcXVpcmUoXCIuL3NtaWxleXMuanNvblwiKTtcbi8qKlxuICogUHJvY2Vzc2VzIGxpbmtzIGFuZCBzbWlsZXlzIGluIFwiYm9keVwiXG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NSZXBsYWNlbWVudHMoYm9keSlcbntcbiAgICAvL21ha2UgbGlua3MgY2xpY2thYmxlXG4gICAgYm9keSA9IGxpbmtpZnkoYm9keSk7XG5cbiAgICAvL2FkZCBzbWlsZXlzXG4gICAgYm9keSA9IHNtaWxpZnkoYm9keSk7XG5cbiAgICByZXR1cm4gYm9keTtcbn1cblxuLyoqXG4gKiBGaW5kcyBhbmQgcmVwbGFjZXMgYWxsIGxpbmtzIGluIHRoZSBsaW5rcyBpbiBcImJvZHlcIlxuICogd2l0aCB0aGVpciA8YSBocmVmPVwiXCI+PC9hPlxuICovXG5mdW5jdGlvbiBsaW5raWZ5KGlucHV0VGV4dClcbntcbiAgICB2YXIgcmVwbGFjZWRUZXh0LCByZXBsYWNlUGF0dGVybjEsIHJlcGxhY2VQYXR0ZXJuMiwgcmVwbGFjZVBhdHRlcm4zO1xuXG4gICAgLy9VUkxzIHN0YXJ0aW5nIHdpdGggaHR0cDovLywgaHR0cHM6Ly8sIG9yIGZ0cDovL1xuICAgIHJlcGxhY2VQYXR0ZXJuMSA9IC8oXFxiKGh0dHBzP3xmdHApOlxcL1xcL1stQS1aMC05KyZAI1xcLyU/PX5ffCE6LC47XSpbLUEtWjAtOSsmQCNcXC8lPX5ffF0pL2dpbTtcbiAgICByZXBsYWNlZFRleHQgPSBpbnB1dFRleHQucmVwbGFjZShyZXBsYWNlUGF0dGVybjEsICc8YSBocmVmPVwiJDFcIiB0YXJnZXQ9XCJfYmxhbmtcIj4kMTwvYT4nKTtcblxuICAgIC8vVVJMcyBzdGFydGluZyB3aXRoIFwid3d3LlwiICh3aXRob3V0IC8vIGJlZm9yZSBpdCwgb3IgaXQnZCByZS1saW5rIHRoZSBvbmVzIGRvbmUgYWJvdmUpLlxuICAgIHJlcGxhY2VQYXR0ZXJuMiA9IC8oXnxbXlxcL10pKHd3d1xcLltcXFNdKyhcXGJ8JCkpL2dpbTtcbiAgICByZXBsYWNlZFRleHQgPSByZXBsYWNlZFRleHQucmVwbGFjZShyZXBsYWNlUGF0dGVybjIsICckMTxhIGhyZWY9XCJodHRwOi8vJDJcIiB0YXJnZXQ9XCJfYmxhbmtcIj4kMjwvYT4nKTtcblxuICAgIC8vQ2hhbmdlIGVtYWlsIGFkZHJlc3NlcyB0byBtYWlsdG86OiBsaW5rcy5cbiAgICByZXBsYWNlUGF0dGVybjMgPSAvKChbYS16QS1aMC05XFwtXFxfXFwuXSkrQFthLXpBLVpcXF9dKz8oXFwuW2EtekEtWl17Miw2fSkrKS9naW07XG4gICAgcmVwbGFjZWRUZXh0ID0gcmVwbGFjZWRUZXh0LnJlcGxhY2UocmVwbGFjZVBhdHRlcm4zLCAnPGEgaHJlZj1cIm1haWx0bzokMVwiPiQxPC9hPicpO1xuXG4gICAgcmV0dXJuIHJlcGxhY2VkVGV4dDtcbn1cblxuLyoqXG4gKiBSZXBsYWNlcyBjb21tb24gc21pbGV5IHN0cmluZ3Mgd2l0aCBpbWFnZXNcbiAqL1xuZnVuY3Rpb24gc21pbGlmeShib2R5KVxue1xuICAgIGlmKCFib2R5KSB7XG4gICAgICAgIHJldHVybiBib2R5O1xuICAgIH1cblxuICAgIHZhciByZWdleHMgPSBTbWlsZXlzW1wicmVnZXhzXCJdO1xuICAgIGZvcih2YXIgc21pbGV5IGluIHJlZ2V4cykge1xuICAgICAgICBpZihyZWdleHMuaGFzT3duUHJvcGVydHkoc21pbGV5KSkge1xuICAgICAgICAgICAgYm9keSA9IGJvZHkucmVwbGFjZShyZWdleHNbc21pbGV5XSxcbiAgICAgICAgICAgICAgICAgICAgJzxpbWcgY2xhc3M9XCJzbWlsZXlcIiBzcmM9XCJpbWFnZXMvc21pbGV5cy8nICsgc21pbGV5ICsgJy5zdmdcIj4nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBib2R5O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBwcm9jZXNzUmVwbGFjZW1lbnRzOiBwcm9jZXNzUmVwbGFjZW1lbnRzLFxuICAgIGxpbmtpZnk6IGxpbmtpZnlcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJzbWlsZXlzXCI6IHtcbiAgICAgICAgXCJzbWlsZXkxXCI6IFwiOilcIixcbiAgICAgICAgXCJzbWlsZXkyXCI6IFwiOihcIixcbiAgICAgICAgXCJzbWlsZXkzXCI6IFwiOkRcIixcbiAgICAgICAgXCJzbWlsZXk0XCI6IFwiKHkpXCIsXG4gICAgICAgIFwic21pbGV5NVwiOiBcIiA6UFwiLFxuICAgICAgICBcInNtaWxleTZcIjogXCIod2F2ZSlcIixcbiAgICAgICAgXCJzbWlsZXk3XCI6IFwiKGJsdXNoKVwiLFxuICAgICAgICBcInNtaWxleThcIjogXCIoY2h1Y2tsZSlcIixcbiAgICAgICAgXCJzbWlsZXk5XCI6IFwiKHNob2NrZWQpXCIsXG4gICAgICAgIFwic21pbGV5MTBcIjogXCI6KlwiLFxuICAgICAgICBcInNtaWxleTExXCI6IFwiKG4pXCIsXG4gICAgICAgIFwic21pbGV5MTJcIjogXCIoc2VhcmNoKVwiLFxuICAgICAgICBcInNtaWxleTEzXCI6IFwiIDwzXCIsXG4gICAgICAgIFwic21pbGV5MTRcIjogXCIob29wcylcIixcbiAgICAgICAgXCJzbWlsZXkxNVwiOiBcIihhbmdyeSlcIixcbiAgICAgICAgXCJzbWlsZXkxNlwiOiBcIihhbmdlbClcIixcbiAgICAgICAgXCJzbWlsZXkxN1wiOiBcIihzaWNrKVwiLFxuICAgICAgICBcInNtaWxleTE4XCI6IFwiOyhcIixcbiAgICAgICAgXCJzbWlsZXkxOVwiOiBcIihib21iKVwiLFxuICAgICAgICBcInNtaWxleTIwXCI6IFwiKGNsYXApXCIsXG4gICAgICAgIFwic21pbGV5MjFcIjogXCIgOylcIlxuICAgIH0sXG4gICAgXCJyZWdleHNcIjoge1xuICAgICAgICBcInNtaWxleTJcIjogLyg6LVxcKFxcKHw6LVxcKHw6XFwoXFwofDpcXCh8XFwoc2FkXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkzXCI6IC8oOi1cXClcXCl8OlxcKVxcKXxcXChsb2xcXCl8Oi1EfDpEKS9naSxcbiAgICAgICAgXCJzbWlsZXkxXCI6IC8oOi1cXCl8OlxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5NFwiOiAvKFxcKHlcXCl8XFwoWVxcKXxcXChva1xcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5NVwiOiAvKDotUHw6UHw6LXB8OnApL2dpLFxuICAgICAgICBcInNtaWxleTZcIjogLyhcXCh3YXZlXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXk3XCI6IC8oXFwoYmx1c2hcXCkpL2dpLFxuICAgICAgICBcInNtaWxleThcIjogLyhcXChjaHVja2xlXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXk5XCI6IC8oOi0wfFxcKHNob2NrZWRcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTEwXCI6IC8oOi1cXCp8OlxcKnxcXChraXNzXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkxMVwiOiAvKFxcKG5cXCkpL2dpLFxuICAgICAgICBcInNtaWxleTEyXCI6IC8oXFwoc2VhcmNoXFwpKS9nLFxuICAgICAgICBcInNtaWxleTEzXCI6IC8oPDN8Jmx0OzN8JmFtcDtsdDszfFxcKExcXCl8XFwobFxcKXxcXChIXFwpfFxcKGhcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTE0XCI6IC8oXFwob29wc1xcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTVcIjogLyhcXChhbmdyeVxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTZcIjogLyhcXChhbmdlbFxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTdcIjogLyhcXChzaWNrXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkxOFwiOiAvKDstXFwoXFwofDtcXChcXCh8Oy1cXCh8O1xcKHw6XCJcXCh8OlwiLVxcKHw6fi1cXCh8On5cXCh8XFwodXBzZXRcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTE5XCI6IC8oXFwoYm9tYlxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MjBcIjogLyhcXChjbGFwXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkyMVwiOiAvKDstXFwpfDtcXCl8Oy1cXClcXCl8O1xcKVxcKXw7LUR8O0R8XFwod2lua1xcKSkvZ2lcbiAgICB9XG59XG4iLCJcbnZhciBudW1iZXJPZkNvbnRhY3RzID0gMDtcbnZhciBub3RpZmljYXRpb25JbnRlcnZhbDtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBudW1iZXIgb2YgcGFydGljaXBhbnRzIGluIHRoZSBjb250YWN0IGxpc3QgYnV0dG9uIGFuZCBzZXRzXG4gKiB0aGUgZ2xvd1xuICogQHBhcmFtIGRlbHRhIGluZGljYXRlcyB3aGV0aGVyIGEgbmV3IHVzZXIgaGFzIGpvaW5lZCAoMSkgb3Igc29tZW9uZSBoYXNcbiAqIGxlZnQoLTEpXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZU51bWJlck9mUGFydGljaXBhbnRzKGRlbHRhKSB7XG4gICAgLy93aGVuIHRoZSB1c2VyIGlzIGFsb25lIHdlIGRvbid0IHNob3cgdGhlIG51bWJlciBvZiBwYXJ0aWNpcGFudHNcbiAgICBpZihudW1iZXJPZkNvbnRhY3RzID09PSAwKSB7XG4gICAgICAgICQoXCIjbnVtYmVyT2ZQYXJ0aWNpcGFudHNcIikudGV4dCgnJyk7XG4gICAgICAgIG51bWJlck9mQ29udGFjdHMgKz0gZGVsdGE7XG4gICAgfSBlbHNlIGlmKG51bWJlck9mQ29udGFjdHMgIT09IDAgJiYgIUNvbnRhY3RMaXN0LmlzVmlzaWJsZSgpKSB7XG4gICAgICAgIENvbnRhY3RMaXN0LnNldFZpc3VhbE5vdGlmaWNhdGlvbih0cnVlKTtcbiAgICAgICAgbnVtYmVyT2ZDb250YWN0cyArPSBkZWx0YTtcbiAgICAgICAgJChcIiNudW1iZXJPZlBhcnRpY2lwYW50c1wiKS50ZXh0KG51bWJlck9mQ29udGFjdHMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBhdmF0YXIgZWxlbWVudC5cbiAqXG4gKiBAcmV0dXJuIHRoZSBuZXdseSBjcmVhdGVkIGF2YXRhciBlbGVtZW50XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUF2YXRhcihpZCkge1xuICAgIHZhciBhdmF0YXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcbiAgICBhdmF0YXIuY2xhc3NOYW1lID0gXCJpY29uLWF2YXRhciBhdmF0YXJcIjtcbiAgICBhdmF0YXIuc3JjID0gXCJodHRwczovL3d3dy5ncmF2YXRhci5jb20vYXZhdGFyL1wiICsgaWQgKyBcIj9kPXdhdmF0YXImc2l6ZT0zMFwiO1xuXG4gICAgcmV0dXJuIGF2YXRhcjtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBkaXNwbGF5IG5hbWUgcGFyYWdyYXBoLlxuICpcbiAqIEBwYXJhbSBkaXNwbGF5TmFtZSB0aGUgZGlzcGxheSBuYW1lIHRvIHNldFxuICovXG5mdW5jdGlvbiBjcmVhdGVEaXNwbGF5TmFtZVBhcmFncmFwaChrZXksIGRpc3BsYXlOYW1lKSB7XG4gICAgdmFyIHAgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdwJyk7XG4gICAgaWYoZGlzcGxheU5hbWUpXG4gICAgICAgIHAuaW5uZXJUZXh0ID0gZGlzcGxheU5hbWU7XG4gICAgZWxzZSBpZihrZXkpXG4gICAge1xuICAgICAgICBwLnNldEF0dHJpYnV0ZShcImRhdGEtaTE4blwiLGtleSk7XG4gICAgICAgIHAuaW5uZXJUZXh0ID0gQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhrZXkpO1xuICAgIH1cblxuICAgIHJldHVybiBwO1xufVxuXG5cbmZ1bmN0aW9uIHN0b3BHbG93aW5nKGdsb3dlcikge1xuICAgIHdpbmRvdy5jbGVhckludGVydmFsKG5vdGlmaWNhdGlvbkludGVydmFsKTtcbiAgICBub3RpZmljYXRpb25JbnRlcnZhbCA9IGZhbHNlO1xuICAgIGdsb3dlci5yZW1vdmVDbGFzcygnZ2xvd2luZycpO1xuICAgIGlmICghQ29udGFjdExpc3QuaXNWaXNpYmxlKCkpIHtcbiAgICAgICAgZ2xvd2VyLnJlbW92ZUNsYXNzKCdhY3RpdmUnKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBDb250YWN0IGxpc3QuXG4gKi9cbnZhciBDb250YWN0TGlzdCA9IHtcbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGNoYXQgaXMgY3VycmVudGx5IHZpc2libGUuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIDx0dD50cnVlPC90dD4gaWYgdGhlIGNoYXQgaXMgY3VycmVudGx5IHZpc2libGUsIDx0dD5mYWxzZTwvdHQ+IC1cbiAgICAgKiBvdGhlcndpc2VcbiAgICAgKi9cbiAgICBpc1Zpc2libGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuICQoJyNjb250YWN0bGlzdCcpLmlzKFwiOnZpc2libGVcIik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEFkZHMgYSBjb250YWN0IGZvciB0aGUgZ2l2ZW4gcGVlckppZCBpZiBzdWNoIGRvZXNuJ3QgeWV0IGV4aXN0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHBlZXJKaWQgdGhlIHBlZXJKaWQgY29ycmVzcG9uZGluZyB0byB0aGUgY29udGFjdFxuICAgICAqIEBwYXJhbSBpZCB0aGUgdXNlcidzIGVtYWlsIG9yIHVzZXJJZCB1c2VkIHRvIGdldCB0aGUgdXNlcidzIGF2YXRhclxuICAgICAqL1xuICAgIGVuc3VyZUFkZENvbnRhY3Q6IGZ1bmN0aW9uIChwZWVySmlkLCBpZCkge1xuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChwZWVySmlkKTtcblxuICAgICAgICB2YXIgY29udGFjdCA9ICQoJyNjb250YWN0bGlzdD51bD5saVtpZD1cIicgKyByZXNvdXJjZUppZCArICdcIl0nKTtcblxuICAgICAgICBpZiAoIWNvbnRhY3QgfHwgY29udGFjdC5sZW5ndGggPD0gMClcbiAgICAgICAgICAgIENvbnRhY3RMaXN0LmFkZENvbnRhY3QocGVlckppZCwgaWQpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBZGRzIGEgY29udGFjdCBmb3IgdGhlIGdpdmVuIHBlZXIgamlkLlxuICAgICAqXG4gICAgICogQHBhcmFtIHBlZXJKaWQgdGhlIGppZCBvZiB0aGUgY29udGFjdCB0byBhZGRcbiAgICAgKiBAcGFyYW0gaWQgdGhlIGVtYWlsIG9yIHVzZXJJZCBvZiB0aGUgdXNlclxuICAgICAqL1xuICAgIGFkZENvbnRhY3Q6IGZ1bmN0aW9uIChwZWVySmlkLCBpZCkge1xuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChwZWVySmlkKTtcblxuICAgICAgICB2YXIgY29udGFjdGxpc3QgPSAkKCcjY29udGFjdGxpc3Q+dWwnKTtcblxuICAgICAgICB2YXIgbmV3Q29udGFjdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpJyk7XG4gICAgICAgIG5ld0NvbnRhY3QuaWQgPSByZXNvdXJjZUppZDtcbiAgICAgICAgbmV3Q29udGFjdC5jbGFzc05hbWUgPSBcImNsaWNrYWJsZVwiO1xuICAgICAgICBuZXdDb250YWN0Lm9uY2xpY2sgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5jdXJyZW50VGFyZ2V0LmNsYXNzTmFtZSA9PT0gXCJjbGlja2FibGVcIikge1xuICAgICAgICAgICAgICAgICQoQ29udGFjdExpc3QpLnRyaWdnZXIoJ2NvbnRhY3RjbGlja2VkJywgW3BlZXJKaWRdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBuZXdDb250YWN0LmFwcGVuZENoaWxkKGNyZWF0ZUF2YXRhcihpZCkpO1xuICAgICAgICBuZXdDb250YWN0LmFwcGVuZENoaWxkKGNyZWF0ZURpc3BsYXlOYW1lUGFyYWdyYXBoKFwicGFydGljaXBhbnRcIikpO1xuXG4gICAgICAgIHZhciBjbEVsZW1lbnQgPSBjb250YWN0bGlzdC5nZXQoMCk7XG5cbiAgICAgICAgaWYgKHJlc291cmNlSmlkID09PSBBUFAueG1wcC5teVJlc291cmNlKClcbiAgICAgICAgICAgICYmICQoJyNjb250YWN0bGlzdD51bCAudGl0bGUnKVswXS5uZXh0U2libGluZy5uZXh0U2libGluZykge1xuICAgICAgICAgICAgY2xFbGVtZW50Lmluc2VydEJlZm9yZShuZXdDb250YWN0LFxuICAgICAgICAgICAgICAgICQoJyNjb250YWN0bGlzdD51bCAudGl0bGUnKVswXS5uZXh0U2libGluZy5uZXh0U2libGluZyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjbEVsZW1lbnQuYXBwZW5kQ2hpbGQobmV3Q29udGFjdCk7XG4gICAgICAgIH1cbiAgICAgICAgdXBkYXRlTnVtYmVyT2ZQYXJ0aWNpcGFudHMoMSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgYSBjb250YWN0IGZvciB0aGUgZ2l2ZW4gcGVlciBqaWQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcGVlckppZCB0aGUgcGVlckppZCBjb3JyZXNwb25kaW5nIHRvIHRoZSBjb250YWN0IHRvIHJlbW92ZVxuICAgICAqL1xuICAgIHJlbW92ZUNvbnRhY3Q6IGZ1bmN0aW9uIChwZWVySmlkKSB7XG4gICAgICAgIHZhciByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKHBlZXJKaWQpO1xuXG4gICAgICAgIHZhciBjb250YWN0ID0gJCgnI2NvbnRhY3RsaXN0PnVsPmxpW2lkPVwiJyArIHJlc291cmNlSmlkICsgJ1wiXScpO1xuXG4gICAgICAgIGlmIChjb250YWN0ICYmIGNvbnRhY3QubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgdmFyIGNvbnRhY3RsaXN0ID0gJCgnI2NvbnRhY3RsaXN0PnVsJyk7XG5cbiAgICAgICAgICAgIGNvbnRhY3RsaXN0LmdldCgwKS5yZW1vdmVDaGlsZChjb250YWN0LmdldCgwKSk7XG5cbiAgICAgICAgICAgIHVwZGF0ZU51bWJlck9mUGFydGljaXBhbnRzKC0xKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBzZXRWaXN1YWxOb3RpZmljYXRpb246IGZ1bmN0aW9uIChzaG93LCBzdG9wR2xvd2luZ0luKSB7XG4gICAgICAgIHZhciBnbG93ZXIgPSAkKCcjY29udGFjdExpc3RCdXR0b24nKTtcblxuICAgICAgICBpZiAoc2hvdyAmJiAhbm90aWZpY2F0aW9uSW50ZXJ2YWwpIHtcbiAgICAgICAgICAgIG5vdGlmaWNhdGlvbkludGVydmFsID0gd2luZG93LnNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBnbG93ZXIudG9nZ2xlQ2xhc3MoJ2FjdGl2ZSBnbG93aW5nJyk7XG4gICAgICAgICAgICB9LCA4MDApO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCFzaG93ICYmIG5vdGlmaWNhdGlvbkludGVydmFsKSB7XG4gICAgICAgICAgICBzdG9wR2xvd2luZyhnbG93ZXIpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzdG9wR2xvd2luZ0luKSB7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBzdG9wR2xvd2luZyhnbG93ZXIpO1xuICAgICAgICAgICAgfSwgc3RvcEdsb3dpbmdJbik7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2V0Q2xpY2thYmxlOiBmdW5jdGlvbiAocmVzb3VyY2VKaWQsIGlzQ2xpY2thYmxlKSB7XG4gICAgICAgIHZhciBjb250YWN0ID0gJCgnI2NvbnRhY3RsaXN0PnVsPmxpW2lkPVwiJyArIHJlc291cmNlSmlkICsgJ1wiXScpO1xuICAgICAgICBpZiAoaXNDbGlja2FibGUpIHtcbiAgICAgICAgICAgIGNvbnRhY3QuYWRkQ2xhc3MoJ2NsaWNrYWJsZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29udGFjdC5yZW1vdmVDbGFzcygnY2xpY2thYmxlJyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgb25EaXNwbGF5TmFtZUNoYW5nZTogZnVuY3Rpb24gKHBlZXJKaWQsIGRpc3BsYXlOYW1lKSB7XG4gICAgICAgIGlmIChwZWVySmlkID09PSAnbG9jYWxWaWRlb0NvbnRhaW5lcicpXG4gICAgICAgICAgICBwZWVySmlkID0gQVBQLnhtcHAubXlKaWQoKTtcblxuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChwZWVySmlkKTtcblxuICAgICAgICB2YXIgY29udGFjdE5hbWUgPSAkKCcjY29udGFjdGxpc3QgIycgKyByZXNvdXJjZUppZCArICc+cCcpO1xuXG4gICAgICAgIGlmIChjb250YWN0TmFtZSAmJiBkaXNwbGF5TmFtZSAmJiBkaXNwbGF5TmFtZS5sZW5ndGggPiAwKVxuICAgICAgICAgICAgY29udGFjdE5hbWUuaHRtbChkaXNwbGF5TmFtZSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb250YWN0TGlzdDsiLCJ2YXIgQXZhdGFyID0gcmVxdWlyZShcIi4uLy4uL2F2YXRhci9BdmF0YXJcIik7XG52YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi8uLi8uLi8uLi9zZXR0aW5ncy9TZXR0aW5nc1wiKTtcbnZhciBVSVV0aWwgPSByZXF1aXJlKFwiLi4vLi4vdXRpbC9VSVV0aWxcIik7XG52YXIgbGFuZ3VhZ2VzID0gcmVxdWlyZShcIi4uLy4uLy4uLy4uL3NlcnZpY2UvdHJhbnNsYXRpb24vbGFuZ3VhZ2VzXCIpO1xuXG5mdW5jdGlvbiBnZW5lcmF0ZUxhbmd1YWdlc1NlbGVjdEJveCgpXG57XG4gICAgdmFyIGN1cnJlbnRMYW5nID0gQVBQLnRyYW5zbGF0aW9uLmdldEN1cnJlbnRMYW5ndWFnZSgpO1xuICAgIHZhciBodG1sID0gXCI8c2VsZWN0IGlkPVxcXCJsYW5ndWFnZXNfc2VsZWN0Ym94XFxcIj5cIjtcbiAgICB2YXIgbGFuZ0FycmF5ID0gbGFuZ3VhZ2VzLmdldExhbmd1YWdlcygpO1xuICAgIGZvcih2YXIgaSA9IDA7IGkgPCBsYW5nQXJyYXkubGVuZ3RoOyBpKyspXG4gICAge1xuICAgICAgICB2YXIgbGFuZyA9IGxhbmdBcnJheVtpXTtcbiAgICAgICAgaHRtbCArPSBcIjxvcHRpb24gXCI7XG4gICAgICAgIGlmKGxhbmcgPT09IGN1cnJlbnRMYW5nKVxuICAgICAgICAgICAgaHRtbCArPSBcInNlbGVjdGVkIFwiO1xuICAgICAgICBodG1sICs9IFwidmFsdWU9XFxcIlwiICsgbGFuZyArIFwiXFxcIiBkYXRhLWkxOG49J2xhbmd1YWdlczpcIiArIGxhbmcgKyBcIic+XCI7XG4gICAgICAgIGh0bWwgKz0gXCI8L29wdGlvbj5cIjtcblxuICAgIH1cblxuICAgIHJldHVybiBodG1sICsgXCI8L3NlbGVjdD5cIjtcbn1cblxuXG52YXIgU2V0dGluZ3NNZW51ID0ge1xuXG4gICAgaW5pdDogZnVuY3Rpb24gKCkge1xuICAgICAgICAkKFwiI3VwZGF0ZVNldHRpbmdzXCIpLmJlZm9yZShnZW5lcmF0ZUxhbmd1YWdlc1NlbGVjdEJveCgpKTtcbiAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZUVsZW1lbnQoJChcIiNsYW5ndWFnZXNfc2VsZWN0Ym94XCIpKTtcbiAgICAgICAgJCgnI3NldHRpbmdzbWVudT5pbnB1dCcpLmtleXVwKGZ1bmN0aW9uKGV2ZW50KXtcbiAgICAgICAgICAgIGlmKGV2ZW50LmtleUNvZGUgPT09IDEzKSB7Ly9lbnRlclxuICAgICAgICAgICAgICAgIFNldHRpbmdzTWVudS51cGRhdGUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgJChcIiN1cGRhdGVTZXR0aW5nc1wiKS5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBTZXR0aW5nc01lbnUudXBkYXRlKCk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICB1cGRhdGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgbmV3RGlzcGxheU5hbWUgPSBVSVV0aWwuZXNjYXBlSHRtbCgkKCcjc2V0RGlzcGxheU5hbWUnKS5nZXQoMCkudmFsdWUpO1xuICAgICAgICB2YXIgbmV3RW1haWwgPSBVSVV0aWwuZXNjYXBlSHRtbCgkKCcjc2V0RW1haWwnKS5nZXQoMCkudmFsdWUpO1xuXG4gICAgICAgIGlmKG5ld0Rpc3BsYXlOYW1lKSB7XG4gICAgICAgICAgICB2YXIgZGlzcGxheU5hbWUgPSBTZXR0aW5ncy5zZXREaXNwbGF5TmFtZShuZXdEaXNwbGF5TmFtZSk7XG4gICAgICAgICAgICBBUFAueG1wcC5hZGRUb1ByZXNlbmNlKFwiZGlzcGxheU5hbWVcIiwgZGlzcGxheU5hbWUsIHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGxhbmd1YWdlID0gJChcIiNsYW5ndWFnZXNfc2VsZWN0Ym94XCIpLnZhbCgpO1xuICAgICAgICBBUFAudHJhbnNsYXRpb24uc2V0TGFuZ3VhZ2UobGFuZ3VhZ2UpO1xuICAgICAgICBTZXR0aW5ncy5zZXRMYW5ndWFnZShsYW5ndWFnZSk7XG5cbiAgICAgICAgQVBQLnhtcHAuYWRkVG9QcmVzZW5jZShcImVtYWlsXCIsIG5ld0VtYWlsKTtcbiAgICAgICAgdmFyIGVtYWlsID0gU2V0dGluZ3Muc2V0RW1haWwobmV3RW1haWwpO1xuXG5cbiAgICAgICAgQXZhdGFyLnNldFVzZXJBdmF0YXIoQVBQLnhtcHAubXlKaWQoKSwgZW1haWwpO1xuICAgIH0sXG5cbiAgICBpc1Zpc2libGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gJCgnI3NldHRpbmdzbWVudScpLmlzKCc6dmlzaWJsZScpO1xuICAgIH0sXG5cbiAgICBzZXREaXNwbGF5TmFtZTogZnVuY3Rpb24obmV3RGlzcGxheU5hbWUpIHtcbiAgICAgICAgdmFyIGRpc3BsYXlOYW1lID0gU2V0dGluZ3Muc2V0RGlzcGxheU5hbWUobmV3RGlzcGxheU5hbWUpO1xuICAgICAgICAkKCcjc2V0RGlzcGxheU5hbWUnKS5nZXQoMCkudmFsdWUgPSBkaXNwbGF5TmFtZTtcbiAgICB9LFxuXG4gICAgb25EaXNwbGF5TmFtZUNoYW5nZTogZnVuY3Rpb24ocGVlckppZCwgbmV3RGlzcGxheU5hbWUpIHtcbiAgICAgICAgaWYocGVlckppZCA9PT0gJ2xvY2FsVmlkZW9Db250YWluZXInIHx8XG4gICAgICAgICAgICBwZWVySmlkID09PSBBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgICAgICB0aGlzLnNldERpc3BsYXlOYW1lKG5ld0Rpc3BsYXlOYW1lKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cblxubW9kdWxlLmV4cG9ydHMgPSBTZXR0aW5nc01lbnU7IiwidmFyIFBhbmVsVG9nZ2xlciA9IHJlcXVpcmUoXCIuLi9zaWRlX3Bhbm5lbHMvU2lkZVBhbmVsVG9nZ2xlclwiKTtcblxudmFyIGJ1dHRvbkhhbmRsZXJzID0ge1xuICAgIFwiYm90dG9tX3Rvb2xiYXJfY29udGFjdF9saXN0XCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQm90dG9tVG9vbGJhci50b2dnbGVDb250YWN0TGlzdCgpO1xuICAgIH0sXG4gICAgXCJib3R0b21fdG9vbGJhcl9maWxtX3N0cmlwXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQm90dG9tVG9vbGJhci50b2dnbGVGaWxtU3RyaXAoKTtcbiAgICB9LFxuICAgIFwiYm90dG9tX3Rvb2xiYXJfY2hhdFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIEJvdHRvbVRvb2xiYXIudG9nZ2xlQ2hhdCgpO1xuICAgIH1cbn07XG5cbnZhciBCb3R0b21Ub29sYmFyID0gKGZ1bmN0aW9uIChteSkge1xuICAgIG15LmluaXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGZvcih2YXIgayBpbiBidXR0b25IYW5kbGVycylcbiAgICAgICAgICAgICQoXCIjXCIgKyBrKS5jbGljayhidXR0b25IYW5kbGVyc1trXSk7XG4gICAgfTtcblxuICAgIG15LnRvZ2dsZUNoYXQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgUGFuZWxUb2dnbGVyLnRvZ2dsZUNoYXQoKTtcbiAgICB9O1xuXG4gICAgbXkudG9nZ2xlQ29udGFjdExpc3QgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgUGFuZWxUb2dnbGVyLnRvZ2dsZUNvbnRhY3RMaXN0KCk7XG4gICAgfTtcblxuICAgIG15LnRvZ2dsZUZpbG1TdHJpcCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgZmlsbXN0cmlwID0gJChcIiNyZW1vdGVWaWRlb3NcIik7XG4gICAgICAgIGZpbG1zdHJpcC50b2dnbGVDbGFzcyhcImhpZGRlblwiKTtcbiAgICB9O1xuXG4gICAgJChkb2N1bWVudCkuYmluZChcInJlbW90ZXZpZGVvLnJlc2l6ZWRcIiwgZnVuY3Rpb24gKGV2ZW50LCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgICAgIHZhciBib3R0b20gPSAoaGVpZ2h0IC0gJCgnI2JvdHRvbVRvb2xiYXInKS5vdXRlckhlaWdodCgpKS8yICsgMTg7XG5cbiAgICAgICAgJCgnI2JvdHRvbVRvb2xiYXInKS5jc3Moe2JvdHRvbTogYm90dG9tICsgJ3B4J30pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIG15O1xufShCb3R0b21Ub29sYmFyIHx8IHt9KSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQm90dG9tVG9vbGJhcjtcbiIsIi8qIGdsb2JhbCBBUFAsJCwgYnV0dG9uQ2xpY2ssIGNvbmZpZywgbG9ja1Jvb20sXG4gICBzZXRTaGFyZWRLZXksIFV0aWwgKi9cbnZhciBtZXNzYWdlSGFuZGxlciA9IHJlcXVpcmUoXCIuLi91dGlsL01lc3NhZ2VIYW5kbGVyXCIpO1xudmFyIEJvdHRvbVRvb2xiYXIgPSByZXF1aXJlKFwiLi9Cb3R0b21Ub29sYmFyXCIpO1xudmFyIFByZXppID0gcmVxdWlyZShcIi4uL3ByZXppL1ByZXppXCIpO1xudmFyIEV0aGVycGFkID0gcmVxdWlyZShcIi4uL2V0aGVycGFkL0V0aGVycGFkXCIpO1xudmFyIFBhbmVsVG9nZ2xlciA9IHJlcXVpcmUoXCIuLi9zaWRlX3Bhbm5lbHMvU2lkZVBhbmVsVG9nZ2xlclwiKTtcbnZhciBBdXRoZW50aWNhdGlvbiA9IHJlcXVpcmUoXCIuLi9hdXRoZW50aWNhdGlvbi9BdXRoZW50aWNhdGlvblwiKTtcbnZhciBVSVV0aWwgPSByZXF1aXJlKFwiLi4vdXRpbC9VSVV0aWxcIik7XG52YXIgQXV0aGVudGljYXRpb25FdmVudHNcbiAgICA9IHJlcXVpcmUoXCIuLi8uLi8uLi9zZXJ2aWNlL2F1dGhlbnRpY2F0aW9uL0F1dGhlbnRpY2F0aW9uRXZlbnRzXCIpO1xuXG52YXIgcm9vbVVybCA9IG51bGw7XG52YXIgc2hhcmVkS2V5ID0gJyc7XG52YXIgVUkgPSBudWxsO1xuXG52YXIgYnV0dG9uSGFuZGxlcnMgPVxue1xuICAgIFwidG9vbGJhcl9idXR0b25fbXV0ZVwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBBUFAuVUkudG9nZ2xlQXVkaW8oKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fY2FtZXJhXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIEFQUC5VSS50b2dnbGVWaWRlbygpO1xuICAgIH0sXG4gICAgLypcInRvb2xiYXJfYnV0dG9uX2F1dGhlbnRpY2F0aW9uXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFRvb2xiYXIuYXV0aGVudGljYXRlQ2xpY2tlZCgpO1xuICAgIH0sKi9cbiAgICBcInRvb2xiYXJfYnV0dG9uX3JlY29yZFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0b2dnbGVSZWNvcmRpbmcoKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fc2VjdXJpdHlcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gVG9vbGJhci5vcGVuTG9ja0RpYWxvZygpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9saW5rXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFRvb2xiYXIub3BlbkxpbmtEaWFsb2coKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fY2hhdFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBCb3R0b21Ub29sYmFyLnRvZ2dsZUNoYXQoKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fcHJlemlcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUHJlemkub3BlblByZXppRGlhbG9nKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX2V0aGVycGFkXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIEV0aGVycGFkLnRvZ2dsZUV0aGVycGFkKDApO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9kZXNrdG9wc2hhcmluZ1wiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBBUFAuZGVza3RvcHNoYXJpbmcudG9nZ2xlU2NyZWVuU2hhcmluZygpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9mdWxsU2NyZWVuXCI6IGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICAgIFVJVXRpbC5idXR0b25DbGljayhcIiNmdWxsU2NyZWVuXCIsIFwiaWNvbi1mdWxsLXNjcmVlbiBpY29uLWV4aXQtZnVsbC1zY3JlZW5cIik7XG4gICAgICAgIHJldHVybiBUb29sYmFyLnRvZ2dsZUZ1bGxTY3JlZW4oKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fc2lwXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGNhbGxTaXBCdXR0b25DbGlja2VkKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX3NldHRpbmdzXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgUGFuZWxUb2dnbGVyLnRvZ2dsZVNldHRpbmdzTWVudSgpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9oYW5ndXBcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gaGFuZ3VwKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX2xvZ2luXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgVG9vbGJhci5hdXRoZW50aWNhdGVDbGlja2VkKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX2xvZ291dFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIEFzayBmb3IgY29uZmlybWF0aW9uXG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2coXG4gICAgICAgICAgICBcImRpYWxvZy5sb2dvdXRUaXRsZVwiLFxuICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgIFwiZGlhbG9nLmxvZ291dFF1ZXN0aW9uXCIsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBcImRpYWxvZy5ZZXNcIixcbiAgICAgICAgICAgIGZ1bmN0aW9uIChldnQsIHllcykge1xuICAgICAgICAgICAgICAgIGlmICh5ZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAubG9nb3V0KGZ1bmN0aW9uICh1cmwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh1cmwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9IHVybDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZ3VwKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgIH1cbn07XG5cbmZ1bmN0aW9uIGhhbmd1cCgpIHtcbiAgICBBUFAueG1wcC5kaXNwb3NlQ29uZmVyZW5jZSgpO1xuICAgIGlmKGNvbmZpZy5lbmFibGVXZWxjb21lUGFnZSlcbiAgICB7XG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKVxuICAgICAgICB7XG4gICAgICAgICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLndlbGNvbWVQYWdlRGlzYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSA9IFwiL1wiO1xuICAgICAgICB9LCAxMDAwMCk7XG5cbiAgICB9XG5cbiAgICB2YXIgdGl0bGUgPSBBUFAudHJhbnNsYXRpb24uZ2VuZXJhdGVUcmFuc2xhdG9uSFRNTChcbiAgICAgICAgXCJkaWFsb2cuc2Vzc1Rlcm1pbmF0ZWRcIik7XG4gICAgdmFyIG1zZyA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFxuICAgICAgICBcImRpYWxvZy5odW5nVXBcIik7XG4gICAgdmFyIGJ1dHRvbiA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFxuICAgICAgICBcImRpYWxvZy5qb2luQWdhaW5cIik7XG4gICAgdmFyIGJ1dHRvbnMgPSBbXTtcbiAgICBidXR0b25zLnB1c2goe3RpdGxlOiBidXR0b24sIHZhbHVlOiB0cnVlfSk7XG5cbiAgICBVSS5tZXNzYWdlSGFuZGxlci5vcGVuRGlhbG9nKFxuICAgICAgICB0aXRsZSxcbiAgICAgICAgbXNnLFxuICAgICAgICB0cnVlLFxuICAgICAgICBidXR0b25zLFxuICAgICAgICBmdW5jdGlvbihldmVudCwgdmFsdWUsIG1lc3NhZ2UsIGZvcm1WYWxzKVxuICAgICAgICB7XG4gICAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucmVsb2FkKCk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICApO1xufVxuXG4vKipcbiAqIFN0YXJ0cyBvciBzdG9wcyB0aGUgcmVjb3JkaW5nIGZvciB0aGUgY29uZmVyZW5jZS5cbiAqL1xuXG5mdW5jdGlvbiB0b2dnbGVSZWNvcmRpbmcoKSB7XG4gICAgQVBQLnhtcHAudG9nZ2xlUmVjb3JkaW5nKGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgICAgICB2YXIgbXNnID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXG4gICAgICAgICAgICBcImRpYWxvZy5yZWNvcmRpbmdUb2tlblwiKTtcbiAgICAgICAgdmFyIHRva2VuID0gQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhcImRpYWxvZy50b2tlblwiKTtcbiAgICAgICAgQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2cobnVsbCwgbnVsbCwgbnVsbCxcbiAgICAgICAgICAgICAgICAnPGgyPicgKyBtc2cgKyAnPC9oMj4nICtcbiAgICAgICAgICAgICAgICAnPGlucHV0IG5hbWU9XCJyZWNvcmRpbmdUb2tlblwiIHR5cGU9XCJ0ZXh0XCIgJyArXG4gICAgICAgICAgICAgICAgJyBkYXRhLWkxOG49XCJbcGxhY2Vob2xkZXJdZGlhbG9nLnRva2VuXCIgJyArXG4gICAgICAgICAgICAgICAgJ3BsYWNlaG9sZGVyPVwiJyArIHRva2VuICsgJ1wiIGF1dG9mb2N1cz4nLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBcImRpYWxvZy5TYXZlXCIsXG4gICAgICAgICAgICBmdW5jdGlvbiAoZSwgdiwgbSwgZikge1xuICAgICAgICAgICAgICAgIGlmICh2KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB0b2tlbiA9IGYucmVjb3JkaW5nVG9rZW47XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayhVSVV0aWwuZXNjYXBlSHRtbCh0b2tlbikpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7IH0sXG4gICAgICAgICAgICAnOmlucHV0OmZpcnN0J1xuICAgICAgICApO1xuICAgIH0sIFRvb2xiYXIuc2V0UmVjb3JkaW5nQnV0dG9uU3RhdGUsIFRvb2xiYXIuc2V0UmVjb3JkaW5nQnV0dG9uU3RhdGUpO1xufVxuXG4vKipcbiAqIExvY2tzIC8gdW5sb2NrcyB0aGUgcm9vbS5cbiAqL1xuZnVuY3Rpb24gbG9ja1Jvb20obG9jaykge1xuICAgIHZhciBjdXJyZW50U2hhcmVkS2V5ID0gJyc7XG4gICAgaWYgKGxvY2spXG4gICAgICAgIGN1cnJlbnRTaGFyZWRLZXkgPSBzaGFyZWRLZXk7XG5cbiAgICBBUFAueG1wcC5sb2NrUm9vbShjdXJyZW50U2hhcmVkS2V5LCBmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgIC8vIHBhc3N3b3JkIGlzIHJlcXVpcmVkXG4gICAgICAgIGlmIChzaGFyZWRLZXkpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzZXQgcm9vbSBwYXNzd29yZCcpO1xuICAgICAgICAgICAgVG9vbGJhci5sb2NrTG9ja0J1dHRvbigpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ3JlbW92ZWQgcm9vbSBwYXNzd29yZCcpO1xuICAgICAgICAgICAgVG9vbGJhci51bmxvY2tMb2NrQnV0dG9uKCk7XG4gICAgICAgIH1cbiAgICB9LCBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUud2Fybignc2V0dGluZyBwYXNzd29yZCBmYWlsZWQnLCBlcnIpO1xuICAgICAgICBtZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoXCJkaWFsb2cubG9ja1RpdGxlXCIsXG4gICAgICAgICAgICBcImRpYWxvZy5sb2NrTWVzc2FnZVwiKTtcbiAgICAgICAgVG9vbGJhci5zZXRTaGFyZWRLZXkoJycpO1xuICAgIH0sIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdyb29tIHBhc3N3b3JkcyBub3Qgc3VwcG9ydGVkJyk7XG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcihcImRpYWxvZy53YXJuaW5nXCIsXG4gICAgICAgICAgICBcImRpYWxvZy5wYXNzd29yZE5vdFN1cHBvcnRlZFwiKTtcbiAgICAgICAgVG9vbGJhci5zZXRTaGFyZWRLZXkoJycpO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBJbnZpdGUgcGFydGljaXBhbnRzIHRvIGNvbmZlcmVuY2UuXG4gKi9cbmZ1bmN0aW9uIGludml0ZVBhcnRpY2lwYW50cygpIHtcbiAgICBpZiAocm9vbVVybCA9PT0gbnVsbClcbiAgICAgICAgcmV0dXJuO1xuXG4gICAgdmFyIHNoYXJlZEtleVRleHQgPSBcIlwiO1xuICAgIGlmIChzaGFyZWRLZXkgJiYgc2hhcmVkS2V5Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgc2hhcmVkS2V5VGV4dCA9XG4gICAgICAgICAgICBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nKFwiZW1haWwuc2hhcmVkS2V5XCIsXG4gICAgICAgICAgICAgICAge3NoYXJlZEtleTogc2hhcmVkS2V5fSk7XG4gICAgICAgIHNoYXJlZEtleVRleHQgPSBzaGFyZWRLZXlUZXh0LnJlcGxhY2UoL1xcbi9nLCBcIiUwRCUwQVwiKTtcbiAgICB9XG5cbiAgICB2YXIgc3VwcG9ydGVkQnJvd3NlcnMgPSBcIkNocm9taXVtLCBHb29nbGUgQ2hyb21lIFwiICtcbiAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhcImVtYWlsLmFuZFwiKSArIFwiIE9wZXJhXCI7XG4gICAgdmFyIGNvbmZlcmVuY2VOYW1lID0gcm9vbVVybC5zdWJzdHJpbmcocm9vbVVybC5sYXN0SW5kZXhPZignLycpICsgMSk7XG4gICAgdmFyIHN1YmplY3QgPSBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nKFwiZW1haWwuc3ViamVjdFwiLFxuICAgICAgICB7YXBwTmFtZTppbnRlcmZhY2VDb25maWcuQVBQX05BTUUsIGNvbmZlcmVuY2VOYW1lOiBjb25mZXJlbmNlTmFtZX0pO1xuICAgIHZhciBib2R5ID0gQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhcImVtYWlsLmJvZHlcIixcbiAgICAgICAge2FwcE5hbWU6aW50ZXJmYWNlQ29uZmlnLkFQUF9OQU1FLCBzaGFyZWRLZXlUZXh0OiBzaGFyZWRLZXlUZXh0LFxuICAgICAgICAgICAgcm9vbVVybDogcm9vbVVybCwgc3VwcG9ydGVkQnJvd3NlcnM6IHN1cHBvcnRlZEJyb3dzZXJzfSk7XG4gICAgYm9keSA9IGJvZHkucmVwbGFjZSgvXFxuL2csIFwiJTBEJTBBXCIpO1xuXG4gICAgaWYgKHdpbmRvdy5sb2NhbFN0b3JhZ2UuZGlzcGxheW5hbWUpIHtcbiAgICAgICAgYm9keSArPSBcIiUwRCUwQSUwRCUwQVwiICsgd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZTtcbiAgICB9XG5cbiAgICBpZiAoaW50ZXJmYWNlQ29uZmlnLklOVklUQVRJT05fUE9XRVJFRF9CWSkge1xuICAgICAgICBib2R5ICs9IFwiJTBEJTBBJTBEJTBBLS0lMEQlMEFwb3dlcmVkIGJ5IGppdHNpLm9yZ1wiO1xuICAgIH1cblxuICAgIHdpbmRvdy5vcGVuKFwibWFpbHRvOj9zdWJqZWN0PVwiICsgc3ViamVjdCArIFwiJmJvZHk9XCIgKyBib2R5LCAnX2JsYW5rJyk7XG59XG5cbmZ1bmN0aW9uIGNhbGxTaXBCdXR0b25DbGlja2VkKClcbntcbiAgICB2YXIgZGVmYXVsdE51bWJlclxuICAgICAgICA9IGNvbmZpZy5kZWZhdWx0U2lwTnVtYmVyID8gY29uZmlnLmRlZmF1bHRTaXBOdW1iZXIgOiAnJztcblxuICAgIHZhciBzaXBNc2cgPSBBUFAudHJhbnNsYXRpb24uZ2VuZXJhdGVUcmFuc2xhdG9uSFRNTChcbiAgICAgICAgXCJkaWFsb2cuc2lwTXNnXCIpO1xuICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2cobnVsbCwgbnVsbCwgbnVsbCxcbiAgICAgICAgJzxoMj4nICsgc2lwTXNnICsgJzwvaDI+JyArXG4gICAgICAgICc8aW5wdXQgbmFtZT1cInNpcE51bWJlclwiIHR5cGU9XCJ0ZXh0XCInICtcbiAgICAgICAgJyB2YWx1ZT1cIicgKyBkZWZhdWx0TnVtYmVyICsgJ1wiIGF1dG9mb2N1cz4nLFxuICAgICAgICBmYWxzZSxcbiAgICAgICAgXCJkaWFsb2cuRGlhbFwiLFxuICAgICAgICBmdW5jdGlvbiAoZSwgdiwgbSwgZikge1xuICAgICAgICAgICAgaWYgKHYpIHtcbiAgICAgICAgICAgICAgICB2YXIgbnVtYmVySW5wdXQgPSBmLnNpcE51bWJlcjtcbiAgICAgICAgICAgICAgICBpZiAobnVtYmVySW5wdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAuZGlhbChcbiAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcklucHV0LCAnZnJvbW51bWJlcicsIFVJLmdldFJvb21OYW1lKCksIHNoYXJlZEtleSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBudWxsLCBudWxsLCAnOmlucHV0OmZpcnN0J1xuICAgICk7XG59XG5cbnZhciBUb29sYmFyID0gKGZ1bmN0aW9uIChteSkge1xuXG4gICAgbXkuaW5pdCA9IGZ1bmN0aW9uICh1aSkge1xuICAgICAgICBmb3IodmFyIGsgaW4gYnV0dG9uSGFuZGxlcnMpXG4gICAgICAgICAgICAkKFwiI1wiICsgaykuY2xpY2soYnV0dG9uSGFuZGxlcnNba10pO1xuICAgICAgICBVSSA9IHVpO1xuICAgICAgICAvLyBVcGRhdGUgbG9naW4gaW5mb1xuICAgICAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihcbiAgICAgICAgICAgIEF1dGhlbnRpY2F0aW9uRXZlbnRzLklERU5USVRZX1VQREFURUQsXG4gICAgICAgICAgICBmdW5jdGlvbiAoYXV0aGVudGljYXRpb25FbmFibGVkLCB1c2VySWRlbnRpdHkpIHtcblxuICAgICAgICAgICAgICAgIHZhciBsb2dnZWRJbiA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIGlmICh1c2VySWRlbnRpdHkpIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VkSW4gPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIFRvb2xiYXIuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbihhdXRoZW50aWNhdGlvbkVuYWJsZWQpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGF1dGhlbnRpY2F0aW9uRW5hYmxlZCkge1xuICAgICAgICAgICAgICAgICAgICBUb29sYmFyLnNldEF1dGhlbnRpY2F0ZWRJZGVudGl0eSh1c2VySWRlbnRpdHkpO1xuXG4gICAgICAgICAgICAgICAgICAgIFRvb2xiYXIuc2hvd0xvZ2luQnV0dG9uKCFsb2dnZWRJbik7XG4gICAgICAgICAgICAgICAgICAgIFRvb2xiYXIuc2hvd0xvZ291dEJ1dHRvbihsb2dnZWRJbik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHNoYXJlZCBrZXlcbiAgICAgKiBAcGFyYW0gc0tleSB0aGUgc2hhcmVkIGtleVxuICAgICAqL1xuICAgIG15LnNldFNoYXJlZEtleSA9IGZ1bmN0aW9uIChzS2V5KSB7XG4gICAgICAgIHNoYXJlZEtleSA9IHNLZXk7XG4gICAgfTtcblxuICAgIG15LmF1dGhlbnRpY2F0ZUNsaWNrZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIEF1dGhlbnRpY2F0aW9uLmZvY3VzQXV0aGVudGljYXRpb25XaW5kb3coKTtcbiAgICAgICAgaWYgKCFBUFAueG1wcC5pc0V4dGVybmFsQXV0aEVuYWJsZWQoKSkge1xuICAgICAgICAgICAgQXV0aGVudGljYXRpb24ueG1wcEF1dGhlbnRpY2F0ZSgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIEdldCBhdXRoZW50aWNhdGlvbiBVUkxcbiAgICAgICAgaWYgKCFBUFAueG1wcC5nZXRNVUNKb2luZWQoKSkge1xuICAgICAgICAgICAgQVBQLnhtcHAuZ2V0TG9naW5VcmwoVUkuZ2V0Um9vbU5hbWUoKSwgZnVuY3Rpb24gKHVybCkge1xuICAgICAgICAgICAgICAgIC8vIElmIGNvbmZlcmVuY2UgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQgeWV0IC0gcmVkaXJlY3QgdG8gbG9naW4gcGFnZVxuICAgICAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gdXJsO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBBUFAueG1wcC5nZXRQb3B1cExvZ2luVXJsKFVJLmdldFJvb21OYW1lKCksIGZ1bmN0aW9uICh1cmwpIHtcbiAgICAgICAgICAgICAgICAvLyBPdGhlcndpc2UgLSBvcGVuIHBvcHVwIHdpdGggYXV0aGVudGljYXRpb24gVVJMXG4gICAgICAgICAgICAgICAgdmFyIGF1dGhlbnRpY2F0aW9uV2luZG93ID0gQXV0aGVudGljYXRpb24uY3JlYXRlQXV0aGVudGljYXRpb25XaW5kb3coXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9uIHBvcHVwIGNsb3NlZCAtIHJldHJ5IHJvb20gYWxsb2NhdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAuYWxsb2NhdGVDb25mZXJlbmNlRm9jdXMoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgQVBQLlVJLmdldFJvb21OYW1lKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkgeyBjb25zb2xlLmluZm8oXCJBVVRIIERPTkVcIik7IH1cbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0sIHVybCk7XG4gICAgICAgICAgICAgICAgaWYgKCFhdXRoZW50aWNhdGlvbldpbmRvdykge1xuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuTWVzc2FnZURpYWxvZyhcbiAgICAgICAgICAgICAgICAgICAgICAgIG51bGwsIFwiZGlhbG9nLnBvcHVwRXJyb3JcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgcm9vbSBpbnZpdGUgdXJsLlxuICAgICAqL1xuICAgIG15LnVwZGF0ZVJvb21VcmwgPSBmdW5jdGlvbiAobmV3Um9vbVVybCkge1xuICAgICAgICByb29tVXJsID0gbmV3Um9vbVVybDtcblxuICAgICAgICAvLyBJZiB0aGUgaW52aXRlIGRpYWxvZyBoYXMgYmVlbiBhbHJlYWR5IG9wZW5lZCB3ZSB1cGRhdGUgdGhlIGluZm9ybWF0aW9uLlxuICAgICAgICB2YXIgaW52aXRlTGluayA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdpbnZpdGVMaW5rUmVmJyk7XG4gICAgICAgIGlmIChpbnZpdGVMaW5rKSB7XG4gICAgICAgICAgICBpbnZpdGVMaW5rLnZhbHVlID0gcm9vbVVybDtcbiAgICAgICAgICAgIGludml0ZUxpbmsuc2VsZWN0KCk7XG4gICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnanFpX3N0YXRlMF9idXR0b25JbnZpdGUnKS5kaXNhYmxlZCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIERpc2FibGVzIGFuZCBlbmFibGVzIHNvbWUgb2YgdGhlIGJ1dHRvbnMuXG4gICAgICovXG4gICAgbXkuc2V0dXBCdXR0b25zRnJvbUNvbmZpZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKGNvbmZpZy5kaXNhYmxlUHJlemkpXG4gICAgICAgIHtcbiAgICAgICAgICAgICQoXCIjcHJlemlfYnV0dG9uXCIpLmNzcyh7ZGlzcGxheTogXCJub25lXCJ9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPcGVucyB0aGUgbG9jayByb29tIGRpYWxvZy5cbiAgICAgKi9cbiAgICBteS5vcGVuTG9ja0RpYWxvZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gT25seSB0aGUgZm9jdXMgaXMgYWJsZSB0byBzZXQgYSBzaGFyZWQga2V5LlxuICAgICAgICBpZiAoIUFQUC54bXBwLmlzTW9kZXJhdG9yKCkpIHtcbiAgICAgICAgICAgIGlmIChzaGFyZWRLZXkpIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuTWVzc2FnZURpYWxvZyhudWxsLFxuICAgICAgICAgICAgICAgICAgICBcImRpYWxvZy5wYXNzd29yZEVycm9yXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuTWVzc2FnZURpYWxvZyhudWxsLCBcImRpYWxvZy5wYXNzd29yZEVycm9yMlwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChzaGFyZWRLZXkpIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKG51bGwsIG51bGwsXG4gICAgICAgICAgICAgICAgICAgIFwiZGlhbG9nLnBhc3N3b3JkQ2hlY2tcIixcbiAgICAgICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIFwiZGlhbG9nLlJlbW92ZVwiLFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZSwgdikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUb29sYmFyLnNldFNoYXJlZEtleSgnJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9ja1Jvb20oZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFyIG1zZyA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFxuICAgICAgICAgICAgICAgICAgICBcImRpYWxvZy5wYXNzd29yZE1zZ1wiKTtcbiAgICAgICAgICAgICAgICB2YXIgeW91clBhc3N3b3JkID0gQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhcbiAgICAgICAgICAgICAgICAgICAgXCJkaWFsb2cueW91clBhc3N3b3JkXCIpO1xuICAgICAgICAgICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2cobnVsbCwgbnVsbCwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgJzxoMj4nICsgbXNnICsgJzwvaDI+JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAnPGlucHV0IG5hbWU9XCJsb2NrS2V5XCIgdHlwZT1cInRleHRcIicgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJyBkYXRhLWkxOG49XCJbcGxhY2Vob2xkZXJdZGlhbG9nLnlvdXJQYXNzd29yZFwiICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJ3BsYWNlaG9sZGVyPVwiJyArIHlvdXJQYXNzd29yZCArICdcIiBhdXRvZm9jdXM+JyxcbiAgICAgICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIFwiZGlhbG9nLlNhdmVcIixcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGUsIHYsIG0sIGYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxvY2tLZXkgPSBmLmxvY2tLZXk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9ja0tleSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUb29sYmFyLnNldFNoYXJlZEtleShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFVJVXRpbC5lc2NhcGVIdG1sKGxvY2tLZXkpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9ja1Jvb20odHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBudWxsLCBudWxsLCAnaW5wdXQ6Zmlyc3QnXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPcGVucyB0aGUgaW52aXRlIGxpbmsgZGlhbG9nLlxuICAgICAqL1xuICAgIG15Lm9wZW5MaW5rRGlhbG9nID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgaW52aXRlQXR0cmVpYnV0ZXM7XG5cbiAgICAgICAgaWYgKHJvb21VcmwgPT09IG51bGwpIHtcbiAgICAgICAgICAgIGludml0ZUF0dHJlaWJ1dGVzID0gJ2RhdGEtaTE4bj1cIlt2YWx1ZV1yb29tVXJsRGVmYXVsdE1zZ1wiIHZhbHVlPVwiJyArXG4gICAgICAgICAgICBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nKFwicm9vbVVybERlZmF1bHRNc2dcIikgKyAnXCInO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaW52aXRlQXR0cmVpYnV0ZXMgPSBcInZhbHVlPVxcXCJcIiArIGVuY29kZVVSSShyb29tVXJsKSArIFwiXFxcIlwiO1xuICAgICAgICB9XG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2coXCJkaWFsb2cuc2hhcmVMaW5rXCIsXG4gICAgICAgICAgICBudWxsLCBudWxsLFxuICAgICAgICAgICAgJzxpbnB1dCBpZD1cImludml0ZUxpbmtSZWZcIiB0eXBlPVwidGV4dFwiICcgK1xuICAgICAgICAgICAgICAgIGludml0ZUF0dHJlaWJ1dGVzICsgJyBvbmNsaWNrPVwidGhpcy5zZWxlY3QoKTtcIiByZWFkb25seT4nLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBcImRpYWxvZy5JbnZpdGVcIixcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlLCB2KSB7XG4gICAgICAgICAgICAgICAgaWYgKHYpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJvb21VcmwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGludml0ZVBhcnRpY2lwYW50cygpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAocm9vbVVybCkge1xuICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnaW52aXRlTGlua1JlZicpLnNlbGVjdCgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdqcWlfc3RhdGUwX2J1dHRvbkludml0ZScpXG4gICAgICAgICAgICAgICAgICAgICAgICAuZGlzYWJsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogT3BlbnMgdGhlIHNldHRpbmdzIGRpYWxvZy5cbiAgICAgKiBGSVhNRTogbm90IHVzZWQgP1xuICAgICAqL1xuICAgIG15Lm9wZW5TZXR0aW5nc0RpYWxvZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNldHRpbmdzMSA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFxuICAgICAgICAgICAgXCJkaWFsb2cuc2V0dGluZ3MxXCIpO1xuICAgICAgICB2YXIgc2V0dGluZ3MyID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXG4gICAgICAgICAgICBcImRpYWxvZy5zZXR0aW5nczJcIik7XG4gICAgICAgIHZhciBzZXR0aW5nczMgPSBBUFAudHJhbnNsYXRpb24uZ2VuZXJhdGVUcmFuc2xhdG9uSFRNTChcbiAgICAgICAgICAgIFwiZGlhbG9nLnNldHRpbmdzM1wiKTtcblxuICAgICAgICB2YXIgeW91clBhc3N3b3JkID0gQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhcbiAgICAgICAgICAgIFwiZGlhbG9nLnlvdXJQYXNzd29yZFwiKTtcblxuICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKG51bGwsXG4gICAgICAgICAgICAnPGgyPicgKyBzZXR0aW5nczEgKyAnPC9oMj4nICtcbiAgICAgICAgICAgICAgICAnPGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGlkPVwiaW5pdE11dGVkXCI+JyArXG4gICAgICAgICAgICAgICAgc2V0dGluZ3MyICsgJzxici8+JyArXG4gICAgICAgICAgICAgICAgJzxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBpZD1cInJlcXVpcmVOaWNrbmFtZXNcIj4nICtcbiAgICAgICAgICAgICAgICAgc2V0dGluZ3MzICtcbiAgICAgICAgICAgICAgICAnPGlucHV0IGlkPVwibG9ja0tleVwiIHR5cGU9XCJ0ZXh0XCIgcGxhY2Vob2xkZXI9XCInICsgeW91clBhc3N3b3JkICtcbiAgICAgICAgICAgICAgICAnXCIgZGF0YS1pMThuPVwiW3BsYWNlaG9sZGVyXWRpYWxvZy55b3VyUGFzc3dvcmRcIiBhdXRvZm9jdXM+JyxcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBcImRpYWxvZy5TYXZlXCIsXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xvY2tLZXknKS5mb2N1cygpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlLCB2KSB7XG4gICAgICAgICAgICAgICAgaWYgKHYpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQoJyNpbml0TXV0ZWQnKS5pcyhcIjpjaGVja2VkXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpdCBpcyBjaGVja2VkXG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpZiAoJCgnI3JlcXVpcmVOaWNrbmFtZXMnKS5pcyhcIjpjaGVja2VkXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpdCBpcyBjaGVja2VkXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAgICAgICAgdmFyIGxvY2tLZXkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9ja0tleScpO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChsb2NrS2V5LnZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRTaGFyZWRLZXkobG9ja0tleS52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2NrUm9vbSh0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVG9nZ2xlcyB0aGUgYXBwbGljYXRpb24gaW4gYW5kIG91dCBvZiBmdWxsIHNjcmVlbiBtb2RlXG4gICAgICogKGEuay5hLiBwcmVzZW50YXRpb24gbW9kZSBpbiBDaHJvbWUpLlxuICAgICAqL1xuICAgIG15LnRvZ2dsZUZ1bGxTY3JlZW4gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBmc0VsZW1lbnQgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XG5cbiAgICAgICAgaWYgKCFkb2N1bWVudC5tb3pGdWxsU2NyZWVuICYmICFkb2N1bWVudC53ZWJraXRJc0Z1bGxTY3JlZW4pIHtcbiAgICAgICAgICAgIC8vRW50ZXIgRnVsbCBTY3JlZW5cbiAgICAgICAgICAgIGlmIChmc0VsZW1lbnQubW96UmVxdWVzdEZ1bGxTY3JlZW4pIHtcbiAgICAgICAgICAgICAgICBmc0VsZW1lbnQubW96UmVxdWVzdEZ1bGxTY3JlZW4oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGZzRWxlbWVudC53ZWJraXRSZXF1ZXN0RnVsbFNjcmVlbihFbGVtZW50LkFMTE9XX0tFWUJPQVJEX0lOUFVUKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vRXhpdCBGdWxsIFNjcmVlblxuICAgICAgICAgICAgaWYgKGRvY3VtZW50Lm1vekNhbmNlbEZ1bGxTY3JlZW4pIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5tb3pDYW5jZWxGdWxsU2NyZWVuKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LndlYmtpdENhbmNlbEZ1bGxTY3JlZW4oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogVW5sb2NrcyB0aGUgbG9jayBidXR0b24gc3RhdGUuXG4gICAgICovXG4gICAgbXkudW5sb2NrTG9ja0J1dHRvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCQoXCIjbG9ja0ljb25cIikuaGFzQ2xhc3MoXCJpY29uLXNlY3VyaXR5LWxvY2tlZFwiKSlcbiAgICAgICAgICAgIFVJVXRpbC5idXR0b25DbGljayhcIiNsb2NrSWNvblwiLCBcImljb24tc2VjdXJpdHkgaWNvbi1zZWN1cml0eS1sb2NrZWRcIik7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBsb2NrIGJ1dHRvbiBzdGF0ZSB0byBsb2NrZWQuXG4gICAgICovXG4gICAgbXkubG9ja0xvY2tCdXR0b24gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICgkKFwiI2xvY2tJY29uXCIpLmhhc0NsYXNzKFwiaWNvbi1zZWN1cml0eVwiKSlcbiAgICAgICAgICAgIFVJVXRpbC5idXR0b25DbGljayhcIiNsb2NrSWNvblwiLCBcImljb24tc2VjdXJpdHkgaWNvbi1zZWN1cml0eS1sb2NrZWRcIik7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIG9yIGhpZGVzIGF1dGhlbnRpY2F0aW9uIGJ1dHRvblxuICAgICAqIEBwYXJhbSBzaG93IDx0dD50cnVlPC90dD4gdG8gc2hvdyBvciA8dHQ+ZmFsc2U8L3R0PiB0byBoaWRlXG4gICAgICovXG4gICAgbXkuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbiA9IGZ1bmN0aW9uIChzaG93KSB7XG4gICAgICAgIGlmIChzaG93KSB7XG4gICAgICAgICAgICAkKCcjYXV0aGVudGljYXRpb24nKS5jc3Moe2Rpc3BsYXk6IFwiaW5saW5lXCJ9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICQoJyNhdXRoZW50aWNhdGlvbicpLmNzcyh7ZGlzcGxheTogXCJub25lXCJ9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBTaG93cyBvciBoaWRlcyB0aGUgJ3JlY29yZGluZycgYnV0dG9uLlxuICAgIG15LnNob3dSZWNvcmRpbmdCdXR0b24gPSBmdW5jdGlvbiAoc2hvdykge1xuICAgICAgICBpZiAoIWNvbmZpZy5lbmFibGVSZWNvcmRpbmcpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzaG93KSB7XG4gICAgICAgICAgICAkKCcjcmVjb3JkaW5nJykuY3NzKHtkaXNwbGF5OiBcImlubGluZVwifSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAkKCcjcmVjb3JkaW5nJykuY3NzKHtkaXNwbGF5OiBcIm5vbmVcIn0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8vIFNldHMgdGhlIHN0YXRlIG9mIHRoZSByZWNvcmRpbmcgYnV0dG9uXG4gICAgbXkuc2V0UmVjb3JkaW5nQnV0dG9uU3RhdGUgPSBmdW5jdGlvbiAoaXNSZWNvcmRpbmcpIHtcbiAgICAgICAgaWYgKGlzUmVjb3JkaW5nKSB7XG4gICAgICAgICAgICAkKCcjcmVjb3JkQnV0dG9uJykucmVtb3ZlQ2xhc3MoXCJpY29uLXJlY0VuYWJsZVwiKTtcbiAgICAgICAgICAgICQoJyNyZWNvcmRCdXR0b24nKS5hZGRDbGFzcyhcImljb24tcmVjRW5hYmxlIGFjdGl2ZVwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICQoJyNyZWNvcmRCdXR0b24nKS5yZW1vdmVDbGFzcyhcImljb24tcmVjRW5hYmxlIGFjdGl2ZVwiKTtcbiAgICAgICAgICAgICQoJyNyZWNvcmRCdXR0b24nKS5hZGRDbGFzcyhcImljb24tcmVjRW5hYmxlXCIpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8vIFNob3dzIG9yIGhpZGVzIFNJUCBjYWxscyBidXR0b25cbiAgICBteS5zaG93U2lwQ2FsbEJ1dHRvbiA9IGZ1bmN0aW9uIChzaG93KSB7XG4gICAgICAgIGlmIChBUFAueG1wcC5pc1NpcEdhdGV3YXlFbmFibGVkKCkgJiYgc2hvdykge1xuICAgICAgICAgICAgJCgnI3NpcENhbGxCdXR0b24nKS5jc3Moe2Rpc3BsYXk6IFwiaW5saW5lLWJsb2NrXCJ9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICQoJyNzaXBDYWxsQnV0dG9uJykuY3NzKHtkaXNwbGF5OiBcIm5vbmVcIn0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIERpc3BsYXlzIHVzZXIgYXV0aGVudGljYXRlZCBpZGVudGl0eSBuYW1lKGxvZ2luKS5cbiAgICAgKiBAcGFyYW0gYXV0aElkZW50aXR5IGlkZW50aXR5IG5hbWUgdG8gYmUgZGlzcGxheWVkLlxuICAgICAqL1xuICAgIG15LnNldEF1dGhlbnRpY2F0ZWRJZGVudGl0eSA9IGZ1bmN0aW9uIChhdXRoSWRlbnRpdHkpIHtcbiAgICAgICAgaWYgKGF1dGhJZGVudGl0eSkge1xuICAgICAgICAgICAgJCgnI3Rvb2xiYXJfYXV0aF9pZGVudGl0eScpLmNzcyh7ZGlzcGxheTogXCJsaXN0LWl0ZW1cIn0pO1xuICAgICAgICAgICAgJCgnI3Rvb2xiYXJfYXV0aF9pZGVudGl0eScpLnRleHQoYXV0aElkZW50aXR5KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICQoJyN0b29sYmFyX2F1dGhfaWRlbnRpdHknKS5jc3Moe2Rpc3BsYXk6IFwibm9uZVwifSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2hvd3MvaGlkZXMgbG9naW4gYnV0dG9uLlxuICAgICAqIEBwYXJhbSBzaG93IDx0dD50cnVlPC90dD4gdG8gc2hvd1xuICAgICAqL1xuICAgIG15LnNob3dMb2dpbkJ1dHRvbiA9IGZ1bmN0aW9uIChzaG93KSB7XG4gICAgICAgIGlmIChzaG93KSB7XG4gICAgICAgICAgICAkKCcjdG9vbGJhcl9idXR0b25fbG9naW4nKS5jc3Moe2Rpc3BsYXk6IFwibGlzdC1pdGVtXCJ9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICQoJyN0b29sYmFyX2J1dHRvbl9sb2dpbicpLmNzcyh7ZGlzcGxheTogXCJub25lXCJ9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cy9oaWRlcyBsb2dvdXQgYnV0dG9uLlxuICAgICAqIEBwYXJhbSBzaG93IDx0dD50cnVlPC90dD4gdG8gc2hvd1xuICAgICAqL1xuICAgIG15LnNob3dMb2dvdXRCdXR0b24gPSBmdW5jdGlvbiAoc2hvdykge1xuICAgICAgICBpZiAoc2hvdykge1xuICAgICAgICAgICAgJCgnI3Rvb2xiYXJfYnV0dG9uX2xvZ291dCcpLmNzcyh7ZGlzcGxheTogXCJsaXN0LWl0ZW1cIn0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgJCgnI3Rvb2xiYXJfYnV0dG9uX2xvZ291dCcpLmNzcyh7ZGlzcGxheTogXCJub25lXCJ9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdGF0ZSBvZiB0aGUgYnV0dG9uLiBUaGUgYnV0dG9uIGhhcyBibHVlIGdsb3cgaWYgZGVza3RvcFxuICAgICAqIHN0cmVhbWluZyBpcyBhY3RpdmUuXG4gICAgICogQHBhcmFtIGFjdGl2ZSB0aGUgc3RhdGUgb2YgdGhlIGRlc2t0b3Agc3RyZWFtaW5nLlxuICAgICAqL1xuICAgIG15LmNoYW5nZURlc2t0b3BTaGFyaW5nQnV0dG9uU3RhdGUgPSBmdW5jdGlvbiAoYWN0aXZlKSB7XG4gICAgICAgIHZhciBidXR0b24gPSAkKFwiI2Rlc2t0b3BzaGFyaW5nID4gYVwiKTtcbiAgICAgICAgaWYgKGFjdGl2ZSlcbiAgICAgICAge1xuICAgICAgICAgICAgYnV0dG9uLmFkZENsYXNzKFwiZ2xvd1wiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIGJ1dHRvbi5yZW1vdmVDbGFzcyhcImdsb3dcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIG15O1xufShUb29sYmFyIHx8IHt9KSk7XG5cbm1vZHVsZS5leHBvcnRzID0gVG9vbGJhcjsiLCIvKiBnbG9iYWwgJCwgaW50ZXJmYWNlQ29uZmlnLCBNb2RlcmF0b3IsIERlc2t0b3BTdHJlYW1pbmcuc2hvd0Rlc2t0b3BTaGFyaW5nQnV0dG9uICovXG5cbnZhciB0b29sYmFyVGltZW91dE9iamVjdCxcbiAgICB0b29sYmFyVGltZW91dCA9IGludGVyZmFjZUNvbmZpZy5JTklUSUFMX1RPT0xCQVJfVElNRU9VVDtcblxuZnVuY3Rpb24gc2hvd0Rlc2t0b3BTaGFyaW5nQnV0dG9uKCkge1xuICAgIGlmIChBUFAuZGVza3RvcHNoYXJpbmcuaXNEZXNrdG9wU2hhcmluZ0VuYWJsZWQoKSkge1xuICAgICAgICAkKCcjZGVza3RvcHNoYXJpbmcnKS5jc3Moe2Rpc3BsYXk6IFwiaW5saW5lXCJ9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgICAkKCcjZGVza3RvcHNoYXJpbmcnKS5jc3Moe2Rpc3BsYXk6IFwibm9uZVwifSk7XG4gICAgfVxufVxuXG4vKipcbiAqIEhpZGVzIHRoZSB0b29sYmFyLlxuICovXG5mdW5jdGlvbiBoaWRlVG9vbGJhcigpIHtcbiAgICB2YXIgaGVhZGVyID0gJChcIiNoZWFkZXJcIiksXG4gICAgICAgIGJvdHRvbVRvb2xiYXIgPSAkKFwiI2JvdHRvbVRvb2xiYXJcIik7XG4gICAgdmFyIGlzVG9vbGJhckhvdmVyID0gZmFsc2U7XG4gICAgaGVhZGVyLmZpbmQoJyonKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGlkID0gJCh0aGlzKS5hdHRyKCdpZCcpO1xuICAgICAgICBpZiAoJChcIiNcIiArIGlkICsgXCI6aG92ZXJcIikubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgaXNUb29sYmFySG92ZXIgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfSk7XG4gICAgaWYgKCQoXCIjYm90dG9tVG9vbGJhcjpob3ZlclwiKS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGlzVG9vbGJhckhvdmVyID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBjbGVhclRpbWVvdXQodG9vbGJhclRpbWVvdXRPYmplY3QpO1xuICAgIHRvb2xiYXJUaW1lb3V0T2JqZWN0ID0gbnVsbDtcblxuICAgIGlmICghaXNUb29sYmFySG92ZXIpIHtcbiAgICAgICAgaGVhZGVyLmhpZGUoXCJzbGlkZVwiLCB7IGRpcmVjdGlvbjogXCJ1cFwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgICAgICQoJyNzdWJqZWN0JykuYW5pbWF0ZSh7dG9wOiBcIi09NDBcIn0sIDMwMCk7XG4gICAgICAgIGlmICgkKFwiI3JlbW90ZVZpZGVvc1wiKS5oYXNDbGFzcyhcImhpZGRlblwiKSkge1xuICAgICAgICAgICAgYm90dG9tVG9vbGJhci5oaWRlKFxuICAgICAgICAgICAgICAgIFwic2xpZGVcIiwge2RpcmVjdGlvbjogXCJyaWdodFwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRvb2xiYXJUaW1lb3V0T2JqZWN0ID0gc2V0VGltZW91dChoaWRlVG9vbGJhciwgdG9vbGJhclRpbWVvdXQpO1xuICAgIH1cbn1cblxudmFyIFRvb2xiYXJUb2dnbGVyID0ge1xuICAgIC8qKlxuICAgICAqIFNob3dzIHRoZSBtYWluIHRvb2xiYXIuXG4gICAgICovXG4gICAgc2hvd1Rvb2xiYXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGhlYWRlciA9ICQoXCIjaGVhZGVyXCIpLFxuICAgICAgICAgICAgYm90dG9tVG9vbGJhciA9ICQoXCIjYm90dG9tVG9vbGJhclwiKTtcbiAgICAgICAgaWYgKCFoZWFkZXIuaXMoJzp2aXNpYmxlJykgfHwgIWJvdHRvbVRvb2xiYXIuaXMoXCI6dmlzaWJsZVwiKSkge1xuICAgICAgICAgICAgaGVhZGVyLnNob3coXCJzbGlkZVwiLCB7IGRpcmVjdGlvbjogXCJ1cFwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgICAgICAgICAkKCcjc3ViamVjdCcpLmFuaW1hdGUoe3RvcDogXCIrPTQwXCJ9LCAzMDApO1xuICAgICAgICAgICAgaWYgKCFib3R0b21Ub29sYmFyLmlzKFwiOnZpc2libGVcIikpIHtcbiAgICAgICAgICAgICAgICBib3R0b21Ub29sYmFyLnNob3coXG4gICAgICAgICAgICAgICAgICAgIFwic2xpZGVcIiwge2RpcmVjdGlvbjogXCJyaWdodFwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0b29sYmFyVGltZW91dE9iamVjdCkge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0b29sYmFyVGltZW91dE9iamVjdCk7XG4gICAgICAgICAgICAgICAgdG9vbGJhclRpbWVvdXRPYmplY3QgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdG9vbGJhclRpbWVvdXRPYmplY3QgPSBzZXRUaW1lb3V0KGhpZGVUb29sYmFyLCB0b29sYmFyVGltZW91dCk7XG4gICAgICAgICAgICB0b29sYmFyVGltZW91dCA9IGludGVyZmFjZUNvbmZpZy5UT09MQkFSX1RJTUVPVVQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoQVBQLnhtcHAuaXNNb2RlcmF0b3IoKSlcbiAgICAgICAge1xuLy8gICAgICAgICAgICBUT0RPOiBFbmFibGUgc2V0dGluZ3MgZnVuY3Rpb25hbGl0eS5cbi8vICAgICAgICAgICAgICAgICAgTmVlZCB0byB1bmNvbW1lbnQgdGhlIHNldHRpbmdzIGJ1dHRvbiBpbiBpbmRleC5odG1sLlxuLy8gICAgICAgICAgICAkKCcjc2V0dGluZ3NCdXR0b24nKS5jc3Moe3Zpc2liaWxpdHk6XCJ2aXNpYmxlXCJ9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNob3cvaGlkZSBkZXNrdG9wIHNoYXJpbmcgYnV0dG9uXG4gICAgICAgIHNob3dEZXNrdG9wU2hhcmluZ0J1dHRvbigpO1xuICAgIH0sXG5cblxuICAgIC8qKlxuICAgICAqIERvY2tzL3VuZG9ja3MgdGhlIHRvb2xiYXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gaXNEb2NrIGluZGljYXRlcyB3aGF0IG9wZXJhdGlvbiB0byBwZXJmb3JtXG4gICAgICovXG4gICAgZG9ja1Rvb2xiYXI6IGZ1bmN0aW9uIChpc0RvY2spIHtcbiAgICAgICAgaWYgKGlzRG9jaykge1xuICAgICAgICAgICAgLy8gRmlyc3QgbWFrZSBzdXJlIHRoZSB0b29sYmFyIGlzIHNob3duLlxuICAgICAgICAgICAgaWYgKCEkKCcjaGVhZGVyJykuaXMoJzp2aXNpYmxlJykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNob3dUb29sYmFyKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFRoZW4gY2xlYXIgdGhlIHRpbWUgb3V0LCB0byBkb2NrIHRoZSB0b29sYmFyLlxuICAgICAgICAgICAgaWYgKHRvb2xiYXJUaW1lb3V0T2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRvb2xiYXJUaW1lb3V0T2JqZWN0KTtcbiAgICAgICAgICAgICAgICB0b29sYmFyVGltZW91dE9iamVjdCA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBpZiAoISQoJyNoZWFkZXInKS5pcygnOnZpc2libGUnKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2hvd1Rvb2xiYXIoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRvb2xiYXJUaW1lb3V0T2JqZWN0ID0gc2V0VGltZW91dChoaWRlVG9vbGJhciwgdG9vbGJhclRpbWVvdXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSxcblxuICAgIHNob3dEZXNrdG9wU2hhcmluZ0J1dHRvbjogc2hvd0Rlc2t0b3BTaGFyaW5nQnV0dG9uXG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gVG9vbGJhclRvZ2dsZXI7IiwidmFyIEppdHNpUG9wb3ZlciA9IChmdW5jdGlvbiAoKSB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0cyBuZXcgSml0c2lQb3BvdmVyIGFuZCBhdHRhY2hlcyBpdCB0byB0aGUgZWxlbWVudFxuICAgICAqIEBwYXJhbSBlbGVtZW50IGpxdWVyeSBzZWxlY3RvclxuICAgICAqIEBwYXJhbSBvcHRpb25zIHRoZSBvcHRpb25zIGZvciB0aGUgcG9wb3Zlci5cbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBKaXRzaVBvcG92ZXIoZWxlbWVudCwgb3B0aW9ucylcbiAgICB7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9IHtcbiAgICAgICAgICAgIHNraW46IFwid2hpdGVcIixcbiAgICAgICAgICAgIGNvbnRlbnQ6IFwiXCJcbiAgICAgICAgfTtcbiAgICAgICAgaWYob3B0aW9ucylcbiAgICAgICAge1xuICAgICAgICAgICAgaWYob3B0aW9ucy5za2luKVxuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5za2luID0gb3B0aW9ucy5za2luO1xuXG4gICAgICAgICAgICBpZihvcHRpb25zLmNvbnRlbnQpXG4gICAgICAgICAgICAgICAgdGhpcy5vcHRpb25zLmNvbnRlbnQgPSBvcHRpb25zLmNvbnRlbnQ7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmVsZW1lbnRJc0hvdmVyZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5wb3BvdmVySXNIb3ZlcmVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMucG9wb3ZlclNob3duID0gZmFsc2U7XG5cbiAgICAgICAgZWxlbWVudC5kYXRhKFwiaml0c2lfcG9wb3ZlclwiLCB0aGlzKTtcbiAgICAgICAgdGhpcy5lbGVtZW50ID0gZWxlbWVudDtcbiAgICAgICAgdGhpcy50ZW1wbGF0ZSA9ICcgPGRpdiBjbGFzcz1cImppdHNpcG9wb3ZlciAnICsgdGhpcy5vcHRpb25zLnNraW4gK1xuICAgICAgICAgICAgJ1wiPjxkaXYgY2xhc3M9XCJhcnJvd1wiPjwvZGl2PjxkaXYgY2xhc3M9XCJqaXRzaXBvcG92ZXItY29udGVudFwiPjwvZGl2PicgK1xuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJqaXRzaVBvcHVwbWVudVBhZGRpbmdcIj48L2Rpdj48L2Rpdj4nO1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHRoaXMuZWxlbWVudC5vbihcIm1vdXNlZW50ZXJcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi5lbGVtZW50SXNIb3ZlcmVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHNlbGYuc2hvdygpO1xuICAgICAgICB9KS5vbihcIm1vdXNlbGVhdmVcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi5lbGVtZW50SXNIb3ZlcmVkID0gZmFsc2U7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBzZWxmLmhpZGUoKTtcbiAgICAgICAgICAgIH0sIDEwKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2hvd3MgdGhlIHBvcG92ZXJcbiAgICAgKi9cbiAgICBKaXRzaVBvcG92ZXIucHJvdG90eXBlLnNob3cgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuY3JlYXRlUG9wb3ZlcigpO1xuICAgICAgICB0aGlzLnBvcG92ZXJTaG93biA9IHRydWU7XG5cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSGlkZXMgdGhlIHBvcG92ZXJcbiAgICAgKi9cbiAgICBKaXRzaVBvcG92ZXIucHJvdG90eXBlLmhpZGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmKCF0aGlzLmVsZW1lbnRJc0hvdmVyZWQgJiYgIXRoaXMucG9wb3ZlcklzSG92ZXJlZCAmJiB0aGlzLnBvcG92ZXJTaG93bilcbiAgICAgICAge1xuICAgICAgICAgICAgdGhpcy5mb3JjZUhpZGUoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBIaWRlcyB0aGUgcG9wb3ZlclxuICAgICAqL1xuICAgIEppdHNpUG9wb3Zlci5wcm90b3R5cGUuZm9yY2VIaWRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAkKFwiLmppdHNpcG9wb3ZlclwiKS5yZW1vdmUoKTtcbiAgICAgICAgdGhpcy5wb3BvdmVyU2hvd24gPSBmYWxzZTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyB0aGUgcG9wb3ZlciBodG1sXG4gICAgICovXG4gICAgSml0c2lQb3BvdmVyLnByb3RvdHlwZS5jcmVhdGVQb3BvdmVyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAkKFwiYm9keVwiKS5hcHBlbmQodGhpcy50ZW1wbGF0ZSk7XG4gICAgICAgICQoXCIuaml0c2lwb3BvdmVyID4gLmppdHNpcG9wb3Zlci1jb250ZW50XCIpLmh0bWwodGhpcy5vcHRpb25zLmNvbnRlbnQpO1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICQoXCIuaml0c2lwb3BvdmVyXCIpLm9uKFwibW91c2VlbnRlclwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBzZWxmLnBvcG92ZXJJc0hvdmVyZWQgPSB0cnVlO1xuICAgICAgICB9KS5vbihcIm1vdXNlbGVhdmVcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi5wb3BvdmVySXNIb3ZlcmVkID0gZmFsc2U7XG4gICAgICAgICAgICBzZWxmLmhpZGUoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5yZWZyZXNoUG9zaXRpb24oKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmVmcmVzaGVzIHRoZSBwb3NpdGlvbiBvZiB0aGUgcG9wb3ZlclxuICAgICAqL1xuICAgIEppdHNpUG9wb3Zlci5wcm90b3R5cGUucmVmcmVzaFBvc2l0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAkKFwiLmppdHNpcG9wb3ZlclwiKS5wb3NpdGlvbih7XG4gICAgICAgICAgICBteTogXCJib3R0b21cIixcbiAgICAgICAgICAgIGF0OiBcInRvcFwiLFxuICAgICAgICAgICAgY29sbGlzaW9uOiBcImZpdFwiLFxuICAgICAgICAgICAgb2Y6IHRoaXMuZWxlbWVudCxcbiAgICAgICAgICAgIHVzaW5nOiBmdW5jdGlvbiAocG9zaXRpb24sIGVsZW1lbnRzKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNhbGNMZWZ0ID0gZWxlbWVudHMudGFyZ2V0LmxlZnQgLSBlbGVtZW50cy5lbGVtZW50LmxlZnQgKyBlbGVtZW50cy50YXJnZXQud2lkdGgvMjtcbiAgICAgICAgICAgICAgICAkKFwiLmppdHNpcG9wb3ZlclwiKS5jc3Moe3RvcDogcG9zaXRpb24udG9wLCBsZWZ0OiBwb3NpdGlvbi5sZWZ0LCBkaXNwbGF5OiBcInRhYmxlXCJ9KTtcbiAgICAgICAgICAgICAgICAkKFwiLmppdHNpcG9wb3ZlciA+IC5hcnJvd1wiKS5jc3Moe2xlZnQ6IGNhbGNMZWZ0fSk7XG4gICAgICAgICAgICAgICAgJChcIi5qaXRzaXBvcG92ZXIgPiAuaml0c2lQb3B1cG1lbnVQYWRkaW5nXCIpLmNzcyh7bGVmdDogY2FsY0xlZnQgLSA1MH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgY29udGVudCBvZiBwb3BvdmVyLlxuICAgICAqIEBwYXJhbSBjb250ZW50IG5ldyBjb250ZW50XG4gICAgICovXG4gICAgSml0c2lQb3BvdmVyLnByb3RvdHlwZS51cGRhdGVDb250ZW50ID0gZnVuY3Rpb24gKGNvbnRlbnQpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zLmNvbnRlbnQgPSBjb250ZW50O1xuICAgICAgICBpZighdGhpcy5wb3BvdmVyU2hvd24pXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICQoXCIuaml0c2lwb3BvdmVyXCIpLnJlbW92ZSgpO1xuICAgICAgICB0aGlzLmNyZWF0ZVBvcG92ZXIoKTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIEppdHNpUG9wb3ZlcjtcblxuXG59KSgpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEppdHNpUG9wb3ZlcjsiLCIvKiBnbG9iYWwgJCwgQVBQLCBqUXVlcnksIHRvYXN0ciAqL1xudmFyIG1lc3NhZ2VIYW5kbGVyID0gKGZ1bmN0aW9uKG15KSB7XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyBhIG1lc3NhZ2UgdG8gdGhlIHVzZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdGl0bGVTdHJpbmcgdGhlIHRpdGxlIG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIG1lc3NhZ2VTdHJpbmcgdGhlIHRleHQgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKi9cbiAgICBteS5vcGVuTWVzc2FnZURpYWxvZyA9IGZ1bmN0aW9uKHRpdGxlS2V5LCBtZXNzYWdlS2V5KSB7XG4gICAgICAgIHZhciB0aXRsZSA9IG51bGw7XG4gICAgICAgIGlmKHRpdGxlS2V5KVxuICAgICAgICB7XG4gICAgICAgICAgICB0aXRsZSA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKHRpdGxlS2V5KTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgbWVzc2FnZSA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKG1lc3NhZ2VLZXkpO1xuICAgICAgICAkLnByb21wdChtZXNzYWdlLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHRpdGxlOiB0aXRsZSxcbiAgICAgICAgICAgICAgICBwZXJzaXN0ZW50OiBmYWxzZVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyBhIG1lc3NhZ2UgdG8gdGhlIHVzZXIgd2l0aCB0d28gYnV0dG9uczogZmlyc3QgaXMgZ2l2ZW4gYXMgYSBwYXJhbWV0ZXIgYW5kIHRoZSBzZWNvbmQgaXMgQ2FuY2VsLlxuICAgICAqXG4gICAgICogQHBhcmFtIHRpdGxlU3RyaW5nIHRoZSB0aXRsZSBvZiB0aGUgbWVzc2FnZVxuICAgICAqIEBwYXJhbSBtc2dTdHJpbmcgdGhlIHRleHQgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gcGVyc2lzdGVudCBib29sZWFuIHZhbHVlIHdoaWNoIGRldGVybWluZXMgd2hldGhlciB0aGUgbWVzc2FnZSBpcyBwZXJzaXN0ZW50IG9yIG5vdFxuICAgICAqIEBwYXJhbSBsZWZ0QnV0dG9uIHRoZSBmaXN0IGJ1dHRvbidzIHRleHRcbiAgICAgKiBAcGFyYW0gc3VibWl0RnVuY3Rpb24gZnVuY3Rpb24gdG8gYmUgY2FsbGVkIG9uIHN1Ym1pdFxuICAgICAqIEBwYXJhbSBsb2FkZWRGdW5jdGlvbiBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYWZ0ZXIgdGhlIHByb21wdCBpcyBmdWxseSBsb2FkZWRcbiAgICAgKiBAcGFyYW0gY2xvc2VGdW5jdGlvbiBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYWZ0ZXIgdGhlIHByb21wdCBpcyBjbG9zZWRcbiAgICAgKiBAcGFyYW0gZm9jdXMgb3B0aW9uYWwgZm9jdXMgc2VsZWN0b3Igb3IgYnV0dG9uIGluZGV4IHRvIGJlIGZvY3VzZWQgYWZ0ZXJcbiAgICAgKiAgICAgICAgdGhlIGRpYWxvZyBpcyBvcGVuZWRcbiAgICAgKiBAcGFyYW0gZGVmYXVsdEJ1dHRvbiBpbmRleCBvZiBkZWZhdWx0IGJ1dHRvbiB3aGljaCB3aWxsIGJlIGFjdGl2YXRlZCB3aGVuXG4gICAgICogICAgICAgIHRoZSB1c2VyIHByZXNzICdlbnRlcicuIEluZGV4ZWQgZnJvbSAwLlxuICAgICAqL1xuICAgIG15Lm9wZW5Ud29CdXR0b25EaWFsb2cgPSBmdW5jdGlvbih0aXRsZUtleSwgdGl0bGVTdHJpbmcsIG1zZ0tleSwgbXNnU3RyaW5nLFxuICAgICAgICBwZXJzaXN0ZW50LCBsZWZ0QnV0dG9uS2V5LCBzdWJtaXRGdW5jdGlvbiwgbG9hZGVkRnVuY3Rpb24sXG4gICAgICAgIGNsb3NlRnVuY3Rpb24sIGZvY3VzLCBkZWZhdWx0QnV0dG9uKVxuICAgIHtcbiAgICAgICAgdmFyIGJ1dHRvbnMgPSBbXTtcblxuICAgICAgICB2YXIgbGVmdEJ1dHRvbiA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKGxlZnRCdXR0b25LZXkpO1xuICAgICAgICBidXR0b25zLnB1c2goeyB0aXRsZTogbGVmdEJ1dHRvbiwgdmFsdWU6IHRydWV9KTtcblxuICAgICAgICB2YXIgY2FuY2VsQnV0dG9uXG4gICAgICAgICAgICA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKFwiZGlhbG9nLkNhbmNlbFwiKTtcbiAgICAgICAgYnV0dG9ucy5wdXNoKHt0aXRsZTogY2FuY2VsQnV0dG9uLCB2YWx1ZTogZmFsc2V9KTtcblxuICAgICAgICB2YXIgbWVzc2FnZSA9IG1zZ1N0cmluZywgdGl0bGUgPSB0aXRsZVN0cmluZztcbiAgICAgICAgaWYgKHRpdGxlS2V5KVxuICAgICAgICB7XG4gICAgICAgICAgICB0aXRsZSA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKHRpdGxlS2V5KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobXNnS2V5KSB7XG4gICAgICAgICAgICBtZXNzYWdlID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwobXNnS2V5KTtcbiAgICAgICAgfVxuICAgICAgICAkLnByb21wdChtZXNzYWdlLCB7XG4gICAgICAgICAgICB0aXRsZTogdGl0bGUsXG4gICAgICAgICAgICBwZXJzaXN0ZW50OiBmYWxzZSxcbiAgICAgICAgICAgIGJ1dHRvbnM6IGJ1dHRvbnMsXG4gICAgICAgICAgICBkZWZhdWx0QnV0dG9uOiBkZWZhdWx0QnV0dG9uLFxuICAgICAgICAgICAgZm9jdXM6IGZvY3VzLFxuICAgICAgICAgICAgbG9hZGVkOiBsb2FkZWRGdW5jdGlvbixcbiAgICAgICAgICAgIHN1Ym1pdDogc3VibWl0RnVuY3Rpb24sXG4gICAgICAgICAgICBjbG9zZTogY2xvc2VGdW5jdGlvblxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2hvd3MgYSBtZXNzYWdlIHRvIHRoZSB1c2VyIHdpdGggdHdvIGJ1dHRvbnM6IGZpcnN0IGlzIGdpdmVuIGFzIGEgcGFyYW1ldGVyIGFuZCB0aGUgc2Vjb25kIGlzIENhbmNlbC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB0aXRsZVN0cmluZyB0aGUgdGl0bGUgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gbXNnU3RyaW5nIHRoZSB0ZXh0IG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIHBlcnNpc3RlbnQgYm9vbGVhbiB2YWx1ZSB3aGljaCBkZXRlcm1pbmVzIHdoZXRoZXIgdGhlIG1lc3NhZ2UgaXMgcGVyc2lzdGVudCBvciBub3RcbiAgICAgKiBAcGFyYW0gYnV0dG9ucyBvYmplY3Qgd2l0aCB0aGUgYnV0dG9ucy4gVGhlIGtleXMgbXVzdCBiZSB0aGUgbmFtZSBvZiB0aGUgYnV0dG9uIGFuZCB2YWx1ZSBpcyB0aGUgdmFsdWVcbiAgICAgKiB0aGF0IHdpbGwgYmUgcGFzc2VkIHRvIHN1Ym1pdEZ1bmN0aW9uXG4gICAgICogQHBhcmFtIHN1Ym1pdEZ1bmN0aW9uIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBvbiBzdWJtaXRcbiAgICAgKiBAcGFyYW0gbG9hZGVkRnVuY3Rpb24gZnVuY3Rpb24gdG8gYmUgY2FsbGVkIGFmdGVyIHRoZSBwcm9tcHQgaXMgZnVsbHkgbG9hZGVkXG4gICAgICovXG4gICAgbXkub3BlbkRpYWxvZyA9IGZ1bmN0aW9uICh0aXRsZVN0cmluZywgbXNnU3RyaW5nLCBwZXJzaXN0ZW50LCBidXR0b25zLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VibWl0RnVuY3Rpb24sIGxvYWRlZEZ1bmN0aW9uKSB7XG4gICAgICAgIHZhciBhcmdzID0ge1xuICAgICAgICAgICAgdGl0bGU6IHRpdGxlU3RyaW5nLFxuICAgICAgICAgICAgcGVyc2lzdGVudDogcGVyc2lzdGVudCxcbiAgICAgICAgICAgIGJ1dHRvbnM6IGJ1dHRvbnMsXG4gICAgICAgICAgICBkZWZhdWx0QnV0dG9uOiAxLFxuICAgICAgICAgICAgbG9hZGVkOiBsb2FkZWRGdW5jdGlvbixcbiAgICAgICAgICAgIHN1Ym1pdDogc3VibWl0RnVuY3Rpb25cbiAgICAgICAgfTtcbiAgICAgICAgaWYgKHBlcnNpc3RlbnQpIHtcbiAgICAgICAgICAgIGFyZ3MuY2xvc2VUZXh0ID0gJyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBJbXByb21wdHUobXNnU3RyaW5nLCBhcmdzKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2xvc2VzIGN1cnJlbnRseSBvcGVuZWQgZGlhbG9nLlxuICAgICAqL1xuICAgIG15LmNsb3NlRGlhbG9nID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAkLnByb21wdC5jbG9zZSgpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyBhIGRpYWxvZyB3aXRoIGRpZmZlcmVudCBzdGF0ZXMgdG8gdGhlIHVzZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RhdGVzT2JqZWN0IG9iamVjdCBjb250YWluaW5nIGFsbCB0aGUgc3RhdGVzIG9mIHRoZSBkaWFsb2dcbiAgICAgKi9cbiAgICBteS5vcGVuRGlhbG9nV2l0aFN0YXRlcyA9IGZ1bmN0aW9uIChzdGF0ZXNPYmplY3QsIG9wdGlvbnMpIHtcblxuICAgICAgICByZXR1cm4gbmV3IEltcHJvbXB0dShzdGF0ZXNPYmplY3QsIG9wdGlvbnMpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPcGVucyBuZXcgcG9wdXAgd2luZG93IGZvciBnaXZlbiA8dHQ+dXJsPC90dD4gY2VudGVyZWQgb3ZlciBjdXJyZW50XG4gICAgICogd2luZG93LlxuICAgICAqXG4gICAgICogQHBhcmFtIHVybCB0aGUgVVJMIHRvIGJlIGRpc3BsYXllZCBpbiB0aGUgcG9wdXAgd2luZG93XG4gICAgICogQHBhcmFtIHcgdGhlIHdpZHRoIG9mIHRoZSBwb3B1cCB3aW5kb3dcbiAgICAgKiBAcGFyYW0gaCB0aGUgaGVpZ2h0IG9mIHRoZSBwb3B1cCB3aW5kb3dcbiAgICAgKiBAcGFyYW0gb25Qb3B1cENsb3NlZCBvcHRpb25hbCBjYWxsYmFjayBmdW5jdGlvbiBjYWxsZWQgd2hlbiBwb3B1cCB3aW5kb3dcbiAgICAgKiAgICAgICAgaGFzIGJlZW4gY2xvc2VkLlxuICAgICAqXG4gICAgICogQHJldHVybnMgcG9wdXAgd2luZG93IG9iamVjdCBpZiBvcGVuZWQgc3VjY2Vzc2Z1bGx5IG9yIHVuZGVmaW5lZFxuICAgICAqICAgICAgICAgIGluIGNhc2Ugd2UgZmFpbGVkIHRvIG9wZW4gaXQocG9wdXAgYmxvY2tlZClcbiAgICAgKi9cbiAgICBteS5vcGVuQ2VudGVyZWRQb3B1cCA9IGZ1bmN0aW9uICh1cmwsIHcsIGgsIG9uUG9wdXBDbG9zZWQpIHtcbiAgICAgICAgdmFyIGwgPSB3aW5kb3cuc2NyZWVuWCArICh3aW5kb3cuaW5uZXJXaWR0aCAvIDIpIC0gKHcgLyAyKTtcbiAgICAgICAgdmFyIHQgPSB3aW5kb3cuc2NyZWVuWSArICh3aW5kb3cuaW5uZXJIZWlnaHQgLyAyKSAtIChoIC8gMik7XG4gICAgICAgIHZhciBwb3B1cCA9IHdpbmRvdy5vcGVuKFxuICAgICAgICAgICAgdXJsLCAnX2JsYW5rJyxcbiAgICAgICAgICAgICd0b3A9JyArIHQgKyAnLCBsZWZ0PScgKyBsICsgJywgd2lkdGg9JyArIHcgKyAnLCBoZWlnaHQ9JyArIGggKyAnJyk7XG4gICAgICAgIGlmIChwb3B1cCAmJiBvblBvcHVwQ2xvc2VkKSB7XG4gICAgICAgICAgICB2YXIgcG9sbFRpbWVyID0gd2luZG93LnNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAocG9wdXAuY2xvc2VkICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbChwb2xsVGltZXIpO1xuICAgICAgICAgICAgICAgICAgICBvblBvcHVwQ2xvc2VkKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgMjAwKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcG9wdXA7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgZGlhbG9nIHByb21wdGluZyB0aGUgdXNlciB0byBzZW5kIGFuIGVycm9yIHJlcG9ydC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB0aXRsZVN0cmluZyB0aGUgdGl0bGUgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gbXNnU3RyaW5nIHRoZSB0ZXh0IG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIGVycm9yIHRoZSBlcnJvciB0aGF0IGlzIGJlaW5nIHJlcG9ydGVkXG4gICAgICovXG4gICAgbXkub3BlblJlcG9ydERpYWxvZyA9IGZ1bmN0aW9uKHRpdGxlS2V5LCBtc2dLZXksIGVycm9yKSB7XG4gICAgICAgIG15Lm9wZW5NZXNzYWdlRGlhbG9nKHRpdGxlS2V5LCBtc2dLZXkpO1xuICAgICAgICBjb25zb2xlLmxvZyhlcnJvcik7XG4gICAgICAgIC8vRklYTUUgc2VuZCB0aGUgZXJyb3IgdG8gdGhlIHNlcnZlclxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiAgU2hvd3MgYW4gZXJyb3IgZGlhbG9nIHRvIHRoZSB1c2VyLlxuICAgICAqIEBwYXJhbSB0aXRsZSB0aGUgdGl0bGUgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSB0aGUgdGV4dCBvZiB0aGUgbWVzc2FmZVxuICAgICAqL1xuICAgIG15LnNob3dFcnJvciA9IGZ1bmN0aW9uKHRpdGxlS2V5LCBtc2dLZXkpIHtcblxuICAgICAgICBpZighdGl0bGVLZXkpIHtcbiAgICAgICAgICAgIHRpdGxlS2V5ID0gXCJkaWFsb2cub29wc1wiO1xuICAgICAgICB9XG4gICAgICAgIGlmKCFtc2dLZXkpXG4gICAgICAgIHtcbiAgICAgICAgICAgIG1zZ0tleSA9IFwiZGlhbG9nLmRlZmF1bHRFcnJvclwiO1xuICAgICAgICB9XG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5NZXNzYWdlRGlhbG9nKHRpdGxlS2V5LCBtc2dLZXkpO1xuICAgIH07XG5cbiAgICBteS5ub3RpZnkgPSBmdW5jdGlvbihkaXNwbGF5TmFtZSwgZGlzcGxheU5hbWVLZXksXG4gICAgICAgICAgICAgICAgICAgICAgICAgY2xzLCBtZXNzYWdlS2V5LCBtZXNzYWdlQXJndW1lbnRzKSB7XG4gICAgICAgIHZhciBkaXNwbGF5TmFtZVNwYW4gPSAnPHNwYW4gY2xhc3M9XCJuaWNrbmFtZVwiICc7XG4gICAgICAgIGlmKGRpc3BsYXlOYW1lKVxuICAgICAgICB7XG4gICAgICAgICAgICBkaXNwbGF5TmFtZVNwYW4gKz0gXCI+XCIgKyBkaXNwbGF5TmFtZTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIGRpc3BsYXlOYW1lU3BhbiArPSBcImRhdGEtaTE4bj0nXCIgKyBkaXNwbGF5TmFtZUtleSArXG4gICAgICAgICAgICAgICAgXCInPlwiICsgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhkaXNwbGF5TmFtZUtleSk7XG4gICAgICAgIH1cbiAgICAgICAgZGlzcGxheU5hbWVTcGFuICs9IFwiPC9zcGFuPlwiO1xuICAgICAgICB0b2FzdHIuaW5mbyhcbiAgICAgICAgICAgIGRpc3BsYXlOYW1lU3BhbiArICc8YnI+JyArXG4gICAgICAgICAgICAnPHNwYW4gY2xhc3M9JyArIGNscyArICcgZGF0YS1pMThuPVwiJyArIG1lc3NhZ2VLZXkgKyAnXCInICtcbiAgICAgICAgICAgICAgICAobWVzc2FnZUFyZ3VtZW50cz9cbiAgICAgICAgICAgICAgICAgICAgXCIgZGF0YS1pMThuLW9wdGlvbnM9J1wiICsgSlNPTi5zdHJpbmdpZnkobWVzc2FnZUFyZ3VtZW50cykgKyBcIidcIlxuICAgICAgICAgICAgICAgICAgICA6IFwiXCIpICsgXCI+XCIgK1xuICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhtZXNzYWdlS2V5LFxuICAgICAgICAgICAgICAgIG1lc3NhZ2VBcmd1bWVudHMpICtcbiAgICAgICAgICAgICc8L3NwYW4+Jyk7XG4gICAgfTtcblxuICAgIHJldHVybiBteTtcbn0obWVzc2FnZUhhbmRsZXIgfHwge30pKTtcblxubW9kdWxlLmV4cG9ydHMgPSBtZXNzYWdlSGFuZGxlcjtcblxuXG4iLCJ2YXIgVUlFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vLi4vc2VydmljZS9VSS9VSUV2ZW50c1wiKTtcblxudmFyIG5pY2tuYW1lID0gbnVsbDtcbnZhciBldmVudEVtaXR0ZXIgPSBudWxsO1xuXG52YXIgTmlja2FuYW1lSGFuZGxlciA9IHtcbiAgICBpbml0OiBmdW5jdGlvbiAoZW1pdHRlcikge1xuICAgICAgICBldmVudEVtaXR0ZXIgPSBlbWl0dGVyO1xuICAgICAgICB2YXIgc3RvcmVkRGlzcGxheU5hbWUgPSB3aW5kb3cubG9jYWxTdG9yYWdlLmRpc3BsYXluYW1lO1xuICAgICAgICBpZiAoc3RvcmVkRGlzcGxheU5hbWUpIHtcbiAgICAgICAgICAgIG5pY2tuYW1lID0gc3RvcmVkRGlzcGxheU5hbWU7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHNldE5pY2tuYW1lOiBmdW5jdGlvbiAobmV3Tmlja25hbWUpIHtcbiAgICAgICAgaWYgKCFuZXdOaWNrbmFtZSB8fCBuaWNrbmFtZSA9PT0gbmV3Tmlja25hbWUpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgbmlja25hbWUgPSBuZXdOaWNrbmFtZTtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZSA9IG5pY2tuYW1lO1xuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChVSUV2ZW50cy5OSUNLTkFNRV9DSEFOR0VELCBuZXdOaWNrbmFtZSk7XG4gICAgfSxcbiAgICBnZXROaWNrbmFtZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbmlja25hbWU7XG4gICAgfSxcbiAgICBhZGRMaXN0ZW5lcjogZnVuY3Rpb24gKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5vbih0eXBlLCBsaXN0ZW5lcik7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBOaWNrYW5hbWVIYW5kbGVyOyIsIi8qKlxuICogQ3JlYXRlZCBieSBocmlzdG8gb24gMTIvMjIvMTQuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGF2YWlsYWJsZSB2aWRlbyB3aWR0aC5cbiAgICAgKi9cbiAgICBnZXRBdmFpbGFibGVWaWRlb1dpZHRoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBQYW5lbFRvZ2dsZXIgPSByZXF1aXJlKFwiLi4vc2lkZV9wYW5uZWxzL1NpZGVQYW5lbFRvZ2dsZXJcIik7XG4gICAgICAgIHZhciByaWdodFBhbmVsV2lkdGhcbiAgICAgICAgICAgID0gUGFuZWxUb2dnbGVyLmlzVmlzaWJsZSgpID8gUGFuZWxUb2dnbGVyLmdldFBhbmVsU2l6ZSgpWzBdIDogMDtcblxuICAgICAgICByZXR1cm4gd2luZG93LmlubmVyV2lkdGggLSByaWdodFBhbmVsV2lkdGg7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBDaGFuZ2VzIHRoZSBzdHlsZSBjbGFzcyBvZiB0aGUgZWxlbWVudCBnaXZlbiBieSBpZC5cbiAgICAgKi9cbiAgICBidXR0b25DbGljazogZnVuY3Rpb24oaWQsIGNsYXNzbmFtZSkge1xuICAgICAgICAkKGlkKS50b2dnbGVDbGFzcyhjbGFzc25hbWUpOyAvLyBhZGQgdGhlIGNsYXNzIHRvIHRoZSBjbGlja2VkIGVsZW1lbnRcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHRleHQgd2lkdGggZm9yIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogQHBhcmFtIGVsIHRoZSBlbGVtZW50XG4gICAgICovXG4gICAgZ2V0VGV4dFdpZHRoOiBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgcmV0dXJuIChlbC5jbGllbnRXaWR0aCArIDEpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSB0ZXh0IGhlaWdodCBmb3IgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZWwgdGhlIGVsZW1lbnRcbiAgICAgKi9cbiAgICBnZXRUZXh0SGVpZ2h0OiBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgcmV0dXJuIChlbC5jbGllbnRIZWlnaHQgKyAxKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUGxheXMgdGhlIHNvdW5kIGdpdmVuIGJ5IGlkLlxuICAgICAqXG4gICAgICogQHBhcmFtIGlkIHRoZSBpZGVudGlmaWVyIG9mIHRoZSBhdWRpbyBlbGVtZW50LlxuICAgICAqL1xuICAgIHBsYXlTb3VuZE5vdGlmaWNhdGlvbjogZnVuY3Rpb24gKGlkKSB7XG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKS5wbGF5KCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEVzY2FwZXMgdGhlIGdpdmVuIHRleHQuXG4gICAgICovXG4gICAgZXNjYXBlSHRtbDogZnVuY3Rpb24gKHVuc2FmZVRleHQpIHtcbiAgICAgICAgcmV0dXJuICQoJzxkaXYvPicpLnRleHQodW5zYWZlVGV4dCkuaHRtbCgpO1xuICAgIH0sXG5cbiAgICBpbWFnZVRvR3JheVNjYWxlOiBmdW5jdGlvbiAoY2FudmFzKSB7XG4gICAgICAgIHZhciBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgICAgIHZhciBpbWdEYXRhID0gY29udGV4dC5nZXRJbWFnZURhdGEoMCwgMCwgY2FudmFzLndpZHRoLCBjYW52YXMuaGVpZ2h0KTtcbiAgICAgICAgdmFyIHBpeGVscyAgPSBpbWdEYXRhLmRhdGE7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIG4gPSBwaXhlbHMubGVuZ3RoOyBpIDwgbjsgaSArPSA0KSB7XG4gICAgICAgICAgICB2YXIgZ3JheXNjYWxlXG4gICAgICAgICAgICAgICAgPSBwaXhlbHNbaV0gKiAuMyArIHBpeGVsc1tpKzFdICogLjU5ICsgcGl4ZWxzW2krMl0gKiAuMTE7XG4gICAgICAgICAgICBwaXhlbHNbaSAgXSA9IGdyYXlzY2FsZTsgICAgICAgIC8vIHJlZFxuICAgICAgICAgICAgcGl4ZWxzW2krMV0gPSBncmF5c2NhbGU7ICAgICAgICAvLyBncmVlblxuICAgICAgICAgICAgcGl4ZWxzW2krMl0gPSBncmF5c2NhbGU7ICAgICAgICAvLyBibHVlXG4gICAgICAgICAgICAvLyBwaXhlbHNbaSszXSAgICAgICAgICAgICAgaXMgYWxwaGFcbiAgICAgICAgfVxuICAgICAgICAvLyByZWRyYXcgdGhlIGltYWdlIGluIGJsYWNrICYgd2hpdGVcbiAgICAgICAgY29udGV4dC5wdXRJbWFnZURhdGEoaW1nRGF0YSwgMCwgMCk7XG4gICAgfSxcblxuICAgIHNldFRvb2x0aXA6IGZ1bmN0aW9uIChlbGVtZW50LCBrZXksIHBvc2l0aW9uKSB7XG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKFwiZGF0YS1pMThuXCIsIFwiW2RhdGEtY29udGVudF1cIiArIGtleSk7XG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKFwiZGF0YS10b2dnbGVcIiwgXCJwb3BvdmVyXCIpO1xuICAgICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZShcImRhdGEtcGxhY2VtZW50XCIsIHBvc2l0aW9uKTtcbiAgICAgICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoXCJkYXRhLWh0bWxcIiwgdHJ1ZSk7XG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKFwiZGF0YS1jb250YWluZXJcIiwgXCJib2R5XCIpO1xuICAgIH1cblxuXG59OyIsInZhciBKaXRzaVBvcG92ZXIgPSByZXF1aXJlKFwiLi4vdXRpbC9KaXRzaVBvcG92ZXJcIik7XG5cbi8qKlxuICogQ29uc3RydWN0cyBuZXcgY29ubmVjdGlvbiBpbmRpY2F0b3IuXG4gKiBAcGFyYW0gdmlkZW9Db250YWluZXIgdGhlIHZpZGVvIGNvbnRhaW5lciBhc3NvY2lhdGVkIHdpdGggdGhlIGluZGljYXRvci5cbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBDb25uZWN0aW9uSW5kaWNhdG9yKHZpZGVvQ29udGFpbmVyLCBqaWQsIFZpZGVvTGF5b3V0KVxue1xuICAgIHRoaXMudmlkZW9Db250YWluZXIgPSB2aWRlb0NvbnRhaW5lcjtcbiAgICB0aGlzLmJhbmR3aWR0aCA9IG51bGw7XG4gICAgdGhpcy5wYWNrZXRMb3NzID0gbnVsbDtcbiAgICB0aGlzLmJpdHJhdGUgPSBudWxsO1xuICAgIHRoaXMuc2hvd01vcmVWYWx1ZSA9IGZhbHNlO1xuICAgIHRoaXMucmVzb2x1dGlvbiA9IG51bGw7XG4gICAgdGhpcy50cmFuc3BvcnQgPSBbXTtcbiAgICB0aGlzLnBvcG92ZXIgPSBudWxsO1xuICAgIHRoaXMuamlkID0gamlkO1xuICAgIHRoaXMuY3JlYXRlKCk7XG4gICAgdGhpcy52aWRlb0xheW91dCA9IFZpZGVvTGF5b3V0O1xufVxuXG4vKipcbiAqIFZhbHVlcyBmb3IgdGhlIGNvbm5lY3Rpb24gcXVhbGl0eVxuICogQHR5cGUge3s5ODogc3RyaW5nLFxuICogICAgICAgICA4MTogc3RyaW5nLFxuICogICAgICAgICA2NDogc3RyaW5nLFxuICogICAgICAgICA0Nzogc3RyaW5nLFxuICogICAgICAgICAzMDogc3RyaW5nLFxuICogICAgICAgICAwOiBzdHJpbmd9fVxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLmNvbm5lY3Rpb25RdWFsaXR5VmFsdWVzID0ge1xuICAgIDk4OiBcIjE4cHhcIiwgLy9mdWxsXG4gICAgODE6IFwiMTVweFwiLC8vNCBiYXJzXG4gICAgNjQ6IFwiMTFweFwiLC8vMyBiYXJzXG4gICAgNDc6IFwiN3B4XCIsLy8yIGJhcnNcbiAgICAzMDogXCIzcHhcIiwvLzEgYmFyXG4gICAgMDogXCIwcHhcIi8vZW1wdHlcbn07XG5cbkNvbm5lY3Rpb25JbmRpY2F0b3IuZ2V0SVAgPSBmdW5jdGlvbih2YWx1ZSlcbntcbiAgICByZXR1cm4gdmFsdWUuc3Vic3RyaW5nKDAsIHZhbHVlLmxhc3RJbmRleE9mKFwiOlwiKSk7XG59O1xuXG5Db25uZWN0aW9uSW5kaWNhdG9yLmdldFBvcnQgPSBmdW5jdGlvbih2YWx1ZSlcbntcbiAgICByZXR1cm4gdmFsdWUuc3Vic3RyaW5nKHZhbHVlLmxhc3RJbmRleE9mKFwiOlwiKSArIDEsIHZhbHVlLmxlbmd0aCk7XG59O1xuXG5Db25uZWN0aW9uSW5kaWNhdG9yLmdldFN0cmluZ0Zyb21BcnJheSA9IGZ1bmN0aW9uIChhcnJheSkge1xuICAgIHZhciByZXMgPSBcIlwiO1xuICAgIGZvcih2YXIgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKylcbiAgICB7XG4gICAgICAgIHJlcyArPSAoaSA9PT0gMD8gXCJcIiA6IFwiLCBcIikgKyBhcnJheVtpXTtcbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbn07XG5cbi8qKlxuICogR2VuZXJhdGVzIHRoZSBodG1sIGNvbnRlbnQuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSB0aGUgaHRtbCBjb250ZW50LlxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5nZW5lcmF0ZVRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGRvd25sb2FkQml0cmF0ZSwgdXBsb2FkQml0cmF0ZSwgcGFja2V0TG9zcywgcmVzb2x1dGlvbiwgaTtcblxuICAgIHZhciB0cmFuc2xhdGUgPSBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nO1xuXG4gICAgaWYodGhpcy5iaXRyYXRlID09PSBudWxsKVxuICAgIHtcbiAgICAgICAgZG93bmxvYWRCaXRyYXRlID0gXCJOL0FcIjtcbiAgICAgICAgdXBsb2FkQml0cmF0ZSA9IFwiTi9BXCI7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIGRvd25sb2FkQml0cmF0ZSA9XG4gICAgICAgICAgICB0aGlzLmJpdHJhdGUuZG93bmxvYWQ/IHRoaXMuYml0cmF0ZS5kb3dubG9hZCArIFwiIEticHNcIiA6IFwiTi9BXCI7XG4gICAgICAgIHVwbG9hZEJpdHJhdGUgPVxuICAgICAgICAgICAgdGhpcy5iaXRyYXRlLnVwbG9hZD8gdGhpcy5iaXRyYXRlLnVwbG9hZCArIFwiIEticHNcIiA6IFwiTi9BXCI7XG4gICAgfVxuXG4gICAgaWYodGhpcy5wYWNrZXRMb3NzID09PSBudWxsKVxuICAgIHtcbiAgICAgICAgcGFja2V0TG9zcyA9IFwiTi9BXCI7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG5cbiAgICAgICAgcGFja2V0TG9zcyA9IFwiPHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ncmVlbic+JmRhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgICAgICh0aGlzLnBhY2tldExvc3MuZG93bmxvYWQgIT09IG51bGw/IHRoaXMucGFja2V0TG9zcy5kb3dubG9hZCA6IFwiTi9BXCIpICtcbiAgICAgICAgICAgIFwiJSA8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX29yYW5nZSc+JnVhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgICAgICh0aGlzLnBhY2tldExvc3MudXBsb2FkICE9PSBudWxsPyB0aGlzLnBhY2tldExvc3MudXBsb2FkIDogXCJOL0FcIikgKyBcIiVcIjtcbiAgICB9XG5cbiAgICB2YXIgcmVzb2x1dGlvblZhbHVlID0gbnVsbDtcbiAgICBpZih0aGlzLnJlc29sdXRpb24gJiYgdGhpcy5qaWQgIT0gbnVsbClcbiAgICB7XG4gICAgICAgIHZhciBrZXlzID0gT2JqZWN0LmtleXModGhpcy5yZXNvbHV0aW9uKTtcbiAgICAgICAgaWYoa2V5cy5sZW5ndGggPT0gMSlcbiAgICAgICAge1xuICAgICAgICAgICAgZm9yKHZhciBzc3JjIGluIHRoaXMucmVzb2x1dGlvbilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSB0aGlzLnJlc29sdXRpb25bc3NyY107XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZihrZXlzLmxlbmd0aCA+IDEpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBkaXNwbGF5ZWRTc3JjID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdTU1JDKHRoaXMuamlkKTtcbiAgICAgICAgICAgIHJlc29sdXRpb25WYWx1ZSA9IHRoaXMucmVzb2x1dGlvbltkaXNwbGF5ZWRTc3JjXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlmKHRoaXMuamlkID09PSBudWxsKVxuICAgIHtcbiAgICAgICAgcmVzb2x1dGlvbiA9IFwiXCI7XG4gICAgICAgIGlmKHRoaXMucmVzb2x1dGlvbiA9PT0gbnVsbCB8fCAhT2JqZWN0LmtleXModGhpcy5yZXNvbHV0aW9uKSB8fFxuICAgICAgICAgICAgT2JqZWN0LmtleXModGhpcy5yZXNvbHV0aW9uKS5sZW5ndGggPT09IDApXG4gICAgICAgIHtcbiAgICAgICAgICAgIHJlc29sdXRpb24gPSBcIk4vQVwiO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGZvcihpIGluIHRoaXMucmVzb2x1dGlvbilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSB0aGlzLnJlc29sdXRpb25baV07XG4gICAgICAgICAgICAgICAgaWYocmVzb2x1dGlvblZhbHVlKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgaWYocmVzb2x1dGlvblZhbHVlLmhlaWdodCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvblZhbHVlLndpZHRoKVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHV0aW9uICs9IChyZXNvbHV0aW9uID09PSBcIlwiPyBcIlwiIDogXCIsIFwiKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvblZhbHVlLndpZHRoICsgXCJ4XCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb25WYWx1ZS5oZWlnaHQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYoIXJlc29sdXRpb25WYWx1ZSB8fFxuICAgICAgICAhcmVzb2x1dGlvblZhbHVlLmhlaWdodCB8fFxuICAgICAgICAhcmVzb2x1dGlvblZhbHVlLndpZHRoKVxuICAgIHtcbiAgICAgICAgcmVzb2x1dGlvbiA9IFwiTi9BXCI7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIHJlc29sdXRpb24gPSByZXNvbHV0aW9uVmFsdWUud2lkdGggKyBcInhcIiArIHJlc29sdXRpb25WYWx1ZS5oZWlnaHQ7XG4gICAgfVxuXG4gICAgdmFyIHJlc3VsdCA9IFwiPHRhYmxlIHN0eWxlPSd3aWR0aDoxMDAlJz5cIiArXG4gICAgICAgIFwiPHRyPlwiICtcbiAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J2Nvbm5lY3Rpb25pbmRpY2F0b3IuYml0cmF0ZSc+XCIgK1xuICAgICAgICB0cmFuc2xhdGUoXCJjb25uZWN0aW9uaW5kaWNhdG9yLmJpdHJhdGVcIikgKyBcIjwvc3Bhbj48L3RkPlwiICtcbiAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ncmVlbic+JmRhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgZG93bmxvYWRCaXRyYXRlICsgXCIgPHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9vcmFuZ2UnPiZ1YXJyOzwvc3Bhbj5cIiArXG4gICAgICAgIHVwbG9hZEJpdHJhdGUgKyBcIjwvdGQ+XCIgK1xuICAgICAgICBcIjwvdHI+PHRyPlwiICtcbiAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J2Nvbm5lY3Rpb25pbmRpY2F0b3IucGFja2V0bG9zcyc+XCIgK1xuICAgICAgICB0cmFuc2xhdGUoXCJjb25uZWN0aW9uaW5kaWNhdG9yLnBhY2tldGxvc3NcIikgKyBcIjwvc3Bhbj48L3RkPlwiICtcbiAgICAgICAgXCI8dGQ+XCIgKyBwYWNrZXRMb3NzICArIFwiPC90ZD5cIiArXG4gICAgICAgIFwiPC90cj48dHI+XCIgK1xuICAgICAgICBcIjx0ZD48c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIGRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5yZXNvbHV0aW9uJz5cIiArXG4gICAgICAgIHRyYW5zbGF0ZShcImNvbm5lY3Rpb25pbmRpY2F0b3IucmVzb2x1dGlvblwiKSArIFwiPC9zcGFuPjwvdGQ+XCIgK1xuICAgICAgICBcIjx0ZD5cIiArIHJlc29sdXRpb24gKyBcIjwvdGQ+PC90cj48L3RhYmxlPlwiO1xuXG4gICAgaWYodGhpcy52aWRlb0NvbnRhaW5lci5pZCA9PSBcImxvY2FsVmlkZW9Db250YWluZXJcIikge1xuICAgICAgICByZXN1bHQgKz0gXCI8ZGl2IGNsYXNzPVxcXCJqaXRzaXBvcG92ZXJfc2hvd21vcmVcXFwiIFwiICtcbiAgICAgICAgICAgIFwib25jbGljayA9IFxcXCJBUFAuVUkuY29ubmVjdGlvbkluZGljYXRvclNob3dNb3JlKCdcIiArXG4gICAgICAgICAgICB0aGlzLnZpZGVvQ29udGFpbmVyLmlkICsgXCInKVxcXCIgIGRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5cIiArXG4gICAgICAgICAgICAgICAgKHRoaXMuc2hvd01vcmVWYWx1ZSA/IFwibGVzc1wiIDogXCJtb3JlXCIpICsgXCInPlwiICtcbiAgICAgICAgICAgIHRyYW5zbGF0ZShcImNvbm5lY3Rpb25pbmRpY2F0b3IuXCIgKyAodGhpcy5zaG93TW9yZVZhbHVlID8gXCJsZXNzXCIgOiBcIm1vcmVcIikpICtcbiAgICAgICAgICAgIFwiPC9kaXY+PGJyIC8+XCI7XG4gICAgfVxuXG4gICAgaWYodGhpcy5zaG93TW9yZVZhbHVlKVxuICAgIHtcbiAgICAgICAgdmFyIGRvd25sb2FkQmFuZHdpZHRoLCB1cGxvYWRCYW5kd2lkdGgsIHRyYW5zcG9ydDtcbiAgICAgICAgaWYodGhpcy5iYW5kd2lkdGggPT09IG51bGwpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGRvd25sb2FkQmFuZHdpZHRoID0gXCJOL0FcIjtcbiAgICAgICAgICAgIHVwbG9hZEJhbmR3aWR0aCA9IFwiTi9BXCI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICBkb3dubG9hZEJhbmR3aWR0aCA9IHRoaXMuYmFuZHdpZHRoLmRvd25sb2FkP1xuICAgICAgICAgICAgICAgIHRoaXMuYmFuZHdpZHRoLmRvd25sb2FkICsgXCIgS2Jwc1wiIDpcbiAgICAgICAgICAgICAgICBcIk4vQVwiO1xuICAgICAgICAgICAgdXBsb2FkQmFuZHdpZHRoID0gdGhpcy5iYW5kd2lkdGgudXBsb2FkP1xuICAgICAgICAgICAgICAgIHRoaXMuYmFuZHdpZHRoLnVwbG9hZCArIFwiIEticHNcIiA6XG4gICAgICAgICAgICAgICAgXCJOL0FcIjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKCF0aGlzLnRyYW5zcG9ydCB8fCB0aGlzLnRyYW5zcG9ydC5sZW5ndGggPT09IDApXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRyYW5zcG9ydCA9IFwiPHRyPlwiICtcbiAgICAgICAgICAgICAgICBcIjx0ZD48c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIFwiICtcbiAgICAgICAgICAgICAgICBcImRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5hZGRyZXNzJz5cIiArXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlKFwiY29ubmVjdGlvbmluZGljYXRvci5hZGRyZXNzXCIpICsgXCI8L3NwYW4+PC90ZD5cIiArXG4gICAgICAgICAgICAgICAgXCI8dGQ+IE4vQTwvdGQ+PC90cj5cIjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBkYXRhID0ge3JlbW90ZUlQOiBbXSwgbG9jYWxJUDpbXSwgcmVtb3RlUG9ydDpbXSwgbG9jYWxQb3J0OltdfTtcbiAgICAgICAgICAgIGZvcihpID0gMDsgaSA8IHRoaXMudHJhbnNwb3J0Lmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHZhciBpcCA9ICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldElQKHRoaXMudHJhbnNwb3J0W2ldLmlwKTtcbiAgICAgICAgICAgICAgICB2YXIgcG9ydCA9IENvbm5lY3Rpb25JbmRpY2F0b3IuZ2V0UG9ydCh0aGlzLnRyYW5zcG9ydFtpXS5pcCk7XG4gICAgICAgICAgICAgICAgdmFyIGxvY2FsSVAgPVxuICAgICAgICAgICAgICAgICAgICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldElQKHRoaXMudHJhbnNwb3J0W2ldLmxvY2FsaXApO1xuICAgICAgICAgICAgICAgIHZhciBsb2NhbFBvcnQgPVxuICAgICAgICAgICAgICAgICAgICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldFBvcnQodGhpcy50cmFuc3BvcnRbaV0ubG9jYWxpcCk7XG4gICAgICAgICAgICAgICAgaWYoZGF0YS5yZW1vdGVJUC5pbmRleE9mKGlwKSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEucmVtb3RlSVAucHVzaChpcCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYoZGF0YS5yZW1vdGVQb3J0LmluZGV4T2YocG9ydCkgPT0gLTEpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBkYXRhLnJlbW90ZVBvcnQucHVzaChwb3J0KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZihkYXRhLmxvY2FsSVAuaW5kZXhPZihsb2NhbElQKSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEubG9jYWxJUC5wdXNoKGxvY2FsSVApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmKGRhdGEubG9jYWxQb3J0LmluZGV4T2YobG9jYWxQb3J0KSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEubG9jYWxQb3J0LnB1c2gobG9jYWxQb3J0KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGxvY2FsX2FkZHJlc3Nfa2V5ID0gXCJjb25uZWN0aW9uaW5kaWNhdG9yLmxvY2FsYWRkcmVzc1wiO1xuICAgICAgICAgICAgdmFyIHJlbW90ZV9hZGRyZXNzX2tleSA9IFwiY29ubmVjdGlvbmluZGljYXRvci5yZW1vdGVhZGRyZXNzXCI7XG4gICAgICAgICAgICB2YXIgbG9jYWxUcmFuc3BvcnQgPVxuICAgICAgICAgICAgICAgIFwiPHRyPjx0ZD48c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIGRhdGEtaTE4bj0nXCIgK1xuICAgICAgICAgICAgICAgIGxvY2FsX2FkZHJlc3Nfa2V5ICtcIicgZGF0YS1pMThuLW9wdGlvbnM9J1wiICtcbiAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoe2NvdW50OiBkYXRhLmxvY2FsSVAubGVuZ3RofSkgKyBcIic+XCIgK1xuICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGUobG9jYWxfYWRkcmVzc19rZXksIHtjb3VudDogZGF0YS5sb2NhbElQLmxlbmd0aH0pICtcbiAgICAgICAgICAgICAgICAgICAgXCI8L3NwYW4+PC90ZD48dGQ+IFwiICtcbiAgICAgICAgICAgICAgICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldFN0cmluZ0Zyb21BcnJheShkYXRhLmxvY2FsSVApICtcbiAgICAgICAgICAgICAgICBcIjwvdGQ+PC90cj5cIjtcbiAgICAgICAgICAgIHRyYW5zcG9ydCA9XG4gICAgICAgICAgICAgICAgXCI8dHI+PHRkPjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfYmx1ZScgZGF0YS1pMThuPSdcIiArXG4gICAgICAgICAgICAgICAgcmVtb3RlX2FkZHJlc3Nfa2V5ICsgXCInIGRhdGEtaTE4bi1vcHRpb25zPSdcIiArXG4gICAgICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHtjb3VudDogZGF0YS5yZW1vdGVJUC5sZW5ndGh9KSArIFwiJz5cIiArXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZShyZW1vdGVfYWRkcmVzc19rZXksXG4gICAgICAgICAgICAgICAgICAgICAgICB7Y291bnQ6IGRhdGEucmVtb3RlSVAubGVuZ3RofSkgK1xuICAgICAgICAgICAgICAgICAgICBcIjwvc3Bhbj48L3RkPjx0ZD4gXCIgK1xuICAgICAgICAgICAgICAgIENvbm5lY3Rpb25JbmRpY2F0b3IuZ2V0U3RyaW5nRnJvbUFycmF5KGRhdGEucmVtb3RlSVApICtcbiAgICAgICAgICAgICAgICBcIjwvdGQ+PC90cj5cIjtcblxuICAgICAgICAgICAgdmFyIGtleV9yZW1vdGUgPSBcImNvbm5lY3Rpb25pbmRpY2F0b3IucmVtb3RlcG9ydFwiLFxuICAgICAgICAgICAgICAgIGtleV9sb2NhbCA9IFwiY29ubmVjdGlvbmluZGljYXRvci5sb2NhbHBvcnRcIjtcblxuICAgICAgICAgICAgdHJhbnNwb3J0ICs9IFwiPHRyPlwiICtcbiAgICAgICAgICAgICAgICBcIjx0ZD5cIiArXG4gICAgICAgICAgICAgICAgXCI8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIGRhdGEtaTE4bj0nXCIgKyBrZXlfcmVtb3RlICtcbiAgICAgICAgICAgICAgICBcIicgZGF0YS1pMThuLW9wdGlvbnM9J1wiICtcbiAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeSh7Y291bnQ6IHRoaXMudHJhbnNwb3J0Lmxlbmd0aH0pICsgXCInPlwiICtcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGUoa2V5X3JlbW90ZSwge2NvdW50OiB0aGlzLnRyYW5zcG9ydC5sZW5ndGh9KSArXG4gICAgICAgICAgICAgICAgXCI8L3NwYW4+PC90ZD48dGQ+XCI7XG4gICAgICAgICAgICBsb2NhbFRyYW5zcG9ydCArPSBcIjx0cj5cIiArXG4gICAgICAgICAgICAgICAgXCI8dGQ+XCIgK1xuICAgICAgICAgICAgICAgIFwiPHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J1wiICsga2V5X2xvY2FsICtcbiAgICAgICAgICAgICAgICBcIicgZGF0YS1pMThuLW9wdGlvbnM9J1wiICtcbiAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeSh7Y291bnQ6IHRoaXMudHJhbnNwb3J0Lmxlbmd0aH0pICsgXCInPlwiICtcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGUoa2V5X2xvY2FsLCB7Y291bnQ6IHRoaXMudHJhbnNwb3J0Lmxlbmd0aH0pICtcbiAgICAgICAgICAgICAgICBcIjwvc3Bhbj48L3RkPjx0ZD5cIjtcblxuICAgICAgICAgICAgdHJhbnNwb3J0ICs9XG4gICAgICAgICAgICAgICAgQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkoZGF0YS5yZW1vdGVQb3J0KTtcbiAgICAgICAgICAgIGxvY2FsVHJhbnNwb3J0ICs9XG4gICAgICAgICAgICAgICAgQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkoZGF0YS5sb2NhbFBvcnQpO1xuICAgICAgICAgICAgdHJhbnNwb3J0ICs9IFwiPC90ZD48L3RyPlwiO1xuICAgICAgICAgICAgdHJhbnNwb3J0ICs9IGxvY2FsVHJhbnNwb3J0ICsgXCI8L3RkPjwvdHI+XCI7XG4gICAgICAgICAgICB0cmFuc3BvcnQgKz1cIjx0cj5cIiArXG4gICAgICAgICAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J2Nvbm5lY3Rpb25pbmRpY2F0b3IudHJhbnNwb3J0Jz5cIiArXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlKFwiY29ubmVjdGlvbmluZGljYXRvci50cmFuc3BvcnRcIikgKyBcIjwvc3Bhbj48L3RkPlwiICtcbiAgICAgICAgICAgICAgICBcIjx0ZD5cIiArIHRoaXMudHJhbnNwb3J0WzBdLnR5cGUgKyBcIjwvdGQ+PC90cj5cIjtcblxuICAgICAgICB9XG5cbiAgICAgICAgcmVzdWx0ICs9IFwiPHRhYmxlICBzdHlsZT0nd2lkdGg6MTAwJSc+XCIgK1xuICAgICAgICAgICAgXCI8dHI+XCIgK1xuICAgICAgICAgICAgXCI8dGQ+XCIgK1xuICAgICAgICAgICAgXCI8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIGRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5iYW5kd2lkdGgnPlwiICtcbiAgICAgICAgICAgIHRyYW5zbGF0ZShcImNvbm5lY3Rpb25pbmRpY2F0b3IuYmFuZHdpZHRoXCIpICsgXCI8L3NwYW4+XCIgK1xuICAgICAgICAgICAgXCI8L3RkPjx0ZD5cIiArXG4gICAgICAgICAgICBcIjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfZ3JlZW4nPiZkYXJyOzwvc3Bhbj5cIiArXG4gICAgICAgICAgICBkb3dubG9hZEJhbmR3aWR0aCArXG4gICAgICAgICAgICBcIiA8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX29yYW5nZSc+JnVhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgICAgIHVwbG9hZEJhbmR3aWR0aCArIFwiPC90ZD48L3RyPlwiO1xuXG4gICAgICAgIHJlc3VsdCArPSB0cmFuc3BvcnQgKyBcIjwvdGFibGU+XCI7XG5cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBTaG93cyBvciBoaWRlIHRoZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLlxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5zaG93TW9yZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnNob3dNb3JlVmFsdWUgPSAhdGhpcy5zaG93TW9yZVZhbHVlO1xuICAgIHRoaXMudXBkYXRlUG9wb3ZlckRhdGEoKTtcbn07XG5cblxuZnVuY3Rpb24gY3JlYXRlSWNvbihjbGFzc2VzKVxue1xuICAgIHZhciBpY29uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNwYW5cIik7XG4gICAgZm9yKHZhciBpIGluIGNsYXNzZXMpXG4gICAge1xuICAgICAgICBpY29uLmNsYXNzTGlzdC5hZGQoY2xhc3Nlc1tpXSk7XG4gICAgfVxuICAgIGljb24uYXBwZW5kQ2hpbGQoXG4gICAgICAgIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpXCIpKS5jbGFzc0xpc3QuYWRkKFwiaWNvbi1jb25uZWN0aW9uXCIpO1xuICAgIHJldHVybiBpY29uO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIGluZGljYXRvclxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5jcmVhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICB0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuY2xhc3NOYW1lID0gXCJjb25uZWN0aW9uaW5kaWNhdG9yXCI7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICB0aGlzLnZpZGVvQ29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lcik7XG4gICAgdGhpcy5wb3BvdmVyID0gbmV3IEppdHNpUG9wb3ZlcihcbiAgICAgICAgJChcIiNcIiArIHRoaXMudmlkZW9Db250YWluZXIuaWQgKyBcIiA+IC5jb25uZWN0aW9uaW5kaWNhdG9yXCIpLFxuICAgICAgICB7Y29udGVudDogXCI8ZGl2IGNsYXNzPVxcXCJjb25uZWN0aW9uX2luZm9cXFwiIGRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5uYSc+XCIgK1xuICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhcImNvbm5lY3Rpb25pbmRpY2F0b3IubmFcIikgKyBcIjwvZGl2PlwiLFxuICAgICAgICAgICAgc2tpbjogXCJibGFja1wifSk7XG5cbiAgICB0aGlzLmVtcHR5SWNvbiA9IHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lci5hcHBlbmRDaGlsZChcbiAgICAgICAgY3JlYXRlSWNvbihbXCJjb25uZWN0aW9uXCIsIFwiY29ubmVjdGlvbl9lbXB0eVwiXSkpO1xuICAgIHRoaXMuZnVsbEljb24gPSB0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuYXBwZW5kQ2hpbGQoXG4gICAgICAgIGNyZWF0ZUljb24oW1wiY29ubmVjdGlvblwiLCBcImNvbm5lY3Rpb25fZnVsbFwiXSkpO1xuXG59O1xuXG4vKipcbiAqIFJlbW92ZXMgdGhlIGluZGljYXRvclxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5yZW1vdmUgPSBmdW5jdGlvbigpXG57XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnJlbW92ZSgpO1xuICAgIHRoaXMucG9wb3Zlci5mb3JjZUhpZGUoKTtcblxufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBkYXRhIG9mIHRoZSBpbmRpY2F0b3JcbiAqIEBwYXJhbSBwZXJjZW50IHRoZSBwZXJjZW50IG9mIGNvbm5lY3Rpb24gcXVhbGl0eVxuICogQHBhcmFtIG9iamVjdCB0aGUgc3RhdGlzdGljcyBkYXRhLlxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS51cGRhdGVDb25uZWN0aW9uUXVhbGl0eSA9XG5mdW5jdGlvbiAocGVyY2VudCwgb2JqZWN0KSB7XG5cbiAgICBpZihwZXJjZW50ID09PSBudWxsKVxuICAgIHtcbiAgICAgICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICAgICAgdGhpcy5wb3BvdmVyLmZvcmNlSGlkZSgpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIGlmKHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lci5zdHlsZS5kaXNwbGF5ID09IFwibm9uZVwiKSB7XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuc3R5bGUuZGlzcGxheSA9IFwiYmxvY2tcIjtcbiAgICAgICAgICAgIHRoaXMudmlkZW9MYXlvdXQudXBkYXRlTXV0ZVBvc2l0aW9uKHRoaXMudmlkZW9Db250YWluZXIuaWQpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHRoaXMuYmFuZHdpZHRoID0gb2JqZWN0LmJhbmR3aWR0aDtcbiAgICB0aGlzLmJpdHJhdGUgPSBvYmplY3QuYml0cmF0ZTtcbiAgICB0aGlzLnBhY2tldExvc3MgPSBvYmplY3QucGFja2V0TG9zcztcbiAgICB0aGlzLnRyYW5zcG9ydCA9IG9iamVjdC50cmFuc3BvcnQ7XG4gICAgaWYob2JqZWN0LnJlc29sdXRpb24pXG4gICAge1xuICAgICAgICB0aGlzLnJlc29sdXRpb24gPSBvYmplY3QucmVzb2x1dGlvbjtcbiAgICB9XG4gICAgZm9yKHZhciBxdWFsaXR5IGluIENvbm5lY3Rpb25JbmRpY2F0b3IuY29ubmVjdGlvblF1YWxpdHlWYWx1ZXMpXG4gICAge1xuICAgICAgICBpZihwZXJjZW50ID49IHF1YWxpdHkpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMuZnVsbEljb24uc3R5bGUud2lkdGggPVxuICAgICAgICAgICAgICAgIENvbm5lY3Rpb25JbmRpY2F0b3IuY29ubmVjdGlvblF1YWxpdHlWYWx1ZXNbcXVhbGl0eV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhpcy51cGRhdGVQb3BvdmVyRGF0YSgpO1xufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSByZXNvbHV0aW9uXG4gKiBAcGFyYW0gcmVzb2x1dGlvbiB0aGUgbmV3IHJlc29sdXRpb25cbiAqL1xuQ29ubmVjdGlvbkluZGljYXRvci5wcm90b3R5cGUudXBkYXRlUmVzb2x1dGlvbiA9IGZ1bmN0aW9uIChyZXNvbHV0aW9uKSB7XG4gICAgdGhpcy5yZXNvbHV0aW9uID0gcmVzb2x1dGlvbjtcbiAgICB0aGlzLnVwZGF0ZVBvcG92ZXJEYXRhKCk7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIGNvbnRlbnQgb2YgdGhlIHBvcG92ZXJcbiAqL1xuQ29ubmVjdGlvbkluZGljYXRvci5wcm90b3R5cGUudXBkYXRlUG9wb3ZlckRhdGEgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5wb3BvdmVyLnVwZGF0ZUNvbnRlbnQoXG4gICAgICAgIFwiPGRpdiBjbGFzcz1cXFwiY29ubmVjdGlvbl9pbmZvXFxcIj5cIiArIHRoaXMuZ2VuZXJhdGVUZXh0KCkgKyBcIjwvZGl2PlwiKTtcbiAgICBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlRWxlbWVudCgkKFwiLmNvbm5lY3Rpb25faW5mb1wiKSk7XG59O1xuXG4vKipcbiAqIEhpZGVzIHRoZSBwb3BvdmVyXG4gKi9cbkNvbm5lY3Rpb25JbmRpY2F0b3IucHJvdG90eXBlLmhpZGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5wb3BvdmVyLmZvcmNlSGlkZSgpO1xufTtcblxuLyoqXG4gKiBIaWRlcyB0aGUgaW5kaWNhdG9yXG4gKi9cbkNvbm5lY3Rpb25JbmRpY2F0b3IucHJvdG90eXBlLmhpZGVJbmRpY2F0b3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICBpZih0aGlzLnBvcG92ZXIpXG4gICAgICAgIHRoaXMucG9wb3Zlci5mb3JjZUhpZGUoKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ29ubmVjdGlvbkluZGljYXRvcjsiLCJ2YXIgQXVkaW9MZXZlbHMgPSByZXF1aXJlKFwiLi4vYXVkaW9fbGV2ZWxzL0F1ZGlvTGV2ZWxzXCIpO1xudmFyIEF2YXRhciA9IHJlcXVpcmUoXCIuLi9hdmF0YXIvQXZhdGFyXCIpO1xudmFyIENoYXQgPSByZXF1aXJlKFwiLi4vc2lkZV9wYW5uZWxzL2NoYXQvQ2hhdFwiKTtcbnZhciBDb250YWN0TGlzdCA9IHJlcXVpcmUoXCIuLi9zaWRlX3Bhbm5lbHMvY29udGFjdGxpc3QvQ29udGFjdExpc3RcIik7XG52YXIgVUlVdGlsID0gcmVxdWlyZShcIi4uL3V0aWwvVUlVdGlsXCIpO1xudmFyIENvbm5lY3Rpb25JbmRpY2F0b3IgPSByZXF1aXJlKFwiLi9Db25uZWN0aW9uSW5kaWNhdG9yXCIpO1xudmFyIE5pY2tuYW1lSGFuZGxlciA9IHJlcXVpcmUoXCIuLi91dGlsL05pY2tuYW1lSGFuZGxlclwiKTtcbnZhciBNZWRpYVN0cmVhbVR5cGUgPSByZXF1aXJlKFwiLi4vLi4vLi4vc2VydmljZS9SVEMvTWVkaWFTdHJlYW1UeXBlc1wiKTtcbnZhciBVSUV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi8uLi9zZXJ2aWNlL1VJL1VJRXZlbnRzXCIpO1xuXG52YXIgY3VycmVudERvbWluYW50U3BlYWtlciA9IG51bGw7XG52YXIgbGFzdE5Db3VudCA9IGNvbmZpZy5jaGFubmVsTGFzdE47XG52YXIgbG9jYWxMYXN0TkNvdW50ID0gY29uZmlnLmNoYW5uZWxMYXN0TjtcbnZhciBsb2NhbExhc3ROU2V0ID0gW107XG52YXIgbGFzdE5FbmRwb2ludHNDYWNoZSA9IFtdO1xudmFyIGxhc3ROUGlja3VwSmlkID0gbnVsbDtcbnZhciBsYXJnZVZpZGVvU3RhdGUgPSB7XG4gICAgdXBkYXRlSW5Qcm9ncmVzczogZmFsc2UsXG4gICAgbmV3U3JjOiAnJ1xufTtcblxudmFyIGV2ZW50RW1pdHRlciA9IG51bGw7XG5cbi8qKlxuICogQ3VycmVudGx5IGZvY3VzZWQgdmlkZW8gXCJzcmNcIihkaXNwbGF5ZWQgaW4gbGFyZ2UgdmlkZW8pLlxuICogQHR5cGUge1N0cmluZ31cbiAqL1xudmFyIGZvY3VzZWRWaWRlb0luZm8gPSBudWxsO1xuXG4vKipcbiAqIEluZGljYXRlcyBpZiB3ZSBoYXZlIG11dGVkIG91ciBhdWRpbyBiZWZvcmUgdGhlIGNvbmZlcmVuY2UgaGFzIHN0YXJ0ZWQuXG4gKiBAdHlwZSB7Ym9vbGVhbn1cbiAqL1xudmFyIHByZU11dGVkID0gZmFsc2U7XG5cbnZhciBtdXRlZEF1ZGlvcyA9IHt9O1xuXG52YXIgZmxpcFhMb2NhbFZpZGVvID0gdHJ1ZTtcbnZhciBjdXJyZW50VmlkZW9XaWR0aCA9IG51bGw7XG52YXIgY3VycmVudFZpZGVvSGVpZ2h0ID0gbnVsbDtcblxudmFyIGxvY2FsVmlkZW9TcmMgPSBudWxsO1xuXG5mdW5jdGlvbiB2aWRlb2FjdGl2ZSggdmlkZW9lbGVtKSB7XG4gICAgaWYgKHZpZGVvZWxlbS5hdHRyKCdpZCcpLmluZGV4T2YoJ21peGVkbXNsYWJlbCcpID09PSAtMSkge1xuICAgICAgICAvLyBpZ25vcmUgbWl4ZWRtc2xhYmVsYTAgYW5kIHYwXG5cbiAgICAgICAgdmlkZW9lbGVtLnNob3coKTtcbiAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplVGh1bWJuYWlscygpO1xuXG4gICAgICAgIHZhciB2aWRlb1BhcmVudCA9IHZpZGVvZWxlbS5wYXJlbnQoKTtcbiAgICAgICAgdmFyIHBhcmVudFJlc291cmNlSmlkID0gbnVsbDtcbiAgICAgICAgaWYgKHZpZGVvUGFyZW50KVxuICAgICAgICAgICAgcGFyZW50UmVzb3VyY2VKaWRcbiAgICAgICAgICAgICAgICA9IFZpZGVvTGF5b3V0LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZCh2aWRlb1BhcmVudFswXSk7XG5cbiAgICAgICAgLy8gVXBkYXRlIHRoZSBsYXJnZSB2aWRlbyB0byB0aGUgbGFzdCBhZGRlZCB2aWRlbyBvbmx5IGlmIHRoZXJlJ3Mgbm9cbiAgICAgICAgLy8gY3VycmVudCBkb21pbmFudCwgZm9jdXNlZCBzcGVha2VyIG9yIHByZXppIHBsYXlpbmcgb3IgdXBkYXRlIGl0IHRvXG4gICAgICAgIC8vIHRoZSBjdXJyZW50IGRvbWluYW50IHNwZWFrZXIuXG4gICAgICAgIGlmICgoIWZvY3VzZWRWaWRlb0luZm8gJiZcbiAgICAgICAgICAgICFWaWRlb0xheW91dC5nZXREb21pbmFudFNwZWFrZXJSZXNvdXJjZUppZCgpICYmXG4gICAgICAgICAgICAhcmVxdWlyZShcIi4uL3ByZXppL1ByZXppXCIpLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpKSB8fFxuICAgICAgICAgICAgKHBhcmVudFJlc291cmNlSmlkICYmXG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuZ2V0RG9taW5hbnRTcGVha2VyUmVzb3VyY2VKaWQoKSA9PT0gcGFyZW50UmVzb3VyY2VKaWQpKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKFxuICAgICAgICAgICAgICAgIEFQUC5SVEMuZ2V0VmlkZW9TcmModmlkZW9lbGVtWzBdKSxcbiAgICAgICAgICAgICAgICAxLFxuICAgICAgICAgICAgICAgIHBhcmVudFJlc291cmNlSmlkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIFZpZGVvTGF5b3V0LnNob3dNb2RlcmF0b3JJbmRpY2F0b3IoKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHdhaXRGb3JSZW1vdGVWaWRlbyhzZWxlY3Rvciwgc3NyYywgc3RyZWFtLCBqaWQpIHtcbiAgICAvLyBYWFgoZ3ApIHNvLCBldmVyeSBjYWxsIHRvIHRoaXMgZnVuY3Rpb24gaXMgKmFsd2F5cyogcHJlY2VkZWQgYnkgYSBjYWxsXG4gICAgLy8gdG8gdGhlIFJUQy5hdHRhY2hNZWRpYVN0cmVhbSgpIGZ1bmN0aW9uIGJ1dCB0aGF0IGNhbGwgaXMgKm5vdCogZm9sbG93ZWRcbiAgICAvLyBieSBhbiB1cGRhdGUgdG8gdGhlIHZpZGVvU3JjVG9Tc3JjIG1hcCFcbiAgICAvL1xuICAgIC8vIFRoZSBhYm92ZSB3YXkgb2YgZG9pbmcgdGhpbmdzIHJlc3VsdHMgaW4gdmlkZW8gU1JDcyB0aGF0IGRvbid0IGNvcnJlc3BvbmRcbiAgICAvLyB0byBhbnkgU1NSQyBmb3IgYSBzaG9ydCBwZXJpb2Qgb2YgdGltZSAodG8gYmUgbW9yZSBwcmVjaXNlLCBmb3IgYXMgbG9uZ1xuICAgIC8vIHRoZSB3YWl0Rm9yUmVtb3RlVmlkZW8gdGFrZXMgdG8gY29tcGxldGUpLiBUaGlzIGNhdXNlcyBwcm9ibGVtcyAoc2VlXG4gICAgLy8gYmVsbG93KS5cbiAgICAvL1xuICAgIC8vIEknbSB3b25kZXJpbmcgd2h5IHdlIG5lZWQgdG8gZG8gdGhhdDsgaS5lLiB3aHkgY2FsbCBSVEMuYXR0YWNoTWVkaWFTdHJlYW0oKVxuICAgIC8vIGEgc2Vjb25kIHRpbWUgaW4gaGVyZSBhbmQgb25seSB0aGVuIHVwZGF0ZSB0aGUgdmlkZW9TcmNUb1NzcmMgbWFwPyBXaHlcbiAgICAvLyBub3Qgc2ltcGx5IHVwZGF0ZSB0aGUgdmlkZW9TcmNUb1NzcmMgbWFwIHdoZW4gdGhlIFJUQy5hdHRhY2hNZWRpYVN0cmVhbSgpXG4gICAgLy8gaXMgY2FsbGVkIHRoZSBmaXJzdCB0aW1lPyBJIGFjdHVhbGx5IGRvIHRoYXQgaW4gdGhlIGxhc3ROIGNoYW5nZWQgZXZlbnRcbiAgICAvLyBoYW5kbGVyIGJlY2F1c2UgdGhlIFwib3JwaGFuXCIgdmlkZW8gU1JDIGlzIGNhdXNpbmcgdHJvdWJsZXMgdGhlcmUuIFRoZVxuICAgIC8vIHB1cnBvc2Ugb2YgdGhpcyBtZXRob2Qgd291bGQgdGhlbiBiZSB0byBmaXJlIHRoZSBcInZpZGVvYWN0aXZlLmppbmdsZVwiLlxuICAgIC8vXG4gICAgLy8gRm9vZCBmb3IgdGhvdWdoIEkgZ3Vlc3MgOi0pXG5cbiAgICBpZiAoc2VsZWN0b3IucmVtb3ZlZCB8fCAhc2VsZWN0b3IucGFyZW50KCkuaXMoXCI6dmlzaWJsZVwiKSkge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJNZWRpYSByZW1vdmVkIGJlZm9yZSBoYWQgc3RhcnRlZFwiLCBzZWxlY3Rvcik7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc3RyZWFtLmlkID09PSAnbWl4ZWRtc2xhYmVsJykgcmV0dXJuO1xuXG4gICAgaWYgKHNlbGVjdG9yWzBdLmN1cnJlbnRUaW1lID4gMCkge1xuICAgICAgICB2YXIgdmlkZW9TdHJlYW0gPSBBUFAuc2ltdWxjYXN0LmdldFJlY2VpdmluZ1ZpZGVvU3RyZWFtKHN0cmVhbSk7XG4gICAgICAgIEFQUC5SVEMuYXR0YWNoTWVkaWFTdHJlYW0oc2VsZWN0b3IsIHZpZGVvU3RyZWFtKTsgLy8gRklYTUU6IHdoeSBkbyBpIGhhdmUgdG8gZG8gdGhpcyBmb3IgRkY/XG4gICAgICAgIHZpZGVvYWN0aXZlKHNlbGVjdG9yKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHdhaXRGb3JSZW1vdGVWaWRlbyhzZWxlY3Rvciwgc3NyYywgc3RyZWFtLCBqaWQpO1xuICAgICAgICB9LCAyNTApO1xuICAgIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIGFuIGFycmF5IG9mIHRoZSB2aWRlbyBob3Jpem9udGFsIGFuZCB2ZXJ0aWNhbCBpbmRlbnRzLFxuICogc28gdGhhdCBpZiBmaXRzIGl0cyBwYXJlbnQuXG4gKlxuICogQHJldHVybiBhbiBhcnJheSB3aXRoIDIgZWxlbWVudHMsIHRoZSBob3Jpem9udGFsIGluZGVudCBhbmQgdGhlIHZlcnRpY2FsXG4gKiBpbmRlbnRcbiAqL1xuZnVuY3Rpb24gZ2V0Q2FtZXJhVmlkZW9Qb3NpdGlvbih2aWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb0hlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFjZVdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlSGVpZ2h0KSB7XG4gICAgLy8gUGFyZW50IGhlaWdodCBpc24ndCBjb21wbGV0ZWx5IGNhbGN1bGF0ZWQgd2hlbiB3ZSBwb3NpdGlvbiB0aGUgdmlkZW8gaW5cbiAgICAvLyBmdWxsIHNjcmVlbiBtb2RlIGFuZCB0aGlzIGlzIHdoeSB3ZSB1c2UgdGhlIHNjcmVlbiBoZWlnaHQgaW4gdGhpcyBjYXNlLlxuICAgIC8vIE5lZWQgdG8gdGhpbmsgaXQgZnVydGhlciBhdCBzb21lIHBvaW50IGFuZCBpbXBsZW1lbnQgaXQgcHJvcGVybHkuXG4gICAgdmFyIGlzRnVsbFNjcmVlbiA9IGRvY3VtZW50LmZ1bGxTY3JlZW4gfHxcbiAgICAgICAgZG9jdW1lbnQubW96RnVsbFNjcmVlbiB8fFxuICAgICAgICBkb2N1bWVudC53ZWJraXRJc0Z1bGxTY3JlZW47XG4gICAgaWYgKGlzRnVsbFNjcmVlbilcbiAgICAgICAgdmlkZW9TcGFjZUhlaWdodCA9IHdpbmRvdy5pbm5lckhlaWdodDtcblxuICAgIHZhciBob3Jpem9udGFsSW5kZW50ID0gKHZpZGVvU3BhY2VXaWR0aCAtIHZpZGVvV2lkdGgpIC8gMjtcbiAgICB2YXIgdmVydGljYWxJbmRlbnQgPSAodmlkZW9TcGFjZUhlaWdodCAtIHZpZGVvSGVpZ2h0KSAvIDI7XG5cbiAgICByZXR1cm4gW2hvcml6b250YWxJbmRlbnQsIHZlcnRpY2FsSW5kZW50XTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGFuIGFycmF5IG9mIHRoZSB2aWRlbyBob3Jpem9udGFsIGFuZCB2ZXJ0aWNhbCBpbmRlbnRzLlxuICogQ2VudGVycyBob3Jpem9udGFsbHkgYW5kIHRvcCBhbGlnbnMgdmVydGljYWxseS5cbiAqXG4gKiBAcmV0dXJuIGFuIGFycmF5IHdpdGggMiBlbGVtZW50cywgdGhlIGhvcml6b250YWwgaW5kZW50IGFuZCB0aGUgdmVydGljYWxcbiAqIGluZGVudFxuICovXG5mdW5jdGlvbiBnZXREZXNrdG9wVmlkZW9Qb3NpdGlvbih2aWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9IZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlSGVpZ2h0KSB7XG5cbiAgICB2YXIgaG9yaXpvbnRhbEluZGVudCA9ICh2aWRlb1NwYWNlV2lkdGggLSB2aWRlb1dpZHRoKSAvIDI7XG5cbiAgICB2YXIgdmVydGljYWxJbmRlbnQgPSAwOy8vIFRvcCBhbGlnbmVkXG5cbiAgICByZXR1cm4gW2hvcml6b250YWxJbmRlbnQsIHZlcnRpY2FsSW5kZW50XTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgYW4gYXJyYXkgb2YgdGhlIHZpZGVvIGRpbWVuc2lvbnMsIHNvIHRoYXQgaXQgY292ZXJzIHRoZSBzY3JlZW4uXG4gKiBJdCBsZWF2ZXMgbm8gZW1wdHkgYXJlYXMsIGJ1dCBzb21lIHBhcnRzIG9mIHRoZSB2aWRlbyBtaWdodCBub3QgYmUgdmlzaWJsZS5cbiAqXG4gKiBAcmV0dXJuIGFuIGFycmF5IHdpdGggMiBlbGVtZW50cywgdGhlIHZpZGVvIHdpZHRoIGFuZCB0aGUgdmlkZW8gaGVpZ2h0XG4gKi9cbmZ1bmN0aW9uIGdldENhbWVyYVZpZGVvU2l6ZSh2aWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlSGVpZ2h0KSB7XG4gICAgaWYgKCF2aWRlb1dpZHRoKVxuICAgICAgICB2aWRlb1dpZHRoID0gY3VycmVudFZpZGVvV2lkdGg7XG4gICAgaWYgKCF2aWRlb0hlaWdodClcbiAgICAgICAgdmlkZW9IZWlnaHQgPSBjdXJyZW50VmlkZW9IZWlnaHQ7XG5cbiAgICB2YXIgYXNwZWN0UmF0aW8gPSB2aWRlb1dpZHRoIC8gdmlkZW9IZWlnaHQ7XG5cbiAgICB2YXIgYXZhaWxhYmxlV2lkdGggPSBNYXRoLm1heCh2aWRlb1dpZHRoLCB2aWRlb1NwYWNlV2lkdGgpO1xuICAgIHZhciBhdmFpbGFibGVIZWlnaHQgPSBNYXRoLm1heCh2aWRlb0hlaWdodCwgdmlkZW9TcGFjZUhlaWdodCk7XG5cbiAgICBpZiAoYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbyA8IHZpZGVvU3BhY2VIZWlnaHQpIHtcbiAgICAgICAgYXZhaWxhYmxlSGVpZ2h0ID0gdmlkZW9TcGFjZUhlaWdodDtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSBhdmFpbGFibGVIZWlnaHQgKiBhc3BlY3RSYXRpbztcbiAgICB9XG5cbiAgICBpZiAoYXZhaWxhYmxlSGVpZ2h0ICogYXNwZWN0UmF0aW8gPCB2aWRlb1NwYWNlV2lkdGgpIHtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSB2aWRlb1NwYWNlV2lkdGg7XG4gICAgICAgIGF2YWlsYWJsZUhlaWdodCA9IGF2YWlsYWJsZVdpZHRoIC8gYXNwZWN0UmF0aW87XG4gICAgfVxuXG4gICAgcmV0dXJuIFthdmFpbGFibGVXaWR0aCwgYXZhaWxhYmxlSGVpZ2h0XTtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBkaXNwbGF5IG5hbWUgZm9yIHRoZSBnaXZlbiB2aWRlbyBzcGFuIGlkLlxuICovXG5mdW5jdGlvbiBzZXREaXNwbGF5TmFtZSh2aWRlb1NwYW5JZCwgZGlzcGxheU5hbWUsIGtleSkge1xuICAgIHZhciBuYW1lU3BhbiA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPnNwYW4uZGlzcGxheW5hbWUnKTtcbiAgICB2YXIgZGVmYXVsdExvY2FsRGlzcGxheU5hbWUgPSBBUFAudHJhbnNsYXRpb24uZ2VuZXJhdGVUcmFuc2xhdG9uSFRNTChcbiAgICAgICAgaW50ZXJmYWNlQ29uZmlnLkRFRkFVTFRfTE9DQUxfRElTUExBWV9OQU1FKTtcblxuICAgIC8vIElmIHdlIGFscmVhZHkgaGF2ZSBhIGRpc3BsYXkgbmFtZSBmb3IgdGhpcyB2aWRlby5cbiAgICBpZiAobmFtZVNwYW4ubGVuZ3RoID4gMCkge1xuICAgICAgICB2YXIgbmFtZVNwYW5FbGVtZW50ID0gbmFtZVNwYW4uZ2V0KDApO1xuXG4gICAgICAgIGlmIChuYW1lU3BhbkVsZW1lbnQuaWQgPT09ICdsb2NhbERpc3BsYXlOYW1lJyAmJlxuICAgICAgICAgICAgJCgnI2xvY2FsRGlzcGxheU5hbWUnKS50ZXh0KCkgIT09IGRpc3BsYXlOYW1lKSB7XG4gICAgICAgICAgICBpZiAoZGlzcGxheU5hbWUgJiYgZGlzcGxheU5hbWUubGVuZ3RoID4gMClcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB2YXIgbWVIVE1MID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXCJtZVwiKTtcbiAgICAgICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLmh0bWwoZGlzcGxheU5hbWUgKyAnICgnICsgbWVIVE1MICsgJyknKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLmh0bWwoZGVmYXVsdExvY2FsRGlzcGxheU5hbWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGRpc3BsYXlOYW1lICYmIGRpc3BsYXlOYW1lLmxlbmd0aCA+IDApXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZCArICdfbmFtZScpLmh0bWwoZGlzcGxheU5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoa2V5ICYmIGtleS5sZW5ndGggPiAwKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHZhciBuYW1lSHRtbCA9IEFQUC50cmFuc2xhdGlvbi5nZW5lcmF0ZVRyYW5zbGF0b25IVE1MKGtleSk7XG4gICAgICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZCArICdfbmFtZScpLmh0bWwobmFtZUh0bWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnX25hbWUnKS50ZXh0KFxuICAgICAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuREVGQVVMVF9SRU1PVEVfRElTUExBWV9OQU1FKTtcbiAgICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBlZGl0QnV0dG9uID0gbnVsbDtcblxuICAgICAgICBuYW1lU3BhbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICAgICAgbmFtZVNwYW4uY2xhc3NOYW1lID0gJ2Rpc3BsYXluYW1lJztcbiAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQobmFtZVNwYW4pO1xuXG4gICAgICAgIGlmICh2aWRlb1NwYW5JZCA9PT0gJ2xvY2FsVmlkZW9Db250YWluZXInKSB7XG4gICAgICAgICAgICBlZGl0QnV0dG9uID0gY3JlYXRlRWRpdERpc3BsYXlOYW1lQnV0dG9uKCk7XG4gICAgICAgICAgICBpZiAoZGlzcGxheU5hbWUgJiYgZGlzcGxheU5hbWUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHZhciBtZUhUTUwgPSBBUFAudHJhbnNsYXRpb24uZ2VuZXJhdGVUcmFuc2xhdG9uSFRNTChcIm1lXCIpO1xuICAgICAgICAgICAgICAgIG5hbWVTcGFuLmlubmVySFRNTCA9IGRpc3BsYXlOYW1lICsgbWVIVE1MO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIG5hbWVTcGFuLmlubmVySFRNTCA9IGRlZmF1bHRMb2NhbERpc3BsYXlOYW1lO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKGRpc3BsYXlOYW1lICYmIGRpc3BsYXlOYW1lLmxlbmd0aCA+IDApIHtcblxuICAgICAgICAgICAgICAgIG5hbWVTcGFuLmlubmVyVGV4dCA9IGRpc3BsYXlOYW1lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIG5hbWVTcGFuLmlubmVyVGV4dCA9IGludGVyZmFjZUNvbmZpZy5ERUZBVUxUX1JFTU9URV9ESVNQTEFZX05BTUU7XG4gICAgICAgIH1cblxuXG4gICAgICAgIGlmICghZWRpdEJ1dHRvbikge1xuICAgICAgICAgICAgbmFtZVNwYW4uaWQgPSB2aWRlb1NwYW5JZCArICdfbmFtZSc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBuYW1lU3Bhbi5pZCA9ICdsb2NhbERpc3BsYXlOYW1lJztcbiAgICAgICAgICAgICQoJyMnICsgdmlkZW9TcGFuSWQpWzBdLmFwcGVuZENoaWxkKGVkaXRCdXR0b24pO1xuICAgICAgICAgICAgLy90cmFuc2xhdGVzIHBvcG92ZXIgb2YgZWRpdCBidXR0b25cbiAgICAgICAgICAgIEFQUC50cmFuc2xhdGlvbi50cmFuc2xhdGVFbGVtZW50KCQoXCJhLmRpc3BsYXluYW1lXCIpKTtcblxuICAgICAgICAgICAgdmFyIGVkaXRhYmxlVGV4dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XG4gICAgICAgICAgICBlZGl0YWJsZVRleHQuY2xhc3NOYW1lID0gJ2Rpc3BsYXluYW1lJztcbiAgICAgICAgICAgIGVkaXRhYmxlVGV4dC50eXBlID0gJ3RleHQnO1xuICAgICAgICAgICAgZWRpdGFibGVUZXh0LmlkID0gJ2VkaXREaXNwbGF5TmFtZSc7XG5cbiAgICAgICAgICAgIGlmIChkaXNwbGF5TmFtZSAmJiBkaXNwbGF5TmFtZS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBlZGl0YWJsZVRleHQudmFsdWVcbiAgICAgICAgICAgICAgICAgICAgPSBkaXNwbGF5TmFtZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGRlZmF1bHROaWNrbmFtZSA9IEFQUC50cmFuc2xhdGlvbi50cmFuc2xhdGVTdHJpbmcoXG4gICAgICAgICAgICAgICAgXCJkZWZhdWx0Tmlja25hbWVcIiwge25hbWU6IFwiSmFuZSBQaW5rXCJ9KTtcbiAgICAgICAgICAgIGVkaXRhYmxlVGV4dC5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgJ2Rpc3BsYXk6bm9uZTsnKTtcbiAgICAgICAgICAgIGVkaXRhYmxlVGV4dC5zZXRBdHRyaWJ1dGUoJ2RhdGEtMThuJyxcbiAgICAgICAgICAgICAgICAnW3BsYWNlaG9sZGVyXWRlZmF1bHROaWNrbmFtZScpO1xuICAgICAgICAgICAgZWRpdGFibGVUZXh0LnNldEF0dHJpYnV0ZShcImRhdGEtaTE4bi1vcHRpb25zXCIsXG4gICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoe25hbWU6IFwiSmFuZSBQaW5rXCJ9KSk7XG4gICAgICAgICAgICBlZGl0YWJsZVRleHQuc2V0QXR0cmlidXRlKFwicGxhY2Vob2xkZXJcIiwgZGVmYXVsdE5pY2tuYW1lKTtcblxuICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQoZWRpdGFibGVUZXh0KTtcblxuICAgICAgICAgICAgJCgnI2xvY2FsVmlkZW9Db250YWluZXIgLmRpc3BsYXluYW1lJylcbiAgICAgICAgICAgICAgICAuYmluZChcImNsaWNrXCIsIGZ1bmN0aW9uIChlKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLmhpZGUoKTtcbiAgICAgICAgICAgICAgICAgICAgJCgnI2VkaXREaXNwbGF5TmFtZScpLnNob3coKTtcbiAgICAgICAgICAgICAgICAgICAgJCgnI2VkaXREaXNwbGF5TmFtZScpLmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgICAgICQoJyNlZGl0RGlzcGxheU5hbWUnKS5zZWxlY3QoKTtcblxuICAgICAgICAgICAgICAgICAgICAkKCcjZWRpdERpc3BsYXlOYW1lJykub25lKFwiZm9jdXNvdXRcIiwgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmlucHV0RGlzcGxheU5hbWVIYW5kbGVyKHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICAkKCcjZWRpdERpc3BsYXlOYW1lJykub24oJ2tleWRvd24nLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMTMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuaW5wdXREaXNwbGF5TmFtZUhhbmRsZXIodGhpcy52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIEdldHMgdGhlIHNlbGVjdG9yIG9mIHZpZGVvIHRodW1ibmFpbCBjb250YWluZXIgZm9yIHRoZSB1c2VyIGlkZW50aWZpZWQgYnlcbiAqIGdpdmVuIDx0dD51c2VySmlkPC90dD5cbiAqIEBwYXJhbSByZXNvdXJjZUppZCB1c2VyJ3MgSmlkIGZvciB3aG9tIHdlIHdhbnQgdG8gZ2V0IHRoZSB2aWRlbyBjb250YWluZXIuXG4gKi9cbmZ1bmN0aW9uIGdldFBhcnRpY2lwYW50Q29udGFpbmVyKHJlc291cmNlSmlkKVxue1xuICAgIGlmICghcmVzb3VyY2VKaWQpXG4gICAgICAgIHJldHVybiBudWxsO1xuXG4gICAgaWYgKHJlc291cmNlSmlkID09PSBBUFAueG1wcC5teVJlc291cmNlKCkpXG4gICAgICAgIHJldHVybiAkKFwiI2xvY2FsVmlkZW9Db250YWluZXJcIik7XG4gICAgZWxzZVxuICAgICAgICByZXR1cm4gJChcIiNwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlSmlkKTtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBzaXplIGFuZCBwb3NpdGlvbiBvZiB0aGUgZ2l2ZW4gdmlkZW8gZWxlbWVudC5cbiAqXG4gKiBAcGFyYW0gdmlkZW8gdGhlIHZpZGVvIGVsZW1lbnQgdG8gcG9zaXRpb25cbiAqIEBwYXJhbSB3aWR0aCB0aGUgZGVzaXJlZCB2aWRlbyB3aWR0aFxuICogQHBhcmFtIGhlaWdodCB0aGUgZGVzaXJlZCB2aWRlbyBoZWlnaHRcbiAqIEBwYXJhbSBob3Jpem9udGFsSW5kZW50IHRoZSBsZWZ0IGFuZCByaWdodCBpbmRlbnRcbiAqIEBwYXJhbSB2ZXJ0aWNhbEluZGVudCB0aGUgdG9wIGFuZCBib3R0b20gaW5kZW50XG4gKi9cbmZ1bmN0aW9uIHBvc2l0aW9uVmlkZW8odmlkZW8sXG4gICAgICAgICAgICAgICAgICAgICAgIHdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgIGhvcml6b250YWxJbmRlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgIHZlcnRpY2FsSW5kZW50KSB7XG4gICAgdmlkZW8ud2lkdGgod2lkdGgpO1xuICAgIHZpZGVvLmhlaWdodChoZWlnaHQpO1xuICAgIHZpZGVvLmNzcyh7ICB0b3A6IHZlcnRpY2FsSW5kZW50ICsgJ3B4JyxcbiAgICAgICAgYm90dG9tOiB2ZXJ0aWNhbEluZGVudCArICdweCcsXG4gICAgICAgIGxlZnQ6IGhvcml6b250YWxJbmRlbnQgKyAncHgnLFxuICAgICAgICByaWdodDogaG9yaXpvbnRhbEluZGVudCArICdweCd9KTtcbn1cblxuLyoqXG4gKiBBZGRzIHRoZSByZW1vdGUgdmlkZW8gbWVudSBlbGVtZW50IGZvciB0aGUgZ2l2ZW4gPHR0PmppZDwvdHQ+IGluIHRoZVxuICogZ2l2ZW4gPHR0PnBhcmVudEVsZW1lbnQ8L3R0Pi5cbiAqXG4gKiBAcGFyYW0gamlkIHRoZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZm9yIHdoaWNoIHdlJ3JlIGFkZGluZyBhIG1lbnUuXG4gKiBAcGFyYW0gcGFyZW50RWxlbWVudCB0aGUgcGFyZW50IGVsZW1lbnQgd2hlcmUgdGhpcyBtZW51IHdpbGwgYmUgYWRkZWRcbiAqL1xuZnVuY3Rpb24gYWRkUmVtb3RlVmlkZW9NZW51KGppZCwgcGFyZW50RWxlbWVudCkge1xuICAgIHZhciBzcGFuRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICBzcGFuRWxlbWVudC5jbGFzc05hbWUgPSAncmVtb3RldmlkZW9tZW51JztcblxuICAgIHBhcmVudEVsZW1lbnQuYXBwZW5kQ2hpbGQoc3BhbkVsZW1lbnQpO1xuXG4gICAgdmFyIG1lbnVFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaScpO1xuICAgIG1lbnVFbGVtZW50LmNsYXNzTmFtZSA9ICdmYSBmYS1hbmdsZS1kb3duJztcbiAgICBtZW51RWxlbWVudC50aXRsZSA9ICdSZW1vdGUgdXNlciBjb250cm9scyc7XG4gICAgc3BhbkVsZW1lbnQuYXBwZW5kQ2hpbGQobWVudUVsZW1lbnQpO1xuXG4vLyAgICAgICAgPHVsIGNsYXNzPVwicG9wdXBtZW51XCI+XG4vLyAgICAgICAgPGxpPjxhIGhyZWY9XCIjXCI+TXV0ZTwvYT48L2xpPlxuLy8gICAgICAgIDxsaT48YSBocmVmPVwiI1wiPkVqZWN0PC9hPjwvbGk+XG4vLyAgICAgICAgPC91bD5cblxuICAgIHZhciBwb3B1cG1lbnVFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndWwnKTtcbiAgICBwb3B1cG1lbnVFbGVtZW50LmNsYXNzTmFtZSA9ICdwb3B1cG1lbnUnO1xuICAgIHBvcHVwbWVudUVsZW1lbnQuaWRcbiAgICAgICAgPSAncmVtb3RlX3BvcHVwbWVudV8nICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICBzcGFuRWxlbWVudC5hcHBlbmRDaGlsZChwb3B1cG1lbnVFbGVtZW50KTtcblxuICAgIHZhciBtdXRlTWVudUl0ZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpO1xuICAgIHZhciBtdXRlTGlua0l0ZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG5cbiAgICB2YXIgbXV0ZWRJbmRpY2F0b3IgPSBcIjxpIHN0eWxlPSdmbG9hdDpsZWZ0OycgY2xhc3M9J2ljb24tbWljLWRpc2FibGVkJz48L2k+XCI7XG5cbiAgICBpZiAoIW11dGVkQXVkaW9zW2ppZF0pIHtcbiAgICAgICAgbXV0ZUxpbmtJdGVtLmlubmVySFRNTCA9IG11dGVkSW5kaWNhdG9yICtcbiAgICAgICAgICAgIFwiIDxkaXYgc3R5bGU9J3dpZHRoOiA5MHB4O21hcmdpbi1sZWZ0OiAyMHB4OycgZGF0YS1pMThuPSd2aWRlb3RodW1ibmFpbC5kb211dGUnPjwvZGl2PlwiO1xuICAgICAgICBtdXRlTGlua0l0ZW0uY2xhc3NOYW1lID0gJ211dGVsaW5rJztcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIG11dGVMaW5rSXRlbS5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArXG4gICAgICAgICAgICBcIiA8ZGl2IHN0eWxlPSd3aWR0aDogOTBweDttYXJnaW4tbGVmdDogMjBweDsnIGRhdGEtaTE4bj0ndmlkZW90aHVtYm5haWwubXV0ZWQnPjwvZGl2PlwiO1xuICAgICAgICBtdXRlTGlua0l0ZW0uY2xhc3NOYW1lID0gJ211dGVsaW5rIGRpc2FibGVkJztcbiAgICB9XG5cbiAgICBtdXRlTGlua0l0ZW0ub25jbGljayA9IGZ1bmN0aW9uKCl7XG4gICAgICAgIGlmICgkKHRoaXMpLmF0dHIoJ2Rpc2FibGVkJykgIT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBpc011dGUgPSBtdXRlZEF1ZGlvc1tqaWRdID09IHRydWU7XG4gICAgICAgIEFQUC54bXBwLnNldE11dGUoamlkLCAhaXNNdXRlKTtcblxuICAgICAgICBwb3B1cG1lbnVFbGVtZW50LnNldEF0dHJpYnV0ZSgnc3R5bGUnLCAnZGlzcGxheTpub25lOycpO1xuXG4gICAgICAgIGlmIChpc011dGUpIHtcbiAgICAgICAgICAgIHRoaXMuaW5uZXJIVE1MID0gbXV0ZWRJbmRpY2F0b3IgK1xuICAgICAgICAgICAgICAgIFwiIDxkaXYgc3R5bGU9J3dpZHRoOiA5MHB4O21hcmdpbi1sZWZ0OiAyMHB4OycgZGF0YS1pMThuPSd2aWRlb3RodW1ibmFpbC5tdXRlZCc+PC9kaXY+XCI7XG4gICAgICAgICAgICB0aGlzLmNsYXNzTmFtZSA9ICdtdXRlbGluayBkaXNhYmxlZCc7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmlubmVySFRNTCA9IG11dGVkSW5kaWNhdG9yICtcbiAgICAgICAgICAgICAgICBcIiA8ZGl2IHN0eWxlPSd3aWR0aDogOTBweDttYXJnaW4tbGVmdDogMjBweDsnIGRhdGEtaTE4bj0ndmlkZW90aHVtYm5haWwuZG9tdXRlJz48L2Rpdj5cIjtcbiAgICAgICAgICAgIHRoaXMuY2xhc3NOYW1lID0gJ211dGVsaW5rJztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBtdXRlTWVudUl0ZW0uYXBwZW5kQ2hpbGQobXV0ZUxpbmtJdGVtKTtcbiAgICBwb3B1cG1lbnVFbGVtZW50LmFwcGVuZENoaWxkKG11dGVNZW51SXRlbSk7XG5cbiAgICB2YXIgZWplY3RJbmRpY2F0b3IgPSBcIjxpIHN0eWxlPSdmbG9hdDpsZWZ0OycgY2xhc3M9J2ZhIGZhLWVqZWN0Jz48L2k+XCI7XG5cbiAgICB2YXIgZWplY3RNZW51SXRlbSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpJyk7XG4gICAgdmFyIGVqZWN0TGlua0l0ZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgdmFyIGVqZWN0VGV4dCA9IFwiPGRpdiBzdHlsZT0nd2lkdGg6IDkwcHg7bWFyZ2luLWxlZnQ6IDIwcHg7JyBkYXRhLWkxOG49J3ZpZGVvdGh1bWJuYWlsLmtpY2snPiZuYnNwOzwvZGl2PlwiO1xuICAgIGVqZWN0TGlua0l0ZW0uaW5uZXJIVE1MID0gZWplY3RJbmRpY2F0b3IgKyAnICcgKyBlamVjdFRleHQ7XG4gICAgZWplY3RMaW5rSXRlbS5vbmNsaWNrID0gZnVuY3Rpb24oKXtcbiAgICAgICAgQVBQLnhtcHAuZWplY3QoamlkKTtcbiAgICAgICAgcG9wdXBtZW51RWxlbWVudC5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgJ2Rpc3BsYXk6bm9uZTsnKTtcbiAgICB9O1xuXG4gICAgZWplY3RNZW51SXRlbS5hcHBlbmRDaGlsZChlamVjdExpbmtJdGVtKTtcbiAgICBwb3B1cG1lbnVFbGVtZW50LmFwcGVuZENoaWxkKGVqZWN0TWVudUl0ZW0pO1xuXG4gICAgdmFyIHBhZGRpbmdTcGFuID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgIHBhZGRpbmdTcGFuLmNsYXNzTmFtZSA9ICdwb3B1cG1lbnVQYWRkaW5nJztcbiAgICBwb3B1cG1lbnVFbGVtZW50LmFwcGVuZENoaWxkKHBhZGRpbmdTcGFuKTtcbiAgICBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlRWxlbWVudCgkKFwiI1wiICsgcG9wdXBtZW51RWxlbWVudC5pZCArIFwiID4gbGkgPiBhID4gZGl2XCIpKTtcbn1cblxuLyoqXG4gKiBSZW1vdmVzIHJlbW90ZSB2aWRlbyBtZW51IGVsZW1lbnQgZnJvbSB2aWRlbyBlbGVtZW50IGlkZW50aWZpZWQgYnlcbiAqIGdpdmVuIDx0dD52aWRlb0VsZW1lbnRJZDwvdHQ+LlxuICpcbiAqIEBwYXJhbSB2aWRlb0VsZW1lbnRJZCB0aGUgaWQgb2YgbG9jYWwgb3IgcmVtb3RlIHZpZGVvIGVsZW1lbnQuXG4gKi9cbmZ1bmN0aW9uIHJlbW92ZVJlbW90ZVZpZGVvTWVudSh2aWRlb0VsZW1lbnRJZCkge1xuICAgIHZhciBtZW51U3BhbiA9ICQoJyMnICsgdmlkZW9FbGVtZW50SWQgKyAnPnNwYW4ucmVtb3RldmlkZW9tZW51Jyk7XG4gICAgaWYgKG1lbnVTcGFuLmxlbmd0aCkge1xuICAgICAgICBtZW51U3Bhbi5yZW1vdmUoKTtcbiAgICB9XG59XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZGF0YSBmb3IgdGhlIGluZGljYXRvclxuICogQHBhcmFtIGlkIHRoZSBpZCBvZiB0aGUgaW5kaWNhdG9yXG4gKiBAcGFyYW0gcGVyY2VudCB0aGUgcGVyY2VudCBmb3IgY29ubmVjdGlvbiBxdWFsaXR5XG4gKiBAcGFyYW0gb2JqZWN0IHRoZSBkYXRhXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZVN0YXRzSW5kaWNhdG9yKGlkLCBwZXJjZW50LCBvYmplY3QpIHtcbiAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tpZF0pXG4gICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW2lkXS51cGRhdGVDb25uZWN0aW9uUXVhbGl0eShwZXJjZW50LCBvYmplY3QpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBhbiBhcnJheSBvZiB0aGUgdmlkZW8gZGltZW5zaW9ucywgc28gdGhhdCBpdCBrZWVwcyBpdCdzIGFzcGVjdFxuICogcmF0aW8gYW5kIGZpdHMgYXZhaWxhYmxlIGFyZWEgd2l0aCBpdCdzIGxhcmdlciBkaW1lbnNpb24uIFRoaXMgbWV0aG9kXG4gKiBlbnN1cmVzIHRoYXQgd2hvbGUgdmlkZW8gd2lsbCBiZSB2aXNpYmxlIGFuZCBjYW4gbGVhdmUgZW1wdHkgYXJlYXMuXG4gKlxuICogQHJldHVybiBhbiBhcnJheSB3aXRoIDIgZWxlbWVudHMsIHRoZSB2aWRlbyB3aWR0aCBhbmQgdGhlIHZpZGVvIGhlaWdodFxuICovXG5mdW5jdGlvbiBnZXREZXNrdG9wVmlkZW9TaXplKHZpZGVvV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VIZWlnaHQpIHtcbiAgICBpZiAoIXZpZGVvV2lkdGgpXG4gICAgICAgIHZpZGVvV2lkdGggPSBjdXJyZW50VmlkZW9XaWR0aDtcbiAgICBpZiAoIXZpZGVvSGVpZ2h0KVxuICAgICAgICB2aWRlb0hlaWdodCA9IGN1cnJlbnRWaWRlb0hlaWdodDtcblxuICAgIHZhciBhc3BlY3RSYXRpbyA9IHZpZGVvV2lkdGggLyB2aWRlb0hlaWdodDtcblxuICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IE1hdGgubWF4KHZpZGVvV2lkdGgsIHZpZGVvU3BhY2VXaWR0aCk7XG4gICAgdmFyIGF2YWlsYWJsZUhlaWdodCA9IE1hdGgubWF4KHZpZGVvSGVpZ2h0LCB2aWRlb1NwYWNlSGVpZ2h0KTtcblxuICAgIHZpZGVvU3BhY2VIZWlnaHQgLT0gJCgnI3JlbW90ZVZpZGVvcycpLm91dGVySGVpZ2h0KCk7XG5cbiAgICBpZiAoYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbyA+PSB2aWRlb1NwYWNlSGVpZ2h0KVxuICAgIHtcbiAgICAgICAgYXZhaWxhYmxlSGVpZ2h0ID0gdmlkZW9TcGFjZUhlaWdodDtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSBhdmFpbGFibGVIZWlnaHQgKiBhc3BlY3RSYXRpbztcbiAgICB9XG5cbiAgICBpZiAoYXZhaWxhYmxlSGVpZ2h0ICogYXNwZWN0UmF0aW8gPj0gdmlkZW9TcGFjZVdpZHRoKVxuICAgIHtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSB2aWRlb1NwYWNlV2lkdGg7XG4gICAgICAgIGF2YWlsYWJsZUhlaWdodCA9IGF2YWlsYWJsZVdpZHRoIC8gYXNwZWN0UmF0aW87XG4gICAgfVxuXG4gICAgcmV0dXJuIFthdmFpbGFibGVXaWR0aCwgYXZhaWxhYmxlSGVpZ2h0XTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBlZGl0IGRpc3BsYXkgbmFtZSBidXR0b24uXG4gKlxuICogQHJldHVybnMgdGhlIGVkaXQgYnV0dG9uXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUVkaXREaXNwbGF5TmFtZUJ1dHRvbigpIHtcbiAgICB2YXIgZWRpdEJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2EnKTtcbiAgICBlZGl0QnV0dG9uLmNsYXNzTmFtZSA9ICdkaXNwbGF5bmFtZSc7XG4gICAgVUlVdGlsLnNldFRvb2x0aXAoZWRpdEJ1dHRvbixcbiAgICAgICAgXCJ2aWRlb3RodW1ibmFpbC5lZGl0bmlja25hbWVcIixcbiAgICAgICAgXCJ0b3BcIik7XG4gICAgZWRpdEJ1dHRvbi5pbm5lckhUTUwgPSAnPGkgY2xhc3M9XCJmYSBmYS1wZW5jaWxcIj48L2k+JztcblxuICAgIHJldHVybiBlZGl0QnV0dG9uO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIGVsZW1lbnQgaW5kaWNhdGluZyB0aGUgbW9kZXJhdG9yKG93bmVyKSBvZiB0aGUgY29uZmVyZW5jZS5cbiAqXG4gKiBAcGFyYW0gcGFyZW50RWxlbWVudCB0aGUgcGFyZW50IGVsZW1lbnQgd2hlcmUgdGhlIG93bmVyIGluZGljYXRvciB3aWxsXG4gKiBiZSBhZGRlZFxuICovXG5mdW5jdGlvbiBjcmVhdGVNb2RlcmF0b3JJbmRpY2F0b3JFbGVtZW50KHBhcmVudEVsZW1lbnQpIHtcbiAgICB2YXIgbW9kZXJhdG9ySW5kaWNhdG9yID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaScpO1xuICAgIG1vZGVyYXRvckluZGljYXRvci5jbGFzc05hbWUgPSAnZmEgZmEtc3Rhcic7XG4gICAgcGFyZW50RWxlbWVudC5hcHBlbmRDaGlsZChtb2RlcmF0b3JJbmRpY2F0b3IpO1xuXG4gICAgVUlVdGlsLnNldFRvb2x0aXAocGFyZW50RWxlbWVudCxcbiAgICAgICAgXCJ2aWRlb3RodW1ibmFpbC5tb2RlcmF0b3JcIixcbiAgICAgICAgXCJ0b3BcIik7XG59XG5cblxudmFyIFZpZGVvTGF5b3V0ID0gKGZ1bmN0aW9uIChteSkge1xuICAgIG15LmNvbm5lY3Rpb25JbmRpY2F0b3JzID0ge307XG5cbiAgICAvLyBCeSBkZWZhdWx0IHdlIHVzZSBjYW1lcmFcbiAgICBteS5nZXRWaWRlb1NpemUgPSBnZXRDYW1lcmFWaWRlb1NpemU7XG4gICAgbXkuZ2V0VmlkZW9Qb3NpdGlvbiA9IGdldENhbWVyYVZpZGVvUG9zaXRpb247XG5cbiAgICBteS5pbml0ID0gZnVuY3Rpb24gKGVtaXR0ZXIpIHtcbiAgICAgICAgLy8gTGlzdGVuIGZvciBsYXJnZSB2aWRlbyBzaXplIHVwZGF0ZXNcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xhcmdlVmlkZW8nKVxuICAgICAgICAgICAgLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWRlZG1ldGFkYXRhJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50VmlkZW9XaWR0aCA9IHRoaXMudmlkZW9XaWR0aDtcbiAgICAgICAgICAgICAgICBjdXJyZW50VmlkZW9IZWlnaHQgPSB0aGlzLnZpZGVvSGVpZ2h0O1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnBvc2l0aW9uTGFyZ2UoY3VycmVudFZpZGVvV2lkdGgsIGN1cnJlbnRWaWRlb0hlaWdodCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgZXZlbnRFbWl0dGVyID0gZW1pdHRlcjtcbiAgICB9O1xuXG4gICAgbXkuaXNJbkxhc3ROID0gZnVuY3Rpb24ocmVzb3VyY2UpIHtcbiAgICAgICAgcmV0dXJuIGxhc3ROQ291bnQgPCAwIC8vIGxhc3ROIGlzIGRpc2FibGVkLCByZXR1cm4gdHJ1ZVxuICAgICAgICAgICAgfHwgKGxhc3ROQ291bnQgPiAwICYmIGxhc3RORW5kcG9pbnRzQ2FjaGUubGVuZ3RoID09IDApIC8vIGxhc3RORW5kcG9pbnRzIGNhY2hlIG5vdCBidWlsdCB5ZXQsIHJldHVybiB0cnVlXG4gICAgICAgICAgICB8fCAobGFzdE5FbmRwb2ludHNDYWNoZSAmJiBsYXN0TkVuZHBvaW50c0NhY2hlLmluZGV4T2YocmVzb3VyY2UpICE9PSAtMSk7XG4gICAgfTtcblxuICAgIG15LmNoYW5nZUxvY2FsU3RyZWFtID0gZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICBWaWRlb0xheW91dC5jaGFuZ2VMb2NhbFZpZGVvKHN0cmVhbSk7XG4gICAgfTtcblxuICAgIG15LmNoYW5nZUxvY2FsQXVkaW8gPSBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgQVBQLlJUQy5hdHRhY2hNZWRpYVN0cmVhbSgkKCcjbG9jYWxBdWRpbycpLCBzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKSk7XG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NhbEF1ZGlvJykuYXV0b3BsYXkgPSB0cnVlO1xuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9jYWxBdWRpbycpLnZvbHVtZSA9IDA7XG4gICAgICAgIGlmIChwcmVNdXRlZCkge1xuICAgICAgICAgICAgaWYoIUFQUC5VSS5zZXRBdWRpb011dGVkKHRydWUpKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHByZU11dGVkID0gbXV0ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHByZU11dGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbXkuY2hhbmdlTG9jYWxWaWRlbyA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICB2YXIgZmxpcFggPSB0cnVlO1xuICAgICAgICBpZihzdHJlYW0udmlkZW9UeXBlID09IFwic2NyZWVuXCIpXG4gICAgICAgICAgICBmbGlwWCA9IGZhbHNlO1xuICAgICAgICB2YXIgbG9jYWxWaWRlbyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3ZpZGVvJyk7XG4gICAgICAgIGxvY2FsVmlkZW8uaWQgPSAnbG9jYWxWaWRlb18nICtcbiAgICAgICAgICAgIEFQUC5SVEMuZ2V0U3RyZWFtSUQoc3RyZWFtLmdldE9yaWdpbmFsU3RyZWFtKCkpO1xuICAgICAgICBsb2NhbFZpZGVvLmF1dG9wbGF5ID0gdHJ1ZTtcbiAgICAgICAgbG9jYWxWaWRlby52b2x1bWUgPSAwOyAvLyBpcyBpdCByZXF1aXJlZCBpZiBhdWRpbyBpcyBzZXBhcmF0ZWQgP1xuICAgICAgICBsb2NhbFZpZGVvLm9uY29udGV4dG1lbnUgPSBmdW5jdGlvbiAoKSB7IHJldHVybiBmYWxzZTsgfTtcblxuICAgICAgICB2YXIgbG9jYWxWaWRlb0NvbnRhaW5lciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NhbFZpZGVvV3JhcHBlcicpO1xuICAgICAgICBsb2NhbFZpZGVvQ29udGFpbmVyLmFwcGVuZENoaWxkKGxvY2FsVmlkZW8pO1xuXG4gICAgICAgIC8vIFNldCBkZWZhdWx0IGRpc3BsYXkgbmFtZS5cbiAgICAgICAgc2V0RGlzcGxheU5hbWUoJ2xvY2FsVmlkZW9Db250YWluZXInKTtcblxuICAgICAgICBpZighVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbXCJsb2NhbFZpZGVvQ29udGFpbmVyXCJdKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tcImxvY2FsVmlkZW9Db250YWluZXJcIl1cbiAgICAgICAgICAgICAgICA9IG5ldyBDb25uZWN0aW9uSW5kaWNhdG9yKCQoXCIjbG9jYWxWaWRlb0NvbnRhaW5lclwiKVswXSwgbnVsbCwgVmlkZW9MYXlvdXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgQXVkaW9MZXZlbHMudXBkYXRlQXVkaW9MZXZlbENhbnZhcyhudWxsLCBWaWRlb0xheW91dCk7XG5cbiAgICAgICAgdmFyIGxvY2FsVmlkZW9TZWxlY3RvciA9ICQoJyMnICsgbG9jYWxWaWRlby5pZCk7XG5cbiAgICAgICAgZnVuY3Rpb24gbG9jYWxWaWRlb0NsaWNrKGV2ZW50KSB7XG4gICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmhhbmRsZVZpZGVvVGh1bWJDbGlja2VkKFxuICAgICAgICAgICAgICAgIEFQUC5SVEMuZ2V0VmlkZW9TcmMobG9jYWxWaWRlbyksXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgQVBQLnhtcHAubXlSZXNvdXJjZSgpKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBZGQgY2xpY2sgaGFuZGxlciB0byBib3RoIHZpZGVvIGFuZCB2aWRlbyB3cmFwcGVyIGVsZW1lbnRzIGluIGNhc2VcbiAgICAgICAgLy8gdGhlcmUncyBubyB2aWRlby5cbiAgICAgICAgbG9jYWxWaWRlb1NlbGVjdG9yLmNsaWNrKGxvY2FsVmlkZW9DbGljayk7XG4gICAgICAgICQoJyNsb2NhbFZpZGVvQ29udGFpbmVyJykuY2xpY2sobG9jYWxWaWRlb0NsaWNrKTtcblxuICAgICAgICAvLyBBZGQgaG92ZXIgaGFuZGxlclxuICAgICAgICAkKCcjbG9jYWxWaWRlb0NvbnRhaW5lcicpLmhvdmVyKFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2hvd0Rpc3BsYXlOYW1lKCdsb2NhbFZpZGVvQ29udGFpbmVyJywgdHJ1ZSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFWaWRlb0xheW91dC5pc0xhcmdlVmlkZW9WaXNpYmxlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIHx8IEFQUC5SVEMuZ2V0VmlkZW9TcmMobG9jYWxWaWRlbykgIT09IEFQUC5SVEMuZ2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSkpXG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dEaXNwbGF5TmFtZSgnbG9jYWxWaWRlb0NvbnRhaW5lcicsIGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgLy8gQWRkIHN0cmVhbSBlbmRlZCBoYW5kbGVyXG4gICAgICAgIHN0cmVhbS5nZXRPcmlnaW5hbFN0cmVhbSgpLm9uZW5kZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBsb2NhbFZpZGVvQ29udGFpbmVyLnJlbW92ZUNoaWxkKGxvY2FsVmlkZW8pO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlUmVtb3ZlZFZpZGVvKEFQUC5SVEMuZ2V0VmlkZW9TcmMobG9jYWxWaWRlbykpO1xuICAgICAgICB9O1xuICAgICAgICAvLyBGbGlwIHZpZGVvIHggYXhpcyBpZiBuZWVkZWRcbiAgICAgICAgZmxpcFhMb2NhbFZpZGVvID0gZmxpcFg7XG4gICAgICAgIGlmIChmbGlwWCkge1xuICAgICAgICAgICAgbG9jYWxWaWRlb1NlbGVjdG9yLmFkZENsYXNzKFwiZmxpcFZpZGVvWFwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBdHRhY2ggV2ViUlRDIHN0cmVhbVxuICAgICAgICB2YXIgdmlkZW9TdHJlYW0gPSBBUFAuc2ltdWxjYXN0LmdldExvY2FsVmlkZW9TdHJlYW0oKTtcbiAgICAgICAgQVBQLlJUQy5hdHRhY2hNZWRpYVN0cmVhbShsb2NhbFZpZGVvU2VsZWN0b3IsIHZpZGVvU3RyZWFtKTtcblxuICAgICAgICBsb2NhbFZpZGVvU3JjID0gQVBQLlJUQy5nZXRWaWRlb1NyYyhsb2NhbFZpZGVvKTtcblxuICAgICAgICB2YXIgbXlSZXNvdXJjZUppZCA9IEFQUC54bXBwLm15UmVzb3VyY2UoKTtcblxuICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKGxvY2FsVmlkZW9TcmMsIDAsXG4gICAgICAgICAgICBteVJlc291cmNlSmlkKTtcblxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBZGRzIG9yIHJlbW92ZXMgaWNvbnMgZm9yIG5vdCBhdmFpbGFibGUgY2FtZXJhIGFuZCBtaWNyb3Bob25lLlxuICAgICAqIEBwYXJhbSByZXNvdXJjZUppZCB0aGUgamlkIG9mIHVzZXJcbiAgICAgKiBAcGFyYW0gZGV2aWNlcyBhdmFpbGFibGUgZGV2aWNlc1xuICAgICAqL1xuICAgIG15LnNldERldmljZUF2YWlsYWJpbGl0eUljb25zID0gZnVuY3Rpb24gKHJlc291cmNlSmlkLCBkZXZpY2VzKSB7XG4gICAgICAgIGlmKCFkZXZpY2VzKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHZhciBjb250YWluZXIgPSBudWxsXG4gICAgICAgIGlmKCFyZXNvdXJjZUppZClcbiAgICAgICAge1xuICAgICAgICAgICAgY29udGFpbmVyID0gJChcIiNsb2NhbFZpZGVvQ29udGFpbmVyXCIpWzBdO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgY29udGFpbmVyID0gJChcIiNwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlSmlkKVswXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKCFjb250YWluZXIpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgJChcIiNcIiArIGNvbnRhaW5lci5pZCArIFwiID4gLm5vTWljXCIpLnJlbW92ZSgpO1xuICAgICAgICAkKFwiI1wiICsgY29udGFpbmVyLmlkICsgXCIgPiAubm9WaWRlb1wiKS5yZW1vdmUoKTtcbiAgICAgICAgaWYoIWRldmljZXMuYXVkaW8pXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpKS5zZXRBdHRyaWJ1dGUoXCJjbGFzc1wiLFwibm9NaWNcIik7XG4gICAgICAgIH1cblxuICAgICAgICBpZighZGV2aWNlcy52aWRlbylcbiAgICAgICAge1xuICAgICAgICAgICAgY29udGFpbmVyLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIikpLnNldEF0dHJpYnV0ZShcImNsYXNzXCIsXCJub1ZpZGVvXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYoIWRldmljZXMuYXVkaW8gJiYgIWRldmljZXMudmlkZW8pXG4gICAgICAgIHtcbiAgICAgICAgICAgICQoXCIjXCIgKyBjb250YWluZXIuaWQgKyBcIiA+IC5ub01pY1wiKS5jc3MoXCJiYWNrZ3JvdW5kLXBvc2l0aW9uXCIsIFwiNzUlXCIpO1xuICAgICAgICAgICAgJChcIiNcIiArIGNvbnRhaW5lci5pZCArIFwiID4gLm5vVmlkZW9cIikuY3NzKFwiYmFja2dyb3VuZC1wb3NpdGlvblwiLCBcIjI1JVwiKTtcbiAgICAgICAgICAgICQoXCIjXCIgKyBjb250YWluZXIuaWQgKyBcIiA+IC5ub1ZpZGVvXCIpLmNzcyhcImJhY2tncm91bmQtY29sb3JcIiwgXCJ0cmFuc3BhcmVudFwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiByZW1vdmVkIHZpZGVvIGlzIGN1cnJlbnRseSBkaXNwbGF5ZWQgYW5kIHRyaWVzIHRvIGRpc3BsYXlcbiAgICAgKiBhbm90aGVyIG9uZSBpbnN0ZWFkLlxuICAgICAqIEBwYXJhbSByZW1vdmVkVmlkZW9TcmMgc3JjIHN0cmVhbSBpZGVudGlmaWVyIG9mIHRoZSB2aWRlby5cbiAgICAgKi9cbiAgICBteS51cGRhdGVSZW1vdmVkVmlkZW8gPSBmdW5jdGlvbihyZW1vdmVkVmlkZW9TcmMpIHtcbiAgICAgICAgaWYgKHJlbW92ZWRWaWRlb1NyYyA9PT0gQVBQLlJUQy5nZXRWaWRlb1NyYygkKCcjbGFyZ2VWaWRlbycpWzBdKSkge1xuICAgICAgICAgICAgLy8gdGhpcyBpcyBjdXJyZW50bHkgZGlzcGxheWVkIGFzIGxhcmdlXG4gICAgICAgICAgICAvLyBwaWNrIHRoZSBsYXN0IHZpc2libGUgdmlkZW8gaW4gdGhlIHJvd1xuICAgICAgICAgICAgLy8gaWYgbm9ib2R5IGVsc2UgaXMgbGVmdCwgdGhpcyBwaWNrcyB0aGUgbG9jYWwgdmlkZW9cbiAgICAgICAgICAgIHZhciBwaWNrXG4gICAgICAgICAgICAgICAgPSAkKCcjcmVtb3RlVmlkZW9zPnNwYW5baWQhPVwibWl4ZWRzdHJlYW1cIl06dmlzaWJsZTpsYXN0PnZpZGVvJylcbiAgICAgICAgICAgICAgICAgICAgLmdldCgwKTtcblxuICAgICAgICAgICAgaWYgKCFwaWNrKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiTGFzdCB2aXNpYmxlIHZpZGVvIG5vIGxvbmdlciBleGlzdHNcIik7XG4gICAgICAgICAgICAgICAgcGljayA9ICQoJyNyZW1vdGVWaWRlb3M+c3BhbltpZCE9XCJtaXhlZHN0cmVhbVwiXT52aWRlbycpLmdldCgwKTtcblxuICAgICAgICAgICAgICAgIGlmICghcGljayB8fCAhQVBQLlJUQy5nZXRWaWRlb1NyYyhwaWNrKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBUcnkgbG9jYWwgdmlkZW9cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiRmFsbGJhY2sgdG8gbG9jYWwgdmlkZW8uLi5cIik7XG4gICAgICAgICAgICAgICAgICAgIHBpY2sgPSAkKCcjcmVtb3RlVmlkZW9zPnNwYW4+c3Bhbj52aWRlbycpLmdldCgwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG11dGUgaWYgbG9jYWx2aWRlb1xuICAgICAgICAgICAgaWYgKHBpY2spIHtcbiAgICAgICAgICAgICAgICB2YXIgY29udGFpbmVyID0gcGljay5wYXJlbnROb2RlO1xuICAgICAgICAgICAgICAgIHZhciBqaWQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGlmKGNvbnRhaW5lcilcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGlmKGNvbnRhaW5lci5pZCA9PSBcImxvY2FsVmlkZW9XcmFwcGVyXCIpXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGppZCA9IEFQUC54bXBwLm15UmVzb3VyY2UoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGppZCA9IFZpZGVvTGF5b3V0LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZChjb250YWluZXIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlTGFyZ2VWaWRlbyhBUFAuUlRDLmdldFZpZGVvU3JjKHBpY2spLCBwaWNrLnZvbHVtZSwgamlkKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiRmFpbGVkIHRvIGVsZWN0IGxhcmdlIHZpZGVvXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICBcbiAgICBteS5vblJlbW90ZVN0cmVhbUFkZGVkID0gZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICB2YXIgY29udGFpbmVyO1xuICAgICAgICB2YXIgcmVtb3RlcyA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyZW1vdGVWaWRlb3MnKTtcblxuICAgICAgICBpZiAoc3RyZWFtLnBlZXJqaWQpIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmVuc3VyZVBlZXJDb250YWluZXJFeGlzdHMoc3RyZWFtLnBlZXJqaWQpO1xuXG4gICAgICAgICAgICBjb250YWluZXIgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXG4gICAgICAgICAgICAgICAgICAgICdwYXJ0aWNpcGFudF8nICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoc3RyZWFtLnBlZXJqaWQpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHZhciBpZCA9IHN0cmVhbS5nZXRPcmlnaW5hbFN0cmVhbSgpLmlkO1xuICAgICAgICAgICAgaWYgKGlkICE9PSAnbWl4ZWRtc2xhYmVsJ1xuICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBkZWZhdWx0IHN0cmVhbSBpcyBhZGRlZCBhbHdheXMgd2l0aCBuZXcgZm9jdXNcbiAgICAgICAgICAgICAgICAvLyAodG8gYmUgaW52ZXN0aWdhdGVkKVxuICAgICAgICAgICAgICAgICYmIGlkICE9PSAnZGVmYXVsdCcpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdjYW4gbm90IGFzc29jaWF0ZSBzdHJlYW0nLFxuICAgICAgICAgICAgICAgICAgICBpZCxcbiAgICAgICAgICAgICAgICAgICAgJ3dpdGggYSBwYXJ0aWNpcGFudCcpO1xuICAgICAgICAgICAgICAgIC8vIFdlIGRvbid0IHdhbnQgdG8gYWRkIGl0IGhlcmUgc2luY2UgaXQgd2lsbCBjYXVzZSB0cm91Ymxlc1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEZJWE1FOiBmb3IgdGhlIG1peGVkIG1zIHdlIGRvbnQgbmVlZCBhIHZpZGVvIC0tIGN1cnJlbnRseVxuICAgICAgICAgICAgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgICAgICAgICAgY29udGFpbmVyLmlkID0gJ21peGVkc3RyZWFtJztcbiAgICAgICAgICAgIGNvbnRhaW5lci5jbGFzc05hbWUgPSAndmlkZW9jb250YWluZXInO1xuICAgICAgICAgICAgcmVtb3Rlcy5hcHBlbmRDaGlsZChjb250YWluZXIpO1xuICAgICAgICAgICAgVUlVdGlsLnBsYXlTb3VuZE5vdGlmaWNhdGlvbigndXNlckpvaW5lZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvbnRhaW5lcikge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuYWRkUmVtb3RlU3RyZWFtRWxlbWVudCggY29udGFpbmVyLFxuICAgICAgICAgICAgICAgIHN0cmVhbS5zaWQsXG4gICAgICAgICAgICAgICAgc3RyZWFtLmdldE9yaWdpbmFsU3RyZWFtKCksXG4gICAgICAgICAgICAgICAgc3RyZWFtLnBlZXJqaWQsXG4gICAgICAgICAgICAgICAgc3RyZWFtLnNzcmMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgbXkuZ2V0TGFyZ2VWaWRlb1N0YXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbGFyZ2VWaWRlb1N0YXRlO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBsYXJnZSB2aWRlbyB3aXRoIHRoZSBnaXZlbiBuZXcgdmlkZW8gc291cmNlLlxuICAgICAqL1xuICAgIG15LnVwZGF0ZUxhcmdlVmlkZW8gPSBmdW5jdGlvbihuZXdTcmMsIHZvbCwgcmVzb3VyY2VKaWQpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ2hvdmVyIGluJywgbmV3U3JjKTtcblxuICAgICAgICBpZiAoQVBQLlJUQy5nZXRWaWRlb1NyYygkKCcjbGFyZ2VWaWRlbycpWzBdKSAhPT0gbmV3U3JjKSB7XG5cbiAgICAgICAgICAgICQoJyNhY3RpdmVTcGVha2VyJykuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuICAgICAgICAgICAgLy8gRHVlIHRvIHRoZSBzaW11bGNhc3QgdGhlIGxvY2FsVmlkZW9TcmMgbWF5IGhhdmUgY2hhbmdlZCB3aGVuIHRoZVxuICAgICAgICAgICAgLy8gZmFkZU91dCBldmVudCB0cmlnZ2Vycy4gSW4gdGhhdCBjYXNlIHRoZSBnZXRKaWRGcm9tVmlkZW9TcmMgYW5kXG4gICAgICAgICAgICAvLyBpc1ZpZGVvU3JjRGVza3RvcCBtZXRob2RzIHdpbGwgbm90IGZ1bmN0aW9uIGNvcnJlY3RseS5cbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBBbHNvLCBhZ2FpbiBkdWUgdG8gdGhlIHNpbXVsY2FzdCwgdGhlIHVwZGF0ZUxhcmdlVmlkZW8gbWV0aG9kIGNhblxuICAgICAgICAgICAgLy8gYmUgY2FsbGVkIG11bHRpcGxlIHRpbWVzIGFsbW9zdCBzaW11bHRhbmVvdXNseS4gVGhlcmVmb3JlLCB3ZVxuICAgICAgICAgICAgLy8gc3RvcmUgdGhlIHN0YXRlIGhlcmUgYW5kIHVwZGF0ZSBvbmx5IG9uY2UuXG5cbiAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5uZXdTcmMgPSBuZXdTcmM7XG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUuaXNWaXNpYmxlID0gJCgnI2xhcmdlVmlkZW8nKS5pcygnOnZpc2libGUnKTtcbiAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5pc0Rlc2t0b3AgPSBBUFAuUlRDLmlzVmlkZW9TcmNEZXNrdG9wKFxuICAgICAgICAgICAgICAgIEFQUC54bXBwLmZpbmRKaWRGcm9tUmVzb3VyY2UocmVzb3VyY2VKaWQpKTtcblxuICAgICAgICAgICAgaWYobGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5vbGRSZXNvdXJjZUppZCA9IGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5vbGRSZXNvdXJjZUppZCA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkID0gcmVzb3VyY2VKaWQ7XG5cbiAgICAgICAgICAgIC8vIFNjcmVlbiBzdHJlYW0gaXMgYWxyZWFkeSByb3RhdGVkXG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUuZmxpcFggPSAobmV3U3JjID09PSBsb2NhbFZpZGVvU3JjKSAmJiBmbGlwWExvY2FsVmlkZW87XG5cbiAgICAgICAgICAgIHZhciB1c2VyQ2hhbmdlZCA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKGxhcmdlVmlkZW9TdGF0ZS5vbGRSZXNvdXJjZUppZCAhPT0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgICAgIHVzZXJDaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAvLyB3ZSB3YW50IHRoZSBub3RpZmljYXRpb24gdG8gdHJpZ2dlciBldmVuIGlmIHVzZXJKaWQgaXMgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIC8vIG9yIG51bGwuXG4gICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoVUlFdmVudHMuU0VMRUNURURfRU5EUE9JTlQsXG4gICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIWxhcmdlVmlkZW9TdGF0ZS51cGRhdGVJblByb2dyZXNzKSB7XG4gICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnVwZGF0ZUluUHJvZ3Jlc3MgPSB0cnVlO1xuXG4gICAgICAgICAgICAgICAgdmFyIGRvVXBkYXRlID0gZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgICAgICAgICAgIEF2YXRhci51cGRhdGVBY3RpdmVTcGVha2VyQXZhdGFyU3JjKFxuICAgICAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCF1c2VyQ2hhbmdlZCAmJiBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQgIT09IG51bGwgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIEFQUC5SVEMuZ2V0VmlkZW9TcmMoJChsYXJnZVZpZGVvU3RhdGUucHJlbG9hZClbMF0pID09PSBuZXdTcmMpXG4gICAgICAgICAgICAgICAgICAgIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdTd2l0Y2hpbmcgdG8gcHJlbG9hZGVkIHZpZGVvJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgYXR0cmlidXRlcyA9ICQoJyNsYXJnZVZpZGVvJykucHJvcChcImF0dHJpYnV0ZXNcIik7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvb3AgdGhyb3VnaCBsYXJnZVZpZGVvIGF0dHJpYnV0ZXMgYW5kIGFwcGx5IHRoZW0gb25cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHByZWxvYWQuXG4gICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXR0cmlidXRlcywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm5hbWUgIT09ICdpZCcgJiYgdGhpcy5uYW1lICE9PSAnc3JjJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZC5hdHRyKHRoaXMubmFtZSwgdGhpcy52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkLmFwcGVuZFRvKCQoJyNsYXJnZVZpZGVvQ29udGFpbmVyJykpO1xuICAgICAgICAgICAgICAgICAgICAgICAgJCgnI2xhcmdlVmlkZW8nKS5hdHRyKCdpZCcsICdwcmV2aW91c0xhcmdlVmlkZW8nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkLmF0dHIoJ2lkJywgJ2xhcmdlVmlkZW8nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICQoJyNwcmV2aW91c0xhcmdlVmlkZW8nKS5yZW1vdmUoKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQub24oJ2xvYWRlZG1ldGFkYXRhJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50VmlkZW9XaWR0aCA9IHRoaXMudmlkZW9XaWR0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50VmlkZW9IZWlnaHQgPSB0aGlzLnZpZGVvSGVpZ2h0O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnBvc2l0aW9uTGFyZ2UoY3VycmVudFZpZGVvV2lkdGgsIGN1cnJlbnRWaWRlb0hlaWdodCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkX3NzcmMgPSAwO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5zZXRWaWRlb1NyYygkKCcjbGFyZ2VWaWRlbycpWzBdLCBsYXJnZVZpZGVvU3RhdGUubmV3U3JjKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHZhciB2aWRlb1RyYW5zZm9ybSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsYXJnZVZpZGVvJylcbiAgICAgICAgICAgICAgICAgICAgICAgIC5zdHlsZS53ZWJraXRUcmFuc2Zvcm07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGxhcmdlVmlkZW9TdGF0ZS5mbGlwWCAmJiB2aWRlb1RyYW5zZm9ybSAhPT0gJ3NjYWxlWCgtMSknKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbGFyZ2VWaWRlbycpLnN0eWxlLndlYmtpdFRyYW5zZm9ybVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gXCJzY2FsZVgoLTEpXCI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoIWxhcmdlVmlkZW9TdGF0ZS5mbGlwWCAmJiB2aWRlb1RyYW5zZm9ybSA9PT0gJ3NjYWxlWCgtMSknKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbGFyZ2VWaWRlbycpLnN0eWxlLndlYmtpdFRyYW5zZm9ybVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gXCJub25lXCI7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBDaGFuZ2UgdGhlIHdheSB3ZSdsbCBiZSBtZWFzdXJpbmcgYW5kIHBvc2l0aW9uaW5nIGxhcmdlIHZpZGVvXG5cbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuZ2V0VmlkZW9TaXplID0gbGFyZ2VWaWRlb1N0YXRlLmlzRGVza3RvcFxuICAgICAgICAgICAgICAgICAgICAgICAgPyBnZXREZXNrdG9wVmlkZW9TaXplXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGdldENhbWVyYVZpZGVvU2l6ZTtcbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuZ2V0VmlkZW9Qb3NpdGlvbiA9IGxhcmdlVmlkZW9TdGF0ZS5pc0Rlc2t0b3BcbiAgICAgICAgICAgICAgICAgICAgICAgID8gZ2V0RGVza3RvcFZpZGVvUG9zaXRpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIDogZ2V0Q2FtZXJhVmlkZW9Qb3NpdGlvbjtcblxuXG4gICAgICAgICAgICAgICAgICAgIC8vIE9ubHkgaWYgdGhlIGxhcmdlIHZpZGVvIGlzIGN1cnJlbnRseSB2aXNpYmxlLlxuICAgICAgICAgICAgICAgICAgICAvLyBEaXNhYmxlIHByZXZpb3VzIGRvbWluYW50IHNwZWFrZXIgdmlkZW8uXG4gICAgICAgICAgICAgICAgICAgIGlmIChsYXJnZVZpZGVvU3RhdGUub2xkUmVzb3VyY2VKaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmVuYWJsZURvbWluYW50U3BlYWtlcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUub2xkUmVzb3VyY2VKaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gRW5hYmxlIG5ldyBkb21pbmFudCBzcGVha2VyIGluIHRoZSByZW1vdGUgdmlkZW9zIHNlY3Rpb24uXG4gICAgICAgICAgICAgICAgICAgIGlmIChsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5lbmFibGVEb21pbmFudFNwZWFrZXIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGlmICh1c2VyQ2hhbmdlZCAmJiBsYXJnZVZpZGVvU3RhdGUuaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB1c2luZyBcInRoaXNcIiBzaG91bGQgYmUgb2sgYmVjYXVzZSB3ZSdyZSBjYWxsZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZyb20gd2l0aGluIHRoZSBmYWRlT3V0IGV2ZW50LlxuICAgICAgICAgICAgICAgICAgICAgICAgJCh0aGlzKS5mYWRlSW4oMzAwKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGlmKHVzZXJDaGFuZ2VkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBBdmF0YXIuc2hvd1VzZXJBdmF0YXIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLm9sZFJlc291cmNlSmlkKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUudXBkYXRlSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBpZiAodXNlckNoYW5nZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgJCgnI2xhcmdlVmlkZW8nKS5mYWRlT3V0KDMwMCwgZG9VcGRhdGUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGRvVXBkYXRlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgQXZhdGFyLnNob3dVc2VyQXZhdGFyKFxuICAgICAgICAgICAgICAgIEFQUC54bXBwLmZpbmRKaWRGcm9tUmVzb3VyY2UoXG4gICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQpKTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgIG15LmhhbmRsZVZpZGVvVGh1bWJDbGlja2VkID0gZnVuY3Rpb24odmlkZW9TcmMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub1Bpbm5lZEVuZHBvaW50Q2hhbmdlZEV2ZW50LCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc291cmNlSmlkKSB7XG4gICAgICAgIC8vIFJlc3RvcmUgc3R5bGUgZm9yIHByZXZpb3VzbHkgZm9jdXNlZCB2aWRlb1xuICAgICAgICB2YXIgb2xkQ29udGFpbmVyID0gbnVsbDtcbiAgICAgICAgaWYoZm9jdXNlZFZpZGVvSW5mbykge1xuICAgICAgICAgICAgdmFyIGZvY3VzUmVzb3VyY2VKaWQgPSBmb2N1c2VkVmlkZW9JbmZvLnJlc291cmNlSmlkO1xuICAgICAgICAgICAgb2xkQ29udGFpbmVyID0gZ2V0UGFydGljaXBhbnRDb250YWluZXIoZm9jdXNSZXNvdXJjZUppZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob2xkQ29udGFpbmVyKSB7XG4gICAgICAgICAgICBvbGRDb250YWluZXIucmVtb3ZlQ2xhc3MoXCJ2aWRlb0NvbnRhaW5lckZvY3VzZWRcIik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVbmxvY2sgY3VycmVudCBmb2N1c2VkLlxuICAgICAgICBpZiAoZm9jdXNlZFZpZGVvSW5mbyAmJiBmb2N1c2VkVmlkZW9JbmZvLnNyYyA9PT0gdmlkZW9TcmMpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGZvY3VzZWRWaWRlb0luZm8gPSBudWxsO1xuICAgICAgICAgICAgdmFyIGRvbWluYW50U3BlYWtlclZpZGVvID0gbnVsbDtcbiAgICAgICAgICAgIC8vIEVuYWJsZSB0aGUgY3VycmVudGx5IHNldCBkb21pbmFudCBzcGVha2VyLlxuICAgICAgICAgICAgaWYgKGN1cnJlbnREb21pbmFudFNwZWFrZXIpIHtcbiAgICAgICAgICAgICAgICBkb21pbmFudFNwZWFrZXJWaWRlb1xuICAgICAgICAgICAgICAgICAgICA9ICQoJyNwYXJ0aWNpcGFudF8nICsgY3VycmVudERvbWluYW50U3BlYWtlciArICc+dmlkZW8nKVxuICAgICAgICAgICAgICAgICAgICAgICAgLmdldCgwKTtcblxuICAgICAgICAgICAgICAgIGlmIChkb21pbmFudFNwZWFrZXJWaWRlbykge1xuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKFxuICAgICAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5nZXRWaWRlb1NyYyhkb21pbmFudFNwZWFrZXJWaWRlbyksXG4gICAgICAgICAgICAgICAgICAgICAgICAxLFxuICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudERvbWluYW50U3BlYWtlcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIW5vUGlubmVkRW5kcG9pbnRDaGFuZ2VkRXZlbnQpIHtcbiAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChVSUV2ZW50cy5QSU5ORURfRU5EUE9JTlQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTG9jayBuZXcgdmlkZW9cbiAgICAgICAgZm9jdXNlZFZpZGVvSW5mbyA9IHtcbiAgICAgICAgICAgIHNyYzogdmlkZW9TcmMsXG4gICAgICAgICAgICByZXNvdXJjZUppZDogcmVzb3VyY2VKaWRcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBVcGRhdGUgZm9jdXNlZC9waW5uZWQgaW50ZXJmYWNlLlxuICAgICAgICBpZiAocmVzb3VyY2VKaWQpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBjb250YWluZXIgPSBnZXRQYXJ0aWNpcGFudENvbnRhaW5lcihyZXNvdXJjZUppZCk7XG4gICAgICAgICAgICBjb250YWluZXIuYWRkQ2xhc3MoXCJ2aWRlb0NvbnRhaW5lckZvY3VzZWRcIik7XG5cbiAgICAgICAgICAgIGlmICghbm9QaW5uZWRFbmRwb2ludENoYW5nZWRFdmVudCkge1xuICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFVJRXZlbnRzLlBJTk5FRF9FTkRQT0lOVCwgcmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCQoJyNsYXJnZVZpZGVvJykuYXR0cignc3JjJykgPT09IHZpZGVvU3JjICYmXG4gICAgICAgICAgICBWaWRlb0xheW91dC5pc0xhcmdlVmlkZW9PblRvcCgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUcmlnZ2VycyBhIFwidmlkZW8uc2VsZWN0ZWRcIiBldmVudC4gVGhlIFwiZmFsc2VcIiBwYXJhbWV0ZXIgaW5kaWNhdGVzXG4gICAgICAgIC8vIHRoaXMgaXNuJ3QgYSBwcmV6aS5cbiAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcihcInZpZGVvLnNlbGVjdGVkXCIsIFtmYWxzZV0pO1xuXG4gICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8odmlkZW9TcmMsIDEsIHJlc291cmNlSmlkKTtcblxuICAgICAgICAkKCdhdWRpbycpLmVhY2goZnVuY3Rpb24gKGlkeCwgZWwpIHtcbiAgICAgICAgICAgIGlmIChlbC5pZC5pbmRleE9mKCdtaXhlZG1zbGFiZWwnKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBlbC52b2x1bWUgPSAwO1xuICAgICAgICAgICAgICAgIGVsLnZvbHVtZSA9IDE7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBQb3NpdGlvbnMgdGhlIGxhcmdlIHZpZGVvLlxuICAgICAqXG4gICAgICogQHBhcmFtIHZpZGVvV2lkdGggdGhlIHN0cmVhbSB2aWRlbyB3aWR0aFxuICAgICAqIEBwYXJhbSB2aWRlb0hlaWdodCB0aGUgc3RyZWFtIHZpZGVvIGhlaWdodFxuICAgICAqL1xuICAgIG15LnBvc2l0aW9uTGFyZ2UgPSBmdW5jdGlvbiAodmlkZW9XaWR0aCwgdmlkZW9IZWlnaHQpIHtcbiAgICAgICAgdmFyIHZpZGVvU3BhY2VXaWR0aCA9ICQoJyN2aWRlb3NwYWNlJykud2lkdGgoKTtcbiAgICAgICAgdmFyIHZpZGVvU3BhY2VIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG5cbiAgICAgICAgdmFyIHZpZGVvU2l6ZSA9IFZpZGVvTGF5b3V0LmdldFZpZGVvU2l6ZSh2aWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlSGVpZ2h0KTtcblxuICAgICAgICB2YXIgbGFyZ2VWaWRlb1dpZHRoID0gdmlkZW9TaXplWzBdO1xuICAgICAgICB2YXIgbGFyZ2VWaWRlb0hlaWdodCA9IHZpZGVvU2l6ZVsxXTtcblxuICAgICAgICB2YXIgdmlkZW9Qb3NpdGlvbiA9IFZpZGVvTGF5b3V0LmdldFZpZGVvUG9zaXRpb24obGFyZ2VWaWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb0hlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VIZWlnaHQpO1xuXG4gICAgICAgIHZhciBob3Jpem9udGFsSW5kZW50ID0gdmlkZW9Qb3NpdGlvblswXTtcbiAgICAgICAgdmFyIHZlcnRpY2FsSW5kZW50ID0gdmlkZW9Qb3NpdGlvblsxXTtcblxuICAgICAgICBwb3NpdGlvblZpZGVvKCQoJyNsYXJnZVZpZGVvJyksXG4gICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9IZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgaG9yaXpvbnRhbEluZGVudCwgdmVydGljYWxJbmRlbnQpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cy9oaWRlcyB0aGUgbGFyZ2UgdmlkZW8uXG4gICAgICovXG4gICAgbXkuc2V0TGFyZ2VWaWRlb1Zpc2libGUgPSBmdW5jdGlvbihpc1Zpc2libGUpIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZDtcblxuICAgICAgICBpZiAoaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmNzcyh7dmlzaWJpbGl0eTogJ3Zpc2libGUnfSk7XG4gICAgICAgICAgICAkKCcud2F0ZXJtYXJrJykuY3NzKHt2aXNpYmlsaXR5OiAndmlzaWJsZSd9KTtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmVuYWJsZURvbWluYW50U3BlYWtlcihyZXNvdXJjZUppZCwgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmNzcyh7dmlzaWJpbGl0eTogJ2hpZGRlbid9KTtcbiAgICAgICAgICAgICQoJyNhY3RpdmVTcGVha2VyJykuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuICAgICAgICAgICAgJCgnLndhdGVybWFyaycpLmNzcyh7dmlzaWJpbGl0eTogJ2hpZGRlbid9KTtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmVuYWJsZURvbWluYW50U3BlYWtlcihyZXNvdXJjZUppZCwgZmFsc2UpO1xuICAgICAgICAgICAgaWYoZm9jdXNlZFZpZGVvSW5mbykge1xuICAgICAgICAgICAgICAgIHZhciBmb2N1c1Jlc291cmNlSmlkID0gZm9jdXNlZFZpZGVvSW5mby5yZXNvdXJjZUppZDtcbiAgICAgICAgICAgICAgICB2YXIgb2xkQ29udGFpbmVyID0gZ2V0UGFydGljaXBhbnRDb250YWluZXIoZm9jdXNSZXNvdXJjZUppZCk7XG5cbiAgICAgICAgICAgICAgICBpZiAob2xkQ29udGFpbmVyICYmIG9sZENvbnRhaW5lci5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIG9sZENvbnRhaW5lci5yZW1vdmVDbGFzcyhcInZpZGVvQ29udGFpbmVyRm9jdXNlZFwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9jdXNlZFZpZGVvSW5mbyA9IG51bGw7XG4gICAgICAgICAgICAgICAgaWYoZm9jdXNSZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgICAgICAgICBBdmF0YXIuc2hvd1VzZXJBdmF0YXIoXG4gICAgICAgICAgICAgICAgICAgICAgICBBUFAueG1wcC5maW5kSmlkRnJvbVJlc291cmNlKGZvY3VzUmVzb3VyY2VKaWQpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSW5kaWNhdGVzIGlmIHRoZSBsYXJnZSB2aWRlbyBpcyBjdXJyZW50bHkgdmlzaWJsZS5cbiAgICAgKlxuICAgICAqIEByZXR1cm4gPHR0PnRydWU8L3R0PiBpZiB2aXNpYmxlLCA8dHQ+ZmFsc2U8L3R0PiAtIG90aGVyd2lzZVxuICAgICAqL1xuICAgIG15LmlzTGFyZ2VWaWRlb1Zpc2libGUgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuICQoJyNsYXJnZVZpZGVvJykuaXMoJzp2aXNpYmxlJyk7XG4gICAgfTtcblxuICAgIG15LmlzTGFyZ2VWaWRlb09uVG9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgRXRoZXJwYWQgPSByZXF1aXJlKFwiLi4vZXRoZXJwYWQvRXRoZXJwYWRcIik7XG4gICAgICAgIHZhciBQcmV6aSA9IHJlcXVpcmUoXCIuLi9wcmV6aS9QcmV6aVwiKTtcbiAgICAgICAgcmV0dXJuICFQcmV6aS5pc1ByZXNlbnRhdGlvblZpc2libGUoKSAmJiAhRXRoZXJwYWQuaXNWaXNpYmxlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBjb250YWluZXIgZm9yIHBhcnRpY2lwYW50IGlkZW50aWZpZWQgYnkgZ2l2ZW4gcGVlckppZCBleGlzdHNcbiAgICAgKiBpbiB0aGUgZG9jdW1lbnQgYW5kIGNyZWF0ZXMgaXQgZXZlbnR1YWxseS5cbiAgICAgKiBcbiAgICAgKiBAcGFyYW0gcGVlckppZCBwZWVyIEppZCB0byBjaGVjay5cbiAgICAgKiBAcGFyYW0gdXNlcklkIHVzZXIgZW1haWwgb3IgaWQgZm9yIHNldHRpbmcgdGhlIGF2YXRhclxuICAgICAqIFxuICAgICAqIEByZXR1cm4gUmV0dXJucyA8dHQ+dHJ1ZTwvdHQ+IGlmIHRoZSBwZWVyIGNvbnRhaW5lciBleGlzdHMsXG4gICAgICogPHR0PmZhbHNlPC90dD4gLSBvdGhlcndpc2VcbiAgICAgKi9cbiAgICBteS5lbnN1cmVQZWVyQ29udGFpbmVyRXhpc3RzID0gZnVuY3Rpb24ocGVlckppZCwgdXNlcklkKSB7XG4gICAgICAgIENvbnRhY3RMaXN0LmVuc3VyZUFkZENvbnRhY3QocGVlckppZCwgdXNlcklkKTtcblxuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChwZWVySmlkKTtcblxuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkO1xuXG4gICAgICAgIGlmICghJCgnIycgKyB2aWRlb1NwYW5JZCkubGVuZ3RoKSB7XG4gICAgICAgICAgICB2YXIgY29udGFpbmVyID1cbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5hZGRSZW1vdGVWaWRlb0NvbnRhaW5lcihwZWVySmlkLCB2aWRlb1NwYW5JZCwgdXNlcklkKTtcbiAgICAgICAgICAgIEF2YXRhci5zZXRVc2VyQXZhdGFyKHBlZXJKaWQsIHVzZXJJZCk7XG4gICAgICAgICAgICAvLyBTZXQgZGVmYXVsdCBkaXNwbGF5IG5hbWUuXG4gICAgICAgICAgICBzZXREaXNwbGF5TmFtZSh2aWRlb1NwYW5JZCk7XG5cbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW3ZpZGVvU3BhbklkXSA9XG4gICAgICAgICAgICAgICAgbmV3IENvbm5lY3Rpb25JbmRpY2F0b3IoY29udGFpbmVyLCBwZWVySmlkLCBWaWRlb0xheW91dCk7XG5cbiAgICAgICAgICAgIHZhciBuaWNrZmllbGQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgICAgICBuaWNrZmllbGQuY2xhc3NOYW1lID0gXCJuaWNrXCI7XG4gICAgICAgICAgICBuaWNrZmllbGQuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUocmVzb3VyY2VKaWQpKTtcbiAgICAgICAgICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChuaWNrZmllbGQpO1xuXG4gICAgICAgICAgICAvLyBJbiBjYXNlIHRoaXMgaXMgbm90IGN1cnJlbnRseSBpbiB0aGUgbGFzdCBuIHdlIGRvbid0IHNob3cgaXQuXG4gICAgICAgICAgICBpZiAobG9jYWxMYXN0TkNvdW50XG4gICAgICAgICAgICAgICAgJiYgbG9jYWxMYXN0TkNvdW50ID4gMFxuICAgICAgICAgICAgICAgICYmICQoJyNyZW1vdGVWaWRlb3M+c3BhbicpLmxlbmd0aCA+PSBsb2NhbExhc3ROQ291bnQgKyAyKSB7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdoaWRlJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplVGh1bWJuYWlscygpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIG15LmFkZFJlbW90ZVZpZGVvQ29udGFpbmVyID0gZnVuY3Rpb24ocGVlckppZCwgc3BhbklkKSB7XG4gICAgICAgIHZhciBjb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgIGNvbnRhaW5lci5pZCA9IHNwYW5JZDtcbiAgICAgICAgY29udGFpbmVyLmNsYXNzTmFtZSA9ICd2aWRlb2NvbnRhaW5lcic7XG4gICAgICAgIHZhciByZW1vdGVzID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3JlbW90ZVZpZGVvcycpO1xuICAgICAgICByZW1vdGVzLmFwcGVuZENoaWxkKGNvbnRhaW5lcik7XG4gICAgICAgIC8vIElmIHRoZSBwZWVySmlkIGlzIG51bGwgdGhlbiB0aGlzIHZpZGVvIHNwYW4gY291bGRuJ3QgYmUgZGlyZWN0bHlcbiAgICAgICAgLy8gYXNzb2NpYXRlZCB3aXRoIGEgcGFydGljaXBhbnQgKHRoaXMgY291bGQgaGFwcGVuIGluIHRoZSBjYXNlIG9mIHByZXppKS5cbiAgICAgICAgaWYgKEFQUC54bXBwLmlzTW9kZXJhdG9yKCkgJiYgcGVlckppZCAhPT0gbnVsbClcbiAgICAgICAgICAgIGFkZFJlbW90ZVZpZGVvTWVudShwZWVySmlkLCBjb250YWluZXIpO1xuICAgICAgICBBdWRpb0xldmVscy51cGRhdGVBdWRpb0xldmVsQ2FudmFzKHBlZXJKaWQsIFZpZGVvTGF5b3V0KTtcblxuICAgICAgICByZXR1cm4gY29udGFpbmVyO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGF1ZGlvIG9yIHZpZGVvIHN0cmVhbSBlbGVtZW50LlxuICAgICAqL1xuICAgIG15LmNyZWF0ZVN0cmVhbUVsZW1lbnQgPSBmdW5jdGlvbiAoc2lkLCBzdHJlYW0pIHtcbiAgICAgICAgdmFyIGlzVmlkZW8gPSBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGggPiAwO1xuXG4gICAgICAgIHZhciBlbGVtZW50ID0gaXNWaWRlb1xuICAgICAgICAgICAgICAgICAgICAgICAgPyBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd2aWRlbycpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2F1ZGlvJyk7XG4gICAgICAgIHZhciBpZCA9IChpc1ZpZGVvID8gJ3JlbW90ZVZpZGVvXycgOiAncmVtb3RlQXVkaW9fJylcbiAgICAgICAgICAgICAgICAgICAgKyBzaWQgKyAnXycgKyBBUFAuUlRDLmdldFN0cmVhbUlEKHN0cmVhbSk7XG5cbiAgICAgICAgZWxlbWVudC5pZCA9IGlkO1xuICAgICAgICBlbGVtZW50LmF1dG9wbGF5ID0gdHJ1ZTtcbiAgICAgICAgZWxlbWVudC5vbmNvbnRleHRtZW51ID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gZmFsc2U7IH07XG5cbiAgICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfTtcblxuICAgIG15LmFkZFJlbW90ZVN0cmVhbUVsZW1lbnRcbiAgICAgICAgPSBmdW5jdGlvbiAoY29udGFpbmVyLCBzaWQsIHN0cmVhbSwgcGVlckppZCwgdGhlc3NyYykge1xuICAgICAgICB2YXIgbmV3RWxlbWVudElkID0gbnVsbDtcblxuICAgICAgICB2YXIgaXNWaWRlbyA9IHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLmxlbmd0aCA+IDA7XG5cbiAgICAgICAgaWYgKGNvbnRhaW5lcikge1xuICAgICAgICAgICAgdmFyIHN0cmVhbUVsZW1lbnQgPSBWaWRlb0xheW91dC5jcmVhdGVTdHJlYW1FbGVtZW50KHNpZCwgc3RyZWFtKTtcbiAgICAgICAgICAgIG5ld0VsZW1lbnRJZCA9IHN0cmVhbUVsZW1lbnQuaWQ7XG5cbiAgICAgICAgICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChzdHJlYW1FbGVtZW50KTtcblxuICAgICAgICAgICAgdmFyIHNlbCA9ICQoJyMnICsgbmV3RWxlbWVudElkKTtcbiAgICAgICAgICAgIHNlbC5oaWRlKCk7XG5cbiAgICAgICAgICAgIC8vIElmIHRoZSBjb250YWluZXIgaXMgY3VycmVudGx5IHZpc2libGUgd2UgYXR0YWNoIHRoZSBzdHJlYW0uXG4gICAgICAgICAgICBpZiAoIWlzVmlkZW9cbiAgICAgICAgICAgICAgICB8fCAoY29udGFpbmVyLm9mZnNldFBhcmVudCAhPT0gbnVsbCAmJiBpc1ZpZGVvKSkge1xuICAgICAgICAgICAgICAgIHZhciB2aWRlb1N0cmVhbSA9IEFQUC5zaW11bGNhc3QuZ2V0UmVjZWl2aW5nVmlkZW9TdHJlYW0oc3RyZWFtKTtcbiAgICAgICAgICAgICAgICBBUFAuUlRDLmF0dGFjaE1lZGlhU3RyZWFtKHNlbCwgdmlkZW9TdHJlYW0pO1xuXG4gICAgICAgICAgICAgICAgaWYgKGlzVmlkZW8pXG4gICAgICAgICAgICAgICAgICAgIHdhaXRGb3JSZW1vdGVWaWRlbyhzZWwsIHRoZXNzcmMsIHN0cmVhbSwgcGVlckppZCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHN0cmVhbS5vbmVuZGVkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzdHJlYW0gZW5kZWQnLCB0aGlzKTtcblxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnJlbW92ZVJlbW90ZVN0cmVhbUVsZW1lbnQoXG4gICAgICAgICAgICAgICAgICAgIHN0cmVhbSwgaXNWaWRlbywgY29udGFpbmVyKTtcblxuICAgICAgICAgICAgICAgIC8vIE5PVEUoZ3ApIGl0IHNlZW1zIHRoYXQgdW5kZXIgY2VydGFpbiBjaXJjdW1zdGFuY2VzLCB0aGVcbiAgICAgICAgICAgICAgICAvLyBvbmVuZGVkIGV2ZW50IGlzIG5vdCBmaXJlZCBhbmQgdGh1cyB0aGUgY29udGFjdCBsaXN0IGlzIG5vdFxuICAgICAgICAgICAgICAgIC8vIHVwZGF0ZWQuXG4gICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAvLyBUaGUgb25lbmRlZCBldmVudCBvZiBhIHN0cmVhbSBzaG91bGQgYmUgZmlyZWQgd2hlbiB0aGUgU1NSQ3NcbiAgICAgICAgICAgICAgICAvLyBjb3JyZXNwb25kaW5nIHRvIHRoYXQgc3RyZWFtIGFyZSByZW1vdmVkIGZyb20gdGhlIFNEUDsgYnV0XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBkb2Vzbid0IHNlZW0gdG8gYWx3YXlzIGJlIHRoZSBjYXNlLCByZXN1bHRpbmcgaW4gZ2hvc3RcbiAgICAgICAgICAgICAgICAvLyBjb250YWN0cy5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIC8vIEluIGFuIGF0dGVtcHQgdG8gZml4IHRoZSBnaG9zdCBjb250YWN0cyBwcm9ibGVtLCBJJ20gbW92aW5nXG4gICAgICAgICAgICAgICAgLy8gdGhlIHJlbW92ZUNvbnRhY3QoKSBtZXRob2QgY2FsbCBpbiBhcHAuanMsIGluc2lkZSB0aGVcbiAgICAgICAgICAgICAgICAvLyAnbXVjLmxlZnQnIGV2ZW50IGhhbmRsZXIuXG5cbiAgICAgICAgICAgICAgICAvL2lmIChwZWVySmlkKVxuICAgICAgICAgICAgICAgIC8vICAgIENvbnRhY3RMaXN0LnJlbW92ZUNvbnRhY3QocGVlckppZCk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvLyBBZGQgY2xpY2sgaGFuZGxlci5cbiAgICAgICAgICAgIGNvbnRhaW5lci5vbmNsaWNrID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAgICAgKiBGSVhNRSBJdCB0dXJucyBvdXQgdGhhdCB2aWRlb1RodW1iIG1heSBub3QgZXhpc3QgKGlmIHRoZXJlIGlzXG4gICAgICAgICAgICAgICAgICogbm8gYWN0dWFsIHZpZGVvKS5cbiAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICB2YXIgdmlkZW9UaHVtYiA9ICQoJyMnICsgY29udGFpbmVyLmlkICsgJz52aWRlbycpLmdldCgwKTtcbiAgICAgICAgICAgICAgICBpZiAodmlkZW9UaHVtYikge1xuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5oYW5kbGVWaWRlb1RodW1iQ2xpY2tlZChcbiAgICAgICAgICAgICAgICAgICAgICAgIEFQUC5SVEMuZ2V0VmlkZW9TcmModmlkZW9UaHVtYiksXG4gICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKHBlZXJKaWQpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8vIEFkZCBob3ZlciBoYW5kbGVyXG4gICAgICAgICAgICAkKGNvbnRhaW5lcikuaG92ZXIoXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dEaXNwbGF5TmFtZShjb250YWluZXIuaWQsIHRydWUpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2aWRlb1NyYyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkKCcjJyArIGNvbnRhaW5lci5pZCArICc+dmlkZW8nKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmICQoJyMnICsgY29udGFpbmVyLmlkICsgJz52aWRlbycpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3JjID0gQVBQLlJUQy5nZXRWaWRlb1NyYygkKCcjJyArIGNvbnRhaW5lci5pZCArICc+dmlkZW8nKS5nZXQoMCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIHZpZGVvIGhhcyBiZWVuIFwicGlubmVkXCIgYnkgdGhlIHVzZXIgd2Ugd2FudCB0b1xuICAgICAgICAgICAgICAgICAgICAvLyBrZWVwIHRoZSBkaXNwbGF5IG5hbWUgb24gcGxhY2UuXG4gICAgICAgICAgICAgICAgICAgIGlmICghVmlkZW9MYXlvdXQuaXNMYXJnZVZpZGVvVmlzaWJsZSgpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfHwgdmlkZW9TcmMgIT09IEFQUC5SVEMuZ2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSkpXG4gICAgICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5zaG93RGlzcGxheU5hbWUoY29udGFpbmVyLmlkLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBuZXdFbGVtZW50SWQ7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgdGhlIHJlbW90ZSBzdHJlYW0gZWxlbWVudCBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiBzdHJlYW0gYW5kXG4gICAgICogcGFyZW50IGNvbnRhaW5lci5cbiAgICAgKiBcbiAgICAgKiBAcGFyYW0gc3RyZWFtIHRoZSBzdHJlYW1cbiAgICAgKiBAcGFyYW0gaXNWaWRlbyA8dHQ+dHJ1ZTwvdHQ+IGlmIGdpdmVuIDx0dD5zdHJlYW08L3R0PiBpcyBhIHZpZGVvIG9uZS5cbiAgICAgKiBAcGFyYW0gY29udGFpbmVyXG4gICAgICovXG4gICAgbXkucmVtb3ZlUmVtb3RlU3RyZWFtRWxlbWVudCA9IGZ1bmN0aW9uIChzdHJlYW0sIGlzVmlkZW8sIGNvbnRhaW5lcikge1xuICAgICAgICBpZiAoIWNvbnRhaW5lcilcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB2YXIgc2VsZWN0ID0gbnVsbDtcbiAgICAgICAgdmFyIHJlbW92ZWRWaWRlb1NyYyA9IG51bGw7XG4gICAgICAgIGlmIChpc1ZpZGVvKSB7XG4gICAgICAgICAgICBzZWxlY3QgPSAkKCcjJyArIGNvbnRhaW5lci5pZCArICc+dmlkZW8nKTtcbiAgICAgICAgICAgIHJlbW92ZWRWaWRlb1NyYyA9IEFQUC5SVEMuZ2V0VmlkZW9TcmMoc2VsZWN0LmdldCgwKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgc2VsZWN0ID0gJCgnIycgKyBjb250YWluZXIuaWQgKyAnPmF1ZGlvJyk7XG5cblxuICAgICAgICAvLyBNYXJrIHZpZGVvIGFzIHJlbW92ZWQgdG8gY2FuY2VsIHdhaXRpbmcgbG9vcChpZiB2aWRlbyBpcyByZW1vdmVkXG4gICAgICAgIC8vIGJlZm9yZSBoYXMgc3RhcnRlZClcbiAgICAgICAgc2VsZWN0LnJlbW92ZWQgPSB0cnVlO1xuICAgICAgICBzZWxlY3QucmVtb3ZlKCk7XG5cbiAgICAgICAgdmFyIGF1ZGlvQ291bnQgPSAkKCcjJyArIGNvbnRhaW5lci5pZCArICc+YXVkaW8nKS5sZW5ndGg7XG4gICAgICAgIHZhciB2aWRlb0NvdW50ID0gJCgnIycgKyBjb250YWluZXIuaWQgKyAnPnZpZGVvJykubGVuZ3RoO1xuXG4gICAgICAgIGlmICghYXVkaW9Db3VudCAmJiAhdmlkZW9Db3VudCkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJSZW1vdmUgd2hvbGUgdXNlclwiLCBjb250YWluZXIuaWQpO1xuICAgICAgICAgICAgaWYoVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbY29udGFpbmVyLmlkXSlcbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tjb250YWluZXIuaWRdLnJlbW92ZSgpO1xuICAgICAgICAgICAgLy8gUmVtb3ZlIHdob2xlIGNvbnRhaW5lclxuICAgICAgICAgICAgY29udGFpbmVyLnJlbW92ZSgpO1xuXG4gICAgICAgICAgICBVSVV0aWwucGxheVNvdW5kTm90aWZpY2F0aW9uKCd1c2VyTGVmdCcpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplVGh1bWJuYWlscygpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJlbW92ZWRWaWRlb1NyYylcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZVJlbW92ZWRWaWRlbyhyZW1vdmVkVmlkZW9TcmMpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93L2hpZGUgcGVlciBjb250YWluZXIgZm9yIHRoZSBnaXZlbiByZXNvdXJjZUppZC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBzaG93UGVlckNvbnRhaW5lcihyZXNvdXJjZUppZCwgc3RhdGUpIHtcbiAgICAgICAgdmFyIHBlZXJDb250YWluZXIgPSAkKCcjcGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICBpZiAoIXBlZXJDb250YWluZXIpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdmFyIGlzSGlkZSA9IHN0YXRlID09PSAnaGlkZSc7XG4gICAgICAgIHZhciByZXNpemVUaHVtYm5haWxzID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKCFpc0hpZGUpIHtcbiAgICAgICAgICAgIGlmICghcGVlckNvbnRhaW5lci5pcygnOnZpc2libGUnKSkge1xuICAgICAgICAgICAgICAgIHJlc2l6ZVRodW1ibmFpbHMgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHBlZXJDb250YWluZXIuc2hvdygpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgamlkID0gQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShyZXNvdXJjZUppZCk7XG4gICAgICAgICAgICBpZiAoc3RhdGUgPT0gJ3Nob3cnKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIC8vIHBlZXJDb250YWluZXIuY3NzKCctd2Via2l0LWZpbHRlcicsICcnKTtcblxuICAgICAgICAgICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihqaWQsIGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgLy8gaWYgKHN0YXRlID09ICdhdmF0YXInKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIC8vIHBlZXJDb250YWluZXIuY3NzKCctd2Via2l0LWZpbHRlcicsICdncmF5c2NhbGUoMTAwJSknKTtcbiAgICAgICAgICAgICAgICBBdmF0YXIuc2hvd1VzZXJBdmF0YXIoamlkLCB0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChwZWVyQ29udGFpbmVyLmlzKCc6dmlzaWJsZScpICYmIGlzSGlkZSlcbiAgICAgICAge1xuICAgICAgICAgICAgcmVzaXplVGh1bWJuYWlscyA9IHRydWU7XG4gICAgICAgICAgICBwZWVyQ29udGFpbmVyLmhpZGUoKTtcbiAgICAgICAgICAgIGlmKFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzWydwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWRdKVxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzWydwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWRdLmhpZGUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyZXNpemVUaHVtYm5haWxzKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5yZXNpemVUaHVtYm5haWxzKCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBXZSB3YW50IHRvIGJlIGFibGUgdG8gcGluIGEgcGFydGljaXBhbnQgZnJvbSB0aGUgY29udGFjdCBsaXN0LCBldmVuXG4gICAgICAgIC8vIGlmIGhlJ3Mgbm90IGluIHRoZSBsYXN0TiBzZXQhXG4gICAgICAgIC8vIENvbnRhY3RMaXN0LnNldENsaWNrYWJsZShyZXNvdXJjZUppZCwgIWlzSGlkZSk7XG5cbiAgICB9O1xuXG4gICAgbXkuaW5wdXREaXNwbGF5TmFtZUhhbmRsZXIgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICBOaWNrbmFtZUhhbmRsZXIuc2V0Tmlja25hbWUobmFtZSk7XG5cbiAgICAgICAgaWYgKCEkKCcjbG9jYWxEaXNwbGF5TmFtZScpLmlzKFwiOnZpc2libGVcIikpIHtcbiAgICAgICAgICAgIGlmIChOaWNrbmFtZUhhbmRsZXIuZ2V0Tmlja25hbWUoKSlcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB2YXIgbWVIVE1MID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXCJtZVwiKTtcbiAgICAgICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLmh0bWwoTmlja25hbWVIYW5kbGVyLmdldE5pY2tuYW1lKCkgKyBcIiAoXCIgKyBtZUhUTUwgKyBcIilcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdmFyIGRlZmF1bHRIVE1MID0gQVBQLnRyYW5zbGF0aW9uLmdlbmVyYXRlVHJhbnNsYXRvbkhUTUwoXG4gICAgICAgICAgICAgICAgICAgIGludGVyZmFjZUNvbmZpZy5ERUZBVUxUX0xPQ0FMX0RJU1BMQVlfTkFNRSk7XG4gICAgICAgICAgICAgICAgJCgnI2xvY2FsRGlzcGxheU5hbWUnKVxuICAgICAgICAgICAgICAgICAgICAuaHRtbChkZWZhdWx0SFRNTCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLnNob3coKTtcbiAgICAgICAgfVxuXG4gICAgICAgICQoJyNlZGl0RGlzcGxheU5hbWUnKS5oaWRlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzL2hpZGVzIHRoZSBkaXNwbGF5IG5hbWUgb24gdGhlIHJlbW90ZSB2aWRlby5cbiAgICAgKiBAcGFyYW0gdmlkZW9TcGFuSWQgdGhlIGlkZW50aWZpZXIgb2YgdGhlIHZpZGVvIHNwYW4gZWxlbWVudFxuICAgICAqIEBwYXJhbSBpc1Nob3cgaW5kaWNhdGVzIGlmIHRoZSBkaXNwbGF5IG5hbWUgc2hvdWxkIGJlIHNob3duIG9yIGhpZGRlblxuICAgICAqL1xuICAgIG15LnNob3dEaXNwbGF5TmFtZSA9IGZ1bmN0aW9uKHZpZGVvU3BhbklkLCBpc1Nob3cpIHtcbiAgICAgICAgdmFyIG5hbWVTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi5kaXNwbGF5bmFtZScpLmdldCgwKTtcbiAgICAgICAgaWYgKGlzU2hvdykge1xuICAgICAgICAgICAgaWYgKG5hbWVTcGFuICYmIG5hbWVTcGFuLmlubmVySFRNTCAmJiBuYW1lU3Bhbi5pbm5lckhUTUwubGVuZ3RoKSBcbiAgICAgICAgICAgICAgICBuYW1lU3Bhbi5zZXRBdHRyaWJ1dGUoXCJzdHlsZVwiLCBcImRpc3BsYXk6aW5saW5lLWJsb2NrO1wiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGlmIChuYW1lU3BhbilcbiAgICAgICAgICAgICAgICBuYW1lU3Bhbi5zZXRBdHRyaWJ1dGUoXCJzdHlsZVwiLCBcImRpc3BsYXk6bm9uZTtcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2hvd3MgdGhlIHByZXNlbmNlIHN0YXR1cyBtZXNzYWdlIGZvciB0aGUgZ2l2ZW4gdmlkZW8uXG4gICAgICovXG4gICAgbXkuc2V0UHJlc2VuY2VTdGF0dXMgPSBmdW5jdGlvbiAodmlkZW9TcGFuSWQsIHN0YXR1c01zZykge1xuXG4gICAgICAgIGlmICghJCgnIycgKyB2aWRlb1NwYW5JZCkubGVuZ3RoKSB7XG4gICAgICAgICAgICAvLyBObyBjb250YWluZXJcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBzdGF0dXNTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi5zdGF0dXMnKTtcbiAgICAgICAgaWYgKCFzdGF0dXNTcGFuLmxlbmd0aCkge1xuICAgICAgICAgICAgLy9BZGQgc3RhdHVzIHNwYW5cbiAgICAgICAgICAgIHN0YXR1c1NwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgICAgICBzdGF0dXNTcGFuLmNsYXNzTmFtZSA9ICdzdGF0dXMnO1xuICAgICAgICAgICAgc3RhdHVzU3Bhbi5pZCA9IHZpZGVvU3BhbklkICsgJ19zdGF0dXMnO1xuICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQoc3RhdHVzU3Bhbik7XG5cbiAgICAgICAgICAgIHN0YXR1c1NwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLnN0YXR1cycpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRGlzcGxheSBzdGF0dXNcbiAgICAgICAgaWYgKHN0YXR1c01zZyAmJiBzdGF0dXNNc2cubGVuZ3RoKSB7XG4gICAgICAgICAgICAkKCcjJyArIHZpZGVvU3BhbklkICsgJ19zdGF0dXMnKS50ZXh0KHN0YXR1c01zZyk7XG4gICAgICAgICAgICBzdGF0dXNTcGFuLmdldCgwKS5zZXRBdHRyaWJ1dGUoXCJzdHlsZVwiLCBcImRpc3BsYXk6aW5saW5lLWJsb2NrO1wiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIEhpZGVcbiAgICAgICAgICAgIHN0YXR1c1NwYW4uZ2V0KDApLnNldEF0dHJpYnV0ZShcInN0eWxlXCIsIFwiZGlzcGxheTpub25lO1wiKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyBhIHZpc3VhbCBpbmRpY2F0b3IgZm9yIHRoZSBtb2RlcmF0b3Igb2YgdGhlIGNvbmZlcmVuY2UuXG4gICAgICovXG4gICAgbXkuc2hvd01vZGVyYXRvckluZGljYXRvciA9IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB2YXIgaXNNb2RlcmF0b3IgPSBBUFAueG1wcC5pc01vZGVyYXRvcigpO1xuICAgICAgICBpZiAoaXNNb2RlcmF0b3IpIHtcbiAgICAgICAgICAgIHZhciBpbmRpY2F0b3JTcGFuID0gJCgnI2xvY2FsVmlkZW9Db250YWluZXIgLmZvY3VzaW5kaWNhdG9yJyk7XG5cbiAgICAgICAgICAgIGlmIChpbmRpY2F0b3JTcGFuLmNoaWxkcmVuKCkubGVuZ3RoID09PSAwKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGNyZWF0ZU1vZGVyYXRvckluZGljYXRvckVsZW1lbnQoaW5kaWNhdG9yU3BhblswXSk7XG4gICAgICAgICAgICAgICAgLy90cmFuc2xhdGVzIHRleHQgaW4gZm9jdXMgaW5kaWNhdG9yXG4gICAgICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZUVsZW1lbnQoJCgnI2xvY2FsVmlkZW9Db250YWluZXIgLmZvY3VzaW5kaWNhdG9yJykpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdmFyIG1lbWJlcnMgPSBBUFAueG1wcC5nZXRNZW1iZXJzKCk7XG5cbiAgICAgICAgT2JqZWN0LmtleXMobWVtYmVycykuZm9yRWFjaChmdW5jdGlvbiAoamlkKSB7XG5cbiAgICAgICAgICAgIGlmIChTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpID09PSAnZm9jdXMnKSB7XG4gICAgICAgICAgICAgICAgLy8gU2tpcCBzZXJ2ZXIgc2lkZSBmb2N1c1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgICAgIHZhciB2aWRlb1NwYW5JZCA9ICdwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICB2YXIgdmlkZW9Db250YWluZXIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh2aWRlb1NwYW5JZCk7XG5cbiAgICAgICAgICAgIGlmICghdmlkZW9Db250YWluZXIpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiTm8gdmlkZW8gY29udGFpbmVyIGZvciBcIiArIGppZCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgbWVtYmVyID0gbWVtYmVyc1tqaWRdO1xuXG4gICAgICAgICAgICBpZiAobWVtYmVyLnJvbGUgPT09ICdtb2RlcmF0b3InKSB7XG4gICAgICAgICAgICAgICAgLy8gUmVtb3ZlIG1lbnUgaWYgcGVlciBpcyBtb2RlcmF0b3JcbiAgICAgICAgICAgICAgICB2YXIgbWVudVNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLnJlbW90ZXZpZGVvbWVudScpO1xuICAgICAgICAgICAgICAgIGlmIChtZW51U3Bhbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlUmVtb3RlVmlkZW9NZW51KHZpZGVvU3BhbklkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gU2hvdyBtb2RlcmF0b3IgaW5kaWNhdG9yXG4gICAgICAgICAgICAgICAgdmFyIGluZGljYXRvclNwYW5cbiAgICAgICAgICAgICAgICAgICAgPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJyAuZm9jdXNpbmRpY2F0b3InKTtcblxuICAgICAgICAgICAgICAgIGlmICghaW5kaWNhdG9yU3BhbiB8fCBpbmRpY2F0b3JTcGFuLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBpbmRpY2F0b3JTcGFuID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgICAgICAgICAgICAgICAgICBpbmRpY2F0b3JTcGFuLmNsYXNzTmFtZSA9ICdmb2N1c2luZGljYXRvcic7XG5cbiAgICAgICAgICAgICAgICAgICAgdmlkZW9Db250YWluZXIuYXBwZW5kQ2hpbGQoaW5kaWNhdG9yU3Bhbik7XG5cbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlTW9kZXJhdG9ySW5kaWNhdG9yRWxlbWVudChpbmRpY2F0b3JTcGFuKTtcbiAgICAgICAgICAgICAgICAgICAgLy90cmFuc2xhdGVzIHRleHQgaW4gZm9jdXMgaW5kaWNhdG9yc1xuICAgICAgICAgICAgICAgICAgICBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlRWxlbWVudCgkKCcjJyArIHZpZGVvU3BhbklkICsgJyAuZm9jdXNpbmRpY2F0b3InKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmIChpc01vZGVyYXRvcikge1xuICAgICAgICAgICAgICAgIC8vIFdlIGFyZSBtb2RlcmF0b3IsIGJ1dCB1c2VyIGlzIG5vdCAtIGFkZCBtZW51XG4gICAgICAgICAgICAgICAgaWYgKCQoJyNyZW1vdGVfcG9wdXBtZW51XycgKyByZXNvdXJjZUppZCkubGVuZ3RoIDw9IDApIHtcbiAgICAgICAgICAgICAgICAgICAgYWRkUmVtb3RlVmlkZW9NZW51KFxuICAgICAgICAgICAgICAgICAgICAgICAgamlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIHZpZGVvIG11dGVkIGluZGljYXRvciBvdmVyIHNtYWxsIHZpZGVvcy5cbiAgICAgKi9cbiAgICBteS5zaG93VmlkZW9JbmRpY2F0b3IgPSBmdW5jdGlvbih2aWRlb1NwYW5JZCwgaXNNdXRlZCkge1xuICAgICAgICB2YXIgdmlkZW9NdXRlZFNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLnZpZGVvTXV0ZWQnKTtcblxuICAgICAgICBpZiAoaXNNdXRlZCA9PT0gJ2ZhbHNlJykge1xuICAgICAgICAgICAgaWYgKHZpZGVvTXV0ZWRTcGFuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICB2aWRlb011dGVkU3Bhbi5yZW1vdmUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGlmKHZpZGVvTXV0ZWRTcGFuLmxlbmd0aCA9PSAwKSB7XG4gICAgICAgICAgICAgICAgdmlkZW9NdXRlZFNwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgICAgICAgICAgdmlkZW9NdXRlZFNwYW4uY2xhc3NOYW1lID0gJ3ZpZGVvTXV0ZWQnO1xuXG4gICAgICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQodmlkZW9NdXRlZFNwYW4pO1xuXG4gICAgICAgICAgICAgICAgdmFyIG11dGVkSW5kaWNhdG9yID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaScpO1xuICAgICAgICAgICAgICAgIG11dGVkSW5kaWNhdG9yLmNsYXNzTmFtZSA9ICdpY29uLWNhbWVyYS1kaXNhYmxlZCc7XG4gICAgICAgICAgICAgICAgVUlVdGlsLnNldFRvb2x0aXAobXV0ZWRJbmRpY2F0b3IsXG4gICAgICAgICAgICAgICAgICAgIFwidmlkZW90aHVtYm5haWwudmlkZW9tdXRlXCIsXG4gICAgICAgICAgICAgICAgICAgIFwidG9wXCIpO1xuICAgICAgICAgICAgICAgIHZpZGVvTXV0ZWRTcGFuLmFwcGVuZENoaWxkKG11dGVkSW5kaWNhdG9yKTtcbiAgICAgICAgICAgICAgICAvL3RyYW5zbGF0ZSB0ZXh0cyBmb3IgbXV0ZWQgaW5kaWNhdG9yXG4gICAgICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZUVsZW1lbnQoJCgnIycgKyB2aWRlb1NwYW5JZCAgKyBcIiA+IHNwYW4gPiBpXCIpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlTXV0ZVBvc2l0aW9uKHZpZGVvU3BhbklkKTtcblxuICAgICAgICB9XG4gICAgfTtcblxuICAgIG15LnVwZGF0ZU11dGVQb3NpdGlvbiA9IGZ1bmN0aW9uICh2aWRlb1NwYW5JZCkge1xuICAgICAgICB2YXIgYXVkaW9NdXRlZFNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLmF1ZGlvTXV0ZWQnKTtcbiAgICAgICAgdmFyIGNvbm5lY3Rpb25JbmRpY2F0b3IgPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5kaXYuY29ubmVjdGlvbmluZGljYXRvcicpO1xuICAgICAgICB2YXIgdmlkZW9NdXRlZFNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLnZpZGVvTXV0ZWQnKTtcbiAgICAgICAgaWYoY29ubmVjdGlvbkluZGljYXRvci5sZW5ndGggPiAwXG4gICAgICAgICAgICAmJiBjb25uZWN0aW9uSW5kaWNhdG9yWzBdLnN0eWxlLmRpc3BsYXkgIT0gXCJub25lXCIpIHtcbiAgICAgICAgICAgIGF1ZGlvTXV0ZWRTcGFuLmNzcyh7cmlnaHQ6IFwiMjNweFwifSk7XG4gICAgICAgICAgICB2aWRlb011dGVkU3Bhbi5jc3Moe3JpZ2h0OiAoKGF1ZGlvTXV0ZWRTcGFuLmxlbmd0aCA+IDA/IDIzIDogMCkgKyAzMCkgKyBcInB4XCJ9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIGF1ZGlvTXV0ZWRTcGFuLmNzcyh7cmlnaHQ6IFwiMHB4XCJ9KTtcbiAgICAgICAgICAgIHZpZGVvTXV0ZWRTcGFuLmNzcyh7cmlnaHQ6IChhdWRpb011dGVkU3Bhbi5sZW5ndGggPiAwPyAzMCA6IDApICsgXCJweFwifSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLyoqXG4gICAgICogU2hvd3MgYXVkaW8gbXV0ZWQgaW5kaWNhdG9yIG92ZXIgc21hbGwgdmlkZW9zLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBpc011dGVkXG4gICAgICovXG4gICAgbXkuc2hvd0F1ZGlvSW5kaWNhdG9yID0gZnVuY3Rpb24odmlkZW9TcGFuSWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgdmFyIGF1ZGlvTXV0ZWRTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi5hdWRpb011dGVkJyk7XG5cbiAgICAgICAgaWYgKGlzTXV0ZWQgPT09ICdmYWxzZScpIHtcbiAgICAgICAgICAgIGlmIChhdWRpb011dGVkU3Bhbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4ucG9wb3ZlcignaGlkZScpO1xuICAgICAgICAgICAgICAgIGF1ZGlvTXV0ZWRTcGFuLnJlbW92ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYoYXVkaW9NdXRlZFNwYW4ubGVuZ3RoID09IDAgKSB7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4uY2xhc3NOYW1lID0gJ2F1ZGlvTXV0ZWQnO1xuICAgICAgICAgICAgICAgIFVJVXRpbC5zZXRUb29sdGlwKGF1ZGlvTXV0ZWRTcGFuLFxuICAgICAgICAgICAgICAgICAgICBcInZpZGVvdGh1bWJuYWlsLm11dGVcIixcbiAgICAgICAgICAgICAgICAgICAgXCJ0b3BcIik7XG5cbiAgICAgICAgICAgICAgICAkKCcjJyArIHZpZGVvU3BhbklkKVswXS5hcHBlbmRDaGlsZChhdWRpb011dGVkU3Bhbik7XG4gICAgICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZUVsZW1lbnQoJCgnIycgKyB2aWRlb1NwYW5JZCArIFwiID4gc3BhblwiKSk7XG4gICAgICAgICAgICAgICAgdmFyIG11dGVkSW5kaWNhdG9yID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaScpO1xuICAgICAgICAgICAgICAgIG11dGVkSW5kaWNhdG9yLmNsYXNzTmFtZSA9ICdpY29uLW1pYy1kaXNhYmxlZCc7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4uYXBwZW5kQ2hpbGQobXV0ZWRJbmRpY2F0b3IpO1xuXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVNdXRlUG9zaXRpb24odmlkZW9TcGFuSWQpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qXG4gICAgICogU2hvd3Mgb3IgaGlkZXMgdGhlIGF1ZGlvIG11dGVkIGluZGljYXRvciBvdmVyIHRoZSBsb2NhbCB0aHVtYm5haWwgdmlkZW8uXG4gICAgICogQHBhcmFtIHtib29sZWFufSBpc011dGVkXG4gICAgICovXG4gICAgbXkuc2hvd0xvY2FsQXVkaW9JbmRpY2F0b3IgPSBmdW5jdGlvbihpc011dGVkKSB7XG4gICAgICAgIFZpZGVvTGF5b3V0LnNob3dBdWRpb0luZGljYXRvcignbG9jYWxWaWRlb0NvbnRhaW5lcicsIGlzTXV0ZWQudG9TdHJpbmcoKSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGhlIGxhcmdlIHZpZGVvIGNvbnRhaW5lci5cbiAgICAgKi9cbiAgICBteS5yZXNpemVMYXJnZVZpZGVvQ29udGFpbmVyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBDaGF0LnJlc2l6ZUNoYXQoKTtcbiAgICAgICAgdmFyIGF2YWlsYWJsZUhlaWdodCA9IHdpbmRvdy5pbm5lckhlaWdodDtcbiAgICAgICAgdmFyIGF2YWlsYWJsZVdpZHRoID0gVUlVdGlsLmdldEF2YWlsYWJsZVZpZGVvV2lkdGgoKTtcblxuICAgICAgICBpZiAoYXZhaWxhYmxlV2lkdGggPCAwIHx8IGF2YWlsYWJsZUhlaWdodCA8IDApIHJldHVybjtcblxuICAgICAgICAkKCcjdmlkZW9zcGFjZScpLndpZHRoKGF2YWlsYWJsZVdpZHRoKTtcbiAgICAgICAgJCgnI3ZpZGVvc3BhY2UnKS5oZWlnaHQoYXZhaWxhYmxlSGVpZ2h0KTtcbiAgICAgICAgJCgnI2xhcmdlVmlkZW9Db250YWluZXInKS53aWR0aChhdmFpbGFibGVXaWR0aCk7XG4gICAgICAgICQoJyNsYXJnZVZpZGVvQ29udGFpbmVyJykuaGVpZ2h0KGF2YWlsYWJsZUhlaWdodCk7XG5cbiAgICAgICAgdmFyIGF2YXRhclNpemUgPSBpbnRlcmZhY2VDb25maWcuQUNUSVZFX1NQRUFLRVJfQVZBVEFSX1NJWkU7XG4gICAgICAgIHZhciB0b3AgPSBhdmFpbGFibGVIZWlnaHQgLyAyIC0gYXZhdGFyU2l6ZSAvIDQgKiAzO1xuICAgICAgICAkKCcjYWN0aXZlU3BlYWtlcicpLmNzcygndG9wJywgdG9wKTtcblxuICAgICAgICBWaWRlb0xheW91dC5yZXNpemVUaHVtYm5haWxzKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGh1bWJuYWlscy5cbiAgICAgKi9cbiAgICBteS5yZXNpemVUaHVtYm5haWxzID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciB2aWRlb1NwYWNlV2lkdGggPSAkKCcjcmVtb3RlVmlkZW9zJykud2lkdGgoKTtcblxuICAgICAgICB2YXIgdGh1bWJuYWlsU2l6ZSA9IFZpZGVvTGF5b3V0LmNhbGN1bGF0ZVRodW1ibmFpbFNpemUodmlkZW9TcGFjZVdpZHRoKTtcbiAgICAgICAgdmFyIHdpZHRoID0gdGh1bWJuYWlsU2l6ZVswXTtcbiAgICAgICAgdmFyIGhlaWdodCA9IHRodW1ibmFpbFNpemVbMV07XG5cbiAgICAgICAgLy8gc2l6ZSB2aWRlb3Mgc28gdGhhdCB3aGlsZSBrZWVwaW5nIEFSIGFuZCBtYXggaGVpZ2h0LCB3ZSBoYXZlIGFcbiAgICAgICAgLy8gbmljZSBmaXRcbiAgICAgICAgJCgnI3JlbW90ZVZpZGVvcycpLmhlaWdodChoZWlnaHQpO1xuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zPnNwYW4nKS53aWR0aCh3aWR0aCk7XG4gICAgICAgICQoJyNyZW1vdGVWaWRlb3M+c3BhbicpLmhlaWdodChoZWlnaHQpO1xuXG4gICAgICAgICQoJy51c2VyQXZhdGFyJykuY3NzKCdsZWZ0JywgKHdpZHRoIC0gaGVpZ2h0KSAvIDIpO1xuXG5cblxuICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKFwicmVtb3RldmlkZW8ucmVzaXplZFwiLCBbd2lkdGgsIGhlaWdodF0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBFbmFibGVzIHRoZSBkb21pbmFudCBzcGVha2VyIFVJLlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc291cmNlSmlkIHRoZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZWxlbWVudCB0b1xuICAgICAqIGFjdGl2YXRlL2RlYWN0aXZhdGVcbiAgICAgKiBAcGFyYW0gaXNFbmFibGUgaW5kaWNhdGVzIGlmIHRoZSBkb21pbmFudCBzcGVha2VyIHNob3VsZCBiZSBlbmFibGVkIG9yXG4gICAgICogZGlzYWJsZWRcbiAgICAgKi9cbiAgICBteS5lbmFibGVEb21pbmFudFNwZWFrZXIgPSBmdW5jdGlvbihyZXNvdXJjZUppZCwgaXNFbmFibGUpIHtcblxuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBudWxsO1xuICAgICAgICB2YXIgdmlkZW9Db250YWluZXJJZCA9IG51bGw7XG4gICAgICAgIGlmIChyZXNvdXJjZUppZFxuICAgICAgICAgICAgICAgID09PSBBUFAueG1wcC5teVJlc291cmNlKCkpIHtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ2xvY2FsVmlkZW9XcmFwcGVyJztcbiAgICAgICAgICAgIHZpZGVvQ29udGFpbmVySWQgPSAnbG9jYWxWaWRlb0NvbnRhaW5lcic7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2aWRlb1NwYW5JZCA9ICdwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICB2aWRlb0NvbnRhaW5lcklkID0gdmlkZW9TcGFuSWQ7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZGlzcGxheU5hbWUgPSByZXNvdXJjZUppZDtcbiAgICAgICAgdmFyIG5hbWVTcGFuID0gJCgnIycgKyB2aWRlb0NvbnRhaW5lcklkICsgJz5zcGFuLmRpc3BsYXluYW1lJyk7XG4gICAgICAgIGlmIChuYW1lU3Bhbi5sZW5ndGggPiAwKVxuICAgICAgICAgICAgZGlzcGxheU5hbWUgPSBuYW1lU3Bhbi5odG1sKCk7XG5cbiAgICAgICAgY29uc29sZS5sb2coXCJVSSBlbmFibGUgZG9taW5hbnQgc3BlYWtlclwiLFxuICAgICAgICAgICAgZGlzcGxheU5hbWUsXG4gICAgICAgICAgICByZXNvdXJjZUppZCxcbiAgICAgICAgICAgIGlzRW5hYmxlKTtcblxuICAgICAgICB2aWRlb1NwYW4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh2aWRlb0NvbnRhaW5lcklkKTtcblxuICAgICAgICBpZiAoIXZpZGVvU3Bhbikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHZpZGVvID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+dmlkZW8nKTtcblxuICAgICAgICBpZiAodmlkZW8gJiYgdmlkZW8ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgaWYgKGlzRW5hYmxlKSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzTGFyZ2VWaWRlb1Zpc2libGUgPSBWaWRlb0xheW91dC5pc0xhcmdlVmlkZW9PblRvcCgpO1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dEaXNwbGF5TmFtZSh2aWRlb0NvbnRhaW5lcklkLCBpc0xhcmdlVmlkZW9WaXNpYmxlKTtcblxuICAgICAgICAgICAgICAgIGlmICghdmlkZW9TcGFuLmNsYXNzTGlzdC5jb250YWlucyhcImRvbWluYW50c3BlYWtlclwiKSlcbiAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFuLmNsYXNzTGlzdC5hZGQoXCJkb21pbmFudHNwZWFrZXJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5zaG93RGlzcGxheU5hbWUodmlkZW9Db250YWluZXJJZCwgZmFsc2UpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHZpZGVvU3Bhbi5jbGFzc0xpc3QuY29udGFpbnMoXCJkb21pbmFudHNwZWFrZXJcIikpXG4gICAgICAgICAgICAgICAgICAgIHZpZGVvU3Bhbi5jbGFzc0xpc3QucmVtb3ZlKFwiZG9taW5hbnRzcGVha2VyXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBBdmF0YXIuc2hvd1VzZXJBdmF0YXIoXG4gICAgICAgICAgICAgICAgQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShyZXNvdXJjZUppZCkpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZXMgdGhlIHRodW1ibmFpbCBzaXplLlxuICAgICAqXG4gICAgICogQHBhcmFtIHZpZGVvU3BhY2VXaWR0aCB0aGUgd2lkdGggb2YgdGhlIHZpZGVvIHNwYWNlXG4gICAgICovXG4gICAgbXkuY2FsY3VsYXRlVGh1bWJuYWlsU2l6ZSA9IGZ1bmN0aW9uICh2aWRlb1NwYWNlV2lkdGgpIHtcbiAgICAgICAgLy8gQ2FsY3VsYXRlIHRoZSBhdmFpbGFibGUgaGVpZ2h0LCB3aGljaCBpcyB0aGUgaW5uZXIgd2luZG93IGhlaWdodCBtaW51c1xuICAgICAgIC8vIDM5cHggZm9yIHRoZSBoZWFkZXIgbWludXMgMnB4IGZvciB0aGUgZGVsaW1pdGVyIGxpbmVzIG9uIHRoZSB0b3AgYW5kXG4gICAgICAgLy8gYm90dG9tIG9mIHRoZSBsYXJnZSB2aWRlbywgbWludXMgdGhlIDM2cHggc3BhY2UgaW5zaWRlIHRoZSByZW1vdGVWaWRlb3NcbiAgICAgICAvLyBjb250YWluZXIgdXNlZCBmb3IgaGlnaGxpZ2h0aW5nIHNoYWRvdy5cbiAgICAgICB2YXIgYXZhaWxhYmxlSGVpZ2h0ID0gMTAwO1xuXG4gICAgICAgIHZhciBudW12aWRzID0gJCgnI3JlbW90ZVZpZGVvcz5zcGFuOnZpc2libGUnKS5sZW5ndGg7XG4gICAgICAgIGlmIChsb2NhbExhc3ROQ291bnQgJiYgbG9jYWxMYXN0TkNvdW50ID4gMCkge1xuICAgICAgICAgICAgbnVtdmlkcyA9IE1hdGgubWluKGxvY2FsTGFzdE5Db3VudCArIDEsIG51bXZpZHMpO1xuICAgICAgICB9XG5cbiAgICAgICAvLyBSZW1vdmUgdGhlIDNweCBib3JkZXJzIGFycm91bmQgdmlkZW9zIGFuZCBib3JkZXIgYXJvdW5kIHRoZSByZW1vdGVcbiAgICAgICAvLyB2aWRlb3MgYXJlYSBhbmQgdGhlIDQgcGl4ZWxzIGJldHdlZW4gdGhlIGxvY2FsIHZpZGVvIGFuZCB0aGUgb3RoZXJzXG4gICAgICAgLy9UT0RPOiBGaW5kIG91dCB3aGVyZSB0aGUgNCBwaXhlbHMgY29tZSBmcm9tIGFuZCByZW1vdmUgdGhlbVxuICAgICAgIHZhciBhdmFpbGFibGVXaW5XaWR0aCA9IHZpZGVvU3BhY2VXaWR0aCAtIDIgKiAzICogbnVtdmlkcyAtIDcwIC0gNDtcblxuICAgICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IGF2YWlsYWJsZVdpbldpZHRoIC8gbnVtdmlkcztcbiAgICAgICB2YXIgYXNwZWN0UmF0aW8gPSAxNi4wIC8gOS4wO1xuICAgICAgIHZhciBtYXhIZWlnaHQgPSBNYXRoLm1pbigxNjAsIGF2YWlsYWJsZUhlaWdodCk7XG4gICAgICAgYXZhaWxhYmxlSGVpZ2h0ID0gTWF0aC5taW4obWF4SGVpZ2h0LCBhdmFpbGFibGVXaWR0aCAvIGFzcGVjdFJhdGlvKTtcbiAgICAgICBpZiAoYXZhaWxhYmxlSGVpZ2h0IDwgYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbykge1xuICAgICAgICAgICBhdmFpbGFibGVXaWR0aCA9IE1hdGguZmxvb3IoYXZhaWxhYmxlSGVpZ2h0ICogYXNwZWN0UmF0aW8pO1xuICAgICAgIH1cblxuICAgICAgIHJldHVybiBbYXZhaWxhYmxlV2lkdGgsIGF2YWlsYWJsZUhlaWdodF07XG4gICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgcmVtb3RlIHZpZGVvIG1lbnUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gamlkIHRoZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZm9yIHdoaWNoIHdlJ3JlIGFkZGluZyBhIG1lbnUuXG4gICAgICogQHBhcmFtIGlzTXV0ZWQgaW5kaWNhdGVzIHRoZSBjdXJyZW50IG11dGUgc3RhdGVcbiAgICAgKi9cbiAgICBteS51cGRhdGVSZW1vdGVWaWRlb01lbnUgPSBmdW5jdGlvbihqaWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgdmFyIG11dGVNZW51SXRlbVxuICAgICAgICAgICAgPSAkKCcjcmVtb3RlX3BvcHVwbWVudV8nXG4gICAgICAgICAgICAgICAgICAgICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKVxuICAgICAgICAgICAgICAgICAgICArICc+bGk+YS5tdXRlbGluaycpO1xuXG4gICAgICAgIHZhciBtdXRlZEluZGljYXRvciA9IFwiPGkgY2xhc3M9J2ljb24tbWljLWRpc2FibGVkJz48L2k+XCI7XG5cbiAgICAgICAgaWYgKG11dGVNZW51SXRlbS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHZhciBtdXRlTGluayA9IG11dGVNZW51SXRlbS5nZXQoMCk7XG5cbiAgICAgICAgICAgIGlmIChpc011dGVkID09PSAndHJ1ZScpIHtcbiAgICAgICAgICAgICAgICBtdXRlTGluay5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArICcgTXV0ZWQnO1xuICAgICAgICAgICAgICAgIG11dGVMaW5rLmNsYXNzTmFtZSA9ICdtdXRlbGluayBkaXNhYmxlZCc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBtdXRlTGluay5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArICcgTXV0ZSc7XG4gICAgICAgICAgICAgICAgbXV0ZUxpbmsuY2xhc3NOYW1lID0gJ211dGVsaW5rJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IGRvbWluYW50IHNwZWFrZXIgcmVzb3VyY2UgamlkLlxuICAgICAqL1xuICAgIG15LmdldERvbWluYW50U3BlYWtlclJlc291cmNlSmlkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY3VycmVudERvbWluYW50U3BlYWtlcjtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgY29ycmVzcG9uZGluZyByZXNvdXJjZSBqaWQgdG8gdGhlIGdpdmVuIHBlZXIgY29udGFpbmVyXG4gICAgICogRE9NIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHRoZSBjb3JyZXNwb25kaW5nIHJlc291cmNlIGppZCB0byB0aGUgZ2l2ZW4gcGVlciBjb250YWluZXJcbiAgICAgKiBET00gZWxlbWVudFxuICAgICAqL1xuICAgIG15LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZCA9IGZ1bmN0aW9uIChjb250YWluZXJFbGVtZW50KSB7XG4gICAgICAgIHZhciBpID0gY29udGFpbmVyRWxlbWVudC5pZC5pbmRleE9mKCdwYXJ0aWNpcGFudF8nKTtcblxuICAgICAgICBpZiAoaSA+PSAwKVxuICAgICAgICAgICAgcmV0dXJuIGNvbnRhaW5lckVsZW1lbnQuaWQuc3Vic3RyaW5nKGkgKyAxMik7IFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPbiBjb250YWN0IGxpc3QgaXRlbSBjbGlja2VkLlxuICAgICAqL1xuICAgICQoQ29udGFjdExpc3QpLmJpbmQoJ2NvbnRhY3RjbGlja2VkJywgZnVuY3Rpb24oZXZlbnQsIGppZCkge1xuICAgICAgICBpZiAoIWppZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHJlc291cmNlID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgdmFyIHZpZGVvQ29udGFpbmVyID0gJChcIiNwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlKTtcbiAgICAgICAgaWYgKHZpZGVvQ29udGFpbmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHZhciB2aWRlb1RodW1iID0gJCgndmlkZW8nLCB2aWRlb0NvbnRhaW5lcikuZ2V0KDApO1xuICAgICAgICAgICAgLy8gSXQgaXMgbm90IGFsd2F5cyB0aGUgY2FzZSB0aGF0IGEgdmlkZW9UaHVtYiBleGlzdHMgKGlmIHRoZXJlIGlzXG4gICAgICAgICAgICAvLyBubyBhY3R1YWwgdmlkZW8pLlxuICAgICAgICAgICAgaWYgKHZpZGVvVGh1bWIpIHtcbiAgICAgICAgICAgICAgICBpZiAodmlkZW9UaHVtYi5zcmMgJiYgdmlkZW9UaHVtYi5zcmMgIT0gJycpIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBXZSBoYXZlIGEgdmlkZW8gc3JjLCBncmVhdCEgTGV0J3MgdXBkYXRlIHRoZSBsYXJnZSB2aWRlb1xuICAgICAgICAgICAgICAgICAgICAvLyBub3cuXG5cbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuaGFuZGxlVmlkZW9UaHVtYkNsaWNrZWQoXG4gICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1RodW1iLnNyYyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB3ZSBkb24ndCBoYXZlIGEgdmlkZW8gc3JjIGZvciBqaWQsIHRoZXJlJ3MgYWJzb2x1dGVseVxuICAgICAgICAgICAgICAgICAgICAvLyBubyBwb2ludCBpbiBjYWxsaW5nIGhhbmRsZVZpZGVvVGh1bWJDbGlja2VkOyBRdWl0ZVxuICAgICAgICAgICAgICAgICAgICAvLyBzaW1wbHksIGl0IHdvbid0IHdvcmsgYmVjYXVzZSBpdCBuZWVkcyBhbiBzcmMgdG8gYXR0YWNoXG4gICAgICAgICAgICAgICAgICAgIC8vIHRvIHRoZSBsYXJnZSB2aWRlby5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gSW5zdGVhZCwgd2UgdHJpZ2dlciB0aGUgcGlubmVkIGVuZHBvaW50IGNoYW5nZWQgZXZlbnQgdG9cbiAgICAgICAgICAgICAgICAgICAgLy8gbGV0IHRoZSBicmlkZ2UgYWRqdXN0IGl0cyBsYXN0TiBzZXQgZm9yIG15amlkIGFuZCBzdG9yZVxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgcGlubmVkIHVzZXIgaW4gdGhlIGxhc3ROUGlja3VwSmlkIHZhcmlhYmxlIHRvIGJlXG4gICAgICAgICAgICAgICAgICAgIC8vIHBpY2tlZCB1cCBsYXRlciBieSB0aGUgbGFzdE4gY2hhbmdlZCBldmVudCBoYW5kbGVyLlxuXG4gICAgICAgICAgICAgICAgICAgIGxhc3ROUGlja3VwSmlkID0gamlkO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChVSUV2ZW50cy5QSU5ORURfRU5EUE9JTlQsXG4gICAgICAgICAgICAgICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGppZCA9PSBBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgICAgICAgICAgJChcIiNsb2NhbFZpZGVvQ29udGFpbmVyXCIpLmNsaWNrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIE9uIGF1ZGlvIG11dGVkIGV2ZW50LlxuICAgICAqL1xuICAgICQoZG9jdW1lbnQpLmJpbmQoJ2F1ZGlvbXV0ZWQubXVjJywgZnVuY3Rpb24gKGV2ZW50LCBqaWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgLypcbiAgICAgICAgIC8vIEZJWE1FOiBidXQgZm9jdXMgY2FuIG5vdCBtdXRlIGluIHRoaXMgY2FzZSA/IC0gY2hlY2tcbiAgICAgICAgaWYgKGppZCA9PT0geG1wcC5teUppZCgpKSB7XG5cbiAgICAgICAgICAgIC8vIFRoZSBsb2NhbCBtdXRlIGluZGljYXRvciBpcyBjb250cm9sbGVkIGxvY2FsbHlcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSovXG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9IG51bGw7XG4gICAgICAgIGlmIChqaWQgPT09IEFQUC54bXBwLm15SmlkKCkpIHtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ2xvY2FsVmlkZW9Db250YWluZXInO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5zdXJlUGVlckNvbnRhaW5lckV4aXN0cyhqaWQpO1xuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIH1cblxuICAgICAgICBtdXRlZEF1ZGlvc1tqaWRdID0gaXNNdXRlZDtcblxuICAgICAgICBpZiAoQVBQLnhtcHAuaXNNb2RlcmF0b3IoKSkge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlUmVtb3RlVmlkZW9NZW51KGppZCwgaXNNdXRlZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodmlkZW9TcGFuSWQpXG4gICAgICAgICAgICBWaWRlb0xheW91dC5zaG93QXVkaW9JbmRpY2F0b3IodmlkZW9TcGFuSWQsIGlzTXV0ZWQpO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogT24gdmlkZW8gbXV0ZWQgZXZlbnQuXG4gICAgICovXG4gICAgJChkb2N1bWVudCkuYmluZCgndmlkZW9tdXRlZC5tdWMnLCBmdW5jdGlvbiAoZXZlbnQsIGppZCwgdmFsdWUpIHtcbiAgICAgICAgdmFyIGlzTXV0ZWQgPSAodmFsdWUgPT09IFwidHJ1ZVwiKTtcbiAgICAgICAgaWYoamlkICE9PSBBUFAueG1wcC5teUppZCgpICYmICFBUFAuUlRDLm11dGVSZW1vdGVWaWRlb1N0cmVhbShqaWQsIGlzTXV0ZWQpKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihqaWQsIGlzTXV0ZWQpO1xuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBudWxsO1xuICAgICAgICBpZiAoamlkID09PSBBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgICAgICB2aWRlb1NwYW5JZCA9ICdsb2NhbFZpZGVvQ29udGFpbmVyJztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmVuc3VyZVBlZXJDb250YWluZXJFeGlzdHMoamlkKTtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHZpZGVvU3BhbklkKVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2hvd1ZpZGVvSW5kaWNhdG9yKHZpZGVvU3BhbklkLCB2YWx1ZSk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBEaXNwbGF5IG5hbWUgY2hhbmdlZC5cbiAgICAgKi9cbiAgICBteS5vbkRpc3BsYXlOYW1lQ2hhbmdlZCA9XG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChqaWQsIGRpc3BsYXlOYW1lLCBzdGF0dXMpIHtcbiAgICAgICAgaWYgKGppZCA9PT0gJ2xvY2FsVmlkZW9Db250YWluZXInXG4gICAgICAgICAgICB8fCBqaWQgPT09IEFQUC54bXBwLm15SmlkKCkpIHtcbiAgICAgICAgICAgIHNldERpc3BsYXlOYW1lKCdsb2NhbFZpZGVvQ29udGFpbmVyJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXlOYW1lKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmVuc3VyZVBlZXJDb250YWluZXJFeGlzdHMoamlkKTtcbiAgICAgICAgICAgIHNldERpc3BsYXlOYW1lKFxuICAgICAgICAgICAgICAgICdwYXJ0aWNpcGFudF8nICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSxcbiAgICAgICAgICAgICAgICBkaXNwbGF5TmFtZSxcbiAgICAgICAgICAgICAgICBzdGF0dXMpO1xuICAgICAgICB9XG5cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogT24gZG9taW5hbnQgc3BlYWtlciBjaGFuZ2VkIGV2ZW50LlxuICAgICAqL1xuICAgIG15Lm9uRG9taW5hbnRTcGVha2VyQ2hhbmdlZCA9IGZ1bmN0aW9uIChyZXNvdXJjZUppZCkge1xuICAgICAgICAvLyBXZSBpZ25vcmUgbG9jYWwgdXNlciBldmVudHMuXG4gICAgICAgIGlmIChyZXNvdXJjZUppZFxuICAgICAgICAgICAgICAgID09PSBBUFAueG1wcC5teVJlc291cmNlKCkpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdmFyIG1lbWJlcnMgPSBBUFAueG1wcC5nZXRNZW1iZXJzKCk7XG4gICAgICAgIC8vIFVwZGF0ZSB0aGUgY3VycmVudCBkb21pbmFudCBzcGVha2VyLlxuICAgICAgICBpZiAocmVzb3VyY2VKaWQgIT09IGN1cnJlbnREb21pbmFudFNwZWFrZXIpIHtcbiAgICAgICAgICAgIHZhciBvbGRTcGVha2VyVmlkZW9TcGFuSWQgPSBcInBhcnRpY2lwYW50X1wiICsgY3VycmVudERvbWluYW50U3BlYWtlcixcbiAgICAgICAgICAgICAgICBuZXdTcGVha2VyVmlkZW9TcGFuSWQgPSBcInBhcnRpY2lwYW50X1wiICsgcmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICB2YXIgY3VycmVudEpJRCA9IEFQUC54bXBwLmZpbmRKaWRGcm9tUmVzb3VyY2UoY3VycmVudERvbWluYW50U3BlYWtlcik7XG4gICAgICAgICAgICB2YXIgbmV3SklEID0gQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShyZXNvdXJjZUppZCk7XG4gICAgICAgICAgICBpZihjdXJyZW50RG9taW5hbnRTcGVha2VyICYmICghbWVtYmVycyB8fCAhbWVtYmVyc1tjdXJyZW50SklEXSB8fFxuICAgICAgICAgICAgICAgICFtZW1iZXJzW2N1cnJlbnRKSURdLmRpc3BsYXlOYW1lKSkge1xuICAgICAgICAgICAgICAgIHNldERpc3BsYXlOYW1lKG9sZFNwZWFrZXJWaWRlb1NwYW5JZCwgbnVsbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZihyZXNvdXJjZUppZCAmJiAoIW1lbWJlcnMgfHwgIW1lbWJlcnNbbmV3SklEXSB8fFxuICAgICAgICAgICAgICAgICFtZW1iZXJzW25ld0pJRF0uZGlzcGxheU5hbWUpKSB7XG4gICAgICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUobmV3U3BlYWtlclZpZGVvU3BhbklkLCBudWxsLFxuICAgICAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuREVGQVVMVF9ET01JTkFOVF9TUEVBS0VSX0RJU1BMQVlfTkFNRSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjdXJyZW50RG9taW5hbnRTcGVha2VyID0gcmVzb3VyY2VKaWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBPYnRhaW4gY29udGFpbmVyIGZvciBuZXcgZG9taW5hbnQgc3BlYWtlci5cbiAgICAgICAgdmFyIGNvbnRhaW5lciAgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcbiAgICAgICAgICAgICAgICAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICAvLyBMb2NhbCB2aWRlbyB3aWxsIG5vdCBoYXZlIGNvbnRhaW5lciBmb3VuZCwgYnV0IHRoYXQncyBva1xuICAgICAgICAvLyBzaW5jZSB3ZSBkb24ndCB3YW50IHRvIHN3aXRjaCB0byBsb2NhbCB2aWRlby5cbiAgICAgICAgaWYgKGNvbnRhaW5lciAmJiAhZm9jdXNlZFZpZGVvSW5mbylcbiAgICAgICAge1xuICAgICAgICAgICAgdmFyIHZpZGVvID0gY29udGFpbmVyLmdldEVsZW1lbnRzQnlUYWdOYW1lKFwidmlkZW9cIik7XG5cbiAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgbGFyZ2UgdmlkZW8gaWYgdGhlIHZpZGVvIHNvdXJjZSBpcyBhbHJlYWR5IGF2YWlsYWJsZSxcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSB3YWl0IGZvciB0aGUgXCJ2aWRlb2FjdGl2ZS5qaW5nbGVcIiBldmVudC5cbiAgICAgICAgICAgIGlmICh2aWRlby5sZW5ndGggJiYgdmlkZW9bMF0uY3VycmVudFRpbWUgPiAwKVxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oQVBQLlJUQy5nZXRWaWRlb1NyYyh2aWRlb1swXSksIHJlc291cmNlSmlkKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPbiBsYXN0IE4gY2hhbmdlIGV2ZW50LlxuICAgICAqXG4gICAgICogQHBhcmFtIGxhc3RORW5kcG9pbnRzIHRoZSBsaXN0IG9mIGxhc3QgTiBlbmRwb2ludHNcbiAgICAgKiBAcGFyYW0gZW5kcG9pbnRzRW50ZXJpbmdMYXN0TiB0aGUgbGlzdCBjdXJyZW50bHkgZW50ZXJpbmcgbGFzdCBOXG4gICAgICogZW5kcG9pbnRzXG4gICAgICovXG4gICAgbXkub25MYXN0TkVuZHBvaW50c0NoYW5nZWQgPSBmdW5jdGlvbiAoIGxhc3RORW5kcG9pbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kcG9pbnRzRW50ZXJpbmdMYXN0TixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmVhbSkge1xuICAgICAgICBpZiAobGFzdE5Db3VudCAhPT0gbGFzdE5FbmRwb2ludHMubGVuZ3RoKVxuICAgICAgICAgICAgbGFzdE5Db3VudCA9IGxhc3RORW5kcG9pbnRzLmxlbmd0aDtcblxuICAgICAgICBsYXN0TkVuZHBvaW50c0NhY2hlID0gbGFzdE5FbmRwb2ludHM7XG5cbiAgICAgICAgLy8gU2F5IEEsIEIsIEMsIEQsIEUsIGFuZCBGIGFyZSBpbiBhIGNvbmZlcmVuY2UgYW5kIExhc3ROID0gMy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gSWYgTGFzdE4gZHJvcHMgdG8sIHNheSwgMiwgYmVjYXVzZSBvZiBhZGFwdGl2aXR5LCB0aGVuIEUgc2hvdWxkIHNlZVxuICAgICAgICAvLyB0aHVtYm5haWxzIGZvciBBLCBCIGFuZCBDLiBBIGFuZCBCIGFyZSBpbiBFJ3Mgc2VydmVyIHNpZGUgTGFzdE4gc2V0LFxuICAgICAgICAvLyBzbyBFIHNlZXMgdGhlbS4gQyBpcyBvbmx5IGluIEUncyBsb2NhbCBMYXN0TiBzZXQuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIElmIEYgc3RhcnRzIHRhbGtpbmcgYW5kIExhc3ROID0gMywgdGhlbiBFIHNob3VsZCBzZWUgdGh1bWJuYWlscyBmb3JcbiAgICAgICAgLy8gRiwgQSwgQi4gQiBnZXRzIFwiZWplY3RlZFwiIGZyb20gRSdzIHNlcnZlciBzaWRlIExhc3ROIHNldCwgYnV0IGl0XG4gICAgICAgIC8vIGVudGVycyBFJ3MgbG9jYWwgTGFzdE4gZWplY3RpbmcgQy5cblxuICAgICAgICAvLyBJbmNyZWFzZSB0aGUgbG9jYWwgTGFzdE4gc2V0IHNpemUsIGlmIG5lY2Vzc2FyeS5cbiAgICAgICAgaWYgKGxhc3ROQ291bnQgPiBsb2NhbExhc3ROQ291bnQpIHtcbiAgICAgICAgICAgIGxvY2FsTGFzdE5Db3VudCA9IGxhc3ROQ291bnQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVcGRhdGUgdGhlIGxvY2FsIExhc3ROIHNldCBwcmVzZXJ2aW5nIHRoZSBvcmRlciBpbiB3aGljaCB0aGVcbiAgICAgICAgLy8gZW5kcG9pbnRzIGFwcGVhcmVkIGluIHRoZSBMYXN0Ti9sb2NhbCBMYXN0TiBzZXQuXG5cbiAgICAgICAgdmFyIG5leHRMb2NhbExhc3ROU2V0ID0gbGFzdE5FbmRwb2ludHMuc2xpY2UoMCk7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbG9jYWxMYXN0TlNldC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKG5leHRMb2NhbExhc3ROU2V0Lmxlbmd0aCA+PSBsb2NhbExhc3ROQ291bnQpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJlc291cmNlSmlkID0gbG9jYWxMYXN0TlNldFtpXTtcbiAgICAgICAgICAgIGlmIChuZXh0TG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICBuZXh0TG9jYWxMYXN0TlNldC5wdXNoKHJlc291cmNlSmlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxvY2FsTGFzdE5TZXQgPSBuZXh0TG9jYWxMYXN0TlNldDtcblxuICAgICAgICB2YXIgdXBkYXRlTGFyZ2VWaWRlbyA9IGZhbHNlO1xuXG4gICAgICAgIC8vIEhhbmRsZSBMYXN0Ti9sb2NhbCBMYXN0TiBjaGFuZ2VzLlxuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zPnNwYW4nKS5lYWNoKGZ1bmN0aW9uKCBpbmRleCwgZWxlbWVudCApIHtcbiAgICAgICAgICAgIHZhciByZXNvdXJjZUppZCA9IFZpZGVvTGF5b3V0LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZChlbGVtZW50KTtcblxuICAgICAgICAgICAgdmFyIGlzUmVjZWl2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgaWYgKHJlc291cmNlSmlkXG4gICAgICAgICAgICAgICAgJiYgbGFzdE5FbmRwb2ludHMuaW5kZXhPZihyZXNvdXJjZUppZCkgPCAwXG4gICAgICAgICAgICAgICAgJiYgbG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA8IDApIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIlJlbW92ZSBmcm9tIGxhc3QgTlwiLCByZXNvdXJjZUppZCk7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdoaWRlJyk7XG4gICAgICAgICAgICAgICAgaXNSZWNlaXZlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChyZXNvdXJjZUppZFxuICAgICAgICAgICAgICAgICYmICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQpLmlzKCc6dmlzaWJsZScpXG4gICAgICAgICAgICAgICAgJiYgbGFzdE5FbmRwb2ludHMuaW5kZXhPZihyZXNvdXJjZUppZCkgPCAwXG4gICAgICAgICAgICAgICAgJiYgbG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA+PSAwKSB7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdhdmF0YXInKTtcbiAgICAgICAgICAgICAgICBpc1JlY2VpdmVkID0gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghaXNSZWNlaXZlZCkge1xuICAgICAgICAgICAgICAgIC8vIHJlc291cmNlSmlkIGhhcyBkcm9wcGVkIG91dCBvZiB0aGUgc2VydmVyIHNpZGUgbGFzdE4gc2V0LCBzb1xuICAgICAgICAgICAgICAgIC8vIGl0IGlzIG5vIGxvbmdlciBiZWluZyByZWNlaXZlZC4gSWYgcmVzb3VyY2VKaWQgd2FzIGJlaW5nXG4gICAgICAgICAgICAgICAgLy8gZGlzcGxheWVkIGluIHRoZSBsYXJnZSB2aWRlbyB3ZSBoYXZlIHRvIHN3aXRjaCB0byBhbm90aGVyXG4gICAgICAgICAgICAgICAgLy8gdXNlci5cbiAgICAgICAgICAgICAgICB2YXIgbGFyZ2VWaWRlb1Jlc291cmNlID0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZDtcbiAgICAgICAgICAgICAgICBpZiAoIXVwZGF0ZUxhcmdlVmlkZW8gJiYgcmVzb3VyY2VKaWQgPT09IGxhcmdlVmlkZW9SZXNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICB1cGRhdGVMYXJnZVZpZGVvID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghZW5kcG9pbnRzRW50ZXJpbmdMYXN0TiB8fCBlbmRwb2ludHNFbnRlcmluZ0xhc3ROLmxlbmd0aCA8IDApXG4gICAgICAgICAgICBlbmRwb2ludHNFbnRlcmluZ0xhc3ROID0gbGFzdE5FbmRwb2ludHM7XG5cbiAgICAgICAgaWYgKGVuZHBvaW50c0VudGVyaW5nTGFzdE4gJiYgZW5kcG9pbnRzRW50ZXJpbmdMYXN0Ti5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBlbmRwb2ludHNFbnRlcmluZ0xhc3ROLmZvckVhY2goZnVuY3Rpb24gKHJlc291cmNlSmlkKSB7XG5cbiAgICAgICAgICAgICAgICB2YXIgaXNWaXNpYmxlID0gJCgnI3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZCkuaXMoJzp2aXNpYmxlJyk7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdzaG93Jyk7XG4gICAgICAgICAgICAgICAgaWYgKCFpc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJBZGQgdG8gbGFzdCBOXCIsIHJlc291cmNlSmlkKTtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgamlkID0gQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShyZXNvdXJjZUppZCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtZWRpYVN0cmVhbSA9IEFQUC5SVEMucmVtb3RlU3RyZWFtc1tqaWRdW01lZGlhU3RyZWFtVHlwZS5WSURFT19UWVBFXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlbCA9ICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQgKyAnPnZpZGVvJyk7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIHZpZGVvU3RyZWFtID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbShcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhU3RyZWFtLnN0cmVhbSk7XG4gICAgICAgICAgICAgICAgICAgIEFQUC5SVEMuYXR0YWNoTWVkaWFTdHJlYW0oc2VsLCB2aWRlb1N0cmVhbSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChsYXN0TlBpY2t1cEppZCA9PSBtZWRpYVN0cmVhbS5wZWVyamlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDbGVhbiB1cCB0aGUgbGFzdE4gcGlja3VwIGppZC5cbiAgICAgICAgICAgICAgICAgICAgICAgIGxhc3ROUGlja3VwSmlkID0gbnVsbDtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRG9uJ3QgZmlyZSB0aGUgZXZlbnRzIGFnYWluLCB0aGV5J3ZlIGFscmVhZHlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJlZW4gZmlyZWQgaW4gdGhlIGNvbnRhY3QgbGlzdCBjbGljayBoYW5kbGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuaGFuZGxlVmlkZW9UaHVtYkNsaWNrZWQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJChzZWwpLmF0dHIoJ3NyYycpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKG1lZGlhU3RyZWFtLnBlZXJqaWQpKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlTGFyZ2VWaWRlbyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHdhaXRGb3JSZW1vdGVWaWRlbyhzZWwsIG1lZGlhU3RyZWFtLnNzcmMsIG1lZGlhU3RyZWFtLnN0cmVhbSwgcmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgIH1cblxuICAgICAgICAvLyBUaGUgZW5kcG9pbnQgdGhhdCB3YXMgYmVpbmcgc2hvd24gaW4gdGhlIGxhcmdlIHZpZGVvIGhhcyBkcm9wcGVkIG91dFxuICAgICAgICAvLyBvZiB0aGUgbGFzdE4gc2V0IGFuZCB0aGVyZSB3YXMgbm8gbGFzdE4gcGlja3VwIGppZC4gV2UgbmVlZCB0byB1cGRhdGVcbiAgICAgICAgLy8gdGhlIGxhcmdlIHZpZGVvIG5vdy5cblxuICAgICAgICBpZiAodXBkYXRlTGFyZ2VWaWRlbykge1xuXG4gICAgICAgICAgICB2YXIgcmVzb3VyY2UsIGNvbnRhaW5lciwgc3JjO1xuICAgICAgICAgICAgdmFyIG15UmVzb3VyY2VcbiAgICAgICAgICAgICAgICA9IEFQUC54bXBwLm15UmVzb3VyY2UoKTtcblxuICAgICAgICAgICAgLy8gRmluZCBvdXQgd2hpY2ggZW5kcG9pbnQgdG8gc2hvdyBpbiB0aGUgbGFyZ2UgdmlkZW8uXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxhc3RORW5kcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcmVzb3VyY2UgPSBsYXN0TkVuZHBvaW50c1tpXTtcbiAgICAgICAgICAgICAgICBpZiAoIXJlc291cmNlIHx8IHJlc291cmNlID09PSBteVJlc291cmNlKVxuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcblxuICAgICAgICAgICAgICAgIGNvbnRhaW5lciA9ICQoXCIjcGFydGljaXBhbnRfXCIgKyByZXNvdXJjZSk7XG4gICAgICAgICAgICAgICAgaWYgKGNvbnRhaW5lci5sZW5ndGggPT0gMClcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG5cbiAgICAgICAgICAgICAgICBzcmMgPSAkKCd2aWRlbycsIGNvbnRhaW5lcikuYXR0cignc3JjJyk7XG4gICAgICAgICAgICAgICAgaWYgKCFzcmMpXG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICAgICAgLy8gdmlkZW9TcmNUb1NzcmMgbmVlZHMgdG8gYmUgdXBkYXRlIGZvciB0aGlzIGNhbGwgdG8gc3VjY2VlZC5cbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKHNyYyk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBteS5vblNpbXVsY2FzdExheWVyc0NoYW5naW5nID0gZnVuY3Rpb24gKGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzKSB7XG4gICAgICAgIGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzLmZvckVhY2goZnVuY3Rpb24gKGVzbCkge1xuXG4gICAgICAgICAgICB2YXIgcmVzb3VyY2UgPSBlc2wuZW5kcG9pbnQ7XG5cbiAgICAgICAgICAgIC8vIGlmIGxhc3ROIGlzIGVuYWJsZWQgKmFuZCogdGhlIGVuZHBvaW50IGlzICpub3QqIGluIHRoZSBsYXN0TiBzZXQsXG4gICAgICAgICAgICAvLyB0aGVuIGlnbm9yZSB0aGUgZXZlbnQgKD0gZG8gbm90IHByZWxvYWQgYW55dGhpbmcpLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIFRoZSBicmlkZ2UgY291bGQgcHJvYmFibHkgc3RvcCBzZW5kaW5nIHRoaXMgbWVzc2FnZSBpZiBpdCdzIGZvclxuICAgICAgICAgICAgLy8gYW4gZW5kcG9pbnQgdGhhdCdzIG5vdCBpbiBsYXN0Ti5cblxuICAgICAgICAgICAgaWYgKGxhc3ROQ291bnQgIT0gLTFcbiAgICAgICAgICAgICAgICAmJiAobGFzdE5Db3VudCA8IDEgfHwgbGFzdE5FbmRwb2ludHNDYWNoZS5pbmRleE9mKHJlc291cmNlKSA9PT0gLTEpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcHJpbWFyeVNTUkMgPSBlc2wuc2ltdWxjYXN0TGF5ZXIucHJpbWFyeVNTUkM7XG5cbiAgICAgICAgICAgIC8vIEdldCBzZXNzaW9uIGFuZCBzdHJlYW0gZnJvbSBwcmltYXJ5IHNzcmMuXG4gICAgICAgICAgICB2YXIgcmVzID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbUJ5U1NSQyhwcmltYXJ5U1NSQyk7XG4gICAgICAgICAgICB2YXIgc2lkID0gcmVzLnNpZDtcbiAgICAgICAgICAgIHZhciBlbGVjdGVkU3RyZWFtID0gcmVzLnN0cmVhbTtcblxuICAgICAgICAgICAgaWYgKHNpZCAmJiBlbGVjdGVkU3RyZWFtKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1zaWQgPSBBUFAuc2ltdWxjYXN0LmdldFJlbW90ZVZpZGVvU3RyZWFtSWRCeVNTUkMocHJpbWFyeVNTUkMpO1xuXG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFtlc2wsIHByaW1hcnlTU1JDLCBtc2lkLCBzaWQsIGVsZWN0ZWRTdHJlYW1dKTtcblxuICAgICAgICAgICAgICAgIHZhciBwcmVsb2FkID0gKFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKEFQUC54bXBwLmdldEppZEZyb21TU1JDKHByaW1hcnlTU1JDKSkgPT0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCk7XG5cbiAgICAgICAgICAgICAgICBpZiAocHJlbG9hZCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQpXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICQobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQpLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbygnUHJlbG9hZGluZyByZW1vdGUgdmlkZW8nKTtcbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQgPSAkKCc8dmlkZW8gYXV0b3BsYXk+PC92aWRlbz4nKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gc3NyY3MgYXJlIHVuaXF1ZSBpbiBhbiBydHAgc2Vzc2lvblxuICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZF9zc3JjID0gcHJpbWFyeVNTUkM7XG5cbiAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5hdHRhY2hNZWRpYVN0cmVhbShsYXJnZVZpZGVvU3RhdGUucHJlbG9hZCwgZWxlY3RlZFN0cmVhbSlcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignQ291bGQgbm90IGZpbmQgYSBzdHJlYW0gb3IgYSBzZXNzaW9uLicsIHNpZCwgZWxlY3RlZFN0cmVhbSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPbiBzaW11bGNhc3QgbGF5ZXJzIGNoYW5nZWQgZXZlbnQuXG4gICAgICovXG4gICAgbXkub25TaW11bGNhc3RMYXllcnNDaGFuZ2VkID0gZnVuY3Rpb24gKGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzKSB7XG4gICAgICAgIGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzLmZvckVhY2goZnVuY3Rpb24gKGVzbCkge1xuXG4gICAgICAgICAgICB2YXIgcmVzb3VyY2UgPSBlc2wuZW5kcG9pbnQ7XG5cbiAgICAgICAgICAgIC8vIGlmIGxhc3ROIGlzIGVuYWJsZWQgKmFuZCogdGhlIGVuZHBvaW50IGlzICpub3QqIGluIHRoZSBsYXN0TiBzZXQsXG4gICAgICAgICAgICAvLyB0aGVuIGlnbm9yZSB0aGUgZXZlbnQgKD0gZG8gbm90IGNoYW5nZSBsYXJnZSB2aWRlby90aHVtYm5haWxcbiAgICAgICAgICAgIC8vIFNSQ3MpLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIE5vdGUgdGhhdCBldmVuIGlmIHdlIGlnbm9yZSB0aGUgXCJjaGFuZ2VkXCIgZXZlbnQgaW4gdGhpcyBldmVudFxuICAgICAgICAgICAgLy8gaGFuZGxlciwgdGhlIGJyaWRnZSBtdXN0IGNvbnRpbnVlIHNlbmRpbmcgdGhlc2UgZXZlbnRzIGJlY2F1c2VcbiAgICAgICAgICAgIC8vIHRoZSBzaW11bGNhc3QgY29kZSBpbiBzaW11bGNhc3QuanMgdXNlcyBpdCB0byBrbm93IHdoYXQncyBnb2luZ1xuICAgICAgICAgICAgLy8gdG8gYmUgc3RyZWFtZWQgYnkgdGhlIGJyaWRnZSB3aGVuL2lmIHRoZSBlbmRwb2ludCBnZXRzIGJhY2sgaW50b1xuICAgICAgICAgICAgLy8gdGhlIGxhc3ROIHNldC5cblxuICAgICAgICAgICAgaWYgKGxhc3ROQ291bnQgIT0gLTFcbiAgICAgICAgICAgICAgICAmJiAobGFzdE5Db3VudCA8IDEgfHwgbGFzdE5FbmRwb2ludHNDYWNoZS5pbmRleE9mKHJlc291cmNlKSA9PT0gLTEpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcHJpbWFyeVNTUkMgPSBlc2wuc2ltdWxjYXN0TGF5ZXIucHJpbWFyeVNTUkM7XG5cbiAgICAgICAgICAgIC8vIEdldCBzZXNzaW9uIGFuZCBzdHJlYW0gZnJvbSBwcmltYXJ5IHNzcmMuXG4gICAgICAgICAgICB2YXIgcmVzID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbUJ5U1NSQyhwcmltYXJ5U1NSQyk7XG4gICAgICAgICAgICB2YXIgc2lkID0gcmVzLnNpZDtcbiAgICAgICAgICAgIHZhciBlbGVjdGVkU3RyZWFtID0gcmVzLnN0cmVhbTtcblxuICAgICAgICAgICAgaWYgKHNpZCAmJiBlbGVjdGVkU3RyZWFtKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1zaWQgPSBBUFAuc2ltdWxjYXN0LmdldFJlbW90ZVZpZGVvU3RyZWFtSWRCeVNTUkMocHJpbWFyeVNTUkMpO1xuXG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdTd2l0Y2hpbmcgc2ltdWxjYXN0IHN1YnN0cmVhbS4nKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oW2VzbCwgcHJpbWFyeVNTUkMsIG1zaWQsIHNpZCwgZWxlY3RlZFN0cmVhbV0pO1xuXG4gICAgICAgICAgICAgICAgdmFyIG1zaWRQYXJ0cyA9IG1zaWQuc3BsaXQoJyAnKTtcbiAgICAgICAgICAgICAgICB2YXIgc2VsUmVtb3RlVmlkZW8gPSAkKFsnIycsICdyZW1vdGVWaWRlb18nLCBzaWQsICdfJywgbXNpZFBhcnRzWzBdXS5qb2luKCcnKSk7XG5cbiAgICAgICAgICAgICAgICB2YXIgdXBkYXRlTGFyZ2VWaWRlbyA9IChTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChBUFAueG1wcC5nZXRKaWRGcm9tU1NSQyhwcmltYXJ5U1NSQykpXG4gICAgICAgICAgICAgICAgICAgID09IGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgICAgIHZhciB1cGRhdGVGb2N1c2VkVmlkZW9TcmMgPSAoZm9jdXNlZFZpZGVvSW5mbyAmJiBmb2N1c2VkVmlkZW9JbmZvLnNyYyAmJiBmb2N1c2VkVmlkZW9JbmZvLnNyYyAhPSAnJyAmJlxuICAgICAgICAgICAgICAgICAgICAoQVBQLlJUQy5nZXRWaWRlb1NyYyhzZWxSZW1vdGVWaWRlb1swXSkgPT0gZm9jdXNlZFZpZGVvSW5mby5zcmMpKTtcblxuICAgICAgICAgICAgICAgIHZhciBlbGVjdGVkU3RyZWFtVXJsO1xuICAgICAgICAgICAgICAgIGlmIChsYXJnZVZpZGVvU3RhdGUucHJlbG9hZF9zc3JjID09IHByaW1hcnlTU1JDKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5zZXRWaWRlb1NyYyhzZWxSZW1vdGVWaWRlb1swXSwgQVBQLlJUQy5nZXRWaWRlb1NyYyhsYXJnZVZpZGVvU3RhdGUucHJlbG9hZFswXSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWRcbiAgICAgICAgICAgICAgICAgICAgICAgICYmIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICQobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQpLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWRfc3NyYyA9IDA7XG5cbiAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5hdHRhY2hNZWRpYVN0cmVhbShzZWxSZW1vdGVWaWRlbywgZWxlY3RlZFN0cmVhbSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGppZCA9IEFQUC54bXBwLmdldEppZEZyb21TU1JDKHByaW1hcnlTU1JDKTtcblxuICAgICAgICAgICAgICAgIGlmICh1cGRhdGVMYXJnZVZpZGVvKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oQVBQLlJUQy5nZXRWaWRlb1NyYyhzZWxSZW1vdGVWaWRlb1swXSksIG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAodXBkYXRlRm9jdXNlZFZpZGVvU3JjKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvY3VzZWRWaWRlb0luZm8uc3JjID0gQVBQLlJUQy5nZXRWaWRlb1NyYyhzZWxSZW1vdGVWaWRlb1swXSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIHZpZGVvSWQ7XG4gICAgICAgICAgICAgICAgaWYocmVzb3VyY2UgPT0gQVBQLnhtcHAubXlSZXNvdXJjZSgpKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdmlkZW9JZCA9IFwibG9jYWxWaWRlb0NvbnRhaW5lclwiO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB2aWRlb0lkID0gXCJwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgY29ubmVjdGlvbkluZGljYXRvciA9IFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW3ZpZGVvSWRdO1xuICAgICAgICAgICAgICAgIGlmKGNvbm5lY3Rpb25JbmRpY2F0b3IpXG4gICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25JbmRpY2F0b3IudXBkYXRlUG9wb3ZlckRhdGEoKTtcblxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdDb3VsZCBub3QgZmluZCBhIHN0cmVhbSBvciBhIHNpZC4nLCBzaWQsIGVsZWN0ZWRTdHJlYW0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyBsb2NhbCBzdGF0c1xuICAgICAqIEBwYXJhbSBwZXJjZW50XG4gICAgICogQHBhcmFtIG9iamVjdFxuICAgICAqL1xuICAgIG15LnVwZGF0ZUxvY2FsQ29ubmVjdGlvblN0YXRzID0gZnVuY3Rpb24gKHBlcmNlbnQsIG9iamVjdCkge1xuICAgICAgICB2YXIgcmVzb2x1dGlvbiA9IG51bGw7XG4gICAgICAgIGlmKG9iamVjdC5yZXNvbHV0aW9uICE9PSBudWxsKVxuICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHV0aW9uID0gb2JqZWN0LnJlc29sdXRpb247XG4gICAgICAgICAgICBvYmplY3QucmVzb2x1dGlvbiA9IHJlc29sdXRpb25bQVBQLnhtcHAubXlKaWQoKV07XG4gICAgICAgICAgICBkZWxldGUgcmVzb2x1dGlvbltBUFAueG1wcC5teUppZCgpXTtcbiAgICAgICAgfVxuICAgICAgICB1cGRhdGVTdGF0c0luZGljYXRvcihcImxvY2FsVmlkZW9Db250YWluZXJcIiwgcGVyY2VudCwgb2JqZWN0KTtcbiAgICAgICAgZm9yKHZhciBqaWQgaW4gcmVzb2x1dGlvbilcbiAgICAgICAge1xuICAgICAgICAgICAgaWYocmVzb2x1dGlvbltqaWRdID09PSBudWxsKVxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgdmFyIGlkID0gJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuICAgICAgICAgICAgaWYoVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbaWRdKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW2lkXS51cGRhdGVSZXNvbHV0aW9uKHJlc29sdXRpb25bamlkXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHJlbW90ZSBzdGF0cy5cbiAgICAgKiBAcGFyYW0gamlkIHRoZSBqaWQgYXNzb2NpYXRlZCB3aXRoIHRoZSBzdGF0c1xuICAgICAqIEBwYXJhbSBwZXJjZW50IHRoZSBjb25uZWN0aW9uIHF1YWxpdHkgcGVyY2VudFxuICAgICAqIEBwYXJhbSBvYmplY3QgdGhlIHN0YXRzIGRhdGFcbiAgICAgKi9cbiAgICBteS51cGRhdGVDb25uZWN0aW9uU3RhdHMgPSBmdW5jdGlvbiAoamlkLCBwZXJjZW50LCBvYmplY3QpIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcblxuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkO1xuICAgICAgICB1cGRhdGVTdGF0c0luZGljYXRvcih2aWRlb1NwYW5JZCwgcGVyY2VudCwgb2JqZWN0KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgY29ubmVjdGlvblxuICAgICAqIEBwYXJhbSBqaWRcbiAgICAgKi9cbiAgICBteS5yZW1vdmVDb25uZWN0aW9uSW5kaWNhdG9yID0gZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1sncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCldKVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpXS5yZW1vdmUoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSGlkZXMgdGhlIGNvbm5lY3Rpb24gaW5kaWNhdG9yXG4gICAgICogQHBhcmFtIGppZFxuICAgICAqL1xuICAgIG15LmhpZGVDb25uZWN0aW9uSW5kaWNhdG9yID0gZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1sncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCldKVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpXS5oaWRlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEhpZGVzIGFsbCB0aGUgaW5kaWNhdG9yc1xuICAgICAqL1xuICAgIG15Lm9uU3RhdHNTdG9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBmb3IodmFyIGluZGljYXRvciBpbiBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9ycylcbiAgICAgICAge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbaW5kaWNhdG9yXS5oaWRlSW5kaWNhdG9yKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbXkucGFydGljaXBhbnRMZWZ0ID0gZnVuY3Rpb24gKGppZCkge1xuICAgICAgICAvLyBVbmxvY2sgbGFyZ2UgdmlkZW9cbiAgICAgICAgaWYgKGZvY3VzZWRWaWRlb0luZm8gJiYgZm9jdXNlZFZpZGVvSW5mby5qaWQgPT09IGppZClcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiRm9jdXNlZCB2aWRlbyBvd25lciBoYXMgbGVmdCB0aGUgY29uZmVyZW5jZVwiKTtcbiAgICAgICAgICAgIGZvY3VzZWRWaWRlb0luZm8gPSBudWxsO1xuICAgICAgICB9XG4gICAgfVxuICAgIFxuICAgIG15Lm9uVmlkZW9UeXBlQ2hhbmdlZCA9IGZ1bmN0aW9uIChqaWQpIHtcbiAgICAgICAgaWYoamlkICYmXG4gICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpID09PSBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkKVxuICAgICAgICB7XG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUuaXNEZXNrdG9wID0gQVBQLlJUQy5pc1ZpZGVvU3JjRGVza3RvcChqaWQpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZ2V0VmlkZW9TaXplID0gbGFyZ2VWaWRlb1N0YXRlLmlzRGVza3RvcFxuICAgICAgICAgICAgICAgID8gZ2V0RGVza3RvcFZpZGVvU2l6ZVxuICAgICAgICAgICAgICAgIDogZ2V0Q2FtZXJhVmlkZW9TaXplO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZ2V0VmlkZW9Qb3NpdGlvbiA9IGxhcmdlVmlkZW9TdGF0ZS5pc0Rlc2t0b3BcbiAgICAgICAgICAgICAgICA/IGdldERlc2t0b3BWaWRlb1Bvc2l0aW9uXG4gICAgICAgICAgICAgICAgOiBnZXRDYW1lcmFWaWRlb1Bvc2l0aW9uO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucG9zaXRpb25MYXJnZShudWxsLCBudWxsKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBteTtcbn0oVmlkZW9MYXlvdXQgfHwge30pKTtcblxubW9kdWxlLmV4cG9ydHMgPSBWaWRlb0xheW91dDsiLCIvL3ZhciBub3VucyA9IFtcbi8vXTtcbnZhciBwbHVyYWxOb3VucyA9IFtcbiAgICBcIkFsaWVuc1wiLCBcIkFuaW1hbHNcIiwgXCJBbnRlbG9wZXNcIiwgXCJBbnRzXCIsIFwiQXBlc1wiLCBcIkFwcGxlc1wiLCBcIkJhYm9vbnNcIiwgXCJCYWN0ZXJpYVwiLCBcIkJhZGdlcnNcIiwgXCJCYW5hbmFzXCIsIFwiQmF0c1wiLFxuICAgIFwiQmVhcnNcIiwgXCJCaXJkc1wiLCBcIkJvbm9ib3NcIiwgXCJCcmlkZXNcIiwgXCJCdWdzXCIsIFwiQnVsbHNcIiwgXCJCdXR0ZXJmbGllc1wiLCBcIkNoZWV0YWhzXCIsXG4gICAgXCJDaGVycmllc1wiLCBcIkNoaWNrZW5cIiwgXCJDaGlsZHJlblwiLCBcIkNoaW1wc1wiLCBcIkNsb3duc1wiLCBcIkNvd3NcIiwgXCJDcmVhdHVyZXNcIiwgXCJEaW5vc2F1cnNcIiwgXCJEb2dzXCIsIFwiRG9scGhpbnNcIixcbiAgICBcIkRvbmtleXNcIiwgXCJEcmFnb25zXCIsIFwiRHVja3NcIiwgXCJEd2FyZnNcIiwgXCJFYWdsZXNcIiwgXCJFbGVwaGFudHNcIiwgXCJFbHZlc1wiLCBcIkZBSUxcIiwgXCJGYXRoZXJzXCIsXG4gICAgXCJGaXNoXCIsIFwiRmxvd2Vyc1wiLCBcIkZyb2dzXCIsIFwiRnJ1aXRcIiwgXCJGdW5naVwiLCBcIkdhbGF4aWVzXCIsIFwiR2Vlc2VcIiwgXCJHb2F0c1wiLFxuICAgIFwiR29yaWxsYXNcIiwgXCJIZWRnZWhvZ3NcIiwgXCJIaXBwb3NcIiwgXCJIb3JzZXNcIiwgXCJIdW50ZXJzXCIsIFwiSW5zZWN0c1wiLCBcIktpZHNcIiwgXCJLbmlnaHRzXCIsXG4gICAgXCJMZW1vbnNcIiwgXCJMZW11cnNcIiwgXCJMZW9wYXJkc1wiLCBcIkxpZmVGb3Jtc1wiLCBcIkxpb25zXCIsIFwiTGl6YXJkc1wiLCBcIk1pY2VcIiwgXCJNb25rZXlzXCIsIFwiTW9uc3RlcnNcIixcbiAgICBcIk11c2hyb29tc1wiLCBcIk9jdG9wb2Rlc1wiLCBcIk9yYW5nZXNcIiwgXCJPcmFuZ3V0YW5zXCIsIFwiT3JnYW5pc21zXCIsIFwiUGFudHNcIiwgXCJQYXJyb3RzXCIsIFwiUGVuZ3VpbnNcIixcbiAgICBcIlBlb3BsZVwiLCBcIlBpZ2VvbnNcIiwgXCJQaWdzXCIsIFwiUGluZWFwcGxlc1wiLCBcIlBsYW50c1wiLCBcIlBvdGF0b2VzXCIsIFwiUHJpZXN0c1wiLCBcIlJhdHNcIiwgXCJSZXB0aWxlc1wiLCBcIlJlcHRpbGlhbnNcIixcbiAgICBcIlJoaW5vc1wiLCBcIlNlYWd1bGxzXCIsIFwiU2hlZXBcIiwgXCJTaWJsaW5nc1wiLCBcIlNuYWtlc1wiLCBcIlNwYWdoZXR0aVwiLCBcIlNwaWRlcnNcIiwgXCJTcXVpZFwiLCBcIlNxdWlycmVsc1wiLFxuICAgIFwiU3RhcnNcIiwgXCJTdHVkZW50c1wiLCBcIlRlYWNoZXJzXCIsIFwiVGlnZXJzXCIsIFwiVG9tYXRvZXNcIiwgXCJUcmVlc1wiLCBcIlZhbXBpcmVzXCIsIFwiVmVnZXRhYmxlc1wiLCBcIlZpcnVzZXNcIiwgXCJWdWxjYW5zXCIsXG4gICAgXCJXYXJld29sdmVzXCIsIFwiV2Vhc2Vsc1wiLCBcIldoYWxlc1wiLCBcIldpdGNoZXNcIiwgXCJXaXphcmRzXCIsIFwiV29sdmVzXCIsIFwiV29ya2Vyc1wiLCBcIldvcm1zXCIsIFwiWmVicmFzXCJcbl07XG4vL3ZhciBwbGFjZXMgPSBbXG4vL1wiUHViXCIsIFwiVW5pdmVyc2l0eVwiLCBcIkFpcnBvcnRcIiwgXCJMaWJyYXJ5XCIsIFwiTWFsbFwiLCBcIlRoZWF0ZXJcIiwgXCJTdGFkaXVtXCIsIFwiT2ZmaWNlXCIsIFwiU2hvd1wiLCBcIkdhbGxvd3NcIiwgXCJCZWFjaFwiLFxuLy8gXCJDZW1ldGVyeVwiLCBcIkhvc3BpdGFsXCIsIFwiUmVjZXB0aW9uXCIsIFwiUmVzdGF1cmFudFwiLCBcIkJhclwiLCBcIkNodXJjaFwiLCBcIkhvdXNlXCIsIFwiU2Nob29sXCIsIFwiU3F1YXJlXCIsIFwiVmlsbGFnZVwiLFxuLy8gXCJDaW5lbWFcIiwgXCJNb3ZpZXNcIiwgXCJQYXJ0eVwiLCBcIlJlc3Ryb29tXCIsIFwiRW5kXCIsIFwiSmFpbFwiLCBcIlBvc3RPZmZpY2VcIiwgXCJTdGF0aW9uXCIsIFwiQ2lyY3VzXCIsIFwiR2F0ZXNcIiwgXCJFbnRyYW5jZVwiLFxuLy8gXCJCcmlkZ2VcIlxuLy9dO1xudmFyIHZlcmJzID0gW1xuICAgIFwiQWJhbmRvblwiLCBcIkFkYXB0XCIsIFwiQWR2ZXJ0aXNlXCIsIFwiQW5zd2VyXCIsIFwiQW50aWNpcGF0ZVwiLCBcIkFwcHJlY2lhdGVcIixcbiAgICBcIkFwcHJvYWNoXCIsIFwiQXJndWVcIiwgXCJBc2tcIiwgXCJCaXRlXCIsIFwiQmxvc3NvbVwiLCBcIkJsdXNoXCIsIFwiQnJlYXRoZVwiLCBcIkJyZWVkXCIsIFwiQnJpYmVcIiwgXCJCdXJuXCIsIFwiQ2FsY3VsYXRlXCIsXG4gICAgXCJDbGVhblwiLCBcIkNvZGVcIiwgXCJDb21tdW5pY2F0ZVwiLCBcIkNvbXB1dGVcIiwgXCJDb25mZXNzXCIsIFwiQ29uZmlzY2F0ZVwiLCBcIkNvbmp1Z2F0ZVwiLCBcIkNvbmp1cmVcIiwgXCJDb25zdW1lXCIsXG4gICAgXCJDb250ZW1wbGF0ZVwiLCBcIkNyYXdsXCIsIFwiRGFuY2VcIiwgXCJEZWxlZ2F0ZVwiLCBcIkRldm91clwiLCBcIkRldmVsb3BcIiwgXCJEaWZmZXJcIiwgXCJEaXNjdXNzXCIsXG4gICAgXCJEaXNzb2x2ZVwiLCBcIkRyaW5rXCIsIFwiRWF0XCIsIFwiRWxhYm9yYXRlXCIsIFwiRW1hbmNpcGF0ZVwiLCBcIkVzdGltYXRlXCIsIFwiRXhwaXJlXCIsIFwiRXh0aW5ndWlzaFwiLFxuICAgIFwiRXh0cmFjdFwiLCBcIkZBSUxcIiwgXCJGYWNpbGl0YXRlXCIsIFwiRmFsbFwiLCBcIkZlZWRcIiwgXCJGaW5pc2hcIiwgXCJGbG9zc1wiLCBcIkZseVwiLCBcIkZvbGxvd1wiLCBcIkZyYWdtZW50XCIsIFwiRnJlZXplXCIsXG4gICAgXCJHYXRoZXJcIiwgXCJHbG93XCIsIFwiR3Jvd1wiLCBcIkhleFwiLCBcIkhpZGVcIiwgXCJIdWdcIiwgXCJIdXJyeVwiLCBcIkltcHJvdmVcIiwgXCJJbnRlcnNlY3RcIiwgXCJJbnZlc3RpZ2F0ZVwiLCBcIkppbnhcIixcbiAgICBcIkpva2VcIiwgXCJKdWJpbGF0ZVwiLCBcIktpc3NcIiwgXCJMYXVnaFwiLCBcIk1hbmFnZVwiLCBcIk1lZXRcIiwgXCJNZXJnZVwiLCBcIk1vdmVcIiwgXCJPYmplY3RcIiwgXCJPYnNlcnZlXCIsIFwiT2ZmZXJcIixcbiAgICBcIlBhaW50XCIsIFwiUGFydGljaXBhdGVcIiwgXCJQYXJ0eVwiLCBcIlBlcmZvcm1cIiwgXCJQbGFuXCIsIFwiUHVyc3VlXCIsIFwiUGllcmNlXCIsIFwiUGxheVwiLCBcIlBvc3Rwb25lXCIsIFwiUHJheVwiLCBcIlByb2NsYWltXCIsXG4gICAgXCJRdWVzdGlvblwiLCBcIlJlYWRcIiwgXCJSZWNrb25cIiwgXCJSZWpvaWNlXCIsIFwiUmVwcmVzZW50XCIsIFwiUmVzaXplXCIsIFwiUmh5bWVcIiwgXCJTY3JlYW1cIiwgXCJTZWFyY2hcIiwgXCJTZWxlY3RcIiwgXCJTaGFyZVwiLCBcIlNob290XCIsXG4gICAgXCJTaG91dFwiLCBcIlNpZ25hbFwiLCBcIlNpbmdcIiwgXCJTa2F0ZVwiLCBcIlNsZWVwXCIsIFwiU21pbGVcIiwgXCJTbW9rZVwiLCBcIlNvbHZlXCIsIFwiU3BlbGxcIiwgXCJTdGVlclwiLCBcIlN0aW5rXCIsXG4gICAgXCJTdWJzdGl0dXRlXCIsIFwiU3dpbVwiLCBcIlRhc3RlXCIsIFwiVGVhY2hcIiwgXCJUZXJtaW5hdGVcIiwgXCJUaGlua1wiLCBcIlR5cGVcIiwgXCJVbml0ZVwiLCBcIlZhbmlzaFwiLCBcIldvcnNoaXBcIlxuXTtcbnZhciBhZHZlcmJzID0gW1xuICAgIFwiQWJzZW50bHlcIiwgXCJBY2N1cmF0ZWx5XCIsIFwiQWNjdXNpbmdseVwiLCBcIkFkb3JhYmx5XCIsIFwiQWxsVGhlVGltZVwiLCBcIkFsb25lXCIsIFwiQWx3YXlzXCIsIFwiQW1hemluZ2x5XCIsIFwiQW5ncmlseVwiLFxuICAgIFwiQW54aW91c2x5XCIsIFwiQW55d2hlcmVcIiwgXCJBcHBhbGxpbmdseVwiLCBcIkFwcGFyZW50bHlcIiwgXCJBcnRpY3VsYXRlbHlcIiwgXCJBc3RvbmlzaGluZ2x5XCIsIFwiQmFkbHlcIiwgXCJCYXJlbHlcIixcbiAgICBcIkJlYXV0aWZ1bGx5XCIsIFwiQmxpbmRseVwiLCBcIkJyYXZlbHlcIiwgXCJCcmlnaHRseVwiLCBcIkJyaXNrbHlcIiwgXCJCcnV0YWxseVwiLCBcIkNhbG1seVwiLCBcIkNhcmVmdWxseVwiLCBcIkNhc3VhbGx5XCIsXG4gICAgXCJDYXV0aW91c2x5XCIsIFwiQ2xldmVybHlcIiwgXCJDb25zdGFudGx5XCIsIFwiQ29ycmVjdGx5XCIsIFwiQ3JhemlseVwiLCBcIkN1cmlvdXNseVwiLCBcIkN5bmljYWxseVwiLCBcIkRhaWx5XCIsXG4gICAgXCJEYW5nZXJvdXNseVwiLCBcIkRlbGliZXJhdGVseVwiLCBcIkRlbGljYXRlbHlcIiwgXCJEZXNwZXJhdGVseVwiLCBcIkRpc2NyZWV0bHlcIiwgXCJFYWdlcmx5XCIsIFwiRWFzaWx5XCIsIFwiRXVwaG9yaWNseVwiLFxuICAgIFwiRXZlbmx5XCIsIFwiRXZlcnl3aGVyZVwiLCBcIkV4YWN0bHlcIiwgXCJFeHBlY3RhbnRseVwiLCBcIkV4dGVuc2l2ZWx5XCIsIFwiRkFJTFwiLCBcIkZlcm9jaW91c2x5XCIsIFwiRmllcmNlbHlcIiwgXCJGaW5lbHlcIixcbiAgICBcIkZsYXRseVwiLCBcIkZyZXF1ZW50bHlcIiwgXCJGcmlnaHRlbmluZ2x5XCIsIFwiR2VudGx5XCIsIFwiR2xvcmlvdXNseVwiLCBcIkdyaW1seVwiLCBcIkd1aWx0aWx5XCIsIFwiSGFwcGlseVwiLFxuICAgIFwiSGFyZFwiLCBcIkhhc3RpbHlcIiwgXCJIZXJvaWNhbGx5XCIsIFwiSGlnaFwiLCBcIkhpZ2hseVwiLCBcIkhvdXJseVwiLCBcIkh1bWJseVwiLCBcIkh5c3RlcmljYWxseVwiLCBcIkltbWVuc2VseVwiLFxuICAgIFwiSW1wYXJ0aWFsbHlcIiwgXCJJbXBvbGl0ZWx5XCIsIFwiSW5kaWZmZXJlbnRseVwiLCBcIkludGVuc2VseVwiLCBcIkplYWxvdXNseVwiLCBcIkpvdmlhbGx5XCIsIFwiS2luZGx5XCIsIFwiTGF6aWx5XCIsXG4gICAgXCJMaWdodGx5XCIsIFwiTG91ZGx5XCIsIFwiTG92aW5nbHlcIiwgXCJMb3lhbGx5XCIsIFwiTWFnbmlmaWNlbnRseVwiLCBcIk1hbGV2b2xlbnRseVwiLCBcIk1lcnJpbHlcIiwgXCJNaWdodGlseVwiLCBcIk1pc2VyYWJseVwiLFxuICAgIFwiTXlzdGVyaW91c2x5XCIsIFwiTk9UXCIsIFwiTmVydm91c2x5XCIsIFwiTmljZWx5XCIsIFwiTm93aGVyZVwiLCBcIk9iamVjdGl2ZWx5XCIsIFwiT2Jub3hpb3VzbHlcIiwgXCJPYnNlc3NpdmVseVwiLFxuICAgIFwiT2J2aW91c2x5XCIsIFwiT2Z0ZW5cIiwgXCJQYWluZnVsbHlcIiwgXCJQYXRpZW50bHlcIiwgXCJQbGF5ZnVsbHlcIiwgXCJQb2xpdGVseVwiLCBcIlBvb3JseVwiLCBcIlByZWNpc2VseVwiLCBcIlByb21wdGx5XCIsXG4gICAgXCJRdWlja2x5XCIsIFwiUXVpZXRseVwiLCBcIlJhbmRvbWx5XCIsIFwiUmFwaWRseVwiLCBcIlJhcmVseVwiLCBcIlJlY2tsZXNzbHlcIiwgXCJSZWd1bGFybHlcIiwgXCJSZW1vcnNlZnVsbHlcIiwgXCJSZXNwb25zaWJseVwiLFxuICAgIFwiUnVkZWx5XCIsIFwiUnV0aGxlc3NseVwiLCBcIlNhZGx5XCIsIFwiU2Nvcm5mdWxseVwiLCBcIlNlYW1sZXNzbHlcIiwgXCJTZWxkb21cIiwgXCJTZWxmaXNobHlcIiwgXCJTZXJpb3VzbHlcIiwgXCJTaGFraWx5XCIsXG4gICAgXCJTaGFycGx5XCIsIFwiU2lkZXdheXNcIiwgXCJTaWxlbnRseVwiLCBcIlNsZWVwaWx5XCIsIFwiU2xpZ2h0bHlcIiwgXCJTbG93bHlcIiwgXCJTbHlseVwiLCBcIlNtb290aGx5XCIsIFwiU29mdGx5XCIsIFwiU29sZW1ubHlcIiwgXCJTdGVhZGlseVwiLCBcIlN0ZXJubHlcIiwgXCJTdHJhbmdlbHlcIiwgXCJTdHJvbmdseVwiLCBcIlN0dW5uaW5nbHlcIiwgXCJTdXJlbHlcIiwgXCJUZW5kZXJseVwiLCBcIlRob3VnaHRmdWxseVwiLFxuICAgIFwiVGlnaHRseVwiLCBcIlVuZWFzaWx5XCIsIFwiVmFuaXNoaW5nbHlcIiwgXCJWaW9sZW50bHlcIiwgXCJXYXJtbHlcIiwgXCJXZWFrbHlcIiwgXCJXZWFyaWx5XCIsIFwiV2Vla2x5XCIsIFwiV2VpcmRseVwiLCBcIldlbGxcIixcbiAgICBcIldlbGxcIiwgXCJXaWNrZWRseVwiLCBcIldpbGRseVwiLCBcIldpc2VseVwiLCBcIldvbmRlcmZ1bGx5XCIsIFwiWWVhcmx5XCJcbl07XG52YXIgYWRqZWN0aXZlcyA9IFtcbiAgICBcIkFib21pbmFibGVcIiwgXCJBY2N1cmF0ZVwiLCBcIkFkb3JhYmxlXCIsIFwiQWxsXCIsIFwiQWxsZWdlZFwiLCBcIkFuY2llbnRcIiwgXCJBbmdyeVwiLCBcIkFuZ3J5XCIsIFwiQW54aW91c1wiLCBcIkFwcGFsbGluZ1wiLFxuICAgIFwiQXBwYXJlbnRcIiwgXCJBc3RvbmlzaGluZ1wiLCBcIkF0dHJhY3RpdmVcIiwgXCJBd2Vzb21lXCIsIFwiQmFieVwiLCBcIkJhZFwiLCBcIkJlYXV0aWZ1bFwiLCBcIkJlbmlnblwiLCBcIkJpZ1wiLCBcIkJpdHRlclwiLFxuICAgIFwiQmxpbmRcIiwgXCJCbHVlXCIsIFwiQm9sZFwiLCBcIkJyYXZlXCIsIFwiQnJpZ2h0XCIsIFwiQnJpc2tcIiwgXCJDYWxtXCIsIFwiQ2Ftb3VmbGFnZWRcIiwgXCJDYXN1YWxcIiwgXCJDYXV0aW91c1wiLFxuICAgIFwiQ2hvcHB5XCIsIFwiQ2hvc2VuXCIsIFwiQ2xldmVyXCIsIFwiQ29sZFwiLCBcIkNvb2xcIiwgXCJDcmF3bHlcIiwgXCJDcmF6eVwiLCBcIkNyZWVweVwiLCBcIkNydWVsXCIsIFwiQ3VyaW91c1wiLCBcIkN5bmljYWxcIixcbiAgICBcIkRhbmdlcm91c1wiLCBcIkRhcmtcIiwgXCJEZWxpY2F0ZVwiLCBcIkRlc3BlcmF0ZVwiLCBcIkRpZmZpY3VsdFwiLCBcIkRpc2NyZWV0XCIsIFwiRGlzZ3Vpc2VkXCIsIFwiRGl6enlcIixcbiAgICBcIkR1bWJcIiwgXCJFYWdlclwiLCBcIkVhc3lcIiwgXCJFZGd5XCIsIFwiRWxlY3RyaWNcIiwgXCJFbGVnYW50XCIsIFwiRW1hbmNpcGF0ZWRcIiwgXCJFbm9ybW91c1wiLCBcIkV1cGhvcmljXCIsIFwiRXZpbFwiLFxuICAgIFwiRkFJTFwiLCBcIkZhc3RcIiwgXCJGZXJvY2lvdXNcIiwgXCJGaWVyY2VcIiwgXCJGaW5lXCIsIFwiRmxhd2VkXCIsIFwiRmx5aW5nXCIsIFwiRm9vbGlzaFwiLCBcIkZveHlcIixcbiAgICBcIkZyZWV6aW5nXCIsIFwiRnVubnlcIiwgXCJGdXJpb3VzXCIsIFwiR2VudGxlXCIsIFwiR2xvcmlvdXNcIiwgXCJHb2xkZW5cIiwgXCJHb29kXCIsIFwiR3JlZW5cIiwgXCJHcmVlblwiLCBcIkd1aWx0eVwiLFxuICAgIFwiSGFpcnlcIiwgXCJIYXBweVwiLCBcIkhhcmRcIiwgXCJIYXN0eVwiLCBcIkhhenlcIiwgXCJIZXJvaWNcIiwgXCJIb3N0aWxlXCIsIFwiSG90XCIsIFwiSHVtYmxlXCIsIFwiSHVtb25nb3VzXCIsXG4gICAgXCJIdW1vcm91c1wiLCBcIkh5c3RlcmljYWxcIiwgXCJJZGVhbGlzdGljXCIsIFwiSWdub3JhbnRcIiwgXCJJbW1lbnNlXCIsIFwiSW1wYXJ0aWFsXCIsIFwiSW1wb2xpdGVcIiwgXCJJbmRpZmZlcmVudFwiLFxuICAgIFwiSW5mdXJpYXRlZFwiLCBcIkluc2lnaHRmdWxcIiwgXCJJbnRlbnNlXCIsIFwiSW50ZXJlc3RpbmdcIiwgXCJJbnRpbWlkYXRlZFwiLCBcIkludHJpZ3VpbmdcIiwgXCJKZWFsb3VzXCIsIFwiSm9sbHlcIiwgXCJKb3ZpYWxcIixcbiAgICBcIkp1bXB5XCIsIFwiS2luZFwiLCBcIkxhdWdoaW5nXCIsIFwiTGF6eVwiLCBcIkxpcXVpZFwiLCBcIkxvbmVseVwiLCBcIkxvbmdpbmdcIiwgXCJMb3VkXCIsIFwiTG92aW5nXCIsIFwiTG95YWxcIiwgXCJNYWNhYnJlXCIsIFwiTWFkXCIsXG4gICAgXCJNYWdpY2FsXCIsIFwiTWFnbmlmaWNlbnRcIiwgXCJNYWxldm9sZW50XCIsIFwiTWVkaWV2YWxcIiwgXCJNZW1vcmFibGVcIiwgXCJNZXJlXCIsIFwiTWVycnlcIiwgXCJNaWdodHlcIixcbiAgICBcIk1pc2NoaWV2b3VzXCIsIFwiTWlzZXJhYmxlXCIsIFwiTW9kaWZpZWRcIiwgXCJNb29keVwiLCBcIk1vc3RcIiwgXCJNeXN0ZXJpb3VzXCIsIFwiTXlzdGljYWxcIiwgXCJOZWVkeVwiLFxuICAgIFwiTmVydm91c1wiLCBcIk5pY2VcIiwgXCJPYmplY3RpdmVcIiwgXCJPYm5veGlvdXNcIiwgXCJPYnNlc3NpdmVcIiwgXCJPYnZpb3VzXCIsIFwiT3BpbmlvbmF0ZWRcIiwgXCJPcmFuZ2VcIixcbiAgICBcIlBhaW5mdWxcIiwgXCJQYXNzaW9uYXRlXCIsIFwiUGVyZmVjdFwiLCBcIlBpbmtcIiwgXCJQbGF5ZnVsXCIsIFwiUG9pc29ub3VzXCIsIFwiUG9saXRlXCIsIFwiUG9vclwiLCBcIlBvcHVsYXJcIiwgXCJQb3dlcmZ1bFwiLFxuICAgIFwiUHJlY2lzZVwiLCBcIlByZXNlcnZlZFwiLCBcIlByZXR0eVwiLCBcIlB1cnBsZVwiLCBcIlF1aWNrXCIsIFwiUXVpZXRcIiwgXCJSYW5kb21cIiwgXCJSYXBpZFwiLCBcIlJhcmVcIiwgXCJSZWFsXCIsXG4gICAgXCJSZWFzc3VyaW5nXCIsIFwiUmVja2xlc3NcIiwgXCJSZWRcIiwgXCJSZWd1bGFyXCIsIFwiUmVtb3JzZWZ1bFwiLCBcIlJlc3BvbnNpYmxlXCIsIFwiUmljaFwiLCBcIlJ1ZGVcIiwgXCJSdXRobGVzc1wiLFxuICAgIFwiU2FkXCIsIFwiU2NhcmVkXCIsIFwiU2NhcnlcIiwgXCJTY29ybmZ1bFwiLCBcIlNjcmVhbWluZ1wiLCBcIlNlbGZpc2hcIiwgXCJTZXJpb3VzXCIsIFwiU2hhZHlcIiwgXCJTaGFreVwiLCBcIlNoYXJwXCIsXG4gICAgXCJTaGlueVwiLCBcIlNoeVwiLCBcIlNpbXBsZVwiLCBcIlNsZWVweVwiLCBcIlNsb3dcIiwgXCJTbHlcIiwgXCJTbWFsbFwiLCBcIlNtYXJ0XCIsIFwiU21lbGx5XCIsIFwiU21pbGluZ1wiLCBcIlNtb290aFwiLFxuICAgIFwiU211Z1wiLCBcIlNvYmVyXCIsIFwiU29mdFwiLCBcIlNvbGVtblwiLCBcIlNxdWFyZVwiLCBcIlNxdWFyZVwiLCBcIlN0ZWFkeVwiLCBcIlN0cmFuZ2VcIiwgXCJTdHJvbmdcIixcbiAgICBcIlN0dW5uaW5nXCIsIFwiU3ViamVjdGl2ZVwiLCBcIlN1Y2Nlc3NmdWxcIiwgXCJTdXJseVwiLCBcIlN3ZWV0XCIsIFwiVGFjdGZ1bFwiLCBcIlRlbnNlXCIsXG4gICAgXCJUaG91Z2h0ZnVsXCIsIFwiVGlnaHRcIiwgXCJUaW55XCIsIFwiVG9sZXJhbnRcIiwgXCJVbmVhc3lcIiwgXCJVbmlxdWVcIiwgXCJVbnNlZW5cIiwgXCJXYXJtXCIsIFwiV2Vha1wiLFxuICAgIFwiV2VpcmRcIiwgXCJXZWxsQ29va2VkXCIsIFwiV2lsZFwiLCBcIldpc2VcIiwgXCJXaXR0eVwiLCBcIldvbmRlcmZ1bFwiLCBcIldvcnJpZWRcIiwgXCJZZWxsb3dcIiwgXCJZb3VuZ1wiLFxuICAgIFwiWmVhbG91c1wiXG4gICAgXTtcbi8vdmFyIHByb25vdW5zID0gW1xuLy9dO1xuLy92YXIgY29uanVuY3Rpb25zID0gW1xuLy9cIkFuZFwiLCBcIk9yXCIsIFwiRm9yXCIsIFwiQWJvdmVcIiwgXCJCZWZvcmVcIiwgXCJBZ2FpbnN0XCIsIFwiQmV0d2VlblwiXG4vL107XG5cbi8qXG4gKiBNYXBzIGEgc3RyaW5nIChjYXRlZ29yeSBuYW1lKSB0byB0aGUgYXJyYXkgb2Ygd29yZHMgZnJvbSB0aGF0IGNhdGVnb3J5LlxuICovXG52YXIgQ0FURUdPUklFUyA9XG57XG4gICAgLy9cIl9OT1VOX1wiOiBub3VucyxcbiAgICBcIl9QTFVSQUxOT1VOX1wiOiBwbHVyYWxOb3VucyxcbiAgICAvL1wiX1BMQUNFX1wiOiBwbGFjZXMsXG4gICAgXCJfVkVSQl9cIjogdmVyYnMsXG4gICAgXCJfQURWRVJCX1wiOiBhZHZlcmJzLFxuICAgIFwiX0FESkVDVElWRV9cIjogYWRqZWN0aXZlc1xuICAgIC8vXCJfUFJPTk9VTl9cIjogcHJvbm91bnMsXG4gICAgLy9cIl9DT05KVU5DVElPTl9cIjogY29uanVuY3Rpb25zLFxufTtcblxudmFyIFBBVFRFUk5TID0gW1xuICAgIFwiX0FESkVDVElWRV9fUExVUkFMTk9VTl9fVkVSQl9fQURWRVJCX1wiXG5cbiAgICAvLyBCZWF1dGlmdWxGdW5naU9yU3BhZ2hldHRpXG4gICAgLy9cIl9BREpFQ1RJVkVfX1BMVVJBTE5PVU5fX0NPTkpVTkNUSU9OX19QTFVSQUxOT1VOX1wiLFxuXG4gICAgLy8gQW1hemluZ2x5U2NhcnlUb3lcbiAgICAvL1wiX0FEVkVSQl9fQURKRUNUSVZFX19OT1VOX1wiLFxuXG4gICAgLy8gTmVpdGhlclRyYXNoTm9yUmlmbGVcbiAgICAvL1wiTmVpdGhlcl9OT1VOX05vcl9OT1VOX1wiLFxuICAgIC8vXCJFaXRoZXJfTk9VTl9Pcl9OT1VOX1wiLFxuXG4gICAgLy8gRWl0aGVyQ29wdWxhdGVPckludmVzdGlnYXRlXG4gICAgLy9cIkVpdGhlcl9WRVJCX09yX1ZFUkJfXCIsXG4gICAgLy9cIk5laXRoZXJfVkVSQl9Ob3JfVkVSQl9cIixcblxuICAgIC8vXCJUaGVfQURKRUNUSVZFX19BREpFQ1RJVkVfX05PVU5fXCIsXG4gICAgLy9cIlRoZV9BRFZFUkJfX0FESkVDVElWRV9fTk9VTl9cIixcbiAgICAvL1wiVGhlX0FEVkVSQl9fQURKRUNUSVZFX19OT1VOX3NcIixcbiAgICAvL1wiVGhlX0FEVkVSQl9fQURKRUNUSVZFX19QTFVSQUxOT1VOX19WRVJCX1wiLFxuXG4gICAgLy8gV29sdmVzQ29tcHV0ZUJhZGx5XG4gICAgLy9cIl9QTFVSQUxOT1VOX19WRVJCX19BRFZFUkJfXCIsXG5cbiAgICAvLyBVbml0ZUZhY2lsaXRhdGVBbmRNZXJnZVxuICAgIC8vXCJfVkVSQl9fVkVSQl9BbmRfVkVSQl9cIixcblxuICAgIC8vTmFzdHlXaXRjaGVzQXRUaGVQdWJcbiAgICAvL1wiX0FESkVDVElWRV9fUExVUkFMTk9VTl9BdFRoZV9QTEFDRV9cIixcbl07XG5cblxuLypcbiAqIFJldHVybnMgYSByYW5kb20gZWxlbWVudCBmcm9tIHRoZSBhcnJheSAnYXJyJ1xuICovXG5mdW5jdGlvbiByYW5kb21FbGVtZW50KGFycilcbntcbiAgICByZXR1cm4gYXJyW01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIGFyci5sZW5ndGgpXTtcbn1cblxuLypcbiAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgc3RyaW5nICdzJyBjb250YWlucyBvbmUgb2YgdGhlXG4gKiB0ZW1wbGF0ZSBzdHJpbmdzLlxuICovXG5mdW5jdGlvbiBoYXNUZW1wbGF0ZShzKVxue1xuICAgIGZvciAodmFyIHRlbXBsYXRlIGluIENBVEVHT1JJRVMpe1xuICAgICAgICBpZiAocy5pbmRleE9mKHRlbXBsYXRlKSA+PSAwKXtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBuZXcgcm9vbSBuYW1lLlxuICovXG52YXIgUm9vbU5hbWVHZW5lcmF0b3IgPSB7XG4gICAgZ2VuZXJhdGVSb29tV2l0aG91dFNlcGFyYXRvcjogZnVuY3Rpb24oKVxuICAgIHtcbiAgICAgICAgLy8gTm90ZSB0aGF0IGlmIG1vcmUgdGhhbiBvbmUgcGF0dGVybiBpcyBhdmFpbGFibGUsIHRoZSBjaG9pY2Ugb2YgJ25hbWUnIHdvbid0IGJlIHJhbmRvbSAobmFtZXMgZnJvbSBwYXR0ZXJuc1xuICAgICAgICAvLyB3aXRoIGZld2VyIG9wdGlvbnMgd2lsbCBoYXZlIGhpZ2hlciBwcm9iYWJpbGl0eSBvZiBiZWluZyBjaG9zZW4gdGhhdCBuYW1lcyBmcm9tIHBhdHRlcm5zIHdpdGggbW9yZSBvcHRpb25zKS5cbiAgICAgICAgdmFyIG5hbWUgPSByYW5kb21FbGVtZW50KFBBVFRFUk5TKTtcbiAgICAgICAgdmFyIHdvcmQ7XG4gICAgICAgIHdoaWxlIChoYXNUZW1wbGF0ZShuYW1lKSl7XG4gICAgICAgICAgICBmb3IgKHZhciB0ZW1wbGF0ZSBpbiBDQVRFR09SSUVTKXtcbiAgICAgICAgICAgICAgICB3b3JkID0gcmFuZG9tRWxlbWVudChDQVRFR09SSUVTW3RlbXBsYXRlXSk7XG4gICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUucmVwbGFjZSh0ZW1wbGF0ZSwgd29yZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbmFtZTtcbiAgICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gUm9vbU5hbWVHZW5lcmF0b3I7XG4iLCJ2YXIgYW5pbWF0ZVRpbWVvdXQsIHVwZGF0ZVRpbWVvdXQ7XG5cbnZhciBSb29tTmFtZUdlbmVyYXRvciA9IHJlcXVpcmUoXCIuL1Jvb21uYW1lR2VuZXJhdG9yXCIpO1xuXG5mdW5jdGlvbiBlbnRlcl9yb29tKClcbntcbiAgICB2YXIgdmFsID0gJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLnZhbCgpO1xuICAgIGlmKCF2YWwpIHtcbiAgICAgICAgdmFsID0gJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLmF0dHIoXCJyb29tX25hbWVcIik7XG4gICAgfVxuICAgIGlmICh2YWwpIHtcbiAgICAgICAgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lID0gXCIvXCIgKyB2YWw7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBhbmltYXRlKHdvcmQpIHtcbiAgICB2YXIgY3VycmVudFZhbCA9ICQoXCIjZW50ZXJfcm9vbV9maWVsZFwiKS5hdHRyKFwicGxhY2Vob2xkZXJcIik7XG4gICAgJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLmF0dHIoXCJwbGFjZWhvbGRlclwiLCBjdXJyZW50VmFsICsgd29yZC5zdWJzdHIoMCwgMSkpO1xuICAgIGFuaW1hdGVUaW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgYW5pbWF0ZSh3b3JkLnN1YnN0cmluZygxLCB3b3JkLmxlbmd0aCkpXG4gICAgfSwgNzApO1xufVxuXG5mdW5jdGlvbiB1cGRhdGVfcm9vbW5hbWUoKVxue1xuICAgIHZhciB3b3JkID0gUm9vbU5hbWVHZW5lcmF0b3IuZ2VuZXJhdGVSb29tV2l0aG91dFNlcGFyYXRvcigpO1xuICAgICQoXCIjZW50ZXJfcm9vbV9maWVsZFwiKS5hdHRyKFwicm9vbV9uYW1lXCIsIHdvcmQpO1xuICAgICQoXCIjZW50ZXJfcm9vbV9maWVsZFwiKS5hdHRyKFwicGxhY2Vob2xkZXJcIiwgXCJcIik7XG4gICAgY2xlYXJUaW1lb3V0KGFuaW1hdGVUaW1lb3V0KTtcbiAgICBhbmltYXRlKHdvcmQpO1xuICAgIHVwZGF0ZVRpbWVvdXQgPSBzZXRUaW1lb3V0KHVwZGF0ZV9yb29tbmFtZSwgMTAwMDApO1xufVxuXG5cbmZ1bmN0aW9uIHNldHVwV2VsY29tZVBhZ2UoKVxue1xuICAgICQoXCIjdmlkZW9jb25mZXJlbmNlX3BhZ2VcIikuaGlkZSgpO1xuICAgICQoXCIjZG9tYWluX25hbWVcIikudGV4dChcbiAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5wcm90b2NvbCArIFwiLy9cIiArIHdpbmRvdy5sb2NhdGlvbi5ob3N0ICsgXCIvXCIpO1xuICAgIGlmIChpbnRlcmZhY2VDb25maWcuU0hPV19KSVRTSV9XQVRFUk1BUkspIHtcbiAgICAgICAgdmFyIGxlZnRXYXRlcm1hcmtEaXZcbiAgICAgICAgICAgID0gJChcIiN3ZWxjb21lX3BhZ2VfaGVhZGVyIGRpdltjbGFzcz0nd2F0ZXJtYXJrIGxlZnR3YXRlcm1hcmsnXVwiKTtcbiAgICAgICAgaWYobGVmdFdhdGVybWFya0RpdiAmJiBsZWZ0V2F0ZXJtYXJrRGl2Lmxlbmd0aCA+IDApXG4gICAgICAgIHtcbiAgICAgICAgICAgIGxlZnRXYXRlcm1hcmtEaXYuY3NzKHtkaXNwbGF5OiAnYmxvY2snfSk7XG4gICAgICAgICAgICBsZWZ0V2F0ZXJtYXJrRGl2LnBhcmVudCgpLmdldCgwKS5ocmVmXG4gICAgICAgICAgICAgICAgPSBpbnRlcmZhY2VDb25maWcuSklUU0lfV0FURVJNQVJLX0xJTks7XG4gICAgICAgIH1cblxuICAgIH1cblxuICAgIGlmIChpbnRlcmZhY2VDb25maWcuU0hPV19CUkFORF9XQVRFUk1BUkspIHtcbiAgICAgICAgdmFyIHJpZ2h0V2F0ZXJtYXJrRGl2XG4gICAgICAgICAgICA9ICQoXCIjd2VsY29tZV9wYWdlX2hlYWRlciBkaXZbY2xhc3M9J3dhdGVybWFyayByaWdodHdhdGVybWFyayddXCIpO1xuICAgICAgICBpZihyaWdodFdhdGVybWFya0RpdiAmJiByaWdodFdhdGVybWFya0Rpdi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICByaWdodFdhdGVybWFya0Rpdi5jc3Moe2Rpc3BsYXk6ICdibG9jayd9KTtcbiAgICAgICAgICAgIHJpZ2h0V2F0ZXJtYXJrRGl2LnBhcmVudCgpLmdldCgwKS5ocmVmXG4gICAgICAgICAgICAgICAgPSBpbnRlcmZhY2VDb25maWcuQlJBTkRfV0FURVJNQVJLX0xJTks7XG4gICAgICAgICAgICByaWdodFdhdGVybWFya0Rpdi5nZXQoMCkuc3R5bGUuYmFja2dyb3VuZEltYWdlXG4gICAgICAgICAgICAgICAgPSBcInVybChpbWFnZXMvcmlnaHR3YXRlcm1hcmsucG5nKVwiO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGludGVyZmFjZUNvbmZpZy5TSE9XX1BPV0VSRURfQlkpIHtcbiAgICAgICAgJChcIiN3ZWxjb21lX3BhZ2VfaGVhZGVyPmFbY2xhc3M9J3Bvd2VyZWRieSddXCIpXG4gICAgICAgICAgICAuY3NzKHtkaXNwbGF5OiAnYmxvY2snfSk7XG4gICAgfVxuXG4gICAgJChcIiNlbnRlcl9yb29tX2J1dHRvblwiKS5jbGljayhmdW5jdGlvbigpXG4gICAge1xuICAgICAgICBlbnRlcl9yb29tKCk7XG4gICAgfSk7XG5cbiAgICAkKFwiI2VudGVyX3Jvb21fZmllbGRcIikua2V5ZG93bihmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgaWYgKGV2ZW50LmtleUNvZGUgPT09IDEzIC8qIGVudGVyICovKSB7XG4gICAgICAgICAgICBlbnRlcl9yb29tKCk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIGlmICghKGludGVyZmFjZUNvbmZpZy5HRU5FUkFURV9ST09NTkFNRVNfT05fV0VMQ09NRV9QQUdFID09PSBmYWxzZSkpe1xuICAgICAgICB2YXIgdXBkYXRlVGltZW91dDtcbiAgICAgICAgdmFyIGFuaW1hdGVUaW1lb3V0O1xuICAgICAgICAkKFwiI3JlbG9hZF9yb29tbmFtZVwiKS5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodXBkYXRlVGltZW91dCk7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQoYW5pbWF0ZVRpbWVvdXQpO1xuICAgICAgICAgICAgdXBkYXRlX3Jvb21uYW1lKCk7XG4gICAgICAgIH0pO1xuICAgICAgICAkKFwiI3JlbG9hZF9yb29tbmFtZVwiKS5zaG93KCk7XG5cblxuICAgICAgICB1cGRhdGVfcm9vbW5hbWUoKTtcbiAgICB9XG5cbiAgICAkKFwiI2Rpc2FibGVfd2VsY29tZVwiKS5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uud2VsY29tZVBhZ2VEaXNhYmxlZFxuICAgICAgICAgICAgPSAkKFwiI2Rpc2FibGVfd2VsY29tZVwiKS5pcyhcIjpjaGVja2VkXCIpO1xuICAgIH0pO1xuXG59XG5cbm1vZHVsZS5leHBvcnRzID0gc2V0dXBXZWxjb21lUGFnZTsiLCJ2YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcImV2ZW50c1wiKTtcbnZhciBldmVudEVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG52YXIgQ1FFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9jb25uZWN0aW9ucXVhbGl0eS9DUUV2ZW50c1wiKTtcbnZhciBYTVBQRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UveG1wcC9YTVBQRXZlbnRzXCIpO1xuXG4vKipcbiAqIGxvY2FsIHN0YXRzXG4gKiBAdHlwZSB7e319XG4gKi9cbnZhciBzdGF0cyA9IHt9O1xuXG4vKipcbiAqIHJlbW90ZSBzdGF0c1xuICogQHR5cGUge3t9fVxuICovXG52YXIgcmVtb3RlU3RhdHMgPSB7fTtcblxuLyoqXG4gKiBJbnRlcnZhbCBmb3Igc2VuZGluZyBzdGF0aXN0aWNzIHRvIG90aGVyIHBhcnRpY2lwYW50c1xuICogQHR5cGUge251bGx9XG4gKi9cbnZhciBzZW5kSW50ZXJ2YWxJZCA9IG51bGw7XG5cblxuLyoqXG4gKiBTdGFydCBzdGF0aXN0aWNzIHNlbmRpbmcuXG4gKi9cbmZ1bmN0aW9uIHN0YXJ0U2VuZGluZ1N0YXRzKCkge1xuICAgIHNlbmRTdGF0cygpO1xuICAgIHNlbmRJbnRlcnZhbElkID0gc2V0SW50ZXJ2YWwoc2VuZFN0YXRzLCAxMDAwMCk7XG59XG5cbi8qKlxuICogU2VuZHMgc3RhdGlzdGljcyB0byBvdGhlciBwYXJ0aWNpcGFudHNcbiAqL1xuZnVuY3Rpb24gc2VuZFN0YXRzKCkge1xuICAgIEFQUC54bXBwLmFkZFRvUHJlc2VuY2UoXCJjb25uZWN0aW9uUXVhbGl0eVwiLCBjb252ZXJ0VG9NVUNTdGF0cyhzdGF0cykpO1xufVxuXG4vKipcbiAqIENvbnZlcnRzIHN0YXRpc3RpY3MgdG8gZm9ybWF0IGZvciBzZW5kaW5nIHRocm91Z2ggWE1QUFxuICogQHBhcmFtIHN0YXRzIHRoZSBzdGF0aXN0aWNzXG4gKiBAcmV0dXJucyB7e2JpdHJhdGVfZG9ud2xvYWQ6ICosIGJpdHJhdGVfdXBscG9hZDogKiwgcGFja2V0TG9zc190b3RhbDogKiwgcGFja2V0TG9zc19kb3dubG9hZDogKiwgcGFja2V0TG9zc191cGxvYWQ6ICp9fVxuICovXG5mdW5jdGlvbiBjb252ZXJ0VG9NVUNTdGF0cyhzdGF0cykge1xuICAgIHJldHVybiB7XG4gICAgICAgIFwiYml0cmF0ZV9kb3dubG9hZFwiOiBzdGF0cy5iaXRyYXRlLmRvd25sb2FkLFxuICAgICAgICBcImJpdHJhdGVfdXBsb2FkXCI6IHN0YXRzLmJpdHJhdGUudXBsb2FkLFxuICAgICAgICBcInBhY2tldExvc3NfdG90YWxcIjogc3RhdHMucGFja2V0TG9zcy50b3RhbCxcbiAgICAgICAgXCJwYWNrZXRMb3NzX2Rvd25sb2FkXCI6IHN0YXRzLnBhY2tldExvc3MuZG93bmxvYWQsXG4gICAgICAgIFwicGFja2V0TG9zc191cGxvYWRcIjogc3RhdHMucGFja2V0TG9zcy51cGxvYWRcbiAgICB9O1xufVxuXG4vKipcbiAqIENvbnZlcnRzIHN0YXRpdGlzdGljcyB0byBmb3JtYXQgdXNlZCBieSBWaWRlb0xheW91dFxuICogQHBhcmFtIHN0YXRzXG4gKiBAcmV0dXJucyB7e2JpdHJhdGU6IHtkb3dubG9hZDogKiwgdXBsb2FkOiAqfSwgcGFja2V0TG9zczoge3RvdGFsOiAqLCBkb3dubG9hZDogKiwgdXBsb2FkOiAqfX19XG4gKi9cbmZ1bmN0aW9uIHBhcnNlTVVDU3RhdHMoc3RhdHMpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBiaXRyYXRlOiB7XG4gICAgICAgICAgICBkb3dubG9hZDogc3RhdHMuYml0cmF0ZV9kb3dubG9hZCxcbiAgICAgICAgICAgIHVwbG9hZDogc3RhdHMuYml0cmF0ZV91cGxvYWRcbiAgICAgICAgfSxcbiAgICAgICAgcGFja2V0TG9zczoge1xuICAgICAgICAgICAgdG90YWw6IHN0YXRzLnBhY2tldExvc3NfdG90YWwsXG4gICAgICAgICAgICBkb3dubG9hZDogc3RhdHMucGFja2V0TG9zc19kb3dubG9hZCxcbiAgICAgICAgICAgIHVwbG9hZDogc3RhdHMucGFja2V0TG9zc191cGxvYWRcbiAgICAgICAgfVxuICAgIH07XG59XG5cblxudmFyIENvbm5lY3Rpb25RdWFsaXR5ID0ge1xuICAgIGluaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5SRU1PVEVfU1RBVFMsIHRoaXMudXBkYXRlUmVtb3RlU3RhdHMpO1xuICAgICAgICBBUFAuc3RhdGlzdGljcy5hZGRDb25uZWN0aW9uU3RhdHNMaXN0ZW5lcih0aGlzLnVwZGF0ZUxvY2FsU3RhdHMpO1xuICAgICAgICBBUFAuc3RhdGlzdGljcy5hZGRSZW1vdGVTdGF0c1N0b3BMaXN0ZW5lcih0aGlzLnN0b3BTZW5kaW5nU3RhdHMpO1xuXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIGxvY2FsIHN0YXRpc3RpY3NcbiAgICAgKiBAcGFyYW0gZGF0YSBuZXcgc3RhdGlzdGljc1xuICAgICAqL1xuICAgIHVwZGF0ZUxvY2FsU3RhdHM6IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgIHN0YXRzID0gZGF0YTtcbiAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoQ1FFdmVudHMuTE9DQUxTVEFUU19VUERBVEVELCAxMDAgLSBzdGF0cy5wYWNrZXRMb3NzLnRvdGFsLCBzdGF0cyk7XG4gICAgICAgIGlmIChzZW5kSW50ZXJ2YWxJZCA9PSBudWxsKSB7XG4gICAgICAgICAgICBzdGFydFNlbmRpbmdTdGF0cygpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgcmVtb3RlIHN0YXRpc3RpY3NcbiAgICAgKiBAcGFyYW0gamlkIHRoZSBqaWQgYXNzb2NpYXRlZCB3aXRoIHRoZSBzdGF0aXN0aWNzXG4gICAgICogQHBhcmFtIGRhdGEgdGhlIHN0YXRpc3RpY3NcbiAgICAgKi9cbiAgICB1cGRhdGVSZW1vdGVTdGF0czogZnVuY3Rpb24gKGppZCwgZGF0YSkge1xuICAgICAgICBpZiAoZGF0YSA9PSBudWxsIHx8IGRhdGEucGFja2V0TG9zc190b3RhbCA9PSBudWxsKSB7XG4gICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChDUUV2ZW50cy5SRU1PVEVTVEFUU19VUERBVEVELCBqaWQsIG51bGwsIG51bGwpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHJlbW90ZVN0YXRzW2ppZF0gPSBwYXJzZU1VQ1N0YXRzKGRhdGEpO1xuXG4gICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KENRRXZlbnRzLlJFTU9URVNUQVRTX1VQREFURUQsXG4gICAgICAgICAgICBqaWQsIDEwMCAtIGRhdGEucGFja2V0TG9zc190b3RhbCwgcmVtb3RlU3RhdHNbamlkXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0b3BzIHN0YXRpc3RpY3Mgc2VuZGluZy5cbiAgICAgKi9cbiAgICBzdG9wU2VuZGluZ1N0YXRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwoc2VuZEludGVydmFsSWQpO1xuICAgICAgICBzZW5kSW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgICAgIC8vbm90aWZ5IFVJIGFib3V0IHN0b3BwaW5nIHN0YXRpc3RpY3MgZ2F0aGVyaW5nXG4gICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KENRRXZlbnRzLlNUT1ApO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBsb2NhbCBzdGF0aXN0aWNzLlxuICAgICAqL1xuICAgIGdldFN0YXRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBzdGF0cztcbiAgICB9LFxuICAgIFxuICAgIGFkZExpc3RlbmVyOiBmdW5jdGlvbiAodHlwZSwgbGlzdGVuZXIpIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLm9uKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ29ubmVjdGlvblF1YWxpdHk7IiwiLyogZ2xvYmFsICQsIGFsZXJ0LCBBUFAsIGNoYW5nZUxvY2FsVmlkZW8sIGNocm9tZSwgY29uZmlnLCBnZXRDb25mZXJlbmNlSGFuZGxlcixcbiBnZXRVc2VyTWVkaWFXaXRoQ29uc3RyYWludHMgKi9cbi8qKlxuICogSW5kaWNhdGVzIHRoYXQgZGVza3RvcCBzdHJlYW0gaXMgY3VycmVudGx5IGluIHVzZShmb3IgdG9nZ2xlIHB1cnBvc2UpLlxuICogQHR5cGUge2Jvb2xlYW59XG4gKi9cbnZhciBpc1VzaW5nU2NyZWVuU3RyZWFtID0gZmFsc2U7XG4vKipcbiAqIEluZGljYXRlcyB0aGF0IHN3aXRjaCBzdHJlYW0gb3BlcmF0aW9uIGlzIGluIHByb2dyZXNzIGFuZCBwcmV2ZW50IGZyb21cbiAqIHRyaWdnZXJpbmcgbmV3IGV2ZW50cy5cbiAqIEB0eXBlIHtib29sZWFufVxuICovXG52YXIgc3dpdGNoSW5Qcm9ncmVzcyA9IGZhbHNlO1xuXG4vKipcbiAqIE1ldGhvZCB1c2VkIHRvIGdldCBzY3JlZW4gc2hhcmluZyBzdHJlYW0uXG4gKlxuICogQHR5cGUge2Z1bmN0aW9uIChzdHJlYW1fY2FsbGJhY2ssIGZhaWx1cmVfY2FsbGJhY2t9XG4gKi9cbnZhciBvYnRhaW5EZXNrdG9wU3RyZWFtID0gbnVsbDtcblxuLyoqXG4gKiBJbmRpY2F0ZXMgd2hldGhlciBkZXNrdG9wIHNoYXJpbmcgZXh0ZW5zaW9uIGlzIGluc3RhbGxlZC5cbiAqIEB0eXBlIHtib29sZWFufVxuICovXG52YXIgZXh0SW5zdGFsbGVkID0gZmFsc2U7XG5cbi8qKlxuICogSW5kaWNhdGVzIHdoZXRoZXIgdXBkYXRlIG9mIGRlc2t0b3Agc2hhcmluZyBleHRlbnNpb24gaXMgcmVxdWlyZWQuXG4gKiBAdHlwZSB7Ym9vbGVhbn1cbiAqL1xudmFyIGV4dFVwZGF0ZVJlcXVpcmVkID0gZmFsc2U7XG5cbi8qKlxuICogRmxhZyB1c2VkIHRvIGNhY2hlIGRlc2t0b3Agc2hhcmluZyBlbmFibGVkIHN0YXRlLiBEbyBub3QgdXNlIGRpcmVjdGx5IGFzXG4gKiBpdCBjYW4gYmUgPHR0Pm51bGw8L3R0Pi5cbiAqXG4gKiBAdHlwZSB7bnVsbHxib29sZWFufVxuICovXG52YXIgX2Rlc2t0b3BTaGFyaW5nRW5hYmxlZCA9IG51bGw7XG5cbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiZXZlbnRzXCIpO1xuXG52YXIgZXZlbnRFbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG52YXIgRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzXG4gICAgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9kZXNrdG9wc2hhcmluZy9EZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXNcIik7XG5cbi8qKlxuICogTWV0aG9kIG9idGFpbnMgZGVza3RvcCBzdHJlYW0gZnJvbSBXZWJSVEMgJ3NjcmVlbicgc291cmNlLlxuICogRmxhZyAnY2hyb21lOi8vZmxhZ3MvI2VuYWJsZS11c2VybWVkaWEtc2NyZWVuLWNhcHR1cmUnIG11c3QgYmUgZW5hYmxlZC5cbiAqL1xuZnVuY3Rpb24gb2J0YWluV2ViUlRDU2NyZWVuKHN0cmVhbUNhbGxiYWNrLCBmYWlsQ2FsbGJhY2spIHtcbiAgICBBUFAuUlRDLmdldFVzZXJNZWRpYVdpdGhDb25zdHJhaW50cyhcbiAgICAgICAgWydzY3JlZW4nXSxcbiAgICAgICAgc3RyZWFtQ2FsbGJhY2ssXG4gICAgICAgIGZhaWxDYWxsYmFja1xuICAgICk7XG59XG5cbi8qKlxuICogQ29uc3RydWN0cyBpbmxpbmUgaW5zdGFsbCBVUkwgZm9yIENocm9tZSBkZXNrdG9wIHN0cmVhbWluZyBleHRlbnNpb24uXG4gKiBUaGUgJ2Nocm9tZUV4dGVuc2lvbklkJyBtdXN0IGJlIGRlZmluZWQgaW4gY29uZmlnLmpzLlxuICogQHJldHVybnMge3N0cmluZ31cbiAqL1xuZnVuY3Rpb24gZ2V0V2ViU3RvcmVJbnN0YWxsVXJsKClcbntcbiAgICByZXR1cm4gXCJodHRwczovL2Nocm9tZS5nb29nbGUuY29tL3dlYnN0b3JlL2RldGFpbC9cIiArXG4gICAgICAgIGNvbmZpZy5jaHJvbWVFeHRlbnNpb25JZDtcbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBleHRlbnNpb24gdXBkYXRlIGlzIHJlcXVpcmVkLlxuICogQHBhcmFtIG1pblZlcnNpb24gbWluaW1hbCByZXF1aXJlZCB2ZXJzaW9uXG4gKiBAcGFyYW0gZXh0VmVyc2lvbiBjdXJyZW50IGV4dGVuc2lvbiB2ZXJzaW9uXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaXNVcGRhdGVSZXF1aXJlZChtaW5WZXJzaW9uLCBleHRWZXJzaW9uKVxue1xuICAgIHRyeVxuICAgIHtcbiAgICAgICAgdmFyIHMxID0gbWluVmVyc2lvbi5zcGxpdCgnLicpO1xuICAgICAgICB2YXIgczIgPSBleHRWZXJzaW9uLnNwbGl0KCcuJyk7XG5cbiAgICAgICAgdmFyIGxlbiA9IE1hdGgubWF4KHMxLmxlbmd0aCwgczIubGVuZ3RoKTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47IGkrKylcbiAgICAgICAge1xuICAgICAgICAgICAgdmFyIG4xID0gMCxcbiAgICAgICAgICAgICAgICBuMiA9IDA7XG5cbiAgICAgICAgICAgIGlmIChpIDwgczEubGVuZ3RoKVxuICAgICAgICAgICAgICAgIG4xID0gcGFyc2VJbnQoczFbaV0pO1xuICAgICAgICAgICAgaWYgKGkgPCBzMi5sZW5ndGgpXG4gICAgICAgICAgICAgICAgbjIgPSBwYXJzZUludChzMltpXSk7XG5cbiAgICAgICAgICAgIGlmIChpc05hTihuMSkgfHwgaXNOYU4objIpKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAobjEgIT09IG4yKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHJldHVybiBuMSA+IG4yO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gd2lsbCBoYXBwZW4gaWYgYm90aHMgdmVyc2lvbiBoYXMgaWRlbnRpY2FsIG51bWJlcnMgaW5cbiAgICAgICAgLy8gdGhlaXIgY29tcG9uZW50cyAoZXZlbiBpZiBvbmUgb2YgdGhlbSBpcyBsb25nZXIsIGhhcyBtb3JlIGNvbXBvbmVudHMpXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY2F0Y2ggKGUpXG4gICAge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiRmFpbGVkIHRvIHBhcnNlIGV4dGVuc2lvbiB2ZXJzaW9uXCIsIGUpO1xuICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKFwiZGlhbG9nLmVycm9yXCIsXG4gICAgICAgICAgICBcImRpYWxvZy5kZXRlY3RleHRcIik7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY2hlY2tFeHRJbnN0YWxsZWQoY2FsbGJhY2spIHtcbiAgICBpZiAoIWNocm9tZS5ydW50aW1lKSB7XG4gICAgICAgIC8vIE5vIEFQSSwgc28gbm8gZXh0ZW5zaW9uIGZvciBzdXJlXG4gICAgICAgIGNhbGxiYWNrKGZhbHNlLCBmYWxzZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY2hyb21lLnJ1bnRpbWUuc2VuZE1lc3NhZ2UoXG4gICAgICAgIGNvbmZpZy5jaHJvbWVFeHRlbnNpb25JZCxcbiAgICAgICAgeyBnZXRWZXJzaW9uOiB0cnVlIH0sXG4gICAgICAgIGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKCFyZXNwb25zZSB8fCAhcmVzcG9uc2UudmVyc2lvbikge1xuICAgICAgICAgICAgICAgIC8vIENvbW11bmljYXRpb24gZmFpbHVyZSAtIGFzc3VtZSB0aGF0IG5vIGVuZHBvaW50IGV4aXN0c1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgICAgICAgXCJFeHRlbnNpb24gbm90IGluc3RhbGxlZD86IFwiLCBjaHJvbWUucnVudGltZS5sYXN0RXJyb3IpO1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGZhbHNlLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gQ2hlY2sgaW5zdGFsbGVkIGV4dGVuc2lvbiB2ZXJzaW9uXG4gICAgICAgICAgICB2YXIgZXh0VmVyc2lvbiA9IHJlc3BvbnNlLnZlcnNpb247XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnRXh0ZW5zaW9uIHZlcnNpb24gaXM6ICcgKyBleHRWZXJzaW9uKTtcbiAgICAgICAgICAgIHZhciB1cGRhdGVSZXF1aXJlZFxuICAgICAgICAgICAgICAgID0gaXNVcGRhdGVSZXF1aXJlZChjb25maWcubWluQ2hyb21lRXh0VmVyc2lvbiwgZXh0VmVyc2lvbik7XG4gICAgICAgICAgICBjYWxsYmFjayghdXBkYXRlUmVxdWlyZWQsIHVwZGF0ZVJlcXVpcmVkKTtcbiAgICAgICAgfVxuICAgICk7XG59XG5cbmZ1bmN0aW9uIGRvR2V0U3RyZWFtRnJvbUV4dGVuc2lvbihzdHJlYW1DYWxsYmFjaywgZmFpbENhbGxiYWNrKSB7XG4gICAgLy8gU2VuZHMgJ2dldFN0cmVhbScgbXNnIHRvIHRoZSBleHRlbnNpb24uXG4gICAgLy8gRXh0ZW5zaW9uIGlkIG11c3QgYmUgZGVmaW5lZCBpbiB0aGUgY29uZmlnLlxuICAgIGNocm9tZS5ydW50aW1lLnNlbmRNZXNzYWdlKFxuICAgICAgICBjb25maWcuY2hyb21lRXh0ZW5zaW9uSWQsXG4gICAgICAgIHsgZ2V0U3RyZWFtOiB0cnVlLCBzb3VyY2VzOiBjb25maWcuZGVza3RvcFNoYXJpbmdTb3VyY2VzIH0sXG4gICAgICAgIGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKCFyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIGZhaWxDYWxsYmFjayhjaHJvbWUucnVudGltZS5sYXN0RXJyb3IpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiUmVzcG9uc2UgZnJvbSBleHRlbnNpb246IFwiICsgcmVzcG9uc2UpO1xuICAgICAgICAgICAgaWYgKHJlc3BvbnNlLnN0cmVhbUlkKSB7XG4gICAgICAgICAgICAgICAgQVBQLlJUQy5nZXRVc2VyTWVkaWFXaXRoQ29uc3RyYWludHMoXG4gICAgICAgICAgICAgICAgICAgIFsnZGVza3RvcCddLFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoc3RyZWFtKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdHJlYW1DYWxsYmFjayhzdHJlYW0pO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmYWlsQ2FsbGJhY2ssXG4gICAgICAgICAgICAgICAgICAgIG51bGwsIG51bGwsIG51bGwsXG4gICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlLnN0cmVhbUlkKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZmFpbENhbGxiYWNrKFwiRXh0ZW5zaW9uIGZhaWxlZCB0byBnZXQgdGhlIHN0cmVhbVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICk7XG59XG4vKipcbiAqIEFza3MgQ2hyb21lIGV4dGVuc2lvbiB0byBjYWxsIGNob29zZURlc2t0b3BNZWRpYSBhbmQgZ2V0cyBjaHJvbWUgJ2Rlc2t0b3AnXG4gKiBzdHJlYW0gZm9yIHJldHVybmVkIHN0cmVhbSB0b2tlbi5cbiAqL1xuZnVuY3Rpb24gb2J0YWluU2NyZWVuRnJvbUV4dGVuc2lvbihzdHJlYW1DYWxsYmFjaywgZmFpbENhbGxiYWNrKSB7XG4gICAgaWYgKGV4dEluc3RhbGxlZCkge1xuICAgICAgICBkb0dldFN0cmVhbUZyb21FeHRlbnNpb24oc3RyZWFtQ2FsbGJhY2ssIGZhaWxDYWxsYmFjayk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKGV4dFVwZGF0ZVJlcXVpcmVkKSB7XG4gICAgICAgICAgICBhbGVydChcbiAgICAgICAgICAgICAgICAnSml0c2kgRGVza3RvcCBTdHJlYW1lciByZXF1aXJlcyB1cGRhdGUuICcgK1xuICAgICAgICAgICAgICAgICdDaGFuZ2VzIHdpbGwgdGFrZSBlZmZlY3QgYWZ0ZXIgbmV4dCBDaHJvbWUgcmVzdGFydC4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNocm9tZS53ZWJzdG9yZS5pbnN0YWxsKFxuICAgICAgICAgICAgZ2V0V2ViU3RvcmVJbnN0YWxsVXJsKCksXG4gICAgICAgICAgICBmdW5jdGlvbiAoYXJnKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJFeHRlbnNpb24gaW5zdGFsbGVkIHN1Y2Nlc3NmdWxseVwiLCBhcmcpO1xuICAgICAgICAgICAgICAgIC8vIFdlIG5lZWQgdG8gcmVsb2FkIHRoZSBwYWdlIGluIG9yZGVyIHRvIGdldCB0aGUgYWNjZXNzIHRvXG4gICAgICAgICAgICAgICAgLy8gY2hyb21lLnJ1bnRpbWVcbiAgICAgICAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucmVsb2FkKGZhbHNlKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoYXJnKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJGYWlsZWQgdG8gaW5zdGFsbCB0aGUgZXh0ZW5zaW9uXCIsIGFyZyk7XG4gICAgICAgICAgICAgICAgZmFpbENhbGxiYWNrKGFyZyk7XG4gICAgICAgICAgICAgICAgQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcihcImRpYWxvZy5lcnJvclwiLFxuICAgICAgICAgICAgICAgICAgICBcImRpYWxvZy5mYWlsdG9pbnN0YWxsXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH1cbn1cblxuLyoqXG4gKiBDYWxsIHRoaXMgbWV0aG9kIHRvIHRvZ2dsZSBkZXNrdG9wIHNoYXJpbmcgZmVhdHVyZS5cbiAqIEBwYXJhbSBtZXRob2QgcGFzcyBcImV4dFwiIHRvIHVzZSBjaHJvbWUgZXh0ZW5zaW9uIGZvciBkZXNrdG9wIGNhcHR1cmUoY2hyb21lXG4gKiAgICAgICAgZXh0ZW5zaW9uIHJlcXVpcmVkKSwgcGFzcyBcIndlYnJ0Y1wiIHRvIHVzZSBXZWJSVEMgXCJzY3JlZW5cIiBkZXNrdG9wXG4gKiAgICAgICAgc291cmNlKCdjaHJvbWU6Ly9mbGFncy8jZW5hYmxlLXVzZXJtZWRpYS1zY3JlZW4tY2FwdHVyZScgbXVzdCBiZVxuICogICAgICAgIGVuYWJsZWQpLCBwYXNzIGFueSBvdGhlciBzdHJpbmcgb3Igbm90aGluZyBpbiBvcmRlciB0byBkaXNhYmxlIHRoaXNcbiAqICAgICAgICBmZWF0dXJlIGNvbXBsZXRlbHkuXG4gKi9cbmZ1bmN0aW9uIHNldERlc2t0b3BTaGFyaW5nKG1ldGhvZCkge1xuICAgIC8vIENoZWNrIGlmIHdlIGFyZSBydW5uaW5nIGNocm9tZVxuICAgIGlmICghbmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYSkge1xuICAgICAgICBvYnRhaW5EZXNrdG9wU3RyZWFtID0gbnVsbDtcbiAgICAgICAgY29uc29sZS5pbmZvKFwiRGVza3RvcCBzaGFyaW5nIGRpc2FibGVkXCIpO1xuICAgIH0gZWxzZSBpZiAobWV0aG9kID09IFwiZXh0XCIpIHtcbiAgICAgICAgb2J0YWluRGVza3RvcFN0cmVhbSA9IG9idGFpblNjcmVlbkZyb21FeHRlbnNpb247XG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIlVzaW5nIENocm9tZSBleHRlbnNpb24gZm9yIGRlc2t0b3Agc2hhcmluZ1wiKTtcbiAgICB9IGVsc2UgaWYgKG1ldGhvZCA9PSBcIndlYnJ0Y1wiKSB7XG4gICAgICAgIG9idGFpbkRlc2t0b3BTdHJlYW0gPSBvYnRhaW5XZWJSVENTY3JlZW47XG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIlVzaW5nIENocm9tZSBXZWJSVEMgZm9yIGRlc2t0b3Agc2hhcmluZ1wiKTtcbiAgICB9XG5cbiAgICAvLyBSZXNldCBlbmFibGVkIGNhY2hlXG4gICAgX2Rlc2t0b3BTaGFyaW5nRW5hYmxlZCA9IG51bGw7XG59XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgPGxpbmsgcmVsPWNocm9tZS13ZWJzdG9yZS1pdGVtIC8+IHdpdGggZXh0ZW5zaW9uIGlkIHNldCBpblxuICogY29uZmlnLmpzIHRvIHN1cHBvcnQgaW5saW5lIGluc3RhbGxzLiBIb3N0IHNpdGUgbXVzdCBiZSBzZWxlY3RlZCBhcyBtYWluXG4gKiB3ZWJzaXRlIG9mIHB1Ymxpc2hlZCBleHRlbnNpb24uXG4gKi9cbmZ1bmN0aW9uIGluaXRJbmxpbmVJbnN0YWxscygpXG57XG4gICAgJChcImxpbmtbcmVsPWNocm9tZS13ZWJzdG9yZS1pdGVtXVwiKS5hdHRyKFwiaHJlZlwiLCBnZXRXZWJTdG9yZUluc3RhbGxVcmwoKSk7XG59XG5cbmZ1bmN0aW9uIGdldFZpZGVvU3RyZWFtRmFpbGVkKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBvYnRhaW4gdGhlIHN0cmVhbSB0byBzd2l0Y2ggdG9cIiwgZXJyb3IpO1xuICAgIHN3aXRjaEluUHJvZ3Jlc3MgPSBmYWxzZTtcbiAgICBpc1VzaW5nU2NyZWVuU3RyZWFtID0gZmFsc2U7XG4gICAgbmV3U3RyZWFtQ3JlYXRlZChudWxsKTtcbn1cblxuZnVuY3Rpb24gZ2V0RGVza3RvcFN0cmVhbUZhaWxlZChlcnJvcikge1xuICAgIGNvbnNvbGUuZXJyb3IoXCJGYWlsZWQgdG8gb2J0YWluIHRoZSBzdHJlYW0gdG8gc3dpdGNoIHRvXCIsIGVycm9yKTtcbiAgICBzd2l0Y2hJblByb2dyZXNzID0gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIHN0cmVhbVN3aXRjaERvbmUoKSB7XG4gICAgc3dpdGNoSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAgIGV2ZW50RW1pdHRlci5lbWl0KFxuICAgICAgICBEZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXMuU1dJVENISU5HX0RPTkUsXG4gICAgICAgIGlzVXNpbmdTY3JlZW5TdHJlYW0pO1xufVxuXG5mdW5jdGlvbiBuZXdTdHJlYW1DcmVhdGVkKHN0cmVhbSlcbntcbiAgICBldmVudEVtaXR0ZXIuZW1pdChEZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXMuTkVXX1NUUkVBTV9DUkVBVEVELFxuICAgICAgICBzdHJlYW0sIGlzVXNpbmdTY3JlZW5TdHJlYW0sIHN0cmVhbVN3aXRjaERvbmUpO1xufVxuXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIGlzVXNpbmdTY3JlZW5TdHJlYW06IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGlzVXNpbmdTY3JlZW5TdHJlYW07XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8dHQ+dHJ1ZTwvdHQ+IGlmIGRlc2t0b3Agc2hhcmluZyBmZWF0dXJlIGlzIGF2YWlsYWJsZVxuICAgICAqICAgICAgICAgIGFuZCBlbmFibGVkLlxuICAgICAqL1xuICAgIGlzRGVza3RvcFNoYXJpbmdFbmFibGVkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmIChfZGVza3RvcFNoYXJpbmdFbmFibGVkID09PSBudWxsKSB7XG4gICAgICAgICAgICBpZiAob2J0YWluRGVza3RvcFN0cmVhbSA9PT0gb2J0YWluU2NyZWVuRnJvbUV4dGVuc2lvbikge1xuICAgICAgICAgICAgICAgIC8vIFBhcnNlIGNocm9tZSB2ZXJzaW9uXG4gICAgICAgICAgICAgICAgdmFyIHVzZXJBZ2VudCA9IG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBjYW4gYXNzdW1lIHRoYXQgdXNlciBhZ2VudCBpcyBjaHJvbWUsIGJlY2F1c2UgaXQnc1xuICAgICAgICAgICAgICAgIC8vIGVuZm9yY2VkIHdoZW4gJ2V4dCcgc3RyZWFtaW5nIG1ldGhvZCBpcyBzZXRcbiAgICAgICAgICAgICAgICB2YXIgdmVyID0gcGFyc2VJbnQodXNlckFnZW50Lm1hdGNoKC9jaHJvbWVcXC8oXFxkKylcXC4vKVsxXSwgMTApO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiQ2hyb21lIHZlcnNpb25cIiArIHVzZXJBZ2VudCwgdmVyKTtcbiAgICAgICAgICAgICAgICBfZGVza3RvcFNoYXJpbmdFbmFibGVkID0gdmVyID49IDM0O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBfZGVza3RvcFNoYXJpbmdFbmFibGVkID1cbiAgICAgICAgICAgICAgICAgICAgb2J0YWluRGVza3RvcFN0cmVhbSA9PT0gb2J0YWluV2ViUlRDU2NyZWVuO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBfZGVza3RvcFNoYXJpbmdFbmFibGVkO1xuICAgIH0sXG4gICAgXG4gICAgaW5pdDogZnVuY3Rpb24gKCkge1xuICAgICAgICBzZXREZXNrdG9wU2hhcmluZyhjb25maWcuZGVza3RvcFNoYXJpbmcpO1xuXG4gICAgICAgIC8vIEluaXRpYWxpemUgQ2hyb21lIGV4dGVuc2lvbiBpbmxpbmUgaW5zdGFsbHNcbiAgICAgICAgaWYgKGNvbmZpZy5jaHJvbWVFeHRlbnNpb25JZCkge1xuXG4gICAgICAgICAgICBpbml0SW5saW5lSW5zdGFsbHMoKTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgZXh0ZW5zaW9uIGlzIGluc3RhbGxlZFxuICAgICAgICAgICAgY2hlY2tFeHRJbnN0YWxsZWQoZnVuY3Rpb24gKGluc3RhbGxlZCwgdXBkYXRlUmVxdWlyZWQpIHtcbiAgICAgICAgICAgICAgICBleHRJbnN0YWxsZWQgPSBpbnN0YWxsZWQ7XG4gICAgICAgICAgICAgICAgZXh0VXBkYXRlUmVxdWlyZWQgPSB1cGRhdGVSZXF1aXJlZDtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICAgICAgICAgIFwiQ2hyb21lIGV4dGVuc2lvbiBpbnN0YWxsZWQ6IFwiICsgZXh0SW5zdGFsbGVkICtcbiAgICAgICAgICAgICAgICAgICAgXCIgdXBkYXRlUmVxdWlyZWQ6IFwiICsgZXh0VXBkYXRlUmVxdWlyZWQpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChEZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXMuSU5JVCk7XG4gICAgfSxcblxuICAgIGFkZExpc3RlbmVyOiBmdW5jdGlvbiAobGlzdGVuZXIsIHR5cGUpXG4gICAge1xuICAgICAgICBldmVudEVtaXR0ZXIub24odHlwZSwgbGlzdGVuZXIpO1xuICAgIH0sXG5cbiAgICByZW1vdmVMaXN0ZW5lcjogZnVuY3Rpb24gKGxpc3RlbmVyLCB0eXBlKSB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcik7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVG9nZ2xlcyBzY3JlZW4gc2hhcmluZy5cbiAgICAgKi9cbiAgICB0b2dnbGVTY3JlZW5TaGFyaW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmIChzd2l0Y2hJblByb2dyZXNzIHx8ICFvYnRhaW5EZXNrdG9wU3RyZWFtKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJTd2l0Y2ggaW4gcHJvZ3Jlc3Mgb3Igbm8gbWV0aG9kIGRlZmluZWRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc3dpdGNoSW5Qcm9ncmVzcyA9IHRydWU7XG5cbiAgICAgICAgaWYgKCFpc1VzaW5nU2NyZWVuU3RyZWFtKVxuICAgICAgICB7XG4gICAgICAgICAgICAvLyBTd2l0Y2ggdG8gZGVza3RvcCBzdHJlYW1cbiAgICAgICAgICAgIG9idGFpbkRlc2t0b3BTdHJlYW0oXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBXZSBub3cgdXNlIHNjcmVlbiBzdHJlYW1cbiAgICAgICAgICAgICAgICAgICAgaXNVc2luZ1NjcmVlblN0cmVhbSA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIC8vIEhvb2sgJ2VuZGVkJyBldmVudCB0byByZXN0b3JlIGNhbWVyYVxuICAgICAgICAgICAgICAgICAgICAvLyB3aGVuIHNjcmVlbiBzdHJlYW0gc3RvcHNcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ2VuZGVkJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFzd2l0Y2hJblByb2dyZXNzICYmIGlzVXNpbmdTY3JlZW5TdHJlYW0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQVBQLmRlc2t0b3BzaGFyaW5nLnRvZ2dsZVNjcmVlblNoYXJpbmcoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIG5ld1N0cmVhbUNyZWF0ZWQoc3RyZWFtKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGdldERlc2t0b3BTdHJlYW1GYWlsZWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRGlzYWJsZSBzY3JlZW4gc3RyZWFtXG4gICAgICAgICAgICBBUFAuUlRDLmdldFVzZXJNZWRpYVdpdGhDb25zdHJhaW50cyhcbiAgICAgICAgICAgICAgICBbJ3ZpZGVvJ10sXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBXZSBhcmUgbm93IHVzaW5nIGNhbWVyYSBzdHJlYW1cbiAgICAgICAgICAgICAgICAgICAgaXNVc2luZ1NjcmVlblN0cmVhbSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICBuZXdTdHJlYW1DcmVhdGVkKHN0cmVhbSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBnZXRWaWRlb1N0cmVhbUZhaWxlZCwgY29uZmlnLnJlc29sdXRpb24gfHwgJzM2MCdcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4iLCIvL21hcHMga2V5Y29kZSB0byBjaGFyYWN0ZXIsIGlkIG9mIHBvcG92ZXIgZm9yIGdpdmVuIGZ1bmN0aW9uIGFuZCBmdW5jdGlvblxudmFyIHNob3J0Y3V0cyA9IHtcbiAgICA2Nzoge1xuICAgICAgICBjaGFyYWN0ZXI6IFwiQ1wiLFxuICAgICAgICBpZDogXCJ0b2dnbGVDaGF0UG9wb3ZlclwiLFxuICAgICAgICBmdW5jdGlvbjogQVBQLlVJLnRvZ2dsZUNoYXRcbiAgICB9LFxuICAgIDcwOiB7XG4gICAgICAgIGNoYXJhY3RlcjogXCJGXCIsXG4gICAgICAgIGlkOiBcImZpbG1zdHJpcFBvcG92ZXJcIixcbiAgICAgICAgZnVuY3Rpb246IEFQUC5VSS50b2dnbGVGaWxtU3RyaXBcbiAgICB9LFxuICAgIDc3OiB7XG4gICAgICAgIGNoYXJhY3RlcjogXCJNXCIsXG4gICAgICAgIGlkOiBcIm11dGVQb3BvdmVyXCIsXG4gICAgICAgIGZ1bmN0aW9uOiBBUFAuVUkudG9nZ2xlQXVkaW9cbiAgICB9LFxuICAgIDg0OiB7XG4gICAgICAgIGNoYXJhY3RlcjogXCJUXCIsXG4gICAgICAgIGZ1bmN0aW9uOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGlmKCFBUFAuUlRDLmxvY2FsQXVkaW8uaXNNdXRlZCgpKSB7XG4gICAgICAgICAgICAgICAgQVBQLlVJLnRvZ2dsZUF1ZGlvKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIDg2OiB7XG4gICAgICAgIGNoYXJhY3RlcjogXCJWXCIsXG4gICAgICAgIGlkOiBcInRvZ2dsZVZpZGVvUG9wb3ZlclwiLFxuICAgICAgICBmdW5jdGlvbjogQVBQLlVJLnRvZ2dsZVZpZGVvXG4gICAgfVxufTtcblxuXG52YXIgS2V5Ym9hcmRTaG9ydGN1dCA9IHtcbiAgICBpbml0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHdpbmRvdy5vbmtleXVwID0gZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgdmFyIGtleWNvZGUgPSBlLndoaWNoO1xuICAgICAgICAgICAgaWYoISgkKFwiOmZvY3VzXCIpLmlzKFwiaW5wdXRbdHlwZT10ZXh0XVwiKSB8fFxuICAgICAgICAgICAgICAgICQoXCI6Zm9jdXNcIikuaXMoXCJpbnB1dFt0eXBlPXBhc3N3b3JkXVwiKSB8fFxuICAgICAgICAgICAgICAgICQoXCI6Zm9jdXNcIikuaXMoXCJ0ZXh0YXJlYVwiKSkpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHNob3J0Y3V0c1trZXljb2RlXSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgICAgICAgICBzaG9ydGN1dHNba2V5Y29kZV0uZnVuY3Rpb24oKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoa2V5Y29kZSA+PSBcIjBcIi5jaGFyQ29kZUF0KDApICYmXG4gICAgICAgICAgICAgICAgICAgIGtleWNvZGUgPD0gXCI5XCIuY2hhckNvZGVBdCgwKSkge1xuICAgICAgICAgICAgICAgICAgICBBUFAuVUkuY2xpY2tPblZpZGVvKGtleWNvZGUgLSBcIjBcIi5jaGFyQ29kZUF0KDApICsgMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vZXNjIHdoaWxlIHRoZSBzbWlsZXlzIGFyZSB2aXNpYmxlIGhpZGVzIHRoZW1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoa2V5Y29kZSA9PT0gMjcgJiYgJCgnI3NtaWxleXNDb250YWluZXInKS5pcygnOnZpc2libGUnKSkge1xuICAgICAgICAgICAgICAgIEFQUC5VSS50b2dnbGVTbWlsZXlzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgd2luZG93Lm9ua2V5ZG93biA9IGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgIGlmKCEoJChcIjpmb2N1c1wiKS5pcyhcImlucHV0W3R5cGU9dGV4dF1cIikgfHxcbiAgICAgICAgICAgICAgICAkKFwiOmZvY3VzXCIpLmlzKFwiaW5wdXRbdHlwZT1wYXNzd29yZF1cIikgfHxcbiAgICAgICAgICAgICAgICAkKFwiOmZvY3VzXCIpLmlzKFwidGV4dGFyZWFcIikpKSB7XG4gICAgICAgICAgICAgICAgaWYoZS53aGljaCA9PT0gXCJUXCIuY2hhckNvZGVBdCgwKSkge1xuICAgICAgICAgICAgICAgICAgICBpZihBUFAuUlRDLmxvY2FsQXVkaW8uaXNNdXRlZCgpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBBUFAuVUkudG9nZ2xlQXVkaW8oKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAkKCdib2R5JykucG9wb3Zlcih7IHNlbGVjdG9yOiAnW2RhdGEtdG9nZ2xlPXBvcG92ZXJdJyxcbiAgICAgICAgICAgIHRyaWdnZXI6ICdjbGljayBob3ZlcicsXG4gICAgICAgICAgICBjb250ZW50OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRBdHRyaWJ1dGUoXCJjb250ZW50XCIpICtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5nZXRTaG9ydGN1dCh0aGlzLmdldEF0dHJpYnV0ZShcInNob3J0Y3V0XCIpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSBpZCBpbmRpY2F0ZXMgdGhlIHBvcG92ZXIgYXNzb2NpYXRlZCB3aXRoIHRoZSBzaG9ydGN1dFxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IHRoZSBrZXlib2FyZCBzaG9ydGN1dCB1c2VkIGZvciB0aGUgaWQgZ2l2ZW5cbiAgICAgKi9cbiAgICBnZXRTaG9ydGN1dDogZnVuY3Rpb24gKGlkKSB7XG4gICAgICAgIGZvciAodmFyIGtleWNvZGUgaW4gc2hvcnRjdXRzKSB7XG4gICAgICAgICAgICBpZiAoc2hvcnRjdXRzLmhhc093blByb3BlcnR5KGtleWNvZGUpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNob3J0Y3V0c1trZXljb2RlXS5pZCA9PT0gaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwiIChcIiArIHNob3J0Y3V0c1trZXljb2RlXS5jaGFyYWN0ZXIgKyBcIilcIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBLZXlib2FyZFNob3J0Y3V0O1xuIiwidmFyIGVtYWlsID0gJyc7XG52YXIgZGlzcGxheU5hbWUgPSAnJztcbnZhciB1c2VySWQ7XG52YXIgbGFuZ3VhZ2UgPSBudWxsO1xuXG5cbmZ1bmN0aW9uIHN1cHBvcnRzTG9jYWxTdG9yYWdlKCkge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiAnbG9jYWxTdG9yYWdlJyBpbiB3aW5kb3cgJiYgd2luZG93LmxvY2FsU3RvcmFnZSAhPT0gbnVsbDtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwibG9jYWxzdG9yYWdlIGlzIG5vdCBzdXBwb3J0ZWRcIik7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59XG5cblxuZnVuY3Rpb24gZ2VuZXJhdGVVbmlxdWVJZCgpIHtcbiAgICBmdW5jdGlvbiBfcDgoKSB7XG4gICAgICAgIHJldHVybiAoTWF0aC5yYW5kb20oKS50b1N0cmluZygxNikgKyBcIjAwMDAwMDAwMFwiKS5zdWJzdHIoMiwgOCk7XG4gICAgfVxuICAgIHJldHVybiBfcDgoKSArIF9wOCgpICsgX3A4KCkgKyBfcDgoKTtcbn1cblxuaWYgKHN1cHBvcnRzTG9jYWxTdG9yYWdlKCkpIHtcbiAgICBpZiAoIXdpbmRvdy5sb2NhbFN0b3JhZ2Uuaml0c2lNZWV0SWQpIHtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5qaXRzaU1lZXRJZCA9IGdlbmVyYXRlVW5pcXVlSWQoKTtcbiAgICAgICAgY29uc29sZS5sb2coXCJnZW5lcmF0ZWQgaWRcIiwgd2luZG93LmxvY2FsU3RvcmFnZS5qaXRzaU1lZXRJZCk7XG4gICAgfVxuICAgIHVzZXJJZCA9IHdpbmRvdy5sb2NhbFN0b3JhZ2Uuaml0c2lNZWV0SWQgfHwgJyc7XG4gICAgZW1haWwgPSB3aW5kb3cubG9jYWxTdG9yYWdlLmVtYWlsIHx8ICcnO1xuICAgIGRpc3BsYXlOYW1lID0gd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZSB8fCAnJztcbiAgICBsYW5ndWFnZSA9IHdpbmRvdy5sb2NhbFN0b3JhZ2UubGFuZ3VhZ2U7XG59IGVsc2Uge1xuICAgIGNvbnNvbGUubG9nKFwibG9jYWwgc3RvcmFnZSBpcyBub3Qgc3VwcG9ydGVkXCIpO1xuICAgIHVzZXJJZCA9IGdlbmVyYXRlVW5pcXVlSWQoKTtcbn1cblxudmFyIFNldHRpbmdzID1cbntcbiAgICBzZXREaXNwbGF5TmFtZTogZnVuY3Rpb24gKG5ld0Rpc3BsYXlOYW1lKSB7XG4gICAgICAgIGRpc3BsYXlOYW1lID0gbmV3RGlzcGxheU5hbWU7XG4gICAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2UuZGlzcGxheW5hbWUgPSBkaXNwbGF5TmFtZTtcbiAgICAgICAgcmV0dXJuIGRpc3BsYXlOYW1lO1xuICAgIH0sXG4gICAgc2V0RW1haWw6IGZ1bmN0aW9uIChuZXdFbWFpbClcbiAgICB7XG4gICAgICAgIGVtYWlsID0gbmV3RW1haWw7XG4gICAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2UuZW1haWwgPSBuZXdFbWFpbDtcbiAgICAgICAgcmV0dXJuIGVtYWlsO1xuICAgIH0sXG4gICAgZ2V0U2V0dGluZ3M6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGVtYWlsOiBlbWFpbCxcbiAgICAgICAgICAgIGRpc3BsYXlOYW1lOiBkaXNwbGF5TmFtZSxcbiAgICAgICAgICAgIHVpZDogdXNlcklkLFxuICAgICAgICAgICAgbGFuZ3VhZ2U6IGxhbmd1YWdlXG4gICAgICAgIH07XG4gICAgfSxcbiAgICBzZXRMYW5ndWFnZTogZnVuY3Rpb24gKGxhbmcpIHtcbiAgICAgICAgbGFuZ3VhZ2UgPSBsYW5nO1xuICAgICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLmxhbmd1YWdlID0gbGFuZztcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNldHRpbmdzO1xuIiwiLyoqXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIFNpbXVsY2FzdExvZ2dlcihuYW1lLCBsdmwpIHtcbiAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgIHRoaXMubHZsID0gbHZsO1xufVxuXG5TaW11bGNhc3RMb2dnZXIucHJvdG90eXBlLmxvZyA9IGZ1bmN0aW9uICh0ZXh0KSB7XG4gICAgaWYgKHRoaXMubHZsKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKHRleHQpO1xuICAgIH1cbn07XG5cblNpbXVsY2FzdExvZ2dlci5wcm90b3R5cGUuaW5mbyA9IGZ1bmN0aW9uICh0ZXh0KSB7XG4gICAgaWYgKHRoaXMubHZsID4gMSkge1xuICAgICAgICBjb25zb2xlLmluZm8odGV4dCk7XG4gICAgfVxufTtcblxuU2ltdWxjYXN0TG9nZ2VyLnByb3RvdHlwZS5maW5lID0gZnVuY3Rpb24gKHRleHQpIHtcbiAgICBpZiAodGhpcy5sdmwgPiAyKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKHRleHQpO1xuICAgIH1cbn07XG5cblNpbXVsY2FzdExvZ2dlci5wcm90b3R5cGUuZXJyb3IgPSBmdW5jdGlvbiAodGV4dCkge1xuICAgIGNvbnNvbGUuZXJyb3IodGV4dCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNpbXVsY2FzdExvZ2dlcjsiLCJ2YXIgU2ltdWxjYXN0TG9nZ2VyID0gcmVxdWlyZShcIi4vU2ltdWxjYXN0TG9nZ2VyXCIpO1xudmFyIFNpbXVsY2FzdFV0aWxzID0gcmVxdWlyZShcIi4vU2ltdWxjYXN0VXRpbHNcIik7XG52YXIgTWVkaWFTdHJlYW1UeXBlID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL01lZGlhU3RyZWFtVHlwZXNcIik7XG5cbmZ1bmN0aW9uIFNpbXVsY2FzdFJlY2VpdmVyKCkge1xuICAgIHRoaXMuc2ltdWxjYXN0VXRpbHMgPSBuZXcgU2ltdWxjYXN0VXRpbHMoKTtcbiAgICB0aGlzLmxvZ2dlciA9IG5ldyBTaW11bGNhc3RMb2dnZXIoJ1NpbXVsY2FzdFJlY2VpdmVyJywgMSk7XG59XG5cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS5fcmVtb3RlVmlkZW9Tb3VyY2VDYWNoZSA9ICcnO1xuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLl9yZW1vdGVNYXBzID0ge1xuICAgIG1zaWQyUXVhbGl0eToge30sXG4gICAgc3NyYzJNc2lkOiB7fSxcbiAgICBtc2lkMnNzcmM6IHt9LFxuICAgIHJlY2VpdmluZ1ZpZGVvU3RyZWFtczoge31cbn07XG5cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS5fY2FjaGVSZW1vdGVWaWRlb1NvdXJjZXMgPSBmdW5jdGlvbiAobGluZXMpIHtcbiAgICB0aGlzLl9yZW1vdGVWaWRlb1NvdXJjZUNhY2hlID0gdGhpcy5zaW11bGNhc3RVdGlscy5fZ2V0VmlkZW9Tb3VyY2VzKGxpbmVzKTtcbn07XG5cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS5fcmVzdG9yZVJlbW90ZVZpZGVvU291cmNlcyA9IGZ1bmN0aW9uIChsaW5lcykge1xuICAgIHRoaXMuc2ltdWxjYXN0VXRpbHMuX3JlcGxhY2VWaWRlb1NvdXJjZXMobGluZXMsIHRoaXMuX3JlbW90ZVZpZGVvU291cmNlQ2FjaGUpO1xufTtcblxuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLl9lbnN1cmVHb29nQ29uZmVyZW5jZSA9IGZ1bmN0aW9uIChsaW5lcykge1xuICAgIHZhciBzYjtcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ0Vuc3VyaW5nIHgtZ29vZ2xlLWNvbmZlcmVuY2UgZmxhZy4uLicpXG5cbiAgICBpZiAodGhpcy5zaW11bGNhc3RVdGlscy5faW5kZXhPZkFycmF5KCdhPXgtZ29vZ2xlLWZsYWc6Y29uZmVyZW5jZScsIGxpbmVzKSA9PT0gdGhpcy5zaW11bGNhc3RVdGlscy5fZW1wdHlDb21wb3VuZEluZGV4KSB7XG4gICAgICAgIC8vIFRPRE8oZ3ApIGRvIHRoYXQgZm9yIHRoZSBhdWRpbyBhcyB3ZWxsIGFzIHN1Z2dlc3RlZCBieSBmaXBwby5cbiAgICAgICAgLy8gQWRkIHRoZSBnb29nbGUgY29uZmVyZW5jZSBmbGFnXG4gICAgICAgIHNiID0gdGhpcy5zaW11bGNhc3RVdGlscy5fZ2V0VmlkZW9Tb3VyY2VzKGxpbmVzKTtcbiAgICAgICAgc2IgPSBbJ2E9eC1nb29nbGUtZmxhZzpjb25mZXJlbmNlJ10uY29uY2F0KHNiKTtcbiAgICAgICAgdGhpcy5zaW11bGNhc3RVdGlscy5fcmVwbGFjZVZpZGVvU291cmNlcyhsaW5lcywgc2IpO1xuICAgIH1cbn07XG5cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS5fcmVzdG9yZVNpbXVsY2FzdEdyb3VwcyA9IGZ1bmN0aW9uIChzYikge1xuICAgIHRoaXMuX3Jlc3RvcmVSZW1vdGVWaWRlb1NvdXJjZXMoc2IpO1xufTtcblxuLyoqXG4gKiBSZXN0b3JlcyB0aGUgc2ltdWxjYXN0IGdyb3VwcyBvZiB0aGUgcmVtb3RlIGRlc2NyaXB0aW9uLiBJblxuICogdHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24gd2UgcmVtb3ZlIHRob3NlIGluIG9yZGVyIGZvciB0aGUgc2V0IHJlbW90ZVxuICogZGVzY3JpcHRpb24gdG8gc3VjY2VlZC4gVGhlIGZvY3VzIG5lZWRzIHRoZSBzaWduYWwgdGhlIGdyb3VwcyB0byBuZXdcbiAqIHBhcnRpY2lwYW50cy5cbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS5yZXZlcnNlVHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHZhciBzYjtcblxuICAgIGlmICghdGhpcy5zaW11bGNhc3RVdGlscy5pc1ZhbGlkRGVzY3JpcHRpb24oZGVzYykpIHtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgaWYgKGNvbmZpZy5lbmFibGVTaW11bGNhc3QpIHtcbiAgICAgICAgc2IgPSBkZXNjLnNkcC5zcGxpdCgnXFxyXFxuJyk7XG5cbiAgICAgICAgdGhpcy5fcmVzdG9yZVNpbXVsY2FzdEdyb3VwcyhzYik7XG5cbiAgICAgICAgZGVzYyA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICAgICAgdHlwZTogZGVzYy50eXBlLFxuICAgICAgICAgICAgc2RwOiBzYi5qb2luKCdcXHJcXG4nKVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZGVzYztcbn07XG5cblNpbXVsY2FzdFV0aWxzLnByb3RvdHlwZS5fZW5zdXJlT3JkZXIgPSBmdW5jdGlvbiAobGluZXMpIHtcbiAgICB2YXIgdmlkZW9Tb3VyY2VzLCBzYjtcblxuICAgIHZpZGVvU291cmNlcyA9IHRoaXMucGFyc2VNZWRpYShsaW5lcywgWyd2aWRlbyddKVswXTtcbiAgICBzYiA9IHRoaXMuX2NvbXBpbGVWaWRlb1NvdXJjZXModmlkZW9Tb3VyY2VzKTtcblxuICAgIHRoaXMuX3JlcGxhY2VWaWRlb1NvdXJjZXMobGluZXMsIHNiKTtcbn07XG5cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS5fdXBkYXRlUmVtb3RlTWFwcyA9IGZ1bmN0aW9uIChsaW5lcykge1xuICAgIHZhciByZW1vdGVWaWRlb1NvdXJjZXMgPSB0aGlzLnNpbXVsY2FzdFV0aWxzLnBhcnNlTWVkaWEobGluZXMsIFsndmlkZW8nXSlbMF0sXG4gICAgICAgIHZpZGVvU291cmNlLCBxdWFsaXR5O1xuXG4gICAgLy8gKHJlKSBpbml0aWFsaXplIHRoZSByZW1vdGUgbWFwcy5cbiAgICB0aGlzLl9yZW1vdGVNYXBzLm1zaWQyUXVhbGl0eSA9IHt9O1xuICAgIHRoaXMuX3JlbW90ZU1hcHMuc3NyYzJNc2lkID0ge307XG4gICAgdGhpcy5fcmVtb3RlTWFwcy5tc2lkMnNzcmMgPSB7fTtcblxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAocmVtb3RlVmlkZW9Tb3VyY2VzLmdyb3VwcyAmJiByZW1vdGVWaWRlb1NvdXJjZXMuZ3JvdXBzLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICByZW1vdGVWaWRlb1NvdXJjZXMuZ3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICBpZiAoZ3JvdXAuc2VtYW50aWNzID09PSAnU0lNJyAmJiBncm91cC5zc3JjcyAmJiBncm91cC5zc3Jjcy5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICAgICAgICBxdWFsaXR5ID0gMDtcbiAgICAgICAgICAgICAgICBncm91cC5zc3Jjcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgIHZpZGVvU291cmNlID0gcmVtb3RlVmlkZW9Tb3VyY2VzLnNvdXJjZXNbc3NyY107XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuX3JlbW90ZU1hcHMubXNpZDJRdWFsaXR5W3ZpZGVvU291cmNlLm1zaWRdID0gcXVhbGl0eSsrO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLl9yZW1vdGVNYXBzLnNzcmMyTXNpZFt2aWRlb1NvdXJjZS5zc3JjXSA9IHZpZGVvU291cmNlLm1zaWQ7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuX3JlbW90ZU1hcHMubXNpZDJzc3JjW3ZpZGVvU291cmNlLm1zaWRdID0gdmlkZW9Tb3VyY2Uuc3NyYztcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxufTtcblxuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLl9zZXRSZWNlaXZpbmdWaWRlb1N0cmVhbSA9IGZ1bmN0aW9uIChyZXNvdXJjZSwgc3NyYykge1xuICAgIHRoaXMuX3JlbW90ZU1hcHMucmVjZWl2aW5nVmlkZW9TdHJlYW1zW3Jlc291cmNlXSA9IHNzcmM7XG59O1xuXG4vKipcbiAqIFJldHVybnMgYSBzdHJlYW0gd2l0aCBzaW5nbGUgdmlkZW8gdHJhY2ssIHRoZSBvbmUgY3VycmVudGx5IGJlaW5nXG4gKiByZWNlaXZlZCBieSB0aGlzIGVuZHBvaW50LlxuICpcbiAqIEBwYXJhbSBzdHJlYW0gdGhlIHJlbW90ZSBzaW11bGNhc3Qgc3RyZWFtLlxuICogQHJldHVybnMge3dlYmtpdE1lZGlhU3RyZWFtfVxuICovXG5TaW11bGNhc3RSZWNlaXZlci5wcm90b3R5cGUuZ2V0UmVjZWl2aW5nVmlkZW9TdHJlYW0gPSBmdW5jdGlvbiAoc3RyZWFtKSB7XG4gICAgdmFyIHRyYWNrcywgaSwgZWxlY3RlZFRyYWNrLCBtc2lkLCBxdWFsaXR5ID0gMCwgcmVjZWl2aW5nVHJhY2tJZDtcblxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAoY29uZmlnLmVuYWJsZVNpbXVsY2FzdCkge1xuXG4gICAgICAgIHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLnNvbWUoZnVuY3Rpb24gKHRyYWNrKSB7XG4gICAgICAgICAgICByZXR1cm4gT2JqZWN0LmtleXMoc2VsZi5fcmVtb3RlTWFwcy5yZWNlaXZpbmdWaWRlb1N0cmVhbXMpLnNvbWUoZnVuY3Rpb24gKHJlc291cmNlKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNzcmMgPSBzZWxmLl9yZW1vdGVNYXBzLnJlY2VpdmluZ1ZpZGVvU3RyZWFtc1tyZXNvdXJjZV07XG4gICAgICAgICAgICAgICAgdmFyIG1zaWQgPSBzZWxmLl9yZW1vdGVNYXBzLnNzcmMyTXNpZFtzc3JjXTtcbiAgICAgICAgICAgICAgICBpZiAobXNpZCA9PSBbc3RyZWFtLmlkLCB0cmFjay5pZF0uam9pbignICcpKSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZWN0ZWRUcmFjayA9IHRyYWNrO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKCFlbGVjdGVkVHJhY2spIHtcbiAgICAgICAgICAgIC8vIHdlIGRvbid0IGhhdmUgYW4gZWxlY3RlZCB0cmFjaywgY2hvb3NlIGJ5IGluaXRpYWwgcXVhbGl0eS5cbiAgICAgICAgICAgIHRyYWNrcyA9IHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpO1xuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IHRyYWNrcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIG1zaWQgPSBbc3RyZWFtLmlkLCB0cmFja3NbaV0uaWRdLmpvaW4oJyAnKTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5fcmVtb3RlTWFwcy5tc2lkMlF1YWxpdHlbbXNpZF0gPT09IHF1YWxpdHkpIHtcbiAgICAgICAgICAgICAgICAgICAgZWxlY3RlZFRyYWNrID0gdHJhY2tzW2ldO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFRPRE8oZ3ApIGlmIHRoZSBpbml0aWFsUXVhbGl0eSBjb3VsZCBub3QgYmUgc2F0aXNmaWVkLCBsb3dlclxuICAgICAgICAgICAgLy8gdGhlIHJlcXVpcmVtZW50IGFuZCB0cnkgYWdhaW4uXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gKGVsZWN0ZWRUcmFjaylcbiAgICAgICAgPyBuZXcgd2Via2l0TWVkaWFTdHJlYW0oW2VsZWN0ZWRUcmFja10pXG4gICAgICAgIDogc3RyZWFtO1xufTtcblxuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLmdldFJlY2VpdmluZ1NTUkMgPSBmdW5jdGlvbiAoamlkKSB7XG4gICAgdmFyIHJlc291cmNlID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICB2YXIgc3NyYyA9IHRoaXMuX3JlbW90ZU1hcHMucmVjZWl2aW5nVmlkZW9TdHJlYW1zW3Jlc291cmNlXTtcblxuICAgIC8vIElmIHdlIGhhdmVuJ3QgcmVjZWl2aW5nIGEgXCJjaGFuZ2VkXCIgZXZlbnQgeWV0LCB0aGVuIHdlIG11c3QgYmUgcmVjZWl2aW5nXG4gICAgLy8gbG93IHF1YWxpdHkgKHRoYXQgdGhlIHNlbmRlciBhbHdheXMgc3RyZWFtcykuXG4gICAgaWYoIXNzcmMpXG4gICAge1xuICAgICAgICB2YXIgcmVtb3RlU3RyZWFtT2JqZWN0ID0gQVBQLlJUQy5yZW1vdGVTdHJlYW1zW2ppZF1bTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdO1xuICAgICAgICB2YXIgcmVtb3RlU3RyZWFtID0gcmVtb3RlU3RyZWFtT2JqZWN0LmdldE9yaWdpbmFsU3RyZWFtKCk7XG4gICAgICAgIHZhciB0cmFja3MgPSByZW1vdGVTdHJlYW0uZ2V0VmlkZW9UcmFja3MoKTtcbiAgICAgICAgaWYgKHRyYWNrcykge1xuICAgICAgICAgICAgZm9yICh2YXIgayA9IDA7IGsgPCB0cmFja3MubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgdHJhY2sgPSB0cmFja3Nba107XG4gICAgICAgICAgICAgICAgdmFyIG1zaWQgPSBbcmVtb3RlU3RyZWFtLmlkLCB0cmFjay5pZF0uam9pbignICcpO1xuICAgICAgICAgICAgICAgIHZhciBfc3NyYyA9IHRoaXMuX3JlbW90ZU1hcHMubXNpZDJzc3JjW21zaWRdO1xuICAgICAgICAgICAgICAgIHZhciBxdWFsaXR5ID0gdGhpcy5fcmVtb3RlTWFwcy5tc2lkMlF1YWxpdHlbbXNpZF07XG4gICAgICAgICAgICAgICAgaWYgKHF1YWxpdHkgPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBzc3JjID0gX3NzcmM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHNzcmM7XG59O1xuXG5TaW11bGNhc3RSZWNlaXZlci5wcm90b3R5cGUuZ2V0UmVjZWl2aW5nVmlkZW9TdHJlYW1CeVNTUkMgPSBmdW5jdGlvbiAoc3NyYylcbntcbiAgICB2YXIgc2lkLCBlbGVjdGVkU3RyZWFtO1xuICAgIHZhciBpLCBqLCBrO1xuICAgIHZhciBqaWQgPSBBUFAueG1wcC5nZXRKaWRGcm9tU1NSQyhzc3JjKTtcbiAgICBpZihqaWQgJiYgQVBQLlJUQy5yZW1vdGVTdHJlYW1zW2ppZF0pXG4gICAge1xuICAgICAgICB2YXIgcmVtb3RlU3RyZWFtT2JqZWN0ID0gQVBQLlJUQy5yZW1vdGVTdHJlYW1zW2ppZF1bTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdO1xuICAgICAgICB2YXIgcmVtb3RlU3RyZWFtID0gcmVtb3RlU3RyZWFtT2JqZWN0LmdldE9yaWdpbmFsU3RyZWFtKCk7XG4gICAgICAgIHZhciB0cmFja3MgPSByZW1vdGVTdHJlYW0uZ2V0VmlkZW9UcmFja3MoKTtcbiAgICAgICAgaWYgKHRyYWNrcykge1xuICAgICAgICAgICAgZm9yIChrID0gMDsgayA8IHRyYWNrcy5sZW5ndGg7IGsrKykge1xuICAgICAgICAgICAgICAgIHZhciB0cmFjayA9IHRyYWNrc1trXTtcbiAgICAgICAgICAgICAgICB2YXIgbXNpZCA9IFtyZW1vdGVTdHJlYW0uaWQsIHRyYWNrLmlkXS5qb2luKCcgJyk7XG4gICAgICAgICAgICAgICAgdmFyIHRtcCA9IHRoaXMuX3JlbW90ZU1hcHMubXNpZDJzc3JjW21zaWRdO1xuICAgICAgICAgICAgICAgIGlmICh0bXAgPT0gc3NyYykge1xuICAgICAgICAgICAgICAgICAgICBlbGVjdGVkU3RyZWFtID0gbmV3IHdlYmtpdE1lZGlhU3RyZWFtKFt0cmFja10pO1xuICAgICAgICAgICAgICAgICAgICBzaWQgPSByZW1vdGVTdHJlYW1PYmplY3Quc2lkO1xuICAgICAgICAgICAgICAgICAgICAvLyBzdHJlYW0gZm91bmQsIHN0b3AuXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIGNvbnNvbGUuZGVidWcoQVBQLlJUQy5yZW1vdGVTdHJlYW1zLCBqaWQsIHNzcmMpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAgIHNpZDogc2lkLFxuICAgICAgICBzdHJlYW06IGVsZWN0ZWRTdHJlYW1cbiAgICB9O1xufTtcblxuLyoqXG4gKiBHZXRzIHRoZSBmdWxseSBxdWFsaWZpZWQgbXNpZCAoc3RyZWFtLmlkICsgdHJhY2suaWQpIGFzc29jaWF0ZWQgdG8gdGhlXG4gKiBTU1JDLlxuICpcbiAqIEBwYXJhbSBzc3JjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLmdldFJlbW90ZVZpZGVvU3RyZWFtSWRCeVNTUkMgPSBmdW5jdGlvbiAoc3NyYykge1xuICAgIHJldHVybiB0aGlzLl9yZW1vdGVNYXBzLnNzcmMyTXNpZFtzc3JjXTtcbn07XG5cbi8qKlxuICogUmVtb3ZlcyB0aGUgc3NyYy1ncm91cDpTSU0gZnJvbSB0aGUgcmVtb3RlIGRlc2NyaXB0aW9uIGJhY2F1c2UgQ2hyb21lXG4gKiBlaXRoZXIgZ2V0cyBjb25mdXNlZCBhbmQgdGhpbmtzIHRoaXMgaXMgYW4gRklEIGdyb3VwIG9yLCBpZiBhbiBGSUQgZ3JvdXBcbiAqIGlzIGFscmVhZHkgcHJlc2VudCwgaXQgZmFpbHMgdG8gc2V0IHRoZSByZW1vdGUgZGVzY3JpcHRpb24uXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RSZWNlaXZlci5wcm90b3R5cGUudHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuXG4gICAgaWYgKGRlc2MgJiYgZGVzYy5zZHApIHtcbiAgICAgICAgdmFyIHNiID0gZGVzYy5zZHAuc3BsaXQoJ1xcclxcbicpO1xuXG4gICAgICAgIHRoaXMuX3VwZGF0ZVJlbW90ZU1hcHMoc2IpO1xuICAgICAgICB0aGlzLl9jYWNoZVJlbW90ZVZpZGVvU291cmNlcyhzYik7XG5cbiAgICAgICAgLy8gTk9URShncCkgdGhpcyBuZWVkcyB0byBiZSBjYWxsZWQgYWZ0ZXIgdXBkYXRlUmVtb3RlTWFwcyBiZWNhdXNlIHdlXG4gICAgICAgIC8vIG5lZWQgdGhlIHNpbXVsY2FzdCBncm91cCBpbiB0aGUgX3VwZGF0ZVJlbW90ZU1hcHMoKSBtZXRob2QuXG4gICAgICAgIHRoaXMuc2ltdWxjYXN0VXRpbHMuX3JlbW92ZVNpbXVsY2FzdEdyb3VwKHNiKTtcblxuICAgICAgICBpZiAoZGVzYy5zZHAuaW5kZXhPZignYT1zc3JjLWdyb3VwOlNJTScpICE9PSAtMSkge1xuICAgICAgICAgICAgLy8gV2UgZG9uJ3QgbmVlZCB0aGUgZ29vZyBjb25mZXJlbmNlIGZsYWcgaWYgd2UncmUgbm90IGRvaW5nXG4gICAgICAgICAgICAvLyBzaW11bGNhc3QuXG4gICAgICAgICAgICB0aGlzLl9lbnN1cmVHb29nQ29uZmVyZW5jZShzYik7XG4gICAgICAgIH1cblxuICAgICAgICBkZXNjID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgICAgICB0eXBlOiBkZXNjLnR5cGUsXG4gICAgICAgICAgICBzZHA6IHNiLmpvaW4oJ1xcclxcbicpXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMubG9nZ2VyLmZpbmUoWydUcmFuc2Zvcm1lZCByZW1vdGUgZGVzY3JpcHRpb24nLCBkZXNjLnNkcF0uam9pbignICcpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZGVzYztcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2ltdWxjYXN0UmVjZWl2ZXI7IiwidmFyIFNpbXVsY2FzdExvZ2dlciA9IHJlcXVpcmUoXCIuL1NpbXVsY2FzdExvZ2dlclwiKTtcbnZhciBTaW11bGNhc3RVdGlscyA9IHJlcXVpcmUoXCIuL1NpbXVsY2FzdFV0aWxzXCIpO1xuXG5mdW5jdGlvbiBTaW11bGNhc3RTZW5kZXIoKSB7XG4gICAgdGhpcy5zaW11bGNhc3RVdGlscyA9IG5ldyBTaW11bGNhc3RVdGlscygpO1xuICAgIHRoaXMubG9nZ2VyID0gbmV3IFNpbXVsY2FzdExvZ2dlcignU2ltdWxjYXN0U2VuZGVyJywgMSk7XG59XG5cblNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuZGlzcGxheWVkTG9jYWxWaWRlb1N0cmVhbSA9IG51bGw7XG5cblNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX2dlbmVyYXRlR3VpZCA9IChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gczQoKSB7XG4gICAgICAgIHJldHVybiBNYXRoLmZsb29yKCgxICsgTWF0aC5yYW5kb20oKSkgKiAweDEwMDAwKVxuICAgICAgICAgICAgLnRvU3RyaW5nKDE2KVxuICAgICAgICAgICAgLnN1YnN0cmluZygxKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gczQoKSArIHM0KCkgKyAnLScgKyBzNCgpICsgJy0nICsgczQoKSArICctJyArXG4gICAgICAgICAgICBzNCgpICsgJy0nICsgczQoKSArIHM0KCkgKyBzNCgpO1xuICAgIH07XG59KCkpO1xuXG4vLyBSZXR1cm5zIGEgcmFuZG9tIGludGVnZXIgYmV0d2VlbiBtaW4gKGluY2x1ZGVkKSBhbmQgbWF4IChleGNsdWRlZClcbi8vIFVzaW5nIE1hdGgucm91bmQoKSBnaXZlcyBhIG5vbi11bmlmb3JtIGRpc3RyaWJ1dGlvbiFcblNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX2dlbmVyYXRlUmFuZG9tU1NSQyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgbWluID0gMCwgbWF4ID0gMHhmZmZmZmZmZjtcbiAgICByZXR1cm4gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogKG1heCAtIG1pbikpICsgbWluO1xufTtcblxuU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5nZXRMb2NhbFZpZGVvU3RyZWFtID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAodGhpcy5kaXNwbGF5ZWRMb2NhbFZpZGVvU3RyZWFtICE9IG51bGwpXG4gICAgICAgID8gdGhpcy5kaXNwbGF5ZWRMb2NhbFZpZGVvU3RyZWFtXG4gICAgICAgIC8vIGluIGNhc2Ugd2UgaGF2ZSBubyBzaW11bGNhc3QgYXQgYWxsLCBpLmUuIHdlIGRpZG4ndCBwZXJmb3JtIHRoZSBHVU1cbiAgICAgICAgOiBBUFAuUlRDLmxvY2FsVmlkZW8uZ2V0T3JpZ2luYWxTdHJlYW0oKTtcbn07XG5cbmZ1bmN0aW9uIE5hdGl2ZVNpbXVsY2FzdFNlbmRlcigpIHtcbiAgICBTaW11bGNhc3RTZW5kZXIuY2FsbCh0aGlzKTsgLy8gY2FsbCB0aGUgc3VwZXIgY29uc3RydWN0b3IuXG59XG5cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKFNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUpO1xuXG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLl9sb2NhbEV4cGxvc2lvbk1hcCA9IHt9O1xuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5faXNVc2luZ1NjcmVlblN0cmVhbSA9IGZhbHNlO1xuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fbG9jYWxWaWRlb1NvdXJjZUNhY2hlID0gJyc7XG5cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUucmVzZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5fbG9jYWxFeHBsb3Npb25NYXAgPSB7fTtcbiAgICB0aGlzLl9pc1VzaW5nU2NyZWVuU3RyZWFtID0gQVBQLmRlc2t0b3BzaGFyaW5nLmlzVXNpbmdTY3JlZW5TdHJlYW0oKTtcbn07XG5cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX2NhY2hlTG9jYWxWaWRlb1NvdXJjZXMgPSBmdW5jdGlvbiAobGluZXMpIHtcbiAgICB0aGlzLl9sb2NhbFZpZGVvU291cmNlQ2FjaGUgPSB0aGlzLnNpbXVsY2FzdFV0aWxzLl9nZXRWaWRlb1NvdXJjZXMobGluZXMpO1xufTtcblxuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fcmVzdG9yZUxvY2FsVmlkZW9Tb3VyY2VzID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdGhpcy5zaW11bGNhc3RVdGlscy5fcmVwbGFjZVZpZGVvU291cmNlcyhsaW5lcywgdGhpcy5fbG9jYWxWaWRlb1NvdXJjZUNhY2hlKTtcbn07XG5cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX2FwcGVuZFNpbXVsY2FzdEdyb3VwID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdmFyIHZpZGVvU291cmNlcywgc3NyY0dyb3VwLCBzaW1TU1JDLCBudW1PZlN1YnMgPSAyLCBpLCBzYiwgbXNpZDtcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ0FwcGVuZGluZyBzaW11bGNhc3QgZ3JvdXAuLi4nKTtcblxuICAgIC8vIEdldCB0aGUgcHJpbWFyeSBTU1JDIGluZm9ybWF0aW9uLlxuICAgIHZpZGVvU291cmNlcyA9IHRoaXMuc2ltdWxjYXN0VXRpbHMucGFyc2VNZWRpYShsaW5lcywgWyd2aWRlbyddKVswXTtcblxuICAgIC8vIFN0YXJ0IGJ1aWxkaW5nIHRoZSBTSU0gU1NSQyBncm91cC5cbiAgICBzc3JjR3JvdXAgPSBbJ2E9c3NyYy1ncm91cDpTSU0nXTtcblxuICAgIC8vIFRoZSB2aWRlbyBzb3VyY2UgYnVmZmVyLlxuICAgIHNiID0gW107XG5cbiAgICAvLyBDcmVhdGUgdGhlIHNpbXVsY2FzdCBzdWItc3RyZWFtcy5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbnVtT2ZTdWJzOyBpKyspIHtcbiAgICAgICAgLy8gVE9ETyhncCkgcHJldmVudCBTU1JDIGNvbGxpc2lvbi5cbiAgICAgICAgc2ltU1NSQyA9IHRoaXMuX2dlbmVyYXRlUmFuZG9tU1NSQygpO1xuICAgICAgICBzc3JjR3JvdXAucHVzaChzaW1TU1JDKTtcblxuICAgICAgICBpZiAodmlkZW9Tb3VyY2VzLmJhc2UpIHtcbiAgICAgICAgICAgIHNiLnNwbGljZS5hcHBseShzYiwgW3NiLmxlbmd0aCwgMF0uY29uY2F0KFxuICAgICAgICAgICAgICAgIFtbXCJhPXNzcmM6XCIsIHNpbVNTUkMsIFwiIGNuYW1lOlwiLCB2aWRlb1NvdXJjZXMuYmFzZS5jbmFtZV0uam9pbignJyksXG4gICAgICAgICAgICAgICAgICAgIFtcImE9c3NyYzpcIiwgc2ltU1NSQywgXCIgbXNpZDpcIiwgdmlkZW9Tb3VyY2VzLmJhc2UubXNpZF0uam9pbignJyldXG4gICAgICAgICAgICApKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubG9nZ2VyLmluZm8oWydHZW5lcmF0ZWQgc3Vic3RyZWFtICcsIGksICcgd2l0aCBTU1JDICcsIHNpbVNTUkMsICcuJ10uam9pbignJykpO1xuXG4gICAgfVxuXG4gICAgLy8gQWRkIHRoZSBncm91cCBzaW0gbGF5ZXJzLlxuICAgIHNiLnNwbGljZSgwLCAwLCBzc3JjR3JvdXAuam9pbignICcpKVxuXG4gICAgdGhpcy5zaW11bGNhc3RVdGlscy5fcmVwbGFjZVZpZGVvU291cmNlcyhsaW5lcywgc2IpO1xufTtcblxuLy8gRG9lcyB0aGUgYWN0dWFsIHBhdGNoaW5nLlxuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fZW5zdXJlU2ltdWxjYXN0R3JvdXAgPSBmdW5jdGlvbiAobGluZXMpIHtcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ0Vuc3VyaW5nIHNpbXVsY2FzdCBncm91cC4uLicpO1xuXG4gICAgaWYgKHRoaXMuc2ltdWxjYXN0VXRpbHMuX2luZGV4T2ZBcnJheSgnYT1zc3JjLWdyb3VwOlNJTScsIGxpbmVzKSA9PT0gdGhpcy5zaW11bGNhc3RVdGlscy5fZW1wdHlDb21wb3VuZEluZGV4KSB7XG4gICAgICAgIHRoaXMuX2FwcGVuZFNpbXVsY2FzdEdyb3VwKGxpbmVzKTtcbiAgICAgICAgdGhpcy5fY2FjaGVMb2NhbFZpZGVvU291cmNlcyhsaW5lcyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdmVyaWZ5IHRoYXQgdGhlIHNzcmNzIHBhcnRpY2lwYXRpbmcgaW4gdGhlIFNJTSBncm91cCBhcmUgcHJlc2VudFxuICAgICAgICAvLyBpbiB0aGUgU0RQIChuZWVkZWQgZm9yIHByZXNlbmNlKS5cbiAgICAgICAgdGhpcy5fcmVzdG9yZUxvY2FsVmlkZW9Tb3VyY2VzKGxpbmVzKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIFByb2R1Y2VzIGEgc2luZ2xlIHN0cmVhbSB3aXRoIG11bHRpcGxlIHRyYWNrcyBmb3IgbG9jYWwgdmlkZW8gc291cmNlcy5cbiAqXG4gKiBAcGFyYW0gbGluZXNcbiAqIEBwcml2YXRlXG4gKi9cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX2V4cGxvZGVTaW11bGNhc3RTZW5kZXJTb3VyY2VzID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdmFyIHNiLCBtc2lkLCBzaWQsIHRpZCwgdmlkZW9Tb3VyY2VzLCBzZWxmO1xuXG4gICAgdGhpcy5sb2dnZXIuaW5mbygnRXhwbG9kaW5nIGxvY2FsIHZpZGVvIHNvdXJjZXMuLi4nKTtcblxuICAgIHZpZGVvU291cmNlcyA9IHRoaXMuc2ltdWxjYXN0VXRpbHMucGFyc2VNZWRpYShsaW5lcywgWyd2aWRlbyddKVswXTtcblxuICAgIHNlbGYgPSB0aGlzO1xuICAgIGlmICh2aWRlb1NvdXJjZXMuZ3JvdXBzICYmIHZpZGVvU291cmNlcy5ncm91cHMubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgIHZpZGVvU291cmNlcy5ncm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgIGlmIChncm91cC5zZW1hbnRpY3MgPT09ICdTSU0nKSB7XG4gICAgICAgICAgICAgICAgZ3JvdXAuc3NyY3MuZm9yRWFjaChmdW5jdGlvbiAoc3NyYykge1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIEdldCB0aGUgbXNpZCBmb3IgdGhpcyBzc3JjLi5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHNlbGYuX2xvY2FsRXhwbG9zaW9uTWFwW3NzcmNdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAuLiBlaXRoZXIgZnJvbSB0aGUgZXhwbG9zaW9uIG1hcC4uXG4gICAgICAgICAgICAgICAgICAgICAgICBtc2lkID0gc2VsZi5fbG9jYWxFeHBsb3Npb25NYXBbc3NyY107XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAuLiBvciBnZW5lcmF0ZSBhIG5ldyBvbmUgKG1zaWQpLlxuICAgICAgICAgICAgICAgICAgICAgICAgc2lkID0gdmlkZW9Tb3VyY2VzLnNvdXJjZXNbc3NyY10ubXNpZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5zdWJzdHJpbmcoMCwgdmlkZW9Tb3VyY2VzLnNvdXJjZXNbc3NyY10ubXNpZC5pbmRleE9mKCcgJykpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICB0aWQgPSBzZWxmLl9nZW5lcmF0ZUd1aWQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1zaWQgPSBbc2lkLCB0aWRdLmpvaW4oJyAnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2xvY2FsRXhwbG9zaW9uTWFwW3NzcmNdID0gbXNpZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIEFzc2lnbiBpdCB0byB0aGUgc291cmNlIG9iamVjdC5cbiAgICAgICAgICAgICAgICAgICAgdmlkZW9Tb3VyY2VzLnNvdXJjZXNbc3NyY10ubXNpZCA9IG1zaWQ7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gVE9ETyhncCkgQ2hhbmdlIHRoZSBtc2lkIG9mIGFzc29jaWF0ZWQgc291cmNlcy5cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc2IgPSB0aGlzLnNpbXVsY2FzdFV0aWxzLl9jb21waWxlVmlkZW9Tb3VyY2VzKHZpZGVvU291cmNlcyk7XG5cbiAgICB0aGlzLnNpbXVsY2FzdFV0aWxzLl9yZXBsYWNlVmlkZW9Tb3VyY2VzKGxpbmVzLCBzYik7XG59O1xuXG4vKipcbiAqIEdVTSBmb3Igc2ltdWxjYXN0LlxuICpcbiAqIEBwYXJhbSBjb25zdHJhaW50c1xuICogQHBhcmFtIHN1Y2Nlc3NcbiAqIEBwYXJhbSBlcnJcbiAqL1xuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbiAoY29uc3RyYWludHMsIHN1Y2Nlc3MsIGVycikge1xuXG4gICAgLy8gVGhlcmUncyBub3RoaW5nIHNwZWNpYWwgdG8gZG8gZm9yIG5hdGl2ZSBzaW11bGNhc3QsIHNvIGp1c3QgZG8gYSBub3JtYWwgR1VNLlxuICAgIG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEoY29uc3RyYWludHMsIGZ1bmN0aW9uIChocVN0cmVhbSkge1xuICAgICAgICBzdWNjZXNzKGhxU3RyZWFtKTtcbiAgICB9LCBlcnIpO1xufTtcblxuLyoqXG4gKiBQcmVwYXJlcyB0aGUgbG9jYWwgZGVzY3JpcHRpb24gZm9yIHB1YmxpYyB1c2FnZSAoaS5lLiB0byBiZSBzaWduYWxlZFxuICogdGhyb3VnaCBKaW5nbGUgdG8gdGhlIGZvY3VzKS5cbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMge1JUQ1Nlc3Npb25EZXNjcmlwdGlvbn1cbiAqL1xuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5yZXZlcnNlVHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgdmFyIHNiO1xuXG4gICAgaWYgKCF0aGlzLnNpbXVsY2FzdFV0aWxzLmlzVmFsaWREZXNjcmlwdGlvbihkZXNjKSB8fCB0aGlzLl9pc1VzaW5nU2NyZWVuU3RyZWFtKSB7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuXG4gICAgc2IgPSBkZXNjLnNkcC5zcGxpdCgnXFxyXFxuJyk7XG5cbiAgICB0aGlzLl9leHBsb2RlU2ltdWxjYXN0U2VuZGVyU291cmNlcyhzYik7XG5cbiAgICBkZXNjID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgIHR5cGU6IGRlc2MudHlwZSxcbiAgICAgICAgc2RwOiBzYi5qb2luKCdcXHJcXG4nKVxuICAgIH0pO1xuXG4gICAgdGhpcy5sb2dnZXIuZmluZShbJ0V4cGxvZGVkIGxvY2FsIHZpZGVvIHNvdXJjZXMnLCBkZXNjLnNkcF0uam9pbignICcpKTtcblxuICAgIHJldHVybiBkZXNjO1xufTtcblxuLyoqXG4gKiBFbnN1cmVzIHRoYXQgdGhlIHNpbXVsY2FzdCBncm91cCBpcyBwcmVzZW50IGluIHRoZSBhbnN3ZXIsIF9pZl8gbmF0aXZlXG4gKiBzaW11bGNhc3QgaXMgZW5hYmxlZCxcbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUudHJhbnNmb3JtQW5zd2VyID0gZnVuY3Rpb24gKGRlc2MpIHtcblxuICAgIGlmICghdGhpcy5zaW11bGNhc3RVdGlscy5pc1ZhbGlkRGVzY3JpcHRpb24oZGVzYykgfHwgdGhpcy5faXNVc2luZ1NjcmVlblN0cmVhbSkge1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICB2YXIgc2IgPSBkZXNjLnNkcC5zcGxpdCgnXFxyXFxuJyk7XG5cbiAgICAvLyBFdmVuIGlmIHdlIGhhdmUgZW5hYmxlZCBuYXRpdmUgc2ltdWxjYXN0aW5nIHByZXZpb3VzbHlcbiAgICAvLyAod2l0aCBhIGNhbGwgdG8gU0xEIHdpdGggYW4gYXBwcm9wcmlhdGUgU0RQLCBmb3IgZXhhbXBsZSksXG4gICAgLy8gY3JlYXRlQW5zd2VyIHNlZW1zIHRvIGNvbnNpc3RlbnRseSBnZW5lcmF0ZSBpbmNvbXBsZXRlIFNEUFxuICAgIC8vIHdpdGggbWlzc2luZyBTU1JDUy5cbiAgICAvL1xuICAgIC8vIFNvLCBzdWJzZXF1ZW50IGNhbGxzIHRvIFNMRCB3aWxsIGhhdmUgbWlzc2luZyBTU1JDUyBhbmQgcHJlc2VuY2VcbiAgICAvLyB3b24ndCBoYXZlIHRoZSBjb21wbGV0ZSBsaXN0IG9mIFNSQ3MuXG4gICAgdGhpcy5fZW5zdXJlU2ltdWxjYXN0R3JvdXAoc2IpO1xuXG4gICAgZGVzYyA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICB0eXBlOiBkZXNjLnR5cGUsXG4gICAgICAgIHNkcDogc2Iuam9pbignXFxyXFxuJylcbiAgICB9KTtcblxuICAgIHRoaXMubG9nZ2VyLmZpbmUoWydUcmFuc2Zvcm1lZCBhbnN3ZXInLCBkZXNjLnNkcF0uam9pbignICcpKTtcblxuICAgIHJldHVybiBkZXNjO1xufTtcblxuXG4vKipcbiAqXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLnRyYW5zZm9ybUxvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiBkZXNjO1xufTtcblxuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fc2V0TG9jYWxWaWRlb1N0cmVhbUVuYWJsZWQgPSBmdW5jdGlvbiAoc3NyYywgZW5hYmxlZCkge1xuICAgIC8vIE5vdGhpbmcgdG8gZG8gaGVyZSwgbmF0aXZlIHNpbXVsY2FzdCBkb2VzIHRoYXQgYXV0by1tYWdpY2FsbHkuXG59O1xuXG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gTmF0aXZlU2ltdWxjYXN0U2VuZGVyO1xuXG5mdW5jdGlvbiBTaW1wbGVTaW11bGNhc3RTZW5kZXIoKSB7XG4gICAgU2ltdWxjYXN0U2VuZGVyLmNhbGwodGhpcyk7XG59XG5cblNpbXBsZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKFNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUpO1xuXG5TaW1wbGVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLmxvY2FsU3RyZWFtID0gbnVsbDtcblNpbXBsZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX2xvY2FsTWFwcyA9IHtcbiAgICBtc2lkczogW10sXG4gICAgbXNpZDJzc3JjOiB7fVxufTtcblxuLyoqXG4gKiBHcm91cHMgbG9jYWwgdmlkZW8gc291cmNlcyB0b2dldGhlciBpbiB0aGUgc3NyYy1ncm91cDpTSU0gZ3JvdXAuXG4gKlxuICogQHBhcmFtIGxpbmVzXG4gKiBAcHJpdmF0ZVxuICovXG5TaW1wbGVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLl9ncm91cExvY2FsVmlkZW9Tb3VyY2VzID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdmFyIHNiLCB2aWRlb1NvdXJjZXMsIHNzcmNzID0gW10sIHNzcmM7XG5cbiAgICB0aGlzLmxvZ2dlci5pbmZvKCdHcm91cGluZyBsb2NhbCB2aWRlbyBzb3VyY2VzLi4uJyk7XG5cbiAgICB2aWRlb1NvdXJjZXMgPSB0aGlzLnNpbXVsY2FzdFV0aWxzLnBhcnNlTWVkaWEobGluZXMsIFsndmlkZW8nXSlbMF07XG5cbiAgICBmb3IgKHNzcmMgaW4gdmlkZW9Tb3VyY2VzLnNvdXJjZXMpIHtcbiAgICAgICAgLy8gaml0c2ktbWVldCBkZXN0cm95cy9jcmVhdGVzIHN0cmVhbXMgYXQgdmFyaW91cyBwbGFjZXMgY2F1c2luZ1xuICAgICAgICAvLyB0aGUgb3JpZ2luYWwgbG9jYWwgc3RyZWFtIGlkcyB0byBjaGFuZ2UuIFRoZSBvbmx5IHRoaW5nIHRoYXRcbiAgICAgICAgLy8gcmVtYWlucyB1bmNoYW5nZWQgaXMgdGhlIHRyYWNraWQuXG4gICAgICAgIHRoaXMuX2xvY2FsTWFwcy5tc2lkMnNzcmNbdmlkZW9Tb3VyY2VzLnNvdXJjZXNbc3NyY10ubXNpZC5zcGxpdCgnICcpWzFdXSA9IHNzcmM7XG4gICAgfVxuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIC8vIFRPRE8oZ3ApIGFkZCBvbmx5IFwiZnJlZVwiIHNvdXJjZXMuXG4gICAgdGhpcy5fbG9jYWxNYXBzLm1zaWRzLmZvckVhY2goZnVuY3Rpb24gKG1zaWQpIHtcbiAgICAgICAgc3NyY3MucHVzaChzZWxmLl9sb2NhbE1hcHMubXNpZDJzc3JjW21zaWRdKTtcbiAgICB9KTtcblxuICAgIGlmICghdmlkZW9Tb3VyY2VzLmdyb3Vwcykge1xuICAgICAgICB2aWRlb1NvdXJjZXMuZ3JvdXBzID0gW107XG4gICAgfVxuXG4gICAgdmlkZW9Tb3VyY2VzLmdyb3Vwcy5wdXNoKHtcbiAgICAgICAgJ3NlbWFudGljcyc6ICdTSU0nLFxuICAgICAgICAnc3NyY3MnOiBzc3Jjc1xuICAgIH0pO1xuXG4gICAgc2IgPSB0aGlzLnNpbXVsY2FzdFV0aWxzLl9jb21waWxlVmlkZW9Tb3VyY2VzKHZpZGVvU291cmNlcyk7XG5cbiAgICB0aGlzLnNpbXVsY2FzdFV0aWxzLl9yZXBsYWNlVmlkZW9Tb3VyY2VzKGxpbmVzLCBzYik7XG59O1xuXG4vKipcbiAqIEdVTSBmb3Igc2ltdWxjYXN0LlxuICpcbiAqIEBwYXJhbSBjb25zdHJhaW50c1xuICogQHBhcmFtIHN1Y2Nlc3NcbiAqIEBwYXJhbSBlcnJcbiAqL1xuU2ltcGxlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbiAoY29uc3RyYWludHMsIHN1Y2Nlc3MsIGVycikge1xuXG4gICAgLy8gVE9ETyhncCkgd2hhdCBpZiB3ZSByZXF1ZXN0IGEgcmVzb2x1dGlvbiBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBoYXJkd2FyZT9cbiAgICAvLyBUT0RPKGdwKSBtYWtlIHRoZSBscSBzdHJlYW0gY29uZmlndXJhYmxlOyBhbHRob3VnaCB0aGlzIHdvdWxkbid0IHdvcmsgd2l0aCBuYXRpdmUgc2ltdWxjYXN0XG4gICAgdmFyIGxxQ29uc3RyYWludHMgPSB7XG4gICAgICAgIGF1ZGlvOiBmYWxzZSxcbiAgICAgICAgdmlkZW86IHtcbiAgICAgICAgICAgIG1hbmRhdG9yeToge1xuICAgICAgICAgICAgICAgIG1heFdpZHRoOiAzMjAsXG4gICAgICAgICAgICAgICAgbWF4SGVpZ2h0OiAxODAsXG4gICAgICAgICAgICAgICAgbWF4RnJhbWVSYXRlOiAxNVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ0hRIGNvbnN0cmFpbnRzOiAnLCBjb25zdHJhaW50cyk7XG4gICAgdGhpcy5sb2dnZXIuaW5mbygnTFEgY29uc3RyYWludHM6ICcsIGxxQ29uc3RyYWludHMpO1xuXG5cbiAgICAvLyBOT1RFKGdwKSBpZiB3ZSByZXF1ZXN0IHRoZSBscSBzdHJlYW0gZmlyc3Qgd2Via2l0R2V0VXNlck1lZGlhXG4gICAgLy8gZmFpbHMgcmFuZG9tbHkuIFRlc3RlZCB3aXRoIENocm9tZSAzNy4gQXMgZmlwcG8gc3VnZ2VzdGVkLCB0aGVcbiAgICAvLyByZWFzb24gYXBwZWFycyB0byBiZSB0aGF0IENocm9tZSBvbmx5IGFjcXVpcmVzIHRoZSBjYW0gb25jZSBhbmRcbiAgICAvLyB0aGVuIGRvd25zY2FsZXMgdGhlIHBpY3R1cmUgKGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0zNDY2MTYjYzExKVxuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEoY29uc3RyYWludHMsIGZ1bmN0aW9uIChocVN0cmVhbSkge1xuXG4gICAgICAgIHNlbGYubG9jYWxTdHJlYW0gPSBocVN0cmVhbTtcblxuICAgICAgICAvLyByZXNldCBsb2NhbCBtYXBzLlxuICAgICAgICBzZWxmLl9sb2NhbE1hcHMubXNpZHMgPSBbXTtcbiAgICAgICAgc2VsZi5fbG9jYWxNYXBzLm1zaWQyc3NyYyA9IHt9O1xuXG4gICAgICAgIC8vIGFkZCBocSB0cmFja2lkIHRvIGxvY2FsIG1hcFxuICAgICAgICBzZWxmLl9sb2NhbE1hcHMubXNpZHMucHVzaChocVN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdLmlkKTtcblxuICAgICAgICBuYXZpZ2F0b3Iud2Via2l0R2V0VXNlck1lZGlhKGxxQ29uc3RyYWludHMsIGZ1bmN0aW9uIChscVN0cmVhbSkge1xuXG4gICAgICAgICAgICBzZWxmLmRpc3BsYXllZExvY2FsVmlkZW9TdHJlYW0gPSBscVN0cmVhbTtcblxuICAgICAgICAgICAgLy8gTk9URShncCkgVGhlIHNwZWNpZmljYXRpb24gc2F5cyBBcnJheS5mb3JFYWNoKCkgd2lsbCB2aXNpdFxuICAgICAgICAgICAgLy8gdGhlIGFycmF5IGVsZW1lbnRzIGluIG51bWVyaWMgb3JkZXIsIGFuZCB0aGF0IGl0IGRvZXNuJ3RcbiAgICAgICAgICAgIC8vIHZpc2l0IGVsZW1lbnRzIHRoYXQgZG9uJ3QgZXhpc3QuXG5cbiAgICAgICAgICAgIC8vIGFkZCBscSB0cmFja2lkIHRvIGxvY2FsIG1hcFxuICAgICAgICAgICAgc2VsZi5fbG9jYWxNYXBzLm1zaWRzLnNwbGljZSgwLCAwLCBscVN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdLmlkKTtcblxuICAgICAgICAgICAgc2VsZi5sb2NhbFN0cmVhbS5hZGRUcmFjayhscVN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdKTtcbiAgICAgICAgICAgIHN1Y2Nlc3Moc2VsZi5sb2NhbFN0cmVhbSk7XG4gICAgICAgIH0sIGVycik7XG4gICAgfSwgZXJyKTtcbn07XG5cbi8qKlxuICogUHJlcGFyZXMgdGhlIGxvY2FsIGRlc2NyaXB0aW9uIGZvciBwdWJsaWMgdXNhZ2UgKGkuZS4gdG8gYmUgc2lnbmFsZWRcbiAqIHRocm91Z2ggSmluZ2xlIHRvIHRoZSBmb2N1cykuXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHtSVENTZXNzaW9uRGVzY3JpcHRpb259XG4gKi9cblNpbXBsZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUucmV2ZXJzZVRyYW5zZm9ybUxvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHZhciBzYjtcblxuICAgIGlmICghdGhpcy5zaW11bGNhc3RVdGlscy5pc1ZhbGlkRGVzY3JpcHRpb24oZGVzYykpIHtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgc2IgPSBkZXNjLnNkcC5zcGxpdCgnXFxyXFxuJyk7XG5cbiAgICB0aGlzLl9ncm91cExvY2FsVmlkZW9Tb3VyY2VzKHNiKTtcblxuICAgIGRlc2MgPSBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgdHlwZTogZGVzYy50eXBlLFxuICAgICAgICBzZHA6IHNiLmpvaW4oJ1xcclxcbicpXG4gICAgfSk7XG5cbiAgICB0aGlzLmxvZ2dlci5maW5lKCdHcm91cGVkIGxvY2FsIHZpZGVvIHNvdXJjZXMnKTtcbiAgICB0aGlzLmxvZ2dlci5maW5lKGRlc2Muc2RwKTtcblxuICAgIHJldHVybiBkZXNjO1xufTtcblxuLyoqXG4gKiBFbnN1cmVzIHRoYXQgdGhlIHNpbXVsY2FzdCBncm91cCBpcyBwcmVzZW50IGluIHRoZSBhbnN3ZXIsIF9pZl8gbmF0aXZlXG4gKiBzaW11bGNhc3QgaXMgZW5hYmxlZCxcbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cblNpbXBsZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUudHJhbnNmb3JtQW5zd2VyID0gZnVuY3Rpb24gKGRlc2MpIHtcbiAgICByZXR1cm4gZGVzYztcbn07XG5cblxuLyoqXG4gKlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuU2ltcGxlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS50cmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uID0gZnVuY3Rpb24gKGRlc2MpIHtcblxuICAgIHZhciBzYiA9IGRlc2Muc2RwLnNwbGl0KCdcXHJcXG4nKTtcblxuICAgIHRoaXMuc2ltdWxjYXN0VXRpbHMuX3JlbW92ZVNpbXVsY2FzdEdyb3VwKHNiKTtcblxuICAgIGRlc2MgPSBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgdHlwZTogZGVzYy50eXBlLFxuICAgICAgICBzZHA6IHNiLmpvaW4oJ1xcclxcbicpXG4gICAgfSk7XG5cbiAgICB0aGlzLmxvZ2dlci5maW5lKCdUcmFuc2Zvcm1lZCBsb2NhbCBkZXNjcmlwdGlvbicpO1xuICAgIHRoaXMubG9nZ2VyLmZpbmUoZGVzYy5zZHApO1xuXG4gICAgcmV0dXJuIGRlc2M7XG59O1xuXG5TaW1wbGVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLl9zZXRMb2NhbFZpZGVvU3RyZWFtRW5hYmxlZCA9IGZ1bmN0aW9uIChzc3JjLCBlbmFibGVkKSB7XG4gICAgdmFyIHRyYWNraWQ7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5sb2dnZXIubG9nKFsnUmVxdWVzdGVkIHRvJywgZW5hYmxlZCA/ICdlbmFibGUnIDogJ2Rpc2FibGUnLCBzc3JjXS5qb2luKCcgJykpO1xuICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLl9sb2NhbE1hcHMubXNpZDJzc3JjKS5zb21lKGZ1bmN0aW9uICh0aWQpIHtcbiAgICAgICAgLy8gU2VhcmNoIGZvciB0aGUgdHJhY2sgaWQgdGhhdCBjb3JyZXNwb25kcyB0byB0aGUgc3NyY1xuICAgICAgICBpZiAoc2VsZi5fbG9jYWxNYXBzLm1zaWQyc3NyY1t0aWRdID09IHNzcmMpIHtcbiAgICAgICAgICAgIHRyYWNraWQgPSB0aWQ7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH0pICYmIHNlbGYubG9jYWxTdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5zb21lKGZ1bmN0aW9uICh0cmFjaykge1xuICAgICAgICAvLyBTdGFydC9zdG9wIHRoZSB0cmFjayB0aGF0IGNvcnJlc3BvbmRzIHRvIHRoZSB0cmFjayBpZFxuICAgICAgICBpZiAodHJhY2suaWQgPT09IHRyYWNraWQpIHtcbiAgICAgICAgICAgIHRyYWNrLmVuYWJsZWQgPSBlbmFibGVkO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9KSkge1xuICAgICAgICB0aGlzLmxvZ2dlci5sb2coW3RyYWNraWQsIGVuYWJsZWQgPyAnZW5hYmxlZCcgOiAnZGlzYWJsZWQnXS5qb2luKCcgJykpO1xuICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKGVuYWJsZWRcbiAgICAgICAgICAgID8gJ3NpbXVsY2FzdGxheWVyc3RhcnRlZCdcbiAgICAgICAgICAgIDogJ3NpbXVsY2FzdGxheWVyc3RvcHBlZCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFwiSSBkb24ndCBoYXZlIGEgbG9jYWwgc3RyZWFtIHdpdGggU1NSQyBcIiArIHNzcmMpO1xuICAgIH1cbn07XG5cblNpbXBsZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTaW1wbGVTaW11bGNhc3RTZW5kZXI7XG5cbmZ1bmN0aW9uIE5vU2ltdWxjYXN0U2VuZGVyKCkge1xuICAgIFNpbXVsY2FzdFNlbmRlci5jYWxsKHRoaXMpO1xufVxuXG5Ob1NpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKFNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUpO1xuXG4vKipcbiAqIEdVTSBmb3Igc2ltdWxjYXN0LlxuICpcbiAqIEBwYXJhbSBjb25zdHJhaW50c1xuICogQHBhcmFtIHN1Y2Nlc3NcbiAqIEBwYXJhbSBlcnJcbiAqL1xuTm9TaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uIChjb25zdHJhaW50cywgc3VjY2VzcywgZXJyKSB7XG4gICAgbmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYShjb25zdHJhaW50cywgZnVuY3Rpb24gKGhxU3RyZWFtKSB7XG4gICAgICAgIHN1Y2Nlc3MoaHFTdHJlYW0pO1xuICAgIH0sIGVycik7XG59O1xuXG4vKipcbiAqIFByZXBhcmVzIHRoZSBsb2NhbCBkZXNjcmlwdGlvbiBmb3IgcHVibGljIHVzYWdlIChpLmUuIHRvIGJlIHNpZ25hbGVkXG4gKiB0aHJvdWdoIEppbmdsZSB0byB0aGUgZm9jdXMpLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7UlRDU2Vzc2lvbkRlc2NyaXB0aW9ufVxuICovXG5Ob1NpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUucmV2ZXJzZVRyYW5zZm9ybUxvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiBkZXNjO1xufTtcblxuLyoqXG4gKiBFbnN1cmVzIHRoYXQgdGhlIHNpbXVsY2FzdCBncm91cCBpcyBwcmVzZW50IGluIHRoZSBhbnN3ZXIsIF9pZl8gbmF0aXZlXG4gKiBzaW11bGNhc3QgaXMgZW5hYmxlZCxcbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cbk5vU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS50cmFuc2Zvcm1BbnN3ZXIgPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiBkZXNjO1xufTtcblxuXG4vKipcbiAqXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5Ob1NpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUudHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgcmV0dXJuIGRlc2M7XG59O1xuXG5Ob1NpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX3NldExvY2FsVmlkZW9TdHJlYW1FbmFibGVkID0gZnVuY3Rpb24gKHNzcmMsIGVuYWJsZWQpIHtcblxufTtcblxuTm9TaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gTm9TaW11bGNhc3RTZW5kZXI7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIFwibmF0aXZlXCI6IE5hdGl2ZVNpbXVsY2FzdFNlbmRlcixcbiAgICBcIm5vXCI6IE5vU2ltdWxjYXN0U2VuZGVyXG59XG4iLCJ2YXIgU2ltdWxjYXN0TG9nZ2VyID0gcmVxdWlyZShcIi4vU2ltdWxjYXN0TG9nZ2VyXCIpO1xuXG4vKipcbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZnVuY3Rpb24gU2ltdWxjYXN0VXRpbHMoKSB7XG4gICAgdGhpcy5sb2dnZXIgPSBuZXcgU2ltdWxjYXN0TG9nZ2VyKFwiU2ltdWxjYXN0VXRpbHNcIiwgMSk7XG59XG5cbi8qKlxuICpcbiAqIEB0eXBlIHt7fX1cbiAqIEBwcml2YXRlXG4gKi9cblNpbXVsY2FzdFV0aWxzLnByb3RvdHlwZS5fZW1wdHlDb21wb3VuZEluZGV4ID0ge307XG5cbi8qKlxuICpcbiAqIEBwYXJhbSBsaW5lc1xuICogQHBhcmFtIHZpZGVvU291cmNlc1xuICogQHByaXZhdGVcbiAqL1xuU2ltdWxjYXN0VXRpbHMucHJvdG90eXBlLl9yZXBsYWNlVmlkZW9Tb3VyY2VzID0gZnVuY3Rpb24gKGxpbmVzLCB2aWRlb1NvdXJjZXMpIHtcbiAgICB2YXIgaSwgaW5WaWRlbyA9IGZhbHNlLCBpbmRleCA9IC0xLCBob3dNYW55ID0gMDtcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ1JlcGxhY2luZyB2aWRlbyBzb3VyY2VzLi4uJyk7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKGluVmlkZW8gJiYgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdtPScubGVuZ3RoKSA9PT0gJ209Jykge1xuICAgICAgICAgICAgLy8gT3V0IG9mIHZpZGVvLlxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWluVmlkZW8gJiYgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdtPXZpZGVvICcubGVuZ3RoKSA9PT0gJ209dmlkZW8gJykge1xuICAgICAgICAgICAgLy8gSW4gdmlkZW8uXG4gICAgICAgICAgICBpblZpZGVvID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpblZpZGVvICYmIChsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ2E9c3NyYzonLmxlbmd0aCkgPT09ICdhPXNzcmM6J1xuICAgICAgICAgICAgfHwgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdhPXNzcmMtZ3JvdXA6Jy5sZW5ndGgpID09PSAnYT1zc3JjLWdyb3VwOicpKSB7XG5cbiAgICAgICAgICAgIGlmIChpbmRleCA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICBpbmRleCA9IGk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGhvd01hbnkrKztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vICBlZmZpY2llbmN5IGJhYnkgOylcbiAgICBsaW5lcy5zcGxpY2UuYXBwbHkobGluZXMsXG4gICAgICAgIFtpbmRleCwgaG93TWFueV0uY29uY2F0KHZpZGVvU291cmNlcykpO1xuXG59O1xuXG5TaW11bGNhc3RVdGlscy5wcm90b3R5cGUuaXNWYWxpZERlc2NyaXB0aW9uID0gZnVuY3Rpb24gKGRlc2MpXG57XG4gICAgcmV0dXJuIGRlc2MgJiYgZGVzYyAhPSBudWxsXG4gICAgICAgICYmIGRlc2MudHlwZSAmJiBkZXNjLnR5cGUgIT0gJydcbiAgICAgICAgJiYgZGVzYy5zZHAgJiYgZGVzYy5zZHAgIT0gJyc7XG59O1xuXG5TaW11bGNhc3RVdGlscy5wcm90b3R5cGUuX2dldFZpZGVvU291cmNlcyA9IGZ1bmN0aW9uIChsaW5lcykge1xuICAgIHZhciBpLCBpblZpZGVvID0gZmFsc2UsIHNiID0gW107XG5cbiAgICB0aGlzLmxvZ2dlci5pbmZvKCdHZXR0aW5nIHZpZGVvIHNvdXJjZXMuLi4nKTtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoaW5WaWRlbyAmJiBsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ209Jy5sZW5ndGgpID09PSAnbT0nKSB7XG4gICAgICAgICAgICAvLyBPdXQgb2YgdmlkZW8uXG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaW5WaWRlbyAmJiBsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ209dmlkZW8gJy5sZW5ndGgpID09PSAnbT12aWRlbyAnKSB7XG4gICAgICAgICAgICAvLyBJbiB2aWRlby5cbiAgICAgICAgICAgIGluVmlkZW8gPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGluVmlkZW8gJiYgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdhPXNzcmM6Jy5sZW5ndGgpID09PSAnYT1zc3JjOicpIHtcbiAgICAgICAgICAgIC8vIEluIFNTUkMuXG4gICAgICAgICAgICBzYi5wdXNoKGxpbmVzW2ldKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpblZpZGVvICYmIGxpbmVzW2ldLnN1YnN0cmluZygwLCAnYT1zc3JjLWdyb3VwOicubGVuZ3RoKSA9PT0gJ2E9c3NyYy1ncm91cDonKSB7XG4gICAgICAgICAgICBzYi5wdXNoKGxpbmVzW2ldKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBzYjtcbn07XG5cblNpbXVsY2FzdFV0aWxzLnByb3RvdHlwZS5wYXJzZU1lZGlhID0gZnVuY3Rpb24gKGxpbmVzLCBtZWRpYXR5cGVzKSB7XG4gICAgdmFyIGksIHJlcyA9IFtdLCB0eXBlLCBjdXJfbWVkaWEsIGlkeCwgc3NyY3MsIGN1cl9zc3JjLCBzc3JjLFxuICAgICAgICBzc3JjX2F0dHJpYnV0ZSwgZ3JvdXAsIHNlbWFudGljcywgc2tpcCA9IHRydWU7XG5cbiAgICB0aGlzLmxvZ2dlci5pbmZvKCdQYXJzaW5nIG1lZGlhIHNvdXJjZXMuLi4nKTtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAobGluZXNbaV0uc3Vic3RyaW5nKDAsICdtPScubGVuZ3RoKSA9PT0gJ209Jykge1xuXG4gICAgICAgICAgICB0eXBlID0gbGluZXNbaV1cbiAgICAgICAgICAgICAgICAuc3Vic3RyKCdtPScubGVuZ3RoLCBsaW5lc1tpXS5pbmRleE9mKCcgJykgLSAnbT0nLmxlbmd0aCk7XG4gICAgICAgICAgICBza2lwID0gbWVkaWF0eXBlcyAhPT0gdW5kZWZpbmVkICYmIG1lZGlhdHlwZXMuaW5kZXhPZih0eXBlKSA9PT0gLTE7XG5cbiAgICAgICAgICAgIGlmICghc2tpcCkge1xuICAgICAgICAgICAgICAgIGN1cl9tZWRpYSA9IHtcbiAgICAgICAgICAgICAgICAgICAgJ3R5cGUnOiB0eXBlLFxuICAgICAgICAgICAgICAgICAgICAnc291cmNlcyc6IHt9LFxuICAgICAgICAgICAgICAgICAgICAnZ3JvdXBzJzogW11cbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgcmVzLnB1c2goY3VyX21lZGlhKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9IGVsc2UgaWYgKCFza2lwICYmIGxpbmVzW2ldLnN1YnN0cmluZygwLCAnYT1zc3JjOicubGVuZ3RoKSA9PT0gJ2E9c3NyYzonKSB7XG5cbiAgICAgICAgICAgIGlkeCA9IGxpbmVzW2ldLmluZGV4T2YoJyAnKTtcbiAgICAgICAgICAgIHNzcmMgPSBsaW5lc1tpXS5zdWJzdHJpbmcoJ2E9c3NyYzonLmxlbmd0aCwgaWR4KTtcbiAgICAgICAgICAgIGlmIChjdXJfbWVkaWEuc291cmNlc1tzc3JjXSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgY3VyX3NzcmMgPSB7J3NzcmMnOiBzc3JjfTtcbiAgICAgICAgICAgICAgICBjdXJfbWVkaWEuc291cmNlc1tzc3JjXSA9IGN1cl9zc3JjO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzc3JjX2F0dHJpYnV0ZSA9IGxpbmVzW2ldLnN1YnN0cihpZHggKyAxKS5zcGxpdCgnOicsIDIpWzBdO1xuICAgICAgICAgICAgY3VyX3NzcmNbc3NyY19hdHRyaWJ1dGVdID0gbGluZXNbaV0uc3Vic3RyKGlkeCArIDEpLnNwbGl0KCc6JywgMilbMV07XG5cbiAgICAgICAgICAgIGlmIChjdXJfbWVkaWEuYmFzZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgY3VyX21lZGlhLmJhc2UgPSBjdXJfc3NyYztcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9IGVsc2UgaWYgKCFza2lwICYmIGxpbmVzW2ldLnN1YnN0cmluZygwLCAnYT1zc3JjLWdyb3VwOicubGVuZ3RoKSA9PT0gJ2E9c3NyYy1ncm91cDonKSB7XG4gICAgICAgICAgICBpZHggPSBsaW5lc1tpXS5pbmRleE9mKCcgJyk7XG4gICAgICAgICAgICBzZW1hbnRpY3MgPSBsaW5lc1tpXS5zdWJzdHIoMCwgaWR4KS5zdWJzdHIoJ2E9c3NyYy1ncm91cDonLmxlbmd0aCk7XG4gICAgICAgICAgICBzc3JjcyA9IGxpbmVzW2ldLnN1YnN0cihpZHgpLnRyaW0oKS5zcGxpdCgnICcpO1xuICAgICAgICAgICAgZ3JvdXAgPSB7XG4gICAgICAgICAgICAgICAgJ3NlbWFudGljcyc6IHNlbWFudGljcyxcbiAgICAgICAgICAgICAgICAnc3NyY3MnOiBzc3Jjc1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGN1cl9tZWRpYS5ncm91cHMucHVzaChncm91cCk7XG4gICAgICAgIH0gZWxzZSBpZiAoIXNraXAgJiYgKGxpbmVzW2ldLnN1YnN0cmluZygwLCAnYT1zZW5kcmVjdicubGVuZ3RoKSA9PT0gJ2E9c2VuZHJlY3YnIHx8XG4gICAgICAgICAgICBsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ2E9cmVjdm9ubHknLmxlbmd0aCkgPT09ICdhPXJlY3Zvbmx5JyB8fFxuICAgICAgICAgICAgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdhPXNlbmRvbmx5Jy5sZW5ndGgpID09PSAnYT1zZW5kb25seScgfHxcbiAgICAgICAgICAgIGxpbmVzW2ldLnN1YnN0cmluZygwLCAnYT1pbmFjdGl2ZScubGVuZ3RoKSA9PT0gJ2E9aW5hY3RpdmUnKSkge1xuXG4gICAgICAgICAgICBjdXJfbWVkaWEuZGlyZWN0aW9uID0gbGluZXNbaV0uc3Vic3RyaW5nKCdhPScubGVuZ3RoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59O1xuXG4vKipcbiAqIFRoZSBfaW5kZXhPZkFycmF5KCkgbWV0aG9kIHJldHVybnMgdGhlIGZpcnN0IGEgQ29tcG91bmRJbmRleCBhdCB3aGljaCBhXG4gKiBnaXZlbiBlbGVtZW50IGNhbiBiZSBmb3VuZCBpbiB0aGUgYXJyYXksIG9yIF9lbXB0eUNvbXBvdW5kSW5kZXggaWYgaXQgaXNcbiAqIG5vdCBwcmVzZW50LlxuICpcbiAqIEV4YW1wbGU6XG4gKlxuICogX2luZGV4T2ZBcnJheSgnMycsIFsgJ3RoaXMgaXMgbGluZSAxJywgJ3RoaXMgaXMgbGluZSAyJywgJ3RoaXMgaXMgbGluZSAzJyBdKVxuICpcbiAqIHJldHVybnMge3JvdzogMiwgY29sdW1uOiAxNH1cbiAqXG4gKiBAcGFyYW0gbmVlZGxlXG4gKiBAcGFyYW0gaGF5c3RhY2tcbiAqIEBwYXJhbSBzdGFydFxuICogQHJldHVybnMge31cbiAqIEBwcml2YXRlXG4gKi9cblNpbXVsY2FzdFV0aWxzLnByb3RvdHlwZS5faW5kZXhPZkFycmF5ID0gZnVuY3Rpb24gKG5lZWRsZSwgaGF5c3RhY2ssIHN0YXJ0KSB7XG4gICAgdmFyIGxlbmd0aCA9IGhheXN0YWNrLmxlbmd0aCwgaWR4LCBpO1xuXG4gICAgaWYgKCFzdGFydCkge1xuICAgICAgICBzdGFydCA9IDA7XG4gICAgfVxuXG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICBpZHggPSBoYXlzdGFja1tpXS5pbmRleE9mKG5lZWRsZSk7XG4gICAgICAgIGlmIChpZHggIT09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4ge3JvdzogaSwgY29sdW1uOiBpZHh9O1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9lbXB0eUNvbXBvdW5kSW5kZXg7XG59O1xuXG5TaW11bGNhc3RVdGlscy5wcm90b3R5cGUuX3JlbW92ZVNpbXVsY2FzdEdyb3VwID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdmFyIGk7XG5cbiAgICBmb3IgKGkgPSBsaW5lcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICBpZiAobGluZXNbaV0uaW5kZXhPZignYT1zc3JjLWdyb3VwOlNJTScpICE9PSAtMSkge1xuICAgICAgICAgICAgbGluZXMuc3BsaWNlKGksIDEpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuU2ltdWxjYXN0VXRpbHMucHJvdG90eXBlLl9jb21waWxlVmlkZW9Tb3VyY2VzID0gZnVuY3Rpb24gKHZpZGVvU291cmNlcykge1xuICAgIHZhciBzYiA9IFtdLCBzc3JjLCBhZGRlZFNTUkNzID0gW107XG5cbiAgICB0aGlzLmxvZ2dlci5pbmZvKCdDb21waWxpbmcgdmlkZW8gc291cmNlcy4uLicpO1xuXG4gICAgLy8gQWRkIHRoZSBncm91cHNcbiAgICBpZiAodmlkZW9Tb3VyY2VzLmdyb3VwcyAmJiB2aWRlb1NvdXJjZXMuZ3JvdXBzLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICB2aWRlb1NvdXJjZXMuZ3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICBpZiAoZ3JvdXAuc3NyY3MgJiYgZ3JvdXAuc3NyY3MubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgc2IucHVzaChbWydhPXNzcmMtZ3JvdXA6JywgZ3JvdXAuc2VtYW50aWNzXS5qb2luKCcnKSwgZ3JvdXAuc3NyY3Muam9pbignICcpXS5qb2luKCcgJykpO1xuXG4gICAgICAgICAgICAgICAgLy8gaWYgKGdyb3VwLnNlbWFudGljcyAhPT0gJ1NJTScpIHtcbiAgICAgICAgICAgICAgICBncm91cC5zc3Jjcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgIGFkZGVkU1NSQ3MucHVzaChzc3JjKTtcbiAgICAgICAgICAgICAgICAgICAgc2Iuc3BsaWNlLmFwcGx5KHNiLCBbc2IubGVuZ3RoLCAwXS5jb25jYXQoW1xuICAgICAgICAgICAgICAgICAgICAgICAgW1wiYT1zc3JjOlwiLCBzc3JjLCBcIiBjbmFtZTpcIiwgdmlkZW9Tb3VyY2VzLnNvdXJjZXNbc3NyY10uY25hbWVdLmpvaW4oJycpLFxuICAgICAgICAgICAgICAgICAgICAgICAgW1wiYT1zc3JjOlwiLCBzc3JjLCBcIiBtc2lkOlwiLCB2aWRlb1NvdXJjZXMuc291cmNlc1tzc3JjXS5tc2lkXS5qb2luKCcnKV0pKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAvL31cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gVGhlbiBhZGQgYW55IGZyZWUgc291cmNlcy5cbiAgICBpZiAodmlkZW9Tb3VyY2VzLnNvdXJjZXMpIHtcbiAgICAgICAgZm9yIChzc3JjIGluIHZpZGVvU291cmNlcy5zb3VyY2VzKSB7XG4gICAgICAgICAgICBpZiAoYWRkZWRTU1JDcy5pbmRleE9mKHNzcmMpID09PSAtMSkge1xuICAgICAgICAgICAgICAgIHNiLnNwbGljZS5hcHBseShzYiwgW3NiLmxlbmd0aCwgMF0uY29uY2F0KFtcbiAgICAgICAgICAgICAgICAgICAgW1wiYT1zc3JjOlwiLCBzc3JjLCBcIiBjbmFtZTpcIiwgdmlkZW9Tb3VyY2VzLnNvdXJjZXNbc3NyY10uY25hbWVdLmpvaW4oJycpLFxuICAgICAgICAgICAgICAgICAgICBbXCJhPXNzcmM6XCIsIHNzcmMsIFwiIG1zaWQ6XCIsIHZpZGVvU291cmNlcy5zb3VyY2VzW3NzcmNdLm1zaWRdLmpvaW4oJycpXSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHNiO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTaW11bGNhc3RVdGlsczsiLCIvKmpzbGludCBwbHVzcGx1czogdHJ1ZSAqL1xuLypqc2xpbnQgbm9tZW46IHRydWUqL1xuXG52YXIgU2ltdWxjYXN0U2VuZGVyID0gcmVxdWlyZShcIi4vU2ltdWxjYXN0U2VuZGVyXCIpO1xudmFyIE5vU2ltdWxjYXN0U2VuZGVyID0gU2ltdWxjYXN0U2VuZGVyW1wibm9cIl07XG52YXIgTmF0aXZlU2ltdWxjYXN0U2VuZGVyID0gU2ltdWxjYXN0U2VuZGVyW1wibmF0aXZlXCJdO1xudmFyIFNpbXVsY2FzdFJlY2VpdmVyID0gcmVxdWlyZShcIi4vU2ltdWxjYXN0UmVjZWl2ZXJcIik7XG52YXIgU2ltdWxjYXN0VXRpbHMgPSByZXF1aXJlKFwiLi9TaW11bGNhc3RVdGlsc1wiKTtcbnZhciBSVENFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvUlRDRXZlbnRzXCIpO1xuXG5cbi8qKlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBTaW11bGNhc3RNYW5hZ2VyKCkge1xuXG4gICAgLy8gQ3JlYXRlIHRoZSBzaW11bGNhc3QgdXRpbGl0aWVzLlxuICAgIHRoaXMuc2ltdWxjYXN0VXRpbHMgPSBuZXcgU2ltdWxjYXN0VXRpbHMoKTtcblxuICAgIC8vIENyZWF0ZSByZW1vdGUgc2ltdWxjYXN0LlxuICAgIHRoaXMuc2ltdWxjYXN0UmVjZWl2ZXIgPSBuZXcgU2ltdWxjYXN0UmVjZWl2ZXIoKTtcblxuICAgIC8vIEluaXRpYWxpemUgbG9jYWwgc2ltdWxjYXN0LlxuXG4gICAgLy8gVE9ETyhncCkgbW92ZSBpbnRvIFNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLmdldFVzZXJNZWRpYSBhbmQgdGFrZSBpbnRvXG4gICAgLy8gYWNjb3VudCBjb25zdHJhaW50cy5cbiAgICBpZiAoIWNvbmZpZy5lbmFibGVTaW11bGNhc3QpIHtcbiAgICAgICAgdGhpcy5zaW11bGNhc3RTZW5kZXIgPSBuZXcgTm9TaW11bGNhc3RTZW5kZXIoKTtcbiAgICB9IGVsc2Uge1xuXG4gICAgICAgIHZhciBpc0Nocm9taXVtID0gd2luZG93LmNocm9tZSxcbiAgICAgICAgICAgIHZlbmRvck5hbWUgPSB3aW5kb3cubmF2aWdhdG9yLnZlbmRvcjtcbiAgICAgICAgaWYoaXNDaHJvbWl1bSAhPT0gbnVsbCAmJiBpc0Nocm9taXVtICE9PSB1bmRlZmluZWRcbiAgICAgICAgICAgIC8qIHNraXAgb3BlcmEgKi9cbiAgICAgICAgICAgICYmIHZlbmRvck5hbWUgPT09IFwiR29vZ2xlIEluYy5cIlxuICAgICAgICAgICAgLyogc2tpcCBDaHJvbWl1bSBhcyBzdWdnZXN0ZWQgYnkgZmlwcG8gKi9cbiAgICAgICAgICAgICYmICF3aW5kb3cubmF2aWdhdG9yLmFwcFZlcnNpb24ubWF0Y2goL0Nocm9taXVtXFwvLykgKSB7XG4gICAgICAgICAgICB2YXIgdmVyID0gcGFyc2VJbnQod2luZG93Lm5hdmlnYXRvci5hcHBWZXJzaW9uLm1hdGNoKC9DaHJvbWVcXC8oXFxkKylcXC4vKVsxXSwgMTApO1xuICAgICAgICAgICAgaWYgKHZlciA+IDM3KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zaW11bGNhc3RTZW5kZXIgPSBuZXcgTmF0aXZlU2ltdWxjYXN0U2VuZGVyKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc2ltdWxjYXN0U2VuZGVyID0gbmV3IE5vU2ltdWxjYXN0U2VuZGVyKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNpbXVsY2FzdFNlbmRlciA9IG5ldyBOb1NpbXVsY2FzdFNlbmRlcigpO1xuICAgICAgICB9XG5cbiAgICB9XG4gICAgQVBQLlJUQy5hZGRMaXN0ZW5lcihSVENFdmVudHMuU0lNVUxDQVNUX0xBWUVSX0NIQU5HRUQsXG4gICAgICAgIGZ1bmN0aW9uIChlbmRwb2ludFNpbXVsY2FzdExheWVycykge1xuICAgICAgICAgICAgZW5kcG9pbnRTaW11bGNhc3RMYXllcnMuZm9yRWFjaChmdW5jdGlvbiAoZXNsKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNzcmMgPSBlc2wuc2ltdWxjYXN0TGF5ZXIucHJpbWFyeVNTUkM7XG4gICAgICAgICAgICAgICAgc2ltdWxjYXN0Ll9zZXRSZWNlaXZpbmdWaWRlb1N0cmVhbShlc2wuZW5kcG9pbnQsIHNzcmMpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIEFQUC5SVEMuYWRkTGlzdGVuZXIoUlRDRXZlbnRzLlNJTVVMQ0FTVF9TVEFSVCwgZnVuY3Rpb24gKHNpbXVsY2FzdExheWVyKSB7XG4gICAgICAgIHZhciBzc3JjID0gc2ltdWxjYXN0TGF5ZXIucHJpbWFyeVNTUkM7XG4gICAgICAgIHNpbXVsY2FzdC5fc2V0TG9jYWxWaWRlb1N0cmVhbUVuYWJsZWQoc3NyYywgdHJ1ZSk7XG4gICAgfSk7XG4gICAgQVBQLlJUQy5hZGRMaXN0ZW5lcihSVENFdmVudHMuU0lNVUxDQVNUX1NUT1AsIGZ1bmN0aW9uIChzaW11bGNhc3RMYXllcikge1xuICAgICAgICB2YXIgc3NyYyA9IHNpbXVsY2FzdExheWVyLnByaW1hcnlTU1JDO1xuICAgICAgICBzaW11bGNhc3QuX3NldExvY2FsVmlkZW9TdHJlYW1FbmFibGVkKHNzcmMsIGZhbHNlKTtcbiAgICB9KTtcblxufVxuXG4vKipcbiAqIFJlc3RvcmVzIHRoZSBzaW11bGNhc3QgZ3JvdXBzIG9mIHRoZSByZW1vdGUgZGVzY3JpcHRpb24uIEluXG4gKiB0cmFuc2Zvcm1SZW1vdGVEZXNjcmlwdGlvbiB3ZSByZW1vdmUgdGhvc2UgaW4gb3JkZXIgZm9yIHRoZSBzZXQgcmVtb3RlXG4gKiBkZXNjcmlwdGlvbiB0byBzdWNjZWVkLiBUaGUgZm9jdXMgbmVlZHMgdGhlIHNpZ25hbCB0aGUgZ3JvdXBzIHRvIG5ld1xuICogcGFydGljaXBhbnRzLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUucmV2ZXJzZVRyYW5zZm9ybVJlbW90ZURlc2NyaXB0aW9uID0gZnVuY3Rpb24gKGRlc2MpIHtcbiAgICByZXR1cm4gdGhpcy5zaW11bGNhc3RSZWNlaXZlci5yZXZlcnNlVHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24oZGVzYyk7XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgdGhlIHNzcmMtZ3JvdXA6U0lNIGZyb20gdGhlIHJlbW90ZSBkZXNjcmlwdGlvbiBiYWNhdXNlIENocm9tZVxuICogZWl0aGVyIGdldHMgY29uZnVzZWQgYW5kIHRoaW5rcyB0aGlzIGlzIGFuIEZJRCBncm91cCBvciwgaWYgYW4gRklEIGdyb3VwXG4gKiBpcyBhbHJlYWR5IHByZXNlbnQsIGl0IGZhaWxzIHRvIHNldCB0aGUgcmVtb3RlIGRlc2NyaXB0aW9uLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUudHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFJlY2VpdmVyLnRyYW5zZm9ybVJlbW90ZURlc2NyaXB0aW9uKGRlc2MpO1xufTtcblxuLyoqXG4gKiBHZXRzIHRoZSBmdWxseSBxdWFsaWZpZWQgbXNpZCAoc3RyZWFtLmlkICsgdHJhY2suaWQpIGFzc29jaWF0ZWQgdG8gdGhlXG4gKiBTU1JDLlxuICpcbiAqIEBwYXJhbSBzc3JjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUuZ2V0UmVtb3RlVmlkZW9TdHJlYW1JZEJ5U1NSQyA9IGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgcmV0dXJuIHRoaXMuc2ltdWxjYXN0UmVjZWl2ZXIuZ2V0UmVtb3RlVmlkZW9TdHJlYW1JZEJ5U1NSQyhzc3JjKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyBhIHN0cmVhbSB3aXRoIHNpbmdsZSB2aWRlbyB0cmFjaywgdGhlIG9uZSBjdXJyZW50bHkgYmVpbmdcbiAqIHJlY2VpdmVkIGJ5IHRoaXMgZW5kcG9pbnQuXG4gKlxuICogQHBhcmFtIHN0cmVhbSB0aGUgcmVtb3RlIHNpbXVsY2FzdCBzdHJlYW0uXG4gKiBAcmV0dXJucyB7d2Via2l0TWVkaWFTdHJlYW19XG4gKi9cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLmdldFJlY2VpdmluZ1ZpZGVvU3RyZWFtID0gZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFJlY2VpdmVyLmdldFJlY2VpdmluZ1ZpZGVvU3RyZWFtKHN0cmVhbSk7XG59O1xuXG4vKipcbiAqXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS50cmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uID0gZnVuY3Rpb24gKGRlc2MpIHtcbiAgICByZXR1cm4gdGhpcy5zaW11bGNhc3RTZW5kZXIudHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbihkZXNjKTtcbn07XG5cbi8qKlxuICpcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5nZXRMb2NhbFZpZGVvU3RyZWFtID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuc2ltdWxjYXN0U2VuZGVyLmdldExvY2FsVmlkZW9TdHJlYW0oKTtcbn07XG5cbi8qKlxuICogR1VNIGZvciBzaW11bGNhc3QuXG4gKlxuICogQHBhcmFtIGNvbnN0cmFpbnRzXG4gKiBAcGFyYW0gc3VjY2Vzc1xuICogQHBhcmFtIGVyclxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbiAoY29uc3RyYWludHMsIHN1Y2Nlc3MsIGVycikge1xuXG4gICAgdGhpcy5zaW11bGNhc3RTZW5kZXIuZ2V0VXNlck1lZGlhKGNvbnN0cmFpbnRzLCBzdWNjZXNzLCBlcnIpO1xufTtcblxuLyoqXG4gKiBQcmVwYXJlcyB0aGUgbG9jYWwgZGVzY3JpcHRpb24gZm9yIHB1YmxpYyB1c2FnZSAoaS5lLiB0byBiZSBzaWduYWxlZFxuICogdGhyb3VnaCBKaW5nbGUgdG8gdGhlIGZvY3VzKS5cbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMge1JUQ1Nlc3Npb25EZXNjcmlwdGlvbn1cbiAqL1xuU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUucmV2ZXJzZVRyYW5zZm9ybUxvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFNlbmRlci5yZXZlcnNlVHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbihkZXNjKTtcbn07XG5cbi8qKlxuICogRW5zdXJlcyB0aGF0IHRoZSBzaW11bGNhc3QgZ3JvdXAgaXMgcHJlc2VudCBpbiB0aGUgYW5zd2VyLCBfaWZfIG5hdGl2ZVxuICogc2ltdWxjYXN0IGlzIGVuYWJsZWQsXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS50cmFuc2Zvcm1BbnN3ZXIgPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFNlbmRlci50cmFuc2Zvcm1BbnN3ZXIoZGVzYyk7XG59O1xuXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5nZXRSZWNlaXZpbmdTU1JDID0gZnVuY3Rpb24gKGppZCkge1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFJlY2VpdmVyLmdldFJlY2VpdmluZ1NTUkMoamlkKTtcbn07XG5cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLmdldFJlY2VpdmluZ1ZpZGVvU3RyZWFtQnlTU1JDID0gZnVuY3Rpb24gKG1zaWQpIHtcbiAgICByZXR1cm4gdGhpcy5zaW11bGNhc3RSZWNlaXZlci5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbUJ5U1NSQyhtc2lkKTtcbn07XG5cbi8qKlxuICpcbiAqIEBwYXJhbSBsaW5lc1xuICogQHBhcmFtIG1lZGlhdHlwZXNcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5wYXJzZU1lZGlhID0gZnVuY3Rpb24obGluZXMsIG1lZGlhdHlwZXMpIHtcbiAgICB2YXIgc2IgPSBsaW5lcy5zZHAuc3BsaXQoJ1xcclxcbicpO1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFV0aWxzLnBhcnNlTWVkaWEoc2IsIG1lZGlhdHlwZXMpO1xufTtcblxuU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUuX3NldFJlY2VpdmluZ1ZpZGVvU3RyZWFtID0gZnVuY3Rpb24ocmVzb3VyY2UsIHNzcmMpIHtcbiAgICB0aGlzLnNpbXVsY2FzdFJlY2VpdmVyLl9zZXRSZWNlaXZpbmdWaWRlb1N0cmVhbShyZXNvdXJjZSwgc3NyYyk7XG59O1xuXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5fc2V0TG9jYWxWaWRlb1N0cmVhbUVuYWJsZWQgPSBmdW5jdGlvbihzc3JjLCBlbmFibGVkKSB7XG4gICAgdGhpcy5zaW11bGNhc3RTZW5kZXIuX3NldExvY2FsVmlkZW9TdHJlYW1FbmFibGVkKHNzcmMsIGVuYWJsZWQpO1xufTtcblxuU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUucmVzZXRTZW5kZXIgPSBmdW5jdGlvbigpIHtcbiAgICBpZiAodHlwZW9mIHRoaXMuc2ltdWxjYXN0U2VuZGVyLnJlc2V0ID09PSAnZnVuY3Rpb24nKXtcbiAgICAgICAgdGhpcy5zaW11bGNhc3RTZW5kZXIucmVzZXQoKTtcbiAgICB9XG59O1xuXG52YXIgc2ltdWxjYXN0ID0gbmV3IFNpbXVsY2FzdE1hbmFnZXIoKTtcblxubW9kdWxlLmV4cG9ydHMgPSBzaW11bGNhc3Q7IiwiLyoqXG4gKiBQcm92aWRlcyBzdGF0aXN0aWNzIGZvciB0aGUgbG9jYWwgc3RyZWFtLlxuICovXG5cblxuLyoqXG4gKiBTaXplIG9mIHRoZSB3ZWJhdWRpbyBhbmFsaXplciBidWZmZXIuXG4gKiBAdHlwZSB7bnVtYmVyfVxuICovXG52YXIgV0VCQVVESU9fQU5BTElaRVJfRkZUX1NJWkUgPSAyMDQ4O1xuXG4vKipcbiAqIFZhbHVlIG9mIHRoZSB3ZWJhdWRpbyBhbmFsaXplciBzbW9vdGhpbmcgdGltZSBwYXJhbWV0ZXIuXG4gKiBAdHlwZSB7bnVtYmVyfVxuICovXG52YXIgV0VCQVVESU9fQU5BTElaRVJfU01PT1RJTkdfVElNRSA9IDAuODtcblxuLyoqXG4gKiBDb252ZXJ0cyB0aW1lIGRvbWFpbiBkYXRhIGFycmF5IHRvIGF1ZGlvIGxldmVsLlxuICogQHBhcmFtIGFycmF5IHRoZSB0aW1lIGRvbWFpbiBkYXRhIGFycmF5LlxuICogQHJldHVybnMge251bWJlcn0gdGhlIGF1ZGlvIGxldmVsXG4gKi9cbmZ1bmN0aW9uIHRpbWVEb21haW5EYXRhVG9BdWRpb0xldmVsKHNhbXBsZXMpIHtcblxuICAgIHZhciBtYXhWb2x1bWUgPSAwO1xuXG4gICAgdmFyIGxlbmd0aCA9IHNhbXBsZXMubGVuZ3RoO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAobWF4Vm9sdW1lIDwgc2FtcGxlc1tpXSlcbiAgICAgICAgICAgIG1heFZvbHVtZSA9IHNhbXBsZXNbaV07XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnNlRmxvYXQoKChtYXhWb2x1bWUgLSAxMjcpIC8gMTI4KS50b0ZpeGVkKDMpKTtcbn07XG5cbi8qKlxuICogQW5pbWF0ZXMgYXVkaW8gbGV2ZWwgY2hhbmdlXG4gKiBAcGFyYW0gbmV3TGV2ZWwgdGhlIG5ldyBhdWRpbyBsZXZlbFxuICogQHBhcmFtIGxhc3RMZXZlbCB0aGUgbGFzdCBhdWRpbyBsZXZlbFxuICogQHJldHVybnMge051bWJlcn0gdGhlIGF1ZGlvIGxldmVsIHRvIGJlIHNldFxuICovXG5mdW5jdGlvbiBhbmltYXRlTGV2ZWwobmV3TGV2ZWwsIGxhc3RMZXZlbClcbntcbiAgICB2YXIgdmFsdWUgPSAwO1xuICAgIHZhciBkaWZmID0gbGFzdExldmVsIC0gbmV3TGV2ZWw7XG4gICAgaWYoZGlmZiA+IDAuMilcbiAgICB7XG4gICAgICAgIHZhbHVlID0gbGFzdExldmVsIC0gMC4yO1xuICAgIH1cbiAgICBlbHNlIGlmKGRpZmYgPCAtMC40KVxuICAgIHtcbiAgICAgICAgdmFsdWUgPSBsYXN0TGV2ZWwgKyAwLjQ7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIHZhbHVlID0gbmV3TGV2ZWw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnNlRmxvYXQodmFsdWUudG9GaXhlZCgzKSk7XG59XG5cblxuLyoqXG4gKiA8dHQ+TG9jYWxTdGF0c0NvbGxlY3RvcjwvdHQ+IGNhbGN1bGF0ZXMgc3RhdGlzdGljcyBmb3IgdGhlIGxvY2FsIHN0cmVhbS5cbiAqXG4gKiBAcGFyYW0gc3RyZWFtIHRoZSBsb2NhbCBzdHJlYW1cbiAqIEBwYXJhbSBpbnRlcnZhbCBzdGF0cyByZWZyZXNoIGludGVydmFsIGdpdmVuIGluIG1zLlxuICogQHBhcmFtIHtmdW5jdGlvbihMb2NhbFN0YXRzQ29sbGVjdG9yKX0gdXBkYXRlQ2FsbGJhY2sgdGhlIGNhbGxiYWNrIGNhbGxlZCBvbiBzdGF0c1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZS5cbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBMb2NhbFN0YXRzQ29sbGVjdG9yKHN0cmVhbSwgaW50ZXJ2YWwsIHN0YXRpc3RpY3NTZXJ2aWNlLCBldmVudEVtaXR0ZXIpIHtcbiAgICB3aW5kb3cuQXVkaW9Db250ZXh0ID0gd2luZG93LkF1ZGlvQ29udGV4dCB8fCB3aW5kb3cud2Via2l0QXVkaW9Db250ZXh0O1xuICAgIHRoaXMuc3RyZWFtID0gc3RyZWFtO1xuICAgIHRoaXMuaW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgdGhpcy5pbnRlcnZhbE1pbGlzID0gaW50ZXJ2YWw7XG4gICAgdGhpcy5ldmVudEVtaXR0ZXIgPSBldmVudEVtaXR0ZXI7XG4gICAgdGhpcy5hdWRpb0xldmVsID0gMDtcbiAgICB0aGlzLnN0YXRpc3RpY3NTZXJ2aWNlID0gc3RhdGlzdGljc1NlcnZpY2U7XG59XG5cbi8qKlxuICogU3RhcnRzIHRoZSBjb2xsZWN0aW5nIHRoZSBzdGF0aXN0aWNzLlxuICovXG5Mb2NhbFN0YXRzQ29sbGVjdG9yLnByb3RvdHlwZS5zdGFydCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoY29uZmlnLmRpc2FibGVBdWRpb0xldmVscyB8fCAhd2luZG93LkF1ZGlvQ29udGV4dClcbiAgICAgICAgcmV0dXJuO1xuXG4gICAgdmFyIGNvbnRleHQgPSBuZXcgQXVkaW9Db250ZXh0KCk7XG4gICAgdmFyIGFuYWx5c2VyID0gY29udGV4dC5jcmVhdGVBbmFseXNlcigpO1xuICAgIGFuYWx5c2VyLnNtb290aGluZ1RpbWVDb25zdGFudCA9IFdFQkFVRElPX0FOQUxJWkVSX1NNT09USU5HX1RJTUU7XG4gICAgYW5hbHlzZXIuZmZ0U2l6ZSA9IFdFQkFVRElPX0FOQUxJWkVSX0ZGVF9TSVpFO1xuXG5cbiAgICB2YXIgc291cmNlID0gY29udGV4dC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZSh0aGlzLnN0cmVhbSk7XG4gICAgc291cmNlLmNvbm5lY3QoYW5hbHlzZXIpO1xuXG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICB0aGlzLmludGVydmFsSWQgPSBzZXRJbnRlcnZhbChcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoYW5hbHlzZXIuZnJlcXVlbmN5QmluQ291bnQpO1xuICAgICAgICAgICAgYW5hbHlzZXIuZ2V0Qnl0ZVRpbWVEb21haW5EYXRhKGFycmF5KTtcbiAgICAgICAgICAgIHZhciBhdWRpb0xldmVsID0gdGltZURvbWFpbkRhdGFUb0F1ZGlvTGV2ZWwoYXJyYXkpO1xuICAgICAgICAgICAgaWYoYXVkaW9MZXZlbCAhPSBzZWxmLmF1ZGlvTGV2ZWwpIHtcbiAgICAgICAgICAgICAgICBzZWxmLmF1ZGlvTGV2ZWwgPSBhbmltYXRlTGV2ZWwoYXVkaW9MZXZlbCwgc2VsZi5hdWRpb0xldmVsKTtcbiAgICAgICAgICAgICAgICBzZWxmLmV2ZW50RW1pdHRlci5lbWl0KFxuICAgICAgICAgICAgICAgICAgICBcInN0YXRpc3RpY3MuYXVkaW9MZXZlbFwiLFxuICAgICAgICAgICAgICAgICAgICBzZWxmLnN0YXRpc3RpY3NTZXJ2aWNlLkxPQ0FMX0pJRCxcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5hdWRpb0xldmVsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgdGhpcy5pbnRlcnZhbE1pbGlzXG4gICAgKTtcblxufTtcblxuLyoqXG4gKiBTdG9wcyBjb2xsZWN0aW5nIHRoZSBzdGF0aXN0aWNzLlxuICovXG5Mb2NhbFN0YXRzQ29sbGVjdG9yLnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLmludGVydmFsSWQpIHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmludGVydmFsSWQpO1xuICAgICAgICB0aGlzLmludGVydmFsSWQgPSBudWxsO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gTG9jYWxTdGF0c0NvbGxlY3RvcjsiLCIvKiBnbG9iYWwgc3NyYzJqaWQgKi9cbi8qIGpzaGludCAtVzExNyAqL1xudmFyIFJUQ0Jyb3dzZXJUeXBlID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL1JUQ0Jyb3dzZXJUeXBlXCIpO1xuXG5cbi8qKlxuICogQ2FsY3VsYXRlcyBwYWNrZXQgbG9zdCBwZXJjZW50IHVzaW5nIHRoZSBudW1iZXIgb2YgbG9zdCBwYWNrZXRzIGFuZCB0aGVcbiAqIG51bWJlciBvZiBhbGwgcGFja2V0LlxuICogQHBhcmFtIGxvc3RQYWNrZXRzIHRoZSBudW1iZXIgb2YgbG9zdCBwYWNrZXRzXG4gKiBAcGFyYW0gdG90YWxQYWNrZXRzIHRoZSBudW1iZXIgb2YgYWxsIHBhY2tldHMuXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBwYWNrZXQgbG9zcyBwZXJjZW50XG4gKi9cbmZ1bmN0aW9uIGNhbGN1bGF0ZVBhY2tldExvc3MobG9zdFBhY2tldHMsIHRvdGFsUGFja2V0cykge1xuICAgIGlmKCF0b3RhbFBhY2tldHMgfHwgdG90YWxQYWNrZXRzIDw9IDAgfHwgIWxvc3RQYWNrZXRzIHx8IGxvc3RQYWNrZXRzIDw9IDApXG4gICAgICAgIHJldHVybiAwO1xuICAgIHJldHVybiBNYXRoLnJvdW5kKChsb3N0UGFja2V0cy90b3RhbFBhY2tldHMpKjEwMCk7XG59XG5cbmZ1bmN0aW9uIGdldFN0YXRWYWx1ZShpdGVtLCBuYW1lKSB7XG4gICAgaWYoIWtleU1hcFtBUFAuUlRDLmdldEJyb3dzZXJUeXBlKCldW25hbWVdKVxuICAgICAgICB0aHJvdyBcIlRoZSBwcm9wZXJ0eSBpc24ndCBzdXBwb3J0ZWQhXCI7XG4gICAgdmFyIGtleSA9IGtleU1hcFtBUFAuUlRDLmdldEJyb3dzZXJUeXBlKCldW25hbWVdO1xuICAgIHJldHVybiBBUFAuUlRDLmdldEJyb3dzZXJUeXBlKCkgPT0gUlRDQnJvd3NlclR5cGUuUlRDX0JST1dTRVJfQ0hST01FPyBpdGVtLnN0YXQoa2V5KSA6IGl0ZW1ba2V5XTtcbn1cblxuLyoqXG4gKiBQZWVyIHN0YXRpc3RpY3MgZGF0YSBob2xkZXIuXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZnVuY3Rpb24gUGVlclN0YXRzKClcbntcbiAgICB0aGlzLnNzcmMyTG9zcyA9IHt9O1xuICAgIHRoaXMuc3NyYzJBdWRpb0xldmVsID0ge307XG4gICAgdGhpcy5zc3JjMmJpdHJhdGUgPSB7fTtcbiAgICB0aGlzLnNzcmMycmVzb2x1dGlvbiA9IHt9O1xufVxuXG4vKipcbiAqIFRoZSBiYW5kd2lkdGhcbiAqIEB0eXBlIHt7fX1cbiAqL1xuUGVlclN0YXRzLmJhbmR3aWR0aCA9IHt9O1xuXG4vKipcbiAqIFRoZSBiaXQgcmF0ZVxuICogQHR5cGUge3t9fVxuICovXG5QZWVyU3RhdHMuYml0cmF0ZSA9IHt9O1xuXG5cblxuLyoqXG4gKiBUaGUgcGFja2V0IGxvc3MgcmF0ZVxuICogQHR5cGUge3t9fVxuICovXG5QZWVyU3RhdHMucGFja2V0TG9zcyA9IG51bGw7XG5cbi8qKlxuICogU2V0cyBwYWNrZXRzIGxvc3MgcmF0ZSBmb3IgZ2l2ZW4gPHR0PnNzcmM8L3R0PiB0aGF0IGJsb25nIHRvIHRoZSBwZWVyXG4gKiByZXByZXNlbnRlZCBieSB0aGlzIGluc3RhbmNlLlxuICogQHBhcmFtIHNzcmMgYXVkaW8gb3IgdmlkZW8gUlRQIHN0cmVhbSBTU1JDLlxuICogQHBhcmFtIGxvc3NSYXRlIG5ldyBwYWNrZXQgbG9zcyByYXRlIHZhbHVlIHRvIGJlIHNldC5cbiAqL1xuUGVlclN0YXRzLnByb3RvdHlwZS5zZXRTc3JjTG9zcyA9IGZ1bmN0aW9uIChzc3JjLCBsb3NzUmF0ZSlcbntcbiAgICB0aGlzLnNzcmMyTG9zc1tzc3JjXSA9IGxvc3NSYXRlO1xufTtcblxuLyoqXG4gKiBTZXRzIHJlc29sdXRpb24gZm9yIGdpdmVuIDx0dD5zc3JjPC90dD4gdGhhdCBiZWxvbmcgdG8gdGhlIHBlZXJcbiAqIHJlcHJlc2VudGVkIGJ5IHRoaXMgaW5zdGFuY2UuXG4gKiBAcGFyYW0gc3NyYyBhdWRpbyBvciB2aWRlbyBSVFAgc3RyZWFtIFNTUkMuXG4gKiBAcGFyYW0gcmVzb2x1dGlvbiBuZXcgcmVzb2x1dGlvbiB2YWx1ZSB0byBiZSBzZXQuXG4gKi9cblBlZXJTdGF0cy5wcm90b3R5cGUuc2V0U3NyY1Jlc29sdXRpb24gPSBmdW5jdGlvbiAoc3NyYywgcmVzb2x1dGlvbilcbntcbiAgICBpZihyZXNvbHV0aW9uID09PSBudWxsICYmIHRoaXMuc3NyYzJyZXNvbHV0aW9uW3NzcmNdKVxuICAgIHtcbiAgICAgICAgZGVsZXRlIHRoaXMuc3NyYzJyZXNvbHV0aW9uW3NzcmNdO1xuICAgIH1cbiAgICBlbHNlIGlmKHJlc29sdXRpb24gIT09IG51bGwpXG4gICAgICAgIHRoaXMuc3NyYzJyZXNvbHV0aW9uW3NzcmNdID0gcmVzb2x1dGlvbjtcbn07XG5cbi8qKlxuICogU2V0cyB0aGUgYml0IHJhdGUgZm9yIGdpdmVuIDx0dD5zc3JjPC90dD4gdGhhdCBibG9uZyB0byB0aGUgcGVlclxuICogcmVwcmVzZW50ZWQgYnkgdGhpcyBpbnN0YW5jZS5cbiAqIEBwYXJhbSBzc3JjIGF1ZGlvIG9yIHZpZGVvIFJUUCBzdHJlYW0gU1NSQy5cbiAqIEBwYXJhbSBiaXRyYXRlIG5ldyBiaXRyYXRlIHZhbHVlIHRvIGJlIHNldC5cbiAqL1xuUGVlclN0YXRzLnByb3RvdHlwZS5zZXRTc3JjQml0cmF0ZSA9IGZ1bmN0aW9uIChzc3JjLCBiaXRyYXRlKVxue1xuICAgIGlmKHRoaXMuc3NyYzJiaXRyYXRlW3NzcmNdKVxuICAgIHtcbiAgICAgICAgdGhpcy5zc3JjMmJpdHJhdGVbc3NyY10uZG93bmxvYWQgKz0gYml0cmF0ZS5kb3dubG9hZDtcbiAgICAgICAgdGhpcy5zc3JjMmJpdHJhdGVbc3NyY10udXBsb2FkICs9IGJpdHJhdGUudXBsb2FkO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5zc3JjMmJpdHJhdGVbc3NyY10gPSBiaXRyYXRlO1xuICAgIH1cbn07XG5cbi8qKlxuICogU2V0cyBuZXcgYXVkaW8gbGV2ZWwoaW5wdXQgb3Igb3V0cHV0KSBmb3IgZ2l2ZW4gPHR0PnNzcmM8L3R0PiB0aGF0IGlkZW50aWZpZXNcbiAqIHRoZSBzdHJlYW0gd2hpY2ggYmVsb25ncyB0byB0aGUgcGVlciByZXByZXNlbnRlZCBieSB0aGlzIGluc3RhbmNlLlxuICogQHBhcmFtIHNzcmMgUlRQIHN0cmVhbSBTU1JDIGZvciB3aGljaCBjdXJyZW50IGF1ZGlvIGxldmVsIHZhbHVlIHdpbGwgYmVcbiAqICAgICAgICB1cGRhdGVkLlxuICogQHBhcmFtIGF1ZGlvTGV2ZWwgdGhlIG5ldyBhdWRpbyBsZXZlbCB2YWx1ZSB0byBiZSBzZXQuIFZhbHVlIGlzIHRydW5jYXRlZCB0b1xuICogICAgICAgIGZpdCB0aGUgcmFuZ2UgZnJvbSAwIHRvIDEuXG4gKi9cblBlZXJTdGF0cy5wcm90b3R5cGUuc2V0U3NyY0F1ZGlvTGV2ZWwgPSBmdW5jdGlvbiAoc3NyYywgYXVkaW9MZXZlbClcbntcbiAgICAvLyBSYW5nZSBsaW1pdCAwIC0gMVxuICAgIHRoaXMuc3NyYzJBdWRpb0xldmVsW3NzcmNdID0gZm9ybWF0QXVkaW9MZXZlbChhdWRpb0xldmVsKTtcbn07XG5cbmZ1bmN0aW9uIGZvcm1hdEF1ZGlvTGV2ZWwoYXVkaW9MZXZlbCkge1xuICAgIHJldHVybiBNYXRoLm1pbihNYXRoLm1heChhdWRpb0xldmVsLCAwKSwgMSk7XG59XG5cbi8qKlxuICogQXJyYXkgd2l0aCB0aGUgdHJhbnNwb3J0IGluZm9ybWF0aW9uLlxuICogQHR5cGUge0FycmF5fVxuICovXG5QZWVyU3RhdHMudHJhbnNwb3J0ID0gW107XG5cblxuLyoqXG4gKiA8dHQ+U3RhdHNDb2xsZWN0b3I8L3R0PiByZWdpc3RlcnMgZm9yIHN0YXRzIHVwZGF0ZXMgb2YgZ2l2ZW5cbiAqIDx0dD5wZWVyY29ubmVjdGlvbjwvdHQ+IGluIGdpdmVuIDx0dD5pbnRlcnZhbDwvdHQ+LiBPbiBlYWNoIHVwZGF0ZSBwYXJ0aWN1bGFyXG4gKiBzdGF0cyBhcmUgZXh0cmFjdGVkIGFuZCBwdXQgaW4ge0BsaW5rIFBlZXJTdGF0c30gb2JqZWN0cy4gT25jZSB0aGUgcHJvY2Vzc2luZ1xuICogaXMgZG9uZSA8dHQ+YXVkaW9MZXZlbHNVcGRhdGVDYWxsYmFjazwvdHQ+IGlzIGNhbGxlZCB3aXRoIDx0dD50aGlzPC90dD5cbiAqIGluc3RhbmNlIGFzIGFuIGV2ZW50IHNvdXJjZS5cbiAqXG4gKiBAcGFyYW0gcGVlcmNvbm5lY3Rpb24gd2ViUlRDIHBlZXIgY29ubmVjdGlvbiBvYmplY3QuXG4gKiBAcGFyYW0gaW50ZXJ2YWwgc3RhdHMgcmVmcmVzaCBpbnRlcnZhbCBnaXZlbiBpbiBtcy5cbiAqIEBwYXJhbSB7ZnVuY3Rpb24oU3RhdHNDb2xsZWN0b3IpfSBhdWRpb0xldmVsc1VwZGF0ZUNhbGxiYWNrIHRoZSBjYWxsYmFja1xuICogY2FsbGVkIG9uIHN0YXRzIHVwZGF0ZS5cbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBTdGF0c0NvbGxlY3RvcihwZWVyY29ubmVjdGlvbiwgYXVkaW9MZXZlbHNJbnRlcnZhbCwgc3RhdHNJbnRlcnZhbCwgZXZlbnRFbWl0dGVyKVxue1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24gPSBwZWVyY29ubmVjdGlvbjtcbiAgICB0aGlzLmJhc2VsaW5lQXVkaW9MZXZlbHNSZXBvcnQgPSBudWxsO1xuICAgIHRoaXMuY3VycmVudEF1ZGlvTGV2ZWxzUmVwb3J0ID0gbnVsbDtcbiAgICB0aGlzLmN1cnJlbnRTdGF0c1JlcG9ydCA9IG51bGw7XG4gICAgdGhpcy5iYXNlbGluZVN0YXRzUmVwb3J0ID0gbnVsbDtcbiAgICB0aGlzLmF1ZGlvTGV2ZWxzSW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgdGhpcy5ldmVudEVtaXR0ZXIgPSBldmVudEVtaXR0ZXI7XG5cbiAgICAvKipcbiAgICAgKiBHYXRoZXIgUGVlckNvbm5lY3Rpb24gc3RhdHMgb25jZSBldmVyeSB0aGlzIG1hbnkgbWlsbGlzZWNvbmRzLlxuICAgICAqL1xuICAgIHRoaXMuR0FUSEVSX0lOVEVSVkFMID0gMTUwMDA7XG5cbiAgICAvKipcbiAgICAgKiBMb2cgc3RhdHMgdmlhIHRoZSBmb2N1cyBvbmNlIGV2ZXJ5IHRoaXMgbWFueSBtaWxsaXNlY29uZHMuXG4gICAgICovXG4gICAgdGhpcy5MT0dfSU5URVJWQUwgPSA2MDAwMDtcblxuICAgIC8qKlxuICAgICAqIEdhdGhlciBzdGF0cyBhbmQgc3RvcmUgdGhlbSBpbiB0aGlzLnN0YXRzVG9CZUxvZ2dlZC5cbiAgICAgKi9cbiAgICB0aGlzLmdhdGhlclN0YXRzSW50ZXJ2YWxJZCA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIHRoZSBzdGF0cyBhbHJlYWR5IHNhdmVkIGluIHRoaXMuc3RhdHNUb0JlTG9nZ2VkIHRvIGJlIGxvZ2dlZCB2aWFcbiAgICAgKiB0aGUgZm9jdXMuXG4gICAgICovXG4gICAgdGhpcy5sb2dTdGF0c0ludGVydmFsSWQgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogU3RvcmVzIHRoZSBzdGF0aXN0aWNzIHdoaWNoIHdpbGwgYmUgc2VuZCB0byB0aGUgZm9jdXMgdG8gYmUgbG9nZ2VkLlxuICAgICAqL1xuICAgIHRoaXMuc3RhdHNUb0JlTG9nZ2VkID1cbiAgICB7XG4gICAgICAgIHRpbWVzdGFtcHM6IFtdLFxuICAgICAgICBzdGF0czoge31cbiAgICB9O1xuXG4gICAgLy8gVXBkYXRlcyBzdGF0cyBpbnRlcnZhbFxuICAgIHRoaXMuYXVkaW9MZXZlbHNJbnRlcnZhbE1pbGlzID0gYXVkaW9MZXZlbHNJbnRlcnZhbDtcblxuICAgIHRoaXMuc3RhdHNJbnRlcnZhbElkID0gbnVsbDtcbiAgICB0aGlzLnN0YXRzSW50ZXJ2YWxNaWxpcyA9IHN0YXRzSW50ZXJ2YWw7XG4gICAgLy8gTWFwIG9mIGppZHMgdG8gUGVlclN0YXRzXG4gICAgdGhpcy5qaWQyc3RhdHMgPSB7fTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBTdGF0c0NvbGxlY3RvcjtcblxuLyoqXG4gKiBTdG9wcyBzdGF0cyB1cGRhdGVzLlxuICovXG5TdGF0c0NvbGxlY3Rvci5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5hdWRpb0xldmVsc0ludGVydmFsSWQpIHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmF1ZGlvTGV2ZWxzSW50ZXJ2YWxJZCk7XG4gICAgICAgIHRoaXMuYXVkaW9MZXZlbHNJbnRlcnZhbElkID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zdGF0c0ludGVydmFsSWQpXG4gICAge1xuICAgICAgICBjbGVhckludGVydmFsKHRoaXMuc3RhdHNJbnRlcnZhbElkKTtcbiAgICAgICAgdGhpcy5zdGF0c0ludGVydmFsSWQgPSBudWxsO1xuICAgIH1cblxuICAgIGlmKHRoaXMubG9nU3RhdHNJbnRlcnZhbElkKVxuICAgIHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmxvZ1N0YXRzSW50ZXJ2YWxJZCk7XG4gICAgICAgIHRoaXMubG9nU3RhdHNJbnRlcnZhbElkID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZih0aGlzLmdhdGhlclN0YXRzSW50ZXJ2YWxJZClcbiAgICB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5nYXRoZXJTdGF0c0ludGVydmFsSWQpO1xuICAgICAgICB0aGlzLmdhdGhlclN0YXRzSW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgfVxufTtcblxuLyoqXG4gKiBDYWxsYmFjayBwYXNzZWQgdG8gPHR0PmdldFN0YXRzPC90dD4gbWV0aG9kLlxuICogQHBhcmFtIGVycm9yIGFuIGVycm9yIHRoYXQgb2NjdXJyZWQgb24gPHR0PmdldFN0YXRzPC90dD4gY2FsbC5cbiAqL1xuU3RhdHNDb2xsZWN0b3IucHJvdG90eXBlLmVycm9yQ2FsbGJhY2sgPSBmdW5jdGlvbiAoZXJyb3IpXG57XG4gICAgY29uc29sZS5lcnJvcihcIkdldCBzdGF0cyBlcnJvclwiLCBlcnJvcik7XG4gICAgdGhpcy5zdG9wKCk7XG59O1xuXG4vKipcbiAqIFN0YXJ0cyBzdGF0cyB1cGRhdGVzLlxuICovXG5TdGF0c0NvbGxlY3Rvci5wcm90b3R5cGUuc3RhcnQgPSBmdW5jdGlvbiAoKVxue1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZighY29uZmlnLmRpc2FibGVBdWRpb0xldmVscykge1xuICAgICAgICB0aGlzLmF1ZGlvTGV2ZWxzSW50ZXJ2YWxJZCA9IHNldEludGVydmFsKFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIC8vIEludGVydmFsIHVwZGF0ZXNcbiAgICAgICAgICAgICAgICBzZWxmLnBlZXJjb25uZWN0aW9uLmdldFN0YXRzKFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVwb3J0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzdWx0cyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXJlcG9ydCB8fCAhcmVwb3J0LnJlc3VsdCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVvZiByZXBvcnQucmVzdWx0ICE9ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gcmVwb3J0O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IHJlcG9ydC5yZXN1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5lcnJvcihcIkdvdCBpbnRlcnZhbCByZXBvcnRcIiwgcmVzdWx0cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmN1cnJlbnRBdWRpb0xldmVsc1JlcG9ydCA9IHJlc3VsdHM7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnByb2Nlc3NBdWRpb0xldmVsUmVwb3J0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmJhc2VsaW5lQXVkaW9MZXZlbHNSZXBvcnQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY3VycmVudEF1ZGlvTGV2ZWxzUmVwb3J0O1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBzZWxmLmVycm9yQ2FsbGJhY2tcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNlbGYuYXVkaW9MZXZlbHNJbnRlcnZhbE1pbGlzXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgaWYoIWNvbmZpZy5kaXNhYmxlU3RhdHMpIHtcbiAgICAgICAgdGhpcy5zdGF0c0ludGVydmFsSWQgPSBzZXRJbnRlcnZhbChcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBJbnRlcnZhbCB1cGRhdGVzXG4gICAgICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5nZXRTdGF0cyhcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlcG9ydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFyZXBvcnQgfHwgIXJlcG9ydC5yZXN1bHQgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlb2YgcmVwb3J0LnJlc3VsdCAhPSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9maXJlZm94XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IHJlcG9ydDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vY2hyb21lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IHJlcG9ydC5yZXN1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5lcnJvcihcIkdvdCBpbnRlcnZhbCByZXBvcnRcIiwgcmVzdWx0cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmN1cnJlbnRTdGF0c1JlcG9ydCA9IHJlc3VsdHM7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucHJvY2Vzc1N0YXRzUmVwb3J0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJVbnN1cHBvcnRlZCBrZXk6XCIgKyBlLCBlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5iYXNlbGluZVN0YXRzUmVwb3J0ID0gc2VsZi5jdXJyZW50U3RhdHNSZXBvcnQ7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHNlbGYuZXJyb3JDYWxsYmFja1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc2VsZi5zdGF0c0ludGVydmFsTWlsaXNcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoY29uZmlnLmxvZ1N0YXRzKSB7XG4gICAgICAgIHRoaXMuZ2F0aGVyU3RhdHNJbnRlcnZhbElkID0gc2V0SW50ZXJ2YWwoXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5nZXRTdGF0cyhcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlcG9ydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5hZGRTdGF0c1RvQmVMb2dnZWQocmVwb3J0LnJlc3VsdCgpKTtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB0aGlzLkdBVEhFUl9JTlRFUlZBTFxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMubG9nU3RhdHNJbnRlcnZhbElkID0gc2V0SW50ZXJ2YWwoXG4gICAgICAgICAgICBmdW5jdGlvbigpIHsgc2VsZi5sb2dTdGF0cygpOyB9LFxuICAgICAgICAgICAgdGhpcy5MT0dfSU5URVJWQUwpO1xuICAgIH1cbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgYSBjZXJ0YWluIHJlY29yZCBzaG91bGQgYmUgaW5jbHVkZWQgaW4gdGhlIGxvZ2dlZCBzdGF0aXN0aWNzLlxuICovXG5mdW5jdGlvbiBhY2NlcHRTdGF0KHJlcG9ydElkLCByZXBvcnRUeXBlLCBzdGF0TmFtZSkge1xuICAgIGlmIChyZXBvcnRUeXBlID09IFwiZ29vZ0NhbmRpZGF0ZVBhaXJcIiAmJiBzdGF0TmFtZSA9PSBcImdvb2dDaGFubmVsSWRcIilcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuXG4gICAgaWYgKHJlcG9ydFR5cGUgPT0gXCJzc3JjXCIpIHtcbiAgICAgICAgaWYgKHN0YXROYW1lID09IFwiZ29vZ1RyYWNrSWRcIiB8fFxuICAgICAgICAgICAgc3RhdE5hbWUgPT0gXCJ0cmFuc3BvcnRJZFwiIHx8XG4gICAgICAgICAgICBzdGF0TmFtZSA9PSBcInNzcmNcIilcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhIGNlcnRhaW4gcmVjb3JkIHNob3VsZCBiZSBpbmNsdWRlZCBpbiB0aGUgbG9nZ2VkIHN0YXRpc3RpY3MuXG4gKi9cbmZ1bmN0aW9uIGFjY2VwdFJlcG9ydChpZCwgdHlwZSkge1xuICAgIGlmIChpZC5zdWJzdHJpbmcoMCwgMTUpID09IFwiZ29vZ0NlcnRpZmljYXRlXCIgfHxcbiAgICAgICAgaWQuc3Vic3RyaW5nKDAsIDkpID09IFwiZ29vZ1RyYWNrXCIgfHxcbiAgICAgICAgaWQuc3Vic3RyaW5nKDAsIDIwKSA9PSBcImdvb2dMaWJqaW5nbGVTZXNzaW9uXCIpXG4gICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgIGlmICh0eXBlID09IFwiZ29vZ0NvbXBvbmVudFwiKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgc3RhdHMgdG8gdGhlIGZvcm1hdCB1c2VkIGZvciBsb2dnaW5nLCBhbmQgc2F2ZXMgdGhlIGRhdGEgaW5cbiAqIHRoaXMuc3RhdHNUb0JlTG9nZ2VkLlxuICogQHBhcmFtIHJlcG9ydHMgUmVwb3J0cyBhcyBnaXZlbiBieSB3ZWJraXRSVENQZXJDb25uZWN0aW9uLmdldFN0YXRzLlxuICovXG5TdGF0c0NvbGxlY3Rvci5wcm90b3R5cGUuYWRkU3RhdHNUb0JlTG9nZ2VkID0gZnVuY3Rpb24gKHJlcG9ydHMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIG51bV9yZWNvcmRzID0gdGhpcy5zdGF0c1RvQmVMb2dnZWQudGltZXN0YW1wcy5sZW5ndGg7XG4gICAgdGhpcy5zdGF0c1RvQmVMb2dnZWQudGltZXN0YW1wcy5wdXNoKG5ldyBEYXRlKCkuZ2V0VGltZSgpKTtcbiAgICByZXBvcnRzLm1hcChmdW5jdGlvbiAocmVwb3J0KSB7XG4gICAgICAgIGlmICghYWNjZXB0UmVwb3J0KHJlcG9ydC5pZCwgcmVwb3J0LnR5cGUpKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB2YXIgc3RhdCA9IHNlbGYuc3RhdHNUb0JlTG9nZ2VkLnN0YXRzW3JlcG9ydC5pZF07XG4gICAgICAgIGlmICghc3RhdCkge1xuICAgICAgICAgICAgc3RhdCA9IHNlbGYuc3RhdHNUb0JlTG9nZ2VkLnN0YXRzW3JlcG9ydC5pZF0gPSB7fTtcbiAgICAgICAgfVxuICAgICAgICBzdGF0LnR5cGUgPSByZXBvcnQudHlwZTtcbiAgICAgICAgcmVwb3J0Lm5hbWVzKCkubWFwKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICBpZiAoIWFjY2VwdFN0YXQocmVwb3J0LmlkLCByZXBvcnQudHlwZSwgbmFtZSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgdmFyIHZhbHVlcyA9IHN0YXRbbmFtZV07XG4gICAgICAgICAgICBpZiAoIXZhbHVlcykge1xuICAgICAgICAgICAgICAgIHZhbHVlcyA9IHN0YXRbbmFtZV0gPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHdoaWxlICh2YWx1ZXMubGVuZ3RoIDwgbnVtX3JlY29yZHMpIHtcbiAgICAgICAgICAgICAgICB2YWx1ZXMucHVzaChudWxsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhbHVlcy5wdXNoKHJlcG9ydC5zdGF0KG5hbWUpKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59O1xuXG5TdGF0c0NvbGxlY3Rvci5wcm90b3R5cGUubG9nU3RhdHMgPSBmdW5jdGlvbiAoKSB7XG5cbiAgICBpZighQVBQLnhtcHAuc2VuZExvZ3ModGhpcy5zdGF0c1RvQmVMb2dnZWQpKVxuICAgICAgICByZXR1cm47XG4gICAgLy8gUmVzZXQgdGhlIHN0YXRzXG4gICAgdGhpcy5zdGF0c1RvQmVMb2dnZWQuc3RhdHMgPSB7fTtcbiAgICB0aGlzLnN0YXRzVG9CZUxvZ2dlZC50aW1lc3RhbXBzID0gW107XG59O1xudmFyIGtleU1hcCA9IHt9O1xua2V5TWFwW1JUQ0Jyb3dzZXJUeXBlLlJUQ19CUk9XU0VSX0ZJUkVGT1hdID0ge1xuICAgIFwic3NyY1wiOiBcInNzcmNcIixcbiAgICBcInBhY2tldHNSZWNlaXZlZFwiOiBcInBhY2tldHNSZWNlaXZlZFwiLFxuICAgIFwicGFja2V0c0xvc3RcIjogXCJwYWNrZXRzTG9zdFwiLFxuICAgIFwicGFja2V0c1NlbnRcIjogXCJwYWNrZXRzU2VudFwiLFxuICAgIFwiYnl0ZXNSZWNlaXZlZFwiOiBcImJ5dGVzUmVjZWl2ZWRcIixcbiAgICBcImJ5dGVzU2VudFwiOiBcImJ5dGVzU2VudFwiXG59O1xua2V5TWFwW1JUQ0Jyb3dzZXJUeXBlLlJUQ19CUk9XU0VSX0NIUk9NRV0gPSB7XG4gICAgXCJyZWNlaXZlQmFuZHdpZHRoXCI6IFwiZ29vZ0F2YWlsYWJsZVJlY2VpdmVCYW5kd2lkdGhcIixcbiAgICBcInNlbmRCYW5kd2lkdGhcIjogXCJnb29nQXZhaWxhYmxlU2VuZEJhbmR3aWR0aFwiLFxuICAgIFwicmVtb3RlQWRkcmVzc1wiOiBcImdvb2dSZW1vdGVBZGRyZXNzXCIsXG4gICAgXCJ0cmFuc3BvcnRUeXBlXCI6IFwiZ29vZ1RyYW5zcG9ydFR5cGVcIixcbiAgICBcImxvY2FsQWRkcmVzc1wiOiBcImdvb2dMb2NhbEFkZHJlc3NcIixcbiAgICBcImFjdGl2ZUNvbm5lY3Rpb25cIjogXCJnb29nQWN0aXZlQ29ubmVjdGlvblwiLFxuICAgIFwic3NyY1wiOiBcInNzcmNcIixcbiAgICBcInBhY2tldHNSZWNlaXZlZFwiOiBcInBhY2tldHNSZWNlaXZlZFwiLFxuICAgIFwicGFja2V0c1NlbnRcIjogXCJwYWNrZXRzU2VudFwiLFxuICAgIFwicGFja2V0c0xvc3RcIjogXCJwYWNrZXRzTG9zdFwiLFxuICAgIFwiYnl0ZXNSZWNlaXZlZFwiOiBcImJ5dGVzUmVjZWl2ZWRcIixcbiAgICBcImJ5dGVzU2VudFwiOiBcImJ5dGVzU2VudFwiLFxuICAgIFwiZ29vZ0ZyYW1lSGVpZ2h0UmVjZWl2ZWRcIjogXCJnb29nRnJhbWVIZWlnaHRSZWNlaXZlZFwiLFxuICAgIFwiZ29vZ0ZyYW1lV2lkdGhSZWNlaXZlZFwiOiBcImdvb2dGcmFtZVdpZHRoUmVjZWl2ZWRcIixcbiAgICBcImdvb2dGcmFtZUhlaWdodFNlbnRcIjogXCJnb29nRnJhbWVIZWlnaHRTZW50XCIsXG4gICAgXCJnb29nRnJhbWVXaWR0aFNlbnRcIjogXCJnb29nRnJhbWVXaWR0aFNlbnRcIixcbiAgICBcImF1ZGlvSW5wdXRMZXZlbFwiOiBcImF1ZGlvSW5wdXRMZXZlbFwiLFxuICAgIFwiYXVkaW9PdXRwdXRMZXZlbFwiOiBcImF1ZGlvT3V0cHV0TGV2ZWxcIlxufTtcblxuXG4vKipcbiAqIFN0YXRzIHByb2Nlc3NpbmcgbG9naWMuXG4gKi9cblN0YXRzQ29sbGVjdG9yLnByb3RvdHlwZS5wcm9jZXNzU3RhdHNSZXBvcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLmJhc2VsaW5lU3RhdHNSZXBvcnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGZvciAodmFyIGlkeCBpbiB0aGlzLmN1cnJlbnRTdGF0c1JlcG9ydCkge1xuICAgICAgICB2YXIgbm93ID0gdGhpcy5jdXJyZW50U3RhdHNSZXBvcnRbaWR4XTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmIChnZXRTdGF0VmFsdWUobm93LCAncmVjZWl2ZUJhbmR3aWR0aCcpIHx8XG4gICAgICAgICAgICAgICAgZ2V0U3RhdFZhbHVlKG5vdywgJ3NlbmRCYW5kd2lkdGgnKSkge1xuICAgICAgICAgICAgICAgIFBlZXJTdGF0cy5iYW5kd2lkdGggPSB7XG4gICAgICAgICAgICAgICAgICAgIFwiZG93bmxvYWRcIjogTWF0aC5yb3VuZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZ2V0U3RhdFZhbHVlKG5vdywgJ3JlY2VpdmVCYW5kd2lkdGgnKSkgLyAxMDAwKSxcbiAgICAgICAgICAgICAgICAgICAgXCJ1cGxvYWRcIjogTWF0aC5yb3VuZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZ2V0U3RhdFZhbHVlKG5vdywgJ3NlbmRCYW5kd2lkdGgnKSkgLyAxMDAwKVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2goZSl7Lypub3Qgc3VwcG9ydGVkKi99XG5cbiAgICAgICAgaWYobm93LnR5cGUgPT0gJ2dvb2dDYW5kaWRhdGVQYWlyJylcbiAgICAgICAge1xuICAgICAgICAgICAgdmFyIGlwLCB0eXBlLCBsb2NhbElQLCBhY3RpdmU7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGlwID0gZ2V0U3RhdFZhbHVlKG5vdywgJ3JlbW90ZUFkZHJlc3MnKTtcbiAgICAgICAgICAgICAgICB0eXBlID0gZ2V0U3RhdFZhbHVlKG5vdywgXCJ0cmFuc3BvcnRUeXBlXCIpO1xuICAgICAgICAgICAgICAgIGxvY2FsSVAgPSBnZXRTdGF0VmFsdWUobm93LCBcImxvY2FsQWRkcmVzc1wiKTtcbiAgICAgICAgICAgICAgICBhY3RpdmUgPSBnZXRTdGF0VmFsdWUobm93LCBcImFjdGl2ZUNvbm5lY3Rpb25cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaChlKXsvKm5vdCBzdXBwb3J0ZWQqL31cbiAgICAgICAgICAgIGlmKCFpcCB8fCAhdHlwZSB8fCAhbG9jYWxJUCB8fCBhY3RpdmUgIT0gXCJ0cnVlXCIpXG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB2YXIgYWRkcmVzc1NhdmVkID0gZmFsc2U7XG4gICAgICAgICAgICBmb3IodmFyIGkgPSAwOyBpIDwgUGVlclN0YXRzLnRyYW5zcG9ydC5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBpZihQZWVyU3RhdHMudHJhbnNwb3J0W2ldLmlwID09IGlwICYmXG4gICAgICAgICAgICAgICAgICAgIFBlZXJTdGF0cy50cmFuc3BvcnRbaV0udHlwZSA9PSB0eXBlICYmXG4gICAgICAgICAgICAgICAgICAgIFBlZXJTdGF0cy50cmFuc3BvcnRbaV0ubG9jYWxpcCA9PSBsb2NhbElQKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgYWRkcmVzc1NhdmVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZihhZGRyZXNzU2F2ZWQpXG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICBQZWVyU3RhdHMudHJhbnNwb3J0LnB1c2goe2xvY2FsaXA6IGxvY2FsSVAsIGlwOiBpcCwgdHlwZTogdHlwZX0pO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZihub3cudHlwZSA9PSBcImNhbmRpZGF0ZXBhaXJcIilcbiAgICAgICAge1xuICAgICAgICAgICAgaWYobm93LnN0YXRlID09IFwic3VjY2VlZGVkXCIpXG4gICAgICAgICAgICAgICAgY29udGludWU7XG5cbiAgICAgICAgICAgIHZhciBsb2NhbCA9IHRoaXMuY3VycmVudFN0YXRzUmVwb3J0W25vdy5sb2NhbENhbmRpZGF0ZUlkXTtcbiAgICAgICAgICAgIHZhciByZW1vdGUgPSB0aGlzLmN1cnJlbnRTdGF0c1JlcG9ydFtub3cucmVtb3RlQ2FuZGlkYXRlSWRdO1xuICAgICAgICAgICAgUGVlclN0YXRzLnRyYW5zcG9ydC5wdXNoKHtsb2NhbGlwOiBsb2NhbC5pcEFkZHJlc3MgKyBcIjpcIiArIGxvY2FsLnBvcnROdW1iZXIsXG4gICAgICAgICAgICAgICAgaXA6IHJlbW90ZS5pcEFkZHJlc3MgKyBcIjpcIiArIHJlbW90ZS5wb3J0TnVtYmVyLCB0eXBlOiBsb2NhbC50cmFuc3BvcnR9KTtcblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG5vdy50eXBlICE9ICdzc3JjJyAmJiBub3cudHlwZSAhPSBcIm91dGJvdW5kcnRwXCIgJiZcbiAgICAgICAgICAgIG5vdy50eXBlICE9IFwiaW5ib3VuZHJ0cFwiKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBiZWZvcmUgPSB0aGlzLmJhc2VsaW5lU3RhdHNSZXBvcnRbaWR4XTtcbiAgICAgICAgaWYgKCFiZWZvcmUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihnZXRTdGF0VmFsdWUobm93LCAnc3NyYycpICsgJyBub3QgZW5vdWdoIGRhdGEnKTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHNzcmMgPSBnZXRTdGF0VmFsdWUobm93LCAnc3NyYycpO1xuICAgICAgICBpZighc3NyYylcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB2YXIgamlkID0gQVBQLnhtcHAuZ2V0SmlkRnJvbVNTUkMoc3NyYyk7XG4gICAgICAgIGlmICghamlkICYmIChEYXRlLm5vdygpIC0gbm93LnRpbWVzdGFtcCkgPCAzMDAwKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJObyBqaWQgZm9yIHNzcmM6IFwiICsgc3NyYyk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBqaWRTdGF0cyA9IHRoaXMuamlkMnN0YXRzW2ppZF07XG4gICAgICAgIGlmICghamlkU3RhdHMpIHtcbiAgICAgICAgICAgIGppZFN0YXRzID0gbmV3IFBlZXJTdGF0cygpO1xuICAgICAgICAgICAgdGhpcy5qaWQyc3RhdHNbamlkXSA9IGppZFN0YXRzO1xuICAgICAgICB9XG5cblxuICAgICAgICB2YXIgaXNEb3dubG9hZFN0cmVhbSA9IHRydWU7XG4gICAgICAgIHZhciBrZXkgPSAncGFja2V0c1JlY2VpdmVkJztcbiAgICAgICAgaWYgKCFnZXRTdGF0VmFsdWUobm93LCBrZXkpKVxuICAgICAgICB7XG4gICAgICAgICAgICBpc0Rvd25sb2FkU3RyZWFtID0gZmFsc2U7XG4gICAgICAgICAgICBrZXkgPSAncGFja2V0c1NlbnQnO1xuICAgICAgICAgICAgaWYgKCFnZXRTdGF0VmFsdWUobm93LCBrZXkpKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIk5vIHBhY2tldHNSZWNlaXZlZCBub3IgcGFja2V0U2VudCBzdGF0IGZvdW5kXCIpO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHZhciBwYWNrZXRzTm93ID0gZ2V0U3RhdFZhbHVlKG5vdywga2V5KTtcbiAgICAgICAgaWYoIXBhY2tldHNOb3cgfHwgcGFja2V0c05vdyA8IDApXG4gICAgICAgICAgICBwYWNrZXRzTm93ID0gMDtcblxuICAgICAgICB2YXIgcGFja2V0c0JlZm9yZSA9IGdldFN0YXRWYWx1ZShiZWZvcmUsIGtleSk7XG4gICAgICAgIGlmKCFwYWNrZXRzQmVmb3JlIHx8IHBhY2tldHNCZWZvcmUgPCAwKVxuICAgICAgICAgICAgcGFja2V0c0JlZm9yZSA9IDA7XG4gICAgICAgIHZhciBwYWNrZXRSYXRlID0gcGFja2V0c05vdyAtIHBhY2tldHNCZWZvcmU7XG4gICAgICAgIGlmKCFwYWNrZXRSYXRlIHx8IHBhY2tldFJhdGUgPCAwKVxuICAgICAgICAgICAgcGFja2V0UmF0ZSA9IDA7XG4gICAgICAgIHZhciBjdXJyZW50TG9zcyA9IGdldFN0YXRWYWx1ZShub3csICdwYWNrZXRzTG9zdCcpO1xuICAgICAgICBpZighY3VycmVudExvc3MgfHwgY3VycmVudExvc3MgPCAwKVxuICAgICAgICAgICAgY3VycmVudExvc3MgPSAwO1xuICAgICAgICB2YXIgcHJldmlvdXNMb3NzID0gZ2V0U3RhdFZhbHVlKGJlZm9yZSwgJ3BhY2tldHNMb3N0Jyk7XG4gICAgICAgIGlmKCFwcmV2aW91c0xvc3MgfHwgcHJldmlvdXNMb3NzIDwgMClcbiAgICAgICAgICAgIHByZXZpb3VzTG9zcyA9IDA7XG4gICAgICAgIHZhciBsb3NzUmF0ZSA9IGN1cnJlbnRMb3NzIC0gcHJldmlvdXNMb3NzO1xuICAgICAgICBpZighbG9zc1JhdGUgfHwgbG9zc1JhdGUgPCAwKVxuICAgICAgICAgICAgbG9zc1JhdGUgPSAwO1xuICAgICAgICB2YXIgcGFja2V0c1RvdGFsID0gKHBhY2tldFJhdGUgKyBsb3NzUmF0ZSk7XG5cbiAgICAgICAgamlkU3RhdHMuc2V0U3NyY0xvc3Moc3NyYyxcbiAgICAgICAgICAgIHtcInBhY2tldHNUb3RhbFwiOiBwYWNrZXRzVG90YWwsXG4gICAgICAgICAgICAgICAgXCJwYWNrZXRzTG9zdFwiOiBsb3NzUmF0ZSxcbiAgICAgICAgICAgICAgICBcImlzRG93bmxvYWRTdHJlYW1cIjogaXNEb3dubG9hZFN0cmVhbX0pO1xuXG5cbiAgICAgICAgdmFyIGJ5dGVzUmVjZWl2ZWQgPSAwLCBieXRlc1NlbnQgPSAwO1xuICAgICAgICBpZihnZXRTdGF0VmFsdWUobm93LCBcImJ5dGVzUmVjZWl2ZWRcIikpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGJ5dGVzUmVjZWl2ZWQgPSBnZXRTdGF0VmFsdWUobm93LCBcImJ5dGVzUmVjZWl2ZWRcIikgLVxuICAgICAgICAgICAgICAgIGdldFN0YXRWYWx1ZShiZWZvcmUsIFwiYnl0ZXNSZWNlaXZlZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKGdldFN0YXRWYWx1ZShub3csIFwiYnl0ZXNTZW50XCIpKVxuICAgICAgICB7XG4gICAgICAgICAgICBieXRlc1NlbnQgPSBnZXRTdGF0VmFsdWUobm93LCBcImJ5dGVzU2VudFwiKSAtXG4gICAgICAgICAgICAgICAgZ2V0U3RhdFZhbHVlKGJlZm9yZSwgXCJieXRlc1NlbnRcIik7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgdGltZSA9IE1hdGgucm91bmQoKG5vdy50aW1lc3RhbXAgLSBiZWZvcmUudGltZXN0YW1wKSAvIDEwMDApO1xuICAgICAgICBpZihieXRlc1JlY2VpdmVkIDw9IDAgfHwgdGltZSA8PSAwKVxuICAgICAgICB7XG4gICAgICAgICAgICBieXRlc1JlY2VpdmVkID0gMDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIGJ5dGVzUmVjZWl2ZWQgPSBNYXRoLnJvdW5kKCgoYnl0ZXNSZWNlaXZlZCAqIDgpIC8gdGltZSkgLyAxMDAwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKGJ5dGVzU2VudCA8PSAwIHx8IHRpbWUgPD0gMClcbiAgICAgICAge1xuICAgICAgICAgICAgYnl0ZXNTZW50ID0gMDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIGJ5dGVzU2VudCA9IE1hdGgucm91bmQoKChieXRlc1NlbnQgKiA4KSAvIHRpbWUpIC8gMTAwMCk7XG4gICAgICAgIH1cblxuICAgICAgICBqaWRTdGF0cy5zZXRTc3JjQml0cmF0ZShzc3JjLCB7XG4gICAgICAgICAgICBcImRvd25sb2FkXCI6IGJ5dGVzUmVjZWl2ZWQsXG4gICAgICAgICAgICBcInVwbG9hZFwiOiBieXRlc1NlbnR9KTtcblxuICAgICAgICB2YXIgcmVzb2x1dGlvbiA9IHtoZWlnaHQ6IG51bGwsIHdpZHRoOiBudWxsfTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmIChnZXRTdGF0VmFsdWUobm93LCBcImdvb2dGcmFtZUhlaWdodFJlY2VpdmVkXCIpICYmXG4gICAgICAgICAgICAgICAgZ2V0U3RhdFZhbHVlKG5vdywgXCJnb29nRnJhbWVXaWR0aFJlY2VpdmVkXCIpKSB7XG4gICAgICAgICAgICAgICAgcmVzb2x1dGlvbi5oZWlnaHQgPSBnZXRTdGF0VmFsdWUobm93LCBcImdvb2dGcmFtZUhlaWdodFJlY2VpdmVkXCIpO1xuICAgICAgICAgICAgICAgIHJlc29sdXRpb24ud2lkdGggPSBnZXRTdGF0VmFsdWUobm93LCBcImdvb2dGcmFtZVdpZHRoUmVjZWl2ZWRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChnZXRTdGF0VmFsdWUobm93LCBcImdvb2dGcmFtZUhlaWdodFNlbnRcIikgJiZcbiAgICAgICAgICAgICAgICBnZXRTdGF0VmFsdWUobm93LCBcImdvb2dGcmFtZVdpZHRoU2VudFwiKSkge1xuICAgICAgICAgICAgICAgIHJlc29sdXRpb24uaGVpZ2h0ID0gZ2V0U3RhdFZhbHVlKG5vdywgXCJnb29nRnJhbWVIZWlnaHRTZW50XCIpO1xuICAgICAgICAgICAgICAgIHJlc29sdXRpb24ud2lkdGggPSBnZXRTdGF0VmFsdWUobm93LCBcImdvb2dGcmFtZVdpZHRoU2VudFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjYXRjaChlKXsvKm5vdCBzdXBwb3J0ZWQqL31cblxuICAgICAgICBpZihyZXNvbHV0aW9uLmhlaWdodCAmJiByZXNvbHV0aW9uLndpZHRoKVxuICAgICAgICB7XG4gICAgICAgICAgICBqaWRTdGF0cy5zZXRTc3JjUmVzb2x1dGlvbihzc3JjLCByZXNvbHV0aW9uKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIGppZFN0YXRzLnNldFNzcmNSZXNvbHV0aW9uKHNzcmMsIG51bGwpO1xuICAgICAgICB9XG5cblxuICAgIH1cblxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAvLyBKaWQgc3RhdHNcbiAgICB2YXIgdG90YWxQYWNrZXRzID0ge2Rvd25sb2FkOiAwLCB1cGxvYWQ6IDB9O1xuICAgIHZhciBsb3N0UGFja2V0cyA9IHtkb3dubG9hZDogMCwgdXBsb2FkOiAwfTtcbiAgICB2YXIgYml0cmF0ZURvd25sb2FkID0gMDtcbiAgICB2YXIgYml0cmF0ZVVwbG9hZCA9IDA7XG4gICAgdmFyIHJlc29sdXRpb25zID0ge307XG4gICAgT2JqZWN0LmtleXModGhpcy5qaWQyc3RhdHMpLmZvckVhY2goXG4gICAgICAgIGZ1bmN0aW9uIChqaWQpXG4gICAgICAgIHtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHNlbGYuamlkMnN0YXRzW2ppZF0uc3NyYzJMb3NzKS5mb3JFYWNoKFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChzc3JjKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHR5cGUgPSBcInVwbG9hZFwiO1xuICAgICAgICAgICAgICAgICAgICBpZihzZWxmLmppZDJzdGF0c1tqaWRdLnNzcmMyTG9zc1tzc3JjXS5pc0Rvd25sb2FkU3RyZWFtKVxuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9IFwiZG93bmxvYWRcIjtcbiAgICAgICAgICAgICAgICAgICAgdG90YWxQYWNrZXRzW3R5cGVdICs9XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmppZDJzdGF0c1tqaWRdLnNzcmMyTG9zc1tzc3JjXS5wYWNrZXRzVG90YWw7XG4gICAgICAgICAgICAgICAgICAgIGxvc3RQYWNrZXRzW3R5cGVdICs9XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmppZDJzdGF0c1tqaWRdLnNzcmMyTG9zc1tzc3JjXS5wYWNrZXRzTG9zdDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgT2JqZWN0LmtleXMoc2VsZi5qaWQyc3RhdHNbamlkXS5zc3JjMmJpdHJhdGUpLmZvckVhY2goXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgICAgICAgICAgICAgYml0cmF0ZURvd25sb2FkICs9XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmppZDJzdGF0c1tqaWRdLnNzcmMyYml0cmF0ZVtzc3JjXS5kb3dubG9hZDtcbiAgICAgICAgICAgICAgICAgICAgYml0cmF0ZVVwbG9hZCArPVxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5qaWQyc3RhdHNbamlkXS5zc3JjMmJpdHJhdGVbc3NyY10udXBsb2FkO1xuXG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBzZWxmLmppZDJzdGF0c1tqaWRdLnNzcmMyYml0cmF0ZVtzc3JjXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmVzb2x1dGlvbnNbamlkXSA9IHNlbGYuamlkMnN0YXRzW2ppZF0uc3NyYzJyZXNvbHV0aW9uO1xuICAgICAgICB9XG4gICAgKTtcblxuICAgIFBlZXJTdGF0cy5iaXRyYXRlID0ge1widXBsb2FkXCI6IGJpdHJhdGVVcGxvYWQsIFwiZG93bmxvYWRcIjogYml0cmF0ZURvd25sb2FkfTtcblxuICAgIFBlZXJTdGF0cy5wYWNrZXRMb3NzID0ge1xuICAgICAgICB0b3RhbDpcbiAgICAgICAgICAgIGNhbGN1bGF0ZVBhY2tldExvc3MobG9zdFBhY2tldHMuZG93bmxvYWQgKyBsb3N0UGFja2V0cy51cGxvYWQsXG4gICAgICAgICAgICAgICAgICAgIHRvdGFsUGFja2V0cy5kb3dubG9hZCArIHRvdGFsUGFja2V0cy51cGxvYWQpLFxuICAgICAgICBkb3dubG9hZDpcbiAgICAgICAgICAgIGNhbGN1bGF0ZVBhY2tldExvc3MobG9zdFBhY2tldHMuZG93bmxvYWQsIHRvdGFsUGFja2V0cy5kb3dubG9hZCksXG4gICAgICAgIHVwbG9hZDpcbiAgICAgICAgICAgIGNhbGN1bGF0ZVBhY2tldExvc3MobG9zdFBhY2tldHMudXBsb2FkLCB0b3RhbFBhY2tldHMudXBsb2FkKVxuICAgIH07XG4gICAgdGhpcy5ldmVudEVtaXR0ZXIuZW1pdChcInN0YXRpc3RpY3MuY29ubmVjdGlvbnN0YXRzXCIsXG4gICAgICAgIHtcbiAgICAgICAgICAgIFwiYml0cmF0ZVwiOiBQZWVyU3RhdHMuYml0cmF0ZSxcbiAgICAgICAgICAgIFwicGFja2V0TG9zc1wiOiBQZWVyU3RhdHMucGFja2V0TG9zcyxcbiAgICAgICAgICAgIFwiYmFuZHdpZHRoXCI6IFBlZXJTdGF0cy5iYW5kd2lkdGgsXG4gICAgICAgICAgICBcInJlc29sdXRpb25cIjogcmVzb2x1dGlvbnMsXG4gICAgICAgICAgICBcInRyYW5zcG9ydFwiOiBQZWVyU3RhdHMudHJhbnNwb3J0XG4gICAgICAgIH0pO1xuICAgIFBlZXJTdGF0cy50cmFuc3BvcnQgPSBbXTtcblxufTtcblxuLyoqXG4gKiBTdGF0cyBwcm9jZXNzaW5nIGxvZ2ljLlxuICovXG5TdGF0c0NvbGxlY3Rvci5wcm90b3R5cGUucHJvY2Vzc0F1ZGlvTGV2ZWxSZXBvcnQgPSBmdW5jdGlvbiAoKVxue1xuICAgIGlmICghdGhpcy5iYXNlbGluZUF1ZGlvTGV2ZWxzUmVwb3J0KVxuICAgIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGZvciAodmFyIGlkeCBpbiB0aGlzLmN1cnJlbnRBdWRpb0xldmVsc1JlcG9ydClcbiAgICB7XG4gICAgICAgIHZhciBub3cgPSB0aGlzLmN1cnJlbnRBdWRpb0xldmVsc1JlcG9ydFtpZHhdO1xuXG4gICAgICAgIGlmIChub3cudHlwZSAhPSAnc3NyYycpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZSA9IHRoaXMuYmFzZWxpbmVBdWRpb0xldmVsc1JlcG9ydFtpZHhdO1xuICAgICAgICBpZiAoIWJlZm9yZSlcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGdldFN0YXRWYWx1ZShub3csICdzc3JjJykgKyAnIG5vdCBlbm91Z2ggZGF0YScpO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc3NyYyA9IGdldFN0YXRWYWx1ZShub3csICdzc3JjJyk7XG4gICAgICAgIHZhciBqaWQgPSBBUFAueG1wcC5nZXRKaWRGcm9tU1NSQyhzc3JjKTtcbiAgICAgICAgaWYgKCFqaWQgJiYgKERhdGUubm93KCkgLSBub3cudGltZXN0YW1wKSA8IDMwMDApXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIk5vIGppZCBmb3Igc3NyYzogXCIgKyBzc3JjKTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGppZFN0YXRzID0gdGhpcy5qaWQyc3RhdHNbamlkXTtcbiAgICAgICAgaWYgKCFqaWRTdGF0cylcbiAgICAgICAge1xuICAgICAgICAgICAgamlkU3RhdHMgPSBuZXcgUGVlclN0YXRzKCk7XG4gICAgICAgICAgICB0aGlzLmppZDJzdGF0c1tqaWRdID0gamlkU3RhdHM7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBdWRpbyBsZXZlbFxuICAgICAgICB2YXIgYXVkaW9MZXZlbCA9IG51bGw7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF1ZGlvTGV2ZWwgPSBnZXRTdGF0VmFsdWUobm93LCAnYXVkaW9JbnB1dExldmVsJyk7XG4gICAgICAgICAgICBpZiAoIWF1ZGlvTGV2ZWwpXG4gICAgICAgICAgICAgICAgYXVkaW9MZXZlbCA9IGdldFN0YXRWYWx1ZShub3csICdhdWRpb091dHB1dExldmVsJyk7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2goZSkgey8qbm90IHN1cHBvcnRlZCovXG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJBdWRpbyBMZXZlbHMgYXJlIG5vdCBhdmFpbGFibGUgaW4gdGhlIHN0YXRpc3RpY3MuXCIpO1xuICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmF1ZGlvTGV2ZWxzSW50ZXJ2YWxJZCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYXVkaW9MZXZlbClcbiAgICAgICAge1xuICAgICAgICAgICAgLy8gVE9ETzogY2FuJ3QgZmluZCBzcGVjcyBhYm91dCB3aGF0IHRoaXMgdmFsdWUgcmVhbGx5IGlzLFxuICAgICAgICAgICAgLy8gYnV0IGl0IHNlZW1zIHRvIHZhcnkgYmV0d2VlbiAwIGFuZCBhcm91bmQgMzJrLlxuICAgICAgICAgICAgYXVkaW9MZXZlbCA9IGF1ZGlvTGV2ZWwgLyAzMjc2NztcbiAgICAgICAgICAgIGppZFN0YXRzLnNldFNzcmNBdWRpb0xldmVsKHNzcmMsIGF1ZGlvTGV2ZWwpO1xuICAgICAgICAgICAgaWYoamlkICE9IEFQUC54bXBwLm15SmlkKCkpXG4gICAgICAgICAgICAgICAgdGhpcy5ldmVudEVtaXR0ZXIuZW1pdChcInN0YXRpc3RpY3MuYXVkaW9MZXZlbFwiLCBqaWQsIGF1ZGlvTGV2ZWwpO1xuICAgICAgICB9XG5cbiAgICB9XG5cblxufTtcbiIsIi8qKlxuICogQ3JlYXRlZCBieSBocmlzdG8gb24gOC80LzE0LlxuICovXG52YXIgTG9jYWxTdGF0cyA9IHJlcXVpcmUoXCIuL0xvY2FsU3RhdHNDb2xsZWN0b3IuanNcIik7XG52YXIgUlRQU3RhdHMgPSByZXF1aXJlKFwiLi9SVFBTdGF0c0NvbGxlY3Rvci5qc1wiKTtcbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiZXZlbnRzXCIpO1xudmFyIFN0cmVhbUV2ZW50VHlwZXMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvU3RyZWFtRXZlbnRUeXBlcy5qc1wiKTtcbnZhciBYTVBQRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UveG1wcC9YTVBQRXZlbnRzXCIpO1xuXG52YXIgZXZlbnRFbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG52YXIgbG9jYWxTdGF0cyA9IG51bGw7XG5cbnZhciBydHBTdGF0cyA9IG51bGw7XG5cbmZ1bmN0aW9uIHN0b3BMb2NhbCgpXG57XG4gICAgaWYobG9jYWxTdGF0cylcbiAgICB7XG4gICAgICAgIGxvY2FsU3RhdHMuc3RvcCgpO1xuICAgICAgICBsb2NhbFN0YXRzID0gbnVsbDtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHN0b3BSZW1vdGUoKVxue1xuICAgIGlmKHJ0cFN0YXRzKVxuICAgIHtcbiAgICAgICAgcnRwU3RhdHMuc3RvcCgpO1xuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChcInN0YXRpc3RpY3Muc3RvcFwiKTtcbiAgICAgICAgcnRwU3RhdHMgPSBudWxsO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gc3RhcnRSZW1vdGVTdGF0cyAocGVlcmNvbm5lY3Rpb24pIHtcbiAgICBpZihydHBTdGF0cylcbiAgICB7XG4gICAgICAgIHJ0cFN0YXRzLnN0b3AoKTtcbiAgICAgICAgcnRwU3RhdHMgPSBudWxsO1xuICAgIH1cblxuICAgIHJ0cFN0YXRzID0gbmV3IFJUUFN0YXRzKHBlZXJjb25uZWN0aW9uLCAyMDAsIDIwMDAsIGV2ZW50RW1pdHRlcik7XG4gICAgcnRwU3RhdHMuc3RhcnQoKTtcbn1cblxuZnVuY3Rpb24gb25TdHJlYW1DcmVhdGVkKHN0cmVhbSlcbntcbiAgICBpZihzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKS5nZXRBdWRpb1RyYWNrcygpLmxlbmd0aCA9PT0gMClcbiAgICAgICAgcmV0dXJuO1xuXG4gICAgbG9jYWxTdGF0cyA9IG5ldyBMb2NhbFN0YXRzKHN0cmVhbS5nZXRPcmlnaW5hbFN0cmVhbSgpLCAyMDAsIHN0YXRpc3RpY3MsXG4gICAgICAgIGV2ZW50RW1pdHRlcik7XG4gICAgbG9jYWxTdGF0cy5zdGFydCgpO1xufVxuXG5mdW5jdGlvbiBvbkRpc3Bvc2VDb25mZXJlbmNlKG9uVW5sb2FkKSB7XG4gICAgc3RvcFJlbW90ZSgpO1xuICAgIGlmKG9uVW5sb2FkKSB7XG4gICAgICAgIHN0b3BMb2NhbCgpO1xuICAgICAgICBldmVudEVtaXR0ZXIucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgfVxufVxuXG5cbnZhciBzdGF0aXN0aWNzID1cbntcbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgdGhhdCB0aGlzIGF1ZGlvIGxldmVsIGlzIGZvciBsb2NhbCBqaWQuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBMT0NBTF9KSUQ6ICdsb2NhbCcsXG5cbiAgICBhZGRBdWRpb0xldmVsTGlzdGVuZXI6IGZ1bmN0aW9uKGxpc3RlbmVyKVxuICAgIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLm9uKFwic3RhdGlzdGljcy5hdWRpb0xldmVsXCIsIGxpc3RlbmVyKTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlQXVkaW9MZXZlbExpc3RlbmVyOiBmdW5jdGlvbihsaXN0ZW5lcilcbiAgICB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5yZW1vdmVMaXN0ZW5lcihcInN0YXRpc3RpY3MuYXVkaW9MZXZlbFwiLCBsaXN0ZW5lcik7XG4gICAgfSxcblxuICAgIGFkZENvbm5lY3Rpb25TdGF0c0xpc3RlbmVyOiBmdW5jdGlvbihsaXN0ZW5lcilcbiAgICB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5vbihcInN0YXRpc3RpY3MuY29ubmVjdGlvbnN0YXRzXCIsIGxpc3RlbmVyKTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlQ29ubmVjdGlvblN0YXRzTGlzdGVuZXI6IGZ1bmN0aW9uKGxpc3RlbmVyKVxuICAgIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLnJlbW92ZUxpc3RlbmVyKFwic3RhdGlzdGljcy5jb25uZWN0aW9uc3RhdHNcIiwgbGlzdGVuZXIpO1xuICAgIH0sXG5cblxuICAgIGFkZFJlbW90ZVN0YXRzU3RvcExpc3RlbmVyOiBmdW5jdGlvbihsaXN0ZW5lcilcbiAgICB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5vbihcInN0YXRpc3RpY3Muc3RvcFwiLCBsaXN0ZW5lcik7XG4gICAgfSxcblxuICAgIHJlbW92ZVJlbW90ZVN0YXRzU3RvcExpc3RlbmVyOiBmdW5jdGlvbihsaXN0ZW5lcilcbiAgICB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5yZW1vdmVMaXN0ZW5lcihcInN0YXRpc3RpY3Muc3RvcFwiLCBsaXN0ZW5lcik7XG4gICAgfSxcblxuICAgIHN0b3A6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc3RvcExvY2FsKCk7XG4gICAgICAgIHN0b3BSZW1vdGUoKTtcbiAgICAgICAgaWYoZXZlbnRFbWl0dGVyKVxuICAgICAgICB7XG4gICAgICAgICAgICBldmVudEVtaXR0ZXIucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc3RvcFJlbW90ZVN0YXRpc3RpY3M6IGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICAgIHN0b3BSZW1vdGUoKTtcbiAgICB9LFxuXG4gICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQVBQLlJUQy5hZGRTdHJlYW1MaXN0ZW5lcihvblN0cmVhbUNyZWF0ZWQsXG4gICAgICAgICAgICBTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfTE9DQUxfQ1JFQVRFRCk7XG4gICAgICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuRElTUE9TRV9DT05GRVJFTkNFLCBvbkRpc3Bvc2VDb25mZXJlbmNlKTtcbiAgICAgICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5DQUxMX0lOQ09NSU5HLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIHN0YXJ0UmVtb3RlU3RhdHMoZXZlbnQucGVlcmNvbm5lY3Rpb24pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbn07XG5cblxuXG5cbm1vZHVsZS5leHBvcnRzID0gc3RhdGlzdGljczsiLCJ2YXIgaTE4biA9IHJlcXVpcmUoXCJpMThuZXh0LWNsaWVudFwiKTtcbnZhciBsYW5ndWFnZXMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS90cmFuc2xhdGlvbi9sYW5ndWFnZXNcIik7XG52YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi4vc2V0dGluZ3MvU2V0dGluZ3NcIik7XG52YXIgREVGQVVMVF9MQU5HID0gbGFuZ3VhZ2VzLkVOO1xuXG5pMThuLmFkZFBvc3RQcm9jZXNzb3IoXCJyZXNvbHZlQXBwTmFtZVwiLCBmdW5jdGlvbih2YWx1ZSwga2V5LCBvcHRpb25zKSB7XG4gICAgcmV0dXJuIHZhbHVlLnJlcGxhY2UoXCJfX2FwcF9fXCIsIGludGVyZmFjZUNvbmZpZy5BUFBfTkFNRSk7XG59KTtcblxuXG5cbnZhciBkZWZhdWx0T3B0aW9ucyA9IHtcbiAgICBkZXRlY3RMbmdRUzogXCJsYW5nXCIsXG4gICAgdXNlQ29va2llOiBmYWxzZSxcbiAgICBmYWxsYmFja0xuZzogREVGQVVMVF9MQU5HLFxuICAgIGxvYWQ6IFwidW5zcGVjaWZpY1wiLFxuICAgIHJlc0dldFBhdGg6ICdsYW5nL19fbnNfXy1fX2xuZ19fLmpzb24nLFxuICAgIG5zOiB7XG4gICAgICAgIG5hbWVzcGFjZXM6IFsnbWFpbicsICdsYW5ndWFnZXMnXSxcbiAgICAgICAgZGVmYXVsdE5zOiAnbWFpbidcbiAgICB9LFxuICAgIGxuZ1doaXRlbGlzdCA6IGxhbmd1YWdlcy5nZXRMYW5ndWFnZXMoKSxcbiAgICBmYWxsYmFja09uTnVsbDogdHJ1ZSxcbiAgICBmYWxsYmFja09uRW1wdHk6IHRydWUsXG4gICAgdXNlRGF0YUF0dHJPcHRpb25zOiB0cnVlLFxuICAgIGRlZmF1bHRWYWx1ZUZyb21Db250ZW50OiBmYWxzZSxcbiAgICBhcHA6IGludGVyZmFjZUNvbmZpZy5BUFBfTkFNRSxcbiAgICBnZXRBc3luYzogZmFsc2UsXG4gICAgZGVmYXVsdFZhbHVlRnJvbUNvbnRlbnQ6IGZhbHNlLFxuICAgIGN1c3RvbUxvYWQ6IGZ1bmN0aW9uKGxuZywgbnMsIG9wdGlvbnMsIGRvbmUpIHtcbiAgICAgICAgdmFyIHJlc1BhdGggPSBcImxhbmcvX19uc19fLV9fbG5nX18uanNvblwiO1xuICAgICAgICBpZihsbmcgPT09IGxhbmd1YWdlcy5FTilcbiAgICAgICAgICAgIHJlc1BhdGggPSBcImxhbmcvX19uc19fLmpzb25cIjtcbiAgICAgICAgdmFyIHVybCA9IGkxOG4uZnVuY3Rpb25zLmFwcGx5UmVwbGFjZW1lbnQocmVzUGF0aCwgeyBsbmc6IGxuZywgbnM6IG5zIH0pO1xuICAgICAgICBpMThuLmZ1bmN0aW9ucy5hamF4KHtcbiAgICAgICAgICAgIHVybDogdXJsLFxuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24oZGF0YSwgc3RhdHVzLCB4aHIpIHtcbiAgICAgICAgICAgICAgICBpMThuLmZ1bmN0aW9ucy5sb2coJ2xvYWRlZDogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgZG9uZShudWxsLCBkYXRhKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBlcnJvciA6IGZ1bmN0aW9uKHhociwgc3RhdHVzLCBlcnJvcikge1xuICAgICAgICAgICAgICAgIGlmICgoc3RhdHVzICYmIHN0YXR1cyA9PSAyMDApIHx8XG4gICAgICAgICAgICAgICAgICAgICh4aHIgJiYgeGhyLnN0YXR1cyAmJiB4aHIuc3RhdHVzID09IDIwMCkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gZmlsZSBsb2FkZWQgYnV0IGludmFsaWQganNvbiwgc3RvcCB3YXN0ZSB0aW1lICFcbiAgICAgICAgICAgICAgICAgICAgaTE4bi5mdW5jdGlvbnMuZXJyb3IoJ1RoZXJlIGlzIGEgdHlwbyBpbjogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICgoc3RhdHVzICYmIHN0YXR1cyA9PSA0MDQpIHx8XG4gICAgICAgICAgICAgICAgICAgICh4aHIgJiYgeGhyLnN0YXR1cyAmJiB4aHIuc3RhdHVzID09IDQwNCkpIHtcbiAgICAgICAgICAgICAgICAgICAgaTE4bi5mdW5jdGlvbnMubG9nKCdEb2VzIG5vdCBleGlzdDogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRoZVN0YXR1cyA9IHN0YXR1cyA/IHN0YXR1cyA6XG4gICAgICAgICAgICAgICAgICAgICAgICAoKHhociAmJiB4aHIuc3RhdHVzKSA/IHhoci5zdGF0dXMgOiBudWxsKTtcbiAgICAgICAgICAgICAgICAgICAgaTE4bi5mdW5jdGlvbnMubG9nKHRoZVN0YXR1cyArICcgd2hlbiBsb2FkaW5nICcgKyB1cmwpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGRvbmUoZXJyb3IsIHt9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkYXRhVHlwZTogXCJqc29uXCIsXG4gICAgICAgICAgICBhc3luYyA6IG9wdGlvbnMuZ2V0QXN5bmNcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIC8vICAgICAgICAgICAgICBvcHRpb25zIGZvciBjYWNoaW5nXG4vLyAgICAgICAgICAgICAgICB1c2VMb2NhbFN0b3JhZ2U6IHRydWUsXG4vLyAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2VFeHBpcmF0aW9uVGltZTogODY0MDAwMDAgLy8gaW4gbXMsIGRlZmF1bHQgMSB3ZWVrXG59O1xuXG5mdW5jdGlvbiBpbml0Q29tcGxldGVkKHQpXG57XG4gICAgJChcIltkYXRhLWkxOG5dXCIpLmkxOG4oKTtcbn1cblxuZnVuY3Rpb24gY2hlY2tGb3JQYXJhbWV0ZXIoKSB7XG4gICAgdmFyIHF1ZXJ5ID0gd2luZG93LmxvY2F0aW9uLnNlYXJjaC5zdWJzdHJpbmcoMSk7XG4gICAgdmFyIHZhcnMgPSBxdWVyeS5zcGxpdChcIiZcIik7XG4gICAgZm9yICh2YXIgaT0wO2k8dmFycy5sZW5ndGg7aSsrKSB7XG4gICAgICAgIHZhciBwYWlyID0gdmFyc1tpXS5zcGxpdChcIj1cIik7XG4gICAgICAgIGlmKHBhaXJbMF0gPT0gXCJsYW5nXCIpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHJldHVybiBwYWlyWzFdO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBpbml0OiBmdW5jdGlvbiAobGFuZykge1xuICAgICAgICB2YXIgb3B0aW9ucyA9IGRlZmF1bHRPcHRpb25zO1xuXG5cbiAgICAgICAgaWYoIWxhbmcpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGxhbmcgPSBjaGVja0ZvclBhcmFtZXRlcigpO1xuICAgICAgICAgICAgaWYoIWxhbmcpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdmFyIHNldHRpbmdzID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbiAgICAgICAgICAgICAgICBpZihzZXR0aW5ncylcbiAgICAgICAgICAgICAgICAgICAgbGFuZyA9IHNldHRpbmdzLmxhbmd1YWdlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYobGFuZykge1xuICAgICAgICAgICAgb3B0aW9ucy5sbmcgPSBsYW5nO1xuICAgICAgICB9XG5cbiAgICAgICAgaTE4bi5pbml0KG9wdGlvbnMsIGluaXRDb21wbGV0ZWQpO1xuICAgIH0sXG4gICAgdHJhbnNsYXRlU3RyaW5nOiBmdW5jdGlvbiAoa2V5LCBvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiBpMThuLnQoa2V5LCBvcHRpb25zKTtcbiAgICB9LFxuICAgIHNldExhbmd1YWdlOiBmdW5jdGlvbiAobGFuZykge1xuICAgICAgICBpZighbGFuZylcbiAgICAgICAgICAgIGxhbmcgPSBERUZBVUxUX0xBTkc7XG4gICAgICAgIGkxOG4uc2V0TG5nKGxhbmcsIGRlZmF1bHRPcHRpb25zLCBpbml0Q29tcGxldGVkKTtcbiAgICB9LFxuICAgIGdldEN1cnJlbnRMYW5ndWFnZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gaTE4bi5sbmcoKTtcbiAgICB9LFxuICAgIHRyYW5zbGF0ZUVsZW1lbnQ6IGZ1bmN0aW9uIChzZWxlY3Rvcikge1xuICAgICAgICBzZWxlY3Rvci5pMThuKCk7XG4gICAgfSxcbiAgICBnZW5lcmF0ZVRyYW5zbGF0b25IVE1MOiBmdW5jdGlvbiAoa2V5LCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBzdHIgPSBcIjxzcGFuIGRhdGEtaTE4bj1cXFwiXCIgKyBrZXkgKyBcIlxcXCJcIjtcbiAgICAgICAgaWYob3B0aW9ucylcbiAgICAgICAge1xuICAgICAgICAgICAgc3RyICs9IFwiIGRhdGEtaTE4bi1vcHRpb25zPVxcXCJcIiArIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMpICsgXCJcXFwiXCI7XG4gICAgICAgIH1cbiAgICAgICAgc3RyICs9IFwiPlwiO1xuICAgICAgICBzdHIgKz0gdGhpcy50cmFuc2xhdGVTdHJpbmcoa2V5LCBvcHRpb25zKTtcbiAgICAgICAgc3RyICs9IFwiPC9zcGFuPlwiO1xuICAgICAgICByZXR1cm4gc3RyO1xuXG4gICAgfVxufTtcbiIsIi8qIGpzaGludCAtVzExNyAqL1xudmFyIFRyYWNlYWJsZVBlZXJDb25uZWN0aW9uID0gcmVxdWlyZShcIi4vVHJhY2VhYmxlUGVlckNvbm5lY3Rpb25cIik7XG52YXIgU0RQRGlmZmVyID0gcmVxdWlyZShcIi4vU0RQRGlmZmVyXCIpO1xudmFyIFNEUFV0aWwgPSByZXF1aXJlKFwiLi9TRFBVdGlsXCIpO1xudmFyIFNEUCA9IHJlcXVpcmUoXCIuL1NEUFwiKTtcbnZhciBSVENCcm93c2VyVHlwZSA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9SVENCcm93c2VyVHlwZVwiKTtcblxuLy8gSmluZ2xlIHN0dWZmXG5mdW5jdGlvbiBKaW5nbGVTZXNzaW9uKG1lLCBzaWQsIGNvbm5lY3Rpb24sIHNlcnZpY2UpIHtcbiAgICB0aGlzLm1lID0gbWU7XG4gICAgdGhpcy5zaWQgPSBzaWQ7XG4gICAgdGhpcy5jb25uZWN0aW9uID0gY29ubmVjdGlvbjtcbiAgICB0aGlzLmluaXRpYXRvciA9IG51bGw7XG4gICAgdGhpcy5yZXNwb25kZXIgPSBudWxsO1xuICAgIHRoaXMuaXNJbml0aWF0b3IgPSBudWxsO1xuICAgIHRoaXMucGVlcmppZCA9IG51bGw7XG4gICAgdGhpcy5zdGF0ZSA9IG51bGw7XG4gICAgdGhpcy5sb2NhbFNEUCA9IG51bGw7XG4gICAgdGhpcy5yZW1vdGVTRFAgPSBudWxsO1xuICAgIHRoaXMucmVsYXllZFN0cmVhbXMgPSBbXTtcbiAgICB0aGlzLnN0YXJ0VGltZSA9IG51bGw7XG4gICAgdGhpcy5zdG9wVGltZSA9IG51bGw7XG4gICAgdGhpcy5tZWRpYV9jb25zdHJhaW50cyA9IG51bGw7XG4gICAgdGhpcy5wY19jb25zdHJhaW50cyA9IG51bGw7XG4gICAgdGhpcy5pY2VfY29uZmlnID0ge307XG4gICAgdGhpcy5kcmlwX2NvbnRhaW5lciA9IFtdO1xuICAgIHRoaXMuc2VydmljZSA9IHNlcnZpY2U7XG5cbiAgICB0aGlzLnVzZXRyaWNrbGUgPSB0cnVlO1xuICAgIHRoaXMudXNlcHJhbnN3ZXIgPSBmYWxzZTsgLy8gZWFybHkgdHJhbnNwb3J0IHdhcm11cCAtLSBtaW5kIHlvdSwgdGhpcyBtaWdodCBmYWlsLiBkZXBlbmRzIG9uIHdlYnJ0YyBpc3N1ZSAxNzE4XG4gICAgdGhpcy51c2VkcmlwID0gZmFsc2U7IC8vIGRyaXBwaW5nIGlzIHNlbmRpbmcgdHJpY2tsZSBjYW5kaWRhdGVzIG5vdCBvbmUtYnktb25lXG5cbiAgICB0aGlzLmhhZHN0dW5jYW5kaWRhdGUgPSBmYWxzZTtcbiAgICB0aGlzLmhhZHR1cm5jYW5kaWRhdGUgPSBmYWxzZTtcbiAgICB0aGlzLmxhc3RpY2VjYW5kaWRhdGUgPSBmYWxzZTtcblxuICAgIHRoaXMuc3RhdHNpbnRlcnZhbCA9IG51bGw7XG5cbiAgICB0aGlzLnJlYXNvbiA9IG51bGw7XG5cbiAgICB0aGlzLmFkZHNzcmMgPSBbXTtcbiAgICB0aGlzLnJlbW92ZXNzcmMgPSBbXTtcbiAgICB0aGlzLnBlbmRpbmdvcCA9IG51bGw7XG4gICAgdGhpcy5zd2l0Y2hzdHJlYW1zID0gZmFsc2U7XG5cbiAgICB0aGlzLndhaXQgPSB0cnVlO1xuICAgIHRoaXMubG9jYWxTdHJlYW1zU1NSQyA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaW5kaWNhdG9yIHdoaWNoIGRldGVybWluZXMgd2hldGhlciB0aGUgKGxvY2FsKSB2aWRlbyBoYXMgYmVlbiBtdXRlZFxuICAgICAqIGluIHJlc3BvbnNlIHRvIGEgdXNlciBjb21tYW5kIGluIGNvbnRyYXN0IHRvIGFuIGF1dG9tYXRpYyBkZWNpc2lvbiBtYWRlXG4gICAgICogYnkgdGhlIGFwcGxpY2F0aW9uIGxvZ2ljLlxuICAgICAqL1xuICAgIHRoaXMudmlkZW9NdXRlQnlVc2VyID0gZmFsc2U7XG59XG5cbi8vVE9ETzogdGhpcyBhcnJheSBtdXN0IGJlIHJlbW92ZWQgd2hlbiBmaXJlZm94IGltcGxlbWVudCBtdWx0aXN0cmVhbSBzdXBwb3J0XG5KaW5nbGVTZXNzaW9uLm5vdFJlY2VpdmVkU1NSQ3MgPSBbXTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuaW5pdGlhdGUgPSBmdW5jdGlvbiAocGVlcmppZCwgaXNJbml0aWF0b3IpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgaWYgKHRoaXMuc3RhdGUgIT09IG51bGwpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignYXR0ZW1wdCB0byBpbml0aWF0ZSBvbiBzZXNzaW9uICcgKyB0aGlzLnNpZCArXG4gICAgICAgICAgICAnaW4gc3RhdGUgJyArIHRoaXMuc3RhdGUpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuaXNJbml0aWF0b3IgPSBpc0luaXRpYXRvcjtcbiAgICB0aGlzLnN0YXRlID0gJ3BlbmRpbmcnO1xuICAgIHRoaXMuaW5pdGlhdG9yID0gaXNJbml0aWF0b3IgPyB0aGlzLm1lIDogcGVlcmppZDtcbiAgICB0aGlzLnJlc3BvbmRlciA9ICFpc0luaXRpYXRvciA/IHRoaXMubWUgOiBwZWVyamlkO1xuICAgIHRoaXMucGVlcmppZCA9IHBlZXJqaWQ7XG4gICAgdGhpcy5oYWRzdHVuY2FuZGlkYXRlID0gZmFsc2U7XG4gICAgdGhpcy5oYWR0dXJuY2FuZGlkYXRlID0gZmFsc2U7XG4gICAgdGhpcy5sYXN0aWNlY2FuZGlkYXRlID0gZmFsc2U7XG5cbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uXG4gICAgICAgID0gbmV3IFRyYWNlYWJsZVBlZXJDb25uZWN0aW9uKFxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmppbmdsZS5pY2VfY29uZmlnLFxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmppbmdsZS5wY19jb25zdHJhaW50cyApO1xuXG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5vbmljZWNhbmRpZGF0ZSA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBzZWxmLnNlbmRJY2VDYW5kaWRhdGUoZXZlbnQuY2FuZGlkYXRlKTtcbiAgICB9O1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25hZGRzdHJlYW0gPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJSRU1PVEUgU1RSRUFNIEFEREVEOiBcIiArIGV2ZW50LnN0cmVhbSArIFwiIC0gXCIgKyBldmVudC5zdHJlYW0uaWQpO1xuICAgICAgICBzZWxmLnJlbW90ZVN0cmVhbUFkZGVkKGV2ZW50KTtcbiAgICB9O1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25yZW1vdmVzdHJlYW0gPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgLy8gUmVtb3ZlIHRoZSBzdHJlYW0gZnJvbSByZW1vdGVTdHJlYW1zXG4gICAgICAgIC8vIEZJWE1FOiByZW1vdGVzdHJlYW1yZW1vdmVkLmppbmdsZSBub3QgZGVmaW5lZCBhbnl3aGVyZSh1bnVzZWQpXG4gICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ3JlbW90ZXN0cmVhbXJlbW92ZWQuamluZ2xlJywgW2V2ZW50LCBzZWxmLnNpZF0pO1xuICAgIH07XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIGlmICghKHNlbGYgJiYgc2VsZi5wZWVyY29ubmVjdGlvbikpIHJldHVybjtcbiAgICB9O1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25pY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgaWYgKCEoc2VsZiAmJiBzZWxmLnBlZXJjb25uZWN0aW9uKSkgcmV0dXJuO1xuICAgICAgICBzd2l0Y2ggKHNlbGYucGVlcmNvbm5lY3Rpb24uaWNlQ29ubmVjdGlvblN0YXRlKSB7XG4gICAgICAgICAgICBjYXNlICdjb25uZWN0ZWQnOlxuICAgICAgICAgICAgICAgIHRoaXMuc3RhcnRUaW1lID0gbmV3IERhdGUoKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ2Rpc2Nvbm5lY3RlZCc6XG4gICAgICAgICAgICAgICAgdGhpcy5zdG9wVGltZSA9IG5ldyBEYXRlKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgb25JY2VDb25uZWN0aW9uU3RhdGVDaGFuZ2Uoc2VsZi5zaWQsIHNlbGYpO1xuICAgIH07XG4gICAgLy8gYWRkIGFueSBsb2NhbCBhbmQgcmVsYXllZCBzdHJlYW1cbiAgICBBUFAuUlRDLmxvY2FsU3RyZWFtcy5mb3JFYWNoKGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICBzZWxmLnBlZXJjb25uZWN0aW9uLmFkZFN0cmVhbShzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKSk7XG4gICAgfSk7XG4gICAgdGhpcy5yZWxheWVkU3RyZWFtcy5mb3JFYWNoKGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICBzZWxmLnBlZXJjb25uZWN0aW9uLmFkZFN0cmVhbShzdHJlYW0pO1xuICAgIH0pO1xufTtcblxuZnVuY3Rpb24gb25JY2VDb25uZWN0aW9uU3RhdGVDaGFuZ2Uoc2lkLCBzZXNzaW9uKSB7XG4gICAgc3dpdGNoIChzZXNzaW9uLnBlZXJjb25uZWN0aW9uLmljZUNvbm5lY3Rpb25TdGF0ZSkge1xuICAgICAgICBjYXNlICdjaGVja2luZyc6XG4gICAgICAgICAgICBzZXNzaW9uLnRpbWVDaGVja2luZyA9IChuZXcgRGF0ZSgpKS5nZXRUaW1lKCk7XG4gICAgICAgICAgICBzZXNzaW9uLmZpcnN0Y29ubmVjdCA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnY29tcGxldGVkJzogLy8gb24gY2FsbGVyIHNpZGVcbiAgICAgICAgY2FzZSAnY29ubmVjdGVkJzpcbiAgICAgICAgICAgIGlmIChzZXNzaW9uLmZpcnN0Y29ubmVjdCkge1xuICAgICAgICAgICAgICAgIHNlc3Npb24uZmlyc3Rjb25uZWN0ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgdmFyIG1ldGFkYXRhID0ge307XG4gICAgICAgICAgICAgICAgbWV0YWRhdGEuc2V0dXBUaW1lXG4gICAgICAgICAgICAgICAgICAgID0gKG5ldyBEYXRlKCkpLmdldFRpbWUoKSAtIHNlc3Npb24udGltZUNoZWNraW5nO1xuICAgICAgICAgICAgICAgIHNlc3Npb24ucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMoZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgICAgICAgICBpZihyZXMgJiYgcmVzLnJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzLnJlc3VsdCgpLmZvckVhY2goZnVuY3Rpb24gKHJlcG9ydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXBvcnQudHlwZSA9PSAnZ29vZ0NhbmRpZGF0ZVBhaXInICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcG9ydC5zdGF0KCdnb29nQWN0aXZlQ29ubmVjdGlvbicpID09ICd0cnVlJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YS5sb2NhbENhbmRpZGF0ZVR5cGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gcmVwb3J0LnN0YXQoJ2dvb2dMb2NhbENhbmRpZGF0ZVR5cGUnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEucmVtb3RlQ2FuZGlkYXRlVHlwZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPSByZXBvcnQuc3RhdCgnZ29vZ1JlbW90ZUNhbmRpZGF0ZVR5cGUnKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBsb2cgcGFpciBhcyB3ZWxsIHNvIHdlIGNhbiBnZXQgbmljZSBwaWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2hhcnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhLmNhbmRpZGF0ZVBhaXJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gcmVwb3J0LnN0YXQoJ2dvb2dMb2NhbENhbmRpZGF0ZVR5cGUnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzsnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBvcnQuc3RhdCgnZ29vZ1JlbW90ZUNhbmRpZGF0ZVR5cGUnKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVwb3J0LnN0YXQoJ2dvb2dSZW1vdGVBZGRyZXNzJykuaW5kZXhPZignWycpID09PSAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YS5pcHY2ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG59XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLmFjY2VwdCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5zdGF0ZSA9ICdhY3RpdmUnO1xuXG4gICAgdmFyIHByYW5zd2VyID0gdGhpcy5wZWVyY29ubmVjdGlvbi5sb2NhbERlc2NyaXB0aW9uO1xuICAgIGlmICghcHJhbnN3ZXIgfHwgcHJhbnN3ZXIudHlwZSAhPSAncHJhbnN3ZXInKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc29sZS5sb2coJ2dvaW5nIGZyb20gcHJhbnN3ZXIgdG8gYW5zd2VyJyk7XG4gICAgaWYgKHRoaXMudXNldHJpY2tsZSkge1xuICAgICAgICAvLyByZW1vdmUgY2FuZGlkYXRlcyBhbHJlYWR5IHNlbnQgZnJvbSBzZXNzaW9uLWFjY2VwdFxuICAgICAgICB2YXIgbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXMocHJhbnN3ZXIuc2RwLCAnYT1jYW5kaWRhdGU6Jyk7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHByYW5zd2VyLnNkcCA9IHByYW5zd2VyLnNkcC5yZXBsYWNlKGxpbmVzW2ldICsgJ1xcclxcbicsICcnKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB3aGlsZSAoU0RQVXRpbC5maW5kX2xpbmUocHJhbnN3ZXIuc2RwLCAnYT1pbmFjdGl2ZScpKSB7XG4gICAgICAgIC8vIEZJWE1FOiBjaGFuZ2UgYW55IGluYWN0aXZlIHRvIHNlbmRyZWN2IG9yIHdoYXRldmVyIHRoZXkgd2VyZSBvcmlnaW5hbGx5XG4gICAgICAgIHByYW5zd2VyLnNkcCA9IHByYW5zd2VyLnNkcC5yZXBsYWNlKCdhPWluYWN0aXZlJywgJ2E9c2VuZHJlY3YnKTtcbiAgICB9XG4gICAgcHJhbnN3ZXIgPSBBUFAuc2ltdWxjYXN0LnJldmVyc2VUcmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uKHByYW5zd2VyKTtcbiAgICB2YXIgcHJzZHAgPSBuZXcgU0RQKHByYW5zd2VyLnNkcCk7XG4gICAgdmFyIGFjY2VwdCA9ICRpcSh7dG86IHRoaXMucGVlcmppZCxcbiAgICAgICAgdHlwZTogJ3NldCd9KVxuICAgICAgICAuYygnamluZ2xlJywge3htbG5zOiAndXJuOnhtcHA6amluZ2xlOjEnLFxuICAgICAgICAgICAgYWN0aW9uOiAnc2Vzc2lvbi1hY2NlcHQnLFxuICAgICAgICAgICAgaW5pdGlhdG9yOiB0aGlzLmluaXRpYXRvcixcbiAgICAgICAgICAgIHJlc3BvbmRlcjogdGhpcy5yZXNwb25kZXIsXG4gICAgICAgICAgICBzaWQ6IHRoaXMuc2lkIH0pO1xuICAgIHByc2RwLnRvSmluZ2xlKGFjY2VwdCwgdGhpcy5pbml0aWF0b3IgPT0gdGhpcy5tZSA/ICdpbml0aWF0b3InIDogJ3Jlc3BvbmRlcicsIHRoaXMubG9jYWxTdHJlYW1zU1NSQyk7XG4gICAgdmFyIHNkcCA9IHRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbi5zZHA7XG4gICAgd2hpbGUgKFNEUFV0aWwuZmluZF9saW5lKHNkcCwgJ2E9aW5hY3RpdmUnKSkge1xuICAgICAgICAvLyBGSVhNRTogY2hhbmdlIGFueSBpbmFjdGl2ZSB0byBzZW5kcmVjdiBvciB3aGF0ZXZlciB0aGV5IHdlcmUgb3JpZ2luYWxseVxuICAgICAgICBzZHAgPSBzZHAucmVwbGFjZSgnYT1pbmFjdGl2ZScsICdhPXNlbmRyZWN2Jyk7XG4gICAgfVxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLnNldExvY2FsRGVzY3JpcHRpb24obmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7dHlwZTogJ2Fuc3dlcicsIHNkcDogc2RwfSksXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ3NldExvY2FsRGVzY3JpcHRpb24gc3VjY2VzcycpO1xuICAgICAgICAgICAgc2VsZi5zZXRMb2NhbERlc2NyaXB0aW9uKCk7XG5cbiAgICAgICAgICAgIHNlbGYuY29ubmVjdGlvbi5zZW5kSVEoYWNjZXB0LFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGFjayA9IHt9O1xuICAgICAgICAgICAgICAgICAgICBhY2suc291cmNlID0gJ2Fuc3dlcic7XG4gICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2Fjay5qaW5nbGUnLCBbc2VsZi5zaWQsIGFja10pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHN0YW56YSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAoJChzdGFuemEpLmZpbmQoJ2Vycm9yJykubGVuZ3RoKSA/IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvZGU6ICQoc3RhbnphKS5maW5kKCdlcnJvcicpLmF0dHIoJ2NvZGUnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlYXNvbjogJChzdGFuemEpLmZpbmQoJ2Vycm9yIDpmaXJzdCcpWzBdLnRhZ05hbWVcbiAgICAgICAgICAgICAgICAgICAgfTp7fTtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3Iuc291cmNlID0gJ2Fuc3dlcic7XG4gICAgICAgICAgICAgICAgICAgIEppbmdsZVNlc3Npb24ub25KaW5nbGVFcnJvcihzZWxmLnNpZCwgZXJyb3IpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgMTAwMDApO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignc2V0TG9jYWxEZXNjcmlwdGlvbiBmYWlsZWQnLCBlKTtcbiAgICAgICAgfVxuICAgICk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS50ZXJtaW5hdGUgPSBmdW5jdGlvbiAocmVhc29uKSB7XG4gICAgdGhpcy5zdGF0ZSA9ICdlbmRlZCc7XG4gICAgdGhpcy5yZWFzb24gPSByZWFzb247XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5jbG9zZSgpO1xuICAgIGlmICh0aGlzLnN0YXRzaW50ZXJ2YWwgIT09IG51bGwpIHtcbiAgICAgICAgd2luZG93LmNsZWFySW50ZXJ2YWwodGhpcy5zdGF0c2ludGVydmFsKTtcbiAgICAgICAgdGhpcy5zdGF0c2ludGVydmFsID0gbnVsbDtcbiAgICB9XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5hY3RpdmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGUgPT0gJ2FjdGl2ZSc7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kSWNlQ2FuZGlkYXRlID0gZnVuY3Rpb24gKGNhbmRpZGF0ZSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAoY2FuZGlkYXRlICYmICF0aGlzLmxhc3RpY2VjYW5kaWRhdGUpIHtcbiAgICAgICAgdmFyIGljZSA9IFNEUFV0aWwuaWNlcGFyYW1zKHRoaXMubG9jYWxTRFAubWVkaWFbY2FuZGlkYXRlLnNkcE1MaW5lSW5kZXhdLCB0aGlzLmxvY2FsU0RQLnNlc3Npb24pO1xuICAgICAgICB2YXIgamNhbmQgPSBTRFBVdGlsLmNhbmRpZGF0ZVRvSmluZ2xlKGNhbmRpZGF0ZS5jYW5kaWRhdGUpO1xuICAgICAgICBpZiAoIShpY2UgJiYgamNhbmQpKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdmYWlsZWQgdG8gZ2V0IGljZSAmJiBqY2FuZCcpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGljZS54bWxucyA9ICd1cm46eG1wcDpqaW5nbGU6dHJhbnNwb3J0czppY2UtdWRwOjEnO1xuXG4gICAgICAgIGlmIChqY2FuZC50eXBlID09PSAnc3JmbHgnKSB7XG4gICAgICAgICAgICB0aGlzLmhhZHN0dW5jYW5kaWRhdGUgPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKGpjYW5kLnR5cGUgPT09ICdyZWxheScpIHtcbiAgICAgICAgICAgIHRoaXMuaGFkdHVybmNhbmRpZGF0ZSA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy51c2V0cmlja2xlKSB7XG4gICAgICAgICAgICBpZiAodGhpcy51c2VkcmlwKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZHJpcF9jb250YWluZXIubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHN0YXJ0IDIwbXMgY2FsbG91dFxuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2VsZi5kcmlwX2NvbnRhaW5lci5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuc2VuZEljZUNhbmRpZGF0ZXMoc2VsZi5kcmlwX2NvbnRhaW5lcik7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmRyaXBfY29udGFpbmVyID0gW107XG4gICAgICAgICAgICAgICAgICAgIH0sIDIwKTtcblxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmRyaXBfY29udGFpbmVyLnB1c2goY2FuZGlkYXRlKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNlbGYuc2VuZEljZUNhbmRpZGF0ZShbY2FuZGlkYXRlXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICAvL2NvbnNvbGUubG9nKCdzZW5kSWNlQ2FuZGlkYXRlOiBsYXN0IGNhbmRpZGF0ZS4nKTtcbiAgICAgICAgaWYgKCF0aGlzLnVzZXRyaWNrbGUpIHtcbiAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ3Nob3VsZCBzZW5kIGZ1bGwgb2ZmZXIgbm93Li4uJyk7XG4gICAgICAgICAgICB2YXIgaW5pdCA9ICRpcSh7dG86IHRoaXMucGVlcmppZCxcbiAgICAgICAgICAgICAgICB0eXBlOiAnc2V0J30pXG4gICAgICAgICAgICAgICAgLmMoJ2ppbmdsZScsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZToxJyxcbiAgICAgICAgICAgICAgICAgICAgYWN0aW9uOiB0aGlzLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24udHlwZSA9PSAnb2ZmZXInID8gJ3Nlc3Npb24taW5pdGlhdGUnIDogJ3Nlc3Npb24tYWNjZXB0JyxcbiAgICAgICAgICAgICAgICAgICAgaW5pdGlhdG9yOiB0aGlzLmluaXRpYXRvcixcbiAgICAgICAgICAgICAgICAgICAgc2lkOiB0aGlzLnNpZH0pO1xuICAgICAgICAgICAgdGhpcy5sb2NhbFNEUCA9IG5ldyBTRFAodGhpcy5wZWVyY29ubmVjdGlvbi5sb2NhbERlc2NyaXB0aW9uLnNkcCk7XG4gICAgICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICAgICB2YXIgc2VuZEppbmdsZSA9IGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgaWYoIXNzcmMpXG4gICAgICAgICAgICAgICAgICAgIHNzcmMgPSB7fTtcbiAgICAgICAgICAgICAgICBzZWxmLmxvY2FsU0RQLnRvSmluZ2xlKGluaXQsIHNlbGYuaW5pdGlhdG9yID09IHNlbGYubWUgPyAnaW5pdGlhdG9yJyA6ICdyZXNwb25kZXInLCBzc3JjKTtcbiAgICAgICAgICAgICAgICBzZWxmLmNvbm5lY3Rpb24uc2VuZElRKGluaXQsXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ3Nlc3Npb24gaW5pdGlhdGUgYWNrJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWNrID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICBhY2suc291cmNlID0gJ29mZmVyJztcbiAgICAgICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2Fjay5qaW5nbGUnLCBbc2VsZi5zaWQsIGFja10pO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoc3RhbnphKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnN0YXRlID0gJ2Vycm9yJztcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uY2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICgkKHN0YW56YSkuZmluZCgnZXJyb3InKS5sZW5ndGgpID8ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZGU6ICQoc3RhbnphKS5maW5kKCdlcnJvcicpLmF0dHIoJ2NvZGUnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFzb246ICQoc3RhbnphKS5maW5kKCdlcnJvciA6Zmlyc3QnKVswXS50YWdOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgfTp7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yLnNvdXJjZSA9ICdvZmZlcic7XG4gICAgICAgICAgICAgICAgICAgICAgICBKaW5nbGVTZXNzaW9uLm9uSmluZ2xlRXJyb3Ioc2VsZi5zaWQsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgMTAwMDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VuZEppbmdsZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubGFzdGljZWNhbmRpZGF0ZSA9IHRydWU7XG4gICAgICAgIGNvbnNvbGUubG9nKCdIYXZlIHdlIGVuY291bnRlcmVkIGFueSBzcmZseCBjYW5kaWRhdGVzPyAnICsgdGhpcy5oYWRzdHVuY2FuZGlkYXRlKTtcbiAgICAgICAgY29uc29sZS5sb2coJ0hhdmUgd2UgZW5jb3VudGVyZWQgYW55IHJlbGF5IGNhbmRpZGF0ZXM/ICcgKyB0aGlzLmhhZHR1cm5jYW5kaWRhdGUpO1xuXG4gICAgICAgIGlmICghKHRoaXMuaGFkc3R1bmNhbmRpZGF0ZSB8fCB0aGlzLmhhZHR1cm5jYW5kaWRhdGUpICYmIHRoaXMucGVlcmNvbm5lY3Rpb24uc2lnbmFsaW5nU3RhdGUgIT0gJ2Nsb3NlZCcpIHtcbiAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ25vc3R1bmNhbmRpZGF0ZXMuamluZ2xlJywgW3RoaXMuc2lkXSk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kSWNlQ2FuZGlkYXRlcyA9IGZ1bmN0aW9uIChjYW5kaWRhdGVzKSB7XG4gICAgY29uc29sZS5sb2coJ3NlbmRJY2VDYW5kaWRhdGVzJywgY2FuZGlkYXRlcyk7XG4gICAgdmFyIGNhbmQgPSAkaXEoe3RvOiB0aGlzLnBlZXJqaWQsIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgLmMoJ2ppbmdsZScsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZToxJyxcbiAgICAgICAgICAgIGFjdGlvbjogJ3RyYW5zcG9ydC1pbmZvJyxcbiAgICAgICAgICAgIGluaXRpYXRvcjogdGhpcy5pbml0aWF0b3IsXG4gICAgICAgICAgICBzaWQ6IHRoaXMuc2lkfSk7XG4gICAgZm9yICh2YXIgbWlkID0gMDsgbWlkIDwgdGhpcy5sb2NhbFNEUC5tZWRpYS5sZW5ndGg7IG1pZCsrKSB7XG4gICAgICAgIHZhciBjYW5kcyA9IGNhbmRpZGF0ZXMuZmlsdGVyKGZ1bmN0aW9uIChlbCkgeyByZXR1cm4gZWwuc2RwTUxpbmVJbmRleCA9PSBtaWQ7IH0pO1xuICAgICAgICB2YXIgbWxpbmUgPSBTRFBVdGlsLnBhcnNlX21saW5lKHRoaXMubG9jYWxTRFAubWVkaWFbbWlkXS5zcGxpdCgnXFxyXFxuJylbMF0pO1xuICAgICAgICBpZiAoY2FuZHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgdmFyIGljZSA9IFNEUFV0aWwuaWNlcGFyYW1zKHRoaXMubG9jYWxTRFAubWVkaWFbbWlkXSwgdGhpcy5sb2NhbFNEUC5zZXNzaW9uKTtcbiAgICAgICAgICAgIGljZS54bWxucyA9ICd1cm46eG1wcDpqaW5nbGU6dHJhbnNwb3J0czppY2UtdWRwOjEnO1xuICAgICAgICAgICAgY2FuZC5jKCdjb250ZW50Jywge2NyZWF0b3I6IHRoaXMuaW5pdGlhdG9yID09IHRoaXMubWUgPyAnaW5pdGlhdG9yJyA6ICdyZXNwb25kZXInLFxuICAgICAgICAgICAgICAgIG5hbWU6IChjYW5kc1swXS5zZHBNaWQ/IGNhbmRzWzBdLnNkcE1pZCA6IG1saW5lLm1lZGlhKVxuICAgICAgICAgICAgfSkuYygndHJhbnNwb3J0JywgaWNlKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2FuZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBjYW5kLmMoJ2NhbmRpZGF0ZScsIFNEUFV0aWwuY2FuZGlkYXRlVG9KaW5nbGUoY2FuZHNbaV0uY2FuZGlkYXRlKSkudXAoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGFkZCBmaW5nZXJwcmludFxuICAgICAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubG9jYWxTRFAubWVkaWFbbWlkXSwgJ2E9ZmluZ2VycHJpbnQ6JywgdGhpcy5sb2NhbFNEUC5zZXNzaW9uKSkge1xuICAgICAgICAgICAgICAgIHZhciB0bXAgPSBTRFBVdGlsLnBhcnNlX2ZpbmdlcnByaW50KFNEUFV0aWwuZmluZF9saW5lKHRoaXMubG9jYWxTRFAubWVkaWFbbWlkXSwgJ2E9ZmluZ2VycHJpbnQ6JywgdGhpcy5sb2NhbFNEUC5zZXNzaW9uKSk7XG4gICAgICAgICAgICAgICAgdG1wLnJlcXVpcmVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBjYW5kLmMoXG4gICAgICAgICAgICAgICAgICAgICdmaW5nZXJwcmludCcsXG4gICAgICAgICAgICAgICAgICAgIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOmR0bHM6MCd9KVxuICAgICAgICAgICAgICAgICAgICAudCh0bXAuZmluZ2VycHJpbnQpO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0bXAuZmluZ2VycHJpbnQ7XG4gICAgICAgICAgICAgICAgY2FuZC5hdHRycyh0bXApO1xuICAgICAgICAgICAgICAgIGNhbmQudXAoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbmQudXAoKTsgLy8gdHJhbnNwb3J0XG4gICAgICAgICAgICBjYW5kLnVwKCk7IC8vIGNvbnRlbnRcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBtaWdodCBtZXJnZSBsYXN0LWNhbmRpZGF0ZSBub3RpZmljYXRpb24gaW50byB0aGlzLCBidXQgaXQgaXMgY2FsbGVkIGFsb3QgbGF0ZXIuIFNlZSB3ZWJydGMgaXNzdWUgIzIzNDBcbiAgICAvL2NvbnNvbGUubG9nKCd3YXMgdGhpcyB0aGUgbGFzdCBjYW5kaWRhdGUnLCB0aGlzLmxhc3RpY2VjYW5kaWRhdGUpO1xuICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kSVEoY2FuZCxcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjayA9IHt9O1xuICAgICAgICAgICAgYWNrLnNvdXJjZSA9ICd0cmFuc3BvcnRpbmZvJztcbiAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2Fjay5qaW5nbGUnLCBbdGhpcy5zaWQsIGFja10pO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoc3RhbnphKSB7XG4gICAgICAgICAgICB2YXIgZXJyb3IgPSAoJChzdGFuemEpLmZpbmQoJ2Vycm9yJykubGVuZ3RoKSA/IHtcbiAgICAgICAgICAgICAgICBjb2RlOiAkKHN0YW56YSkuZmluZCgnZXJyb3InKS5hdHRyKCdjb2RlJyksXG4gICAgICAgICAgICAgICAgcmVhc29uOiAkKHN0YW56YSkuZmluZCgnZXJyb3IgOmZpcnN0JylbMF0udGFnTmFtZSxcbiAgICAgICAgICAgIH06e307XG4gICAgICAgICAgICBlcnJvci5zb3VyY2UgPSAndHJhbnNwb3J0aW5mbyc7XG4gICAgICAgICAgICBKaW5nbGVTZXNzaW9uLm9uSmluZ2xlRXJyb3IodGhpcy5zaWQsIGVycm9yKTtcbiAgICAgICAgfSxcbiAgICAgICAgMTAwMDApO1xufTtcblxuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kT2ZmZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgLy9jb25zb2xlLmxvZygnc2VuZE9mZmVyLi4uJyk7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uY3JlYXRlT2ZmZXIoZnVuY3Rpb24gKHNkcCkge1xuICAgICAgICAgICAgc2VsZi5jcmVhdGVkT2ZmZXIoc2RwKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ2NyZWF0ZU9mZmVyIGZhaWxlZCcsIGUpO1xuICAgICAgICB9LFxuICAgICAgICB0aGlzLm1lZGlhX2NvbnN0cmFpbnRzXG4gICAgKTtcbn07XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLmNyZWF0ZWRPZmZlciA9IGZ1bmN0aW9uIChzZHApIHtcbiAgICAvL2NvbnNvbGUubG9nKCdjcmVhdGVkT2ZmZXInLCBzZHApO1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLmxvY2FsU0RQID0gbmV3IFNEUChzZHAuc2RwKTtcbiAgICAvL3RoaXMubG9jYWxTRFAubWFuZ2xlKCk7XG4gICAgdmFyIHNlbmRKaW5nbGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbml0ID0gJGlxKHt0bzogdGhpcy5wZWVyamlkLFxuICAgICAgICAgICAgdHlwZTogJ3NldCd9KVxuICAgICAgICAgICAgLmMoJ2ppbmdsZScsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZToxJyxcbiAgICAgICAgICAgICAgICBhY3Rpb246ICdzZXNzaW9uLWluaXRpYXRlJyxcbiAgICAgICAgICAgICAgICBpbml0aWF0b3I6IHRoaXMuaW5pdGlhdG9yLFxuICAgICAgICAgICAgICAgIHNpZDogdGhpcy5zaWR9KTtcbiAgICAgICAgc2VsZi5sb2NhbFNEUC50b0ppbmdsZShpbml0LCB0aGlzLmluaXRpYXRvciA9PSB0aGlzLm1lID8gJ2luaXRpYXRvcicgOiAncmVzcG9uZGVyJywgdGhpcy5sb2NhbFN0cmVhbXNTU1JDKTtcbiAgICAgICAgc2VsZi5jb25uZWN0aW9uLnNlbmRJUShpbml0LFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBhY2sgPSB7fTtcbiAgICAgICAgICAgICAgICBhY2suc291cmNlID0gJ29mZmVyJztcbiAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdhY2suamluZ2xlJywgW3NlbGYuc2lkLCBhY2tdKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoc3RhbnphKSB7XG4gICAgICAgICAgICAgICAgc2VsZi5zdGF0ZSA9ICdlcnJvcic7XG4gICAgICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5jbG9zZSgpO1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICgkKHN0YW56YSkuZmluZCgnZXJyb3InKS5sZW5ndGgpID8ge1xuICAgICAgICAgICAgICAgICAgICBjb2RlOiAkKHN0YW56YSkuZmluZCgnZXJyb3InKS5hdHRyKCdjb2RlJyksXG4gICAgICAgICAgICAgICAgICAgIHJlYXNvbjogJChzdGFuemEpLmZpbmQoJ2Vycm9yIDpmaXJzdCcpWzBdLnRhZ05hbWUsXG4gICAgICAgICAgICAgICAgfTp7fTtcbiAgICAgICAgICAgICAgICBlcnJvci5zb3VyY2UgPSAnb2ZmZXInO1xuICAgICAgICAgICAgICAgIEppbmdsZVNlc3Npb24ub25KaW5nbGVFcnJvcihzZWxmLnNpZCwgZXJyb3IpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIDEwMDAwKTtcbiAgICB9XG4gICAgc2RwLnNkcCA9IHRoaXMubG9jYWxTRFAucmF3O1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uc2V0TG9jYWxEZXNjcmlwdGlvbihzZHAsXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmKHNlbGYudXNldHJpY2tsZSlcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBzZW5kSmluZ2xlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzZWxmLnNldExvY2FsRGVzY3JpcHRpb24oKTtcbiAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ3NldExvY2FsRGVzY3JpcHRpb24gc3VjY2VzcycpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignc2V0TG9jYWxEZXNjcmlwdGlvbiBmYWlsZWQnLCBlKTtcbiAgICAgICAgfVxuICAgICk7XG4gICAgdmFyIGNhbmRzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMubG9jYWxTRFAucmF3LCAnYT1jYW5kaWRhdGU6Jyk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjYW5kcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgY2FuZCA9IFNEUFV0aWwucGFyc2VfaWNlY2FuZGlkYXRlKGNhbmRzW2ldKTtcbiAgICAgICAgaWYgKGNhbmQudHlwZSA9PSAnc3JmbHgnKSB7XG4gICAgICAgICAgICB0aGlzLmhhZHN0dW5jYW5kaWRhdGUgPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKGNhbmQudHlwZSA9PSAncmVsYXknKSB7XG4gICAgICAgICAgICB0aGlzLmhhZHR1cm5jYW5kaWRhdGUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuc2V0UmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZWxlbSwgZGVzY3R5cGUpIHtcbiAgICAvL2NvbnNvbGUubG9nKCdzZXR0aW5nIHJlbW90ZSBkZXNjcmlwdGlvbi4uLiAnLCBkZXNjdHlwZSk7XG4gICAgdGhpcy5yZW1vdGVTRFAgPSBuZXcgU0RQKCcnKTtcbiAgICB0aGlzLnJlbW90ZVNEUC5mcm9tSmluZ2xlKGVsZW0pO1xuICAgIGlmICh0aGlzLnBlZXJjb25uZWN0aW9uLnJlbW90ZURlc2NyaXB0aW9uICE9PSBudWxsKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdzZXRSZW1vdGVEZXNjcmlwdGlvbiB3aGVuIHJlbW90ZSBkZXNjcmlwdGlvbiBpcyBub3QgbnVsbCwgc2hvdWxkIGJlIHByYW5zd2VyJywgdGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbik7XG4gICAgICAgIGlmICh0aGlzLnBlZXJjb25uZWN0aW9uLnJlbW90ZURlc2NyaXB0aW9uLnR5cGUgPT0gJ3ByYW5zd2VyJykge1xuICAgICAgICAgICAgdmFyIHByYW5zd2VyID0gbmV3IFNEUCh0aGlzLnBlZXJjb25uZWN0aW9uLnJlbW90ZURlc2NyaXB0aW9uLnNkcCk7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHByYW5zd2VyLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGhhdmUgaWNlIHVmcmFnIGFuZCBwd2RcbiAgICAgICAgICAgICAgICBpZiAoIVNEUFV0aWwuZmluZF9saW5lKHRoaXMucmVtb3RlU0RQLm1lZGlhW2ldLCAnYT1pY2UtdWZyYWc6JywgdGhpcy5yZW1vdGVTRFAuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHByYW5zd2VyLm1lZGlhW2ldLCAnYT1pY2UtdWZyYWc6JywgcHJhbnN3ZXIuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3RlU0RQLm1lZGlhW2ldICs9IFNEUFV0aWwuZmluZF9saW5lKHByYW5zd2VyLm1lZGlhW2ldLCAnYT1pY2UtdWZyYWc6JywgcHJhbnN3ZXIuc2Vzc2lvbikgKyAnXFxyXFxuJztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2Fybignbm8gaWNlIHVmcmFnPycpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZShwcmFuc3dlci5tZWRpYVtpXSwgJ2E9aWNlLXB3ZDonLCBwcmFuc3dlci5zZXNzaW9uKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdGVTRFAubWVkaWFbaV0gKz0gU0RQVXRpbC5maW5kX2xpbmUocHJhbnN3ZXIubWVkaWFbaV0sICdhPWljZS1wd2Q6JywgcHJhbnN3ZXIuc2Vzc2lvbikgKyAnXFxyXFxuJztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2Fybignbm8gaWNlIHB3ZD8nKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBjb3B5IG92ZXIgY2FuZGlkYXRlc1xuICAgICAgICAgICAgICAgIHZhciBsaW5lcyA9IFNEUFV0aWwuZmluZF9saW5lcyhwcmFuc3dlci5tZWRpYVtpXSwgJ2E9Y2FuZGlkYXRlOicpO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbGluZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZW1vdGVTRFAubWVkaWFbaV0gKz0gbGluZXNbal0gKyAnXFxyXFxuJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnJlbW90ZVNEUC5yYXcgPSB0aGlzLnJlbW90ZVNEUC5zZXNzaW9uICsgdGhpcy5yZW1vdGVTRFAubWVkaWEuam9pbignJyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdmFyIHJlbW90ZWRlc2MgPSBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHt0eXBlOiBkZXNjdHlwZSwgc2RwOiB0aGlzLnJlbW90ZVNEUC5yYXd9KTtcblxuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uc2V0UmVtb3RlRGVzY3JpcHRpb24ocmVtb3RlZGVzYyxcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgLy9jb25zb2xlLmxvZygnc2V0UmVtb3RlRGVzY3JpcHRpb24gc3VjY2VzcycpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignc2V0UmVtb3RlRGVzY3JpcHRpb24gZXJyb3InLCBlKTtcbiAgICAgICAgICAgIEppbmdsZVNlc3Npb24ub25KaW5nbGVGYXRhbEVycm9yKHNlbGYsIGUpO1xuICAgICAgICB9XG4gICAgKTtcbn07XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uIChlbGVtKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmICh0aGlzLnBlZXJjb25uZWN0aW9uLnNpZ25hbGluZ1N0YXRlID09ICdjbG9zZWQnKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnBlZXJjb25uZWN0aW9uLnJlbW90ZURlc2NyaXB0aW9uICYmIHRoaXMucGVlcmNvbm5lY3Rpb24uc2lnbmFsaW5nU3RhdGUgPT0gJ2hhdmUtbG9jYWwtb2ZmZXInKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCd0cmlja2xlIGljZSBjYW5kaWRhdGUgYXJyaXZpbmcgYmVmb3JlIHNlc3Npb24gYWNjZXB0Li4uJyk7XG4gICAgICAgIC8vIGNyZWF0ZSBhIFBSQU5TV0VSIGZvciBzZXRSZW1vdGVEZXNjcmlwdGlvblxuICAgICAgICBpZiAoIXRoaXMucmVtb3RlU0RQKSB7XG4gICAgICAgICAgICB2YXIgY29iYmxlZCA9ICd2PTBcXHJcXG4nICtcbiAgICAgICAgICAgICAgICAnbz0tICcgKyAnMTkyMzUxODUxNicgKyAnIDIgSU4gSVA0IDAuMC4wLjBcXHJcXG4nICsvLyBGSVhNRVxuICAgICAgICAgICAgICAgICdzPS1cXHJcXG4nICtcbiAgICAgICAgICAgICAgICAndD0wIDBcXHJcXG4nO1xuICAgICAgICAgICAgLy8gZmlyc3QsIHRha2Ugc29tZSB0aGluZ3MgZnJvbSB0aGUgbG9jYWwgZGVzY3JpcHRpb25cbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sb2NhbFNEUC5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGNvYmJsZWQgKz0gU0RQVXRpbC5maW5kX2xpbmUodGhpcy5sb2NhbFNEUC5tZWRpYVtpXSwgJ209JykgKyAnXFxyXFxuJztcbiAgICAgICAgICAgICAgICBjb2JibGVkICs9IFNEUFV0aWwuZmluZF9saW5lcyh0aGlzLmxvY2FsU0RQLm1lZGlhW2ldLCAnYT1ydHBtYXA6Jykuam9pbignXFxyXFxuJykgKyAnXFxyXFxuJztcbiAgICAgICAgICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5sb2NhbFNEUC5tZWRpYVtpXSwgJ2E9bWlkOicpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvYmJsZWQgKz0gU0RQVXRpbC5maW5kX2xpbmUodGhpcy5sb2NhbFNEUC5tZWRpYVtpXSwgJ2E9bWlkOicpICsgJ1xcclxcbic7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvYmJsZWQgKz0gJ2E9aW5hY3RpdmVcXHJcXG4nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5yZW1vdGVTRFAgPSBuZXcgU0RQKGNvYmJsZWQpO1xuICAgICAgICB9XG4gICAgICAgIC8vIHRoZW4gYWRkIHRoaW5ncyBsaWtlIGljZSBhbmQgZHRscyBmcm9tIHJlbW90ZSBjYW5kaWRhdGVcbiAgICAgICAgZWxlbS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2VsZi5yZW1vdGVTRFAubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUoc2VsZi5yZW1vdGVTRFAubWVkaWFbaV0sICdhPW1pZDonICsgJCh0aGlzKS5hdHRyKCduYW1lJykpIHx8XG4gICAgICAgICAgICAgICAgICAgIHNlbGYucmVtb3RlU0RQLm1lZGlhW2ldLmluZGV4T2YoJ209JyArICQodGhpcykuYXR0cignbmFtZScpKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIVNEUFV0aWwuZmluZF9saW5lKHNlbGYucmVtb3RlU0RQLm1lZGlhW2ldLCAnYT1pY2UtdWZyYWc6JykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0bXAgPSAkKHRoaXMpLmZpbmQoJ3RyYW5zcG9ydCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5yZW1vdGVTRFAubWVkaWFbaV0gKz0gJ2E9aWNlLXVmcmFnOicgKyB0bXAuYXR0cigndWZyYWcnKSArICdcXHJcXG4nO1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5yZW1vdGVTRFAubWVkaWFbaV0gKz0gJ2E9aWNlLXB3ZDonICsgdG1wLmF0dHIoJ3B3ZCcpICsgJ1xcclxcbic7XG4gICAgICAgICAgICAgICAgICAgICAgICB0bXAgPSAkKHRoaXMpLmZpbmQoJ3RyYW5zcG9ydD5maW5nZXJwcmludCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRtcC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnJlbW90ZVNEUC5tZWRpYVtpXSArPSAnYT1maW5nZXJwcmludDonICsgdG1wLmF0dHIoJ2hhc2gnKSArICcgJyArIHRtcC50ZXh0KCkgKyAnXFxyXFxuJztcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ25vIGR0bHMgZmluZ2VycHJpbnQgKHdlYnJ0YyBpc3N1ZSAjMTcxOD8pJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5yZW1vdGVTRFAubWVkaWFbaV0gKz0gJ2E9Y3J5cHRvOjEgQUVTX0NNXzEyOF9ITUFDX1NIQTFfODAgaW5saW5lOkJBQURCQUFEQkFBREJBQURCQUFEQkFBREJBQURCQUFEQkFBREJBQURcXHJcXG4nO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnJlbW90ZVNEUC5yYXcgPSB0aGlzLnJlbW90ZVNEUC5zZXNzaW9uICsgdGhpcy5yZW1vdGVTRFAubWVkaWEuam9pbignJyk7XG5cbiAgICAgICAgLy8gd2UgbmVlZCBhIGNvbXBsZXRlIFNEUCB3aXRoIGljZS11ZnJhZy9pY2UtcHdkIGluIGFsbCBwYXJ0c1xuICAgICAgICAvLyB0aGlzIG1ha2VzIHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlIFBSQU5TV0VSIGlzIGNvbnN0cnVjdGVkIHN1Y2ggdGhhdCB0aGUgaWNlLXVmcmFnIGlzIGluIGFsbCBtZWRpYXBhcnRzXG4gICAgICAgIC8vIGJ1dCBpdCBjb3VsZCBiZSBpbiB0aGUgc2Vzc2lvbiBwYXJ0IGFzIHdlbGwuIHNpbmNlIHRoZSBjb2RlIGFib3ZlIGNvbnN0cnVjdHMgdGhpcyBzZHAgdGhpcyBjYW4ndCBoYXBwZW4gaG93ZXZlclxuICAgICAgICB2YXIgaXNjb21wbGV0ZSA9IHRoaXMucmVtb3RlU0RQLm1lZGlhLmZpbHRlcihmdW5jdGlvbiAobWVkaWFwYXJ0KSB7XG4gICAgICAgICAgICByZXR1cm4gU0RQVXRpbC5maW5kX2xpbmUobWVkaWFwYXJ0LCAnYT1pY2UtdWZyYWc6Jyk7XG4gICAgICAgIH0pLmxlbmd0aCA9PSB0aGlzLnJlbW90ZVNEUC5tZWRpYS5sZW5ndGg7XG5cbiAgICAgICAgaWYgKGlzY29tcGxldGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzZXR0aW5nIHByYW5zd2VyJyk7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uc2V0UmVtb3RlRGVzY3JpcHRpb24obmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7dHlwZTogJ3ByYW5zd2VyJywgc2RwOiB0aGlzLnJlbW90ZVNEUC5yYXcgfSksXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnc2V0UmVtb3RlRGVzY3JpcHRpb24gcHJhbnN3ZXIgZmFpbGVkJywgZS50b1N0cmluZygpKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignc2V0dGluZyBwcmFuc3dlciBmYWlsZWQnLCBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ25vdCB5ZXQgc2V0dGluZyBwcmFuc3dlcicpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIG9wZXJhdGUgb24gZWFjaCBjb250ZW50IGVsZW1lbnRcbiAgICBlbGVtLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyB3b3VsZCBsb3ZlIHRvIGRlYWN0aXZhdGUgdGhpcywgYnV0IGZpcmVmb3ggc3RpbGwgcmVxdWlyZXMgaXRcbiAgICAgICAgdmFyIGlkeCA9IC0xO1xuICAgICAgICB2YXIgaTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHNlbGYucmVtb3RlU0RQLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUoc2VsZi5yZW1vdGVTRFAubWVkaWFbaV0sICdhPW1pZDonICsgJCh0aGlzKS5hdHRyKCduYW1lJykpIHx8XG4gICAgICAgICAgICAgICAgc2VsZi5yZW1vdGVTRFAubWVkaWFbaV0uaW5kZXhPZignbT0nICsgJCh0aGlzKS5hdHRyKCduYW1lJykpID09PSAwKSB7XG4gICAgICAgICAgICAgICAgaWR4ID0gaTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoaWR4ID09IC0xKSB7IC8vIGZhbGwgYmFjayB0byBsb2NhbGRlc2NyaXB0aW9uXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgc2VsZi5sb2NhbFNEUC5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZShzZWxmLmxvY2FsU0RQLm1lZGlhW2ldLCAnYT1taWQ6JyArICQodGhpcykuYXR0cignbmFtZScpKSB8fFxuICAgICAgICAgICAgICAgICAgICBzZWxmLmxvY2FsU0RQLm1lZGlhW2ldLmluZGV4T2YoJ209JyArICQodGhpcykuYXR0cignbmFtZScpKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBpZHggPSBpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdmFyIG5hbWUgPSAkKHRoaXMpLmF0dHIoJ25hbWUnKTtcbiAgICAgICAgLy8gVE9ETzogY2hlY2sgaWNlLXB3ZCBhbmQgaWNlLXVmcmFnP1xuICAgICAgICAkKHRoaXMpLmZpbmQoJ3RyYW5zcG9ydD5jYW5kaWRhdGUnKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBsaW5lLCBjYW5kaWRhdGU7XG4gICAgICAgICAgICBsaW5lID0gU0RQVXRpbC5jYW5kaWRhdGVGcm9tSmluZ2xlKHRoaXMpO1xuICAgICAgICAgICAgY2FuZGlkYXRlID0gbmV3IFJUQ0ljZUNhbmRpZGF0ZSh7c2RwTUxpbmVJbmRleDogaWR4LFxuICAgICAgICAgICAgICAgIHNkcE1pZDogbmFtZSxcbiAgICAgICAgICAgICAgICBjYW5kaWRhdGU6IGxpbmV9KTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5hZGRJY2VDYW5kaWRhdGUoY2FuZGlkYXRlKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdhZGRJY2VDYW5kaWRhdGUgZmFpbGVkJywgZS50b1N0cmluZygpLCBsaW5lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kQW5zd2VyID0gZnVuY3Rpb24gKHByb3Zpc2lvbmFsKSB7XG4gICAgLy9jb25zb2xlLmxvZygnY3JlYXRlQW5zd2VyJywgcHJvdmlzaW9uYWwpO1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLmNyZWF0ZUFuc3dlcihcbiAgICAgICAgZnVuY3Rpb24gKHNkcCkge1xuICAgICAgICAgICAgc2VsZi5jcmVhdGVkQW5zd2VyKHNkcCwgcHJvdmlzaW9uYWwpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignY3JlYXRlQW5zd2VyIGZhaWxlZCcsIGUpO1xuICAgICAgICB9LFxuICAgICAgICB0aGlzLm1lZGlhX2NvbnN0cmFpbnRzXG4gICAgKTtcbn07XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLmNyZWF0ZWRBbnN3ZXIgPSBmdW5jdGlvbiAoc2RwLCBwcm92aXNpb25hbCkge1xuICAgIC8vY29uc29sZS5sb2coJ2NyZWF0ZUFuc3dlciBjYWxsYmFjaycpO1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLmxvY2FsU0RQID0gbmV3IFNEUChzZHAuc2RwKTtcbiAgICAvL3RoaXMubG9jYWxTRFAubWFuZ2xlKCk7XG4gICAgdGhpcy51c2VwcmFuc3dlciA9IHByb3Zpc2lvbmFsID09PSB0cnVlO1xuICAgIGlmICh0aGlzLnVzZXRyaWNrbGUpIHtcbiAgICAgICAgaWYgKHRoaXMudXNlcHJhbnN3ZXIpIHtcbiAgICAgICAgICAgIHNkcC50eXBlID0gJ3ByYW5zd2VyJztcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sb2NhbFNEUC5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHRoaXMubG9jYWxTRFAubWVkaWFbaV0gPSB0aGlzLmxvY2FsU0RQLm1lZGlhW2ldLnJlcGxhY2UoJ2E9c2VuZHJlY3ZcXHJcXG4nLCAnYT1pbmFjdGl2ZVxcclxcbicpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5sb2NhbFNEUC5yYXcgPSB0aGlzLmxvY2FsU0RQLnNlc3Npb24gKyAnXFxyXFxuJyArIHRoaXMubG9jYWxTRFAubWVkaWEuam9pbignJyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBzZW5kSmluZ2xlID0gZnVuY3Rpb24gKHNzcmNzKSB7XG5cbiAgICAgICAgICAgICAgICB2YXIgYWNjZXB0ID0gJGlxKHt0bzogc2VsZi5wZWVyamlkLFxuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnc2V0J30pXG4gICAgICAgICAgICAgICAgICAgIC5jKCdqaW5nbGUnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb246ICdzZXNzaW9uLWFjY2VwdCcsXG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0aWF0b3I6IHNlbGYuaW5pdGlhdG9yLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uZGVyOiBzZWxmLnJlc3BvbmRlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIHNpZDogc2VsZi5zaWQgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHB1YmxpY0xvY2FsRGVzYyA9IEFQUC5zaW11bGNhc3QucmV2ZXJzZVRyYW5zZm9ybUxvY2FsRGVzY3JpcHRpb24oc2RwKTtcbiAgICAgICAgICAgICAgICB2YXIgcHVibGljTG9jYWxTRFAgPSBuZXcgU0RQKHB1YmxpY0xvY2FsRGVzYy5zZHApO1xuICAgICAgICAgICAgICAgIHB1YmxpY0xvY2FsU0RQLnRvSmluZ2xlKGFjY2VwdCwgc2VsZi5pbml0aWF0b3IgPT0gc2VsZi5tZSA/ICdpbml0aWF0b3InIDogJ3Jlc3BvbmRlcicsIHNzcmNzKTtcbiAgICAgICAgICAgICAgICBzZWxmLmNvbm5lY3Rpb24uc2VuZElRKGFjY2VwdCxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFjayA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgYWNrLnNvdXJjZSA9ICdhbnN3ZXInO1xuICAgICAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignYWNrLmppbmdsZScsIFtzZWxmLnNpZCwgYWNrXSk7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChzdGFuemEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICgkKHN0YW56YSkuZmluZCgnZXJyb3InKS5sZW5ndGgpID8ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZGU6ICQoc3RhbnphKS5maW5kKCdlcnJvcicpLmF0dHIoJ2NvZGUnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFzb246ICQoc3RhbnphKS5maW5kKCdlcnJvciA6Zmlyc3QnKVswXS50YWdOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgfTp7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yLnNvdXJjZSA9ICdhbnN3ZXInO1xuICAgICAgICAgICAgICAgICAgICAgICAgSmluZ2xlU2Vzc2lvbi5vbkppbmdsZUVycm9yKHNlbGYuc2lkLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIDEwMDAwKTtcbiAgICB9XG4gICAgc2RwLnNkcCA9IHRoaXMubG9jYWxTRFAucmF3O1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uc2V0TG9jYWxEZXNjcmlwdGlvbihzZHAsXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcblxuICAgICAgICAgICAgLy9jb25zb2xlLmxvZygnc2V0TG9jYWxEZXNjcmlwdGlvbiBzdWNjZXNzJyk7XG4gICAgICAgICAgICBpZiAoc2VsZi51c2V0cmlja2xlICYmICFzZWxmLnVzZXByYW5zd2VyKSB7XG4gICAgICAgICAgICAgICAgc2VuZEppbmdsZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VsZi5zZXRMb2NhbERlc2NyaXB0aW9uKCk7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdzZXRMb2NhbERlc2NyaXB0aW9uIGZhaWxlZCcsIGUpO1xuICAgICAgICB9XG4gICAgKTtcbiAgICB2YXIgY2FuZHMgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5sb2NhbFNEUC5yYXcsICdhPWNhbmRpZGF0ZTonKTtcbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IGNhbmRzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHZhciBjYW5kID0gU0RQVXRpbC5wYXJzZV9pY2VjYW5kaWRhdGUoY2FuZHNbal0pO1xuICAgICAgICBpZiAoY2FuZC50eXBlID09ICdzcmZseCcpIHtcbiAgICAgICAgICAgIHRoaXMuaGFkc3R1bmNhbmRpZGF0ZSA9IHRydWU7XG4gICAgICAgIH0gZWxzZSBpZiAoY2FuZC50eXBlID09ICdyZWxheScpIHtcbiAgICAgICAgICAgIHRoaXMuaGFkdHVybmNhbmRpZGF0ZSA9IHRydWU7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kVGVybWluYXRlID0gZnVuY3Rpb24gKHJlYXNvbiwgdGV4dCkge1xuICAgIHZhciBzZWxmID0gdGhpcyxcbiAgICAgICAgdGVybSA9ICRpcSh7dG86IHRoaXMucGVlcmppZCxcbiAgICAgICAgICAgIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgICAgIC5jKCdqaW5nbGUnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICAgICAgYWN0aW9uOiAnc2Vzc2lvbi10ZXJtaW5hdGUnLFxuICAgICAgICAgICAgICAgIGluaXRpYXRvcjogdGhpcy5pbml0aWF0b3IsXG4gICAgICAgICAgICAgICAgc2lkOiB0aGlzLnNpZH0pXG4gICAgICAgICAgICAuYygncmVhc29uJylcbiAgICAgICAgICAgIC5jKHJlYXNvbiB8fCAnc3VjY2VzcycpO1xuXG4gICAgaWYgKHRleHQpIHtcbiAgICAgICAgdGVybS51cCgpLmMoJ3RleHQnKS50KHRleHQpO1xuICAgIH1cblxuICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kSVEodGVybSxcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5jbG9zZSgpO1xuICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbiA9IG51bGw7XG4gICAgICAgICAgICBzZWxmLnRlcm1pbmF0ZSgpO1xuICAgICAgICAgICAgdmFyIGFjayA9IHt9O1xuICAgICAgICAgICAgYWNrLnNvdXJjZSA9ICd0ZXJtaW5hdGUnO1xuICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignYWNrLmppbmdsZScsIFtzZWxmLnNpZCwgYWNrXSk7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uIChzdGFuemEpIHtcbiAgICAgICAgICAgIHZhciBlcnJvciA9ICgkKHN0YW56YSkuZmluZCgnZXJyb3InKS5sZW5ndGgpID8ge1xuICAgICAgICAgICAgICAgIGNvZGU6ICQoc3RhbnphKS5maW5kKCdlcnJvcicpLmF0dHIoJ2NvZGUnKSxcbiAgICAgICAgICAgICAgICByZWFzb246ICQoc3RhbnphKS5maW5kKCdlcnJvciA6Zmlyc3QnKVswXS50YWdOYW1lLFxuICAgICAgICAgICAgfTp7fTtcbiAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2Fjay5qaW5nbGUnLCBbc2VsZi5zaWQsIGVycm9yXSk7XG4gICAgICAgIH0sXG4gICAgICAgIDEwMDAwKTtcbiAgICBpZiAodGhpcy5zdGF0c2ludGVydmFsICE9PSBudWxsKSB7XG4gICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKHRoaXMuc3RhdHNpbnRlcnZhbCk7XG4gICAgICAgIHRoaXMuc3RhdHNpbnRlcnZhbCA9IG51bGw7XG4gICAgfVxufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuYWRkU291cmNlID0gZnVuY3Rpb24gKGVsZW0sIGZyb21KaWQpIHtcblxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAvLyBGSVhNRTogZGlydHkgd2FpdGluZ1xuICAgIGlmICghdGhpcy5wZWVyY29ubmVjdGlvbi5sb2NhbERlc2NyaXB0aW9uKVxuICAgIHtcbiAgICAgICAgY29uc29sZS53YXJuKFwiYWRkU291cmNlIC0gbG9jYWxEZXNjcmlwdGlvbiBub3QgcmVhZHkgeWV0XCIpXG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHNlbGYuYWRkU291cmNlKGVsZW0sIGZyb21KaWQpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIDIwMFxuICAgICAgICApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc29sZS5sb2coJ2FkZHNzcmMnLCBuZXcgRGF0ZSgpLmdldFRpbWUoKSk7XG4gICAgY29uc29sZS5sb2coJ2ljZScsIHRoaXMucGVlcmNvbm5lY3Rpb24uaWNlQ29ubmVjdGlvblN0YXRlKTtcbiAgICB2YXIgc2RwID0gbmV3IFNEUCh0aGlzLnBlZXJjb25uZWN0aW9uLnJlbW90ZURlc2NyaXB0aW9uLnNkcCk7XG4gICAgdmFyIG15U2RwID0gbmV3IFNEUCh0aGlzLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24uc2RwKTtcblxuICAgICQoZWxlbSkuZWFjaChmdW5jdGlvbiAoaWR4LCBjb250ZW50KSB7XG4gICAgICAgIHZhciBuYW1lID0gJChjb250ZW50KS5hdHRyKCduYW1lJyk7XG4gICAgICAgIHZhciBsaW5lcyA9ICcnO1xuICAgICAgICAkKGNvbnRlbnQpLmZpbmQoJ3NzcmMtZ3JvdXBbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6c3NtYTowXCJdJykuZWFjaChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBzZW1hbnRpY3MgPSB0aGlzLmdldEF0dHJpYnV0ZSgnc2VtYW50aWNzJyk7XG4gICAgICAgICAgICB2YXIgc3NyY3MgPSAkKHRoaXMpLmZpbmQoJz5zb3VyY2UnKS5tYXAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZSgnc3NyYycpO1xuICAgICAgICAgICAgfSkuZ2V0KCk7XG5cbiAgICAgICAgICAgIGlmIChzc3Jjcy5sZW5ndGggIT0gMCkge1xuICAgICAgICAgICAgICAgIGxpbmVzICs9ICdhPXNzcmMtZ3JvdXA6JyArIHNlbWFudGljcyArICcgJyArIHNzcmNzLmpvaW4oJyAnKSArICdcXHJcXG4nO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdmFyIHRtcCA9ICQoY29udGVudCkuZmluZCgnc291cmNlW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnNzbWE6MFwiXScpOyAvLyBjYW4gaGFuZGxlIGJvdGggPnNvdXJjZSBhbmQgPmRlc2NyaXB0aW9uPnNvdXJjZVxuICAgICAgICB0bXAuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgc3NyYyA9ICQodGhpcykuYXR0cignc3NyYycpO1xuICAgICAgICAgICAgaWYobXlTZHAuY29udGFpbnNTU1JDKHNzcmMpKXtcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGlzIGhhcHBlbnMgd2hlbiBtdWx0aXBsZSBwYXJ0aWNpcGFudHMgY2hhbmdlIHRoZWlyIHN0cmVhbXMgYXQgdGhlIHNhbWUgdGltZSBhbmRcbiAgICAgICAgICAgICAgICAgKiBDb2xpYnJpRm9jdXMubW9kaWZ5U291cmNlcyBoYXZlIHRvIHdhaXQgZm9yIHN0YWJsZSBzdGF0ZS4gSW4gdGhlIG1lYW50aW1lIG11bHRpcGxlXG4gICAgICAgICAgICAgICAgICogYWRkc3NyYyBhcmUgc2NoZWR1bGVkIGZvciB1cGRhdGUgSVEuIFNlZVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIkdvdCBhZGQgc3RyZWFtIHJlcXVlc3QgZm9yIG15IG93biBzc3JjOiBcIitzc3JjKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkKHRoaXMpLmZpbmQoJz5wYXJhbWV0ZXInKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBsaW5lcyArPSAnYT1zc3JjOicgKyBzc3JjICsgJyAnICsgJCh0aGlzKS5hdHRyKCduYW1lJyk7XG4gICAgICAgICAgICAgICAgaWYgKCQodGhpcykuYXR0cigndmFsdWUnKSAmJiAkKHRoaXMpLmF0dHIoJ3ZhbHVlJykubGVuZ3RoKVxuICAgICAgICAgICAgICAgICAgICBsaW5lcyArPSAnOicgKyAkKHRoaXMpLmF0dHIoJ3ZhbHVlJyk7XG4gICAgICAgICAgICAgICAgbGluZXMgKz0gJ1xcclxcbic7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHNkcC5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKG1lZGlhLCBpZHgpIHtcbiAgICAgICAgICAgIGlmICghU0RQVXRpbC5maW5kX2xpbmUobWVkaWEsICdhPW1pZDonICsgbmFtZSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgc2RwLm1lZGlhW2lkeF0gKz0gbGluZXM7XG4gICAgICAgICAgICBpZiAoIXNlbGYuYWRkc3NyY1tpZHhdKSBzZWxmLmFkZHNzcmNbaWR4XSA9ICcnO1xuICAgICAgICAgICAgc2VsZi5hZGRzc3JjW2lkeF0gKz0gbGluZXM7XG4gICAgICAgIH0pO1xuICAgICAgICBzZHAucmF3ID0gc2RwLnNlc3Npb24gKyBzZHAubWVkaWEuam9pbignJyk7XG4gICAgfSk7XG4gICAgdGhpcy5tb2RpZnlTb3VyY2VzKCk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5yZW1vdmVTb3VyY2UgPSBmdW5jdGlvbiAoZWxlbSwgZnJvbUppZCkge1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIC8vIEZJWE1FOiBkaXJ0eSB3YWl0aW5nXG4gICAgaWYgKCF0aGlzLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24pXG4gICAge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJyZW1vdmVTb3VyY2UgLSBsb2NhbERlc2NyaXB0aW9uIG5vdCByZWFkeSB5ZXRcIilcbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgc2VsZi5yZW1vdmVTb3VyY2UoZWxlbSwgZnJvbUppZCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgMjAwXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZygncmVtb3Zlc3NyYycsIG5ldyBEYXRlKCkuZ2V0VGltZSgpKTtcbiAgICBjb25zb2xlLmxvZygnaWNlJywgdGhpcy5wZWVyY29ubmVjdGlvbi5pY2VDb25uZWN0aW9uU3RhdGUpO1xuICAgIHZhciBzZHAgPSBuZXcgU0RQKHRoaXMucGVlcmNvbm5lY3Rpb24ucmVtb3RlRGVzY3JpcHRpb24uc2RwKTtcbiAgICB2YXIgbXlTZHAgPSBuZXcgU0RQKHRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbi5zZHApO1xuXG4gICAgJChlbGVtKS5lYWNoKGZ1bmN0aW9uIChpZHgsIGNvbnRlbnQpIHtcbiAgICAgICAgdmFyIG5hbWUgPSAkKGNvbnRlbnQpLmF0dHIoJ25hbWUnKTtcbiAgICAgICAgdmFyIGxpbmVzID0gJyc7XG4gICAgICAgICQoY29udGVudCkuZmluZCgnc3NyYy1ncm91cFt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjBcIl0nKS5lYWNoKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIHNlbWFudGljcyA9IHRoaXMuZ2V0QXR0cmlidXRlKCdzZW1hbnRpY3MnKTtcbiAgICAgICAgICAgIHZhciBzc3JjcyA9ICQodGhpcykuZmluZCgnPnNvdXJjZScpLm1hcChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QXR0cmlidXRlKCdzc3JjJyk7XG4gICAgICAgICAgICB9KS5nZXQoKTtcblxuICAgICAgICAgICAgaWYgKHNzcmNzLmxlbmd0aCAhPSAwKSB7XG4gICAgICAgICAgICAgICAgbGluZXMgKz0gJ2E9c3NyYy1ncm91cDonICsgc2VtYW50aWNzICsgJyAnICsgc3NyY3Muam9pbignICcpICsgJ1xcclxcbic7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICB2YXIgdG1wID0gJChjb250ZW50KS5maW5kKCdzb3VyY2VbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6c3NtYTowXCJdJyk7IC8vIGNhbiBoYW5kbGUgYm90aCA+c291cmNlIGFuZCA+ZGVzY3JpcHRpb24+c291cmNlXG4gICAgICAgIHRtcC5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBzc3JjID0gJCh0aGlzKS5hdHRyKCdzc3JjJyk7XG4gICAgICAgICAgICAvLyBUaGlzIHNob3VsZCBuZXZlciBoYXBwZW4sIGJ1dCBjYW4gYmUgdXNlZnVsIGZvciBidWcgZGV0ZWN0aW9uXG4gICAgICAgICAgICBpZihteVNkcC5jb250YWluc1NTUkMoc3NyYykpe1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJHb3QgcmVtb3ZlIHN0cmVhbSByZXF1ZXN0IGZvciBteSBvd24gc3NyYzogXCIrc3NyYyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJCh0aGlzKS5maW5kKCc+cGFyYW1ldGVyJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgbGluZXMgKz0gJ2E9c3NyYzonICsgc3NyYyArICcgJyArICQodGhpcykuYXR0cignbmFtZScpO1xuICAgICAgICAgICAgICAgIGlmICgkKHRoaXMpLmF0dHIoJ3ZhbHVlJykgJiYgJCh0aGlzKS5hdHRyKCd2YWx1ZScpLmxlbmd0aClcbiAgICAgICAgICAgICAgICAgICAgbGluZXMgKz0gJzonICsgJCh0aGlzKS5hdHRyKCd2YWx1ZScpO1xuICAgICAgICAgICAgICAgIGxpbmVzICs9ICdcXHJcXG4nO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBzZHAubWVkaWEuZm9yRWFjaChmdW5jdGlvbihtZWRpYSwgaWR4KSB7XG4gICAgICAgICAgICBpZiAoIVNEUFV0aWwuZmluZF9saW5lKG1lZGlhLCAnYT1taWQ6JyArIG5hbWUpKVxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIHNkcC5tZWRpYVtpZHhdICs9IGxpbmVzO1xuICAgICAgICAgICAgaWYgKCFzZWxmLnJlbW92ZXNzcmNbaWR4XSkgc2VsZi5yZW1vdmVzc3JjW2lkeF0gPSAnJztcbiAgICAgICAgICAgIHNlbGYucmVtb3Zlc3NyY1tpZHhdICs9IGxpbmVzO1xuICAgICAgICB9KTtcbiAgICAgICAgc2RwLnJhdyA9IHNkcC5zZXNzaW9uICsgc2RwLm1lZGlhLmpvaW4oJycpO1xuICAgIH0pO1xuICAgIHRoaXMubW9kaWZ5U291cmNlcygpO1xufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUubW9kaWZ5U291cmNlcyA9IGZ1bmN0aW9uIChzdWNjZXNzQ2FsbGJhY2spIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgaWYgKHRoaXMucGVlcmNvbm5lY3Rpb24uc2lnbmFsaW5nU3RhdGUgPT0gJ2Nsb3NlZCcpIHJldHVybjtcbiAgICBpZiAoISh0aGlzLmFkZHNzcmMubGVuZ3RoIHx8IHRoaXMucmVtb3Zlc3NyYy5sZW5ndGggfHwgdGhpcy5wZW5kaW5nb3AgIT09IG51bGwgfHwgdGhpcy5zd2l0Y2hzdHJlYW1zKSl7XG4gICAgICAgIC8vIFRoZXJlIGlzIG5vdGhpbmcgdG8gZG8gc2luY2Ugc2NoZWR1bGVkIGpvYiBtaWdodCBoYXZlIGJlZW4gZXhlY3V0ZWQgYnkgYW5vdGhlciBzdWNjZWVkaW5nIGNhbGxcbiAgICAgICAgdGhpcy5zZXRMb2NhbERlc2NyaXB0aW9uKCk7XG4gICAgICAgIGlmKHN1Y2Nlc3NDYWxsYmFjayl7XG4gICAgICAgICAgICBzdWNjZXNzQ2FsbGJhY2soKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gRklYTUU6IHRoaXMgaXMgYSBiaWcgaGFja1xuICAgIC8vIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3Avd2VicnRjL2lzc3Vlcy9kZXRhaWw/aWQ9MjY4OFxuICAgIC8vIF4gaGFzIGJlZW4gZml4ZWQuXG4gICAgaWYgKCEodGhpcy5wZWVyY29ubmVjdGlvbi5zaWduYWxpbmdTdGF0ZSA9PSAnc3RhYmxlJyAmJiB0aGlzLnBlZXJjb25uZWN0aW9uLmljZUNvbm5lY3Rpb25TdGF0ZSA9PSAnY29ubmVjdGVkJykpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdtb2RpZnlTb3VyY2VzIG5vdCB5ZXQnLCB0aGlzLnBlZXJjb25uZWN0aW9uLnNpZ25hbGluZ1N0YXRlLCB0aGlzLnBlZXJjb25uZWN0aW9uLmljZUNvbm5lY3Rpb25TdGF0ZSk7XG4gICAgICAgIHRoaXMud2FpdCA9IHRydWU7XG4gICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCkgeyBzZWxmLm1vZGlmeVNvdXJjZXMoc3VjY2Vzc0NhbGxiYWNrKTsgfSwgMjUwKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAodGhpcy53YWl0KSB7XG4gICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCkgeyBzZWxmLm1vZGlmeVNvdXJjZXMoc3VjY2Vzc0NhbGxiYWNrKTsgfSwgMjUwMCk7XG4gICAgICAgIHRoaXMud2FpdCA9IGZhbHNlO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgc3dpdGNoIHN0cmVhbXMgZmxhZ1xuICAgIHRoaXMuc3dpdGNoc3RyZWFtcyA9IGZhbHNlO1xuXG4gICAgdmFyIHNkcCA9IG5ldyBTRFAodGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbi5zZHApO1xuXG4gICAgLy8gYWRkIHNvdXJjZXNcbiAgICB0aGlzLmFkZHNzcmMuZm9yRWFjaChmdW5jdGlvbihsaW5lcywgaWR4KSB7XG4gICAgICAgIHNkcC5tZWRpYVtpZHhdICs9IGxpbmVzO1xuICAgIH0pO1xuICAgIHRoaXMuYWRkc3NyYyA9IFtdO1xuXG4gICAgLy8gcmVtb3ZlIHNvdXJjZXNcbiAgICB0aGlzLnJlbW92ZXNzcmMuZm9yRWFjaChmdW5jdGlvbihsaW5lcywgaWR4KSB7XG4gICAgICAgIGxpbmVzID0gbGluZXMuc3BsaXQoJ1xcclxcbicpO1xuICAgICAgICBsaW5lcy5wb3AoKTsgLy8gcmVtb3ZlIGVtcHR5IGxhc3QgZWxlbWVudDtcbiAgICAgICAgbGluZXMuZm9yRWFjaChmdW5jdGlvbihsaW5lKSB7XG4gICAgICAgICAgICBzZHAubWVkaWFbaWR4XSA9IHNkcC5tZWRpYVtpZHhdLnJlcGxhY2UobGluZSArICdcXHJcXG4nLCAnJyk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuICAgIHRoaXMucmVtb3Zlc3NyYyA9IFtdO1xuXG4gICAgLy8gRklYTUU6XG4gICAgLy8gdGhpcyB3YXMgYSBoYWNrIGZvciB0aGUgc2l0dWF0aW9uIHdoZW4gb25seSBvbmUgcGVlciBleGlzdHNcbiAgICAvLyBpbiB0aGUgY29uZmVyZW5jZS5cbiAgICAvLyBjaGVjayBpZiBzdGlsbCByZXF1aXJlZCBhbmQgcmVtb3ZlXG4gICAgaWYgKHNkcC5tZWRpYVswXSlcbiAgICAgICAgc2RwLm1lZGlhWzBdID0gc2RwLm1lZGlhWzBdLnJlcGxhY2UoJ2E9cmVjdm9ubHknLCAnYT1zZW5kcmVjdicpO1xuICAgIGlmIChzZHAubWVkaWFbMV0pXG4gICAgICAgIHNkcC5tZWRpYVsxXSA9IHNkcC5tZWRpYVsxXS5yZXBsYWNlKCdhPXJlY3Zvbmx5JywgJ2E9c2VuZHJlY3YnKTtcblxuICAgIHNkcC5yYXcgPSBzZHAuc2Vzc2lvbiArIHNkcC5tZWRpYS5qb2luKCcnKTtcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLnNldFJlbW90ZURlc2NyaXB0aW9uKG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe3R5cGU6ICdvZmZlcicsIHNkcDogc2RwLnJhd30pLFxuICAgICAgICBmdW5jdGlvbigpIHtcblxuICAgICAgICAgICAgaWYoc2VsZi5zaWduYWxpbmdTdGF0ZSA9PSAnY2xvc2VkJykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJjcmVhdGVBbnN3ZXIgYXR0ZW1wdCBvbiBjbG9zZWQgc3RhdGVcIik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZWxmLnBlZXJjb25uZWN0aW9uLmNyZWF0ZUFuc3dlcihcbiAgICAgICAgICAgICAgICBmdW5jdGlvbihtb2RpZmllZEFuc3dlcikge1xuICAgICAgICAgICAgICAgICAgICAvLyBjaGFuZ2UgdmlkZW8gZGlyZWN0aW9uLCBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2ppdHNpL2ppdG1lZXQvaXNzdWVzLzQxXG4gICAgICAgICAgICAgICAgICAgIGlmIChzZWxmLnBlbmRpbmdvcCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHNkcCA9IG5ldyBTRFAobW9kaWZpZWRBbnN3ZXIuc2RwKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZHAubWVkaWEubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaChzZWxmLnBlbmRpbmdvcCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdtdXRlJzpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkcC5tZWRpYVsxXSA9IHNkcC5tZWRpYVsxXS5yZXBsYWNlKCdhPXNlbmRyZWN2JywgJ2E9cmVjdm9ubHknKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICd1bm11dGUnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2RwLm1lZGlhWzFdID0gc2RwLm1lZGlhWzFdLnJlcGxhY2UoJ2E9cmVjdm9ubHknLCAnYT1zZW5kcmVjdicpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkcC5yYXcgPSBzZHAuc2Vzc2lvbiArIHNkcC5tZWRpYS5qb2luKCcnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RpZmllZEFuc3dlci5zZHAgPSBzZHAucmF3O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5wZW5kaW5nb3AgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gRklYTUU6IHB1c2hpbmcgZG93biBhbiBhbnN3ZXIgd2hpbGUgaWNlIGNvbm5lY3Rpb24gc3RhdGVcbiAgICAgICAgICAgICAgICAgICAgLy8gaXMgc3RpbGwgY2hlY2tpbmcgaXMgYmFkLi4uXG4gICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5sb2coc2VsZi5wZWVyY29ubmVjdGlvbi5pY2VDb25uZWN0aW9uU3RhdGUpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIHRyeWluZyB0byB3b3JrIGFyb3VuZCBhbm90aGVyIGNocm9tZSBidWdcbiAgICAgICAgICAgICAgICAgICAgLy9tb2RpZmllZEFuc3dlci5zZHAgPSBtb2RpZmllZEFuc3dlci5zZHAucmVwbGFjZSgvYT1zZXR1cDphY3RpdmUvZywgJ2E9c2V0dXA6YWN0cGFzcycpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnBlZXJjb25uZWN0aW9uLnNldExvY2FsRGVzY3JpcHRpb24obW9kaWZpZWRBbnN3ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdtb2RpZmllZCBzZXRMb2NhbERlc2NyaXB0aW9uIG9rJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5zZXRMb2NhbERlc2NyaXB0aW9uKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYoc3VjY2Vzc0NhbGxiYWNrKXtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VjY2Vzc0NhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignbW9kaWZpZWQgc2V0TG9jYWxEZXNjcmlwdGlvbiBmYWlsZWQnLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbihlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdtb2RpZmllZCBhbnN3ZXIgZmFpbGVkJywgZXJyb3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uKGVycm9yKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdtb2RpZnkgZmFpbGVkJywgZXJyb3IpO1xuICAgICAgICB9XG4gICAgKTtcbn07XG5cbi8qKlxuICogU3dpdGNoZXMgdmlkZW8gc3RyZWFtcy5cbiAqIEBwYXJhbSBuZXdfc3RyZWFtIG5ldyBzdHJlYW0gdGhhdCB3aWxsIGJlIHVzZWQgYXMgdmlkZW8gb2YgdGhpcyBzZXNzaW9uLlxuICogQHBhcmFtIG9sZFN0cmVhbSBvbGQgdmlkZW8gc3RyZWFtIG9mIHRoaXMgc2Vzc2lvbi5cbiAqIEBwYXJhbSBzdWNjZXNzX2NhbGxiYWNrIGNhbGxiYWNrIGV4ZWN1dGVkIGFmdGVyIHN1Y2Nlc3NmdWwgc3RyZWFtIHN3aXRjaC5cbiAqL1xuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuc3dpdGNoU3RyZWFtcyA9IGZ1bmN0aW9uIChuZXdfc3RyZWFtLCBvbGRTdHJlYW0sIHN1Y2Nlc3NfY2FsbGJhY2spIHtcblxuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIC8vIFJlbWVtYmVyIFNEUCB0byBmaWd1cmUgb3V0IGFkZGVkL3JlbW92ZWQgU1NSQ3NcbiAgICB2YXIgb2xkU2RwID0gbnVsbDtcbiAgICBpZihzZWxmLnBlZXJjb25uZWN0aW9uKSB7XG4gICAgICAgIGlmKHNlbGYucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbikge1xuICAgICAgICAgICAgb2xkU2RwID0gbmV3IFNEUChzZWxmLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24uc2RwKTtcbiAgICAgICAgfVxuICAgICAgICBzZWxmLnBlZXJjb25uZWN0aW9uLnJlbW92ZVN0cmVhbShvbGRTdHJlYW0sIHRydWUpO1xuICAgICAgICBpZihuZXdfc3RyZWFtKVxuICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5hZGRTdHJlYW0obmV3X3N0cmVhbSk7XG4gICAgfVxuXG4gICAgQVBQLlJUQy5zd2l0Y2hWaWRlb1N0cmVhbXMobmV3X3N0cmVhbSwgb2xkU3RyZWFtKTtcblxuICAgIC8vIENvbmZlcmVuY2UgaXMgbm90IGFjdGl2ZVxuICAgIGlmKCFvbGRTZHAgfHwgIXNlbGYucGVlcmNvbm5lY3Rpb24pIHtcbiAgICAgICAgc3VjY2Vzc19jYWxsYmFjaygpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgc2VsZi5zd2l0Y2hzdHJlYW1zID0gdHJ1ZTtcbiAgICBzZWxmLm1vZGlmeVNvdXJjZXMoZnVuY3Rpb24oKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdtb2RpZnkgc291cmNlcyBkb25lJyk7XG5cbiAgICAgICAgc3VjY2Vzc19jYWxsYmFjaygpO1xuXG4gICAgICAgIHZhciBuZXdTZHAgPSBuZXcgU0RQKHNlbGYucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbi5zZHApO1xuICAgICAgICBjb25zb2xlLmxvZyhcIlNEUHNcIiwgb2xkU2RwLCBuZXdTZHApO1xuICAgICAgICBzZWxmLm5vdGlmeU15U1NSQ1VwZGF0ZShvbGRTZHAsIG5ld1NkcCk7XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIEZpZ3VyZXMgb3V0IGFkZGVkL3JlbW92ZWQgc3NyY3MgYW5kIHNlbmQgdXBkYXRlIElRcy5cbiAqIEBwYXJhbSBvbGRfc2RwIFNEUCBvYmplY3QgZm9yIG9sZCBkZXNjcmlwdGlvbi5cbiAqIEBwYXJhbSBuZXdfc2RwIFNEUCBvYmplY3QgZm9yIG5ldyBkZXNjcmlwdGlvbi5cbiAqL1xuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUubm90aWZ5TXlTU1JDVXBkYXRlID0gZnVuY3Rpb24gKG9sZF9zZHAsIG5ld19zZHApIHtcblxuICAgIGlmICghKHRoaXMucGVlcmNvbm5lY3Rpb24uc2lnbmFsaW5nU3RhdGUgPT0gJ3N0YWJsZScgJiZcbiAgICAgICAgdGhpcy5wZWVyY29ubmVjdGlvbi5pY2VDb25uZWN0aW9uU3RhdGUgPT0gJ2Nvbm5lY3RlZCcpKXtcbiAgICAgICAgY29uc29sZS5sb2coXCJUb28gZWFybHkgdG8gc2VuZCB1cGRhdGVzXCIpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gc2VuZCBzb3VyY2UtcmVtb3ZlIElRLlxuICAgIHNkcERpZmZlciA9IG5ldyBTRFBEaWZmZXIobmV3X3NkcCwgb2xkX3NkcCk7XG4gICAgdmFyIHJlbW92ZSA9ICRpcSh7dG86IHRoaXMucGVlcmppZCwgdHlwZTogJ3NldCd9KVxuICAgICAgICAuYygnamluZ2xlJywge1xuICAgICAgICAgICAgeG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICBhY3Rpb246ICdzb3VyY2UtcmVtb3ZlJyxcbiAgICAgICAgICAgIGluaXRpYXRvcjogdGhpcy5pbml0aWF0b3IsXG4gICAgICAgICAgICBzaWQ6IHRoaXMuc2lkXG4gICAgICAgIH1cbiAgICApO1xuICAgIHZhciByZW1vdmVkID0gc2RwRGlmZmVyLnRvSmluZ2xlKHJlbW92ZSk7XG4gICAgaWYgKHJlbW92ZWQpIHtcbiAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmRJUShyZW1vdmUsXG4gICAgICAgICAgICBmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdnb3QgcmVtb3ZlIHJlc3VsdCcsIHJlcyk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ2dvdCByZW1vdmUgZXJyb3InLCBlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdyZW1vdmFsIG5vdCBuZWNlc3NhcnknKTtcbiAgICB9XG5cbiAgICAvLyBzZW5kIHNvdXJjZS1hZGQgSVEuXG4gICAgdmFyIHNkcERpZmZlciA9IG5ldyBTRFBEaWZmZXIob2xkX3NkcCwgbmV3X3NkcCk7XG4gICAgdmFyIGFkZCA9ICRpcSh7dG86IHRoaXMucGVlcmppZCwgdHlwZTogJ3NldCd9KVxuICAgICAgICAuYygnamluZ2xlJywge1xuICAgICAgICAgICAgeG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICBhY3Rpb246ICdzb3VyY2UtYWRkJyxcbiAgICAgICAgICAgIGluaXRpYXRvcjogdGhpcy5pbml0aWF0b3IsXG4gICAgICAgICAgICBzaWQ6IHRoaXMuc2lkXG4gICAgICAgIH1cbiAgICApO1xuICAgIHZhciBhZGRlZCA9IHNkcERpZmZlci50b0ppbmdsZShhZGQpO1xuICAgIGlmIChhZGRlZCkge1xuICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKGFkZCxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oJ2dvdCBhZGQgcmVzdWx0JywgcmVzKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignZ290IGFkZCBlcnJvcicsIGVycik7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5sb2coJ2FkZGl0aW9uIG5vdCBuZWNlc3NhcnknKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIE11dGVzL3VubXV0ZXMgdGhlIChsb2NhbCkgdmlkZW8gaS5lLiBlbmFibGVzL2Rpc2FibGVzIGFsbCB2aWRlbyB0cmFja3MuXG4gKlxuICogQHBhcmFtIG11dGUgPHR0PnRydWU8L3R0PiB0byBtdXRlIHRoZSAobG9jYWwpIHZpZGVvIGkuZS4gdG8gZGlzYWJsZSBhbGwgdmlkZW9cbiAqIHRyYWNrczsgb3RoZXJ3aXNlLCA8dHQ+ZmFsc2U8L3R0PlxuICogQHBhcmFtIGNhbGxiYWNrIGEgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB3aXRoIDx0dD5tdXRlPC90dD4gYWZ0ZXIgYWxsIHZpZGVvXG4gKiB0cmFja3MgaGF2ZSBiZWVuIGVuYWJsZWQvZGlzYWJsZWQuIFRoZSBmdW5jdGlvbiBtYXksIG9wdGlvbmFsbHksIHJldHVyblxuICogYW5vdGhlciBmdW5jdGlvbiB3aGljaCBpcyB0byBiZSBpbnZva2VkIGFmdGVyIHRoZSB3aG9sZSBtdXRlL3VubXV0ZSBvcGVyYXRpb25cbiAqIGhhcyBjb21wbGV0ZWQgc3VjY2Vzc2Z1bGx5LlxuICogQHBhcmFtIG9wdGlvbnMgYW4gb2JqZWN0IHdoaWNoIHNwZWNpZmllcyBvcHRpb25hbCBhcmd1bWVudHMgc3VjaCBhcyB0aGVcbiAqIDx0dD5ib29sZWFuPC90dD4ga2V5IDx0dD5ieVVzZXI8L3R0PiB3aXRoIGRlZmF1bHQgdmFsdWUgPHR0PnRydWU8L3R0PiB3aGljaFxuICogc3BlY2lmaWVzIHdoZXRoZXIgdGhlIG1ldGhvZCB3YXMgaW5pdGlhdGVkIGluIHJlc3BvbnNlIHRvIGEgdXNlciBjb21tYW5kIChpblxuICogY29udHJhc3QgdG8gYW4gYXV0b21hdGljIGRlY2lzaW9uIG1hZGUgYnkgdGhlIGFwcGxpY2F0aW9uIGxvZ2ljKVxuICovXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZXRWaWRlb011dGUgPSBmdW5jdGlvbiAobXV0ZSwgY2FsbGJhY2ssIG9wdGlvbnMpIHtcbiAgICB2YXIgYnlVc2VyO1xuXG4gICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgYnlVc2VyID0gb3B0aW9ucy5ieVVzZXI7XG4gICAgICAgIGlmICh0eXBlb2YgYnlVc2VyID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgYnlVc2VyID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAgIGJ5VXNlciA9IHRydWU7XG4gICAgfVxuICAgIC8vIFRoZSB1c2VyJ3MgY29tbWFuZCB0byBtdXRlIHRoZSAobG9jYWwpIHZpZGVvIHRha2VzIHByZWNlZGVuY2Ugb3ZlciBhbnlcbiAgICAvLyBhdXRvbWF0aWMgZGVjaXNpb24gbWFkZSBieSB0aGUgYXBwbGljYXRpb24gbG9naWMuXG4gICAgaWYgKGJ5VXNlcikge1xuICAgICAgICB0aGlzLnZpZGVvTXV0ZUJ5VXNlciA9IG11dGU7XG4gICAgfSBlbHNlIGlmICh0aGlzLnZpZGVvTXV0ZUJ5VXNlcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5oYXJkTXV0ZVZpZGVvKG11dGUpO1xuXG4gICAgdGhpcy5tb2RpZnlTb3VyY2VzKGNhbGxiYWNrKG11dGUpKTtcbn07XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLmhhcmRNdXRlVmlkZW8gPSBmdW5jdGlvbiAobXV0ZWQpIHtcbiAgICB0aGlzLnBlbmRpbmdvcCA9IG11dGVkID8gJ211dGUnIDogJ3VubXV0ZSc7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kTXV0ZSA9IGZ1bmN0aW9uIChtdXRlZCwgY29udGVudCkge1xuICAgIHZhciBpbmZvID0gJGlxKHt0bzogdGhpcy5wZWVyamlkLFxuICAgICAgICB0eXBlOiAnc2V0J30pXG4gICAgICAgIC5jKCdqaW5nbGUnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICBhY3Rpb246ICdzZXNzaW9uLWluZm8nLFxuICAgICAgICAgICAgaW5pdGlhdG9yOiB0aGlzLmluaXRpYXRvcixcbiAgICAgICAgICAgIHNpZDogdGhpcy5zaWQgfSk7XG4gICAgaW5mby5jKG11dGVkID8gJ211dGUnIDogJ3VubXV0ZScsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDppbmZvOjEnfSk7XG4gICAgaW5mby5hdHRycyh7J2NyZWF0b3InOiB0aGlzLm1lID09IHRoaXMuaW5pdGlhdG9yID8gJ2NyZWF0b3InIDogJ3Jlc3BvbmRlcid9KTtcbiAgICBpZiAoY29udGVudCkge1xuICAgICAgICBpbmZvLmF0dHJzKHsnbmFtZSc6IGNvbnRlbnR9KTtcbiAgICB9XG4gICAgdGhpcy5jb25uZWN0aW9uLnNlbmQoaW5mbyk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kUmluZ2luZyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgaW5mbyA9ICRpcSh7dG86IHRoaXMucGVlcmppZCxcbiAgICAgICAgdHlwZTogJ3NldCd9KVxuICAgICAgICAuYygnamluZ2xlJywge3htbG5zOiAndXJuOnhtcHA6amluZ2xlOjEnLFxuICAgICAgICAgICAgYWN0aW9uOiAnc2Vzc2lvbi1pbmZvJyxcbiAgICAgICAgICAgIGluaXRpYXRvcjogdGhpcy5pbml0aWF0b3IsXG4gICAgICAgICAgICBzaWQ6IHRoaXMuc2lkIH0pO1xuICAgIGluZm8uYygncmluZ2luZycsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDppbmZvOjEnfSk7XG4gICAgdGhpcy5jb25uZWN0aW9uLnNlbmQoaW5mbyk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5nZXRTdGF0cyA9IGZ1bmN0aW9uIChpbnRlcnZhbCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgcmVjdiA9IHthdWRpbzogMCwgdmlkZW86IDB9O1xuICAgIHZhciBsb3N0ID0ge2F1ZGlvOiAwLCB2aWRlbzogMH07XG4gICAgdmFyIGxhc3RyZWN2ID0ge2F1ZGlvOiAwLCB2aWRlbzogMH07XG4gICAgdmFyIGxhc3Rsb3N0ID0ge2F1ZGlvOiAwLCB2aWRlbzogMH07XG4gICAgdmFyIGxvc3MgPSB7YXVkaW86IDAsIHZpZGVvOiAwfTtcbiAgICB2YXIgZGVsdGEgPSB7YXVkaW86IDAsIHZpZGVvOiAwfTtcbiAgICB0aGlzLnN0YXRzaW50ZXJ2YWwgPSB3aW5kb3cuc2V0SW50ZXJ2YWwoZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoc2VsZiAmJiBzZWxmLnBlZXJjb25uZWN0aW9uICYmIHNlbGYucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMpIHtcbiAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMoZnVuY3Rpb24gKHN0YXRzKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSBzdGF0cy5yZXN1bHQoKTtcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiB0aGVyZSBhcmUgc28gbXVjaCBzdGF0aXN0aWNzIHlvdSBjYW4gZ2V0IGZyb20gdGhpcy4uXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZXN1bHRzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHRzW2ldLnR5cGUgPT0gJ3NzcmMnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcGFja2V0c3JlY3YgPSByZXN1bHRzW2ldLnN0YXQoJ3BhY2tldHNSZWNlaXZlZCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHBhY2tldHNsb3N0ID0gcmVzdWx0c1tpXS5zdGF0KCdwYWNrZXRzTG9zdCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhY2tldHNyZWN2ICYmIHBhY2tldHNsb3N0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFja2V0c3JlY3YgPSBwYXJzZUludChwYWNrZXRzcmVjdiwgMTApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhY2tldHNsb3N0ID0gcGFyc2VJbnQocGFja2V0c2xvc3QsIDEwKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHRzW2ldLnN0YXQoJ2dvb2dGcmFtZVJhdGVSZWNlaXZlZCcpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3Rsb3N0LnZpZGVvID0gbG9zdC52aWRlbztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFzdHJlY3YudmlkZW8gPSByZWN2LnZpZGVvO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWN2LnZpZGVvID0gcGFja2V0c3JlY3Y7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvc3QudmlkZW8gPSBwYWNrZXRzbG9zdDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXN0bG9zdC5hdWRpbyA9IGxvc3QuYXVkaW87XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RyZWN2LmF1ZGlvID0gcmVjdi5hdWRpbztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjdi5hdWRpbyA9IHBhY2tldHNyZWN2O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3N0LmF1ZGlvID0gcGFja2V0c2xvc3Q7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGRlbHRhLmF1ZGlvID0gcmVjdi5hdWRpbyAtIGxhc3RyZWN2LmF1ZGlvO1xuICAgICAgICAgICAgICAgIGRlbHRhLnZpZGVvID0gcmVjdi52aWRlbyAtIGxhc3RyZWN2LnZpZGVvO1xuICAgICAgICAgICAgICAgIGxvc3MuYXVkaW8gPSAoZGVsdGEuYXVkaW8gPiAwKSA/IE1hdGguY2VpbCgxMDAgKiAobG9zdC5hdWRpbyAtIGxhc3Rsb3N0LmF1ZGlvKSAvIGRlbHRhLmF1ZGlvKSA6IDA7XG4gICAgICAgICAgICAgICAgbG9zcy52aWRlbyA9IChkZWx0YS52aWRlbyA+IDApID8gTWF0aC5jZWlsKDEwMCAqIChsb3N0LnZpZGVvIC0gbGFzdGxvc3QudmlkZW8pIC8gZGVsdGEudmlkZW8pIDogMDtcbiAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdwYWNrZXRsb3NzLmppbmdsZScsIFtzZWxmLnNpZCwgbG9zc10pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9LCBpbnRlcnZhbCB8fCAzMDAwKTtcbiAgICByZXR1cm4gdGhpcy5zdGF0c2ludGVydmFsO1xufTtcblxuSmluZ2xlU2Vzc2lvbi5vbkppbmdsZUVycm9yID0gZnVuY3Rpb24gKHNlc3Npb24sIGVycm9yKVxue1xuICAgIGNvbnNvbGUuZXJyb3IoXCJKaW5nbGUgZXJyb3JcIiwgZXJyb3IpO1xufVxuXG5KaW5nbGVTZXNzaW9uLm9uSmluZ2xlRmF0YWxFcnJvciA9IGZ1bmN0aW9uIChzZXNzaW9uLCBlcnJvcilcbntcbiAgICB0aGlzLnNlcnZpY2Uuc2Vzc2lvblRlcm1pbmF0ZWQgPSB0cnVlO1xuICAgIHRoaXMuY29ubmVjdGlvbi5lbXVjLmRvTGVhdmUoKTtcbiAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKFwiZGlhbG9nLnNvcnJ5XCIsXG4gICAgICAgIFwiZGlhbG9nLmludGVybmFsRXJyb3JcIik7XG59XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLnNldExvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgLy8gcHV0IG91ciBzc3JjcyBpbnRvIHByZXNlbmNlIHNvIG90aGVyIGNsaWVudHMgY2FuIGlkZW50aWZ5IG91ciBzdHJlYW1cbiAgICB2YXIgbmV3c3NyY3MgPSBbXTtcbiAgICB2YXIgbWVkaWEgPSBBUFAuc2ltdWxjYXN0LnBhcnNlTWVkaWEodGhpcy5wZWVyY29ubmVjdGlvbi5sb2NhbERlc2NyaXB0aW9uKTtcbiAgICBtZWRpYS5mb3JFYWNoKGZ1bmN0aW9uIChtZWRpYSkge1xuXG4gICAgICAgIGlmKE9iamVjdC5rZXlzKG1lZGlhLnNvdXJjZXMpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIC8vIFRPRE8oZ3ApIG1heWJlIGV4Y2x1ZGUgRklEIHN0cmVhbXM/XG4gICAgICAgICAgICBPYmplY3Qua2V5cyhtZWRpYS5zb3VyY2VzKS5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgbmV3c3NyY3MucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICdzc3JjJzogc3NyYyxcbiAgICAgICAgICAgICAgICAgICAgJ3R5cGUnOiBtZWRpYS50eXBlLFxuICAgICAgICAgICAgICAgICAgICAnZGlyZWN0aW9uJzogbWVkaWEuZGlyZWN0aW9uXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmKHRoaXMubG9jYWxTdHJlYW1zU1NSQyAmJiB0aGlzLmxvY2FsU3RyZWFtc1NTUkNbbWVkaWEudHlwZV0pXG4gICAgICAgIHtcbiAgICAgICAgICAgIG5ld3NzcmNzLnB1c2goe1xuICAgICAgICAgICAgICAgICdzc3JjJzogdGhpcy5sb2NhbFN0cmVhbXNTU1JDW21lZGlhLnR5cGVdLFxuICAgICAgICAgICAgICAgICd0eXBlJzogbWVkaWEudHlwZSxcbiAgICAgICAgICAgICAgICAnZGlyZWN0aW9uJzogbWVkaWEuZGlyZWN0aW9uXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgfSk7XG5cbiAgICBjb25zb2xlLmxvZygnbmV3IHNzcmNzJywgbmV3c3NyY3MpO1xuXG4gICAgLy8gSGF2ZSB0byBjbGVhciBwcmVzZW5jZSBtYXAgdG8gZ2V0IHJpZCBvZiByZW1vdmVkIHN0cmVhbXNcbiAgICB0aGlzLmNvbm5lY3Rpb24uZW11Yy5jbGVhclByZXNlbmNlTWVkaWEoKTtcblxuICAgIGlmIChuZXdzc3Jjcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDw9IG5ld3NzcmNzLmxlbmd0aDsgaSArKykge1xuICAgICAgICAgICAgLy8gQ2hhbmdlIHZpZGVvIHR5cGUgdG8gc2NyZWVuXG4gICAgICAgICAgICBpZiAobmV3c3NyY3NbaS0xXS50eXBlID09PSAndmlkZW8nICYmIEFQUC5kZXNrdG9wc2hhcmluZy5pc1VzaW5nU2NyZWVuU3RyZWFtKCkpIHtcbiAgICAgICAgICAgICAgICBuZXdzc3Jjc1tpLTFdLnR5cGUgPSAnc2NyZWVuJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5lbXVjLmFkZE1lZGlhVG9QcmVzZW5jZShpLFxuICAgICAgICAgICAgICAgIG5ld3NzcmNzW2ktMV0udHlwZSwgbmV3c3NyY3NbaS0xXS5zc3JjLCBuZXdzc3Jjc1tpLTFdLmRpcmVjdGlvbik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZW11Yy5zZW5kUHJlc2VuY2UoKTtcbiAgICB9XG59XG5cbi8vIGFuIGF0dGVtcHQgdG8gd29yayBhcm91bmQgaHR0cHM6Ly9naXRodWIuY29tL2ppdHNpL2ppdG1lZXQvaXNzdWVzLzMyXG5mdW5jdGlvbiBzZW5kS2V5ZnJhbWUocGMpIHtcbiAgICBjb25zb2xlLmxvZygnc2VuZGtleWZyYW1lJywgcGMuaWNlQ29ubmVjdGlvblN0YXRlKTtcbiAgICBpZiAocGMuaWNlQ29ubmVjdGlvblN0YXRlICE9PSAnY29ubmVjdGVkJykgcmV0dXJuOyAvLyBzYWZlLi4uXG4gICAgcGMuc2V0UmVtb3RlRGVzY3JpcHRpb24oXG4gICAgICAgIHBjLnJlbW90ZURlc2NyaXB0aW9uLFxuICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBwYy5jcmVhdGVBbnN3ZXIoXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKG1vZGlmaWVkQW5zd2VyKSB7XG4gICAgICAgICAgICAgICAgICAgIHBjLnNldExvY2FsRGVzY3JpcHRpb24oXG4gICAgICAgICAgICAgICAgICAgICAgICBtb2RpZmllZEFuc3dlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBub29wXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3RyaWdnZXJLZXlmcmFtZSBzZXRMb2NhbERlc2NyaXB0aW9uIGZhaWxlZCcsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3RyaWdnZXJLZXlmcmFtZSBjcmVhdGVBbnN3ZXIgZmFpbGVkJywgZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygndHJpZ2dlcktleWZyYW1lIHNldFJlbW90ZURlc2NyaXB0aW9uIGZhaWxlZCcsIGVycm9yKTtcbiAgICAgICAgICAgIEFQUC5VSS5tZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoKTtcbiAgICAgICAgfVxuICAgICk7XG59XG5cblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUucmVtb3RlU3RyZWFtQWRkZWQgPSBmdW5jdGlvbiAoZGF0YSwgdGltZXMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHRoZXNzcmM7XG4gICAgdmFyIHNzcmMyamlkID0gdGhpcy5jb25uZWN0aW9uLmVtdWMuc3NyYzJqaWQ7XG5cbiAgICAvLyBsb29rIHVwIGFuIGFzc29jaWF0ZWQgSklEIGZvciBhIHN0cmVhbSBpZFxuICAgIGlmIChkYXRhLnN0cmVhbS5pZCAmJiBkYXRhLnN0cmVhbS5pZC5pbmRleE9mKCdtaXhlZG1zbGFiZWwnKSA9PT0gLTEpIHtcbiAgICAgICAgLy8gbG9vayBvbmx5IGF0IGE9c3NyYzogYW5kIF9ub3RfIGF0IGE9c3NyYy1ncm91cDogbGluZXNcblxuICAgICAgICB2YXIgc3NyY2xpbmVzXG4gICAgICAgICAgICA9IFNEUFV0aWwuZmluZF9saW5lcyh0aGlzLnBlZXJjb25uZWN0aW9uLnJlbW90ZURlc2NyaXB0aW9uLnNkcCwgJ2E9c3NyYzonKTtcbiAgICAgICAgc3NyY2xpbmVzID0gc3NyY2xpbmVzLmZpbHRlcihmdW5jdGlvbiAobGluZSkge1xuICAgICAgICAgICAgLy8gTk9URShncCkgcHJldmlvdXNseSB3ZSBmaWx0ZXJlZCBvbiB0aGUgbXNsYWJlbCwgYnV0IHRoYXQgcHJvcGVydHlcbiAgICAgICAgICAgIC8vIGlzIG5vdCBhbHdheXMgcHJlc2VudC5cbiAgICAgICAgICAgIC8vIHJldHVybiBsaW5lLmluZGV4T2YoJ21zbGFiZWw6JyArIGRhdGEuc3RyZWFtLmxhYmVsKSAhPT0gLTE7XG5cbiAgICAgICAgICAgIHJldHVybiAoKGxpbmUuaW5kZXhPZignbXNpZDonICsgZGF0YS5zdHJlYW0uaWQpICE9PSAtMSkpO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHNzcmNsaW5lcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRoZXNzcmMgPSBzc3JjbGluZXNbMF0uc3Vic3RyaW5nKDcpLnNwbGl0KCcgJylbMF07XG5cbiAgICAgICAgICAgIC8vIFdlIHNpZ25hbCBvdXIgc3RyZWFtcyAodGhyb3VnaCBKaW5nbGUgdG8gdGhlIGZvY3VzKSBiZWZvcmUgd2Ugc2V0XG4gICAgICAgICAgICAvLyBvdXIgcHJlc2VuY2UgKHRocm91Z2ggd2hpY2ggcGVlcnMgYXNzb2NpYXRlIHJlbW90ZSBzdHJlYW1zIHRvXG4gICAgICAgICAgICAvLyBqaWRzKS4gU28sIGl0IG1pZ2h0IGFycml2ZSB0aGF0IGEgcmVtb3RlIHN0cmVhbSBpcyBhZGRlZCBidXRcbiAgICAgICAgICAgIC8vIHNzcmMyamlkIGlzIG5vdCB5ZXQgdXBkYXRlZCBhbmQgdGh1cyBkYXRhLnBlZXJqaWQgY2Fubm90IGJlXG4gICAgICAgICAgICAvLyBzdWNjZXNzZnVsbHkgc2V0LiBIZXJlIHdlIHdhaXQgZm9yIHVwIHRvIGEgc2Vjb25kIGZvciB0aGVcbiAgICAgICAgICAgIC8vIHByZXNlbmNlIHRvIGFycml2ZS5cblxuICAgICAgICAgICAgaWYgKCFzc3JjMmppZFt0aGVzc3JjXSkge1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB0aW1lcyA9PT0gJ3VuZGVmaW5lZCcpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aW1lcyA9IDA7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRpbWVzID4gMTApXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm5pbmcoJ1dhaXRpbmcgZm9yIGppZCB0aW1lZCBvdXQnLCB0aGVzc3JjKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbihkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5yZW1vdGVTdHJlYW1BZGRlZChkLCB0aW1lcysrKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfShkYXRhKSwgMjUwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBvayB0byBvdmVyd3JpdGUgdGhlIG9uZSBmcm9tIGZvY3VzPyBtaWdodCBzYXZlIHdvcmsgaW4gY29saWJyaS5qc1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ2Fzc29jaWF0ZWQgamlkJywgc3NyYzJqaWRbdGhlc3NyY10sIGRhdGEucGVlcmppZCk7XG4gICAgICAgICAgICBpZiAoc3NyYzJqaWRbdGhlc3NyY10pIHtcbiAgICAgICAgICAgICAgICBkYXRhLnBlZXJqaWQgPSBzc3JjMmppZFt0aGVzc3JjXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIEFQUC5SVEMuY3JlYXRlUmVtb3RlU3RyZWFtKGRhdGEsIHRoaXMuc2lkLCB0aGVzc3JjKTtcblxuICAgIHZhciBpc1ZpZGVvID0gZGF0YS5zdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGggPiAwO1xuICAgIC8vIGFuIGF0dGVtcHQgdG8gd29yayBhcm91bmQgaHR0cHM6Ly9naXRodWIuY29tL2ppdHNpL2ppdG1lZXQvaXNzdWVzLzMyXG4gICAgaWYgKGlzVmlkZW8gJiZcbiAgICAgICAgZGF0YS5wZWVyamlkICYmIHRoaXMucGVlcmppZCA9PT0gZGF0YS5wZWVyamlkICYmXG4gICAgICAgIGRhdGEuc3RyZWFtLmdldFZpZGVvVHJhY2tzKCkubGVuZ3RoID09PSAwICYmXG4gICAgICAgIEFQUC5SVEMubG9jYWxWaWRlby5nZXRUcmFja3MoKS5sZW5ndGggPiAwKSB7XG4gICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbmRLZXlmcmFtZShzZWxmLnBlZXJjb25uZWN0aW9uKTtcbiAgICAgICAgfSwgMzAwMCk7XG4gICAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IEppbmdsZVNlc3Npb247XG4iLCIvKiBqc2hpbnQgLVcxMTcgKi9cbnZhciBTRFBVdGlsID0gcmVxdWlyZShcIi4vU0RQVXRpbFwiKTtcblxuLy8gU0RQIFNUVUZGXG5mdW5jdGlvbiBTRFAoc2RwKSB7XG4gICAgdGhpcy5tZWRpYSA9IHNkcC5zcGxpdCgnXFxyXFxubT0nKTtcbiAgICBmb3IgKHZhciBpID0gMTsgaSA8IHRoaXMubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy5tZWRpYVtpXSA9ICdtPScgKyB0aGlzLm1lZGlhW2ldO1xuICAgICAgICBpZiAoaSAhPSB0aGlzLm1lZGlhLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgICAgIHRoaXMubWVkaWFbaV0gKz0gJ1xcclxcbic7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5zZXNzaW9uID0gdGhpcy5tZWRpYS5zaGlmdCgpICsgJ1xcclxcbic7XG4gICAgdGhpcy5yYXcgPSB0aGlzLnNlc3Npb24gKyB0aGlzLm1lZGlhLmpvaW4oJycpO1xufVxuLyoqXG4gKiBSZXR1cm5zIG1hcCBvZiBNZWRpYUNoYW5uZWwgbWFwcGVkIHBlciBjaGFubmVsIGlkeC5cbiAqL1xuU0RQLnByb3RvdHlwZS5nZXRNZWRpYVNzcmNNYXAgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIG1lZGlhX3NzcmNzID0ge307XG4gICAgdmFyIHRtcDtcbiAgICBmb3IgKHZhciBtZWRpYWluZGV4ID0gMDsgbWVkaWFpbmRleCA8IHNlbGYubWVkaWEubGVuZ3RoOyBtZWRpYWluZGV4KyspIHtcbiAgICAgICAgdG1wID0gU0RQVXRpbC5maW5kX2xpbmVzKHNlbGYubWVkaWFbbWVkaWFpbmRleF0sICdhPXNzcmM6Jyk7XG4gICAgICAgIHZhciBtaWQgPSBTRFBVdGlsLnBhcnNlX21pZChTRFBVdGlsLmZpbmRfbGluZShzZWxmLm1lZGlhW21lZGlhaW5kZXhdLCAnYT1taWQ6JykpO1xuICAgICAgICB2YXIgbWVkaWEgPSB7XG4gICAgICAgICAgICBtZWRpYWluZGV4OiBtZWRpYWluZGV4LFxuICAgICAgICAgICAgbWlkOiBtaWQsXG4gICAgICAgICAgICBzc3Jjczoge30sXG4gICAgICAgICAgICBzc3JjR3JvdXBzOiBbXVxuICAgICAgICB9O1xuICAgICAgICBtZWRpYV9zc3Jjc1ttZWRpYWluZGV4XSA9IG1lZGlhO1xuICAgICAgICB0bXAuZm9yRWFjaChmdW5jdGlvbiAobGluZSkge1xuICAgICAgICAgICAgdmFyIGxpbmVzc3JjID0gbGluZS5zdWJzdHJpbmcoNykuc3BsaXQoJyAnKVswXTtcbiAgICAgICAgICAgIC8vIGFsbG9jYXRlIG5ldyBDaGFubmVsU3NyY1xuICAgICAgICAgICAgaWYoIW1lZGlhLnNzcmNzW2xpbmVzc3JjXSkge1xuICAgICAgICAgICAgICAgIG1lZGlhLnNzcmNzW2xpbmVzc3JjXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgc3NyYzogbGluZXNzcmMsXG4gICAgICAgICAgICAgICAgICAgIGxpbmVzOiBbXVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBtZWRpYS5zc3Jjc1tsaW5lc3NyY10ubGluZXMucHVzaChsaW5lKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRtcCA9IFNEUFV0aWwuZmluZF9saW5lcyhzZWxmLm1lZGlhW21lZGlhaW5kZXhdLCAnYT1zc3JjLWdyb3VwOicpO1xuICAgICAgICB0bXAuZm9yRWFjaChmdW5jdGlvbihsaW5lKXtcbiAgICAgICAgICAgIHZhciBzZW1hbnRpY3MgPSBsaW5lLnN1YnN0cigwLCBpZHgpLnN1YnN0cigxMyk7XG4gICAgICAgICAgICB2YXIgc3NyY3MgPSBsaW5lLnN1YnN0cigxNCArIHNlbWFudGljcy5sZW5ndGgpLnNwbGl0KCcgJyk7XG4gICAgICAgICAgICBpZiAoc3NyY3MubGVuZ3RoICE9IDApIHtcbiAgICAgICAgICAgICAgICBtZWRpYS5zc3JjR3JvdXBzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBzZW1hbnRpY3M6IHNlbWFudGljcyxcbiAgICAgICAgICAgICAgICAgICAgc3NyY3M6IHNzcmNzXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gbWVkaWFfc3NyY3M7XG59O1xuLyoqXG4gKiBSZXR1cm5zIDx0dD50cnVlPC90dD4gaWYgdGhpcyBTRFAgY29udGFpbnMgZ2l2ZW4gU1NSQy5cbiAqIEBwYXJhbSBzc3JjIHRoZSBzc3JjIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IDx0dD50cnVlPC90dD4gaWYgdGhpcyBTRFAgY29udGFpbnMgZ2l2ZW4gU1NSQy5cbiAqL1xuU0RQLnByb3RvdHlwZS5jb250YWluc1NTUkMgPSBmdW5jdGlvbihzc3JjKSB7XG4gICAgdmFyIG1lZGlhcyA9IHRoaXMuZ2V0TWVkaWFTc3JjTWFwKCk7XG4gICAgdmFyIGNvbnRhaW5zID0gZmFsc2U7XG4gICAgT2JqZWN0LmtleXMobWVkaWFzKS5mb3JFYWNoKGZ1bmN0aW9uKG1lZGlhaW5kZXgpe1xuICAgICAgICB2YXIgbWVkaWEgPSBtZWRpYXNbbWVkaWFpbmRleF07XG4gICAgICAgIC8vY29uc29sZS5sb2coXCJDaGVja1wiLCBjaGFubmVsLCBzc3JjKTtcbiAgICAgICAgaWYoT2JqZWN0LmtleXMobWVkaWEuc3NyY3MpLmluZGV4T2Yoc3NyYykgIT0gLTEpe1xuICAgICAgICAgICAgY29udGFpbnMgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIGNvbnRhaW5zO1xufTtcblxuXG4vLyByZW1vdmUgaVNBQyBhbmQgQ04gZnJvbSBTRFBcblNEUC5wcm90b3R5cGUubWFuZ2xlID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBpLCBqLCBtbGluZSwgbGluZXMsIHJ0cG1hcCwgbmV3ZGVzYztcbiAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICBsaW5lcyA9IHRoaXMubWVkaWFbaV0uc3BsaXQoJ1xcclxcbicpO1xuICAgICAgICBsaW5lcy5wb3AoKTsgLy8gcmVtb3ZlIGVtcHR5IGxhc3QgZWxlbWVudFxuICAgICAgICBtbGluZSA9IFNEUFV0aWwucGFyc2VfbWxpbmUobGluZXMuc2hpZnQoKSk7XG4gICAgICAgIGlmIChtbGluZS5tZWRpYSAhPSAnYXVkaW8nKVxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIG5ld2Rlc2MgPSAnJztcbiAgICAgICAgbWxpbmUuZm10Lmxlbmd0aCA9IDA7XG4gICAgICAgIGZvciAoaiA9IDA7IGogPCBsaW5lcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgaWYgKGxpbmVzW2pdLnN1YnN0cigwLCA5KSA9PSAnYT1ydHBtYXA6Jykge1xuICAgICAgICAgICAgICAgIHJ0cG1hcCA9IFNEUFV0aWwucGFyc2VfcnRwbWFwKGxpbmVzW2pdKTtcbiAgICAgICAgICAgICAgICBpZiAocnRwbWFwLm5hbWUgPT0gJ0NOJyB8fCBydHBtYXAubmFtZSA9PSAnSVNBQycpXG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIG1saW5lLmZtdC5wdXNoKHJ0cG1hcC5pZCk7XG4gICAgICAgICAgICAgICAgbmV3ZGVzYyArPSBsaW5lc1tqXSArICdcXHJcXG4nO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZXdkZXNjICs9IGxpbmVzW2pdICsgJ1xcclxcbic7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tZWRpYVtpXSA9IFNEUFV0aWwuYnVpbGRfbWxpbmUobWxpbmUpICsgJ1xcclxcbic7XG4gICAgICAgIHRoaXMubWVkaWFbaV0gKz0gbmV3ZGVzYztcbiAgICB9XG4gICAgdGhpcy5yYXcgPSB0aGlzLnNlc3Npb24gKyB0aGlzLm1lZGlhLmpvaW4oJycpO1xufTtcblxuLy8gcmVtb3ZlIGxpbmVzIG1hdGNoaW5nIHByZWZpeCBmcm9tIHNlc3Npb24gc2VjdGlvblxuU0RQLnByb3RvdHlwZS5yZW1vdmVTZXNzaW9uTGluZXMgPSBmdW5jdGlvbihwcmVmaXgpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGxpbmVzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMuc2Vzc2lvbiwgcHJlZml4KTtcbiAgICBsaW5lcy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgICAgc2VsZi5zZXNzaW9uID0gc2VsZi5zZXNzaW9uLnJlcGxhY2UobGluZSArICdcXHJcXG4nLCAnJyk7XG4gICAgfSk7XG4gICAgdGhpcy5yYXcgPSB0aGlzLnNlc3Npb24gKyB0aGlzLm1lZGlhLmpvaW4oJycpO1xuICAgIHJldHVybiBsaW5lcztcbn1cbi8vIHJlbW92ZSBsaW5lcyBtYXRjaGluZyBwcmVmaXggZnJvbSBhIG1lZGlhIHNlY3Rpb24gc3BlY2lmaWVkIGJ5IG1lZGlhaW5kZXhcbi8vIFRPRE86IG5vbi1udW1lcmljIG1lZGlhaW5kZXggY291bGQgbWF0Y2ggbWlkXG5TRFAucHJvdG90eXBlLnJlbW92ZU1lZGlhTGluZXMgPSBmdW5jdGlvbihtZWRpYWluZGV4LCBwcmVmaXgpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGxpbmVzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMubWVkaWFbbWVkaWFpbmRleF0sIHByZWZpeCk7XG4gICAgbGluZXMuZm9yRWFjaChmdW5jdGlvbihsaW5lKSB7XG4gICAgICAgIHNlbGYubWVkaWFbbWVkaWFpbmRleF0gPSBzZWxmLm1lZGlhW21lZGlhaW5kZXhdLnJlcGxhY2UobGluZSArICdcXHJcXG4nLCAnJyk7XG4gICAgfSk7XG4gICAgdGhpcy5yYXcgPSB0aGlzLnNlc3Npb24gKyB0aGlzLm1lZGlhLmpvaW4oJycpO1xuICAgIHJldHVybiBsaW5lcztcbn1cblxuLy8gYWRkIGNvbnRlbnQncyB0byBhIGppbmdsZSBlbGVtZW50XG5TRFAucHJvdG90eXBlLnRvSmluZ2xlID0gZnVuY3Rpb24gKGVsZW0sIHRoZWNyZWF0b3IsIHNzcmNzKSB7XG4vLyAgICBjb25zb2xlLmxvZyhcIlNTUkNcIiArIHNzcmNzW1wiYXVkaW9cIl0gKyBcIiAtIFwiICsgc3NyY3NbXCJ2aWRlb1wiXSk7XG4gICAgdmFyIGksIGosIGssIG1saW5lLCBzc3JjLCBydHBtYXAsIHRtcCwgbGluZSwgbGluZXM7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIC8vIG5ldyBidW5kbGUgcGxhblxuICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLnNlc3Npb24sICdhPWdyb3VwOicpKSB7XG4gICAgICAgIGxpbmVzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMuc2Vzc2lvbiwgJ2E9Z3JvdXA6Jyk7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdG1wID0gbGluZXNbaV0uc3BsaXQoJyAnKTtcbiAgICAgICAgICAgIHZhciBzZW1hbnRpY3MgPSB0bXAuc2hpZnQoKS5zdWJzdHIoOCk7XG4gICAgICAgICAgICBlbGVtLmMoJ2dyb3VwJywge3htbG5zOiAndXJuOnhtcHA6amluZ2xlOmFwcHM6Z3JvdXBpbmc6MCcsIHNlbWFudGljczpzZW1hbnRpY3N9KTtcbiAgICAgICAgICAgIGZvciAoaiA9IDA7IGogPCB0bXAubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICBlbGVtLmMoJ2NvbnRlbnQnLCB7bmFtZTogdG1wW2pdfSkudXAoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsZW0udXAoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICBtbGluZSA9IFNEUFV0aWwucGFyc2VfbWxpbmUodGhpcy5tZWRpYVtpXS5zcGxpdCgnXFxyXFxuJylbMF0pO1xuICAgICAgICBpZiAoIShtbGluZS5tZWRpYSA9PT0gJ2F1ZGlvJyB8fFxuICAgICAgICAgICAgICBtbGluZS5tZWRpYSA9PT0gJ3ZpZGVvJyB8fFxuICAgICAgICAgICAgICBtbGluZS5tZWRpYSA9PT0gJ2FwcGxpY2F0aW9uJykpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1zc3JjOicpKSB7XG4gICAgICAgICAgICBzc3JjID0gU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9c3NyYzonKS5zdWJzdHJpbmcoNykuc3BsaXQoJyAnKVswXTsgLy8gdGFrZSB0aGUgZmlyc3RcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmKHNzcmNzICYmIHNzcmNzW21saW5lLm1lZGlhXSlcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBzc3JjID0gc3NyY3NbbWxpbmUubWVkaWFdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHNzcmMgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGVsZW0uYygnY29udGVudCcsIHtjcmVhdG9yOiB0aGVjcmVhdG9yLCBuYW1lOiBtbGluZS5tZWRpYX0pO1xuICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9bWlkOicpKSB7XG4gICAgICAgICAgICAvLyBwcmVmZXIgaWRlbnRpZmllciBmcm9tIGE9bWlkIGlmIHByZXNlbnRcbiAgICAgICAgICAgIHZhciBtaWQgPSBTRFBVdGlsLnBhcnNlX21pZChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1taWQ6JykpO1xuICAgICAgICAgICAgZWxlbS5hdHRycyh7IG5hbWU6IG1pZCB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1ydHBtYXA6JykubGVuZ3RoKVxuICAgICAgICB7XG4gICAgICAgICAgICBlbGVtLmMoJ2Rlc2NyaXB0aW9uJyxcbiAgICAgICAgICAgICAgICB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6MScsXG4gICAgICAgICAgICAgICAgICAgIG1lZGlhOiBtbGluZS5tZWRpYSB9KTtcbiAgICAgICAgICAgIGlmIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7c3NyYzogc3NyY30pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IG1saW5lLmZtdC5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIHJ0cG1hcCA9IFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPXJ0cG1hcDonICsgbWxpbmUuZm10W2pdKTtcbiAgICAgICAgICAgICAgICBlbGVtLmMoJ3BheWxvYWQtdHlwZScsIFNEUFV0aWwucGFyc2VfcnRwbWFwKHJ0cG1hcCkpO1xuICAgICAgICAgICAgICAgIC8vIHB1dCBhbnkgJ2E9Zm10cDonICsgbWxpbmUuZm10W2pdIGxpbmVzIGludG8gPHBhcmFtIG5hbWU9Zm9vIHZhbHVlPWJhci8+XG4gICAgICAgICAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPWZtdHA6JyArIG1saW5lLmZtdFtqXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdG1wID0gU0RQVXRpbC5wYXJzZV9mbXRwKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPWZtdHA6JyArIG1saW5lLmZtdFtqXSkpO1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGsgPSAwOyBrIDwgdG1wLmxlbmd0aDsgaysrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ3BhcmFtZXRlcicsIHRtcFtrXSkudXAoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLlJ0Y3BGYlRvSmluZ2xlKGksIGVsZW0sIG1saW5lLmZtdFtqXSk7IC8vIFhFUC0wMjkzIC0tIG1hcCBhPXJ0Y3AtZmJcblxuICAgICAgICAgICAgICAgIGVsZW0udXAoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1jcnlwdG86JywgdGhpcy5zZXNzaW9uKSkge1xuICAgICAgICAgICAgICAgIGVsZW0uYygnZW5jcnlwdGlvbicsIHtyZXF1aXJlZDogMX0pO1xuICAgICAgICAgICAgICAgIHZhciBjcnlwdG8gPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5tZWRpYVtpXSwgJ2E9Y3J5cHRvOicsIHRoaXMuc2Vzc2lvbik7XG4gICAgICAgICAgICAgICAgY3J5cHRvLmZvckVhY2goZnVuY3Rpb24obGluZSkge1xuICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ2NyeXB0bycsIFNEUFV0aWwucGFyc2VfY3J5cHRvKGxpbmUpKS51cCgpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGVsZW0udXAoKTsgLy8gZW5kIG9mIGVuY3J5cHRpb25cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHNzcmMpIHtcbiAgICAgICAgICAgICAgICAvLyBuZXcgc3R5bGUgbWFwcGluZ1xuICAgICAgICAgICAgICAgIGVsZW0uYygnc291cmNlJywgeyBzc3JjOiBzc3JjLCB4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjAnIH0pO1xuICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBncm91cCBieSBzc3JjIGFuZCBzdXBwb3J0IG11bHRpcGxlIGRpZmZlcmVudCBzc3Jjc1xuICAgICAgICAgICAgICAgIHZhciBzc3JjbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5tZWRpYVtpXSwgJ2E9c3NyYzonKTtcbiAgICAgICAgICAgICAgICBpZihzc3JjbGluZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBzc3JjbGluZXMuZm9yRWFjaChmdW5jdGlvbiAobGluZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWR4ID0gbGluZS5pbmRleE9mKCcgJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgbGluZXNzcmMgPSBsaW5lLnN1YnN0cigwLCBpZHgpLnN1YnN0cig3KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChsaW5lc3NyYyAhPSBzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcmMgPSBsaW5lc3NyYztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ3NvdXJjZScsIHsgc3NyYzogc3NyYywgeG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6c3NtYTowJyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBrdiA9IGxpbmUuc3Vic3RyKGlkeCArIDEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5jKCdwYXJhbWV0ZXInKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChrdi5pbmRleE9mKCc6JykgPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHsgbmFtZToga3YgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoeyBuYW1lOiBrdi5zcGxpdCgnOicsIDIpWzBdIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoeyB2YWx1ZToga3Yuc3BsaXQoJzonLCAyKVsxXSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0udXAoKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGVsZW0udXAoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ3NvdXJjZScsIHsgc3NyYzogc3NyYywgeG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6c3NtYTowJyB9KTtcbiAgICAgICAgICAgICAgICAgICAgZWxlbS5jKCdwYXJhbWV0ZXInKTtcbiAgICAgICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7bmFtZTogXCJjbmFtZVwiLCB2YWx1ZTpNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHJpbmcoNyl9KTtcbiAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgbXNpZCA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIGlmKG1saW5lLm1lZGlhID09IFwiYXVkaW9cIilcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgbXNpZCA9IEFQUC5SVEMubG9jYWxBdWRpby5nZXRJZCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgbXNpZCA9IEFQUC5SVEMubG9jYWxWaWRlby5nZXRJZCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmKG1zaWQgIT0gbnVsbClcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgbXNpZCA9IG1zaWQucmVwbGFjZSgvW1xceyxcXH1dL2csXCJcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ3BhcmFtZXRlcicpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7bmFtZTogXCJtc2lkXCIsIHZhbHVlOm1zaWR9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0udXAoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYygncGFyYW1ldGVyJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHtuYW1lOiBcIm1zbGFiZWxcIiwgdmFsdWU6bXNpZH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5jKCdwYXJhbWV0ZXInKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoe25hbWU6IFwibGFiZWxcIiwgdmFsdWU6bXNpZH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cblxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIFhFUC0wMzM5IGhhbmRsZSBzc3JjLWdyb3VwIGF0dHJpYnV0ZXNcbiAgICAgICAgICAgICAgICB2YXIgc3NyY19ncm91cF9saW5lcyA9IFNEUFV0aWwuZmluZF9saW5lcyh0aGlzLm1lZGlhW2ldLCAnYT1zc3JjLWdyb3VwOicpO1xuICAgICAgICAgICAgICAgIHNzcmNfZ3JvdXBfbGluZXMuZm9yRWFjaChmdW5jdGlvbihsaW5lKSB7XG4gICAgICAgICAgICAgICAgICAgIGlkeCA9IGxpbmUuaW5kZXhPZignICcpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2VtYW50aWNzID0gbGluZS5zdWJzdHIoMCwgaWR4KS5zdWJzdHIoMTMpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgc3NyY3MgPSBsaW5lLnN1YnN0cigxNCArIHNlbWFudGljcy5sZW5ndGgpLnNwbGl0KCcgJyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChzc3Jjcy5sZW5ndGggIT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5jKCdzc3JjLWdyb3VwJywgeyBzZW1hbnRpY3M6IHNlbWFudGljcywgeG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6c3NtYTowJyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNzcmNzLmZvckVhY2goZnVuY3Rpb24oc3NyYykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYygnc291cmNlJywgeyBzc3JjOiBzc3JjIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC51cCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPXJ0Y3AtbXV4JykpIHtcbiAgICAgICAgICAgICAgICBlbGVtLmMoJ3J0Y3AtbXV4JykudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gWEVQLTAyOTMgLS0gbWFwIGE9cnRjcC1mYjoqXG4gICAgICAgICAgICB0aGlzLlJ0Y3BGYlRvSmluZ2xlKGksIGVsZW0sICcqJyk7XG5cbiAgICAgICAgICAgIC8vIFhFUC0wMjk0XG4gICAgICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9ZXh0bWFwOicpKSB7XG4gICAgICAgICAgICAgICAgbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5tZWRpYVtpXSwgJ2E9ZXh0bWFwOicpO1xuICAgICAgICAgICAgICAgIGZvciAoaiA9IDA7IGogPCBsaW5lcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgICAgICB0bXAgPSBTRFBVdGlsLnBhcnNlX2V4dG1hcChsaW5lc1tqXSk7XG4gICAgICAgICAgICAgICAgICAgIGVsZW0uYygncnRwLWhkcmV4dCcsIHsgeG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6cnRwLWhkcmV4dDowJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHVyaTogdG1wLnVyaSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlkOiB0bXAudmFsdWUgfSk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0bXAuaGFzT3duUHJvcGVydHkoJ2RpcmVjdGlvbicpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKHRtcC5kaXJlY3Rpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdzZW5kb25seSc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoe3NlbmRlcnM6ICdyZXNwb25kZXInfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ3JlY3Zvbmx5JzpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7c2VuZGVyczogJ2luaXRpYXRvcid9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnc2VuZHJlY3YnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHtzZW5kZXJzOiAnYm90aCd9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnaW5hY3RpdmUnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHtzZW5kZXJzOiAnbm9uZSd9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gVE9ETzogaGFuZGxlIHBhcmFtc1xuICAgICAgICAgICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxlbS51cCgpOyAvLyBlbmQgb2YgZGVzY3JpcHRpb25cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIG1hcCBpY2UtdWZyYWcvcHdkLCBkdGxzIGZpbmdlcnByaW50LCBjYW5kaWRhdGVzXG4gICAgICAgIHRoaXMuVHJhbnNwb3J0VG9KaW5nbGUoaSwgZWxlbSk7XG5cbiAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPXNlbmRyZWN2JywgdGhpcy5zZXNzaW9uKSkge1xuICAgICAgICAgICAgZWxlbS5hdHRycyh7c2VuZGVyczogJ2JvdGgnfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9c2VuZG9ubHknLCB0aGlzLnNlc3Npb24pKSB7XG4gICAgICAgICAgICBlbGVtLmF0dHJzKHtzZW5kZXJzOiAnaW5pdGlhdG9yJ30pO1xuICAgICAgICB9IGVsc2UgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPXJlY3Zvbmx5JywgdGhpcy5zZXNzaW9uKSkge1xuICAgICAgICAgICAgZWxlbS5hdHRycyh7c2VuZGVyczogJ3Jlc3BvbmRlcid9KTtcbiAgICAgICAgfSBlbHNlIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1pbmFjdGl2ZScsIHRoaXMuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgIGVsZW0uYXR0cnMoe3NlbmRlcnM6ICdub25lJ30pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtbGluZS5wb3J0ID09ICcwJykge1xuICAgICAgICAgICAgLy8gZXN0b3MgaGFjayB0byByZWplY3QgYW4gbS1saW5lXG4gICAgICAgICAgICBlbGVtLmF0dHJzKHtzZW5kZXJzOiAncmVqZWN0ZWQnfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxlbS51cCgpOyAvLyBlbmQgb2YgY29udGVudFxuICAgIH1cbiAgICBlbGVtLnVwKCk7XG4gICAgcmV0dXJuIGVsZW07XG59O1xuXG5TRFAucHJvdG90eXBlLlRyYW5zcG9ydFRvSmluZ2xlID0gZnVuY3Rpb24gKG1lZGlhaW5kZXgsIGVsZW0pIHtcbiAgICB2YXIgaSA9IG1lZGlhaW5kZXg7XG4gICAgdmFyIHRtcDtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgZWxlbS5jKCd0cmFuc3BvcnQnKTtcblxuICAgIC8vIFhFUC0wMzQzIERUTFMvU0NUUFxuICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW21lZGlhaW5kZXhdLCAnYT1zY3RwbWFwOicpLmxlbmd0aClcbiAgICB7XG4gICAgICAgIHZhciBzY3RwbWFwID0gU0RQVXRpbC5maW5kX2xpbmUoXG4gICAgICAgICAgICB0aGlzLm1lZGlhW2ldLCAnYT1zY3RwbWFwOicsIHNlbGYuc2Vzc2lvbik7XG4gICAgICAgIGlmIChzY3RwbWFwKVxuICAgICAgICB7XG4gICAgICAgICAgICB2YXIgc2N0cEF0dHJzID0gU0RQVXRpbC5wYXJzZV9zY3RwbWFwKHNjdHBtYXApO1xuICAgICAgICAgICAgZWxlbS5jKCdzY3RwbWFwJyxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHhtbG5zOiAndXJuOnhtcHA6amluZ2xlOnRyYW5zcG9ydHM6ZHRscy1zY3RwOjEnLFxuICAgICAgICAgICAgICAgICAgICBudW1iZXI6IHNjdHBBdHRyc1swXSwgLyogU0NUUCBwb3J0ICovXG4gICAgICAgICAgICAgICAgICAgIHByb3RvY29sOiBzY3RwQXR0cnNbMV0sIC8qIHByb3RvY29sICovXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAvLyBPcHRpb25hbCBzdHJlYW0gY291bnQgYXR0cmlidXRlXG4gICAgICAgICAgICBpZiAoc2N0cEF0dHJzLmxlbmd0aCA+IDIpXG4gICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7IHN0cmVhbXM6IHNjdHBBdHRyc1syXX0pO1xuICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIFhFUC0wMzIwXG4gICAgdmFyIGZpbmdlcnByaW50cyA9IFNEUFV0aWwuZmluZF9saW5lcyh0aGlzLm1lZGlhW21lZGlhaW5kZXhdLCAnYT1maW5nZXJwcmludDonLCB0aGlzLnNlc3Npb24pO1xuICAgIGZpbmdlcnByaW50cy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgICAgdG1wID0gU0RQVXRpbC5wYXJzZV9maW5nZXJwcmludChsaW5lKTtcbiAgICAgICAgdG1wLnhtbG5zID0gJ3Vybjp4bXBwOmppbmdsZTphcHBzOmR0bHM6MCc7XG4gICAgICAgIGVsZW0uYygnZmluZ2VycHJpbnQnKS50KHRtcC5maW5nZXJwcmludCk7XG4gICAgICAgIGRlbGV0ZSB0bXAuZmluZ2VycHJpbnQ7XG4gICAgICAgIGxpbmUgPSBTRFBVdGlsLmZpbmRfbGluZShzZWxmLm1lZGlhW21lZGlhaW5kZXhdLCAnYT1zZXR1cDonLCBzZWxmLnNlc3Npb24pO1xuICAgICAgICBpZiAobGluZSkge1xuICAgICAgICAgICAgdG1wLnNldHVwID0gbGluZS5zdWJzdHIoOCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxlbS5hdHRycyh0bXApO1xuICAgICAgICBlbGVtLnVwKCk7IC8vIGVuZCBvZiBmaW5nZXJwcmludFxuICAgIH0pO1xuICAgIHRtcCA9IFNEUFV0aWwuaWNlcGFyYW1zKHRoaXMubWVkaWFbbWVkaWFpbmRleF0sIHRoaXMuc2Vzc2lvbik7XG4gICAgaWYgKHRtcCkge1xuICAgICAgICB0bXAueG1sbnMgPSAndXJuOnhtcHA6amluZ2xlOnRyYW5zcG9ydHM6aWNlLXVkcDoxJztcbiAgICAgICAgZWxlbS5hdHRycyh0bXApO1xuICAgICAgICAvLyBYRVAtMDE3NlxuICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVttZWRpYWluZGV4XSwgJ2E9Y2FuZGlkYXRlOicsIHRoaXMuc2Vzc2lvbikpIHsgLy8gYWRkIGFueSBhPWNhbmRpZGF0ZSBsaW5lc1xuICAgICAgICAgICAgdmFyIGxpbmVzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMubWVkaWFbbWVkaWFpbmRleF0sICdhPWNhbmRpZGF0ZTonLCB0aGlzLnNlc3Npb24pO1xuICAgICAgICAgICAgbGluZXMuZm9yRWFjaChmdW5jdGlvbiAobGluZSkge1xuICAgICAgICAgICAgICAgIGVsZW0uYygnY2FuZGlkYXRlJywgU0RQVXRpbC5jYW5kaWRhdGVUb0ppbmdsZShsaW5lKSkudXAoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsZW0udXAoKTsgLy8gZW5kIG9mIHRyYW5zcG9ydFxufVxuXG5TRFAucHJvdG90eXBlLlJ0Y3BGYlRvSmluZ2xlID0gZnVuY3Rpb24gKG1lZGlhaW5kZXgsIGVsZW0sIHBheWxvYWR0eXBlKSB7IC8vIFhFUC0wMjkzXG4gICAgdmFyIGxpbmVzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMubWVkaWFbbWVkaWFpbmRleF0sICdhPXJ0Y3AtZmI6JyArIHBheWxvYWR0eXBlKTtcbiAgICBsaW5lcy5mb3JFYWNoKGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHZhciB0bXAgPSBTRFBVdGlsLnBhcnNlX3J0Y3BmYihsaW5lKTtcbiAgICAgICAgaWYgKHRtcC50eXBlID09ICd0cnItaW50Jykge1xuICAgICAgICAgICAgZWxlbS5jKCdydGNwLWZiLXRyci1pbnQnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6cnRjcC1mYjowJywgdmFsdWU6IHRtcC5wYXJhbXNbMF19KTtcbiAgICAgICAgICAgIGVsZW0udXAoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGVsZW0uYygncnRjcC1mYicsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpydGNwLWZiOjAnLCB0eXBlOiB0bXAudHlwZX0pO1xuICAgICAgICAgICAgaWYgKHRtcC5wYXJhbXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoeydzdWJ0eXBlJzogdG1wLnBhcmFtc1swXX0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICB9XG4gICAgfSk7XG59O1xuXG5TRFAucHJvdG90eXBlLlJ0Y3BGYkZyb21KaW5nbGUgPSBmdW5jdGlvbiAoZWxlbSwgcGF5bG9hZHR5cGUpIHsgLy8gWEVQLTAyOTNcbiAgICB2YXIgbWVkaWEgPSAnJztcbiAgICB2YXIgdG1wID0gZWxlbS5maW5kKCc+cnRjcC1mYi10cnItaW50W3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnJ0Y3AtZmI6MFwiXScpO1xuICAgIGlmICh0bXAubGVuZ3RoKSB7XG4gICAgICAgIG1lZGlhICs9ICdhPXJ0Y3AtZmI6JyArICcqJyArICcgJyArICd0cnItaW50JyArICcgJztcbiAgICAgICAgaWYgKHRtcC5hdHRyKCd2YWx1ZScpKSB7XG4gICAgICAgICAgICBtZWRpYSArPSB0bXAuYXR0cigndmFsdWUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG1lZGlhICs9ICcwJztcbiAgICAgICAgfVxuICAgICAgICBtZWRpYSArPSAnXFxyXFxuJztcbiAgICB9XG4gICAgdG1wID0gZWxlbS5maW5kKCc+cnRjcC1mYlt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpydGNwLWZiOjBcIl0nKTtcbiAgICB0bXAuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1lZGlhICs9ICdhPXJ0Y3AtZmI6JyArIHBheWxvYWR0eXBlICsgJyAnICsgJCh0aGlzKS5hdHRyKCd0eXBlJyk7XG4gICAgICAgIGlmICgkKHRoaXMpLmF0dHIoJ3N1YnR5cGUnKSkge1xuICAgICAgICAgICAgbWVkaWEgKz0gJyAnICsgJCh0aGlzKS5hdHRyKCdzdWJ0eXBlJyk7XG4gICAgICAgIH1cbiAgICAgICAgbWVkaWEgKz0gJ1xcclxcbic7XG4gICAgfSk7XG4gICAgcmV0dXJuIG1lZGlhO1xufTtcblxuLy8gY29uc3RydWN0IGFuIFNEUCBmcm9tIGEgamluZ2xlIHN0YW56YVxuU0RQLnByb3RvdHlwZS5mcm9tSmluZ2xlID0gZnVuY3Rpb24gKGppbmdsZSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLnJhdyA9ICd2PTBcXHJcXG4nICtcbiAgICAgICAgJ289LSAnICsgJzE5MjM1MTg1MTYnICsgJyAyIElOIElQNCAwLjAuMC4wXFxyXFxuJyArLy8gRklYTUVcbiAgICAgICAgJ3M9LVxcclxcbicgK1xuICAgICAgICAndD0wIDBcXHJcXG4nO1xuICAgIC8vIGh0dHA6Ly90b29scy5pZXRmLm9yZy9odG1sL2RyYWZ0LWlldGYtbW11c2ljLXNkcC1idW5kbGUtbmVnb3RpYXRpb24tMDQjc2VjdGlvbi04XG4gICAgaWYgKCQoamluZ2xlKS5maW5kKCc+Z3JvdXBbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpncm91cGluZzowXCJdJykubGVuZ3RoKSB7XG4gICAgICAgICQoamluZ2xlKS5maW5kKCc+Z3JvdXBbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpncm91cGluZzowXCJdJykuZWFjaChmdW5jdGlvbiAoaWR4LCBncm91cCkge1xuICAgICAgICAgICAgdmFyIGNvbnRlbnRzID0gJChncm91cCkuZmluZCgnPmNvbnRlbnQnKS5tYXAoZnVuY3Rpb24gKGlkeCwgY29udGVudCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBjb250ZW50LmdldEF0dHJpYnV0ZSgnbmFtZScpO1xuICAgICAgICAgICAgfSkuZ2V0KCk7XG4gICAgICAgICAgICBpZiAoY29udGVudHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHNlbGYucmF3ICs9ICdhPWdyb3VwOicgKyAoZ3JvdXAuZ2V0QXR0cmlidXRlKCdzZW1hbnRpY3MnKSB8fCBncm91cC5nZXRBdHRyaWJ1dGUoJ3R5cGUnKSkgKyAnICcgKyBjb250ZW50cy5qb2luKCcgJykgKyAnXFxyXFxuJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5zZXNzaW9uID0gdGhpcy5yYXc7XG4gICAgamluZ2xlLmZpbmQoJz5jb250ZW50JykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBtID0gc2VsZi5qaW5nbGUybWVkaWEoJCh0aGlzKSk7XG4gICAgICAgIHNlbGYubWVkaWEucHVzaChtKTtcbiAgICB9KTtcblxuICAgIC8vIHJlY29uc3RydWN0IG1zaWQtc2VtYW50aWMgLS0gYXBwYXJlbnRseSBub3QgbmVjZXNzYXJ5XG4gICAgLypcbiAgICAgdmFyIG1zaWQgPSBTRFBVdGlsLnBhcnNlX3NzcmModGhpcy5yYXcpO1xuICAgICBpZiAobXNpZC5oYXNPd25Qcm9wZXJ0eSgnbXNsYWJlbCcpKSB7XG4gICAgIHRoaXMuc2Vzc2lvbiArPSBcImE9bXNpZC1zZW1hbnRpYzogV01TIFwiICsgbXNpZC5tc2xhYmVsICsgXCJcXHJcXG5cIjtcbiAgICAgfVxuICAgICAqL1xuXG4gICAgdGhpcy5yYXcgPSB0aGlzLnNlc3Npb24gKyB0aGlzLm1lZGlhLmpvaW4oJycpO1xufTtcblxuLy8gdHJhbnNsYXRlIGEgamluZ2xlIGNvbnRlbnQgZWxlbWVudCBpbnRvIGFuIGFuIFNEUCBtZWRpYSBwYXJ0XG5TRFAucHJvdG90eXBlLmppbmdsZTJtZWRpYSA9IGZ1bmN0aW9uIChjb250ZW50KSB7XG4gICAgdmFyIG1lZGlhID0gJycsXG4gICAgICAgIGRlc2MgPSBjb250ZW50LmZpbmQoJ2Rlc2NyaXB0aW9uJyksXG4gICAgICAgIHNzcmMgPSBkZXNjLmF0dHIoJ3NzcmMnKSxcbiAgICAgICAgc2VsZiA9IHRoaXMsXG4gICAgICAgIHRtcDtcbiAgICB2YXIgc2N0cCA9IGNvbnRlbnQuZmluZChcbiAgICAgICAgJz50cmFuc3BvcnQ+c2N0cG1hcFt4bWxucz1cInVybjp4bXBwOmppbmdsZTp0cmFuc3BvcnRzOmR0bHMtc2N0cDoxXCJdJyk7XG5cbiAgICB0bXAgPSB7IG1lZGlhOiBkZXNjLmF0dHIoJ21lZGlhJykgfTtcbiAgICB0bXAucG9ydCA9ICcxJztcbiAgICBpZiAoY29udGVudC5hdHRyKCdzZW5kZXJzJykgPT0gJ3JlamVjdGVkJykge1xuICAgICAgICAvLyBlc3RvcyBoYWNrIHRvIHJlamVjdCBhbiBtLWxpbmUuXG4gICAgICAgIHRtcC5wb3J0ID0gJzAnO1xuICAgIH1cbiAgICBpZiAoY29udGVudC5maW5kKCc+dHJhbnNwb3J0PmZpbmdlcnByaW50JykubGVuZ3RoIHx8IGRlc2MuZmluZCgnZW5jcnlwdGlvbicpLmxlbmd0aCkge1xuICAgICAgICBpZiAoc2N0cC5sZW5ndGgpXG4gICAgICAgICAgICB0bXAucHJvdG8gPSAnRFRMUy9TQ1RQJztcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgdG1wLnByb3RvID0gJ1JUUC9TQVZQRic7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdG1wLnByb3RvID0gJ1JUUC9BVlBGJztcbiAgICB9XG4gICAgaWYgKCFzY3RwLmxlbmd0aClcbiAgICB7XG4gICAgICAgIHRtcC5mbXQgPSBkZXNjLmZpbmQoJ3BheWxvYWQtdHlwZScpLm1hcChcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuZ2V0QXR0cmlidXRlKCdpZCcpOyB9KS5nZXQoKTtcbiAgICAgICAgbWVkaWEgKz0gU0RQVXRpbC5idWlsZF9tbGluZSh0bXApICsgJ1xcclxcbic7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIG1lZGlhICs9ICdtPWFwcGxpY2F0aW9uIDEgRFRMUy9TQ1RQICcgKyBzY3RwLmF0dHIoJ251bWJlcicpICsgJ1xcclxcbic7XG4gICAgICAgIG1lZGlhICs9ICdhPXNjdHBtYXA6JyArIHNjdHAuYXR0cignbnVtYmVyJykgK1xuICAgICAgICAgICAgJyAnICsgc2N0cC5hdHRyKCdwcm90b2NvbCcpO1xuXG4gICAgICAgIHZhciBzdHJlYW1Db3VudCA9IHNjdHAuYXR0cignc3RyZWFtcycpO1xuICAgICAgICBpZiAoc3RyZWFtQ291bnQpXG4gICAgICAgICAgICBtZWRpYSArPSAnICcgKyBzdHJlYW1Db3VudCArICdcXHJcXG4nO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBtZWRpYSArPSAnXFxyXFxuJztcbiAgICB9XG5cbiAgICBtZWRpYSArPSAnYz1JTiBJUDQgMC4wLjAuMFxcclxcbic7XG4gICAgaWYgKCFzY3RwLmxlbmd0aClcbiAgICAgICAgbWVkaWEgKz0gJ2E9cnRjcDoxIElOIElQNCAwLjAuMC4wXFxyXFxuJztcbiAgICB0bXAgPSBjb250ZW50LmZpbmQoJz50cmFuc3BvcnRbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6dHJhbnNwb3J0czppY2UtdWRwOjFcIl0nKTtcbiAgICBpZiAodG1wLmxlbmd0aCkge1xuICAgICAgICBpZiAodG1wLmF0dHIoJ3VmcmFnJykpIHtcbiAgICAgICAgICAgIG1lZGlhICs9IFNEUFV0aWwuYnVpbGRfaWNldWZyYWcodG1wLmF0dHIoJ3VmcmFnJykpICsgJ1xcclxcbic7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRtcC5hdHRyKCdwd2QnKSkge1xuICAgICAgICAgICAgbWVkaWEgKz0gU0RQVXRpbC5idWlsZF9pY2Vwd2QodG1wLmF0dHIoJ3B3ZCcpKSArICdcXHJcXG4nO1xuICAgICAgICB9XG4gICAgICAgIHRtcC5maW5kKCc+ZmluZ2VycHJpbnQnKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vIEZJWE1FOiBjaGVjayBuYW1lc3BhY2UgYXQgc29tZSBwb2ludFxuICAgICAgICAgICAgbWVkaWEgKz0gJ2E9ZmluZ2VycHJpbnQ6JyArIHRoaXMuZ2V0QXR0cmlidXRlKCdoYXNoJyk7XG4gICAgICAgICAgICBtZWRpYSArPSAnICcgKyAkKHRoaXMpLnRleHQoKTtcbiAgICAgICAgICAgIG1lZGlhICs9ICdcXHJcXG4nO1xuICAgICAgICAgICAgaWYgKHRoaXMuZ2V0QXR0cmlidXRlKCdzZXR1cCcpKSB7XG4gICAgICAgICAgICAgICAgbWVkaWEgKz0gJ2E9c2V0dXA6JyArIHRoaXMuZ2V0QXR0cmlidXRlKCdzZXR1cCcpICsgJ1xcclxcbic7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBzd2l0Y2ggKGNvbnRlbnQuYXR0cignc2VuZGVycycpKSB7XG4gICAgICAgIGNhc2UgJ2luaXRpYXRvcic6XG4gICAgICAgICAgICBtZWRpYSArPSAnYT1zZW5kb25seVxcclxcbic7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAncmVzcG9uZGVyJzpcbiAgICAgICAgICAgIG1lZGlhICs9ICdhPXJlY3Zvbmx5XFxyXFxuJztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdub25lJzpcbiAgICAgICAgICAgIG1lZGlhICs9ICdhPWluYWN0aXZlXFxyXFxuJztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdib3RoJzpcbiAgICAgICAgICAgIG1lZGlhICs9ICdhPXNlbmRyZWN2XFxyXFxuJztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgIH1cbiAgICBtZWRpYSArPSAnYT1taWQ6JyArIGNvbnRlbnQuYXR0cignbmFtZScpICsgJ1xcclxcbic7XG5cbiAgICAvLyA8ZGVzY3JpcHRpb24+PHJ0Y3AtbXV4Lz48L2Rlc2NyaXB0aW9uPlxuICAgIC8vIHNlZSBodHRwOi8vY29kZS5nb29nbGUuY29tL3AvbGliamluZ2xlL2lzc3Vlcy9kZXRhaWw/aWQ9MzA5IC0tIG5vIHNwZWMgdGhvdWdoXG4gICAgLy8gYW5kIGh0dHA6Ly9tYWlsLmphYmJlci5vcmcvcGlwZXJtYWlsL2ppbmdsZS8yMDExLURlY2VtYmVyLzAwMTc2MS5odG1sXG4gICAgaWYgKGRlc2MuZmluZCgncnRjcC1tdXgnKS5sZW5ndGgpIHtcbiAgICAgICAgbWVkaWEgKz0gJ2E9cnRjcC1tdXhcXHJcXG4nO1xuICAgIH1cblxuICAgIGlmIChkZXNjLmZpbmQoJ2VuY3J5cHRpb24nKS5sZW5ndGgpIHtcbiAgICAgICAgZGVzYy5maW5kKCdlbmNyeXB0aW9uPmNyeXB0bycpLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgbWVkaWEgKz0gJ2E9Y3J5cHRvOicgKyB0aGlzLmdldEF0dHJpYnV0ZSgndGFnJyk7XG4gICAgICAgICAgICBtZWRpYSArPSAnICcgKyB0aGlzLmdldEF0dHJpYnV0ZSgnY3J5cHRvLXN1aXRlJyk7XG4gICAgICAgICAgICBtZWRpYSArPSAnICcgKyB0aGlzLmdldEF0dHJpYnV0ZSgna2V5LXBhcmFtcycpO1xuICAgICAgICAgICAgaWYgKHRoaXMuZ2V0QXR0cmlidXRlKCdzZXNzaW9uLXBhcmFtcycpKSB7XG4gICAgICAgICAgICAgICAgbWVkaWEgKz0gJyAnICsgdGhpcy5nZXRBdHRyaWJ1dGUoJ3Nlc3Npb24tcGFyYW1zJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBtZWRpYSArPSAnXFxyXFxuJztcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGRlc2MuZmluZCgncGF5bG9hZC10eXBlJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1lZGlhICs9IFNEUFV0aWwuYnVpbGRfcnRwbWFwKHRoaXMpICsgJ1xcclxcbic7XG4gICAgICAgIGlmICgkKHRoaXMpLmZpbmQoJz5wYXJhbWV0ZXInKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIG1lZGlhICs9ICdhPWZtdHA6JyArIHRoaXMuZ2V0QXR0cmlidXRlKCdpZCcpICsgJyAnO1xuICAgICAgICAgICAgbWVkaWEgKz0gJCh0aGlzKS5maW5kKCdwYXJhbWV0ZXInKS5tYXAoZnVuY3Rpb24gKCkgeyByZXR1cm4gKHRoaXMuZ2V0QXR0cmlidXRlKCduYW1lJykgPyAodGhpcy5nZXRBdHRyaWJ1dGUoJ25hbWUnKSArICc9JykgOiAnJykgKyB0aGlzLmdldEF0dHJpYnV0ZSgndmFsdWUnKTsgfSkuZ2V0KCkuam9pbignOyAnKTtcbiAgICAgICAgICAgIG1lZGlhICs9ICdcXHJcXG4nO1xuICAgICAgICB9XG4gICAgICAgIC8vIHhlcC0wMjkzXG4gICAgICAgIG1lZGlhICs9IHNlbGYuUnRjcEZiRnJvbUppbmdsZSgkKHRoaXMpLCB0aGlzLmdldEF0dHJpYnV0ZSgnaWQnKSk7XG4gICAgfSk7XG5cbiAgICAvLyB4ZXAtMDI5M1xuICAgIG1lZGlhICs9IHNlbGYuUnRjcEZiRnJvbUppbmdsZShkZXNjLCAnKicpO1xuXG4gICAgLy8geGVwLTAyOTRcbiAgICB0bXAgPSBkZXNjLmZpbmQoJz5ydHAtaGRyZXh0W3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnJ0cC1oZHJleHQ6MFwiXScpO1xuICAgIHRtcC5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbWVkaWEgKz0gJ2E9ZXh0bWFwOicgKyB0aGlzLmdldEF0dHJpYnV0ZSgnaWQnKSArICcgJyArIHRoaXMuZ2V0QXR0cmlidXRlKCd1cmknKSArICdcXHJcXG4nO1xuICAgIH0pO1xuXG4gICAgY29udGVudC5maW5kKCc+dHJhbnNwb3J0W3htbG5zPVwidXJuOnhtcHA6amluZ2xlOnRyYW5zcG9ydHM6aWNlLXVkcDoxXCJdPmNhbmRpZGF0ZScpLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICBtZWRpYSArPSBTRFBVdGlsLmNhbmRpZGF0ZUZyb21KaW5nbGUodGhpcyk7XG4gICAgfSk7XG5cbiAgICAvLyBYRVAtMDMzOSBoYW5kbGUgc3NyYy1ncm91cCBhdHRyaWJ1dGVzXG4gICAgdG1wID0gY29udGVudC5maW5kKCdkZXNjcmlwdGlvbj5zc3JjLWdyb3VwW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnNzbWE6MFwiXScpLmVhY2goZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBzZW1hbnRpY3MgPSB0aGlzLmdldEF0dHJpYnV0ZSgnc2VtYW50aWNzJyk7XG4gICAgICAgIHZhciBzc3JjcyA9ICQodGhpcykuZmluZCgnPnNvdXJjZScpLm1hcChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZSgnc3NyYycpO1xuICAgICAgICB9KS5nZXQoKTtcblxuICAgICAgICBpZiAoc3NyY3MubGVuZ3RoICE9IDApIHtcbiAgICAgICAgICAgIG1lZGlhICs9ICdhPXNzcmMtZ3JvdXA6JyArIHNlbWFudGljcyArICcgJyArIHNzcmNzLmpvaW4oJyAnKSArICdcXHJcXG4nO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICB0bXAgPSBjb250ZW50LmZpbmQoJ2Rlc2NyaXB0aW9uPnNvdXJjZVt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjBcIl0nKTtcbiAgICB0bXAuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzc3JjID0gdGhpcy5nZXRBdHRyaWJ1dGUoJ3NzcmMnKTtcbiAgICAgICAgJCh0aGlzKS5maW5kKCc+cGFyYW1ldGVyJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBtZWRpYSArPSAnYT1zc3JjOicgKyBzc3JjICsgJyAnICsgdGhpcy5nZXRBdHRyaWJ1dGUoJ25hbWUnKTtcbiAgICAgICAgICAgIGlmICh0aGlzLmdldEF0dHJpYnV0ZSgndmFsdWUnKSAmJiB0aGlzLmdldEF0dHJpYnV0ZSgndmFsdWUnKS5sZW5ndGgpXG4gICAgICAgICAgICAgICAgbWVkaWEgKz0gJzonICsgdGhpcy5nZXRBdHRyaWJ1dGUoJ3ZhbHVlJyk7XG4gICAgICAgICAgICBtZWRpYSArPSAnXFxyXFxuJztcbiAgICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gbWVkaWE7XG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gU0RQO1xuXG4iLCJmdW5jdGlvbiBTRFBEaWZmZXIobXlTRFAsIG90aGVyU0RQKSB7XG4gICAgdGhpcy5teVNEUCA9IG15U0RQO1xuICAgIHRoaXMub3RoZXJTRFAgPSBvdGhlclNEUDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIG1hcCBvZiBNZWRpYUNoYW5uZWwgdGhhdCBjb250YWlucyBvbmx5IG1lZGlhIG5vdCBjb250YWluZWQgaW4gPHR0Pm90aGVyU2RwPC90dD4uIE1hcHBlZCBieSBjaGFubmVsIGlkeC5cbiAqIEBwYXJhbSBvdGhlclNkcCB0aGUgb3RoZXIgU0RQIHRvIGNoZWNrIHNzcmMgd2l0aC5cbiAqL1xuU0RQRGlmZmVyLnByb3RvdHlwZS5nZXROZXdNZWRpYSA9IGZ1bmN0aW9uKCkge1xuXG4gICAgLy8gdGhpcyBjb3VsZCBiZSB1c2VmdWwgaW4gQXJyYXkucHJvdG90eXBlLlxuICAgIGZ1bmN0aW9uIGFycmF5RXF1YWxzKGFycmF5KSB7XG4gICAgICAgIC8vIGlmIHRoZSBvdGhlciBhcnJheSBpcyBhIGZhbHN5IHZhbHVlLCByZXR1cm5cbiAgICAgICAgaWYgKCFhcnJheSlcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgICAgICAvLyBjb21wYXJlIGxlbmd0aHMgLSBjYW4gc2F2ZSBhIGxvdCBvZiB0aW1lXG4gICAgICAgIGlmICh0aGlzLmxlbmd0aCAhPSBhcnJheS5sZW5ndGgpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGw9dGhpcy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHdlIGhhdmUgbmVzdGVkIGFycmF5c1xuICAgICAgICAgICAgaWYgKHRoaXNbaV0gaW5zdGFuY2VvZiBBcnJheSAmJiBhcnJheVtpXSBpbnN0YW5jZW9mIEFycmF5KSB7XG4gICAgICAgICAgICAgICAgLy8gcmVjdXJzZSBpbnRvIHRoZSBuZXN0ZWQgYXJyYXlzXG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzW2ldLmVxdWFscyhhcnJheVtpXSkpXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHRoaXNbaV0gIT0gYXJyYXlbaV0pIHtcbiAgICAgICAgICAgICAgICAvLyBXYXJuaW5nIC0gdHdvIGRpZmZlcmVudCBvYmplY3QgaW5zdGFuY2VzIHdpbGwgbmV2ZXIgYmUgZXF1YWw6IHt4OjIwfSAhPSB7eDoyMH1cbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgdmFyIG15TWVkaWFzID0gdGhpcy5teVNEUC5nZXRNZWRpYVNzcmNNYXAoKTtcbiAgICB2YXIgb3RoZXJzTWVkaWFzID0gdGhpcy5vdGhlclNEUC5nZXRNZWRpYVNzcmNNYXAoKTtcbiAgICB2YXIgbmV3TWVkaWEgPSB7fTtcbiAgICBPYmplY3Qua2V5cyhvdGhlcnNNZWRpYXMpLmZvckVhY2goZnVuY3Rpb24ob3RoZXJzTWVkaWFJZHgpIHtcbiAgICAgICAgdmFyIG15TWVkaWEgPSBteU1lZGlhc1tvdGhlcnNNZWRpYUlkeF07XG4gICAgICAgIHZhciBvdGhlcnNNZWRpYSA9IG90aGVyc01lZGlhc1tvdGhlcnNNZWRpYUlkeF07XG4gICAgICAgIGlmKCFteU1lZGlhICYmIG90aGVyc01lZGlhKSB7XG4gICAgICAgICAgICAvLyBBZGQgd2hvbGUgY2hhbm5lbFxuICAgICAgICAgICAgbmV3TWVkaWFbb3RoZXJzTWVkaWFJZHhdID0gb3RoZXJzTWVkaWE7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gTG9vayBmb3IgbmV3IHNzcmNzIGFjY3Jvc3MgdGhlIGNoYW5uZWxcbiAgICAgICAgT2JqZWN0LmtleXMob3RoZXJzTWVkaWEuc3NyY3MpLmZvckVhY2goZnVuY3Rpb24oc3NyYykge1xuICAgICAgICAgICAgaWYoT2JqZWN0LmtleXMobXlNZWRpYS5zc3JjcykuaW5kZXhPZihzc3JjKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAvLyBBbGxvY2F0ZSBjaGFubmVsIGlmIHdlJ3ZlIGZvdW5kIHNzcmMgdGhhdCBkb2Vzbid0IGV4aXN0IGluIG91ciBjaGFubmVsXG4gICAgICAgICAgICAgICAgaWYoIW5ld01lZGlhW290aGVyc01lZGlhSWR4XSl7XG4gICAgICAgICAgICAgICAgICAgIG5ld01lZGlhW290aGVyc01lZGlhSWR4XSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhaW5kZXg6IG90aGVyc01lZGlhLm1lZGlhaW5kZXgsXG4gICAgICAgICAgICAgICAgICAgICAgICBtaWQ6IG90aGVyc01lZGlhLm1pZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNzcmNzOiB7fSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNzcmNHcm91cHM6IFtdXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIG5ld01lZGlhW290aGVyc01lZGlhSWR4XS5zc3Jjc1tzc3JjXSA9IG90aGVyc01lZGlhLnNzcmNzW3NzcmNdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBMb29rIGZvciBuZXcgc3NyYyBncm91cHMgYWNyb3NzIHRoZSBjaGFubmVsc1xuICAgICAgICBvdGhlcnNNZWRpYS5zc3JjR3JvdXBzLmZvckVhY2goZnVuY3Rpb24ob3RoZXJTc3JjR3JvdXApe1xuXG4gICAgICAgICAgICAvLyB0cnkgdG8gbWF0Y2ggdGhlIG90aGVyIHNzcmMtZ3JvdXAgd2l0aCBhbiBzc3JjLWdyb3VwIG9mIG91cnNcbiAgICAgICAgICAgIHZhciBtYXRjaGVkID0gZmFsc2U7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG15TWVkaWEuc3NyY0dyb3Vwcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHZhciBteVNzcmNHcm91cCA9IG15TWVkaWEuc3NyY0dyb3Vwc1tpXTtcbiAgICAgICAgICAgICAgICBpZiAob3RoZXJTc3JjR3JvdXAuc2VtYW50aWNzID09IG15U3NyY0dyb3VwLnNlbWFudGljc1xuICAgICAgICAgICAgICAgICAgICAmJiBhcnJheUVxdWFscy5hcHBseShvdGhlclNzcmNHcm91cC5zc3JjcywgW215U3NyY0dyb3VwLnNzcmNzXSkpIHtcblxuICAgICAgICAgICAgICAgICAgICBtYXRjaGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIW1hdGNoZWQpIHtcbiAgICAgICAgICAgICAgICAvLyBBbGxvY2F0ZSBjaGFubmVsIGlmIHdlJ3ZlIGZvdW5kIGFuIHNzcmMtZ3JvdXAgdGhhdCBkb2Vzbid0XG4gICAgICAgICAgICAgICAgLy8gZXhpc3QgaW4gb3VyIGNoYW5uZWxcblxuICAgICAgICAgICAgICAgIGlmKCFuZXdNZWRpYVtvdGhlcnNNZWRpYUlkeF0pe1xuICAgICAgICAgICAgICAgICAgICBuZXdNZWRpYVtvdGhlcnNNZWRpYUlkeF0gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZWRpYWluZGV4OiBvdGhlcnNNZWRpYS5tZWRpYWluZGV4LFxuICAgICAgICAgICAgICAgICAgICAgICAgbWlkOiBvdGhlcnNNZWRpYS5taWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBzc3Jjczoge30sXG4gICAgICAgICAgICAgICAgICAgICAgICBzc3JjR3JvdXBzOiBbXVxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBuZXdNZWRpYVtvdGhlcnNNZWRpYUlkeF0uc3NyY0dyb3Vwcy5wdXNoKG90aGVyU3NyY0dyb3VwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIG5ld01lZGlhO1xufTtcblxuLyoqXG4gKiBTZW5kcyBTU1JDIHVwZGF0ZSBJUS5cbiAqIEBwYXJhbSBzZHBNZWRpYVNzcmNzIFNTUkNzIG1hcCBvYnRhaW5lZCBmcm9tIFNEUC5nZXROZXdNZWRpYS4gQ250YWlucyBTU1JDcyB0byBhZGQvcmVtb3ZlLlxuICogQHBhcmFtIHNpZCBzZXNzaW9uIGlkZW50aWZpZXIgdGhhdCB3aWxsIGJlIHB1dCBpbnRvIHRoZSBJUS5cbiAqIEBwYXJhbSBpbml0aWF0b3IgaW5pdGlhdG9yIGlkZW50aWZpZXIuXG4gKiBAcGFyYW0gdG9KaWQgZGVzdGluYXRpb24gSmlkXG4gKiBAcGFyYW0gaXNBZGQgaW5kaWNhdGVzIGlmIHRoaXMgaXMgcmVtb3ZlIG9yIGFkZCBvcGVyYXRpb24uXG4gKi9cblNEUERpZmZlci5wcm90b3R5cGUudG9KaW5nbGUgPSBmdW5jdGlvbihtb2RpZnkpIHtcbiAgICB2YXIgc2RwTWVkaWFTc3JjcyA9IHRoaXMuZ2V0TmV3TWVkaWEoKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAvLyBGSVhNRTogb25seSBhbm5vdW5jZSB2aWRlbyBzc3JjcyBzaW5jZSB3ZSBtaXggYXVkaW8gYW5kIGRvbnQgbmVlZFxuICAgIC8vICAgICAgdGhlIGF1ZGlvIHNzcmNzIHRoZXJlZm9yZVxuICAgIHZhciBtb2RpZmllZCA9IGZhbHNlO1xuICAgIE9iamVjdC5rZXlzKHNkcE1lZGlhU3NyY3MpLmZvckVhY2goZnVuY3Rpb24obWVkaWFpbmRleCl7XG4gICAgICAgIG1vZGlmaWVkID0gdHJ1ZTtcbiAgICAgICAgdmFyIG1lZGlhID0gc2RwTWVkaWFTc3Jjc1ttZWRpYWluZGV4XTtcbiAgICAgICAgbW9kaWZ5LmMoJ2NvbnRlbnQnLCB7bmFtZTogbWVkaWEubWlkfSk7XG5cbiAgICAgICAgbW9kaWZ5LmMoJ2Rlc2NyaXB0aW9uJywge3htbG5zOid1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6MScsIG1lZGlhOiBtZWRpYS5taWR9KTtcbiAgICAgICAgLy8gRklYTUU6IG5vdCBjb21wbGV0bHkgc3VyZSB0aGlzIG9wZXJhdGVzIG9uIGJsb2NrcyBhbmQgLyBvciBoYW5kbGVzIGRpZmZlcmVudCBzc3JjcyBjb3JyZWN0bHlcbiAgICAgICAgLy8gZ2VuZXJhdGUgc291cmNlcyBmcm9tIGxpbmVzXG4gICAgICAgIE9iamVjdC5rZXlzKG1lZGlhLnNzcmNzKS5mb3JFYWNoKGZ1bmN0aW9uKHNzcmNOdW0pIHtcbiAgICAgICAgICAgIHZhciBtZWRpYVNzcmMgPSBtZWRpYS5zc3Jjc1tzc3JjTnVtXTtcbiAgICAgICAgICAgIG1vZGlmeS5jKCdzb3VyY2UnLCB7IHhtbG5zOiAndXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnNzbWE6MCcgfSk7XG4gICAgICAgICAgICBtb2RpZnkuYXR0cnMoe3NzcmM6IG1lZGlhU3NyYy5zc3JjfSk7XG4gICAgICAgICAgICAvLyBpdGVyYXRlIG92ZXIgc3NyYyBsaW5lc1xuICAgICAgICAgICAgbWVkaWFTc3JjLmxpbmVzLmZvckVhY2goZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgICAgICAgICB2YXIgaWR4ID0gbGluZS5pbmRleE9mKCcgJyk7XG4gICAgICAgICAgICAgICAgdmFyIGt2ID0gbGluZS5zdWJzdHIoaWR4ICsgMSk7XG4gICAgICAgICAgICAgICAgbW9kaWZ5LmMoJ3BhcmFtZXRlcicpO1xuICAgICAgICAgICAgICAgIGlmIChrdi5pbmRleE9mKCc6JykgPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgbW9kaWZ5LmF0dHJzKHsgbmFtZToga3YgfSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbW9kaWZ5LmF0dHJzKHsgbmFtZToga3Yuc3BsaXQoJzonLCAyKVswXSB9KTtcbiAgICAgICAgICAgICAgICAgICAgbW9kaWZ5LmF0dHJzKHsgdmFsdWU6IGt2LnNwbGl0KCc6JywgMilbMV0gfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIG1vZGlmeS51cCgpOyAvLyBlbmQgb2YgcGFyYW1ldGVyXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIG1vZGlmeS51cCgpOyAvLyBlbmQgb2Ygc291cmNlXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIGdlbmVyYXRlIHNvdXJjZSBncm91cHMgZnJvbSBsaW5lc1xuICAgICAgICBtZWRpYS5zc3JjR3JvdXBzLmZvckVhY2goZnVuY3Rpb24oc3NyY0dyb3VwKSB7XG4gICAgICAgICAgICBpZiAoc3NyY0dyb3VwLnNzcmNzLmxlbmd0aCAhPSAwKSB7XG5cbiAgICAgICAgICAgICAgICBtb2RpZnkuYygnc3NyYy1ncm91cCcsIHtcbiAgICAgICAgICAgICAgICAgICAgc2VtYW50aWNzOiBzc3JjR3JvdXAuc2VtYW50aWNzLFxuICAgICAgICAgICAgICAgICAgICB4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjAnXG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICBzc3JjR3JvdXAuc3NyY3MuZm9yRWFjaChmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgICAgICAgICBtb2RpZnkuYygnc291cmNlJywgeyBzc3JjOiBzc3JjIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAudXAoKTsgLy8gZW5kIG9mIHNvdXJjZVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIG1vZGlmeS51cCgpOyAvLyBlbmQgb2Ygc3NyYy1ncm91cFxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBtb2RpZnkudXAoKTsgLy8gZW5kIG9mIGRlc2NyaXB0aW9uXG4gICAgICAgIG1vZGlmeS51cCgpOyAvLyBlbmQgb2YgY29udGVudFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIG1vZGlmaWVkO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTRFBEaWZmZXI7IiwiU0RQVXRpbCA9IHtcbiAgICBpY2VwYXJhbXM6IGZ1bmN0aW9uIChtZWRpYWRlc2MsIHNlc3Npb25kZXNjKSB7XG4gICAgICAgIHZhciBkYXRhID0gbnVsbDtcbiAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKG1lZGlhZGVzYywgJ2E9aWNlLXVmcmFnOicsIHNlc3Npb25kZXNjKSAmJlxuICAgICAgICAgICAgU0RQVXRpbC5maW5kX2xpbmUobWVkaWFkZXNjLCAnYT1pY2UtcHdkOicsIHNlc3Npb25kZXNjKSkge1xuICAgICAgICAgICAgZGF0YSA9IHtcbiAgICAgICAgICAgICAgICB1ZnJhZzogU0RQVXRpbC5wYXJzZV9pY2V1ZnJhZyhTRFBVdGlsLmZpbmRfbGluZShtZWRpYWRlc2MsICdhPWljZS11ZnJhZzonLCBzZXNzaW9uZGVzYykpLFxuICAgICAgICAgICAgICAgIHB3ZDogU0RQVXRpbC5wYXJzZV9pY2Vwd2QoU0RQVXRpbC5maW5kX2xpbmUobWVkaWFkZXNjLCAnYT1pY2UtcHdkOicsIHNlc3Npb25kZXNjKSlcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSxcbiAgICBwYXJzZV9pY2V1ZnJhZzogZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgcmV0dXJuIGxpbmUuc3Vic3RyaW5nKDEyKTtcbiAgICB9LFxuICAgIGJ1aWxkX2ljZXVmcmFnOiBmdW5jdGlvbiAoZnJhZykge1xuICAgICAgICByZXR1cm4gJ2E9aWNlLXVmcmFnOicgKyBmcmFnO1xuICAgIH0sXG4gICAgcGFyc2VfaWNlcHdkOiBmdW5jdGlvbiAobGluZSkge1xuICAgICAgICByZXR1cm4gbGluZS5zdWJzdHJpbmcoMTApO1xuICAgIH0sXG4gICAgYnVpbGRfaWNlcHdkOiBmdW5jdGlvbiAocHdkKSB7XG4gICAgICAgIHJldHVybiAnYT1pY2UtcHdkOicgKyBwd2Q7XG4gICAgfSxcbiAgICBwYXJzZV9taWQ6IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHJldHVybiBsaW5lLnN1YnN0cmluZyg2KTtcbiAgICB9LFxuICAgIHBhcnNlX21saW5lOiBmdW5jdGlvbiAobGluZSkge1xuICAgICAgICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cmluZygyKS5zcGxpdCgnICcpLFxuICAgICAgICAgICAgZGF0YSA9IHt9O1xuICAgICAgICBkYXRhLm1lZGlhID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgZGF0YS5wb3J0ID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgZGF0YS5wcm90byA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGlmIChwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXSA9PT0gJycpIHsgLy8gdHJhaWxpbmcgd2hpdGVzcGFjZVxuICAgICAgICAgICAgcGFydHMucG9wKCk7XG4gICAgICAgIH1cbiAgICAgICAgZGF0YS5mbXQgPSBwYXJ0cztcbiAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSxcbiAgICBidWlsZF9tbGluZTogZnVuY3Rpb24gKG1saW5lKSB7XG4gICAgICAgIHJldHVybiAnbT0nICsgbWxpbmUubWVkaWEgKyAnICcgKyBtbGluZS5wb3J0ICsgJyAnICsgbWxpbmUucHJvdG8gKyAnICcgKyBtbGluZS5mbXQuam9pbignICcpO1xuICAgIH0sXG4gICAgcGFyc2VfcnRwbWFwOiBmdW5jdGlvbiAobGluZSkge1xuICAgICAgICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cmluZyg5KS5zcGxpdCgnICcpLFxuICAgICAgICAgICAgZGF0YSA9IHt9O1xuICAgICAgICBkYXRhLmlkID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgcGFydHMgPSBwYXJ0c1swXS5zcGxpdCgnLycpO1xuICAgICAgICBkYXRhLm5hbWUgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhLmNsb2NrcmF0ZSA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGRhdGEuY2hhbm5lbHMgPSBwYXJ0cy5sZW5ndGggPyBwYXJ0cy5zaGlmdCgpIDogJzEnO1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIFBhcnNlcyBTRFAgbGluZSBcImE9c2N0cG1hcDouLi5cIiBhbmQgZXh0cmFjdHMgU0NUUCBwb3J0IGZyb20gaXQuXG4gICAgICogQHBhcmFtIGxpbmUgZWcuIFwiYT1zY3RwbWFwOjUwMDAgd2VicnRjLWRhdGFjaGFubmVsXCJcbiAgICAgKiBAcmV0dXJucyBbU0NUUCBwb3J0IG51bWJlciwgcHJvdG9jb2wsIHN0cmVhbXNdXG4gICAgICovXG4gICAgcGFyc2Vfc2N0cG1hcDogZnVuY3Rpb24gKGxpbmUpXG4gICAge1xuICAgICAgICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cmluZygxMCkuc3BsaXQoJyAnKTtcbiAgICAgICAgdmFyIHNjdHBQb3J0ID0gcGFydHNbMF07XG4gICAgICAgIHZhciBwcm90b2NvbCA9IHBhcnRzWzFdO1xuICAgICAgICAvLyBTdHJlYW0gY291bnQgaXMgb3B0aW9uYWxcbiAgICAgICAgdmFyIHN0cmVhbUNvdW50ID0gcGFydHMubGVuZ3RoID4gMiA/IHBhcnRzWzJdIDogbnVsbDtcbiAgICAgICAgcmV0dXJuIFtzY3RwUG9ydCwgcHJvdG9jb2wsIHN0cmVhbUNvdW50XTsvLyBTQ1RQIHBvcnRcbiAgICB9LFxuICAgIGJ1aWxkX3J0cG1hcDogZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgIHZhciBsaW5lID0gJ2E9cnRwbWFwOicgKyBlbC5nZXRBdHRyaWJ1dGUoJ2lkJykgKyAnICcgKyBlbC5nZXRBdHRyaWJ1dGUoJ25hbWUnKSArICcvJyArIGVsLmdldEF0dHJpYnV0ZSgnY2xvY2tyYXRlJyk7XG4gICAgICAgIGlmIChlbC5nZXRBdHRyaWJ1dGUoJ2NoYW5uZWxzJykgJiYgZWwuZ2V0QXR0cmlidXRlKCdjaGFubmVscycpICE9ICcxJykge1xuICAgICAgICAgICAgbGluZSArPSAnLycgKyBlbC5nZXRBdHRyaWJ1dGUoJ2NoYW5uZWxzJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGxpbmU7XG4gICAgfSxcbiAgICBwYXJzZV9jcnlwdG86IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDkpLnNwbGl0KCcgJyksXG4gICAgICAgICAgICBkYXRhID0ge307XG4gICAgICAgIGRhdGEudGFnID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgZGF0YVsnY3J5cHRvLXN1aXRlJ10gPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhWydrZXktcGFyYW1zJ10gPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBpZiAocGFydHMubGVuZ3RoKSB7XG4gICAgICAgICAgICBkYXRhWydzZXNzaW9uLXBhcmFtcyddID0gcGFydHMuam9pbignICcpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH0sXG4gICAgcGFyc2VfZmluZ2VycHJpbnQ6IGZ1bmN0aW9uIChsaW5lKSB7IC8vIFJGQyA0NTcyXG4gICAgICAgIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDE0KS5zcGxpdCgnICcpLFxuICAgICAgICAgICAgZGF0YSA9IHt9O1xuICAgICAgICBkYXRhLmhhc2ggPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhLmZpbmdlcnByaW50ID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgLy8gVE9ETyBhc3NlcnQgdGhhdCBmaW5nZXJwcmludCBzYXRpc2ZpZXMgMlVIRVggKihcIjpcIiAyVUhFWCkgP1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9LFxuICAgIHBhcnNlX2ZtdHA6IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHZhciBwYXJ0cyA9IGxpbmUuc3BsaXQoJyAnKSxcbiAgICAgICAgICAgIGksIGtleSwgdmFsdWUsXG4gICAgICAgICAgICBkYXRhID0gW107XG4gICAgICAgIHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIHBhcnRzID0gcGFydHMuam9pbignICcpLnNwbGl0KCc7Jyk7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAga2V5ID0gcGFydHNbaV0uc3BsaXQoJz0nKVswXTtcbiAgICAgICAgICAgIHdoaWxlIChrZXkubGVuZ3RoICYmIGtleVswXSA9PSAnICcpIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBrZXkuc3Vic3RyaW5nKDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFsdWUgPSBwYXJ0c1tpXS5zcGxpdCgnPScpWzFdO1xuICAgICAgICAgICAgaWYgKGtleSAmJiB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGRhdGEucHVzaCh7bmFtZToga2V5LCB2YWx1ZTogdmFsdWV9KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoa2V5KSB7XG4gICAgICAgICAgICAgICAgLy8gcmZjIDQ3MzMgKERUTUYpIHN0eWxlIHN0dWZmXG4gICAgICAgICAgICAgICAgZGF0YS5wdXNoKHtuYW1lOiAnJywgdmFsdWU6IGtleX0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH0sXG4gICAgcGFyc2VfaWNlY2FuZGlkYXRlOiBmdW5jdGlvbiAobGluZSkge1xuICAgICAgICB2YXIgY2FuZGlkYXRlID0ge30sXG4gICAgICAgICAgICBlbGVtcyA9IGxpbmUuc3BsaXQoJyAnKTtcbiAgICAgICAgY2FuZGlkYXRlLmZvdW5kYXRpb24gPSBlbGVtc1swXS5zdWJzdHJpbmcoMTIpO1xuICAgICAgICBjYW5kaWRhdGUuY29tcG9uZW50ID0gZWxlbXNbMV07XG4gICAgICAgIGNhbmRpZGF0ZS5wcm90b2NvbCA9IGVsZW1zWzJdLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGNhbmRpZGF0ZS5wcmlvcml0eSA9IGVsZW1zWzNdO1xuICAgICAgICBjYW5kaWRhdGUuaXAgPSBlbGVtc1s0XTtcbiAgICAgICAgY2FuZGlkYXRlLnBvcnQgPSBlbGVtc1s1XTtcbiAgICAgICAgLy8gZWxlbXNbNl0gPT4gXCJ0eXBcIlxuICAgICAgICBjYW5kaWRhdGUudHlwZSA9IGVsZW1zWzddO1xuICAgICAgICBjYW5kaWRhdGUuZ2VuZXJhdGlvbiA9IDA7IC8vIGRlZmF1bHQgdmFsdWUsIG1heSBiZSBvdmVyd3JpdHRlbiBiZWxvd1xuICAgICAgICBmb3IgKHZhciBpID0gODsgaSA8IGVsZW1zLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgICAgICAgICBzd2l0Y2ggKGVsZW1zW2ldKSB7XG4gICAgICAgICAgICAgICAgY2FzZSAncmFkZHInOlxuICAgICAgICAgICAgICAgICAgICBjYW5kaWRhdGVbJ3JlbC1hZGRyJ10gPSBlbGVtc1tpICsgMV07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3Jwb3J0JzpcbiAgICAgICAgICAgICAgICAgICAgY2FuZGlkYXRlWydyZWwtcG9ydCddID0gZWxlbXNbaSArIDFdO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdnZW5lcmF0aW9uJzpcbiAgICAgICAgICAgICAgICAgICAgY2FuZGlkYXRlLmdlbmVyYXRpb24gPSBlbGVtc1tpICsgMV07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3RjcHR5cGUnOlxuICAgICAgICAgICAgICAgICAgICBjYW5kaWRhdGUudGNwdHlwZSA9IGVsZW1zW2kgKyAxXTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDogLy8gVE9ET1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygncGFyc2VfaWNlY2FuZGlkYXRlIG5vdCB0cmFuc2xhdGluZyBcIicgKyBlbGVtc1tpXSArICdcIiA9IFwiJyArIGVsZW1zW2kgKyAxXSArICdcIicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNhbmRpZGF0ZS5uZXR3b3JrID0gJzEnO1xuICAgICAgICBjYW5kaWRhdGUuaWQgPSBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHIoMiwgMTApOyAvLyBub3QgYXBwbGljYWJsZSB0byBTRFAgLS0gRklYTUU6IHNob3VsZCBiZSB1bmlxdWUsIG5vdCBqdXN0IHJhbmRvbVxuICAgICAgICByZXR1cm4gY2FuZGlkYXRlO1xuICAgIH0sXG4gICAgYnVpbGRfaWNlY2FuZGlkYXRlOiBmdW5jdGlvbiAoY2FuZCkge1xuICAgICAgICB2YXIgbGluZSA9IFsnYT1jYW5kaWRhdGU6JyArIGNhbmQuZm91bmRhdGlvbiwgY2FuZC5jb21wb25lbnQsIGNhbmQucHJvdG9jb2wsIGNhbmQucHJpb3JpdHksIGNhbmQuaXAsIGNhbmQucG9ydCwgJ3R5cCcsIGNhbmQudHlwZV0uam9pbignICcpO1xuICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgc3dpdGNoIChjYW5kLnR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgJ3NyZmx4JzpcbiAgICAgICAgICAgIGNhc2UgJ3ByZmx4JzpcbiAgICAgICAgICAgIGNhc2UgJ3JlbGF5JzpcbiAgICAgICAgICAgICAgICBpZiAoY2FuZC5oYXNPd25BdHRyaWJ1dGUoJ3JlbC1hZGRyJykgJiYgY2FuZC5oYXNPd25BdHRyaWJ1dGUoJ3JlbC1wb3J0JykpIHtcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSAncmFkZHInO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSBjYW5kWydyZWwtYWRkciddO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSAncnBvcnQnO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSBjYW5kWydyZWwtcG9ydCddO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNhbmQuaGFzT3duQXR0cmlidXRlKCd0Y3B0eXBlJykpIHtcbiAgICAgICAgICAgIGxpbmUgKz0gJ3RjcHR5cGUnO1xuICAgICAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgICAgICBsaW5lICs9IGNhbmQudGNwdHlwZTtcbiAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICB9XG4gICAgICAgIGxpbmUgKz0gJ2dlbmVyYXRpb24nO1xuICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgbGluZSArPSBjYW5kLmhhc093bkF0dHJpYnV0ZSgnZ2VuZXJhdGlvbicpID8gY2FuZC5nZW5lcmF0aW9uIDogJzAnO1xuICAgICAgICByZXR1cm4gbGluZTtcbiAgICB9LFxuICAgIHBhcnNlX3NzcmM6IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgICAgIC8vIHByb3ByaWV0YXJ5IG1hcHBpbmcgb2YgYT1zc3JjIGxpbmVzXG4gICAgICAgIC8vIFRPRE86IHNlZSBcIkppbmdsZSBSVFAgU291cmNlIERlc2NyaXB0aW9uXCIgYnkgSnViZXJ0aSBhbmQgUC4gVGhhdGNoZXIgb24gZ29vZ2xlIGRvY3NcbiAgICAgICAgLy8gYW5kIHBhcnNlIGFjY29yZGluZyB0byB0aGF0XG4gICAgICAgIHZhciBsaW5lcyA9IGRlc2Muc3BsaXQoJ1xcclxcbicpLFxuICAgICAgICAgICAgZGF0YSA9IHt9O1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAobGluZXNbaV0uc3Vic3RyaW5nKDAsIDcpID09ICdhPXNzcmM6Jykge1xuICAgICAgICAgICAgICAgIHZhciBpZHggPSBsaW5lc1tpXS5pbmRleE9mKCcgJyk7XG4gICAgICAgICAgICAgICAgZGF0YVtsaW5lc1tpXS5zdWJzdHIoaWR4ICsgMSkuc3BsaXQoJzonLCAyKVswXV0gPSBsaW5lc1tpXS5zdWJzdHIoaWR4ICsgMSkuc3BsaXQoJzonLCAyKVsxXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9LFxuICAgIHBhcnNlX3J0Y3BmYjogZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHIoMTApLnNwbGl0KCcgJyk7XG4gICAgICAgIHZhciBkYXRhID0ge307XG4gICAgICAgIGRhdGEucHQgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhLnR5cGUgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhLnBhcmFtcyA9IHBhcnRzO1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9LFxuICAgIHBhcnNlX2V4dG1hcDogZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHIoOSkuc3BsaXQoJyAnKTtcbiAgICAgICAgdmFyIGRhdGEgPSB7fTtcbiAgICAgICAgZGF0YS52YWx1ZSA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGlmIChkYXRhLnZhbHVlLmluZGV4T2YoJy8nKSAhPSAtMSkge1xuICAgICAgICAgICAgZGF0YS5kaXJlY3Rpb24gPSBkYXRhLnZhbHVlLnN1YnN0cihkYXRhLnZhbHVlLmluZGV4T2YoJy8nKSArIDEpO1xuICAgICAgICAgICAgZGF0YS52YWx1ZSA9IGRhdGEudmFsdWUuc3Vic3RyKDAsIGRhdGEudmFsdWUuaW5kZXhPZignLycpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRhdGEuZGlyZWN0aW9uID0gJ2JvdGgnO1xuICAgICAgICB9XG4gICAgICAgIGRhdGEudXJpID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgZGF0YS5wYXJhbXMgPSBwYXJ0cztcbiAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSxcbiAgICBmaW5kX2xpbmU6IGZ1bmN0aW9uIChoYXlzdGFjaywgbmVlZGxlLCBzZXNzaW9ucGFydCkge1xuICAgICAgICB2YXIgbGluZXMgPSBoYXlzdGFjay5zcGxpdCgnXFxyXFxuJyk7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChsaW5lc1tpXS5zdWJzdHJpbmcoMCwgbmVlZGxlLmxlbmd0aCkgPT0gbmVlZGxlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGxpbmVzW2ldO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghc2Vzc2lvbnBhcnQpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBzZWFyY2ggc2Vzc2lvbiBwYXJ0XG4gICAgICAgIGxpbmVzID0gc2Vzc2lvbnBhcnQuc3BsaXQoJ1xcclxcbicpO1xuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGxpbmVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICBpZiAobGluZXNbal0uc3Vic3RyaW5nKDAsIG5lZWRsZS5sZW5ndGgpID09IG5lZWRsZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBsaW5lc1tqXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSxcbiAgICBmaW5kX2xpbmVzOiBmdW5jdGlvbiAoaGF5c3RhY2ssIG5lZWRsZSwgc2Vzc2lvbnBhcnQpIHtcbiAgICAgICAgdmFyIGxpbmVzID0gaGF5c3RhY2suc3BsaXQoJ1xcclxcbicpLFxuICAgICAgICAgICAgbmVlZGxlcyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAobGluZXNbaV0uc3Vic3RyaW5nKDAsIG5lZWRsZS5sZW5ndGgpID09IG5lZWRsZSlcbiAgICAgICAgICAgICAgICBuZWVkbGVzLnB1c2gobGluZXNbaV0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChuZWVkbGVzLmxlbmd0aCB8fCAhc2Vzc2lvbnBhcnQpIHtcbiAgICAgICAgICAgIHJldHVybiBuZWVkbGVzO1xuICAgICAgICB9XG4gICAgICAgIC8vIHNlYXJjaCBzZXNzaW9uIHBhcnRcbiAgICAgICAgbGluZXMgPSBzZXNzaW9ucGFydC5zcGxpdCgnXFxyXFxuJyk7XG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbGluZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIGlmIChsaW5lc1tqXS5zdWJzdHJpbmcoMCwgbmVlZGxlLmxlbmd0aCkgPT0gbmVlZGxlKSB7XG4gICAgICAgICAgICAgICAgbmVlZGxlcy5wdXNoKGxpbmVzW2pdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmVlZGxlcztcbiAgICB9LFxuICAgIGNhbmRpZGF0ZVRvSmluZ2xlOiBmdW5jdGlvbiAobGluZSkge1xuICAgICAgICAvLyBhPWNhbmRpZGF0ZToyOTc5MTY2NjYyIDEgdWRwIDIxMTM5MzcxNTEgMTkyLjE2OC4yLjEwMCA1NzY5OCB0eXAgaG9zdCBnZW5lcmF0aW9uIDBcbiAgICAgICAgLy8gICAgICA8Y2FuZGlkYXRlIGNvbXBvbmVudD0uLi4gZm91bmRhdGlvbj0uLi4gZ2VuZXJhdGlvbj0uLi4gaWQ9Li4uIGlwPS4uLiBuZXR3b3JrPS4uLiBwb3J0PS4uLiBwcmlvcml0eT0uLi4gcHJvdG9jb2w9Li4uIHR5cGU9Li4uLz5cbiAgICAgICAgaWYgKGxpbmUuaW5kZXhPZignY2FuZGlkYXRlOicpID09PSAwKSB7XG4gICAgICAgICAgICBsaW5lID0gJ2E9JyArIGxpbmU7XG4gICAgICAgIH0gZWxzZSBpZiAobGluZS5zdWJzdHJpbmcoMCwgMTIpICE9ICdhPWNhbmRpZGF0ZTonKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygncGFyc2VDYW5kaWRhdGUgY2FsbGVkIHdpdGggYSBsaW5lIHRoYXQgaXMgbm90IGEgY2FuZGlkYXRlIGxpbmUnKTtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGxpbmUpO1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGxpbmUuc3Vic3RyaW5nKGxpbmUubGVuZ3RoIC0gMikgPT0gJ1xcclxcbicpIC8vIGNob21wIGl0XG4gICAgICAgICAgICBsaW5lID0gbGluZS5zdWJzdHJpbmcoMCwgbGluZS5sZW5ndGggLSAyKTtcbiAgICAgICAgdmFyIGNhbmRpZGF0ZSA9IHt9LFxuICAgICAgICAgICAgZWxlbXMgPSBsaW5lLnNwbGl0KCcgJyksXG4gICAgICAgICAgICBpO1xuICAgICAgICBpZiAoZWxlbXNbNl0gIT0gJ3R5cCcpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdkaWQgbm90IGZpbmQgdHlwIGluIHRoZSByaWdodCBwbGFjZScpO1xuICAgICAgICAgICAgY29uc29sZS5sb2cobGluZSk7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBjYW5kaWRhdGUuZm91bmRhdGlvbiA9IGVsZW1zWzBdLnN1YnN0cmluZygxMik7XG4gICAgICAgIGNhbmRpZGF0ZS5jb21wb25lbnQgPSBlbGVtc1sxXTtcbiAgICAgICAgY2FuZGlkYXRlLnByb3RvY29sID0gZWxlbXNbMl0udG9Mb3dlckNhc2UoKTtcbiAgICAgICAgY2FuZGlkYXRlLnByaW9yaXR5ID0gZWxlbXNbM107XG4gICAgICAgIGNhbmRpZGF0ZS5pcCA9IGVsZW1zWzRdO1xuICAgICAgICBjYW5kaWRhdGUucG9ydCA9IGVsZW1zWzVdO1xuICAgICAgICAvLyBlbGVtc1s2XSA9PiBcInR5cFwiXG4gICAgICAgIGNhbmRpZGF0ZS50eXBlID0gZWxlbXNbN107XG5cbiAgICAgICAgY2FuZGlkYXRlLmdlbmVyYXRpb24gPSAnMCc7IC8vIGRlZmF1bHQsIG1heSBiZSBvdmVyd3JpdHRlbiBiZWxvd1xuICAgICAgICBmb3IgKGkgPSA4OyBpIDwgZWxlbXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgICAgICAgIHN3aXRjaCAoZWxlbXNbaV0pIHtcbiAgICAgICAgICAgICAgICBjYXNlICdyYWRkcic6XG4gICAgICAgICAgICAgICAgICAgIGNhbmRpZGF0ZVsncmVsLWFkZHInXSA9IGVsZW1zW2kgKyAxXTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAncnBvcnQnOlxuICAgICAgICAgICAgICAgICAgICBjYW5kaWRhdGVbJ3JlbC1wb3J0J10gPSBlbGVtc1tpICsgMV07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2dlbmVyYXRpb24nOlxuICAgICAgICAgICAgICAgICAgICBjYW5kaWRhdGUuZ2VuZXJhdGlvbiA9IGVsZW1zW2kgKyAxXTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAndGNwdHlwZSc6XG4gICAgICAgICAgICAgICAgICAgIGNhbmRpZGF0ZS50Y3B0eXBlID0gZWxlbXNbaSArIDFdO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBkZWZhdWx0OiAvLyBUT0RPXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdub3QgdHJhbnNsYXRpbmcgXCInICsgZWxlbXNbaV0gKyAnXCIgPSBcIicgKyBlbGVtc1tpICsgMV0gKyAnXCInKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjYW5kaWRhdGUubmV0d29yayA9ICcxJztcbiAgICAgICAgY2FuZGlkYXRlLmlkID0gTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyKDIsIDEwKTsgLy8gbm90IGFwcGxpY2FibGUgdG8gU0RQIC0tIEZJWE1FOiBzaG91bGQgYmUgdW5pcXVlLCBub3QganVzdCByYW5kb21cbiAgICAgICAgcmV0dXJuIGNhbmRpZGF0ZTtcbiAgICB9LFxuICAgIGNhbmRpZGF0ZUZyb21KaW5nbGU6IGZ1bmN0aW9uIChjYW5kKSB7XG4gICAgICAgIHZhciBsaW5lID0gJ2E9Y2FuZGlkYXRlOic7XG4gICAgICAgIGxpbmUgKz0gY2FuZC5nZXRBdHRyaWJ1dGUoJ2ZvdW5kYXRpb24nKTtcbiAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgIGxpbmUgKz0gY2FuZC5nZXRBdHRyaWJ1dGUoJ2NvbXBvbmVudCcpO1xuICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgncHJvdG9jb2wnKTsgLy8udG9VcHBlckNhc2UoKTsgLy8gY2hyb21lIE0yMyBkb2Vzbid0IGxpa2UgdGhpc1xuICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgncHJpb3JpdHknKTtcbiAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgIGxpbmUgKz0gY2FuZC5nZXRBdHRyaWJ1dGUoJ2lwJyk7XG4gICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICBsaW5lICs9IGNhbmQuZ2V0QXR0cmlidXRlKCdwb3J0Jyk7XG4gICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICBsaW5lICs9ICd0eXAnO1xuICAgICAgICBsaW5lICs9ICcgJyArIGNhbmQuZ2V0QXR0cmlidXRlKCd0eXBlJyk7XG4gICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICBzd2l0Y2ggKGNhbmQuZ2V0QXR0cmlidXRlKCd0eXBlJykpIHtcbiAgICAgICAgICAgIGNhc2UgJ3NyZmx4JzpcbiAgICAgICAgICAgIGNhc2UgJ3ByZmx4JzpcbiAgICAgICAgICAgIGNhc2UgJ3JlbGF5JzpcbiAgICAgICAgICAgICAgICBpZiAoY2FuZC5nZXRBdHRyaWJ1dGUoJ3JlbC1hZGRyJykgJiYgY2FuZC5nZXRBdHRyaWJ1dGUoJ3JlbC1wb3J0JykpIHtcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSAncmFkZHInO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgncmVsLWFkZHInKTtcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgICAgICAgICAgICAgIGxpbmUgKz0gJ3Jwb3J0JztcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgICAgICAgICAgICAgIGxpbmUgKz0gY2FuZC5nZXRBdHRyaWJ1dGUoJ3JlbC1wb3J0Jyk7XG4gICAgICAgICAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBpZiAoY2FuZC5nZXRBdHRyaWJ1dGUoJ3Byb3RvY29sJykudG9Mb3dlckNhc2UoKSA9PSAndGNwJykge1xuICAgICAgICAgICAgbGluZSArPSAndGNwdHlwZSc7XG4gICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgIGxpbmUgKz0gY2FuZC5nZXRBdHRyaWJ1dGUoJ3RjcHR5cGUnKTtcbiAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICB9XG4gICAgICAgIGxpbmUgKz0gJ2dlbmVyYXRpb24nO1xuICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgnZ2VuZXJhdGlvbicpIHx8ICcwJztcbiAgICAgICAgcmV0dXJuIGxpbmUgKyAnXFxyXFxuJztcbiAgICB9XG59O1xubW9kdWxlLmV4cG9ydHMgPSBTRFBVdGlsOyIsImZ1bmN0aW9uIFRyYWNlYWJsZVBlZXJDb25uZWN0aW9uKGljZV9jb25maWcsIGNvbnN0cmFpbnRzKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBSVENQZWVyY29ubmVjdGlvbiA9IG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEgPyBtb3pSVENQZWVyQ29ubmVjdGlvbiA6IHdlYmtpdFJUQ1BlZXJDb25uZWN0aW9uO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24gPSBuZXcgUlRDUGVlcmNvbm5lY3Rpb24oaWNlX2NvbmZpZywgY29uc3RyYWludHMpO1xuICAgIHRoaXMudXBkYXRlTG9nID0gW107XG4gICAgdGhpcy5zdGF0cyA9IHt9O1xuICAgIHRoaXMuc3RhdHNpbnRlcnZhbCA9IG51bGw7XG4gICAgdGhpcy5tYXhzdGF0cyA9IDA7IC8vIGxpbWl0IHRvIDMwMCB2YWx1ZXMsIGkuZS4gNSBtaW51dGVzOyBzZXQgdG8gMCB0byBkaXNhYmxlXG4gICAgdmFyIEludGVyb3AgPSByZXF1aXJlKCdzZHAtaW50ZXJvcCcpLkludGVyb3A7XG4gICAgdGhpcy5pbnRlcm9wID0gbmV3IEludGVyb3AoKTtcblxuICAgIC8vIG92ZXJyaWRlIGFzIGRlc2lyZWRcbiAgICB0aGlzLnRyYWNlID0gZnVuY3Rpb24gKHdoYXQsIGluZm8pIHtcbiAgICAgICAgLy9jb25zb2xlLndhcm4oJ1dUUkFDRScsIHdoYXQsIGluZm8pO1xuICAgICAgICBzZWxmLnVwZGF0ZUxvZy5wdXNoKHtcbiAgICAgICAgICAgIHRpbWU6IG5ldyBEYXRlKCksXG4gICAgICAgICAgICB0eXBlOiB3aGF0LFxuICAgICAgICAgICAgdmFsdWU6IGluZm8gfHwgXCJcIlxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIHRoaXMub25pY2VjYW5kaWRhdGUgPSBudWxsO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25pY2VjYW5kaWRhdGUgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2VsZi50cmFjZSgnb25pY2VjYW5kaWRhdGUnLCBKU09OLnN0cmluZ2lmeShldmVudC5jYW5kaWRhdGUsIG51bGwsICcgJykpO1xuICAgICAgICBpZiAoc2VsZi5vbmljZWNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgc2VsZi5vbmljZWNhbmRpZGF0ZShldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMub25hZGRzdHJlYW0gPSBudWxsO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25hZGRzdHJlYW0gPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2VsZi50cmFjZSgnb25hZGRzdHJlYW0nLCBldmVudC5zdHJlYW0uaWQpO1xuICAgICAgICBpZiAoc2VsZi5vbmFkZHN0cmVhbSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgc2VsZi5vbmFkZHN0cmVhbShldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMub25yZW1vdmVzdHJlYW0gPSBudWxsO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25yZW1vdmVzdHJlYW0gPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2VsZi50cmFjZSgnb25yZW1vdmVzdHJlYW0nLCBldmVudC5zdHJlYW0uaWQpO1xuICAgICAgICBpZiAoc2VsZi5vbnJlbW92ZXN0cmVhbSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgc2VsZi5vbnJlbW92ZXN0cmVhbShldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMub25zaWduYWxpbmdzdGF0ZWNoYW5nZSA9IG51bGw7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHNlbGYudHJhY2UoJ29uc2lnbmFsaW5nc3RhdGVjaGFuZ2UnLCBzZWxmLnNpZ25hbGluZ1N0YXRlKTtcbiAgICAgICAgaWYgKHNlbGYub25zaWduYWxpbmdzdGF0ZWNoYW5nZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgc2VsZi5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlKGV2ZW50KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgdGhpcy5vbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZSA9IG51bGw7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5vbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBzZWxmLnRyYWNlKCdvbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZScsIHNlbGYuaWNlQ29ubmVjdGlvblN0YXRlKTtcbiAgICAgICAgaWYgKHNlbGYub25pY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHNlbGYub25pY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UoZXZlbnQpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICB0aGlzLm9ubmVnb3RpYXRpb25uZWVkZWQgPSBudWxsO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25uZWdvdGlhdGlvbm5lZWRlZCA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBzZWxmLnRyYWNlKCdvbm5lZ290aWF0aW9ubmVlZGVkJyk7XG4gICAgICAgIGlmIChzZWxmLm9ubmVnb3RpYXRpb25uZWVkZWQgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHNlbGYub25uZWdvdGlhdGlvbm5lZWRlZChldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHNlbGYub25kYXRhY2hhbm5lbCA9IG51bGw7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5vbmRhdGFjaGFubmVsID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHNlbGYudHJhY2UoJ29uZGF0YWNoYW5uZWwnLCBldmVudCk7XG4gICAgICAgIGlmIChzZWxmLm9uZGF0YWNoYW5uZWwgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHNlbGYub25kYXRhY2hhbm5lbChldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGlmICghbmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYSAmJiB0aGlzLm1heHN0YXRzKSB7XG4gICAgICAgIHRoaXMuc3RhdHNpbnRlcnZhbCA9IHdpbmRvdy5zZXRJbnRlcnZhbChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMoZnVuY3Rpb24oc3RhdHMpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHN0YXRzLnJlc3VsdCgpO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVzdWx0cy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUubG9nKHJlc3VsdHNbaV0udHlwZSwgcmVzdWx0c1tpXS5pZCwgcmVzdWx0c1tpXS5uYW1lcygpKVxuICAgICAgICAgICAgICAgICAgICB2YXIgbm93ID0gbmV3IERhdGUoKTtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0c1tpXS5uYW1lcygpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpZCA9IHJlc3VsdHNbaV0uaWQgKyAnLScgKyBuYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFzZWxmLnN0YXRzW2lkXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuc3RhdHNbaWRdID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydFRpbWU6IG5vdyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kVGltZTogbm93LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM6IFtdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lczogW11cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5zdGF0c1tpZF0udmFsdWVzLnB1c2gocmVzdWx0c1tpXS5zdGF0KG5hbWUpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuc3RhdHNbaWRdLnRpbWVzLnB1c2gobm93LmdldFRpbWUoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2VsZi5zdGF0c1tpZF0udmFsdWVzLmxlbmd0aCA+IHNlbGYubWF4c3RhdHMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnN0YXRzW2lkXS52YWx1ZXMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnN0YXRzW2lkXS50aW1lcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5zdGF0c1tpZF0uZW5kVGltZSA9IG5vdztcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgfSwgMTAwMCk7XG4gICAgfVxufTtcblxuZHVtcFNEUCA9IGZ1bmN0aW9uKGRlc2NyaXB0aW9uKSB7XG4gICAgaWYgKHR5cGVvZiBkZXNjcmlwdGlvbiA9PT0gJ3VuZGVmaW5lZCcgfHwgZGVzY3JpcHRpb24gPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgcmV0dXJuICd0eXBlOiAnICsgZGVzY3JpcHRpb24udHlwZSArICdcXHJcXG4nICsgZGVzY3JpcHRpb24uc2RwO1xufTtcblxuaWYgKFRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fX2RlZmluZUdldHRlcl9fICE9PSB1bmRlZmluZWQpIHtcbiAgICBUcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX19kZWZpbmVHZXR0ZXJfXygnc2lnbmFsaW5nU3RhdGUnLCBmdW5jdGlvbigpIHsgcmV0dXJuIHRoaXMucGVlcmNvbm5lY3Rpb24uc2lnbmFsaW5nU3RhdGU7IH0pO1xuICAgIFRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fX2RlZmluZUdldHRlcl9fKCdpY2VDb25uZWN0aW9uU3RhdGUnLCBmdW5jdGlvbigpIHsgcmV0dXJuIHRoaXMucGVlcmNvbm5lY3Rpb24uaWNlQ29ubmVjdGlvblN0YXRlOyB9KTtcbiAgICBUcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX19kZWZpbmVHZXR0ZXJfXygnbG9jYWxEZXNjcmlwdGlvbicsIGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLnRyYWNlKCdnZXRMb2NhbERlc2NyaXB0aW9uOjpwcmVUcmFuc2Zvcm0gKFBsYW4gQSknLCBkdW1wU0RQKHRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbikpO1xuICAgICAgICAvLyBpZiB3ZSdyZSBydW5uaW5nIG9uIEZGLCB0cmFuc2Zvcm0gdG8gUGxhbiBCIGZpcnN0LlxuICAgICAgICB2YXIgZGVzYyA9IHRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbjtcbiAgICAgICAgaWYgKG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgICAgIGRlc2MgPSB0aGlzLmludGVyb3AudG9QbGFuQihkZXNjKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRlc2MgPSBBUFAuc2ltdWxjYXN0LnJldmVyc2VUcmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uKHRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50cmFjZSgnZ2V0TG9jYWxEZXNjcmlwdGlvbjo6cG9zdFRyYW5zZm9ybSAoUGxhbiBCKScsIGR1bXBTRFAoZGVzYykpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9KTtcbiAgICBUcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX19kZWZpbmVHZXR0ZXJfXygncmVtb3RlRGVzY3JpcHRpb24nLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdGhpcy50cmFjZSgnZ2V0UmVtb3RlRGVzY3JpcHRpb246OnByZVRyYW5zZm9ybSAoUGxhbiBBKScsIGR1bXBTRFAodGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbikpO1xuICAgICAgICAvLyBpZiB3ZSdyZSBydW5uaW5nIG9uIEZGLCB0cmFuc2Zvcm0gdG8gUGxhbiBCIGZpcnN0LlxuICAgICAgICB2YXIgZGVzYyA9IHRoaXMucGVlcmNvbm5lY3Rpb24ucmVtb3RlRGVzY3JpcHRpb247XG4gICAgICAgIGlmIChuYXZpZ2F0b3IubW96R2V0VXNlck1lZGlhKSB7XG4gICAgICAgICAgICBkZXNjID0gdGhpcy5pbnRlcm9wLnRvUGxhbkIoZGVzYyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkZXNjID0gQVBQLnNpbXVsY2FzdC5yZXZlcnNlVHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24odGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy50cmFjZSgnZ2V0UmVtb3RlRGVzY3JpcHRpb246OnBvc3RUcmFuc2Zvcm0gKFBsYW4gQiknLCBkdW1wU0RQKGRlc2MpKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfSk7XG59XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRTdHJlYW0gPSBmdW5jdGlvbiAoc3RyZWFtKSB7XG4gICAgdGhpcy50cmFjZSgnYWRkU3RyZWFtJywgc3RyZWFtLmlkKTtcbiAgICBBUFAuc2ltdWxjYXN0LnJlc2V0U2VuZGVyKCk7XG4gICAgdHJ5XG4gICAge1xuICAgICAgICB0aGlzLnBlZXJjb25uZWN0aW9uLmFkZFN0cmVhbShzdHJlYW0pO1xuICAgIH1cbiAgICBjYXRjaCAoZSlcbiAgICB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG59O1xuXG5UcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUucmVtb3ZlU3RyZWFtID0gZnVuY3Rpb24gKHN0cmVhbSwgc3RvcFN0cmVhbXMpIHtcbiAgICB0aGlzLnRyYWNlKCdyZW1vdmVTdHJlYW0nLCBzdHJlYW0uaWQpO1xuICAgIEFQUC5zaW11bGNhc3QucmVzZXRTZW5kZXIoKTtcbiAgICBpZihzdG9wU3RyZWFtcykge1xuICAgICAgICBzdHJlYW0uZ2V0QXVkaW9UcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uICh0cmFjaykge1xuICAgICAgICAgICAgdHJhY2suc3RvcCgpO1xuICAgICAgICB9KTtcbiAgICAgICAgc3RyZWFtLmdldFZpZGVvVHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbiAodHJhY2spIHtcbiAgICAgICAgICAgIHRyYWNrLnN0b3AoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgICAgLy8gRkYgZG9lc24ndCBzdXBwb3J0IHRoaXMgeWV0LlxuICAgICAgICB0aGlzLnBlZXJjb25uZWN0aW9uLnJlbW92ZVN0cmVhbShzdHJlYW0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICB9XG59O1xuXG5UcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuY3JlYXRlRGF0YUNoYW5uZWwgPSBmdW5jdGlvbiAobGFiZWwsIG9wdHMpIHtcbiAgICB0aGlzLnRyYWNlKCdjcmVhdGVEYXRhQ2hhbm5lbCcsIGxhYmVsLCBvcHRzKTtcbiAgICByZXR1cm4gdGhpcy5wZWVyY29ubmVjdGlvbi5jcmVhdGVEYXRhQ2hhbm5lbChsYWJlbCwgb3B0cyk7XG59O1xuXG5UcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuc2V0TG9jYWxEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjcmlwdGlvbiwgc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICB0aGlzLnRyYWNlKCdzZXRMb2NhbERlc2NyaXB0aW9uOjpwcmVUcmFuc2Zvcm0gKFBsYW4gQiknLCBkdW1wU0RQKGRlc2NyaXB0aW9uKSk7XG4gICAgLy8gaWYgd2UncmUgcnVubmluZyBvbiBGRiwgdHJhbnNmb3JtIHRvIFBsYW4gQSBmaXJzdC5cbiAgICBpZiAobmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYSkge1xuICAgICAgICBkZXNjcmlwdGlvbiA9IHRoaXMuaW50ZXJvcC50b1BsYW5BKGRlc2NyaXB0aW9uKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBkZXNjcmlwdGlvbiA9IEFQUC5zaW11bGNhc3QudHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbihkZXNjcmlwdGlvbik7XG4gICAgfVxuICAgIHRoaXMudHJhY2UoJ3NldExvY2FsRGVzY3JpcHRpb246OnBvc3RUcmFuc2Zvcm0gKFBsYW4gQSknLCBkdW1wU0RQKGRlc2NyaXB0aW9uKSk7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uc2V0TG9jYWxEZXNjcmlwdGlvbihkZXNjcmlwdGlvbixcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi50cmFjZSgnc2V0TG9jYWxEZXNjcmlwdGlvbk9uU3VjY2VzcycpO1xuICAgICAgICAgICAgc3VjY2Vzc0NhbGxiYWNrKCk7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgIHNlbGYudHJhY2UoJ3NldExvY2FsRGVzY3JpcHRpb25PbkZhaWx1cmUnLCBlcnIpO1xuICAgICAgICAgICAgZmFpbHVyZUNhbGxiYWNrKGVycik7XG4gICAgICAgIH1cbiAgICApO1xuICAgIC8qXG4gICAgIGlmICh0aGlzLnN0YXRzaW50ZXJ2YWwgPT09IG51bGwgJiYgdGhpcy5tYXhzdGF0cyA+IDApIHtcbiAgICAgLy8gc3RhcnQgZ2F0aGVyaW5nIHN0YXRzXG4gICAgIH1cbiAgICAgKi9cbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5zZXRSZW1vdGVEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjcmlwdGlvbiwgc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICB0aGlzLnRyYWNlKCdzZXRSZW1vdGVEZXNjcmlwdGlvbjo6cHJlVHJhbnNmb3JtIChQbGFuIEIpJywgZHVtcFNEUChkZXNjcmlwdGlvbikpO1xuICAgIC8vIGlmIHdlJ3JlIHJ1bm5pbmcgb24gRkYsIHRyYW5zZm9ybSB0byBQbGFuIEEgZmlyc3QuXG4gICAgaWYgKG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgZGVzY3JpcHRpb24gPSB0aGlzLmludGVyb3AudG9QbGFuQShkZXNjcmlwdGlvbik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBkZXNjcmlwdGlvbiA9IEFQUC5zaW11bGNhc3QudHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24oZGVzY3JpcHRpb24pO1xuICAgIH1cbiAgICB0aGlzLnRyYWNlKCdzZXRSZW1vdGVEZXNjcmlwdGlvbjo6cG9zdFRyYW5zZm9ybSAoUGxhbiBBKScsIGR1bXBTRFAoZGVzY3JpcHRpb24pKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5zZXRSZW1vdGVEZXNjcmlwdGlvbihkZXNjcmlwdGlvbixcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi50cmFjZSgnc2V0UmVtb3RlRGVzY3JpcHRpb25PblN1Y2Nlc3MnKTtcbiAgICAgICAgICAgIHN1Y2Nlc3NDYWxsYmFjaygpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICBzZWxmLnRyYWNlKCdzZXRSZW1vdGVEZXNjcmlwdGlvbk9uRmFpbHVyZScsIGVycik7XG4gICAgICAgICAgICBmYWlsdXJlQ2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuICAgICk7XG4gICAgLypcbiAgICAgaWYgKHRoaXMuc3RhdHNpbnRlcnZhbCA9PT0gbnVsbCAmJiB0aGlzLm1heHN0YXRzID4gMCkge1xuICAgICAvLyBzdGFydCBnYXRoZXJpbmcgc3RhdHNcbiAgICAgfVxuICAgICAqL1xufTtcblxuVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMudHJhY2UoJ3N0b3AnKTtcbiAgICBpZiAodGhpcy5zdGF0c2ludGVydmFsICE9PSBudWxsKSB7XG4gICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKHRoaXMuc3RhdHNpbnRlcnZhbCk7XG4gICAgICAgIHRoaXMuc3RhdHNpbnRlcnZhbCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uY2xvc2UoKTtcbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jcmVhdGVPZmZlciA9IGZ1bmN0aW9uIChzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjaywgY29uc3RyYWludHMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy50cmFjZSgnY3JlYXRlT2ZmZXInLCBKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cywgbnVsbCwgJyAnKSk7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5jcmVhdGVPZmZlcihcbiAgICAgICAgZnVuY3Rpb24gKG9mZmVyKSB7XG4gICAgICAgICAgICBzZWxmLnRyYWNlKCdjcmVhdGVPZmZlck9uU3VjY2Vzczo6cHJlVHJhbnNmb3JtIChQbGFuIEEpJywgZHVtcFNEUChvZmZlcikpO1xuICAgICAgICAgICAgLy8gaWYgd2UncmUgcnVubmluZyBvbiBGRiwgdHJhbnNmb3JtIHRvIFBsYW4gQiBmaXJzdC5cbiAgICAgICAgICAgIGlmIChuYXZpZ2F0b3IubW96R2V0VXNlck1lZGlhKSB7XG4gICAgICAgICAgICAgICAgb2ZmZXIgPSBzZWxmLmludGVyb3AudG9QbGFuQihvZmZlcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzZWxmLnRyYWNlKCdjcmVhdGVPZmZlck9uU3VjY2Vzczo6cG9zdFRyYW5zZm9ybSAoUGxhbiBCKScsIGR1bXBTRFAob2ZmZXIpKTtcbiAgICAgICAgICAgIHN1Y2Nlc3NDYWxsYmFjayhvZmZlcik7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uKGVycikge1xuICAgICAgICAgICAgc2VsZi50cmFjZSgnY3JlYXRlT2ZmZXJPbkZhaWx1cmUnLCBlcnIpO1xuICAgICAgICAgICAgZmFpbHVyZUNhbGxiYWNrKGVycik7XG4gICAgICAgIH0sXG4gICAgICAgIGNvbnN0cmFpbnRzXG4gICAgKTtcbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jcmVhdGVBbnN3ZXIgPSBmdW5jdGlvbiAoc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2ssIGNvbnN0cmFpbnRzKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMudHJhY2UoJ2NyZWF0ZUFuc3dlcicsIEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzLCBudWxsLCAnICcpKTtcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLmNyZWF0ZUFuc3dlcihcbiAgICAgICAgZnVuY3Rpb24gKGFuc3dlcikge1xuICAgICAgICAgICAgc2VsZi50cmFjZSgnY3JlYXRlQW5zd2VyT25TdWNjZXNzOjpwcmVUcmFuc2ZvbSAoUGxhbiBBKScsIGR1bXBTRFAoYW5zd2VyKSk7XG4gICAgICAgICAgICAvLyBpZiB3ZSdyZSBydW5uaW5nIG9uIEZGLCB0cmFuc2Zvcm0gdG8gUGxhbiBBIGZpcnN0LlxuICAgICAgICAgICAgaWYgKG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgICAgICAgICBhbnN3ZXIgPSBzZWxmLmludGVyb3AudG9QbGFuQihhbnN3ZXIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhbnN3ZXIgPSBBUFAuc2ltdWxjYXN0LnRyYW5zZm9ybUFuc3dlcihhbnN3ZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VsZi50cmFjZSgnY3JlYXRlQW5zd2VyT25TdWNjZXNzOjpwb3N0VHJhbnNmb20gKFBsYW4gQiknLCBkdW1wU0RQKGFuc3dlcikpO1xuICAgICAgICAgICAgc3VjY2Vzc0NhbGxiYWNrKGFuc3dlcik7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uKGVycikge1xuICAgICAgICAgICAgc2VsZi50cmFjZSgnY3JlYXRlQW5zd2VyT25GYWlsdXJlJywgZXJyKTtcbiAgICAgICAgICAgIGZhaWx1cmVDYWxsYmFjayhlcnIpO1xuICAgICAgICB9LFxuICAgICAgICBjb25zdHJhaW50c1xuICAgICk7XG59O1xuXG5UcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkSWNlQ2FuZGlkYXRlID0gZnVuY3Rpb24gKGNhbmRpZGF0ZSwgc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2spIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy50cmFjZSgnYWRkSWNlQ2FuZGlkYXRlJywgSlNPTi5zdHJpbmdpZnkoY2FuZGlkYXRlLCBudWxsLCAnICcpKTtcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLmFkZEljZUNhbmRpZGF0ZShjYW5kaWRhdGUpO1xuICAgIC8qIG1heWJlIGxhdGVyXG4gICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uYWRkSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZSxcbiAgICAgZnVuY3Rpb24gKCkge1xuICAgICBzZWxmLnRyYWNlKCdhZGRJY2VDYW5kaWRhdGVPblN1Y2Nlc3MnKTtcbiAgICAgc3VjY2Vzc0NhbGxiYWNrKCk7XG4gICAgIH0sXG4gICAgIGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgc2VsZi50cmFjZSgnYWRkSWNlQ2FuZGlkYXRlT25GYWlsdXJlJywgZXJyKTtcbiAgICAgZmFpbHVyZUNhbGxiYWNrKGVycik7XG4gICAgIH1cbiAgICAgKTtcbiAgICAgKi9cbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTdGF0cyA9IGZ1bmN0aW9uKGNhbGxiYWNrLCBlcnJiYWNrKSB7XG4gICAgaWYgKG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgLy8gaWdub3JlIGZvciBub3cuLi5cbiAgICAgICAgaWYoIWVycmJhY2spXG4gICAgICAgICAgICBlcnJiYWNrID0gZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgICB9XG4gICAgICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMobnVsbCxjYWxsYmFjayxlcnJiYWNrKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnBlZXJjb25uZWN0aW9uLmdldFN0YXRzKGNhbGxiYWNrKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFRyYWNlYWJsZVBlZXJDb25uZWN0aW9uO1xuXG4iLCIvKiBnbG9iYWwgJCwgJGlxLCBBUFAsIGNvbmZpZywgY29ubmVjdGlvbiwgVUksIG1lc3NhZ2VIYW5kbGVyLFxuIHJvb21OYW1lLCBzZXNzaW9uVGVybWluYXRlZCwgU3Ryb3BoZSwgVXRpbCAqL1xudmFyIFhNUFBFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS94bXBwL1hNUFBFdmVudHNcIik7XG52YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi4vc2V0dGluZ3MvU2V0dGluZ3NcIik7XG5cbnZhciBBdXRoZW50aWNhdGlvbkV2ZW50c1xuICAgID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvYXV0aGVudGljYXRpb24vQXV0aGVudGljYXRpb25FdmVudHNcIik7XG5cbi8qKlxuICogQ29udGFpbnMgbG9naWMgcmVzcG9uc2libGUgZm9yIGVuYWJsaW5nL2Rpc2FibGluZyBmdW5jdGlvbmFsaXR5IGF2YWlsYWJsZVxuICogb25seSB0byBtb2RlcmF0b3IgdXNlcnMuXG4gKi9cbnZhciBjb25uZWN0aW9uID0gbnVsbDtcbnZhciBmb2N1c1VzZXJKaWQ7XG5cbmZ1bmN0aW9uIGNyZWF0ZUV4cEJhY2tvZmZUaW1lcihzdGVwKSB7XG4gICAgdmFyIGNvdW50ID0gMTtcbiAgICByZXR1cm4gZnVuY3Rpb24gKHJlc2V0KSB7XG4gICAgICAgIC8vIFJlc2V0IGNhbGxcbiAgICAgICAgaWYgKHJlc2V0KSB7XG4gICAgICAgICAgICBjb3VudCA9IDE7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ2FsY3VsYXRlIG5leHQgdGltZW91dFxuICAgICAgICB2YXIgdGltZW91dCA9IE1hdGgucG93KDIsIGNvdW50IC0gMSk7XG4gICAgICAgIGNvdW50ICs9IDE7XG4gICAgICAgIHJldHVybiB0aW1lb3V0ICogc3RlcDtcbiAgICB9O1xufVxuXG52YXIgZ2V0TmV4dFRpbWVvdXQgPSBjcmVhdGVFeHBCYWNrb2ZmVGltZXIoMTAwMCk7XG52YXIgZ2V0TmV4dEVycm9yVGltZW91dCA9IGNyZWF0ZUV4cEJhY2tvZmZUaW1lcigxMDAwKTtcbi8vIEV4dGVybmFsIGF1dGhlbnRpY2F0aW9uIHN0dWZmXG52YXIgZXh0ZXJuYWxBdXRoRW5hYmxlZCA9IGZhbHNlO1xuLy8gU2lwIGdhdGV3YXkgY2FuIGJlIGVuYWJsZWQgYnkgY29uZmlndXJpbmcgSmlnYXNpIGhvc3QgaW4gY29uZmlnLmpzIG9yXG4vLyBpdCB3aWxsIGJlIGVuYWJsZWQgYXV0b21hdGljYWxseSBpZiBmb2N1cyBkZXRlY3RzIHRoZSBjb21wb25lbnQgdGhyb3VnaFxuLy8gc2VydmljZSBkaXNjb3ZlcnkuXG52YXIgc2lwR2F0ZXdheUVuYWJsZWQgPSBjb25maWcuaG9zdHMuY2FsbF9jb250cm9sICE9PSB1bmRlZmluZWQ7XG5cbnZhciBldmVudEVtaXR0ZXIgPSBudWxsO1xuXG52YXIgTW9kZXJhdG9yID0ge1xuICAgIGlzTW9kZXJhdG9yOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uICYmIGNvbm5lY3Rpb24uZW11Yy5pc01vZGVyYXRvcigpO1xuICAgIH0sXG5cbiAgICBpc1BlZXJNb2RlcmF0b3I6IGZ1bmN0aW9uIChwZWVySmlkKSB7XG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uICYmXG4gICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuZ2V0TWVtYmVyUm9sZShwZWVySmlkKSA9PT0gJ21vZGVyYXRvcic7XG4gICAgfSxcblxuICAgIGlzRXh0ZXJuYWxBdXRoRW5hYmxlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gZXh0ZXJuYWxBdXRoRW5hYmxlZDtcbiAgICB9LFxuXG4gICAgaXNTaXBHYXRld2F5RW5hYmxlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gc2lwR2F0ZXdheUVuYWJsZWQ7XG4gICAgfSxcblxuICAgIHNldENvbm5lY3Rpb246IGZ1bmN0aW9uIChjb24pIHtcbiAgICAgICAgY29ubmVjdGlvbiA9IGNvbjtcbiAgICB9LFxuXG4gICAgaW5pdDogZnVuY3Rpb24gKHhtcHAsIGVtaXR0ZXIpIHtcbiAgICAgICAgdGhpcy54bXBwU2VydmljZSA9IHhtcHA7XG4gICAgICAgIGV2ZW50RW1pdHRlciA9IGVtaXR0ZXI7XG5cbiAgICAgICAgLy8gTWVzc2FnZSBsaXN0ZW5lciB0aGF0IHRhbGtzIHRvIFBPUFVQIHdpbmRvd1xuICAgICAgICBmdW5jdGlvbiBsaXN0ZW5lcihldmVudCkge1xuICAgICAgICAgICAgaWYgKGV2ZW50LmRhdGEgJiYgZXZlbnQuZGF0YS5zZXNzaW9uSWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXZlbnQub3JpZ2luICE9PSB3aW5kb3cubG9jYXRpb24ub3JpZ2luKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiSWdub3Jpbmcgc2Vzc2lvbklkIGZyb20gZGlmZmVyZW50IG9yaWdpbjogXCIgKyBldmVudC5vcmlnaW4pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKCdzZXNzaW9uSWQnLCBldmVudC5kYXRhLnNlc3Npb25JZCk7XG4gICAgICAgICAgICAgICAgLy8gQWZ0ZXIgcG9wdXAgaXMgY2xvc2VkIHdlIHdpbGwgYXV0aGVudGljYXRlXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gUmVnaXN0ZXJcbiAgICAgICAgaWYgKHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKSB7XG4gICAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcIm1lc3NhZ2VcIiwgbGlzdGVuZXIsIGZhbHNlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHdpbmRvdy5hdHRhY2hFdmVudChcIm9ubWVzc2FnZVwiLCBsaXN0ZW5lcik7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgb25NdWNMZWZ0OiBmdW5jdGlvbiAoamlkKSB7XG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIlNvbWVvbmUgbGVmdCBpcyBpdCBmb2N1cyA/IFwiICsgamlkKTtcbiAgICAgICAgdmFyIHJlc291cmNlID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgaWYgKHJlc291cmNlID09PSAnZm9jdXMnICYmICF0aGlzLnhtcHBTZXJ2aWNlLnNlc3Npb25UZXJtaW5hdGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICAgICAgXCJGb2N1cyBoYXMgbGVmdCB0aGUgcm9vbSAtIGxlYXZpbmcgY29uZmVyZW5jZVwiKTtcbiAgICAgICAgICAgIC8vaGFuZ1VwKCk7XG4gICAgICAgICAgICAvLyBXZSdkIHJhdGhlciByZWxvYWQgdG8gaGF2ZSBldmVyeXRoaW5nIHJlLWluaXRpYWxpemVkXG4gICAgICAgICAgICAvLyBGSVhNRTogc2hvdyBzb21lIG1lc3NhZ2UgYmVmb3JlIHJlbG9hZFxuICAgICAgICAgICAgbG9jYXRpb24ucmVsb2FkKCk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIFxuICAgIHNldEZvY3VzVXNlckppZDogZnVuY3Rpb24gKGZvY3VzSmlkKSB7XG4gICAgICAgIGlmICghZm9jdXNVc2VySmlkKSB7XG4gICAgICAgICAgICBmb2N1c1VzZXJKaWQgPSBmb2N1c0ppZDtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkZvY3VzIGppZCBzZXQgdG86IFwiICsgZm9jdXNVc2VySmlkKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBnZXRGb2N1c1VzZXJKaWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGZvY3VzVXNlckppZDtcbiAgICB9LFxuXG4gICAgZ2V0Rm9jdXNDb21wb25lbnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gR2V0IGZvY3VzIGNvbXBvbmVudCBhZGRyZXNzXG4gICAgICAgIHZhciBmb2N1c0NvbXBvbmVudCA9IGNvbmZpZy5ob3N0cy5mb2N1cztcbiAgICAgICAgLy8gSWYgbm90IHNwZWNpZmllZCB1c2UgZGVmYXVsdDogJ2ZvY3VzLmRvbWFpbidcbiAgICAgICAgaWYgKCFmb2N1c0NvbXBvbmVudCkge1xuICAgICAgICAgICAgZm9jdXNDb21wb25lbnQgPSAnZm9jdXMuJyArIGNvbmZpZy5ob3N0cy5kb21haW47XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZvY3VzQ29tcG9uZW50O1xuICAgIH0sXG5cbiAgICBjcmVhdGVDb25mZXJlbmNlSXE6IGZ1bmN0aW9uIChyb29tTmFtZSkge1xuICAgICAgICAvLyBHZW5lcmF0ZSBjcmVhdGUgY29uZmVyZW5jZSBJUVxuICAgICAgICB2YXIgZWxlbSA9ICRpcSh7dG86IE1vZGVyYXRvci5nZXRGb2N1c0NvbXBvbmVudCgpLCB0eXBlOiAnc2V0J30pO1xuXG4gICAgICAgIC8vIFNlc3Npb24gSWQgdXNlZCBmb3IgYXV0aGVudGljYXRpb25cbiAgICAgICAgdmFyIHNlc3Npb25JZCA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdzZXNzaW9uSWQnKTtcbiAgICAgICAgdmFyIG1hY2hpbmVVSUQgPSBTZXR0aW5ncy5nZXRTZXR0aW5ncygpLnVpZDtcblxuICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICBcIlNlc3Npb24gSUQ6IFwiICsgc2Vzc2lvbklkICsgXCIgbWFjaGluZSBVSUQ6IFwiICsgbWFjaGluZVVJRCk7XG5cbiAgICAgICAgZWxlbS5jKCdjb25mZXJlbmNlJywge1xuICAgICAgICAgICAgeG1sbnM6ICdodHRwOi8vaml0c2kub3JnL3Byb3RvY29sL2ZvY3VzJyxcbiAgICAgICAgICAgIHJvb206IHJvb21OYW1lLFxuICAgICAgICAgICAgJ21hY2hpbmUtdWlkJzogbWFjaGluZVVJRFxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoc2Vzc2lvbklkKSB7XG4gICAgICAgICAgICBlbGVtLmF0dHJzKHsgJ3Nlc3Npb24taWQnOiBzZXNzaW9uSWR9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjb25maWcuaG9zdHMuYnJpZGdlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGVsZW0uYyhcbiAgICAgICAgICAgICAgICAncHJvcGVydHknLFxuICAgICAgICAgICAgICAgIHsgbmFtZTogJ2JyaWRnZScsIHZhbHVlOiBjb25maWcuaG9zdHMuYnJpZGdlfSlcbiAgICAgICAgICAgICAgICAudXAoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBUZWxsIHRoZSBmb2N1cyB3ZSBoYXZlIEppZ2FzaSBjb25maWd1cmVkXG4gICAgICAgIGlmIChjb25maWcuaG9zdHMuY2FsbF9jb250cm9sICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGVsZW0uYyhcbiAgICAgICAgICAgICAgICAncHJvcGVydHknLFxuICAgICAgICAgICAgICAgIHsgbmFtZTogJ2NhbGxfY29udHJvbCcsIHZhbHVlOiBjb25maWcuaG9zdHMuY2FsbF9jb250cm9sfSlcbiAgICAgICAgICAgICAgICAudXAoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29uZmlnLmNoYW5uZWxMYXN0TiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBlbGVtLmMoXG4gICAgICAgICAgICAgICAgJ3Byb3BlcnR5JyxcbiAgICAgICAgICAgICAgICB7IG5hbWU6ICdjaGFubmVsTGFzdE4nLCB2YWx1ZTogY29uZmlnLmNoYW5uZWxMYXN0Tn0pXG4gICAgICAgICAgICAgICAgLnVwKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNvbmZpZy5hZGFwdGl2ZUxhc3ROICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGVsZW0uYyhcbiAgICAgICAgICAgICAgICAncHJvcGVydHknLFxuICAgICAgICAgICAgICAgIHsgbmFtZTogJ2FkYXB0aXZlTGFzdE4nLCB2YWx1ZTogY29uZmlnLmFkYXB0aXZlTGFzdE59KVxuICAgICAgICAgICAgICAgIC51cCgpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjb25maWcuYWRhcHRpdmVTaW11bGNhc3QgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZWxlbS5jKFxuICAgICAgICAgICAgICAgICdwcm9wZXJ0eScsXG4gICAgICAgICAgICAgICAgeyBuYW1lOiAnYWRhcHRpdmVTaW11bGNhc3QnLCB2YWx1ZTogY29uZmlnLmFkYXB0aXZlU2ltdWxjYXN0fSlcbiAgICAgICAgICAgICAgICAudXAoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29uZmlnLm9wZW5TY3RwICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGVsZW0uYyhcbiAgICAgICAgICAgICAgICAncHJvcGVydHknLFxuICAgICAgICAgICAgICAgIHsgbmFtZTogJ29wZW5TY3RwJywgdmFsdWU6IGNvbmZpZy5vcGVuU2N0cH0pXG4gICAgICAgICAgICAgICAgLnVwKCk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHJvb21OYW1lID0gQVBQLlVJLmdlbmVyYXRlUm9vbU5hbWUoKTtcbiAgICAgICAgaWYgKHR5cGVvZiByb29tTmFtZSAhPT0gJ3N0cmluZycpIHJvb21OYW1lID0gJyc7XG4gICAgICAgIGlmIChjb25maWcuZW5hYmxlRmlyZWZveFN1cHBvcnQgIT09IHVuZGVmaW5lZCAmJiByb29tTmFtZS5pbmRleE9mKCdyZW1ic29uQCcpID09PSAtMSkge1xuICAgICAgICAgICAgZWxlbS5jKFxuICAgICAgICAgICAgICAgICdwcm9wZXJ0eScsXG4gICAgICAgICAgICAgICAgeyBuYW1lOiAnZW5hYmxlRmlyZWZveEhhY2tzJyxcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IGNvbmZpZy5lbmFibGVGaXJlZm94U3VwcG9ydH0pXG4gICAgICAgICAgICAgICAgLnVwKCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICByZXR1cm4gZWxlbTtcbiAgICB9LFxuXG4gICAgcGFyc2VTZXNzaW9uSWQ6IGZ1bmN0aW9uIChyZXN1bHRJcSkge1xuICAgICAgICB2YXIgc2Vzc2lvbklkID0gJChyZXN1bHRJcSkuZmluZCgnY29uZmVyZW5jZScpLmF0dHIoJ3Nlc3Npb24taWQnKTtcbiAgICAgICAgaWYgKHNlc3Npb25JZCkge1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKCdSZWNlaXZlZCBzZXNzaW9uSWQ6ICcgKyBzZXNzaW9uSWQpO1xuICAgICAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3Nlc3Npb25JZCcsIHNlc3Npb25JZCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgcGFyc2VDb25maWdPcHRpb25zOiBmdW5jdGlvbiAocmVzdWx0SXEpIHtcblxuICAgICAgICBNb2RlcmF0b3Iuc2V0Rm9jdXNVc2VySmlkKFxuICAgICAgICAgICAgJChyZXN1bHRJcSkuZmluZCgnY29uZmVyZW5jZScpLmF0dHIoJ2ZvY3VzamlkJykpO1xuXG4gICAgICAgIHZhciBhdXRoZW50aWNhdGlvbkVuYWJsZWRcbiAgICAgICAgICAgID0gJChyZXN1bHRJcSkuZmluZChcbiAgICAgICAgICAgICAgICAnPmNvbmZlcmVuY2U+cHJvcGVydHknICtcbiAgICAgICAgICAgICAgICAnW25hbWU9XFwnYXV0aGVudGljYXRpb25cXCddW3ZhbHVlPVxcJ3RydWVcXCddJykubGVuZ3RoID4gMDtcblxuICAgICAgICBjb25zb2xlLmluZm8oXCJBdXRoZW50aWNhdGlvbiBlbmFibGVkOiBcIiArIGF1dGhlbnRpY2F0aW9uRW5hYmxlZCk7XG5cbiAgICAgICAgZXh0ZXJuYWxBdXRoRW5hYmxlZFxuICAgICAgICAgICAgPSAkKHJlc3VsdElxKS5maW5kKFxuICAgICAgICAgICAgICAgICc+Y29uZmVyZW5jZT5wcm9wZXJ0eScgK1xuICAgICAgICAgICAgICAgICdbbmFtZT1cXCdleHRlcm5hbEF1dGhcXCddW3ZhbHVlPVxcJ3RydWVcXCddJykubGVuZ3RoID4gMDtcblxuICAgICAgICBjb25zb2xlLmluZm8oJ0V4dGVybmFsIGF1dGhlbnRpY2F0aW9uIGVuYWJsZWQ6ICcgKyBleHRlcm5hbEF1dGhFbmFibGVkKTtcblxuICAgICAgICBpZiAoIWV4dGVybmFsQXV0aEVuYWJsZWQpIHtcbiAgICAgICAgICAgIC8vIFdlIGV4cGVjdCB0byByZWNlaXZlIHNlc3Npb25JZCBpbiAnaW50ZXJuYWwnIGF1dGhlbnRpY2F0aW9uIG1vZGVcbiAgICAgICAgICAgIE1vZGVyYXRvci5wYXJzZVNlc3Npb25JZChyZXN1bHRJcSk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXV0aElkZW50aXR5ID0gJChyZXN1bHRJcSkuZmluZCgnPmNvbmZlcmVuY2UnKS5hdHRyKCdpZGVudGl0eScpO1xuXG4gICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KEF1dGhlbnRpY2F0aW9uRXZlbnRzLklERU5USVRZX1VQREFURUQsXG4gICAgICAgICAgICBhdXRoZW50aWNhdGlvbkVuYWJsZWQsIGF1dGhJZGVudGl0eSk7XG4gICAgXG4gICAgICAgIC8vIENoZWNrIGlmIGZvY3VzIGhhcyBhdXRvLWRldGVjdGVkIEppZ2FzaSBjb21wb25lbnQodGhpcyB3aWxsIGJlIGFsc29cbiAgICAgICAgLy8gaW5jbHVkZWQgaWYgd2UgaGF2ZSBwYXNzZWQgb3VyIGhvc3QgZnJvbSB0aGUgY29uZmlnKVxuICAgICAgICBpZiAoJChyZXN1bHRJcSkuZmluZChcbiAgICAgICAgICAgICc+Y29uZmVyZW5jZT5wcm9wZXJ0eScgK1xuICAgICAgICAgICAgJ1tuYW1lPVxcJ3NpcEdhdGV3YXlFbmFibGVkXFwnXVt2YWx1ZT1cXCd0cnVlXFwnXScpLmxlbmd0aCkge1xuICAgICAgICAgICAgc2lwR2F0ZXdheUVuYWJsZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIlNpcCBnYXRld2F5IGVuYWJsZWQ6IFwiICsgc2lwR2F0ZXdheUVuYWJsZWQpO1xuICAgIH0sXG5cbiAgICAvLyBGSVhNRTogd2UgbmVlZCB0byBzaG93IHRoZSBmYWN0IHRoYXQgd2UncmUgd2FpdGluZyBmb3IgdGhlIGZvY3VzXG4gICAgLy8gdG8gdGhlIHVzZXIob3IgdGhhdCBmb2N1cyBpcyBub3QgYXZhaWxhYmxlKVxuICAgIGFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzOiBmdW5jdGlvbiAocm9vbU5hbWUsIGNhbGxiYWNrKSB7XG4gICAgICAgIC8vIFRyeSB0byB1c2UgZm9jdXMgdXNlciBKSUQgZnJvbSB0aGUgY29uZmlnXG4gICAgICAgIE1vZGVyYXRvci5zZXRGb2N1c1VzZXJKaWQoY29uZmlnLmZvY3VzVXNlckppZCk7XG4gICAgICAgIC8vIFNlbmQgY3JlYXRlIGNvbmZlcmVuY2UgSVFcbiAgICAgICAgdmFyIGlxID0gTW9kZXJhdG9yLmNyZWF0ZUNvbmZlcmVuY2VJcShyb29tTmFtZSk7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgY29ubmVjdGlvbi5zZW5kSVEoXG4gICAgICAgICAgICBpcSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChyZXN1bHQpIHtcblxuICAgICAgICAgICAgICAgIC8vIFNldHVwIGNvbmZpZyBvcHRpb25zXG4gICAgICAgICAgICAgICAgTW9kZXJhdG9yLnBhcnNlQ29uZmlnT3B0aW9ucyhyZXN1bHQpO1xuXG4gICAgICAgICAgICAgICAgaWYgKCd0cnVlJyA9PT0gJChyZXN1bHQpLmZpbmQoJ2NvbmZlcmVuY2UnKS5hdHRyKCdyZWFkeScpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFJlc2V0IGJvdGggdGltZXJzXG4gICAgICAgICAgICAgICAgICAgIGdldE5leHRUaW1lb3V0KHRydWUpO1xuICAgICAgICAgICAgICAgICAgICBnZXROZXh0RXJyb3JUaW1lb3V0KHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAvLyBFeGVjIGNhbGxiYWNrXG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHdhaXRNcyA9IGdldE5leHRUaW1lb3V0KCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIldhaXRpbmcgZm9yIHRoZSBmb2N1cy4uLiBcIiArIHdhaXRNcyk7XG4gICAgICAgICAgICAgICAgICAgIC8vIFJlc2V0IGVycm9yIHRpbWVvdXRcbiAgICAgICAgICAgICAgICAgICAgZ2V0TmV4dEVycm9yVGltZW91dCh0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgd2luZG93LnNldFRpbWVvdXQoXG4gICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kZXJhdG9yLmFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb29tTmFtZSwgY2FsbGJhY2spO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSwgd2FpdE1zKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgLy8gSW52YWxpZCBzZXNzaW9uID8gcmVtb3ZlIGFuZCB0cnkgYWdhaW5cbiAgICAgICAgICAgICAgICAvLyB3aXRob3V0IHNlc3Npb24gSUQgdG8gZ2V0IGEgbmV3IG9uZVxuICAgICAgICAgICAgICAgIHZhciBpbnZhbGlkU2Vzc2lvblxuICAgICAgICAgICAgICAgICAgICA9ICQoZXJyb3IpLmZpbmQoJz5lcnJvcj5zZXNzaW9uLWludmFsaWQnKS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgaWYgKGludmFsaWRTZXNzaW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIlNlc3Npb24gZXhwaXJlZCEgLSByZW1vdmluZ1wiKTtcbiAgICAgICAgICAgICAgICAgICAgbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0oXCJzZXNzaW9uSWRcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICgkKGVycm9yKS5maW5kKCc+ZXJyb3I+Z3JhY2VmdWwtc2h1dGRvd24nKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoWE1QUEV2ZW50cy5HUkFDRUZVTF9TSFVURE9XTik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgZm9yIGVycm9yIHJldHVybmVkIGJ5IHRoZSByZXNlcnZhdGlvbiBzeXN0ZW1cbiAgICAgICAgICAgICAgICB2YXIgcmVzZXJ2YXRpb25FcnIgPSAkKGVycm9yKS5maW5kKCc+ZXJyb3I+cmVzZXJ2YXRpb24tZXJyb3InKTtcbiAgICAgICAgICAgICAgICBpZiAocmVzZXJ2YXRpb25FcnIubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRyaWdnZXIgZXJyb3IgZXZlbnRcbiAgICAgICAgICAgICAgICAgICAgdmFyIGVycm9yQ29kZSA9IHJlc2VydmF0aW9uRXJyLmF0dHIoJ2Vycm9yLWNvZGUnKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGVycm9yTXNnO1xuICAgICAgICAgICAgICAgICAgICBpZiAoJChlcnJvcikuZmluZCgnPmVycm9yPnRleHQnKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JNc2cgPSAkKGVycm9yKS5maW5kKCc+ZXJyb3I+dGV4dCcpLnRleHQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChcbiAgICAgICAgICAgICAgICAgICAgICAgIFhNUFBFdmVudHMuUkVTRVJWQVRJT05fRVJST1IsIGVycm9yQ29kZSwgZXJyb3JNc2cpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIE5vdCBhdXRob3JpemVkIHRvIGNyZWF0ZSBuZXcgcm9vbVxuICAgICAgICAgICAgICAgIGlmICgkKGVycm9yKS5maW5kKCc+ZXJyb3I+bm90LWF1dGhvcml6ZWQnKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiVW5hdXRob3JpemVkIHRvIHN0YXJ0IHRoZSBjb25mZXJlbmNlXCIsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRvRG9tYWluXG4gICAgICAgICAgICAgICAgICAgICAgICA9IFN0cm9waGUuZ2V0RG9tYWluRnJvbUppZChlcnJvci5nZXRBdHRyaWJ1dGUoJ3RvJykpO1xuICAgICAgICAgICAgICAgICAgICBpZiAodG9Eb21haW4gIT09IGNvbmZpZy5ob3N0cy5hbm9ueW1vdXNkb21haW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBcImlzIGV4dGVybmFsXCIgc2hvdWxkIGNvbWUgZWl0aGVyIGZyb21cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSBmb2N1cyBvciBjb25maWcuanNcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4dGVybmFsQXV0aEVuYWJsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFxuICAgICAgICAgICAgICAgICAgICAgICAgWE1QUEV2ZW50cy5BVVRIRU5USUNBVElPTl9SRVFVSVJFRCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBNb2RlcmF0b3IuYWxsb2NhdGVDb25mZXJlbmNlRm9jdXMoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvb21OYW1lLCBjYWxsYmFjayk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgd2FpdE1zID0gZ2V0TmV4dEVycm9yVGltZW91dCgpO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJGb2N1cyBlcnJvciwgcmV0cnkgYWZ0ZXIgXCIgKyB3YWl0TXMsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAvLyBTaG93IG1lc3NhZ2VcbiAgICAgICAgICAgICAgICB2YXIgZm9jdXNDb21wb25lbnQgPSBNb2RlcmF0b3IuZ2V0Rm9jdXNDb21wb25lbnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgcmV0cnlTZWMgPSB3YWl0TXMgLyAxMDAwO1xuICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBtZXNzYWdlIGlzIGR1cGxpY2F0ZWQgP1xuICAgICAgICAgICAgICAgIC8vIERvIG5vdCBzaG93IGluIGNhc2Ugb2Ygc2Vzc2lvbiBpbnZhbGlkXG4gICAgICAgICAgICAgICAgLy8gd2hpY2ggbWVhbnMganVzdCBhIHJldHJ5XG4gICAgICAgICAgICAgICAgaWYgKCFpbnZhbGlkU2Vzc2lvbikge1xuICAgICAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIubm90aWZ5KFxuICAgICAgICAgICAgICAgICAgICAgICAgbnVsbCwgXCJub3RpZnkuZm9jdXNcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICdkaXNjb25uZWN0ZWQnLCBcIm5vdGlmeS5mb2N1c0ZhaWxcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIHtjb21wb25lbnQ6IGZvY3VzQ29tcG9uZW50LCBtczogcmV0cnlTZWN9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gUmVzZXQgcmVzcG9uc2UgdGltZW91dFxuICAgICAgICAgICAgICAgIGdldE5leHRUaW1lb3V0KHRydWUpO1xuICAgICAgICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBNb2RlcmF0b3IuYWxsb2NhdGVDb25mZXJlbmNlRm9jdXMocm9vbU5hbWUsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgICAgICAgICAgfSwgd2FpdE1zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9LFxuXG4gICAgZ2V0TG9naW5Vcmw6IGZ1bmN0aW9uIChyb29tTmFtZSwgdXJsQ2FsbGJhY2spIHtcbiAgICAgICAgdmFyIGlxID0gJGlxKHt0bzogTW9kZXJhdG9yLmdldEZvY3VzQ29tcG9uZW50KCksIHR5cGU6ICdnZXQnfSk7XG4gICAgICAgIGlxLmMoJ2xvZ2luLXVybCcsIHtcbiAgICAgICAgICAgIHhtbG5zOiAnaHR0cDovL2ppdHNpLm9yZy9wcm90b2NvbC9mb2N1cycsXG4gICAgICAgICAgICByb29tOiByb29tTmFtZSxcbiAgICAgICAgICAgICdtYWNoaW5lLXVpZCc6IFNldHRpbmdzLmdldFNldHRpbmdzKCkudWlkXG4gICAgICAgIH0pO1xuICAgICAgICBjb25uZWN0aW9uLnNlbmRJUShcbiAgICAgICAgICAgIGlxLFxuICAgICAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSAkKHJlc3VsdCkuZmluZCgnbG9naW4tdXJsJykuYXR0cigndXJsJyk7XG4gICAgICAgICAgICAgICAgdXJsID0gdXJsID0gZGVjb2RlVVJJQ29tcG9uZW50KHVybCk7XG4gICAgICAgICAgICAgICAgaWYgKHVybCkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXCJHb3QgYXV0aCB1cmw6IFwiICsgdXJsKTtcbiAgICAgICAgICAgICAgICAgICAgdXJsQ2FsbGJhY2sodXJsKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJGYWlsZWQgdG8gZ2V0IGF1dGggdXJsIGZyb20gdGhlIGZvY3VzXCIsIHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJHZXQgYXV0aCB1cmwgZXJyb3JcIiwgZXJyb3IpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH0sXG4gICAgZ2V0UG9wdXBMb2dpblVybDogZnVuY3Rpb24gKHJvb21OYW1lLCB1cmxDYWxsYmFjaykge1xuICAgICAgICB2YXIgaXEgPSAkaXEoe3RvOiBNb2RlcmF0b3IuZ2V0Rm9jdXNDb21wb25lbnQoKSwgdHlwZTogJ2dldCd9KTtcbiAgICAgICAgaXEuYygnbG9naW4tdXJsJywge1xuICAgICAgICAgICAgeG1sbnM6ICdodHRwOi8vaml0c2kub3JnL3Byb3RvY29sL2ZvY3VzJyxcbiAgICAgICAgICAgIHJvb206IHJvb21OYW1lLFxuICAgICAgICAgICAgJ21hY2hpbmUtdWlkJzogU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKS51aWQsXG4gICAgICAgICAgICBwb3B1cDogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgY29ubmVjdGlvbi5zZW5kSVEoXG4gICAgICAgICAgICBpcSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gJChyZXN1bHQpLmZpbmQoJ2xvZ2luLXVybCcpLmF0dHIoJ3VybCcpO1xuICAgICAgICAgICAgICAgIHVybCA9IHVybCA9IGRlY29kZVVSSUNvbXBvbmVudCh1cmwpO1xuICAgICAgICAgICAgICAgIGlmICh1cmwpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiR290IFBPUFVQIGF1dGggdXJsOiBcIiArIHVybCk7XG4gICAgICAgICAgICAgICAgICAgIHVybENhbGxiYWNrKHVybCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiRmFpbGVkIHRvIGdldCBQT1BVUCBhdXRoIHVybCBmcm9tIHRoZSBmb2N1c1wiLCByZXN1bHQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdHZXQgUE9QVVAgYXV0aCB1cmwgZXJyb3InLCBlcnJvcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfSxcbiAgICBsb2dvdXQ6IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgICAgICB2YXIgaXEgPSAkaXEoe3RvOiBNb2RlcmF0b3IuZ2V0Rm9jdXNDb21wb25lbnQoKSwgdHlwZTogJ3NldCd9KTtcbiAgICAgICAgdmFyIHNlc3Npb25JZCA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdzZXNzaW9uSWQnKTtcbiAgICAgICAgaWYgKCFzZXNzaW9uSWQpIHtcbiAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaXEuYygnbG9nb3V0Jywge1xuICAgICAgICAgICAgeG1sbnM6ICdodHRwOi8vaml0c2kub3JnL3Byb3RvY29sL2ZvY3VzJyxcbiAgICAgICAgICAgICdzZXNzaW9uLWlkJzogc2Vzc2lvbklkXG4gICAgICAgIH0pO1xuICAgICAgICBjb25uZWN0aW9uLnNlbmRJUShcbiAgICAgICAgICAgIGlxLFxuICAgICAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgIHZhciBsb2dvdXRVcmwgPSAkKHJlc3VsdCkuZmluZCgnbG9nb3V0JykuYXR0cignbG9nb3V0LXVybCcpO1xuICAgICAgICAgICAgICAgIGlmIChsb2dvdXRVcmwpIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nb3V0VXJsID0gZGVjb2RlVVJJQ29tcG9uZW50KGxvZ291dFVybCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkxvZyBvdXQgT0ssIHVybDogXCIgKyBsb2dvdXRVcmwsIHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0oJ3Nlc3Npb25JZCcpO1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGxvZ291dFVybCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkxvZ291dCBlcnJvclwiLCBlcnJvcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBNb2RlcmF0b3I7XG5cblxuXG4iLCIvKiBnbG9iYWwgJCwgJGlxLCBjb25maWcsIGNvbm5lY3Rpb24sIGZvY3VzTXVjSmlkLCBtZXNzYWdlSGFuZGxlciwgTW9kZXJhdG9yLFxuICAgVG9vbGJhciwgVXRpbCAqL1xudmFyIE1vZGVyYXRvciA9IHJlcXVpcmUoXCIuL21vZGVyYXRvclwiKTtcblxuXG52YXIgcmVjb3JkaW5nVG9rZW4gPSBudWxsO1xudmFyIHJlY29yZGluZ0VuYWJsZWQ7XG5cbi8qKlxuICogV2hldGhlciB0byB1c2UgYSBqaXJlY29uIGNvbXBvbmVudCBmb3IgcmVjb3JkaW5nLCBvciB1c2UgdGhlIHZpZGVvYnJpZGdlXG4gKiB0aHJvdWdoIENPTElCUkkuXG4gKi9cbnZhciB1c2VKaXJlY29uID0gKHR5cGVvZiBjb25maWcuaG9zdHMuamlyZWNvbiAhPSBcInVuZGVmaW5lZFwiKTtcblxuLyoqXG4gKiBUaGUgSUQgb2YgdGhlIGppcmVjb24gcmVjb3JkaW5nIHNlc3Npb24uIEppcmVjb24gZ2VuZXJhdGVzIGl0IHdoZW4gd2VcbiAqIGluaXRpYWxseSBzdGFydCByZWNvcmRpbmcsIGFuZCBpdCBuZWVkcyB0byBiZSB1c2VkIGluIHN1YnNlcXVlbnQgcmVxdWVzdHNcbiAqIHRvIGppcmVjb24uXG4gKi9cbnZhciBqaXJlY29uUmlkID0gbnVsbDtcblxuZnVuY3Rpb24gc2V0UmVjb3JkaW5nVG9rZW4odG9rZW4pIHtcbiAgICByZWNvcmRpbmdUb2tlbiA9IHRva2VuO1xufVxuXG5mdW5jdGlvbiBzZXRSZWNvcmRpbmcoc3RhdGUsIHRva2VuLCBjYWxsYmFjaywgY29ubmVjdGlvbikge1xuICAgIGlmICh1c2VKaXJlY29uKXtcbiAgICAgICAgc2V0UmVjb3JkaW5nSmlyZWNvbihzdGF0ZSwgdG9rZW4sIGNhbGxiYWNrLCBjb25uZWN0aW9uKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBzZXRSZWNvcmRpbmdDb2xpYnJpKHN0YXRlLCB0b2tlbiwgY2FsbGJhY2ssIGNvbm5lY3Rpb24pO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gc2V0UmVjb3JkaW5nSmlyZWNvbihzdGF0ZSwgdG9rZW4sIGNhbGxiYWNrLCBjb25uZWN0aW9uKSB7XG4gICAgaWYgKHN0YXRlID09IHJlY29yZGluZ0VuYWJsZWQpe1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGlxID0gJGlxKHt0bzogY29uZmlnLmhvc3RzLmppcmVjb24sIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgLmMoJ3JlY29yZGluZycsIHt4bWxuczogJ2h0dHA6Ly9qaXRzaS5vcmcvcHJvdG9jb2wvamlyZWNvbicsXG4gICAgICAgICAgICBhY3Rpb246IHN0YXRlID8gJ3N0YXJ0JyA6ICdzdG9wJyxcbiAgICAgICAgICAgIG11Y2ppZDogY29ubmVjdGlvbi5lbXVjLnJvb21qaWR9KTtcbiAgICBpZiAoIXN0YXRlKXtcbiAgICAgICAgaXEuYXR0cnMoe3JpZDogamlyZWNvblJpZH0pO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKCdTdGFydCByZWNvcmRpbmcnKTtcblxuICAgIGNvbm5lY3Rpb24uc2VuZElRKFxuICAgICAgICBpcSxcbiAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgLy8gVE9ETyB3YWl0IGZvciBhbiBJUSB3aXRoIHRoZSByZWFsIHN0YXR1cywgc2luY2UgdGhpcyBpc1xuICAgICAgICAgICAgLy8gcHJvdmlzaW9uYWw/XG4gICAgICAgICAgICBqaXJlY29uUmlkID0gJChyZXN1bHQpLmZpbmQoJ3JlY29yZGluZycpLmF0dHIoJ3JpZCcpO1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ1JlY29yZGluZyAnICsgKHN0YXRlID8gJ3N0YXJ0ZWQnIDogJ3N0b3BwZWQnKSArXG4gICAgICAgICAgICAgICAgJyhqaXJlY29uKScgKyByZXN1bHQpO1xuICAgICAgICAgICAgcmVjb3JkaW5nRW5hYmxlZCA9IHN0YXRlO1xuICAgICAgICAgICAgaWYgKCFzdGF0ZSl7XG4gICAgICAgICAgICAgICAgamlyZWNvblJpZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNhbGxiYWNrKHN0YXRlKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnRmFpbGVkIHRvIHN0YXJ0IHJlY29yZGluZywgZXJyb3I6ICcsIGVycm9yKTtcbiAgICAgICAgICAgIGNhbGxiYWNrKHJlY29yZGluZ0VuYWJsZWQpO1xuICAgICAgICB9KTtcbn1cblxuLy8gU2VuZHMgYSBDT0xJQlJJIG1lc3NhZ2Ugd2hpY2ggZW5hYmxlcyBvciBkaXNhYmxlcyAoYWNjb3JkaW5nIHRvICdzdGF0ZScpXG4vLyB0aGUgcmVjb3JkaW5nIG9uIHRoZSBicmlkZ2UuIFdhaXRzIGZvciB0aGUgcmVzdWx0IElRIGFuZCBjYWxscyAnY2FsbGJhY2snXG4vLyB3aXRoIHRoZSBuZXcgcmVjb3JkaW5nIHN0YXRlLCBhY2NvcmRpbmcgdG8gdGhlIElRLlxuZnVuY3Rpb24gc2V0UmVjb3JkaW5nQ29saWJyaShzdGF0ZSwgdG9rZW4sIGNhbGxiYWNrLCBjb25uZWN0aW9uKSB7XG4gICAgdmFyIGVsZW0gPSAkaXEoe3RvOiBjb25uZWN0aW9uLmVtdWMuZm9jdXNNdWNKaWQsIHR5cGU6ICdzZXQnfSk7XG4gICAgZWxlbS5jKCdjb25mZXJlbmNlJywge1xuICAgICAgICB4bWxuczogJ2h0dHA6Ly9qaXRzaS5vcmcvcHJvdG9jb2wvY29saWJyaSdcbiAgICB9KTtcbiAgICBlbGVtLmMoJ3JlY29yZGluZycsIHtzdGF0ZTogc3RhdGUsIHRva2VuOiB0b2tlbn0pO1xuXG4gICAgY29ubmVjdGlvbi5zZW5kSVEoZWxlbSxcbiAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ1NldCByZWNvcmRpbmcgXCInLCBzdGF0ZSwgJ1wiLiBSZXN1bHQ6JywgcmVzdWx0KTtcbiAgICAgICAgICAgIHZhciByZWNvcmRpbmdFbGVtID0gJChyZXN1bHQpLmZpbmQoJz5jb25mZXJlbmNlPnJlY29yZGluZycpO1xuICAgICAgICAgICAgdmFyIG5ld1N0YXRlID0gKCd0cnVlJyA9PT0gcmVjb3JkaW5nRWxlbS5hdHRyKCdzdGF0ZScpKTtcblxuICAgICAgICAgICAgcmVjb3JkaW5nRW5hYmxlZCA9IG5ld1N0YXRlO1xuICAgICAgICAgICAgY2FsbGJhY2sobmV3U3RhdGUpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgICAgICBjYWxsYmFjayhyZWNvcmRpbmdFbmFibGVkKTtcbiAgICAgICAgfVxuICAgICk7XG59XG5cbnZhciBSZWNvcmRpbmcgPSB7XG4gICAgdG9nZ2xlUmVjb3JkaW5nOiBmdW5jdGlvbiAodG9rZW5FbXB0eUNhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0aW5nQ2FsbGJhY2ssIHN0YXJ0ZWRDYWxsYmFjaywgY29ubmVjdGlvbikge1xuICAgICAgICBpZiAoIU1vZGVyYXRvci5pc01vZGVyYXRvcigpKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAgICAgJ25vbi1mb2N1cywgb3IgY29uZmVyZW5jZSBub3QgeWV0IG9yZ2FuaXplZDonICtcbiAgICAgICAgICAgICAgICAgICAgJyBub3QgZW5hYmxpbmcgcmVjb3JkaW5nJyk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIC8vIEppcmVjb24gZG9lcyBub3QgKGN1cnJlbnRseSkgc3VwcG9ydCBhIHRva2VuLlxuICAgICAgICBpZiAoIXJlY29yZGluZ1Rva2VuICYmICF1c2VKaXJlY29uKSB7XG4gICAgICAgICAgICB0b2tlbkVtcHR5Q2FsbGJhY2soZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgc2V0UmVjb3JkaW5nVG9rZW4odmFsdWUpO1xuICAgICAgICAgICAgICAgIHNlbGYudG9nZ2xlUmVjb3JkaW5nKHRva2VuRW1wdHlDYWxsYmFjayxcbiAgICAgICAgICAgICAgICAgICAgc3RhcnRpbmdDYWxsYmFjaywgc3RhcnRlZENhbGxiYWNrLCBjb25uZWN0aW9uKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgb2xkU3RhdGUgPSByZWNvcmRpbmdFbmFibGVkO1xuICAgICAgICBzdGFydGluZ0NhbGxiYWNrKCFvbGRTdGF0ZSk7XG4gICAgICAgIHNldFJlY29yZGluZyghb2xkU3RhdGUsXG4gICAgICAgICAgICByZWNvcmRpbmdUb2tlbixcbiAgICAgICAgICAgIGZ1bmN0aW9uIChzdGF0ZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiTmV3IHJlY29yZGluZyBzdGF0ZTogXCIsIHN0YXRlKTtcbiAgICAgICAgICAgICAgICBpZiAoc3RhdGUgPT09IG9sZFN0YXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBuZXcgZm9jdXM6XG4gICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgd2lsbCBub3Qgd29yayB3aGVuIG1vZGVyYXRvciBjaGFuZ2VzXG4gICAgICAgICAgICAgICAgICAgIC8vIGR1cmluZyBhY3RpdmUgc2Vzc2lvbi4gVGhlbiBpdCB3aWxsIGFzc3VtZSB0aGF0XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlY29yZGluZyBzdGF0dXMgaGFzIGNoYW5nZWQgdG8gdHJ1ZSwgYnV0IGl0IG1pZ2h0IGhhdmVcbiAgICAgICAgICAgICAgICAgICAgLy8gYmVlbiBhbHJlYWR5IHRydWUoYW5kIHdlIG9ubHkgcmVjZWl2ZWQgYWN0dWFsIHN0YXR1cyBmcm9tXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSBmb2N1cykuXG4gICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgIC8vIFNPIHdlIHN0YXJ0IHdpdGggc3RhdHVzIG51bGwsIHNvIHRoYXQgaXQgaXMgaW5pdGlhbGl6ZWRcbiAgICAgICAgICAgICAgICAgICAgLy8gaGVyZSBhbmQgd2lsbCBmYWlsIG9ubHkgYWZ0ZXIgc2Vjb25kIGNsaWNrLCBzbyBpZiBpbnZhbGlkXG4gICAgICAgICAgICAgICAgICAgIC8vIHRva2VuIHdhcyB1c2VkIHdlIGhhdmUgdG8gcHJlc3MgdGhlIGJ1dHRvbiB0d2ljZSBiZWZvcmVcbiAgICAgICAgICAgICAgICAgICAgLy8gY3VycmVudCBzdGF0dXMgd2lsbCBiZSBmZXRjaGVkIGFuZCB0b2tlbiB3aWxsIGJlIHJlc2V0LlxuICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAvLyBSZWxpYWJsZSB3YXkgd291bGQgYmUgdG8gcmV0dXJuIGF1dGhlbnRpY2F0aW9uIGVycm9yLlxuICAgICAgICAgICAgICAgICAgICAvLyBPciBzdGF0dXMgdXBkYXRlIHdoZW4gbW9kZXJhdG9yIGNvbm5lY3RzLlxuICAgICAgICAgICAgICAgICAgICAvLyBPciB3ZSBoYXZlIHRvIHN0b3AgcmVjb3JkaW5nIHNlc3Npb24gd2hlbiBjdXJyZW50XG4gICAgICAgICAgICAgICAgICAgIC8vIG1vZGVyYXRvciBsZWF2ZXMgdGhlIHJvb20uXG5cbiAgICAgICAgICAgICAgICAgICAgLy8gRmFpbGVkIHRvIGNoYW5nZSwgcmVzZXQgdGhlIHRva2VuIGJlY2F1c2UgaXQgbWlnaHRcbiAgICAgICAgICAgICAgICAgICAgLy8gaGF2ZSBiZWVuIHdyb25nXG4gICAgICAgICAgICAgICAgICAgIHNldFJlY29yZGluZ1Rva2VuKG51bGwpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzdGFydGVkQ2FsbGJhY2soc3RhdGUpO1xuXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY29ubmVjdGlvblxuICAgICAgICApO1xuICAgIH1cblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFJlY29yZGluZzsiLCIvKiBqc2hpbnQgLVcxMTcgKi9cbi8qIGEgc2ltcGxlIE1VQyBjb25uZWN0aW9uIHBsdWdpblxuICogY2FuIG9ubHkgaGFuZGxlIGEgc2luZ2xlIE1VQyByb29tXG4gKi9cbnZhciBYTVBQRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UveG1wcC9YTVBQRXZlbnRzXCIpO1xudmFyIE1vZGVyYXRvciA9IHJlcXVpcmUoXCIuL21vZGVyYXRvclwiKTtcbnZhciBKaW5nbGVTZXNzaW9uID0gcmVxdWlyZShcIi4vSmluZ2xlU2Vzc2lvblwiKTtcblxudmFyIGJyaWRnZUlzRG93biA9IGZhbHNlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKFhNUFAsIGV2ZW50RW1pdHRlcikge1xuICAgIFN0cm9waGUuYWRkQ29ubmVjdGlvblBsdWdpbignZW11YycsIHtcbiAgICAgICAgY29ubmVjdGlvbjogbnVsbCxcbiAgICAgICAgcm9vbWppZDogbnVsbCxcbiAgICAgICAgbXlyb29tamlkOiBudWxsLFxuICAgICAgICBtZW1iZXJzOiB7fSxcbiAgICAgICAgbGlzdF9tZW1iZXJzOiBbXSwgLy8gc28gd2UgY2FuIGVsZWN0IGEgbmV3IGZvY3VzXG4gICAgICAgIHByZXNNYXA6IHt9LFxuICAgICAgICBwcmV6aU1hcDoge30sXG4gICAgICAgIGpvaW5lZDogZmFsc2UsXG4gICAgICAgIGlzT3duZXI6IGZhbHNlLFxuICAgICAgICByb2xlOiBudWxsLFxuICAgICAgICBmb2N1c011Y0ppZDogbnVsbCxcbiAgICAgICAgc3NyYzJqaWQ6IHt9LFxuICAgICAgICBpbml0OiBmdW5jdGlvbiAoY29ubikge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gY29ubjtcbiAgICAgICAgfSxcbiAgICAgICAgaW5pdFByZXNlbmNlTWFwOiBmdW5jdGlvbiAobXlyb29tamlkKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3RvJ10gPSBteXJvb21qaWQ7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3hucyddID0gJ2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211Yyc7XG4gICAgICAgIH0sXG4gICAgICAgIGRvSm9pbjogZnVuY3Rpb24gKGppZCwgcGFzc3dvcmQpIHtcbiAgICAgICAgICAgIHRoaXMubXlyb29tamlkID0gamlkO1xuXG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXCJKb2luZWQgTVVDIGFzIFwiICsgdGhpcy5teXJvb21qaWQpO1xuXG4gICAgICAgICAgICB0aGlzLmluaXRQcmVzZW5jZU1hcCh0aGlzLm15cm9vbWppZCk7XG5cbiAgICAgICAgICAgIGlmICghdGhpcy5yb29tamlkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5yb29tamlkID0gU3Ryb3BoZS5nZXRCYXJlSmlkRnJvbUppZChqaWQpO1xuICAgICAgICAgICAgICAgIC8vIGFkZCBoYW5kbGVycyAoanVzdCBvbmNlKVxuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5hZGRIYW5kbGVyKHRoaXMub25QcmVzZW5jZS5iaW5kKHRoaXMpLCBudWxsLCAncHJlc2VuY2UnLCBudWxsLCBudWxsLCB0aGlzLnJvb21qaWQsIHttYXRjaEJhcmU6IHRydWV9KTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uYWRkSGFuZGxlcih0aGlzLm9uUHJlc2VuY2VVbmF2YWlsYWJsZS5iaW5kKHRoaXMpLCBudWxsLCAncHJlc2VuY2UnLCAndW5hdmFpbGFibGUnLCBudWxsLCB0aGlzLnJvb21qaWQsIHttYXRjaEJhcmU6IHRydWV9KTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uYWRkSGFuZGxlcih0aGlzLm9uUHJlc2VuY2VFcnJvci5iaW5kKHRoaXMpLCBudWxsLCAncHJlc2VuY2UnLCAnZXJyb3InLCBudWxsLCB0aGlzLnJvb21qaWQsIHttYXRjaEJhcmU6IHRydWV9KTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uYWRkSGFuZGxlcih0aGlzLm9uTWVzc2FnZS5iaW5kKHRoaXMpLCBudWxsLCAnbWVzc2FnZScsIG51bGwsIG51bGwsIHRoaXMucm9vbWppZCwge21hdGNoQmFyZTogdHJ1ZX0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHBhc3N3b3JkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3Bhc3N3b3JkJ10gPSBwYXNzd29yZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuc2VuZFByZXNlbmNlKCk7XG4gICAgICAgIH0sXG4gICAgICAgIGRvTGVhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiZG8gbGVhdmVcIiwgdGhpcy5teXJvb21qaWQpO1xuICAgICAgICAgICAgdmFyIHByZXMgPSAkcHJlcyh7dG86IHRoaXMubXlyb29tamlkLCB0eXBlOiAndW5hdmFpbGFibGUnIH0pO1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwLmxlbmd0aCA9IDA7XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZChwcmVzKTtcbiAgICAgICAgfSxcbiAgICAgICAgY3JlYXRlTm9uQW5vbnltb3VzUm9vbTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgLy8gaHR0cDovL3htcHAub3JnL2V4dGVuc2lvbnMveGVwLTAwNDUuaHRtbCNjcmVhdGVyb29tLXJlc2VydmVkXG5cbiAgICAgICAgICAgIHZhciBnZXRGb3JtID0gJGlxKHt0eXBlOiAnZ2V0JywgdG86IHRoaXMucm9vbWppZH0pXG4gICAgICAgICAgICAgICAgLmMoJ3F1ZXJ5Jywge3htbG5zOiAnaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvbXVjI293bmVyJ30pXG4gICAgICAgICAgICAgICAgLmMoJ3gnLCB7eG1sbnM6ICdqYWJiZXI6eDpkYXRhJywgdHlwZTogJ3N1Ym1pdCd9KTtcblxuICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKGdldEZvcm0sIGZ1bmN0aW9uIChmb3JtKSB7XG5cbiAgICAgICAgICAgICAgICBpZiAoISQoZm9ybSkuZmluZChcbiAgICAgICAgICAgICAgICAgICAgICAgICc+cXVlcnk+eFt4bWxucz1cImphYmJlcjp4OmRhdGFcIl0nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICc+ZmllbGRbdmFyPVwibXVjI3Jvb21jb25maWdfd2hvaXNcIl0nKS5sZW5ndGgpIHtcblxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdub24tYW5vbnltb3VzIHJvb21zIG5vdCBzdXBwb3J0ZWQnKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBmb3JtU3VibWl0ID0gJGlxKHt0bzogdGhpcy5yb29tamlkLCB0eXBlOiAnc2V0J30pXG4gICAgICAgICAgICAgICAgICAgIC5jKCdxdWVyeScsIHt4bWxuczogJ2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyNvd25lcid9KTtcblxuICAgICAgICAgICAgICAgIGZvcm1TdWJtaXQuYygneCcsIHt4bWxuczogJ2phYmJlcjp4OmRhdGEnLCB0eXBlOiAnc3VibWl0J30pO1xuXG4gICAgICAgICAgICAgICAgZm9ybVN1Ym1pdC5jKCdmaWVsZCcsIHsndmFyJzogJ0ZPUk1fVFlQRSd9KVxuICAgICAgICAgICAgICAgICAgICAuYygndmFsdWUnKVxuICAgICAgICAgICAgICAgICAgICAudCgnaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvbXVjI3Jvb21jb25maWcnKS51cCgpLnVwKCk7XG5cbiAgICAgICAgICAgICAgICBmb3JtU3VibWl0LmMoJ2ZpZWxkJywgeyd2YXInOiAnbXVjI3Jvb21jb25maWdfd2hvaXMnfSlcbiAgICAgICAgICAgICAgICAgICAgLmMoJ3ZhbHVlJykudCgnYW55b25lJykudXAoKS51cCgpO1xuXG4gICAgICAgICAgICAgICAgc2VsZi5jb25uZWN0aW9uLnNlbmRJUShmb3JtU3VibWl0KTtcblxuICAgICAgICAgICAgfSwgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGdldHRpbmcgcm9vbSBjb25maWd1cmF0aW9uIGZvcm1cIik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgb25QcmVzZW5jZTogZnVuY3Rpb24gKHByZXMpIHtcbiAgICAgICAgICAgIHZhciBmcm9tID0gcHJlcy5nZXRBdHRyaWJ1dGUoJ2Zyb20nKTtcblxuICAgICAgICAgICAgLy8gV2hhdCBpcyB0aGlzIGZvcj8gQSB3b3JrYXJvdW5kIGZvciBzb21ldGhpbmc/XG4gICAgICAgICAgICBpZiAocHJlcy5nZXRBdHRyaWJ1dGUoJ3R5cGUnKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBQYXJzZSBldGhlcnBhZCB0YWcuXG4gICAgICAgICAgICB2YXIgZXRoZXJwYWQgPSAkKHByZXMpLmZpbmQoJz5ldGhlcnBhZCcpO1xuICAgICAgICAgICAgaWYgKGV0aGVycGFkLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGlmIChjb25maWcuZXRoZXJwYWRfYmFzZSAmJiAhTW9kZXJhdG9yLmlzTW9kZXJhdG9yKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoWE1QUEV2ZW50cy5FVEhFUlBBRCwgZXRoZXJwYWQudGV4dCgpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFBhcnNlIHByZXppIHRhZy5cbiAgICAgICAgICAgIHZhciBwcmVzZW50YXRpb24gPSAkKHByZXMpLmZpbmQoJz5wcmV6aScpO1xuICAgICAgICAgICAgaWYgKHByZXNlbnRhdGlvbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gcHJlc2VudGF0aW9uLmF0dHIoJ3VybCcpO1xuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50ID0gcHJlc2VudGF0aW9uLmZpbmQoJz5jdXJyZW50JykudGV4dCgpO1xuXG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3ByZXNlbnRhdGlvbiBpbmZvIHJlY2VpdmVkIGZyb20nLCBmcm9tLCB1cmwpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucHJlemlNYXBbZnJvbV0gPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnByZXppTWFwW2Zyb21dID0gdXJsO1xuXG4gICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ3ByZXNlbnRhdGlvbmFkZGVkLm11YycsIFtmcm9tLCB1cmwsIGN1cnJlbnRdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2dvdG9zbGlkZS5tdWMnLCBbZnJvbSwgdXJsLCBjdXJyZW50XSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAodGhpcy5wcmV6aU1hcFtmcm9tXSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgdmFyIHVybCA9IHRoaXMucHJlemlNYXBbZnJvbV07XG4gICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMucHJlemlNYXBbZnJvbV07XG4gICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcigncHJlc2VudGF0aW9ucmVtb3ZlZC5tdWMnLCBbZnJvbSwgdXJsXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFBhcnNlIGF1ZGlvIGluZm8gdGFnLlxuICAgICAgICAgICAgdmFyIGF1ZGlvTXV0ZWQgPSAkKHByZXMpLmZpbmQoJz5hdWRpb211dGVkJyk7XG4gICAgICAgICAgICBpZiAoYXVkaW9NdXRlZC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdhdWRpb211dGVkLm11YycsIFtmcm9tLCBhdWRpb011dGVkLnRleHQoKV0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBQYXJzZSB2aWRlbyBpbmZvIHRhZy5cbiAgICAgICAgICAgIHZhciB2aWRlb011dGVkID0gJChwcmVzKS5maW5kKCc+dmlkZW9tdXRlZCcpO1xuICAgICAgICAgICAgaWYgKHZpZGVvTXV0ZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcigndmlkZW9tdXRlZC5tdWMnLCBbZnJvbSwgdmlkZW9NdXRlZC50ZXh0KCldKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGRldmljZXMgPSAkKHByZXMpLmZpbmQoJz5kZXZpY2VzJyk7XG4gICAgICAgICAgICBpZihkZXZpY2VzLmxlbmd0aClcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB2YXIgYXVkaW8gPSBkZXZpY2VzLmZpbmQoJz5hdWRpbycpO1xuICAgICAgICAgICAgICAgIHZhciB2aWRlbyA9IGRldmljZXMuZmluZCgnPnZpZGVvJyk7XG4gICAgICAgICAgICAgICAgdmFyIGRldmljZXNWYWx1ZXMgPSB7YXVkaW86IGZhbHNlLCB2aWRlbzogZmFsc2V9O1xuICAgICAgICAgICAgICAgIGlmKGF1ZGlvLmxlbmd0aCAmJiBhdWRpby50ZXh0KCkgPT09IFwidHJ1ZVwiKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZGV2aWNlc1ZhbHVlcy5hdWRpbyA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYodmlkZW8ubGVuZ3RoICYmIHZpZGVvLnRleHQoKSA9PT0gXCJ0cnVlXCIpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBkZXZpY2VzVmFsdWVzLnZpZGVvID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoWE1QUEV2ZW50cy5ERVZJQ0VfQVZBSUxBQkxFLFxuICAgICAgICAgICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChmcm9tKSwgZGV2aWNlc1ZhbHVlcyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBzdGF0cyA9ICQocHJlcykuZmluZCgnPnN0YXRzJyk7XG4gICAgICAgICAgICBpZiAoc3RhdHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdmFyIHN0YXRzT2JqID0ge307XG4gICAgICAgICAgICAgICAgU3Ryb3BoZS5mb3JFYWNoQ2hpbGQoc3RhdHNbMF0sIFwic3RhdFwiLCBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgc3RhdHNPYmpbZWwuZ2V0QXR0cmlidXRlKFwibmFtZVwiKV0gPSBlbC5nZXRBdHRyaWJ1dGUoXCJ2YWx1ZVwiKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLlJFTU9URV9TVEFUUywgZnJvbSwgc3RhdHNPYmopO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBQYXJzZSBzdGF0dXMuXG4gICAgICAgICAgICBpZiAoJChwcmVzKS5maW5kKCc+eFt4bWxucz1cImh0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyN1c2VyXCJdPnN0YXR1c1tjb2RlPVwiMjAxXCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pc093bmVyID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmNyZWF0ZU5vbkFub255bW91c1Jvb20oKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUGFyc2Ugcm9sZXMuXG4gICAgICAgICAgICB2YXIgbWVtYmVyID0ge307XG4gICAgICAgICAgICBtZW1iZXIuc2hvdyA9ICQocHJlcykuZmluZCgnPnNob3cnKS50ZXh0KCk7XG4gICAgICAgICAgICBtZW1iZXIuc3RhdHVzID0gJChwcmVzKS5maW5kKCc+c3RhdHVzJykudGV4dCgpO1xuICAgICAgICAgICAgdmFyIHRtcCA9ICQocHJlcykuZmluZCgnPnhbeG1sbnM9XCJodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjdXNlclwiXT5pdGVtJyk7XG4gICAgICAgICAgICBtZW1iZXIuYWZmaWxpYXRpb24gPSB0bXAuYXR0cignYWZmaWxpYXRpb24nKTtcbiAgICAgICAgICAgIG1lbWJlci5yb2xlID0gdG1wLmF0dHIoJ3JvbGUnKTtcblxuICAgICAgICAgICAgLy8gRm9jdXMgcmVjb2duaXRpb25cbiAgICAgICAgICAgIG1lbWJlci5qaWQgPSB0bXAuYXR0cignamlkJyk7XG4gICAgICAgICAgICBtZW1iZXIuaXNGb2N1cyA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKG1lbWJlci5qaWRcbiAgICAgICAgICAgICAgICAmJiBtZW1iZXIuamlkLmluZGV4T2YoTW9kZXJhdG9yLmdldEZvY3VzVXNlckppZCgpICsgXCIvXCIpID09IDApIHtcbiAgICAgICAgICAgICAgICBtZW1iZXIuaXNGb2N1cyA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBuaWNrdGFnID0gJChwcmVzKS5maW5kKCc+bmlja1t4bWxucz1cImh0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL25pY2tcIl0nKTtcbiAgICAgICAgICAgIG1lbWJlci5kaXNwbGF5TmFtZSA9IChuaWNrdGFnLmxlbmd0aCA+IDAgPyBuaWNrdGFnLmh0bWwoKSA6IG51bGwpO1xuXG4gICAgICAgICAgICBpZiAoZnJvbSA9PSB0aGlzLm15cm9vbWppZCkge1xuICAgICAgICAgICAgICAgIGlmIChtZW1iZXIuYWZmaWxpYXRpb24gPT0gJ293bmVyJykgdGhpcy5pc093bmVyID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5yb2xlICE9PSBtZW1iZXIucm9sZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJvbGUgPSBtZW1iZXIucm9sZTtcblxuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkxPQ0FMUk9MRV9DSEFOR0VELFxuICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSwgbWVtYmVyLCBwcmVzLCBNb2RlcmF0b3IuaXNNb2RlcmF0b3IoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5qb2luZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5qb2luZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLk1VQ19KT0lORUQsIGZyb20sIG1lbWJlcik7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdF9tZW1iZXJzLnB1c2goZnJvbSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLm1lbWJlcnNbZnJvbV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIC8vIG5ldyBwYXJ0aWNpcGFudFxuICAgICAgICAgICAgICAgIHRoaXMubWVtYmVyc1tmcm9tXSA9IG1lbWJlcjtcbiAgICAgICAgICAgICAgICB0aGlzLmxpc3RfbWVtYmVycy5wdXNoKGZyb20pO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdlbnRlcmVkJywgZnJvbSwgbWVtYmVyKTtcbiAgICAgICAgICAgICAgICBpZiAobWVtYmVyLmlzRm9jdXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5mb2N1c011Y0ppZCA9IGZyb207XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIklnbm9yZSBmb2N1czogXCIgKyBmcm9tICsgXCIsIHJlYWwgSklEOiBcIiArIG1lbWJlci5qaWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGlkID0gJChwcmVzKS5maW5kKCc+dXNlcklEJykudGV4dCgpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZW1haWwgPSAkKHByZXMpLmZpbmQoJz5lbWFpbCcpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZW1haWwubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWQgPSBlbWFpbC50ZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoWE1QUEV2ZW50cy5NVUNfRU5URVIsIGZyb20sIGlkLCBtZW1iZXIuZGlzcGxheU5hbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gUHJlc2VuY2UgdXBkYXRlIGZvciBleGlzdGluZyBwYXJ0aWNpcGFudFxuICAgICAgICAgICAgICAgIC8vIFdhdGNoIHJvbGUgY2hhbmdlOlxuICAgICAgICAgICAgICAgIGlmICh0aGlzLm1lbWJlcnNbZnJvbV0ucm9sZSAhPSBtZW1iZXIucm9sZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm1lbWJlcnNbZnJvbV0ucm9sZSA9IG1lbWJlci5yb2xlO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLk1VQ19ST0xFX0NIQU5HRUQsXG4gICAgICAgICAgICAgICAgICAgICAgICBtZW1iZXIucm9sZSwgbWVtYmVyLmRpc3BsYXlOYW1lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEFsd2F5cyB0cmlnZ2VyIHByZXNlbmNlIHRvIHVwZGF0ZSBiaW5kaW5nc1xuICAgICAgICAgICAgdGhpcy5wYXJzZVByZXNlbmNlKGZyb20sIG1lbWJlciwgcHJlcyk7XG5cbiAgICAgICAgICAgIC8vIFRyaWdnZXIgc3RhdHVzIG1lc3NhZ2UgdXBkYXRlXG4gICAgICAgICAgICBpZiAobWVtYmVyLnN0YXR1cykge1xuICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuUFJFU0VOQ0VfU1RBVFVTLCBmcm9tLCBtZW1iZXIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgb25QcmVzZW5jZVVuYXZhaWxhYmxlOiBmdW5jdGlvbiAocHJlcykge1xuICAgICAgICAgICAgdmFyIGZyb20gPSBwcmVzLmdldEF0dHJpYnV0ZSgnZnJvbScpO1xuICAgICAgICAgICAgLy8gcm9vbSBkZXN0cm95ZWQgP1xuICAgICAgICAgICAgaWYgKCQocHJlcykuZmluZCgnPnhbeG1sbnM9XCJodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjdXNlclwiXScgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPmRlc3Ryb3knKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVhc29uO1xuICAgICAgICAgICAgICAgIHZhciByZWFzb25TZWxlY3QgPSAkKHByZXMpLmZpbmQoXG4gICAgICAgICAgICAgICAgICAgICc+eFt4bWxucz1cImh0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyN1c2VyXCJdJyArXG4gICAgICAgICAgICAgICAgICAgICc+ZGVzdHJveT5yZWFzb24nKTtcbiAgICAgICAgICAgICAgICBpZiAocmVhc29uU2VsZWN0Lmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICByZWFzb24gPSByZWFzb25TZWxlY3QudGV4dCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBYTVBQLmRpc3Bvc2VDb25mZXJlbmNlKGZhbHNlKTtcbiAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLk1VQ19ERVNUUk9ZRUQsIHJlYXNvbik7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBTdGF0dXMgY29kZSAxMTAgaW5kaWNhdGVzIHRoYXQgdGhpcyBub3RpZmljYXRpb24gaXMgXCJzZWxmLXByZXNlbmNlXCIuXG4gICAgICAgICAgICBpZiAoISQocHJlcykuZmluZCgnPnhbeG1sbnM9XCJodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjdXNlclwiXT5zdGF0dXNbY29kZT1cIjExMFwiXScpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLm1lbWJlcnNbZnJvbV07XG4gICAgICAgICAgICAgICAgdGhpcy5saXN0X21lbWJlcnMuc3BsaWNlKHRoaXMubGlzdF9tZW1iZXJzLmluZGV4T2YoZnJvbSksIDEpO1xuICAgICAgICAgICAgICAgIHRoaXMub25QYXJ0aWNpcGFudExlZnQoZnJvbSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBJZiB0aGUgc3RhdHVzIGNvZGUgaXMgMTEwIHRoaXMgbWVhbnMgd2UncmUgbGVhdmluZyBhbmQgd2Ugd291bGQgbGlrZVxuICAgICAgICAgICAgLy8gdG8gcmVtb3ZlIGV2ZXJ5b25lIGVsc2UgZnJvbSBvdXIgdmlldywgc28gd2UgdHJpZ2dlciB0aGUgZXZlbnQuXG4gICAgICAgICAgICBlbHNlIGlmICh0aGlzLmxpc3RfbWVtYmVycy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxpc3RfbWVtYmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgbWVtYmVyID0gdGhpcy5saXN0X21lbWJlcnNbaV07XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLm1lbWJlcnNbaV07XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdF9tZW1iZXJzLnNwbGljZShpLCAxKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vblBhcnRpY2lwYW50TGVmdChtZW1iZXIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICgkKHByZXMpLmZpbmQoJz54W3htbG5zPVwiaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvbXVjI3VzZXJcIl0+c3RhdHVzW2NvZGU9XCIzMDdcIl0nKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdraWNrZWQubXVjJywgW2Zyb21dKTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5teXJvb21qaWQgPT09IGZyb20pIHtcbiAgICAgICAgICAgICAgICAgICAgWE1QUC5kaXNwb3NlQ29uZmVyZW5jZShmYWxzZSk7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuS0lDS0VEKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgb25QcmVzZW5jZUVycm9yOiBmdW5jdGlvbiAocHJlcykge1xuICAgICAgICAgICAgdmFyIGZyb20gPSBwcmVzLmdldEF0dHJpYnV0ZSgnZnJvbScpO1xuICAgICAgICAgICAgaWYgKCQocHJlcykuZmluZCgnPmVycm9yW3R5cGU9XCJhdXRoXCJdPm5vdC1hdXRob3JpemVkW3htbG5zPVwidXJuOmlldGY6cGFyYW1zOnhtbDpuczp4bXBwLXN0YW56YXNcIl0nKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnb24gcGFzc3dvcmQgcmVxdWlyZWQnLCBmcm9tKTtcbiAgICAgICAgICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoWE1QUEV2ZW50cy5QQVNTV09SRF9SRVFVSVJFRCwgZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuZG9Kb2luKGZyb20sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoJChwcmVzKS5maW5kKFxuICAgICAgICAgICAgICAgICc+ZXJyb3JbdHlwZT1cImNhbmNlbFwiXT5ub3QtYWxsb3dlZFt4bWxucz1cInVybjppZXRmOnBhcmFtczp4bWw6bnM6eG1wcC1zdGFuemFzXCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRvRG9tYWluID0gU3Ryb3BoZS5nZXREb21haW5Gcm9tSmlkKHByZXMuZ2V0QXR0cmlidXRlKCd0bycpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9Eb21haW4gPT09IGNvbmZpZy5ob3N0cy5hbm9ueW1vdXNkb21haW4pIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gZW50ZXIgdGhlIHJvb20gYnkgcmVwbHlpbmcgd2l0aCAnbm90LWF1dGhvcml6ZWQnLiBUaGlzIHdvdWxkXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlc3VsdCBpbiByZWNvbm5lY3Rpb24gZnJvbSBhdXRob3JpemVkIGRvbWFpbi5cbiAgICAgICAgICAgICAgICAgICAgLy8gV2UncmUgZWl0aGVyIG1pc3NpbmcgSmljb2ZvL1Byb3NvZHkgY29uZmlnIGZvciBhbm9ueW1vdXNcbiAgICAgICAgICAgICAgICAgICAgLy8gZG9tYWlucyBvciBzb21ldGhpbmcgaXMgd3JvbmcuXG4vLyAgICAgICAgICAgICAgICAgICAgWE1QUC5wcm9tcHRMb2dpbigpO1xuICAgICAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIub3BlblJlcG9ydERpYWxvZyhudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJkaWFsb2cuam9pbkVycm9yXCIsIHByZXMpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2Fybignb25QcmVzRXJyb3IgJywgcHJlcyk7XG4gICAgICAgICAgICAgICAgICAgIEFQUC5VSS5tZXNzYWdlSGFuZGxlci5vcGVuUmVwb3J0RGlhbG9nKG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICBcImRpYWxvZy5jb25uZWN0RXJyb3JcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZXMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdvblByZXNFcnJvciAnLCBwcmVzKTtcbiAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIub3BlblJlcG9ydERpYWxvZyhudWxsLFxuICAgICAgICAgICAgICAgICAgICBcImRpYWxvZy5jb25uZWN0RXJyb3JcIixcbiAgICAgICAgICAgICAgICAgICAgcHJlcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2VuZE1lc3NhZ2U6IGZ1bmN0aW9uIChib2R5LCBuaWNrbmFtZSkge1xuICAgICAgICAgICAgdmFyIG1zZyA9ICRtc2coe3RvOiB0aGlzLnJvb21qaWQsIHR5cGU6ICdncm91cGNoYXQnfSk7XG4gICAgICAgICAgICBtc2cuYygnYm9keScsIGJvZHkpLnVwKCk7XG4gICAgICAgICAgICBpZiAobmlja25hbWUpIHtcbiAgICAgICAgICAgICAgICBtc2cuYygnbmljaycsIHt4bWxuczogJ2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL25pY2snfSkudChuaWNrbmFtZSkudXAoKS51cCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQobXNnKTtcbiAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuU0VORElOR19DSEFUX01FU1NBR0UsIGJvZHkpO1xuICAgICAgICB9LFxuICAgICAgICBzZXRTdWJqZWN0OiBmdW5jdGlvbiAoc3ViamVjdCkge1xuICAgICAgICAgICAgdmFyIG1zZyA9ICRtc2coe3RvOiB0aGlzLnJvb21qaWQsIHR5cGU6ICdncm91cGNoYXQnfSk7XG4gICAgICAgICAgICBtc2cuYygnc3ViamVjdCcsIHN1YmplY3QpO1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQobXNnKTtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwidG9waWMgY2hhbmdlZCB0byBcIiArIHN1YmplY3QpO1xuICAgICAgICB9LFxuICAgICAgICBvbk1lc3NhZ2U6IGZ1bmN0aW9uIChtc2cpIHtcbiAgICAgICAgICAgIC8vIEZJWE1FOiB0aGlzIGlzIGEgaGFjay4gYnV0IGppbmdsZSBvbiBtdWMgbWFrZXMgbmlja2NoYW5nZXMgaGFyZFxuICAgICAgICAgICAgdmFyIGZyb20gPSBtc2cuZ2V0QXR0cmlidXRlKCdmcm9tJyk7XG4gICAgICAgICAgICB2YXIgbmljayA9XG4gICAgICAgICAgICAgICAgJChtc2cpLmZpbmQoJz5uaWNrW3htbG5zPVwiaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvbmlja1wiXScpXG4gICAgICAgICAgICAgICAgICAgIC50ZXh0KCkgfHxcbiAgICAgICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChmcm9tKTtcblxuICAgICAgICAgICAgdmFyIHR4dCA9ICQobXNnKS5maW5kKCc+Ym9keScpLnRleHQoKTtcbiAgICAgICAgICAgIHZhciB0eXBlID0gbXNnLmdldEF0dHJpYnV0ZShcInR5cGVcIik7XG4gICAgICAgICAgICBpZiAodHlwZSA9PSBcImVycm9yXCIpIHtcbiAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkNIQVRfRVJST1JfUkVDRUlWRUQsXG4gICAgICAgICAgICAgICAgICAgICQobXNnKS5maW5kKCc+dGV4dCcpLnRleHQoKSwgdHh0KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHN1YmplY3QgPSAkKG1zZykuZmluZCgnPnN1YmplY3QnKTtcbiAgICAgICAgICAgIGlmIChzdWJqZWN0Lmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBzdWJqZWN0VGV4dCA9IHN1YmplY3QudGV4dCgpO1xuICAgICAgICAgICAgICAgIGlmIChzdWJqZWN0VGV4dCB8fCBzdWJqZWN0VGV4dCA9PSBcIlwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuU1VCSkVDVF9DSEFOR0VELCBzdWJqZWN0VGV4dCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiU3ViamVjdCBpcyBjaGFuZ2VkIHRvIFwiICsgc3ViamVjdFRleHQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICBpZiAodHh0KSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ2NoYXQnLCBuaWNrLCB0eHQpO1xuICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuTUVTU0FHRV9SRUNFSVZFRCxcbiAgICAgICAgICAgICAgICAgICAgZnJvbSwgbmljaywgdHh0LCB0aGlzLm15cm9vbWppZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgbG9ja1Jvb206IGZ1bmN0aW9uIChrZXksIG9uU3VjY2Vzcywgb25FcnJvciwgb25Ob3RTdXBwb3J0ZWQpIHtcbiAgICAgICAgICAgIC8vaHR0cDovL3htcHAub3JnL2V4dGVuc2lvbnMveGVwLTAwNDUuaHRtbCNyb29tY29uZmlnXG4gICAgICAgICAgICB2YXIgb2IgPSB0aGlzO1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmRJUSgkaXEoe3RvOiB0aGlzLnJvb21qaWQsIHR5cGU6ICdnZXQnfSkuYygncXVlcnknLCB7eG1sbnM6ICdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjb3duZXInfSksXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoJChyZXMpLmZpbmQoJz5xdWVyeT54W3htbG5zPVwiamFiYmVyOng6ZGF0YVwiXT5maWVsZFt2YXI9XCJtdWMjcm9vbWNvbmZpZ19yb29tc2VjcmV0XCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZm9ybXN1Ym1pdCA9ICRpcSh7dG86IG9iLnJvb21qaWQsIHR5cGU6ICdzZXQnfSkuYygncXVlcnknLCB7eG1sbnM6ICdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjb3duZXInfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3Jtc3VibWl0LmMoJ3gnLCB7eG1sbnM6ICdqYWJiZXI6eDpkYXRhJywgdHlwZTogJ3N1Ym1pdCd9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1zdWJtaXQuYygnZmllbGQnLCB7J3Zhcic6ICdGT1JNX1RZUEUnfSkuYygndmFsdWUnKS50KCdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjcm9vbWNvbmZpZycpLnVwKCkudXAoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1zdWJtaXQuYygnZmllbGQnLCB7J3Zhcic6ICdtdWMjcm9vbWNvbmZpZ19yb29tc2VjcmV0J30pLmMoJ3ZhbHVlJykudChrZXkpLnVwKCkudXAoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZpeGVzIGEgYnVnIGluIHByb3NvZHkgMC45LisgaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9seG1wcGQvaXNzdWVzL2RldGFpbD9pZD0zNzNcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1zdWJtaXQuYygnZmllbGQnLCB7J3Zhcic6ICdtdWMjcm9vbWNvbmZpZ193aG9pcyd9KS5jKCd2YWx1ZScpLnQoJ2FueW9uZScpLnVwKCkudXAoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBpcyBtdWMjcm9vbWNvbmZpZ19wYXNzd29yZHByb3RlY3RlZHJvb20gcmVxdWlyZWQ/XG4gICAgICAgICAgICAgICAgICAgICAgICBvYi5jb25uZWN0aW9uLnNlbmRJUShmb3Jtc3VibWl0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uU3VjY2VzcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbkVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uTm90U3VwcG9ydGVkKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LCBvbkVycm9yKTtcbiAgICAgICAgfSxcbiAgICAgICAga2ljazogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICAgICAgdmFyIGtpY2tJUSA9ICRpcSh7dG86IHRoaXMucm9vbWppZCwgdHlwZTogJ3NldCd9KVxuICAgICAgICAgICAgICAgIC5jKCdxdWVyeScsIHt4bWxuczogJ2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyNhZG1pbid9KVxuICAgICAgICAgICAgICAgIC5jKCdpdGVtJywge25pY2s6IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCksIHJvbGU6ICdub25lJ30pXG4gICAgICAgICAgICAgICAgLmMoJ3JlYXNvbicpLnQoJ1lvdSBoYXZlIGJlZW4ga2lja2VkLicpLnVwKCkudXAoKS51cCgpO1xuXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKFxuICAgICAgICAgICAgICAgIGtpY2tJUSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdLaWNrIHBhcnRpY2lwYW50IHdpdGggamlkOiAnLCBqaWQsIHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ0tpY2sgcGFydGljaXBhbnQgZXJyb3I6ICcsIGVycm9yKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgc2VuZFByZXNlbmNlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcHJlcyA9ICRwcmVzKHt0bzogdGhpcy5wcmVzTWFwWyd0byddIH0pO1xuICAgICAgICAgICAgcHJlcy5jKCd4Jywge3htbG5zOiB0aGlzLnByZXNNYXBbJ3hucyddfSk7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnByZXNNYXBbJ3Bhc3N3b3JkJ10pIHtcbiAgICAgICAgICAgICAgICBwcmVzLmMoJ3Bhc3N3b3JkJykudCh0aGlzLnByZXNNYXBbJ3Bhc3N3b3JkJ10pLnVwKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXMudXAoKTtcblxuICAgICAgICAgICAgLy8gU2VuZCBYRVAtMDExNSAnYycgc3RhbnphIHRoYXQgY29udGFpbnMgb3VyIGNhcGFiaWxpdGllcyBpbmZvXG4gICAgICAgICAgICBpZiAodGhpcy5jb25uZWN0aW9uLmNhcHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uY2Fwcy5ub2RlID0gY29uZmlnLmNsaWVudE5vZGU7XG4gICAgICAgICAgICAgICAgcHJlcy5jKCdjJywgdGhpcy5jb25uZWN0aW9uLmNhcHMuZ2VuZXJhdGVDYXBzQXR0cnMoKSkudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcHJlcy5jKCd1c2VyLWFnZW50Jywge3htbG5zOiAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L3VzZXItYWdlbnQnfSlcbiAgICAgICAgICAgICAgICAudChuYXZpZ2F0b3IudXNlckFnZW50KS51cCgpO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5wcmVzTWFwWydicmlkZ2VJc0Rvd24nXSkge1xuICAgICAgICAgICAgICAgIHByZXMuYygnYnJpZGdlSXNEb3duJykudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMucHJlc01hcFsnZW1haWwnXSkge1xuICAgICAgICAgICAgICAgIHByZXMuYygnZW1haWwnKS50KHRoaXMucHJlc01hcFsnZW1haWwnXSkudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMucHJlc01hcFsndXNlcklkJ10pIHtcbiAgICAgICAgICAgICAgICBwcmVzLmMoJ3VzZXJJZCcpLnQodGhpcy5wcmVzTWFwWyd1c2VySWQnXSkudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMucHJlc01hcFsnZGlzcGxheU5hbWUnXSkge1xuICAgICAgICAgICAgICAgIC8vIFhFUC0wMTcyXG4gICAgICAgICAgICAgICAgcHJlcy5jKCduaWNrJywge3htbG5zOiAnaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvbmljayd9KVxuICAgICAgICAgICAgICAgICAgICAudCh0aGlzLnByZXNNYXBbJ2Rpc3BsYXlOYW1lJ10pLnVwKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmKHRoaXMucHJlc01hcFtcImRldmljZXNcIl0pXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgcHJlcy5jKCdkZXZpY2VzJykuYygnYXVkaW8nKS50KHRoaXMucHJlc01hcFsnZGV2aWNlcyddLmF1ZGlvKS51cCgpXG4gICAgICAgICAgICAgICAgICAgIC5jKCd2aWRlbycpLnQodGhpcy5wcmVzTWFwWydkZXZpY2VzJ10udmlkZW8pLnVwKCkudXAoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0aGlzLnByZXNNYXBbJ2F1ZGlvbnMnXSkge1xuICAgICAgICAgICAgICAgIHByZXMuYygnYXVkaW9tdXRlZCcsIHt4bWxuczogdGhpcy5wcmVzTWFwWydhdWRpb25zJ119KVxuICAgICAgICAgICAgICAgICAgICAudCh0aGlzLnByZXNNYXBbJ2F1ZGlvbXV0ZWQnXSkudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMucHJlc01hcFsndmlkZW9ucyddKSB7XG4gICAgICAgICAgICAgICAgcHJlcy5jKCd2aWRlb211dGVkJywge3htbG5zOiB0aGlzLnByZXNNYXBbJ3ZpZGVvbnMnXX0pXG4gICAgICAgICAgICAgICAgICAgIC50KHRoaXMucHJlc01hcFsndmlkZW9tdXRlZCddKS51cCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5wcmVzTWFwWydzdGF0c25zJ10pIHtcbiAgICAgICAgICAgICAgICB2YXIgc3RhdHMgPSBwcmVzLmMoJ3N0YXRzJywge3htbG5zOiB0aGlzLnByZXNNYXBbJ3N0YXRzbnMnXX0pO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIHN0YXQgaW4gdGhpcy5wcmVzTWFwW1wic3RhdHNcIl0pXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnByZXNNYXBbXCJzdGF0c1wiXVtzdGF0XSAhPSBudWxsKVxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMuYyhcInN0YXRcIiwge25hbWU6IHN0YXQsIHZhbHVlOiB0aGlzLnByZXNNYXBbXCJzdGF0c1wiXVtzdGF0XX0pLnVwKCk7XG4gICAgICAgICAgICAgICAgcHJlcy51cCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5wcmVzTWFwWydwcmV6aW5zJ10pIHtcbiAgICAgICAgICAgICAgICBwcmVzLmMoJ3ByZXppJyxcbiAgICAgICAgICAgICAgICAgICAge3htbG5zOiB0aGlzLnByZXNNYXBbJ3ByZXppbnMnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICd1cmwnOiB0aGlzLnByZXNNYXBbJ3ByZXppdXJsJ119KVxuICAgICAgICAgICAgICAgICAgICAuYygnY3VycmVudCcpLnQodGhpcy5wcmVzTWFwWydwcmV6aWN1cnJlbnQnXSkudXAoKS51cCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5wcmVzTWFwWydldGhlcnBhZG5zJ10pIHtcbiAgICAgICAgICAgICAgICBwcmVzLmMoJ2V0aGVycGFkJywge3htbG5zOiB0aGlzLnByZXNNYXBbJ2V0aGVycGFkbnMnXX0pXG4gICAgICAgICAgICAgICAgICAgIC50KHRoaXMucHJlc01hcFsnZXRoZXJwYWRuYW1lJ10pLnVwKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnByZXNNYXBbJ21lZGlhbnMnXSkge1xuICAgICAgICAgICAgICAgIHByZXMuYygnbWVkaWEnLCB7eG1sbnM6IHRoaXMucHJlc01hcFsnbWVkaWFucyddfSk7XG4gICAgICAgICAgICAgICAgdmFyIHNvdXJjZU51bWJlciA9IDA7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmtleXModGhpcy5wcmVzTWFwKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGtleS5pbmRleE9mKCdzb3VyY2UnKSA+PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VOdW1iZXIrKztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGlmIChzb3VyY2VOdW1iZXIgPiAwKVxuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMTsgaSA8PSBzb3VyY2VOdW1iZXIgLyAzOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZXMuYygnc291cmNlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7dHlwZTogdGhpcy5wcmVzTWFwWydzb3VyY2UnICsgaSArICdfdHlwZSddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc3JjOiB0aGlzLnByZXNNYXBbJ3NvdXJjZScgKyBpICsgJ19zc3JjJ10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbjogdGhpcy5wcmVzTWFwWydzb3VyY2UnICsgaSArICdfZGlyZWN0aW9uJ11cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8ICdzZW5kcmVjdicgfVxuICAgICAgICAgICAgICAgICAgICAgICAgKS51cCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXMudXAoKTtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kKHByZXMpO1xuICAgICAgICB9LFxuICAgICAgICBhZGREaXNwbGF5TmFtZVRvUHJlc2VuY2U6IGZ1bmN0aW9uIChkaXNwbGF5TmFtZSkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydkaXNwbGF5TmFtZSddID0gZGlzcGxheU5hbWU7XG4gICAgICAgIH0sXG4gICAgICAgIGFkZE1lZGlhVG9QcmVzZW5jZTogZnVuY3Rpb24gKHNvdXJjZU51bWJlciwgbXR5cGUsIHNzcmNzLCBkaXJlY3Rpb24pIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5wcmVzTWFwWydtZWRpYW5zJ10pXG4gICAgICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydtZWRpYW5zJ10gPSAnaHR0cDovL2VzdG9zLmRlL25zL21qcyc7XG5cbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsnc291cmNlJyArIHNvdXJjZU51bWJlciArICdfdHlwZSddID0gbXR5cGU7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3NvdXJjZScgKyBzb3VyY2VOdW1iZXIgKyAnX3NzcmMnXSA9IHNzcmNzO1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydzb3VyY2UnICsgc291cmNlTnVtYmVyICsgJ19kaXJlY3Rpb24nXSA9IGRpcmVjdGlvbjtcbiAgICAgICAgfSxcbiAgICAgICAgYWRkRGV2aWNlc1RvUHJlc2VuY2U6IGZ1bmN0aW9uIChkZXZpY2VzKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ2RldmljZXMnXSA9IGRldmljZXM7XG4gICAgICAgIH0sXG4gICAgICAgIGNsZWFyUHJlc2VuY2VNZWRpYTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgICAgT2JqZWN0LmtleXModGhpcy5wcmVzTWFwKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgICAgICBpZiAoa2V5LmluZGV4T2YoJ3NvdXJjZScpICE9IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBzZWxmLnByZXNNYXBba2V5XTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgYWRkUHJlemlUb1ByZXNlbmNlOiBmdW5jdGlvbiAodXJsLCBjdXJyZW50U2xpZGUpIHtcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsncHJlemlucyddID0gJ2h0dHA6Ly9qaXRzaS5vcmcvaml0bWVldC9wcmV6aSc7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3ByZXppdXJsJ10gPSB1cmw7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3ByZXppY3VycmVudCddID0gY3VycmVudFNsaWRlO1xuICAgICAgICB9LFxuICAgICAgICByZW1vdmVQcmV6aUZyb21QcmVzZW5jZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMucHJlc01hcFsncHJlemlucyddO1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMucHJlc01hcFsncHJleml1cmwnXTtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnByZXNNYXBbJ3ByZXppY3VycmVudCddO1xuICAgICAgICB9LFxuICAgICAgICBhZGRDdXJyZW50U2xpZGVUb1ByZXNlbmNlOiBmdW5jdGlvbiAoY3VycmVudFNsaWRlKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3ByZXppY3VycmVudCddID0gY3VycmVudFNsaWRlO1xuICAgICAgICB9LFxuICAgICAgICBnZXRQcmV6aTogZnVuY3Rpb24gKHJvb21qaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnByZXppTWFwW3Jvb21qaWRdO1xuICAgICAgICB9LFxuICAgICAgICBhZGRFdGhlcnBhZFRvUHJlc2VuY2U6IGZ1bmN0aW9uIChldGhlcnBhZE5hbWUpIHtcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsnZXRoZXJwYWRucyddID0gJ2h0dHA6Ly9qaXRzaS5vcmcvaml0bWVldC9ldGhlcnBhZCc7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ2V0aGVycGFkbmFtZSddID0gZXRoZXJwYWROYW1lO1xuICAgICAgICB9LFxuICAgICAgICBhZGRBdWRpb0luZm9Ub1ByZXNlbmNlOiBmdW5jdGlvbiAoaXNNdXRlZCkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydhdWRpb25zJ10gPSAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L2F1ZGlvJztcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsnYXVkaW9tdXRlZCddID0gaXNNdXRlZC50b1N0cmluZygpO1xuICAgICAgICB9LFxuICAgICAgICBhZGRWaWRlb0luZm9Ub1ByZXNlbmNlOiBmdW5jdGlvbiAoaXNNdXRlZCkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWyd2aWRlb25zJ10gPSAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L3ZpZGVvJztcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsndmlkZW9tdXRlZCddID0gaXNNdXRlZC50b1N0cmluZygpO1xuICAgICAgICB9LFxuICAgICAgICBhZGRDb25uZWN0aW9uSW5mb1RvUHJlc2VuY2U6IGZ1bmN0aW9uIChzdGF0cykge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydzdGF0c25zJ10gPSAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L3N0YXRzJztcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsnc3RhdHMnXSA9IHN0YXRzO1xuICAgICAgICB9LFxuICAgICAgICBmaW5kSmlkRnJvbVJlc291cmNlOiBmdW5jdGlvbiAocmVzb3VyY2VKaWQpIHtcbiAgICAgICAgICAgIGlmIChyZXNvdXJjZUppZCAmJlxuICAgICAgICAgICAgICAgIHJlc291cmNlSmlkID09PSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZCh0aGlzLm15cm9vbWppZCkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5teXJvb21qaWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcGVlckppZCA9IG51bGw7XG4gICAgICAgICAgICBPYmplY3Qua2V5cyh0aGlzLm1lbWJlcnMpLnNvbWUoZnVuY3Rpb24gKGppZCkge1xuICAgICAgICAgICAgICAgIHBlZXJKaWQgPSBqaWQ7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCkgPT09IHJlc291cmNlSmlkO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gcGVlckppZDtcbiAgICAgICAgfSxcbiAgICAgICAgYWRkQnJpZGdlSXNEb3duVG9QcmVzZW5jZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydicmlkZ2VJc0Rvd24nXSA9IHRydWU7XG4gICAgICAgIH0sXG4gICAgICAgIGFkZEVtYWlsVG9QcmVzZW5jZTogZnVuY3Rpb24gKGVtYWlsKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ2VtYWlsJ10gPSBlbWFpbDtcbiAgICAgICAgfSxcbiAgICAgICAgYWRkVXNlcklkVG9QcmVzZW5jZTogZnVuY3Rpb24gKHVzZXJJZCkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWyd1c2VySWQnXSA9IHVzZXJJZDtcbiAgICAgICAgfSxcbiAgICAgICAgaXNNb2RlcmF0b3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvbGUgPT09ICdtb2RlcmF0b3InO1xuICAgICAgICB9LFxuICAgICAgICBnZXRNZW1iZXJSb2xlOiBmdW5jdGlvbiAocGVlckppZCkge1xuICAgICAgICAgICAgaWYgKHRoaXMubWVtYmVyc1twZWVySmlkXSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm1lbWJlcnNbcGVlckppZF0ucm9sZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9LFxuICAgICAgICBvblBhcnRpY2lwYW50TGVmdDogZnVuY3Rpb24gKGppZCkge1xuXG4gICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLk1VQ19MRUZULCBqaWQpO1xuXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uamluZ2xlLnRlcm1pbmF0ZUJ5SmlkKGppZCk7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLmdldFByZXppKGppZCkpIHtcbiAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdwcmVzZW50YXRpb25yZW1vdmVkLm11YycsXG4gICAgICAgICAgICAgICAgICAgIFtqaWQsIHRoaXMuZ2V0UHJlemkoamlkKV0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBNb2RlcmF0b3Iub25NdWNMZWZ0KGppZCk7XG4gICAgICAgIH0sXG4gICAgICAgIHBhcnNlUHJlc2VuY2U6IGZ1bmN0aW9uIChmcm9tLCBtZW1lYmVyLCBwcmVzKSB7XG4gICAgICAgICAgICBpZigkKHByZXMpLmZpbmQoXCI+YnJpZGdlSXNEb3duXCIpLmxlbmd0aCA+IDAgJiYgIWJyaWRnZUlzRG93bikge1xuICAgICAgICAgICAgICAgIGJyaWRnZUlzRG93biA9IHRydWU7XG4gICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoWE1QUEV2ZW50cy5CUklER0VfRE9XTik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmKG1lbWViZXIuaXNGb2N1cylcbiAgICAgICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICAgIC8vIFJlbW92ZSBvbGQgc3NyY3MgY29taW5nIGZyb20gdGhlIGppZFxuICAgICAgICAgICAgT2JqZWN0LmtleXModGhpcy5zc3JjMmppZCkuZm9yRWFjaChmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgICAgIGlmIChzZWxmLnNzcmMyamlkW3NzcmNdID09IGZyb20pIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNlbGYuc3NyYzJqaWRbc3NyY107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciBjaGFuZ2VkU3RyZWFtcyA9IFtdO1xuICAgICAgICAgICAgJChwcmVzKS5maW5kKCc+bWVkaWFbeG1sbnM9XCJodHRwOi8vZXN0b3MuZGUvbnMvbWpzXCJdPnNvdXJjZScpLmVhY2goZnVuY3Rpb24gKGlkeCwgc3NyYykge1xuICAgICAgICAgICAgICAgIC8vY29uc29sZS5sb2coamlkLCAnYXNzb2Mgc3NyYycsIHNzcmMuZ2V0QXR0cmlidXRlKCd0eXBlJyksIHNzcmMuZ2V0QXR0cmlidXRlKCdzc3JjJykpO1xuICAgICAgICAgICAgICAgIHZhciBzc3JjViA9IHNzcmMuZ2V0QXR0cmlidXRlKCdzc3JjJyk7XG4gICAgICAgICAgICAgICAgc2VsZi5zc3JjMmppZFtzc3JjVl0gPSBmcm9tO1xuICAgICAgICAgICAgICAgIEppbmdsZVNlc3Npb24ubm90UmVjZWl2ZWRTU1JDcy5wdXNoKHNzcmNWKTtcblxuXG4gICAgICAgICAgICAgICAgdmFyIHR5cGUgPSBzc3JjLmdldEF0dHJpYnV0ZSgndHlwZScpO1xuXG4gICAgICAgICAgICAgICAgdmFyIGRpcmVjdGlvbiA9IHNzcmMuZ2V0QXR0cmlidXRlKCdkaXJlY3Rpb24nKTtcblxuICAgICAgICAgICAgICAgIGNoYW5nZWRTdHJlYW1zLnB1c2goe3R5cGU6IHR5cGUsIGRpcmVjdGlvbjogZGlyZWN0aW9ufSk7XG5cbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkNIQU5HRURfU1RSRUFNUywgZnJvbSwgY2hhbmdlZFN0cmVhbXMpO1xuXG4gICAgICAgICAgICB2YXIgZGlzcGxheU5hbWUgPSAhY29uZmlnLmRpc3BsYXlKaWRzXG4gICAgICAgICAgICAgICAgPyBtZW1lYmVyLmRpc3BsYXlOYW1lIDogU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoZnJvbSk7XG5cbiAgICAgICAgICAgIGlmIChkaXNwbGF5TmFtZSAmJiBkaXNwbGF5TmFtZS5sZW5ndGggPiAwKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuRElTUExBWV9OQU1FX0NIQU5HRUQsIGZyb20sIGRpc3BsYXlOYW1lKTtcbiAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICB2YXIgaWQgPSAkKHByZXMpLmZpbmQoJz51c2VySUQnKS50ZXh0KCk7XG4gICAgICAgICAgICB2YXIgZW1haWwgPSAkKHByZXMpLmZpbmQoJz5lbWFpbCcpO1xuICAgICAgICAgICAgaWYoZW1haWwubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGlkID0gZW1haWwudGV4dCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLlVTRVJfSURfQ0hBTkdFRCwgZnJvbSwgaWQpO1xuICAgICAgICB9XG4gICAgfSk7XG59O1xuXG4iLCIvKiBqc2hpbnQgLVcxMTcgKi9cblxudmFyIEppbmdsZVNlc3Npb24gPSByZXF1aXJlKFwiLi9KaW5nbGVTZXNzaW9uXCIpO1xudmFyIFhNUFBFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS94bXBwL1hNUFBFdmVudHNcIik7XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihYTVBQLCBldmVudEVtaXR0ZXIpXG57XG4gICAgZnVuY3Rpb24gQ2FsbEluY29taW5nSmluZ2xlKHNpZCwgY29ubmVjdGlvbikge1xuICAgICAgICB2YXIgc2VzcyA9IGNvbm5lY3Rpb24uamluZ2xlLnNlc3Npb25zW3NpZF07XG5cbiAgICAgICAgLy8gVE9ETzogZG8gd2UgY2hlY2sgYWN0aXZlY2FsbCA9PSBudWxsP1xuICAgICAgICBjb25uZWN0aW9uLmppbmdsZS5hY3RpdmVjYWxsID0gc2VzcztcblxuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkNBTExfSU5DT01JTkcsIHNlc3MpO1xuXG4gICAgICAgIC8vIFRPRE86IGNoZWNrIGFmZmlsaWF0aW9uIGFuZC9vciByb2xlXG4gICAgICAgIGNvbnNvbGUubG9nKCdlbXVjIGRhdGEgZm9yJywgc2Vzcy5wZWVyamlkLCBjb25uZWN0aW9uLmVtdWMubWVtYmVyc1tzZXNzLnBlZXJqaWRdKTtcbiAgICAgICAgc2Vzcy51c2VkcmlwID0gdHJ1ZTsgLy8gbm90LXNvLW5haXZlIHRyaWNrbGUgaWNlXG4gICAgICAgIHNlc3Muc2VuZEFuc3dlcigpO1xuICAgICAgICBzZXNzLmFjY2VwdCgpO1xuXG4gICAgfTtcblxuICAgIFN0cm9waGUuYWRkQ29ubmVjdGlvblBsdWdpbignamluZ2xlJywge1xuICAgICAgICBjb25uZWN0aW9uOiBudWxsLFxuICAgICAgICBzZXNzaW9uczoge30sXG4gICAgICAgIGppZDJzZXNzaW9uOiB7fSxcbiAgICAgICAgaWNlX2NvbmZpZzoge2ljZVNlcnZlcnM6IFtdfSxcbiAgICAgICAgcGNfY29uc3RyYWludHM6IHt9LFxuICAgICAgICBhY3RpdmVjYWxsOiBudWxsLFxuICAgICAgICBtZWRpYV9jb25zdHJhaW50czoge1xuICAgICAgICAgICAgbWFuZGF0b3J5OiB7XG4gICAgICAgICAgICAgICAgJ09mZmVyVG9SZWNlaXZlQXVkaW8nOiB0cnVlLFxuICAgICAgICAgICAgICAgICdPZmZlclRvUmVjZWl2ZVZpZGVvJzogdHJ1ZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gTW96RG9udE9mZmVyRGF0YUNoYW5uZWw6IHRydWUgd2hlbiB0aGlzIGlzIGZpcmVmb3hcbiAgICAgICAgfSxcbiAgICAgICAgaW5pdDogZnVuY3Rpb24gKGNvbm4pIHtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbiA9IGNvbm47XG4gICAgICAgICAgICBpZiAodGhpcy5jb25uZWN0aW9uLmRpc2NvKSB7XG4gICAgICAgICAgICAgICAgLy8gaHR0cDovL3htcHAub3JnL2V4dGVuc2lvbnMveGVwLTAxNjcuaHRtbCNzdXBwb3J0XG4gICAgICAgICAgICAgICAgLy8gaHR0cDovL3htcHAub3JnL2V4dGVuc2lvbnMveGVwLTAxNzYuaHRtbCNzdXBwb3J0XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3Vybjp4bXBwOmppbmdsZToxJyk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDoxJyk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3Vybjp4bXBwOmppbmdsZTp0cmFuc3BvcnRzOmljZS11ZHA6MScpO1xuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5kaXNjby5hZGRGZWF0dXJlKCd1cm46eG1wcDpqaW5nbGU6dHJhbnNwb3J0czpkdGxzLXNjdHA6MScpO1xuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5kaXNjby5hZGRGZWF0dXJlKCd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6YXVkaW8nKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZGlzY28uYWRkRmVhdHVyZSgndXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnZpZGVvJyk7XG5cblxuICAgICAgICAgICAgICAgIC8vIHRoaXMgaXMgZGVhbHQgd2l0aCBieSBTRFAgTy9BIHNvIHdlIGRvbid0IG5lZWQgdG8gYW5ub3VjZSB0aGlzXG4gICAgICAgICAgICAgICAgLy90aGlzLmNvbm5lY3Rpb24uZGlzY28uYWRkRmVhdHVyZSgndXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnJ0Y3AtZmI6MCcpOyAvLyBYRVAtMDI5M1xuICAgICAgICAgICAgICAgIC8vdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpydHAtaGRyZXh0OjAnKTsgLy8gWEVQLTAyOTRcbiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLnVzZVJ0Y3BNdXgpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3VybjppZXRmOnJmYzo1NzYxJyk7IC8vIHJ0Y3AtbXV4XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChjb25maWcudXNlQnVuZGxlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5kaXNjby5hZGRGZWF0dXJlKCd1cm46aWV0ZjpyZmM6NTg4OCcpOyAvLyBhPWdyb3VwLCBlLmcuIGJ1bmRsZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvL3RoaXMuY29ubmVjdGlvbi5kaXNjby5hZGRGZWF0dXJlKCd1cm46aWV0ZjpyZmM6NTU3NicpOyAvLyBhPXNzcmNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5hZGRIYW5kbGVyKHRoaXMub25KaW5nbGUuYmluZCh0aGlzKSwgJ3Vybjp4bXBwOmppbmdsZToxJywgJ2lxJywgJ3NldCcsIG51bGwsIG51bGwpO1xuICAgICAgICB9LFxuICAgICAgICBvbkppbmdsZTogZnVuY3Rpb24gKGlxKSB7XG4gICAgICAgICAgICB2YXIgc2lkID0gJChpcSkuZmluZCgnamluZ2xlJykuYXR0cignc2lkJyk7XG4gICAgICAgICAgICB2YXIgYWN0aW9uID0gJChpcSkuZmluZCgnamluZ2xlJykuYXR0cignYWN0aW9uJyk7XG4gICAgICAgICAgICB2YXIgZnJvbUppZCA9IGlxLmdldEF0dHJpYnV0ZSgnZnJvbScpO1xuICAgICAgICAgICAgLy8gc2VuZCBhY2sgZmlyc3RcbiAgICAgICAgICAgIHZhciBhY2sgPSAkaXEoe3R5cGU6ICdyZXN1bHQnLFxuICAgICAgICAgICAgICAgIHRvOiBmcm9tSmlkLFxuICAgICAgICAgICAgICAgIGlkOiBpcS5nZXRBdHRyaWJ1dGUoJ2lkJylcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ29uIGppbmdsZSAnICsgYWN0aW9uICsgJyBmcm9tICcgKyBmcm9tSmlkLCBpcSk7XG4gICAgICAgICAgICB2YXIgc2VzcyA9IHRoaXMuc2Vzc2lvbnNbc2lkXTtcbiAgICAgICAgICAgIGlmICgnc2Vzc2lvbi1pbml0aWF0ZScgIT0gYWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNlc3MgPT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgYWNrLnR5cGUgPSAnZXJyb3InO1xuICAgICAgICAgICAgICAgICAgICBhY2suYygnZXJyb3InLCB7dHlwZTogJ2NhbmNlbCd9KVxuICAgICAgICAgICAgICAgICAgICAgICAgLmMoJ2l0ZW0tbm90LWZvdW5kJywge3htbG5zOiAndXJuOmlldGY6cGFyYW1zOnhtbDpuczp4bXBwLXN0YW56YXMnfSkudXAoKVxuICAgICAgICAgICAgICAgICAgICAgICAgLmMoJ3Vua25vd24tc2Vzc2lvbicsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTplcnJvcnM6MSd9KTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQoYWNrKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIGNvbXBhcmUgZnJvbSB0byBzZXNzLnBlZXJqaWQgKGJhcmUgamlkIGNvbXBhcmlzb24gZm9yIGxhdGVyIGNvbXBhdCB3aXRoIG1lc3NhZ2UtbW9kZSlcbiAgICAgICAgICAgICAgICAvLyBsb2NhbCBqaWQgaXMgbm90IGNoZWNrZWRcbiAgICAgICAgICAgICAgICBpZiAoU3Ryb3BoZS5nZXRCYXJlSmlkRnJvbUppZChmcm9tSmlkKSAhPSBTdHJvcGhlLmdldEJhcmVKaWRGcm9tSmlkKHNlc3MucGVlcmppZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdqaWQgbWlzbWF0Y2ggZm9yIHNlc3Npb24gaWQnLCBzaWQsIGZyb21KaWQsIHNlc3MucGVlcmppZCk7XG4gICAgICAgICAgICAgICAgICAgIGFjay50eXBlID0gJ2Vycm9yJztcbiAgICAgICAgICAgICAgICAgICAgYWNrLmMoJ2Vycm9yJywge3R5cGU6ICdjYW5jZWwnfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC5jKCdpdGVtLW5vdC1mb3VuZCcsIHt4bWxuczogJ3VybjppZXRmOnBhcmFtczp4bWw6bnM6eG1wcC1zdGFuemFzJ30pLnVwKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC5jKCd1bmtub3duLXNlc3Npb24nLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6ZXJyb3JzOjEnfSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kKGFjayk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoc2VzcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgLy8gZXhpc3Rpbmcgc2Vzc2lvbiB3aXRoIHNhbWUgc2Vzc2lvbiBpZFxuICAgICAgICAgICAgICAgIC8vIHRoaXMgbWlnaHQgYmUgb3V0LW9mLW9yZGVyIGlmIHRoZSBzZXNzLnBlZXJqaWQgaXMgdGhlIHNhbWUgYXMgZnJvbVxuICAgICAgICAgICAgICAgIGFjay50eXBlID0gJ2Vycm9yJztcbiAgICAgICAgICAgICAgICBhY2suYygnZXJyb3InLCB7dHlwZTogJ2NhbmNlbCd9KVxuICAgICAgICAgICAgICAgICAgICAuYygnc2VydmljZS11bmF2YWlsYWJsZScsIHt4bWxuczogJ3VybjppZXRmOnBhcmFtczp4bWw6bnM6eG1wcC1zdGFuemFzJ30pLnVwKCk7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdkdXBsaWNhdGUgc2Vzc2lvbiBpZCcsIHNpZCk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQoYWNrKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEZJWE1FOiBjaGVjayBmb3IgYSBkZWZpbmVkIGFjdGlvblxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQoYWNrKTtcbiAgICAgICAgICAgIC8vIHNlZSBodHRwOi8veG1wcC5vcmcvZXh0ZW5zaW9ucy94ZXAtMDE2Ni5odG1sI2NvbmNlcHRzLXNlc3Npb25cbiAgICAgICAgICAgIHN3aXRjaCAoYWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY2FzZSAnc2Vzc2lvbi1pbml0aWF0ZSc6XG4gICAgICAgICAgICAgICAgICAgIHNlc3MgPSBuZXcgSmluZ2xlU2Vzc2lvbihcbiAgICAgICAgICAgICAgICAgICAgICAgICQoaXEpLmF0dHIoJ3RvJyksICQoaXEpLmZpbmQoJ2ppbmdsZScpLmF0dHIoJ3NpZCcpLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLCBYTVBQKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gY29uZmlndXJlIHNlc3Npb25cblxuICAgICAgICAgICAgICAgICAgICBzZXNzLm1lZGlhX2NvbnN0cmFpbnRzID0gdGhpcy5tZWRpYV9jb25zdHJhaW50cztcbiAgICAgICAgICAgICAgICAgICAgc2Vzcy5wY19jb25zdHJhaW50cyA9IHRoaXMucGNfY29uc3RyYWludHM7XG4gICAgICAgICAgICAgICAgICAgIHNlc3MuaWNlX2NvbmZpZyA9IHRoaXMuaWNlX2NvbmZpZztcblxuICAgICAgICAgICAgICAgICAgICBzZXNzLmluaXRpYXRlKGZyb21KaWQsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gRklYTUU6IHNldFJlbW90ZURlc2NyaXB0aW9uIHNob3VsZCBvbmx5IGJlIGRvbmUgd2hlbiB0aGlzIGNhbGwgaXMgdG8gYmUgYWNjZXB0ZWRcbiAgICAgICAgICAgICAgICAgICAgc2Vzcy5zZXRSZW1vdGVEZXNjcmlwdGlvbigkKGlxKS5maW5kKCc+amluZ2xlJyksICdvZmZlcicpO1xuXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2Vzc2lvbnNbc2Vzcy5zaWRdID0gc2VzcztcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5qaWQyc2Vzc2lvbltzZXNzLnBlZXJqaWRdID0gc2VzcztcblxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgY2FsbGJhY2sgc2hvdWxkIGVpdGhlclxuICAgICAgICAgICAgICAgICAgICAvLyAuc2VuZEFuc3dlciBhbmQgLmFjY2VwdFxuICAgICAgICAgICAgICAgICAgICAvLyBvciAuc2VuZFRlcm1pbmF0ZSAtLSBub3QgbmVjZXNzYXJpbHkgc3luY2hyb251c1xuICAgICAgICAgICAgICAgICAgICBDYWxsSW5jb21pbmdKaW5nbGUoc2Vzcy5zaWQsIHRoaXMuY29ubmVjdGlvbik7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3Nlc3Npb24tYWNjZXB0JzpcbiAgICAgICAgICAgICAgICAgICAgc2Vzcy5zZXRSZW1vdGVEZXNjcmlwdGlvbigkKGlxKS5maW5kKCc+amluZ2xlJyksICdhbnN3ZXInKTtcbiAgICAgICAgICAgICAgICAgICAgc2Vzcy5hY2NlcHQoKTtcbiAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignY2FsbGFjY2VwdGVkLmppbmdsZScsIFtzZXNzLnNpZF0pO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdzZXNzaW9uLXRlcm1pbmF0ZSc6XG4gICAgICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgaXMgbm90IHRoZSBmb2N1cyBzZW5kaW5nIHRoZSB0ZXJtaW5hdGUsIHdlIGhhdmVcbiAgICAgICAgICAgICAgICAgICAgLy8gbm90aGluZyBtb3JlIHRvIGRvIGhlcmUuXG4gICAgICAgICAgICAgICAgICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLnNlc3Npb25zKS5sZW5ndGggPCAxXG4gICAgICAgICAgICAgICAgICAgICAgICB8fCAhKHRoaXMuc2Vzc2lvbnNbT2JqZWN0LmtleXModGhpcy5zZXNzaW9ucylbMF1dXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5zdGFuY2VvZiBKaW5nbGVTZXNzaW9uKSlcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3Rlcm1pbmF0aW5nLi4uJywgc2Vzcy5zaWQpO1xuICAgICAgICAgICAgICAgICAgICBzZXNzLnRlcm1pbmF0ZSgpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRlcm1pbmF0ZShzZXNzLnNpZCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkKGlxKS5maW5kKCc+amluZ2xlPnJlYXNvbicpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignY2FsbHRlcm1pbmF0ZWQuamluZ2xlJywgW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc3Muc2lkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc3MucGVlcmppZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKGlxKS5maW5kKCc+amluZ2xlPnJlYXNvbj46Zmlyc3QnKVswXS50YWdOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoaXEpLmZpbmQoJz5qaW5nbGU+cmVhc29uPnRleHQnKS50ZXh0KClcbiAgICAgICAgICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignY2FsbHRlcm1pbmF0ZWQuamluZ2xlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBbc2Vzcy5zaWQsIHNlc3MucGVlcmppZF0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3RyYW5zcG9ydC1pbmZvJzpcbiAgICAgICAgICAgICAgICAgICAgc2Vzcy5hZGRJY2VDYW5kaWRhdGUoJChpcSkuZmluZCgnPmppbmdsZT5jb250ZW50JykpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdzZXNzaW9uLWluZm8nOlxuICAgICAgICAgICAgICAgICAgICB2YXIgYWZmZWN0ZWQ7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkKGlxKS5maW5kKCc+amluZ2xlPnJpbmdpbmdbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6aW5mbzoxXCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdyaW5naW5nLmppbmdsZScsIFtzZXNzLnNpZF0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCQoaXEpLmZpbmQoJz5qaW5nbGU+bXV0ZVt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOnJ0cDppbmZvOjFcIl0nKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFmZmVjdGVkID0gJChpcSkuZmluZCgnPmppbmdsZT5tdXRlW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOmluZm86MVwiXScpLmF0dHIoJ25hbWUnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ211dGUuamluZ2xlJywgW3Nlc3Muc2lkLCBhZmZlY3RlZF0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCQoaXEpLmZpbmQoJz5qaW5nbGU+dW5tdXRlW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOmluZm86MVwiXScpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWZmZWN0ZWQgPSAkKGlxKS5maW5kKCc+amluZ2xlPnVubXV0ZVt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOnJ0cDppbmZvOjFcIl0nKS5hdHRyKCduYW1lJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCd1bm11dGUuamluZ2xlJywgW3Nlc3Muc2lkLCBhZmZlY3RlZF0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2FkZHNvdXJjZSc6IC8vIEZJWE1FOiBwcm9wcmlldGFyeSwgdW4tamluZ2xlaXNoXG4gICAgICAgICAgICAgICAgY2FzZSAnc291cmNlLWFkZCc6IC8vIEZJWE1FOiBwcm9wcmlldGFyeVxuICAgICAgICAgICAgICAgICAgICBzZXNzLmFkZFNvdXJjZSgkKGlxKS5maW5kKCc+amluZ2xlPmNvbnRlbnQnKSwgZnJvbUppZCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3JlbW92ZXNvdXJjZSc6IC8vIEZJWE1FOiBwcm9wcmlldGFyeSwgdW4tamluZ2xlaXNoXG4gICAgICAgICAgICAgICAgY2FzZSAnc291cmNlLXJlbW92ZSc6IC8vIEZJWE1FOiBwcm9wcmlldGFyeVxuICAgICAgICAgICAgICAgICAgICBzZXNzLnJlbW92ZVNvdXJjZSgkKGlxKS5maW5kKCc+amluZ2xlPmNvbnRlbnQnKSwgZnJvbUppZCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignamluZ2xlIGFjdGlvbiBub3QgaW1wbGVtZW50ZWQnLCBhY3Rpb24pO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9LFxuICAgICAgICBpbml0aWF0ZTogZnVuY3Rpb24gKHBlZXJqaWQsIG15amlkKSB7IC8vIGluaXRpYXRlIGEgbmV3IGppbmdsZXNlc3Npb24gdG8gcGVlcmppZFxuICAgICAgICAgICAgdmFyIHNlc3MgPSBuZXcgSmluZ2xlU2Vzc2lvbihteWppZCB8fCB0aGlzLmNvbm5lY3Rpb24uamlkLFxuICAgICAgICAgICAgICAgIE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cigyLCAxMiksIC8vIHJhbmRvbSBzdHJpbmdcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24sIFhNUFApO1xuICAgICAgICAgICAgLy8gY29uZmlndXJlIHNlc3Npb25cblxuICAgICAgICAgICAgc2Vzcy5tZWRpYV9jb25zdHJhaW50cyA9IHRoaXMubWVkaWFfY29uc3RyYWludHM7XG4gICAgICAgICAgICBzZXNzLnBjX2NvbnN0cmFpbnRzID0gdGhpcy5wY19jb25zdHJhaW50cztcbiAgICAgICAgICAgIHNlc3MuaWNlX2NvbmZpZyA9IHRoaXMuaWNlX2NvbmZpZztcblxuICAgICAgICAgICAgc2Vzcy5pbml0aWF0ZShwZWVyamlkLCB0cnVlKTtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbnNbc2Vzcy5zaWRdID0gc2VzcztcbiAgICAgICAgICAgIHRoaXMuamlkMnNlc3Npb25bc2Vzcy5wZWVyamlkXSA9IHNlc3M7XG4gICAgICAgICAgICBzZXNzLnNlbmRPZmZlcigpO1xuICAgICAgICAgICAgcmV0dXJuIHNlc3M7XG4gICAgICAgIH0sXG4gICAgICAgIHRlcm1pbmF0ZTogZnVuY3Rpb24gKHNpZCwgcmVhc29uLCB0ZXh0KSB7IC8vIHRlcm1pbmF0ZSBieSBzZXNzaW9uaWQgKG9yIGFsbCBzZXNzaW9ucylcbiAgICAgICAgICAgIGlmIChzaWQgPT09IG51bGwgfHwgc2lkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBmb3IgKHNpZCBpbiB0aGlzLnNlc3Npb25zKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnNlc3Npb25zW3NpZF0uc3RhdGUgIT0gJ2VuZGVkJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXNzaW9uc1tzaWRdLnNlbmRUZXJtaW5hdGUocmVhc29uIHx8ICghdGhpcy5zZXNzaW9uc1tzaWRdLmFjdGl2ZSgpKSA/ICdjYW5jZWwnIDogbnVsbCwgdGV4dCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNlc3Npb25zW3NpZF0udGVybWluYXRlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuamlkMnNlc3Npb25bdGhpcy5zZXNzaW9uc1tzaWRdLnBlZXJqaWRdO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5zZXNzaW9uc1tzaWRdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5zZXNzaW9ucy5oYXNPd25Qcm9wZXJ0eShzaWQpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc2Vzc2lvbnNbc2lkXS5zdGF0ZSAhPSAnZW5kZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2Vzc2lvbnNbc2lkXS5zZW5kVGVybWluYXRlKHJlYXNvbiB8fCAoIXRoaXMuc2Vzc2lvbnNbc2lkXS5hY3RpdmUoKSkgPyAnY2FuY2VsJyA6IG51bGwsIHRleHQpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlc3Npb25zW3NpZF0udGVybWluYXRlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmppZDJzZXNzaW9uW3RoaXMuc2Vzc2lvbnNbc2lkXS5wZWVyamlkXTtcbiAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5zZXNzaW9uc1tzaWRdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICAvLyBVc2VkIHRvIHRlcm1pbmF0ZSBhIHNlc3Npb24gd2hlbiBhbiB1bmF2YWlsYWJsZSBwcmVzZW5jZSBpcyByZWNlaXZlZC5cbiAgICAgICAgdGVybWluYXRlQnlKaWQ6IGZ1bmN0aW9uIChqaWQpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmppZDJzZXNzaW9uLmhhc093blByb3BlcnR5KGppZCkpIHtcbiAgICAgICAgICAgICAgICB2YXIgc2VzcyA9IHRoaXMuamlkMnNlc3Npb25bamlkXTtcbiAgICAgICAgICAgICAgICBpZiAoc2Vzcykge1xuICAgICAgICAgICAgICAgICAgICBzZXNzLnRlcm1pbmF0ZSgpO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygncGVlciB3ZW50IGF3YXkgc2lsZW50bHknLCBqaWQpO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5zZXNzaW9uc1tzZXNzLnNpZF07XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmppZDJzZXNzaW9uW2ppZF07XG4gICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2NhbGx0ZXJtaW5hdGVkLmppbmdsZScsXG4gICAgICAgICAgICAgICAgICAgICAgICBbc2Vzcy5zaWQsIGppZF0sICdnb25lJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB0ZXJtaW5hdGVSZW1vdGVCeUppZDogZnVuY3Rpb24gKGppZCwgcmVhc29uKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5qaWQyc2Vzc2lvbi5oYXNPd25Qcm9wZXJ0eShqaWQpKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNlc3MgPSB0aGlzLmppZDJzZXNzaW9uW2ppZF07XG4gICAgICAgICAgICAgICAgaWYgKHNlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgc2Vzcy5zZW5kVGVybWluYXRlKHJlYXNvbiB8fCAoIXNlc3MuYWN0aXZlKCkpID8gJ2tpY2snIDogbnVsbCk7XG4gICAgICAgICAgICAgICAgICAgIHNlc3MudGVybWluYXRlKCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCd0ZXJtaW5hdGUgcGVlciB3aXRoIGppZCcsIHNlc3Muc2lkLCBqaWQpO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5zZXNzaW9uc1tzZXNzLnNpZF07XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmppZDJzZXNzaW9uW2ppZF07XG4gICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2NhbGx0ZXJtaW5hdGVkLmppbmdsZScsXG4gICAgICAgICAgICAgICAgICAgICAgICBbc2Vzcy5zaWQsIGppZCwgJ2tpY2tlZCddKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGdldFN0dW5BbmRUdXJuQ3JlZGVudGlhbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vIGdldCBzdHVuIGFuZCB0dXJuIGNvbmZpZ3VyYXRpb24gZnJvbSBzZXJ2ZXIgdmlhIHhlcC0wMjE1XG4gICAgICAgICAgICAvLyB1c2VzIHRpbWUtbGltaXRlZCBjcmVkZW50aWFscyBhcyBkZXNjcmliZWQgaW5cbiAgICAgICAgICAgIC8vIGh0dHA6Ly90b29scy5pZXRmLm9yZy9odG1sL2RyYWZ0LXViZXJ0aS1iZWhhdmUtdHVybi1yZXN0LTAwXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gc2VlIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvcHJvc29keS1tb2R1bGVzL3NvdXJjZS9icm93c2UvbW9kX3R1cm5jcmVkZW50aWFscy9tb2RfdHVybmNyZWRlbnRpYWxzLmx1YVxuICAgICAgICAgICAgLy8gZm9yIGEgcHJvc29keSBtb2R1bGUgd2hpY2ggaW1wbGVtZW50cyB0aGlzXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gY3VycmVudGx5LCB0aGlzIGRvZXNuJ3Qgd29yayB3aXRoIHVwZGF0ZUljZSBhbmQgdGhlcmVmb3JlIGNyZWRlbnRpYWxzIHdpdGggYSBsb25nXG4gICAgICAgICAgICAvLyB2YWxpZGl0eSBoYXZlIHRvIGJlIGZldGNoZWQgYmVmb3JlIGNyZWF0aW5nIHRoZSBwZWVyY29ubmVjdGlvblxuICAgICAgICAgICAgLy8gVE9ETzogaW1wbGVtZW50IHJlZnJlc2ggdmlhIHVwZGF0ZUljZSBhcyBkZXNjcmliZWQgaW5cbiAgICAgICAgICAgIC8vICAgICAgaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC93ZWJydGMvaXNzdWVzL2RldGFpbD9pZD0xNjUwXG4gICAgICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKFxuICAgICAgICAgICAgICAgICRpcSh7dHlwZTogJ2dldCcsIHRvOiB0aGlzLmNvbm5lY3Rpb24uZG9tYWlufSlcbiAgICAgICAgICAgICAgICAgICAgLmMoJ3NlcnZpY2VzJywge3htbG5zOiAndXJuOnhtcHA6ZXh0ZGlzY286MSd9KS5jKCdzZXJ2aWNlJywge2hvc3Q6ICd0dXJuLicgKyB0aGlzLmNvbm5lY3Rpb24uZG9tYWlufSksXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgaWNlc2VydmVycyA9IFtdO1xuICAgICAgICAgICAgICAgICAgICAkKHJlcykuZmluZCgnPnNlcnZpY2VzPnNlcnZpY2UnKS5lYWNoKGZ1bmN0aW9uIChpZHgsIGVsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbCA9ICQoZWwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGRpY3QgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0eXBlID0gZWwuYXR0cigndHlwZScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoICh0eXBlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnc3R1bic6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpY3QudXJsID0gJ3N0dW46JyArIGVsLmF0dHIoJ2hvc3QnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsLmF0dHIoJ3BvcnQnKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGljdC51cmwgKz0gJzonICsgZWwuYXR0cigncG9ydCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGljZXNlcnZlcnMucHVzaChkaWN0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAndHVybic6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAndHVybnMnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWN0LnVybCA9IHR5cGUgKyAnOic7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbC5hdHRyKCd1c2VybmFtZScpKSB7IC8vIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3Avd2VicnRjL2lzc3Vlcy9kZXRhaWw/aWQ9MTUwOFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goL0Nocm9tKGV8aXVtKVxcLyhbMC05XSspXFwuLykgJiYgcGFyc2VJbnQobmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvQ2hyb20oZXxpdW0pXFwvKFswLTldKylcXC4vKVsyXSwgMTApIDwgMjgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWN0LnVybCArPSBlbC5hdHRyKCd1c2VybmFtZScpICsgJ0AnO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWN0LnVzZXJuYW1lID0gZWwuYXR0cigndXNlcm5hbWUnKTsgLy8gb25seSB3b3JrcyBpbiBNMjhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWN0LnVybCArPSBlbC5hdHRyKCdob3N0Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbC5hdHRyKCdwb3J0JykgJiYgZWwuYXR0cigncG9ydCcpICE9ICczNDc4Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGljdC51cmwgKz0gJzonICsgZWwuYXR0cigncG9ydCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbC5hdHRyKCd0cmFuc3BvcnQnKSAmJiBlbC5hdHRyKCd0cmFuc3BvcnQnKSAhPSAndWRwJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGljdC51cmwgKz0gJz90cmFuc3BvcnQ9JyArIGVsLmF0dHIoJ3RyYW5zcG9ydCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbC5hdHRyKCdwYXNzd29yZCcpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWN0LmNyZWRlbnRpYWwgPSBlbC5hdHRyKCdwYXNzd29yZCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGljZXNlcnZlcnMucHVzaChkaWN0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLmljZV9jb25maWcuaWNlU2VydmVycyA9IGljZXNlcnZlcnM7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignZ2V0dGluZyB0dXJuIGNyZWRlbnRpYWxzIGZhaWxlZCcsIGVycik7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignaXMgbW9kX3R1cm5jcmVkZW50aWFscyBvciBzaW1pbGFyIGluc3RhbGxlZD8nKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgLy8gaW1wbGVtZW50IHB1c2g/XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBvcHVsYXRlcyB0aGUgbG9nIGRhdGFcbiAgICAgICAgICovXG4gICAgICAgIHBvcHVsYXRlRGF0YTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGRhdGEgPSB7fTtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHRoaXMuc2Vzc2lvbnMpLmZvckVhY2goZnVuY3Rpb24gKHNpZCkge1xuICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5zZXNzaW9uc1tzaWRdO1xuICAgICAgICAgICAgICAgIGlmIChzZXNzaW9uLnBlZXJjb25uZWN0aW9uICYmIHNlc3Npb24ucGVlcmNvbm5lY3Rpb24udXBkYXRlTG9nKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBzaG91bGQgcHJvYmFibHkgYmUgYSAuZHVtcCBjYWxsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFbXCJqaW5nbGVfXCIgKyBzZXNzaW9uLnNpZF0gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVMb2c6IHNlc3Npb24ucGVlcmNvbm5lY3Rpb24udXBkYXRlTG9nLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHM6IHNlc3Npb24ucGVlcmNvbm5lY3Rpb24uc3RhdHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB1cmw6IHdpbmRvdy5sb2NhdGlvbi5ocmVmXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gZGF0YTtcbiAgICAgICAgfVxuICAgIH0pO1xufTtcblxuIiwiLyogZ2xvYmFsIFN0cm9waGUgKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKCkge1xuXG4gICAgU3Ryb3BoZS5hZGRDb25uZWN0aW9uUGx1Z2luKCdsb2dnZXInLCB7XG4gICAgICAgIC8vIGxvZ3MgcmF3IHN0YW56YXMgYW5kIG1ha2VzIHRoZW0gYXZhaWxhYmxlIGZvciBkb3dubG9hZCBhcyBKU09OXG4gICAgICAgIGNvbm5lY3Rpb246IG51bGwsXG4gICAgICAgIGxvZzogW10sXG4gICAgICAgIGluaXQ6IGZ1bmN0aW9uIChjb25uKSB7XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24gPSBjb25uO1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnJhd0lucHV0ID0gdGhpcy5sb2dfaW5jb21pbmcuYmluZCh0aGlzKTtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5yYXdPdXRwdXQgPSB0aGlzLmxvZ19vdXRnb2luZy5iaW5kKHRoaXMpO1xuICAgICAgICB9LFxuICAgICAgICBsb2dfaW5jb21pbmc6IGZ1bmN0aW9uIChzdGFuemEpIHtcbiAgICAgICAgICAgIHRoaXMubG9nLnB1c2goW25ldyBEYXRlKCkuZ2V0VGltZSgpLCAnaW5jb21pbmcnLCBzdGFuemFdKTtcbiAgICAgICAgfSxcbiAgICAgICAgbG9nX291dGdvaW5nOiBmdW5jdGlvbiAoc3RhbnphKSB7XG4gICAgICAgICAgICB0aGlzLmxvZy5wdXNoKFtuZXcgRGF0ZSgpLmdldFRpbWUoKSwgJ291dGdvaW5nJywgc3RhbnphXSk7XG4gICAgICAgIH1cbiAgICB9KTtcbn07IiwiLyogZ2xvYmFsICQsICRpcSwgY29uZmlnLCBjb25uZWN0aW9uLCBmb2N1c011Y0ppZCwgZm9yY2VNdXRlZCxcbiAgIHNldEF1ZGlvTXV0ZWQsIFN0cm9waGUgKi9cbi8qKlxuICogTW9kZXJhdGUgY29ubmVjdGlvbiBwbHVnaW4uXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKFhNUFApIHtcbiAgICBTdHJvcGhlLmFkZENvbm5lY3Rpb25QbHVnaW4oJ21vZGVyYXRlJywge1xuICAgICAgICBjb25uZWN0aW9uOiBudWxsLFxuICAgICAgICBpbml0OiBmdW5jdGlvbiAoY29ubikge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gY29ubjtcblxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmFkZEhhbmRsZXIodGhpcy5vbk11dGUuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L2F1ZGlvJyxcbiAgICAgICAgICAgICAgICAnaXEnLFxuICAgICAgICAgICAgICAgICdzZXQnLFxuICAgICAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICAgICAgbnVsbCk7XG4gICAgICAgIH0sXG4gICAgICAgIHNldE11dGU6IGZ1bmN0aW9uIChqaWQsIG11dGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcInNldCBtdXRlXCIsIG11dGUpO1xuICAgICAgICAgICAgdmFyIGlxVG9Gb2N1cyA9ICRpcSh7dG86IHRoaXMuY29ubmVjdGlvbi5lbXVjLmZvY3VzTXVjSmlkLCB0eXBlOiAnc2V0J30pXG4gICAgICAgICAgICAgICAgLmMoJ211dGUnLCB7XG4gICAgICAgICAgICAgICAgICAgIHhtbG5zOiAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L2F1ZGlvJyxcbiAgICAgICAgICAgICAgICAgICAgamlkOiBqaWRcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC50KG11dGUudG9TdHJpbmcoKSlcbiAgICAgICAgICAgICAgICAudXAoKTtcblxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmRJUShcbiAgICAgICAgICAgICAgICBpcVRvRm9jdXMsXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnc2V0IG11dGUnLCByZXN1bHQpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzZXQgbXV0ZSBlcnJvcicsIGVycm9yKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgb25NdXRlOiBmdW5jdGlvbiAoaXEpIHtcbiAgICAgICAgICAgIHZhciBmcm9tID0gaXEuZ2V0QXR0cmlidXRlKCdmcm9tJyk7XG4gICAgICAgICAgICBpZiAoZnJvbSAhPT0gdGhpcy5jb25uZWN0aW9uLmVtdWMuZm9jdXNNdWNKaWQpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCJJZ25vcmVkIG11dGUgZnJvbSBub24gZm9jdXMgcGVlclwiKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgbXV0ZSA9ICQoaXEpLmZpbmQoJ211dGUnKTtcbiAgICAgICAgICAgIGlmIChtdXRlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBkb011dGVBdWRpbyA9IG11dGUudGV4dCgpID09PSBcInRydWVcIjtcbiAgICAgICAgICAgICAgICBBUFAuVUkuc2V0QXVkaW9NdXRlZChkb011dGVBdWRpbyk7XG4gICAgICAgICAgICAgICAgWE1QUC5mb3JjZU11dGVkID0gZG9NdXRlQXVkaW87XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgZWplY3Q6IGZ1bmN0aW9uIChqaWQpIHtcbiAgICAgICAgICAgIC8vIFdlJ3JlIG5vdCB0aGUgZm9jdXMsIHNvIGNhbid0IHRlcm1pbmF0ZVxuICAgICAgICAgICAgLy9jb25uZWN0aW9uLmppbmdsZS50ZXJtaW5hdGVSZW1vdGVCeUppZChqaWQsICdraWNrJyk7XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZW11Yy5raWNrKGppZCk7XG4gICAgICAgIH1cbiAgICB9KTtcbn0iLCIvKiBqc2hpbnQgLVcxMTcgKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oKSB7XG4gICAgU3Ryb3BoZS5hZGRDb25uZWN0aW9uUGx1Z2luKCdyYXlvJyxcbiAgICAgICAge1xuICAgICAgICAgICAgUkFZT19YTUxOUzogJ3Vybjp4bXBwOnJheW86MScsXG4gICAgICAgICAgICBjb25uZWN0aW9uOiBudWxsLFxuICAgICAgICAgICAgaW5pdDogZnVuY3Rpb24gKGNvbm4pIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24gPSBjb25uO1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbm5lY3Rpb24uZGlzY28pIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3Vybjp4bXBwOnJheW86Y2xpZW50OjEnKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uYWRkSGFuZGxlcihcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vblJheW8uYmluZCh0aGlzKSwgdGhpcy5SQVlPX1hNTE5TLCAnaXEnLCAnc2V0JywgbnVsbCwgbnVsbCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25SYXlvOiBmdW5jdGlvbiAoaXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXCJSYXlvIElRXCIsIGlxKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkaWFsOiBmdW5jdGlvbiAodG8sIGZyb20sIHJvb21OYW1lLCByb29tUGFzcykge1xuICAgICAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICAgICAgICB2YXIgcmVxID0gJGlxKFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnc2V0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvOiB0aGlzLmNvbm5lY3Rpb24uZW11Yy5mb2N1c011Y0ppZFxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICByZXEuYygnZGlhbCcsXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHhtbG5zOiB0aGlzLlJBWU9fWE1MTlMsXG4gICAgICAgICAgICAgICAgICAgICAgICB0bzogdG8sXG4gICAgICAgICAgICAgICAgICAgICAgICBmcm9tOiBmcm9tXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJlcS5jKCdoZWFkZXInLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiAnSnZiUm9vbU5hbWUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHJvb21OYW1lXG4gICAgICAgICAgICAgICAgICAgIH0pLnVwKCk7XG5cbiAgICAgICAgICAgICAgICBpZiAocm9vbVBhc3MgIT09IG51bGwgJiYgcm9vbVBhc3MubGVuZ3RoKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgcmVxLmMoJ2hlYWRlcicsXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogJ0p2YlJvb21QYXNzd29yZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHJvb21QYXNzXG4gICAgICAgICAgICAgICAgICAgICAgICB9KS51cCgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kSVEoXG4gICAgICAgICAgICAgICAgICAgIHJlcSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdEaWFsIHJlc3VsdCAnLCByZXN1bHQpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzb3VyY2UgPSAkKHJlc3VsdCkuZmluZCgncmVmJykuYXR0cigndXJpJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNhbGxfcmVzb3VyY2UgPSByZXNvdXJjZS5zdWJzdHIoJ3htcHA6Jy5sZW5ndGgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlJlY2VpdmVkIGNhbGwgcmVzb3VyY2U6IFwiICsgdGhpcy5jYWxsX3Jlc291cmNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oJ0RpYWwgZXJyb3IgJywgZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBoYW5nX3VwOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNhbGxfcmVzb3VyY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiTm8gY2FsbCBpbiBwcm9ncmVzc1wiKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICAgICAgICB2YXIgcmVxID0gJGlxKFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnc2V0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvOiB0aGlzLmNhbGxfcmVzb3VyY2VcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgcmVxLmMoJ2hhbmd1cCcsXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHhtbG5zOiB0aGlzLlJBWU9fWE1MTlNcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKFxuICAgICAgICAgICAgICAgICAgICByZXEsXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbygnSGFuZ3VwIHJlc3VsdCAnLCByZXN1bHQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5jYWxsX3Jlc291cmNlID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oJ0hhbmd1cCBlcnJvciAnLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNhbGxfcmVzb3VyY2UgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICk7XG59O1xuIiwiLyoqXG4gKiBTdHJvcGhlIGxvZ2dlciBpbXBsZW1lbnRhdGlvbi4gTG9ncyBmcm9tIGxldmVsIFdBUk4gYW5kIGFib3ZlLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICgpIHtcblxuICAgIFN0cm9waGUubG9nID0gZnVuY3Rpb24gKGxldmVsLCBtc2cpIHtcbiAgICAgICAgc3dpdGNoIChsZXZlbCkge1xuICAgICAgICAgICAgY2FzZSBTdHJvcGhlLkxvZ0xldmVsLldBUk46XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiU3Ryb3BoZTogXCIgKyBtc2cpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBTdHJvcGhlLkxvZ0xldmVsLkVSUk9SOlxuICAgICAgICAgICAgY2FzZSBTdHJvcGhlLkxvZ0xldmVsLkZBVEFMOlxuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJTdHJvcGhlOiBcIiArIG1zZyk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgU3Ryb3BoZS5nZXRTdGF0dXNTdHJpbmcgPSBmdW5jdGlvbiAoc3RhdHVzKSB7XG4gICAgICAgIHN3aXRjaCAoc3RhdHVzKSB7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuU3RhdHVzLkVSUk9SOlxuICAgICAgICAgICAgICAgIHJldHVybiBcIkVSUk9SXCI7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuU3RhdHVzLkNPTk5FQ1RJTkc6XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiQ09OTkVDVElOR1wiO1xuICAgICAgICAgICAgY2FzZSBTdHJvcGhlLlN0YXR1cy5DT05ORkFJTDpcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJDT05ORkFJTFwiO1xuICAgICAgICAgICAgY2FzZSBTdHJvcGhlLlN0YXR1cy5BVVRIRU5USUNBVElORzpcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJBVVRIRU5USUNBVElOR1wiO1xuICAgICAgICAgICAgY2FzZSBTdHJvcGhlLlN0YXR1cy5BVVRIRkFJTDpcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJBVVRIRkFJTFwiO1xuICAgICAgICAgICAgY2FzZSBTdHJvcGhlLlN0YXR1cy5DT05ORUNURUQ6XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiQ09OTkVDVEVEXCI7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuU3RhdHVzLkRJU0NPTk5FQ1RFRDpcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJESVNDT05ORUNURURcIjtcbiAgICAgICAgICAgIGNhc2UgU3Ryb3BoZS5TdGF0dXMuRElTQ09OTkVDVElORzpcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJESVNDT05ORUNUSU5HXCI7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuU3RhdHVzLkFUVEFDSEVEOlxuICAgICAgICAgICAgICAgIHJldHVybiBcIkFUVEFDSEVEXCI7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHJldHVybiBcInVua25vd25cIjtcbiAgICAgICAgfVxuICAgIH07XG59O1xuIiwiLyogZ2xvYmFsICQsIEFQUCwgY29uZmlnLCBTdHJvcGhlKi9cbnZhciBNb2RlcmF0b3IgPSByZXF1aXJlKFwiLi9tb2RlcmF0b3JcIik7XG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcImV2ZW50c1wiKTtcbnZhciBSZWNvcmRpbmcgPSByZXF1aXJlKFwiLi9yZWNvcmRpbmdcIik7XG52YXIgU0RQID0gcmVxdWlyZShcIi4vU0RQXCIpO1xudmFyIFNldHRpbmdzID0gcmVxdWlyZShcIi4uL3NldHRpbmdzL1NldHRpbmdzXCIpO1xudmFyIFBha28gPSByZXF1aXJlKFwicGFrb1wiKTtcbnZhciBTdHJlYW1FdmVudFR5cGVzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL1N0cmVhbUV2ZW50VHlwZXNcIik7XG52YXIgUlRDRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL1JUQ0V2ZW50c1wiKTtcbnZhciBVSUV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1VJL1VJRXZlbnRzXCIpO1xudmFyIFhNUFBFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS94bXBwL1hNUFBFdmVudHNcIik7XG5cbnZhciBldmVudEVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG52YXIgY29ubmVjdGlvbiA9IG51bGw7XG52YXIgYXV0aGVudGljYXRlZFVzZXIgPSBmYWxzZTtcblxuZnVuY3Rpb24gY29ubmVjdChqaWQsIHBhc3N3b3JkKSB7XG4gICAgY29ubmVjdGlvbiA9IFhNUFAuY3JlYXRlQ29ubmVjdGlvbigpO1xuICAgIE1vZGVyYXRvci5zZXRDb25uZWN0aW9uKGNvbm5lY3Rpb24pO1xuXG4gICAgaWYgKGNvbm5lY3Rpb24uZGlzY28pIHtcbiAgICAgICAgLy8gZm9yIGNocm9tZSwgYWRkIG11bHRpc3RyZWFtIGNhcFxuICAgIH1cbiAgICBjb25uZWN0aW9uLmppbmdsZS5wY19jb25zdHJhaW50cyA9IEFQUC5SVEMuZ2V0UENDb25zdHJhaW50cygpO1xuICAgIGlmIChjb25maWcudXNlSVB2Nikge1xuICAgICAgICAvLyBodHRwczovL2NvZGUuZ29vZ2xlLmNvbS9wL3dlYnJ0Yy9pc3N1ZXMvZGV0YWlsP2lkPTI4MjhcbiAgICAgICAgaWYgKCFjb25uZWN0aW9uLmppbmdsZS5wY19jb25zdHJhaW50cy5vcHRpb25hbClcbiAgICAgICAgICAgIGNvbm5lY3Rpb24uamluZ2xlLnBjX2NvbnN0cmFpbnRzLm9wdGlvbmFsID0gW107XG4gICAgICAgIGNvbm5lY3Rpb24uamluZ2xlLnBjX2NvbnN0cmFpbnRzLm9wdGlvbmFsLnB1c2goe2dvb2dJUHY2OiB0cnVlfSk7XG4gICAgfVxuXG4gICAgLy8gSW5jbHVkZSB1c2VyIGluZm8gaW4gTVVDIHByZXNlbmNlXG4gICAgdmFyIHNldHRpbmdzID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbiAgICBpZiAoc2V0dGluZ3MuZW1haWwpIHtcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZEVtYWlsVG9QcmVzZW5jZShzZXR0aW5ncy5lbWFpbCk7XG4gICAgfVxuICAgIGlmIChzZXR0aW5ncy51aWQpIHtcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZFVzZXJJZFRvUHJlc2VuY2Uoc2V0dGluZ3MudWlkKTtcbiAgICB9XG4gICAgaWYgKHNldHRpbmdzLmRpc3BsYXlOYW1lKSB7XG4gICAgICAgIGNvbm5lY3Rpb24uZW11Yy5hZGREaXNwbGF5TmFtZVRvUHJlc2VuY2Uoc2V0dGluZ3MuZGlzcGxheU5hbWUpO1xuICAgIH1cblxuICAgIHZhciBhbm9ueW1vdXNDb25uZWN0aW9uRmFpbGVkID0gZmFsc2U7XG4gICAgY29ubmVjdGlvbi5jb25uZWN0KGppZCwgcGFzc3dvcmQsIGZ1bmN0aW9uIChzdGF0dXMsIG1zZykge1xuICAgICAgICBjb25zb2xlLmxvZygnU3Ryb3BoZSBzdGF0dXMgY2hhbmdlZCB0bycsXG4gICAgICAgICAgICBTdHJvcGhlLmdldFN0YXR1c1N0cmluZyhzdGF0dXMpKTtcbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gU3Ryb3BoZS5TdGF0dXMuQ09OTkVDVEVEKSB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLnVzZVN0dW5UdXJuKSB7XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5qaW5nbGUuZ2V0U3R1bkFuZFR1cm5DcmVkZW50aWFscygpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXCJNeSBKYWJiZXIgSUQ6IFwiICsgY29ubmVjdGlvbi5qaWQpO1xuXG4gICAgICAgICAgICBpZihwYXNzd29yZClcbiAgICAgICAgICAgICAgICBhdXRoZW50aWNhdGVkVXNlciA9IHRydWU7XG4gICAgICAgICAgICBtYXliZURvSm9pbigpO1xuICAgICAgICB9IGVsc2UgaWYgKHN0YXR1cyA9PT0gU3Ryb3BoZS5TdGF0dXMuQ09OTkZBSUwpIHtcbiAgICAgICAgICAgIGlmKG1zZyA9PT0gJ3gtc3Ryb3BoZS1iYWQtbm9uLWFub24tamlkJykge1xuICAgICAgICAgICAgICAgIGFub255bW91c0Nvbm5lY3Rpb25GYWlsZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHN0YXR1cyA9PT0gU3Ryb3BoZS5TdGF0dXMuRElTQ09OTkVDVEVEKSB7XG4gICAgICAgICAgICBpZihhbm9ueW1vdXNDb25uZWN0aW9uRmFpbGVkKSB7XG4gICAgICAgICAgICAgICAgLy8gcHJvbXB0IHVzZXIgZm9yIHVzZXJuYW1lIGFuZCBwYXNzd29yZFxuICAgICAgICAgICAgICAgIFhNUFAucHJvbXB0TG9naW4oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChzdGF0dXMgPT09IFN0cm9waGUuU3RhdHVzLkFVVEhGQUlMKSB7XG4gICAgICAgICAgICAvLyB3cm9uZyBwYXNzd29yZCBvciB1c2VybmFtZSwgcHJvbXB0IHVzZXJcbiAgICAgICAgICAgIFhNUFAucHJvbXB0TG9naW4oKTtcblxuICAgICAgICB9XG4gICAgfSk7XG59XG5cblxuXG5mdW5jdGlvbiBtYXliZURvSm9pbigpIHtcbiAgICBpZiAoY29ubmVjdGlvbiAmJiBjb25uZWN0aW9uLmNvbm5lY3RlZCAmJlxuICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChjb25uZWN0aW9uLmppZClcbiAgICAgICAgJiYgKEFQUC5SVEMubG9jYWxBdWRpbyB8fCBBUFAuUlRDLmxvY2FsVmlkZW8pKSB7XG4gICAgICAgIC8vIC5jb25uZWN0ZWQgaXMgdHJ1ZSB3aGlsZSBjb25uZWN0aW5nP1xuICAgICAgICBkb0pvaW4oKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGRvSm9pbigpIHtcbiAgICB2YXIgcm9vbU5hbWUgPSBBUFAuVUkuZ2VuZXJhdGVSb29tTmFtZSgpO1xuXG4gICAgTW9kZXJhdG9yLmFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzKFxuICAgICAgICByb29tTmFtZSwgQVBQLlVJLmNoZWNrRm9yTmlja25hbWVBbmRKb2luKTtcbn1cblxuZnVuY3Rpb24gaW5pdFN0cm9waGVQbHVnaW5zKClcbntcbiAgICByZXF1aXJlKFwiLi9zdHJvcGhlLmVtdWNcIikoWE1QUCwgZXZlbnRFbWl0dGVyKTtcbiAgICByZXF1aXJlKFwiLi9zdHJvcGhlLmppbmdsZVwiKShYTVBQLCBldmVudEVtaXR0ZXIpO1xuICAgIHJlcXVpcmUoXCIuL3N0cm9waGUubW9kZXJhdGVcIikoWE1QUCk7XG4gICAgcmVxdWlyZShcIi4vc3Ryb3BoZS51dGlsXCIpKCk7XG4gICAgcmVxdWlyZShcIi4vc3Ryb3BoZS5yYXlvXCIpKCk7XG4gICAgcmVxdWlyZShcIi4vc3Ryb3BoZS5sb2dnZXJcIikoKTtcbn1cblxuZnVuY3Rpb24gcmVnaXN0ZXJMaXN0ZW5lcnMoKSB7XG4gICAgQVBQLlJUQy5hZGRTdHJlYW1MaXN0ZW5lcihtYXliZURvSm9pbixcbiAgICAgICAgU3RyZWFtRXZlbnRUeXBlcy5FVkVOVF9UWVBFX0xPQ0FMX0NSRUFURUQpO1xuICAgIEFQUC5SVEMuYWRkTGlzdGVuZXIoUlRDRXZlbnRzLkFWQUlMQUJMRV9ERVZJQ0VTX0NIQU5HRUQsIGZ1bmN0aW9uIChkZXZpY2VzKSB7XG4gICAgICAgIFhNUFAuYWRkVG9QcmVzZW5jZShcImRldmljZXNcIiwgZGV2aWNlcyk7XG4gICAgfSlcbiAgICBBUFAuVUkuYWRkTGlzdGVuZXIoVUlFdmVudHMuTklDS05BTUVfQ0hBTkdFRCwgZnVuY3Rpb24gKG5pY2tuYW1lKSB7XG4gICAgICAgIFhNUFAuYWRkVG9QcmVzZW5jZShcImRpc3BsYXlOYW1lXCIsIG5pY2tuYW1lKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gc2V0dXBFdmVudHMoKSB7XG4gICAgJCh3aW5kb3cpLmJpbmQoJ2JlZm9yZXVubG9hZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKGNvbm5lY3Rpb24gJiYgY29ubmVjdGlvbi5jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIC8vIGVuc3VyZSBzaWdub3V0XG4gICAgICAgICAgICAkLmFqYXgoe1xuICAgICAgICAgICAgICAgIHR5cGU6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICB1cmw6IGNvbmZpZy5ib3NoLFxuICAgICAgICAgICAgICAgIGFzeW5jOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBjYWNoZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi94bWwnLFxuICAgICAgICAgICAgICAgIGRhdGE6IFwiPGJvZHkgcmlkPSdcIiArIChjb25uZWN0aW9uLnJpZCB8fCBjb25uZWN0aW9uLl9wcm90by5yaWQpXG4gICAgICAgICAgICAgICAgICAgICsgXCInIHhtbG5zPSdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9odHRwYmluZCcgc2lkPSdcIlxuICAgICAgICAgICAgICAgICAgICArIChjb25uZWN0aW9uLnNpZCB8fCBjb25uZWN0aW9uLl9wcm90by5zaWQpXG4gICAgICAgICAgICAgICAgICAgICsgXCInIHR5cGU9J3Rlcm1pbmF0ZSc+XCIgK1xuICAgICAgICAgICAgICAgICAgICBcIjxwcmVzZW5jZSB4bWxucz0namFiYmVyOmNsaWVudCcgdHlwZT0ndW5hdmFpbGFibGUnLz5cIiArXG4gICAgICAgICAgICAgICAgICAgIFwiPC9ib2R5PlwiLFxuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzaWduZWQgb3V0Jyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uIChYTUxIdHRwUmVxdWVzdCwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24pIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3NpZ25vdXQgZXJyb3InLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHRTdGF0dXMgKyAnICgnICsgZXJyb3JUaHJvd24gKyAnKScpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIFhNUFAuZGlzcG9zZUNvbmZlcmVuY2UodHJ1ZSk7XG4gICAgfSk7XG59XG5cbnZhciBYTVBQID0ge1xuICAgIHNlc3Npb25UZXJtaW5hdGVkOiBmYWxzZSxcblxuICAgIC8qKlxuICAgICAqIFhNUFAgY29ubmVjdGlvbiBzdGF0dXNcbiAgICAgKi9cbiAgICBTdGF0dXM6IFN0cm9waGUuU3RhdHVzLFxuXG4gICAgLyoqXG4gICAgICogUmVtZW1iZXJzIGlmIHdlIHdlcmUgbXV0ZWQgYnkgdGhlIGZvY3VzLlxuICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAqL1xuICAgIGZvcmNlTXV0ZWQ6IGZhbHNlLFxuICAgIHN0YXJ0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNldHVwRXZlbnRzKCk7XG4gICAgICAgIGluaXRTdHJvcGhlUGx1Z2lucygpO1xuICAgICAgICByZWdpc3Rlckxpc3RlbmVycygpO1xuICAgICAgICBNb2RlcmF0b3IuaW5pdCh0aGlzLCBldmVudEVtaXR0ZXIpO1xuICAgICAgICB2YXIgY29uZmlnRG9tYWluID0gY29uZmlnLmhvc3RzLmFub255bW91c2RvbWFpbiB8fCBjb25maWcuaG9zdHMuZG9tYWluO1xuICAgICAgICAvLyBGb3JjZSBhdXRoZW50aWNhdGVkIGRvbWFpbiBpZiByb29tIGlzIGFwcGVuZGVkIHdpdGggJz9sb2dpbj10cnVlJ1xuICAgICAgICBpZiAoY29uZmlnLmhvc3RzLmFub255bW91c2RvbWFpbiAmJlxuICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLnNlYXJjaC5pbmRleE9mKFwibG9naW49dHJ1ZVwiKSAhPT0gLTEpIHtcbiAgICAgICAgICAgIGNvbmZpZ0RvbWFpbiA9IGNvbmZpZy5ob3N0cy5kb21haW47XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGppZCA9IGNvbmZpZ0RvbWFpbiB8fCB3aW5kb3cubG9jYXRpb24uaG9zdG5hbWU7XG4gICAgICAgIGNvbm5lY3QoamlkLCBudWxsKTtcbiAgICB9LFxuICAgIGNyZWF0ZUNvbm5lY3Rpb246IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGJvc2ggPSBjb25maWcuYm9zaCB8fCAnL2h0dHAtYmluZCc7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBTdHJvcGhlLkNvbm5lY3Rpb24oYm9zaCk7XG4gICAgfSxcbiAgICBnZXRTdGF0dXNTdHJpbmc6IGZ1bmN0aW9uIChzdGF0dXMpIHtcbiAgICAgICAgcmV0dXJuIFN0cm9waGUuZ2V0U3RhdHVzU3RyaW5nKHN0YXR1cyk7XG4gICAgfSxcbiAgICBwcm9tcHRMb2dpbjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBGSVhNRTogcmUtdXNlIExvZ2luRGlhbG9nIHdoaWNoIHN1cHBvcnRzIHJldHJpZXNcbiAgICAgICAgQVBQLlVJLnNob3dMb2dpblBvcHVwKGNvbm5lY3QpO1xuICAgIH0sXG4gICAgam9pblJvb206IGZ1bmN0aW9uKHJvb21OYW1lLCB1c2VOaWNrcywgbmljaylcbiAgICB7XG4gICAgICAgIHZhciByb29tamlkO1xuICAgICAgICByb29tamlkID0gcm9vbU5hbWU7XG5cbiAgICAgICAgaWYgKHVzZU5pY2tzKSB7XG4gICAgICAgICAgICBpZiAobmljaykge1xuICAgICAgICAgICAgICAgIHJvb21qaWQgKz0gJy8nICsgbmljaztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcm9vbWppZCArPSAnLycgKyBTdHJvcGhlLmdldE5vZGVGcm9tSmlkKGNvbm5lY3Rpb24uamlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgdmFyIHRtcEppZCA9IFN0cm9waGUuZ2V0Tm9kZUZyb21KaWQoY29ubmVjdGlvbi5qaWQpO1xuXG4gICAgICAgICAgICBpZighYXV0aGVudGljYXRlZFVzZXIpXG4gICAgICAgICAgICAgICAgdG1wSmlkID0gdG1wSmlkLnN1YnN0cigwLCA4KTtcblxuICAgICAgICAgICAgcm9vbWppZCArPSAnLycgKyB0bXBKaWQ7XG4gICAgICAgIH1cbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLmRvSm9pbihyb29tamlkKTtcbiAgICB9LFxuICAgIG15SmlkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmKCFjb25uZWN0aW9uKVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uLmVtdWMubXlyb29tamlkO1xuICAgIH0sXG4gICAgbXlSZXNvdXJjZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZighY29ubmVjdGlvbiB8fCAhIGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgcmV0dXJuIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpO1xuICAgIH0sXG4gICAgZGlzcG9zZUNvbmZlcmVuY2U6IGZ1bmN0aW9uIChvblVubG9hZCkge1xuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkRJU1BPU0VfQ09ORkVSRU5DRSwgb25VbmxvYWQpO1xuICAgICAgICB2YXIgaGFuZGxlciA9IGNvbm5lY3Rpb24uamluZ2xlLmFjdGl2ZWNhbGw7XG4gICAgICAgIGlmIChoYW5kbGVyICYmIGhhbmRsZXIucGVlcmNvbm5lY3Rpb24pIHtcbiAgICAgICAgICAgIC8vIEZJWE1FOiBwcm9iYWJseSByZW1vdmluZyBzdHJlYW1zIGlzIG5vdCByZXF1aXJlZCBhbmQgY2xvc2UoKSBzaG91bGRcbiAgICAgICAgICAgIC8vIGJlIGVub3VnaFxuICAgICAgICAgICAgaWYgKEFQUC5SVEMubG9jYWxBdWRpbykge1xuICAgICAgICAgICAgICAgIGhhbmRsZXIucGVlcmNvbm5lY3Rpb24ucmVtb3ZlU3RyZWFtKFxuICAgICAgICAgICAgICAgICAgICBBUFAuUlRDLmxvY2FsQXVkaW8uZ2V0T3JpZ2luYWxTdHJlYW0oKSwgb25VbmxvYWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKEFQUC5SVEMubG9jYWxWaWRlbykge1xuICAgICAgICAgICAgICAgIGhhbmRsZXIucGVlcmNvbm5lY3Rpb24ucmVtb3ZlU3RyZWFtKFxuICAgICAgICAgICAgICAgICAgICBBUFAuUlRDLmxvY2FsVmlkZW8uZ2V0T3JpZ2luYWxTdHJlYW0oKSwgb25VbmxvYWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaGFuZGxlci5wZWVyY29ubmVjdGlvbi5jbG9zZSgpO1xuICAgICAgICB9XG4gICAgICAgIGNvbm5lY3Rpb24uamluZ2xlLmFjdGl2ZWNhbGwgPSBudWxsO1xuICAgICAgICBpZighb25VbmxvYWQpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvblRlcm1pbmF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmRvTGVhdmUoKTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgYWRkTGlzdGVuZXI6IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKVxuICAgIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLm9uKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9LFxuICAgIHJlbW92ZUxpc3RlbmVyOiBmdW5jdGlvbiAodHlwZSwgbGlzdGVuZXIpIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9LFxuICAgIGFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzOiBmdW5jdGlvbihyb29tTmFtZSwgY2FsbGJhY2spIHtcbiAgICAgICAgTW9kZXJhdG9yLmFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzKHJvb21OYW1lLCBjYWxsYmFjayk7XG4gICAgfSxcbiAgICBnZXRMb2dpblVybDogZnVuY3Rpb24gKHJvb21OYW1lLCBjYWxsYmFjaykge1xuICAgICAgICBNb2RlcmF0b3IuZ2V0TG9naW5Vcmwocm9vbU5hbWUsIGNhbGxiYWNrKTtcbiAgICB9LFxuICAgIGdldFBvcHVwTG9naW5Vcmw6IGZ1bmN0aW9uIChyb29tTmFtZSwgY2FsbGJhY2spIHtcbiAgICAgICAgTW9kZXJhdG9yLmdldFBvcHVwTG9naW5Vcmwocm9vbU5hbWUsIGNhbGxiYWNrKTtcbiAgICB9LFxuICAgIGlzTW9kZXJhdG9yOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBNb2RlcmF0b3IuaXNNb2RlcmF0b3IoKTtcbiAgICB9LFxuICAgIGlzU2lwR2F0ZXdheUVuYWJsZWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIE1vZGVyYXRvci5pc1NpcEdhdGV3YXlFbmFibGVkKCk7XG4gICAgfSxcbiAgICBpc0V4dGVybmFsQXV0aEVuYWJsZWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIE1vZGVyYXRvci5pc0V4dGVybmFsQXV0aEVuYWJsZWQoKTtcbiAgICB9LFxuICAgIHN3aXRjaFN0cmVhbXM6IGZ1bmN0aW9uIChzdHJlYW0sIG9sZFN0cmVhbSwgY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKGNvbm5lY3Rpb24gJiYgY29ubmVjdGlvbi5qaW5nbGUuYWN0aXZlY2FsbCkge1xuICAgICAgICAgICAgLy8gRklYTUU6IHdpbGwgYmxvY2sgc3dpdGNoSW5Qcm9ncmVzcyBvbiB0cnVlIHZhbHVlIGluIGNhc2Ugb2YgZXhjZXB0aW9uXG4gICAgICAgICAgICBjb25uZWN0aW9uLmppbmdsZS5hY3RpdmVjYWxsLnN3aXRjaFN0cmVhbXMoc3RyZWFtLCBvbGRTdHJlYW0sIGNhbGxiYWNrKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIFdlIGFyZSBkb25lIGltbWVkaWF0ZWx5XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJObyBjb25mZXJlbmNlIGhhbmRsZXIgb3IgY29uZmVyZW5jZSBub3Qgc3RhcnRlZCB5ZXRcIik7XG4gICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzZW5kVmlkZW9JbmZvUHJlc2VuY2U6IGZ1bmN0aW9uIChtdXRlKSB7XG4gICAgICAgIGNvbm5lY3Rpb24uZW11Yy5hZGRWaWRlb0luZm9Ub1ByZXNlbmNlKG11dGUpO1xuICAgICAgICBjb25uZWN0aW9uLmVtdWMuc2VuZFByZXNlbmNlKCk7XG4gICAgfSxcbiAgICBzZXRWaWRlb011dGU6IGZ1bmN0aW9uIChtdXRlLCBjYWxsYmFjaywgb3B0aW9ucykge1xuICAgICAgICBpZighY29ubmVjdGlvbilcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB2YXIgbG9jYWxDYWxsYmFjayA9IGZ1bmN0aW9uIChtdXRlKSB7XG4gICAgICAgICAgICBzZWxmLnNlbmRWaWRlb0luZm9QcmVzZW5jZShtdXRlKTtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhtdXRlKTtcbiAgICAgICAgfTtcblxuICAgICAgICBpZihjb25uZWN0aW9uLmppbmdsZS5hY3RpdmVjYWxsKVxuICAgICAgICB7XG4gICAgICAgICAgICBjb25uZWN0aW9uLmppbmdsZS5hY3RpdmVjYWxsLnNldFZpZGVvTXV0ZShcbiAgICAgICAgICAgICAgICBtdXRlLCBsb2NhbENhbGxiYWNrLCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxvY2FsQ2FsbGJhY2sobXV0ZSk7XG4gICAgICAgIH1cblxuICAgIH0sXG4gICAgc2V0QXVkaW9NdXRlOiBmdW5jdGlvbiAobXV0ZSwgY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKCEoY29ubmVjdGlvbiAmJiBBUFAuUlRDLmxvY2FsQXVkaW8pKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuXG4gICAgICAgIGlmICh0aGlzLmZvcmNlTXV0ZWQgJiYgIW11dGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkFza2luZyBmb2N1cyBmb3IgdW5tdXRlXCIpO1xuICAgICAgICAgICAgY29ubmVjdGlvbi5tb2RlcmF0ZS5zZXRNdXRlKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQsIG11dGUpO1xuICAgICAgICAgICAgLy8gRklYTUU6IHdhaXQgZm9yIHJlc3VsdCBiZWZvcmUgcmVzZXR0aW5nIG11dGVkIHN0YXR1c1xuICAgICAgICAgICAgdGhpcy5mb3JjZU11dGVkID0gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobXV0ZSA9PSBBUFAuUlRDLmxvY2FsQXVkaW8uaXNNdXRlZCgpKSB7XG4gICAgICAgICAgICAvLyBOb3RoaW5nIHRvIGRvXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEl0IGlzIG5vdCBjbGVhciB3aGF0IGlzIHRoZSByaWdodCB3YXkgdG8gaGFuZGxlIG11bHRpcGxlIHRyYWNrcy5cbiAgICAgICAgLy8gU28gYXQgbGVhc3QgbWFrZSBzdXJlIHRoYXQgdGhleSBhcmUgYWxsIG11dGVkIG9yIGFsbCB1bm11dGVkIGFuZFxuICAgICAgICAvLyB0aGF0IHdlIHNlbmQgcHJlc2VuY2UganVzdCBvbmNlLlxuICAgICAgICBBUFAuUlRDLmxvY2FsQXVkaW8ubXV0ZSgpO1xuICAgICAgICAvLyBpc011dGVkIGlzIHRoZSBvcHBvc2l0ZSBvZiBhdWRpb0VuYWJsZWRcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZEF1ZGlvSW5mb1RvUHJlc2VuY2UobXV0ZSk7XG4gICAgICAgIGNvbm5lY3Rpb24uZW11Yy5zZW5kUHJlc2VuY2UoKTtcbiAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSxcbiAgICAvLyBSZWFsbHkgbXV0ZSB2aWRlbywgaS5lLiBkb250IGV2ZW4gc2VuZCBibGFjayBmcmFtZXNcbiAgICBtdXRlVmlkZW86IGZ1bmN0aW9uIChwYywgdW5tdXRlKSB7XG4gICAgICAgIC8vIEZJWE1FOiB0aGlzIHByb2JhYmx5IG5lZWRzIGFub3RoZXIgb2YgdGhvc2UgbG92ZWx5IHN0YXRlIHNhZmVndWFyZHMuLi5cbiAgICAgICAgLy8gd2hpY2ggY2hlY2tzIGZvciBpY2Vjb25uID09IGNvbm5lY3RlZCBhbmQgc2lnc3RhdGUgPT0gc3RhYmxlXG4gICAgICAgIHBjLnNldFJlbW90ZURlc2NyaXB0aW9uKHBjLnJlbW90ZURlc2NyaXB0aW9uLFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHBjLmNyZWF0ZUFuc3dlcihcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGFuc3dlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHNkcCA9IG5ldyBTRFAoYW5zd2VyLnNkcCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2RwLm1lZGlhLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodW5tdXRlKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZHAubWVkaWFbMV0gPSBzZHAubWVkaWFbMV0ucmVwbGFjZSgnYT1yZWN2b25seScsICdhPXNlbmRyZWN2Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZHAubWVkaWFbMV0gPSBzZHAubWVkaWFbMV0ucmVwbGFjZSgnYT1zZW5kcmVjdicsICdhPXJlY3Zvbmx5Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2RwLnJhdyA9IHNkcC5zZXNzaW9uICsgc2RwLm1lZGlhLmpvaW4oJycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuc3dlci5zZHAgPSBzZHAucmF3O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgcGMuc2V0TG9jYWxEZXNjcmlwdGlvbihhbnN3ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnbXV0ZSBTTEQgb2snKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnbXV0ZSBTTEQgZXJyb3InKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcihcImRpYWxvZy5lcnJvclwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJkaWFsb2cuU0xERmFpbHVyZVwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIEFQUC5VSS5tZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ211dGVWaWRlbyBTUkQgZXJyb3InKTtcbiAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKFwiZGlhbG9nLmVycm9yXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiZGlhbG9nLlNSREZhaWx1cmVcIik7XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9LFxuICAgIHRvZ2dsZVJlY29yZGluZzogZnVuY3Rpb24gKHRva2VuRW1wdHlDYWxsYmFjayxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydGluZ0NhbGxiYWNrLCBzdGFydGVkQ2FsbGJhY2spIHtcbiAgICAgICAgUmVjb3JkaW5nLnRvZ2dsZVJlY29yZGluZyh0b2tlbkVtcHR5Q2FsbGJhY2ssXG4gICAgICAgICAgICBzdGFydGluZ0NhbGxiYWNrLCBzdGFydGVkQ2FsbGJhY2ssIGNvbm5lY3Rpb24pO1xuICAgIH0sXG4gICAgYWRkVG9QcmVzZW5jZTogZnVuY3Rpb24gKG5hbWUsIHZhbHVlLCBkb250U2VuZCkge1xuICAgICAgICBzd2l0Y2ggKG5hbWUpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNhc2UgXCJkaXNwbGF5TmFtZVwiOlxuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uZW11Yy5hZGREaXNwbGF5TmFtZVRvUHJlc2VuY2UodmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcImV0aGVycGFkXCI6XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZEV0aGVycGFkVG9QcmVzZW5jZSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwicHJlemlcIjpcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuYWRkUHJlemlUb1ByZXNlbmNlKHZhbHVlLCAwKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJwcmV6aVNsaWRlXCI6XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZEN1cnJlbnRTbGlkZVRvUHJlc2VuY2UodmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcImNvbm5lY3Rpb25RdWFsaXR5XCI6XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZENvbm5lY3Rpb25JbmZvVG9QcmVzZW5jZSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiZW1haWxcIjpcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuYWRkRW1haWxUb1ByZXNlbmNlKHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJkZXZpY2VzXCI6XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZERldmljZXNUb1ByZXNlbmNlKHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGRlZmF1bHQgOlxuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiVW5rbm93biB0YWcgZm9yIHByZXNlbmNlOiBcIiArIG5hbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRvbnRTZW5kKVxuICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLnNlbmRQcmVzZW5jZSgpO1xuICAgIH0sXG4gICAgLyoqXG4gICAgICogU2VuZHMgJ2RhdGEnIGFzIGEgbG9nIG1lc3NhZ2UgdG8gdGhlIGZvY3VzLiBSZXR1cm5zIHRydWUgaWZmIGEgbWVzc2FnZVxuICAgICAqIHdhcyBzZW50LlxuICAgICAqIEBwYXJhbSBkYXRhXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IHRydWUgaWZmIGEgbWVzc2FnZSB3YXMgc2VudC5cbiAgICAgKi9cbiAgICBzZW5kTG9nczogZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgaWYoIWNvbm5lY3Rpb24uZW11Yy5mb2N1c011Y0ppZClcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgICAgICB2YXIgZGVmbGF0ZSA9IHRydWU7XG5cbiAgICAgICAgdmFyIGNvbnRlbnQgPSBKU09OLnN0cmluZ2lmeShkYXRhKTtcbiAgICAgICAgaWYgKGRlZmxhdGUpIHtcbiAgICAgICAgICAgIGNvbnRlbnQgPSBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIFBha28uZGVmbGF0ZVJhdyhjb250ZW50KSk7XG4gICAgICAgIH1cbiAgICAgICAgY29udGVudCA9IEJhc2U2NC5lbmNvZGUoY29udGVudCk7XG4gICAgICAgIC8vIFhFUC0wMzM3LWlzaFxuICAgICAgICB2YXIgbWVzc2FnZSA9ICRtc2coe3RvOiBjb25uZWN0aW9uLmVtdWMuZm9jdXNNdWNKaWQsIHR5cGU6ICdub3JtYWwnfSk7XG4gICAgICAgIG1lc3NhZ2UuYygnbG9nJywgeyB4bWxuczogJ3Vybjp4bXBwOmV2ZW50bG9nJyxcbiAgICAgICAgICAgIGlkOiAnUGVlckNvbm5lY3Rpb25TdGF0cyd9KTtcbiAgICAgICAgbWVzc2FnZS5jKCdtZXNzYWdlJykudChjb250ZW50KS51cCgpO1xuICAgICAgICBpZiAoZGVmbGF0ZSkge1xuICAgICAgICAgICAgbWVzc2FnZS5jKCd0YWcnLCB7bmFtZTogXCJkZWZsYXRlZFwiLCB2YWx1ZTogXCJ0cnVlXCJ9KS51cCgpO1xuICAgICAgICB9XG4gICAgICAgIG1lc3NhZ2UudXAoKTtcblxuICAgICAgICBjb25uZWN0aW9uLnNlbmQobWVzc2FnZSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG4gICAgcG9wdWxhdGVEYXRhOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkYXRhID0ge307XG4gICAgICAgIGlmIChjb25uZWN0aW9uLmppbmdsZSkge1xuICAgICAgICAgICAgZGF0YSA9IGNvbm5lY3Rpb24uamluZ2xlLnBvcHVsYXRlRGF0YSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH0sXG4gICAgZ2V0TG9nZ2VyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmKGNvbm5lY3Rpb24ubG9nZ2VyKVxuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3Rpb24ubG9nZ2VyLmxvZztcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSxcbiAgICBnZXRQcmV6aTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY29ubmVjdGlvbi5lbXVjLmdldFByZXppKHRoaXMubXlKaWQoKSk7XG4gICAgfSxcbiAgICByZW1vdmVQcmV6aUZyb21QcmVzZW5jZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25uZWN0aW9uLmVtdWMucmVtb3ZlUHJlemlGcm9tUHJlc2VuY2UoKTtcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLnNlbmRQcmVzZW5jZSgpO1xuICAgIH0sXG4gICAgc2VuZENoYXRNZXNzYWdlOiBmdW5jdGlvbiAobWVzc2FnZSwgbmlja25hbWUpIHtcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLnNlbmRNZXNzYWdlKG1lc3NhZ2UsIG5pY2tuYW1lKTtcbiAgICB9LFxuICAgIHNldFN1YmplY3Q6IGZ1bmN0aW9uICh0b3BpYykge1xuICAgICAgICBjb25uZWN0aW9uLmVtdWMuc2V0U3ViamVjdCh0b3BpYyk7XG4gICAgfSxcbiAgICBsb2NrUm9vbTogZnVuY3Rpb24gKGtleSwgb25TdWNjZXNzLCBvbkVycm9yLCBvbk5vdFN1cHBvcnRlZCkge1xuICAgICAgICBjb25uZWN0aW9uLmVtdWMubG9ja1Jvb20oa2V5LCBvblN1Y2Nlc3MsIG9uRXJyb3IsIG9uTm90U3VwcG9ydGVkKTtcbiAgICB9LFxuICAgIGRpYWw6IGZ1bmN0aW9uICh0bywgZnJvbSwgcm9vbU5hbWUscm9vbVBhc3MpIHtcbiAgICAgICAgY29ubmVjdGlvbi5yYXlvLmRpYWwodG8sIGZyb20sIHJvb21OYW1lLHJvb21QYXNzKTtcbiAgICB9LFxuICAgIHNldE11dGU6IGZ1bmN0aW9uIChqaWQsIG11dGUpIHtcbiAgICAgICAgY29ubmVjdGlvbi5tb2RlcmF0ZS5zZXRNdXRlKGppZCwgbXV0ZSk7XG4gICAgfSxcbiAgICBlamVjdDogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBjb25uZWN0aW9uLm1vZGVyYXRlLmVqZWN0KGppZCk7XG4gICAgfSxcbiAgICBsb2dvdXQ6IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgICAgICBNb2RlcmF0b3IubG9nb3V0KGNhbGxiYWNrKTtcbiAgICB9LFxuICAgIGZpbmRKaWRGcm9tUmVzb3VyY2U6IGZ1bmN0aW9uIChyZXNvdXJjZSkge1xuICAgICAgICByZXR1cm4gY29ubmVjdGlvbi5lbXVjLmZpbmRKaWRGcm9tUmVzb3VyY2UocmVzb3VyY2UpO1xuICAgIH0sXG4gICAgZ2V0TWVtYmVyczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY29ubmVjdGlvbi5lbXVjLm1lbWJlcnM7XG4gICAgfSxcbiAgICBnZXRKaWRGcm9tU1NSQzogZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgaWYoIWNvbm5lY3Rpb24pXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgcmV0dXJuIGNvbm5lY3Rpb24uZW11Yy5zc3JjMmppZFtzc3JjXTtcbiAgICB9LFxuICAgIGdldE1VQ0pvaW5lZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY29ubmVjdGlvbi5lbXVjLmpvaW5lZDtcbiAgICB9LFxuICAgIGdldFNlc3Npb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uLmppbmdsZS5zZXNzaW9ucztcbiAgICB9LFxuICAgIHJlbW92ZVN0cmVhbTogZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICBpZighY29ubmVjdGlvbiB8fCAhY29ubmVjdGlvbi5qaW5nbGUuYWN0aXZlY2FsbCB8fFxuICAgICAgICAgICAgIWNvbm5lY3Rpb24uamluZ2xlLmFjdGl2ZWNhbGwucGVlcmNvbm5lY3Rpb24pXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIGNvbm5lY3Rpb24uamluZ2xlLmFjdGl2ZWNhbGwucGVlcmNvbm5lY3Rpb24ucmVtb3ZlU3RyZWFtKHN0cmVhbSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBYTVBQO1xuIiwiLy8gaTE4bmV4dCwgdjEuNy43XG4vLyBDb3B5cmlnaHQgKGMpMjAxNCBKYW4gTcO8aGxlbWFubiAoamFtdWhsKS5cbi8vIERpc3RyaWJ1dGVkIHVuZGVyIE1JVCBsaWNlbnNlXG4vLyBodHRwOi8vaTE4bmV4dC5jb21cbihmdW5jdGlvbigpIHtcblxuICAgIC8vIGFkZCBpbmRleE9mIHRvIG5vbiBFQ01BLTI2MiBzdGFuZGFyZCBjb21wbGlhbnQgYnJvd3NlcnNcbiAgICBpZiAoIUFycmF5LnByb3RvdHlwZS5pbmRleE9mKSB7XG4gICAgICAgIEFycmF5LnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gKHNlYXJjaEVsZW1lbnQgLyosIGZyb21JbmRleCAqLyApIHtcbiAgICAgICAgICAgIFwidXNlIHN0cmljdFwiO1xuICAgICAgICAgICAgaWYgKHRoaXMgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciB0ID0gT2JqZWN0KHRoaXMpO1xuICAgICAgICAgICAgdmFyIGxlbiA9IHQubGVuZ3RoID4+PiAwO1xuICAgICAgICAgICAgaWYgKGxlbiA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBuID0gMDtcbiAgICAgICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIG4gPSBOdW1iZXIoYXJndW1lbnRzWzFdKTtcbiAgICAgICAgICAgICAgICBpZiAobiAhPSBuKSB7IC8vIHNob3J0Y3V0IGZvciB2ZXJpZnlpbmcgaWYgaXQncyBOYU5cbiAgICAgICAgICAgICAgICAgICAgbiA9IDA7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChuICE9IDAgJiYgbiAhPSBJbmZpbml0eSAmJiBuICE9IC1JbmZpbml0eSkge1xuICAgICAgICAgICAgICAgICAgICBuID0gKG4gPiAwIHx8IC0xKSAqIE1hdGguZmxvb3IoTWF0aC5hYnMobikpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChuID49IGxlbikge1xuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBrID0gbiA+PSAwID8gbiA6IE1hdGgubWF4KGxlbiAtIE1hdGguYWJzKG4pLCAwKTtcbiAgICAgICAgICAgIGZvciAoOyBrIDwgbGVuOyBrKyspIHtcbiAgICAgICAgICAgICAgICBpZiAoayBpbiB0ICYmIHRba10gPT09IHNlYXJjaEVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIGFkZCBsYXN0SW5kZXhPZiB0byBub24gRUNNQS0yNjIgc3RhbmRhcmQgY29tcGxpYW50IGJyb3dzZXJzXG4gICAgaWYgKCFBcnJheS5wcm90b3R5cGUubGFzdEluZGV4T2YpIHtcbiAgICAgICAgQXJyYXkucHJvdG90eXBlLmxhc3RJbmRleE9mID0gZnVuY3Rpb24oc2VhcmNoRWxlbWVudCAvKiwgZnJvbUluZGV4Ki8pIHtcbiAgICAgICAgICAgIFwidXNlIHN0cmljdFwiO1xuICAgICAgICAgICAgaWYgKHRoaXMgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciB0ID0gT2JqZWN0KHRoaXMpO1xuICAgICAgICAgICAgdmFyIGxlbiA9IHQubGVuZ3RoID4+PiAwO1xuICAgICAgICAgICAgaWYgKGxlbiA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBuID0gbGVuO1xuICAgICAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgbiA9IE51bWJlcihhcmd1bWVudHNbMV0pO1xuICAgICAgICAgICAgICAgIGlmIChuICE9IG4pIHtcbiAgICAgICAgICAgICAgICAgICAgbiA9IDA7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChuICE9IDAgJiYgbiAhPSAoMSAvIDApICYmIG4gIT0gLSgxIC8gMCkpIHtcbiAgICAgICAgICAgICAgICAgICAgbiA9IChuID4gMCB8fCAtMSkgKiBNYXRoLmZsb29yKE1hdGguYWJzKG4pKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgayA9IG4gPj0gMCA/IE1hdGgubWluKG4sIGxlbiAtIDEpIDogbGVuIC0gTWF0aC5hYnMobik7XG4gICAgICAgICAgICBmb3IgKDsgayA+PSAwOyBrLS0pIHtcbiAgICAgICAgICAgICAgICBpZiAoayBpbiB0ICYmIHRba10gPT09IHNlYXJjaEVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9O1xuICAgIH1cbiAgICBcbiAgICAvLyBBZGQgc3RyaW5nIHRyaW0gZm9yIElFOC5cbiAgICBpZiAodHlwZW9mIFN0cmluZy5wcm90b3R5cGUudHJpbSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBTdHJpbmcucHJvdG90eXBlLnRyaW0gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKTsgXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgcm9vdCA9IHRoaXNcbiAgICAgICwgJCA9IHJvb3QualF1ZXJ5IHx8IHJvb3QuWmVwdG9cbiAgICAgICwgaTE4biA9IHt9XG4gICAgICAsIHJlc1N0b3JlID0ge31cbiAgICAgICwgY3VycmVudExuZ1xuICAgICAgLCByZXBsYWNlbWVudENvdW50ZXIgPSAwXG4gICAgICAsIGxhbmd1YWdlcyA9IFtdXG4gICAgICAsIGluaXRpYWxpemVkID0gZmFsc2VcbiAgICAgICwgc3luYyA9IHt9O1xuXG5cblxuICAgIC8vIEV4cG9ydCB0aGUgaTE4bmV4dCBvYmplY3QgZm9yICoqQ29tbW9uSlMqKi4gXG4gICAgLy8gSWYgd2UncmUgbm90IGluIENvbW1vbkpTLCBhZGQgYGkxOG5gIHRvIHRoZVxuICAgIC8vIGdsb2JhbCBvYmplY3Qgb3IgdG8ganF1ZXJ5LlxuICAgIGlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyAmJiBtb2R1bGUuZXhwb3J0cykge1xuICAgICAgICBpZiAoISQpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgJCA9IHJlcXVpcmUoJ2pxdWVyeScpO1xuICAgICAgICAgIH0gY2F0Y2goZSkge1xuICAgICAgICAgICAgLy8ganVzdCBpZ25vcmVcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCQpIHtcbiAgICAgICAgICAgICQuaTE4biA9ICQuaTE4biB8fCBpMThuO1xuICAgICAgICB9XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gaTE4bjtcbiAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoJCkge1xuICAgICAgICAgICAgJC5pMThuID0gJC5pMThuIHx8IGkxOG47XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIHJvb3QuaTE4biA9IHJvb3QuaTE4biB8fCBpMThuO1xuICAgIH1cbiAgICBzeW5jID0ge1xuICAgIFxuICAgICAgICBsb2FkOiBmdW5jdGlvbihsbmdzLCBvcHRpb25zLCBjYikge1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMudXNlTG9jYWxTdG9yYWdlKSB7XG4gICAgICAgICAgICAgICAgc3luYy5fbG9hZExvY2FsKGxuZ3MsIG9wdGlvbnMsIGZ1bmN0aW9uKGVyciwgc3RvcmUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG1pc3NpbmdMbmdzID0gW107XG4gICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBsbmdzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXN0b3JlW2xuZ3NbaV1dKSBtaXNzaW5nTG5ncy5wdXNoKGxuZ3NbaV0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgICAgIGlmIChtaXNzaW5nTG5ncy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzeW5jLl9mZXRjaChtaXNzaW5nTG5ncywgb3B0aW9ucywgZnVuY3Rpb24oZXJyLCBmZXRjaGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZi5leHRlbmQoc3RvcmUsIGZldGNoZWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bmMuX3N0b3JlTG9jYWwoZmV0Y2hlZCk7XG4gICAgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2IobnVsbCwgc3RvcmUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYihudWxsLCBzdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3luYy5fZmV0Y2gobG5ncywgb3B0aW9ucywgZnVuY3Rpb24oZXJyLCBzdG9yZSl7XG4gICAgICAgICAgICAgICAgICAgIGNiKG51bGwsIHN0b3JlKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICBcbiAgICAgICAgX2xvYWRMb2NhbDogZnVuY3Rpb24obG5ncywgb3B0aW9ucywgY2IpIHtcbiAgICAgICAgICAgIHZhciBzdG9yZSA9IHt9XG4gICAgICAgICAgICAgICwgbm93TVMgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICBcbiAgICAgICAgICAgIGlmKHdpbmRvdy5sb2NhbFN0b3JhZ2UpIHtcbiAgICBcbiAgICAgICAgICAgICAgICB2YXIgdG9kbyA9IGxuZ3MubGVuZ3RoO1xuICAgIFxuICAgICAgICAgICAgICAgIGYuZWFjaChsbmdzLCBmdW5jdGlvbihrZXksIGxuZykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgbG9jYWwgPSB3aW5kb3cubG9jYWxTdG9yYWdlLmdldEl0ZW0oJ3Jlc18nICsgbG5nKTtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgaWYgKGxvY2FsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2NhbCA9IEpTT04ucGFyc2UobG9jYWwpO1xuICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGxvY2FsLmkxOG5TdGFtcCAmJiBsb2NhbC5pMThuU3RhbXAgKyBvcHRpb25zLmxvY2FsU3RvcmFnZUV4cGlyYXRpb25UaW1lID4gbm93TVMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdG9yZVtsbmddID0gbG9jYWw7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAgICAgdG9kby0tOyAvLyB3YWl0IGZvciBhbGwgZG9uZSBiZWZvciBjYWxsYmFja1xuICAgICAgICAgICAgICAgICAgICBpZiAodG9kbyA9PT0gMCkgY2IobnVsbCwgc3RvcmUpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgIFxuICAgICAgICBfc3RvcmVMb2NhbDogZnVuY3Rpb24oc3RvcmUpIHtcbiAgICAgICAgICAgIGlmKHdpbmRvdy5sb2NhbFN0b3JhZ2UpIHtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBtIGluIHN0b3JlKSB7XG4gICAgICAgICAgICAgICAgICAgIHN0b3JlW21dLmkxOG5TdGFtcCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICAgICAgICAgICAgICBmLmxvY2FsU3RvcmFnZS5zZXRJdGVtKCdyZXNfJyArIG0sIEpTT04uc3RyaW5naWZ5KHN0b3JlW21dKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9LFxuICAgIFxuICAgICAgICBfZmV0Y2g6IGZ1bmN0aW9uKGxuZ3MsIG9wdGlvbnMsIGNiKSB7XG4gICAgICAgICAgICB2YXIgbnMgPSBvcHRpb25zLm5zXG4gICAgICAgICAgICAgICwgc3RvcmUgPSB7fTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgaWYgKCFvcHRpb25zLmR5bmFtaWNMb2FkKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRvZG8gPSBucy5uYW1lc3BhY2VzLmxlbmd0aCAqIGxuZ3MubGVuZ3RoXG4gICAgICAgICAgICAgICAgICAsIGVycm9ycztcbiAgICBcbiAgICAgICAgICAgICAgICAvLyBsb2FkIGVhY2ggZmlsZSBpbmRpdmlkdWFsXG4gICAgICAgICAgICAgICAgZi5lYWNoKG5zLm5hbWVzcGFjZXMsIGZ1bmN0aW9uKG5zSW5kZXgsIG5zVmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgZi5lYWNoKGxuZ3MsIGZ1bmN0aW9uKGxuZ0luZGV4LCBsbmdWYWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDYWxsIHRoaXMgb25jZSBvdXIgdHJhbnNsYXRpb24gaGFzIHJldHVybmVkLlxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxvYWRDb21wbGV0ZSA9IGZ1bmN0aW9uKGVyciwgZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcnMucHVzaChlcnIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdG9yZVtsbmdWYWx1ZV0gPSBzdG9yZVtsbmdWYWx1ZV0gfHwge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RvcmVbbG5nVmFsdWVdW25zVmFsdWVdID0gZGF0YTtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b2RvLS07IC8vIHdhaXQgZm9yIGFsbCBkb25lIGJlZm9yIGNhbGxiYWNrXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRvZG8gPT09IDApIGNiKGVycm9ycywgc3RvcmUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgaWYodHlwZW9mIG9wdGlvbnMuY3VzdG9tTG9hZCA9PSAnZnVuY3Rpb24nKXtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgdGhlIHNwZWNpZmllZCBjdXN0b20gY2FsbGJhY2suXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2FkKGxuZ1ZhbHVlLCBuc1ZhbHVlLCBvcHRpb25zLCBsb2FkQ29tcGxldGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL34gLy8gVXNlIG91ciBpbmJ1aWx0IHN5bmMuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3luYy5fZmV0Y2hPbmUobG5nVmFsdWUsIG5zVmFsdWUsIG9wdGlvbnMsIGxvYWRDb21wbGV0ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBDYWxsIHRoaXMgb25jZSBvdXIgdHJhbnNsYXRpb24gaGFzIHJldHVybmVkLlxuICAgICAgICAgICAgICAgIHZhciBsb2FkQ29tcGxldGUgPSBmdW5jdGlvbihlcnIsIGRhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgY2IobnVsbCwgZGF0YSk7XG4gICAgICAgICAgICAgICAgfTtcbiAgICBcbiAgICAgICAgICAgICAgICBpZih0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2FkID09ICdmdW5jdGlvbicpe1xuICAgICAgICAgICAgICAgICAgICAvLyBVc2UgdGhlIHNwZWNpZmllZCBjdXN0b20gY2FsbGJhY2suXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuY3VzdG9tTG9hZChsbmdzLCBucy5uYW1lc3BhY2VzLCBvcHRpb25zLCBsb2FkQ29tcGxldGUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmwgPSBhcHBseVJlcGxhY2VtZW50KG9wdGlvbnMucmVzR2V0UGF0aCwgeyBsbmc6IGxuZ3Muam9pbignKycpLCBuczogbnMubmFtZXNwYWNlcy5qb2luKCcrJykgfSk7XG4gICAgICAgICAgICAgICAgICAgIC8vIGxvYWQgYWxsIG5lZWRlZCBzdHVmZiBvbmNlXG4gICAgICAgICAgICAgICAgICAgIGYuYWpheCh7XG4gICAgICAgICAgICAgICAgICAgICAgICB1cmw6IHVybCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uKGRhdGEsIHN0YXR1cywgeGhyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZi5sb2coJ2xvYWRlZDogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9hZENvbXBsZXRlKG51bGwsIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yIDogZnVuY3Rpb24oeGhyLCBzdGF0dXMsIGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZi5sb2coJ2ZhaWxlZCBsb2FkaW5nOiAnICsgdXJsKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2FkQ29tcGxldGUoJ2ZhaWxlZCBsb2FkaW5nIHJlc291cmNlLmpzb24gZXJyb3I6ICcgKyBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVR5cGU6IFwianNvblwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXN5bmMgOiBvcHRpb25zLmdldEFzeW5jXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0gICAgXG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgXG4gICAgICAgIF9mZXRjaE9uZTogZnVuY3Rpb24obG5nLCBucywgb3B0aW9ucywgZG9uZSkge1xuICAgICAgICAgICAgdmFyIHVybCA9IGFwcGx5UmVwbGFjZW1lbnQob3B0aW9ucy5yZXNHZXRQYXRoLCB7IGxuZzogbG5nLCBuczogbnMgfSk7XG4gICAgICAgICAgICBmLmFqYXgoe1xuICAgICAgICAgICAgICAgIHVybDogdXJsLFxuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uKGRhdGEsIHN0YXR1cywgeGhyKSB7XG4gICAgICAgICAgICAgICAgICAgIGYubG9nKCdsb2FkZWQ6ICcgKyB1cmwpO1xuICAgICAgICAgICAgICAgICAgICBkb25lKG51bGwsIGRhdGEpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZXJyb3IgOiBmdW5jdGlvbih4aHIsIHN0YXR1cywgZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKChzdGF0dXMgJiYgc3RhdHVzID09IDIwMCkgfHwgKHhociAmJiB4aHIuc3RhdHVzICYmIHhoci5zdGF0dXMgPT0gMjAwKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmlsZSBsb2FkZWQgYnV0IGludmFsaWQganNvbiwgc3RvcCB3YXN0ZSB0aW1lICFcbiAgICAgICAgICAgICAgICAgICAgICAgIGYuZXJyb3IoJ1RoZXJlIGlzIGEgdHlwbyBpbjogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoKHN0YXR1cyAmJiBzdGF0dXMgPT0gNDA0KSB8fCAoeGhyICYmIHhoci5zdGF0dXMgJiYgeGhyLnN0YXR1cyA9PSA0MDQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmLmxvZygnRG9lcyBub3QgZXhpc3Q6ICcgKyB1cmwpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRoZVN0YXR1cyA9IHN0YXR1cyA/IHN0YXR1cyA6ICgoeGhyICYmIHhoci5zdGF0dXMpID8geGhyLnN0YXR1cyA6IG51bGwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZi5sb2codGhlU3RhdHVzICsgJyB3aGVuIGxvYWRpbmcgJyArIHVybCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgIGRvbmUoZXJyb3IsIHt9KTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGRhdGFUeXBlOiBcImpzb25cIixcbiAgICAgICAgICAgICAgICBhc3luYyA6IG9wdGlvbnMuZ2V0QXN5bmNcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuICAgIFxuICAgICAgICBwb3N0TWlzc2luZzogZnVuY3Rpb24obG5nLCBucywga2V5LCBkZWZhdWx0VmFsdWUsIGxuZ3MpIHtcbiAgICAgICAgICAgIHZhciBwYXlsb2FkID0ge307XG4gICAgICAgICAgICBwYXlsb2FkW2tleV0gPSBkZWZhdWx0VmFsdWU7XG4gICAgXG4gICAgICAgICAgICB2YXIgdXJscyA9IFtdO1xuICAgIFxuICAgICAgICAgICAgaWYgKG8uc2VuZE1pc3NpbmdUbyA9PT0gJ2ZhbGxiYWNrJyAmJiBvLmZhbGxiYWNrTG5nWzBdICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgby5mYWxsYmFja0xuZy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICB1cmxzLnB1c2goe2xuZzogby5mYWxsYmFja0xuZ1tpXSwgdXJsOiBhcHBseVJlcGxhY2VtZW50KG8ucmVzUG9zdFBhdGgsIHsgbG5nOiBvLmZhbGxiYWNrTG5nW2ldLCBuczogbnMgfSl9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG8uc2VuZE1pc3NpbmdUbyA9PT0gJ2N1cnJlbnQnIHx8IChvLnNlbmRNaXNzaW5nVG8gPT09ICdmYWxsYmFjaycgJiYgby5mYWxsYmFja0xuZ1swXSA9PT0gZmFsc2UpICkge1xuICAgICAgICAgICAgICAgIHVybHMucHVzaCh7bG5nOiBsbmcsIHVybDogYXBwbHlSZXBsYWNlbWVudChvLnJlc1Bvc3RQYXRoLCB7IGxuZzogbG5nLCBuczogbnMgfSl9KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoby5zZW5kTWlzc2luZ1RvID09PSAnYWxsJykge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gbG5ncy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgdXJscy5wdXNoKHtsbmc6IGxuZ3NbaV0sIHVybDogYXBwbHlSZXBsYWNlbWVudChvLnJlc1Bvc3RQYXRoLCB7IGxuZzogbG5nc1tpXSwgbnM6IG5zIH0pfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgZm9yICh2YXIgeSA9IDAsIGxlbiA9IHVybHMubGVuZ3RoOyB5IDwgbGVuOyB5KyspIHtcbiAgICAgICAgICAgICAgICB2YXIgaXRlbSA9IHVybHNbeV07XG4gICAgICAgICAgICAgICAgZi5hamF4KHtcbiAgICAgICAgICAgICAgICAgICAgdXJsOiBpdGVtLnVybCxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogby5zZW5kVHlwZSxcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogcGF5bG9hZCxcbiAgICAgICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24oZGF0YSwgc3RhdHVzLCB4aHIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGYubG9nKCdwb3N0ZWQgbWlzc2luZyBrZXkgXFwnJyArIGtleSArICdcXCcgdG86ICcgKyBpdGVtLnVybCk7XG4gICAgXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhZGQga2V5IHRvIHJlc1N0b3JlXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIga2V5cyA9IGtleS5zcGxpdCgnLicpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHggPSAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gcmVzU3RvcmVbaXRlbS5sbmddW25zXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIChrZXlzW3hdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHggPT09IGtleXMubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlW2tleXNbeF1dID0gZGVmYXVsdFZhbHVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWVba2V5c1t4XV0gPSB2YWx1ZVtrZXlzW3hdXSB8fCB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeCsrO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBlcnJvciA6IGZ1bmN0aW9uKHhociwgc3RhdHVzLCBlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZi5sb2coJ2ZhaWxlZCBwb3N0aW5nIG1pc3Npbmcga2V5IFxcJycgKyBrZXkgKyAnXFwnIHRvOiAnICsgaXRlbS51cmwpO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBkYXRhVHlwZTogXCJqc29uXCIsXG4gICAgICAgICAgICAgICAgICAgIGFzeW5jIDogby5wb3N0QXN5bmNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICBcbiAgICAgICAgcmVsb2FkOiByZWxvYWRcbiAgICB9O1xuICAgIC8vIGRlZmF1bHRzXG4gICAgdmFyIG8gPSB7XG4gICAgICAgIGxuZzogdW5kZWZpbmVkLFxuICAgICAgICBsb2FkOiAnYWxsJyxcbiAgICAgICAgcHJlbG9hZDogW10sXG4gICAgICAgIGxvd2VyQ2FzZUxuZzogZmFsc2UsXG4gICAgICAgIHJldHVybk9iamVjdFRyZWVzOiBmYWxzZSxcbiAgICAgICAgZmFsbGJhY2tMbmc6IFsnZGV2J10sXG4gICAgICAgIGZhbGxiYWNrTlM6IFtdLFxuICAgICAgICBkZXRlY3RMbmdRUzogJ3NldExuZycsXG4gICAgICAgIGRldGVjdExuZ0Zyb21Mb2NhbFN0b3JhZ2U6IGZhbHNlLFxuICAgICAgICBuczogJ3RyYW5zbGF0aW9uJyxcbiAgICAgICAgZmFsbGJhY2tPbk51bGw6IHRydWUsXG4gICAgICAgIGZhbGxiYWNrT25FbXB0eTogZmFsc2UsXG4gICAgICAgIGZhbGxiYWNrVG9EZWZhdWx0TlM6IGZhbHNlLFxuICAgICAgICBuc3NlcGFyYXRvcjogJzonLFxuICAgICAgICBrZXlzZXBhcmF0b3I6ICcuJyxcbiAgICAgICAgc2VsZWN0b3JBdHRyOiAnZGF0YS1pMThuJyxcbiAgICAgICAgZGVidWc6IGZhbHNlLFxuICAgICAgICBcbiAgICAgICAgcmVzR2V0UGF0aDogJ2xvY2FsZXMvX19sbmdfXy9fX25zX18uanNvbicsXG4gICAgICAgIHJlc1Bvc3RQYXRoOiAnbG9jYWxlcy9hZGQvX19sbmdfXy9fX25zX18nLFxuICAgIFxuICAgICAgICBnZXRBc3luYzogdHJ1ZSxcbiAgICAgICAgcG9zdEFzeW5jOiB0cnVlLFxuICAgIFxuICAgICAgICByZXNTdG9yZTogdW5kZWZpbmVkLFxuICAgICAgICB1c2VMb2NhbFN0b3JhZ2U6IGZhbHNlLFxuICAgICAgICBsb2NhbFN0b3JhZ2VFeHBpcmF0aW9uVGltZTogNyoyNCo2MCo2MCoxMDAwLFxuICAgIFxuICAgICAgICBkeW5hbWljTG9hZDogZmFsc2UsXG4gICAgICAgIHNlbmRNaXNzaW5nOiBmYWxzZSxcbiAgICAgICAgc2VuZE1pc3NpbmdUbzogJ2ZhbGxiYWNrJywgLy8gY3VycmVudCB8IGFsbFxuICAgICAgICBzZW5kVHlwZTogJ1BPU1QnLFxuICAgIFxuICAgICAgICBpbnRlcnBvbGF0aW9uUHJlZml4OiAnX18nLFxuICAgICAgICBpbnRlcnBvbGF0aW9uU3VmZml4OiAnX18nLFxuICAgICAgICBkZWZhdWx0VmFyaWFibGVzOiBmYWxzZSxcbiAgICAgICAgcmV1c2VQcmVmaXg6ICckdCgnLFxuICAgICAgICByZXVzZVN1ZmZpeDogJyknLFxuICAgICAgICBwbHVyYWxTdWZmaXg6ICdfcGx1cmFsJyxcbiAgICAgICAgcGx1cmFsTm90Rm91bmQ6IFsncGx1cmFsX25vdF9mb3VuZCcsIE1hdGgucmFuZG9tKCldLmpvaW4oJycpLFxuICAgICAgICBjb250ZXh0Tm90Rm91bmQ6IFsnY29udGV4dF9ub3RfZm91bmQnLCBNYXRoLnJhbmRvbSgpXS5qb2luKCcnKSxcbiAgICAgICAgZXNjYXBlSW50ZXJwb2xhdGlvbjogZmFsc2UsXG4gICAgICAgIGluZGVmaW5pdGVTdWZmaXg6ICdfaW5kZWZpbml0ZScsXG4gICAgICAgIGluZGVmaW5pdGVOb3RGb3VuZDogWydpbmRlZmluaXRlX25vdF9mb3VuZCcsIE1hdGgucmFuZG9tKCldLmpvaW4oJycpLFxuICAgIFxuICAgICAgICBzZXRKcXVlcnlFeHQ6IHRydWUsXG4gICAgICAgIGRlZmF1bHRWYWx1ZUZyb21Db250ZW50OiB0cnVlLFxuICAgICAgICB1c2VEYXRhQXR0ck9wdGlvbnM6IGZhbHNlLFxuICAgICAgICBjb29raWVFeHBpcmF0aW9uVGltZTogdW5kZWZpbmVkLFxuICAgICAgICB1c2VDb29raWU6IHRydWUsXG4gICAgICAgIGNvb2tpZU5hbWU6ICdpMThuZXh0JyxcbiAgICAgICAgY29va2llRG9tYWluOiB1bmRlZmluZWQsXG4gICAgXG4gICAgICAgIG9iamVjdFRyZWVLZXlIYW5kbGVyOiB1bmRlZmluZWQsXG4gICAgICAgIHBvc3RQcm9jZXNzOiB1bmRlZmluZWQsXG4gICAgICAgIHBhcnNlTWlzc2luZ0tleTogdW5kZWZpbmVkLFxuICAgICAgICBtaXNzaW5nS2V5SGFuZGxlcjogc3luYy5wb3N0TWlzc2luZyxcbiAgICBcbiAgICAgICAgc2hvcnRjdXRGdW5jdGlvbjogJ3NwcmludGYnIC8vIG9yOiBkZWZhdWx0VmFsdWVcbiAgICB9O1xuICAgIGZ1bmN0aW9uIF9leHRlbmQodGFyZ2V0LCBzb3VyY2UpIHtcbiAgICAgICAgaWYgKCFzb3VyY2UgfHwgdHlwZW9mIHNvdXJjZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBmb3IgKHZhciBhdHRyIGluIHNvdXJjZSkgeyB0YXJnZXRbYXR0cl0gPSBzb3VyY2VbYXR0cl07IH1cbiAgICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gX2RlZXBFeHRlbmQodGFyZ2V0LCBzb3VyY2UpIHtcbiAgICAgICAgZm9yICh2YXIgcHJvcCBpbiBzb3VyY2UpXG4gICAgICAgICAgICBpZiAocHJvcCBpbiB0YXJnZXQpXG4gICAgICAgICAgICAgICAgX2RlZXBFeHRlbmQodGFyZ2V0W3Byb3BdLCBzb3VyY2VbcHJvcF0pO1xuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHRhcmdldFtwcm9wXSA9IHNvdXJjZVtwcm9wXTtcbiAgICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gX2VhY2gob2JqZWN0LCBjYWxsYmFjaywgYXJncykge1xuICAgICAgICB2YXIgbmFtZSwgaSA9IDAsXG4gICAgICAgICAgICBsZW5ndGggPSBvYmplY3QubGVuZ3RoLFxuICAgICAgICAgICAgaXNPYmogPSBsZW5ndGggPT09IHVuZGVmaW5lZCB8fCBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmFwcGx5KG9iamVjdCkgIT09ICdbb2JqZWN0IEFycmF5XScgfHwgdHlwZW9mIG9iamVjdCA9PT0gXCJmdW5jdGlvblwiO1xuICAgIFxuICAgICAgICBpZiAoYXJncykge1xuICAgICAgICAgICAgaWYgKGlzT2JqKSB7XG4gICAgICAgICAgICAgICAgZm9yIChuYW1lIGluIG9iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY2FsbGJhY2suYXBwbHkob2JqZWN0W25hbWVdLCBhcmdzKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmb3IgKCA7IGkgPCBsZW5ndGg7ICkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY2FsbGJhY2suYXBwbHkob2JqZWN0W2krK10sIGFyZ3MpID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgIC8vIEEgc3BlY2lhbCwgZmFzdCwgY2FzZSBmb3IgdGhlIG1vc3QgY29tbW9uIHVzZSBvZiBlYWNoXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoaXNPYmopIHtcbiAgICAgICAgICAgICAgICBmb3IgKG5hbWUgaW4gb2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjay5jYWxsKG9iamVjdFtuYW1lXSwgbmFtZSwgb2JqZWN0W25hbWVdKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmb3IgKCA7IGkgPCBsZW5ndGg7ICkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY2FsbGJhY2suY2FsbChvYmplY3RbaV0sIGksIG9iamVjdFtpKytdKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIHJldHVybiBvYmplY3Q7XG4gICAgfVxuICAgIFxuICAgIHZhciBfZW50aXR5TWFwID0ge1xuICAgICAgICBcIiZcIjogXCImYW1wO1wiLFxuICAgICAgICBcIjxcIjogXCImbHQ7XCIsXG4gICAgICAgIFwiPlwiOiBcIiZndDtcIixcbiAgICAgICAgJ1wiJzogJyZxdW90OycsXG4gICAgICAgIFwiJ1wiOiAnJiMzOTsnLFxuICAgICAgICBcIi9cIjogJyYjeDJGOydcbiAgICB9O1xuICAgIFxuICAgIGZ1bmN0aW9uIF9lc2NhcGUoZGF0YSkge1xuICAgICAgICBpZiAodHlwZW9mIGRhdGEgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gZGF0YS5yZXBsYWNlKC9bJjw+XCInXFwvXS9nLCBmdW5jdGlvbiAocykge1xuICAgICAgICAgICAgICAgIHJldHVybiBfZW50aXR5TWFwW3NdO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1lbHNle1xuICAgICAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gX2FqYXgob3B0aW9ucykge1xuICAgIFxuICAgICAgICAvLyB2MC41LjAgb2YgaHR0cHM6Ly9naXRodWIuY29tL2dvbG9yb2Rlbi9odHRwLmpzXG4gICAgICAgIHZhciBnZXRYaHIgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgIC8vIFVzZSB0aGUgbmF0aXZlIFhIUiBvYmplY3QgaWYgdGhlIGJyb3dzZXIgc3VwcG9ydHMgaXQuXG4gICAgICAgICAgICBpZiAod2luZG93LlhNTEh0dHBSZXF1ZXN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG51bGwsIG5ldyBYTUxIdHRwUmVxdWVzdCgpKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAod2luZG93LkFjdGl2ZVhPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAvLyBJbiBJbnRlcm5ldCBFeHBsb3JlciBjaGVjayBmb3IgQWN0aXZlWCB2ZXJzaW9ucyBvZiB0aGUgWEhSIG9iamVjdC5cbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgbmV3IEFjdGl2ZVhPYmplY3QoXCJNc3htbDIuWE1MSFRUUFwiKSk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgbmV3IEFjdGl2ZVhPYmplY3QoXCJNaWNyb3NvZnQuWE1MSFRUUFwiKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgLy8gSWYgbm8gWEhSIHN1cHBvcnQgd2FzIGZvdW5kLCB0aHJvdyBhbiBlcnJvci5cbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhuZXcgRXJyb3IoKSk7XG4gICAgICAgIH07XG4gICAgXG4gICAgICAgIHZhciBlbmNvZGVVc2luZ1VybEVuY29kaW5nID0gZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgICAgIGlmKHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IFtdO1xuICAgICAgICAgICAgZm9yKHZhciBkYXRhSXRlbSBpbiBkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYoZGF0YS5oYXNPd25Qcm9wZXJ0eShkYXRhSXRlbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goZW5jb2RlVVJJQ29tcG9uZW50KGRhdGFJdGVtKSArICc9JyArIGVuY29kZVVSSUNvbXBvbmVudChkYXRhW2RhdGFJdGVtXSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQuam9pbignJicpO1xuICAgICAgICB9O1xuICAgIFxuICAgICAgICB2YXIgdXRmOCA9IGZ1bmN0aW9uICh0ZXh0KSB7XG4gICAgICAgICAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXHJcXG4vZywgJ1xcbicpO1xuICAgICAgICAgICAgdmFyIHJlc3VsdCA9ICcnO1xuICAgIFxuICAgICAgICAgICAgZm9yKHZhciBpID0gMDsgaSA8IHRleHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgYyA9IHRleHQuY2hhckNvZGVBdChpKTtcbiAgICBcbiAgICAgICAgICAgICAgICBpZihjIDwgMTI4KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShjKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYoKGMgPiAxMjcpICYmIChjIDwgMjA0OCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChjID4+IDYpIHwgMTkyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChjICYgNjMpIHwgMTI4KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgPj4gMTIpIHwgMjI0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKCgoYyA+PiA2KSAmIDYzKSB8IDEyOCk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoYyAmIDYzKSB8IDEyOCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgdmFyIGJhc2U2NCA9IGZ1bmN0aW9uICh0ZXh0KSB7XG4gICAgICAgICAgICB2YXIga2V5U3RyID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky89JztcbiAgICBcbiAgICAgICAgICAgIHRleHQgPSB1dGY4KHRleHQpO1xuICAgICAgICAgICAgdmFyIHJlc3VsdCA9ICcnLFxuICAgICAgICAgICAgICAgICAgICBjaHIxLCBjaHIyLCBjaHIzLFxuICAgICAgICAgICAgICAgICAgICBlbmMxLCBlbmMyLCBlbmMzLCBlbmM0LFxuICAgICAgICAgICAgICAgICAgICBpID0gMDtcbiAgICBcbiAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgICBjaHIxID0gdGV4dC5jaGFyQ29kZUF0KGkrKyk7XG4gICAgICAgICAgICAgICAgY2hyMiA9IHRleHQuY2hhckNvZGVBdChpKyspO1xuICAgICAgICAgICAgICAgIGNocjMgPSB0ZXh0LmNoYXJDb2RlQXQoaSsrKTtcbiAgICBcbiAgICAgICAgICAgICAgICBlbmMxID0gY2hyMSA+PiAyO1xuICAgICAgICAgICAgICAgIGVuYzIgPSAoKGNocjEgJiAzKSA8PCA0KSB8IChjaHIyID4+IDQpO1xuICAgICAgICAgICAgICAgIGVuYzMgPSAoKGNocjIgJiAxNSkgPDwgMikgfCAoY2hyMyA+PiA2KTtcbiAgICAgICAgICAgICAgICBlbmM0ID0gY2hyMyAmIDYzO1xuICAgIFxuICAgICAgICAgICAgICAgIGlmKGlzTmFOKGNocjIpKSB7XG4gICAgICAgICAgICAgICAgICAgIGVuYzMgPSBlbmM0ID0gNjQ7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmKGlzTmFOKGNocjMpKSB7XG4gICAgICAgICAgICAgICAgICAgIGVuYzQgPSA2NDtcbiAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9XG4gICAgICAgICAgICAgICAgICAgIGtleVN0ci5jaGFyQXQoZW5jMSkgK1xuICAgICAgICAgICAgICAgICAgICBrZXlTdHIuY2hhckF0KGVuYzIpICtcbiAgICAgICAgICAgICAgICAgICAga2V5U3RyLmNoYXJBdChlbmMzKSArXG4gICAgICAgICAgICAgICAgICAgIGtleVN0ci5jaGFyQXQoZW5jNCk7XG4gICAgICAgICAgICAgICAgY2hyMSA9IGNocjIgPSBjaHIzID0gJyc7XG4gICAgICAgICAgICAgICAgZW5jMSA9IGVuYzIgPSBlbmMzID0gZW5jNCA9ICcnO1xuICAgICAgICAgICAgfSB3aGlsZShpIDwgdGV4dC5sZW5ndGgpO1xuICAgIFxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgdmFyIG1lcmdlSGVhZGVycyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vIFVzZSB0aGUgZmlyc3QgaGVhZGVyIG9iamVjdCBhcyBiYXNlLlxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IGFyZ3VtZW50c1swXTtcbiAgICBcbiAgICAgICAgICAgIC8vIEl0ZXJhdGUgdGhyb3VnaCB0aGUgcmVtYWluaW5nIGhlYWRlciBvYmplY3RzIGFuZCBhZGQgdGhlbS5cbiAgICAgICAgICAgIGZvcih2YXIgaSA9IDE7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgY3VycmVudEhlYWRlcnMgPSBhcmd1bWVudHNbaV07XG4gICAgICAgICAgICAgICAgZm9yKHZhciBoZWFkZXIgaW4gY3VycmVudEhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYoY3VycmVudEhlYWRlcnMuaGFzT3duUHJvcGVydHkoaGVhZGVyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0W2hlYWRlcl0gPSBjdXJyZW50SGVhZGVyc1toZWFkZXJdO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgLy8gUmV0dXJuIHRoZSBtZXJnZWQgaGVhZGVycy5cbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH07XG4gICAgXG4gICAgICAgIHZhciBhamF4ID0gZnVuY3Rpb24gKG1ldGhvZCwgdXJsLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgLy8gQWRqdXN0IHBhcmFtZXRlcnMuXG4gICAgICAgICAgICBpZih0eXBlb2Ygb3B0aW9ucyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrID0gb3B0aW9ucztcbiAgICAgICAgICAgICAgICBvcHRpb25zID0ge307XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAvLyBTZXQgZGVmYXVsdCBwYXJhbWV0ZXIgdmFsdWVzLlxuICAgICAgICAgICAgb3B0aW9ucy5jYWNoZSA9IG9wdGlvbnMuY2FjaGUgfHwgZmFsc2U7XG4gICAgICAgICAgICBvcHRpb25zLmRhdGEgPSBvcHRpb25zLmRhdGEgfHwge307XG4gICAgICAgICAgICBvcHRpb25zLmhlYWRlcnMgPSBvcHRpb25zLmhlYWRlcnMgfHwge307XG4gICAgICAgICAgICBvcHRpb25zLmpzb25wID0gb3B0aW9ucy5qc29ucCB8fCBmYWxzZTtcbiAgICAgICAgICAgIG9wdGlvbnMuYXN5bmMgPSBvcHRpb25zLmFzeW5jID09PSB1bmRlZmluZWQgPyB0cnVlIDogb3B0aW9ucy5hc3luYztcbiAgICBcbiAgICAgICAgICAgIC8vIE1lcmdlIHRoZSB2YXJpb3VzIGhlYWRlciBvYmplY3RzLlxuICAgICAgICAgICAgdmFyIGhlYWRlcnMgPSBtZXJnZUhlYWRlcnMoe1xuICAgICAgICAgICAgICAgICdhY2NlcHQnOiAnKi8qJyxcbiAgICAgICAgICAgICAgICAnY29udGVudC10eXBlJzogJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PVVURi04J1xuICAgICAgICAgICAgfSwgYWpheC5oZWFkZXJzLCBvcHRpb25zLmhlYWRlcnMpO1xuICAgIFxuICAgICAgICAgICAgLy8gRW5jb2RlIHRoZSBkYXRhIGFjY29yZGluZyB0byB0aGUgY29udGVudC10eXBlLlxuICAgICAgICAgICAgdmFyIHBheWxvYWQ7XG4gICAgICAgICAgICBpZiAoaGVhZGVyc1snY29udGVudC10eXBlJ10gPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgICAgIHBheWxvYWQgPSBKU09OLnN0cmluZ2lmeShvcHRpb25zLmRhdGEpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXlsb2FkID0gZW5jb2RlVXNpbmdVcmxFbmNvZGluZyhvcHRpb25zLmRhdGEpO1xuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgLy8gU3BlY2lhbGx5IHByZXBhcmUgR0VUIHJlcXVlc3RzOiBTZXR1cCB0aGUgcXVlcnkgc3RyaW5nLCBoYW5kbGUgY2FjaGluZyBhbmQgbWFrZSBhIEpTT05QIGNhbGxcbiAgICAgICAgICAgIC8vIGlmIG5lY2Nlc3NhcnkuXG4gICAgICAgICAgICBpZihtZXRob2QgPT09ICdHRVQnKSB7XG4gICAgICAgICAgICAgICAgLy8gU2V0dXAgdGhlIHF1ZXJ5IHN0cmluZy5cbiAgICAgICAgICAgICAgICB2YXIgcXVlcnlTdHJpbmcgPSBbXTtcbiAgICAgICAgICAgICAgICBpZihwYXlsb2FkKSB7XG4gICAgICAgICAgICAgICAgICAgIHF1ZXJ5U3RyaW5nLnB1c2gocGF5bG9hZCk7XG4gICAgICAgICAgICAgICAgICAgIHBheWxvYWQgPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAvLyBIYW5kbGUgY2FjaGluZy5cbiAgICAgICAgICAgICAgICBpZighb3B0aW9ucy5jYWNoZSkge1xuICAgICAgICAgICAgICAgICAgICBxdWVyeVN0cmluZy5wdXNoKCdfPScgKyAobmV3IERhdGUoKSkuZ2V0VGltZSgpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgLy8gSWYgbmVjY2Vzc2FyeSBwcmVwYXJlIHRoZSBxdWVyeSBzdHJpbmcgZm9yIGEgSlNPTlAgY2FsbC5cbiAgICAgICAgICAgICAgICBpZihvcHRpb25zLmpzb25wKSB7XG4gICAgICAgICAgICAgICAgICAgIHF1ZXJ5U3RyaW5nLnB1c2goJ2NhbGxiYWNrPScgKyBvcHRpb25zLmpzb25wKTtcbiAgICAgICAgICAgICAgICAgICAgcXVlcnlTdHJpbmcucHVzaCgnanNvbnA9JyArIG9wdGlvbnMuanNvbnApO1xuICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAvLyBNZXJnZSB0aGUgcXVlcnkgc3RyaW5nIGFuZCBhdHRhY2ggaXQgdG8gdGhlIHVybC5cbiAgICAgICAgICAgICAgICBxdWVyeVN0cmluZyA9IHF1ZXJ5U3RyaW5nLmpvaW4oJyYnKTtcbiAgICAgICAgICAgICAgICBpZiAocXVlcnlTdHJpbmcubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAodXJsLmluZGV4T2YoJz8nKSA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1cmwgKz0gJyYnICsgcXVlcnlTdHJpbmc7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1cmwgKz0gJz8nICsgcXVlcnlTdHJpbmc7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgLy8gTWFrZSBhIEpTT05QIGNhbGwgaWYgbmVjY2Vzc2FyeS5cbiAgICAgICAgICAgICAgICBpZihvcHRpb25zLmpzb25wKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBoZWFkID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2hlYWQnKVswXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpO1xuICAgICAgICAgICAgICAgICAgICBzY3JpcHQudHlwZSA9ICd0ZXh0L2phdmFzY3JpcHQnO1xuICAgICAgICAgICAgICAgICAgICBzY3JpcHQuc3JjID0gdXJsO1xuICAgICAgICAgICAgICAgICAgICBoZWFkLmFwcGVuZENoaWxkKHNjcmlwdCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAvLyBTaW5jZSB3ZSBnb3QgaGVyZSwgaXQgaXMgbm8gSlNPTlAgcmVxdWVzdCwgc28gbWFrZSBhIG5vcm1hbCBYSFIgcmVxdWVzdC5cbiAgICAgICAgICAgIGdldFhocihmdW5jdGlvbiAoZXJyLCB4aHIpIHtcbiAgICAgICAgICAgICAgICBpZihlcnIpIHJldHVybiBjYWxsYmFjayhlcnIpO1xuICAgIFxuICAgICAgICAgICAgICAgIC8vIE9wZW4gdGhlIHJlcXVlc3QuXG4gICAgICAgICAgICAgICAgeGhyLm9wZW4obWV0aG9kLCB1cmwsIG9wdGlvbnMuYXN5bmMpO1xuICAgIFxuICAgICAgICAgICAgICAgIC8vIFNldCB0aGUgcmVxdWVzdCBoZWFkZXJzLlxuICAgICAgICAgICAgICAgIGZvcih2YXIgaGVhZGVyIGluIGhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYoaGVhZGVycy5oYXNPd25Qcm9wZXJ0eShoZWFkZXIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcihoZWFkZXIsIGhlYWRlcnNbaGVhZGVyXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgLy8gSGFuZGxlIHRoZSByZXF1ZXN0IGV2ZW50cy5cbiAgICAgICAgICAgICAgICB4aHIub25yZWFkeXN0YXRlY2hhbmdlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBpZih4aHIucmVhZHlTdGF0ZSA9PT0gNCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSB4aHIucmVzcG9uc2VUZXh0IHx8ICcnO1xuICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgbm8gY2FsbGJhY2sgaXMgZ2l2ZW4sIHJldHVybi5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmKCFjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJldHVybiBhbiBvYmplY3QgdGhhdCBwcm92aWRlcyBhY2Nlc3MgdG8gdGhlIGRhdGEgYXMgdGV4dCBhbmQgSlNPTi5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKHhoci5zdGF0dXMsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAganNvbjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZi5lcnJvcignQ2FuIG5vdCBwYXJzZSBKU09OLiBVUkw6ICcgKyB1cmwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgIFxuICAgICAgICAgICAgICAgIC8vIEFjdHVhbGx5IHNlbmQgdGhlIFhIUiByZXF1ZXN0LlxuICAgICAgICAgICAgICAgIHhoci5zZW5kKHBheWxvYWQpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG4gICAgXG4gICAgICAgIC8vIERlZmluZSB0aGUgZXh0ZXJuYWwgaW50ZXJmYWNlLlxuICAgICAgICB2YXIgaHR0cCA9IHtcbiAgICAgICAgICAgIGF1dGhCYXNpYzogZnVuY3Rpb24gKHVzZXJuYW1lLCBwYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIGFqYXguaGVhZGVyc1snQXV0aG9yaXphdGlvbiddID0gJ0Jhc2ljICcgKyBiYXNlNjQodXNlcm5hbWUgKyAnOicgKyBwYXNzd29yZCk7XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgY29ubmVjdDogZnVuY3Rpb24gKHVybCwgb3B0aW9ucywgY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWpheCgnQ09OTkVDVCcsIHVybCwgb3B0aW9ucywgY2FsbGJhY2spO1xuICAgICAgICAgICAgfSxcbiAgICBcbiAgICAgICAgICAgIGRlbDogZnVuY3Rpb24gKHVybCwgb3B0aW9ucywgY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWpheCgnREVMRVRFJywgdXJsLCBvcHRpb25zLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbiAodXJsLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJldHVybiBhamF4KCdHRVQnLCB1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICBoZWFkOiBmdW5jdGlvbiAodXJsLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJldHVybiBhamF4KCdIRUFEJywgdXJsLCBvcHRpb25zLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgaGVhZGVyczogZnVuY3Rpb24gKGhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICBhamF4LmhlYWRlcnMgPSBoZWFkZXJzIHx8IHt9O1xuICAgICAgICAgICAgfSxcbiAgICBcbiAgICAgICAgICAgIGlzQWxsb3dlZDogZnVuY3Rpb24gKHVybCwgdmVyYiwgY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnModXJsLCBmdW5jdGlvbiAoc3RhdHVzLCBkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKGRhdGEudGV4dCgpLmluZGV4T2YodmVyYikgIT09IC0xKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAodXJsLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJldHVybiBhamF4KCdPUFRJT05TJywgdXJsLCBvcHRpb25zLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICh1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFqYXgoJ1BBVENIJywgdXJsLCBvcHRpb25zLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgcG9zdDogZnVuY3Rpb24gKHVybCwgb3B0aW9ucywgY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWpheCgnUE9TVCcsIHVybCwgb3B0aW9ucywgY2FsbGJhY2spO1xuICAgICAgICAgICAgfSxcbiAgICBcbiAgICAgICAgICAgIHB1dDogZnVuY3Rpb24gKHVybCwgb3B0aW9ucywgY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWpheCgnUFVUJywgdXJsLCBvcHRpb25zLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgdHJhY2U6IGZ1bmN0aW9uICh1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFqYXgoJ1RSQUNFJywgdXJsLCBvcHRpb25zLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgXG4gICAgXG4gICAgICAgIHZhciBtZXRob2RlID0gb3B0aW9ucy50eXBlID8gb3B0aW9ucy50eXBlLnRvTG93ZXJDYXNlKCkgOiAnZ2V0JztcbiAgICBcbiAgICAgICAgaHR0cFttZXRob2RlXShvcHRpb25zLnVybCwgb3B0aW9ucywgZnVuY3Rpb24gKHN0YXR1cywgZGF0YSkge1xuICAgICAgICAgICAgLy8gZmlsZTogcHJvdG9jb2wgYWx3YXlzIGdpdmVzIHN0YXR1cyBjb2RlIDAsIHNvIGNoZWNrIGZvciBkYXRhXG4gICAgICAgICAgICBpZiAoc3RhdHVzID09PSAyMDAgfHwgKHN0YXR1cyA9PT0gMCAmJiBkYXRhLnRleHQoKSkpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MoZGF0YS5qc29uKCksIHN0YXR1cywgbnVsbCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IoZGF0YS50ZXh0KCksIHN0YXR1cywgbnVsbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBcbiAgICB2YXIgX2Nvb2tpZSA9IHtcbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbihuYW1lLHZhbHVlLG1pbnV0ZXMsZG9tYWluKSB7XG4gICAgICAgICAgICB2YXIgZXhwaXJlcztcbiAgICAgICAgICAgIGlmIChtaW51dGVzKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGUgPSBuZXcgRGF0ZSgpO1xuICAgICAgICAgICAgICAgIGRhdGUuc2V0VGltZShkYXRlLmdldFRpbWUoKSsobWludXRlcyo2MCoxMDAwKSk7XG4gICAgICAgICAgICAgICAgZXhwaXJlcyA9IFwiOyBleHBpcmVzPVwiK2RhdGUudG9HTVRTdHJpbmcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgZXhwaXJlcyA9IFwiXCI7XG4gICAgICAgICAgICBkb21haW4gPSAoZG9tYWluKT8gXCJkb21haW49XCIrZG9tYWluK1wiO1wiIDogXCJcIjtcbiAgICAgICAgICAgIGRvY3VtZW50LmNvb2tpZSA9IG5hbWUrXCI9XCIrdmFsdWUrZXhwaXJlcytcIjtcIitkb21haW4rXCJwYXRoPS9cIjtcbiAgICAgICAgfSxcbiAgICBcbiAgICAgICAgcmVhZDogZnVuY3Rpb24obmFtZSkge1xuICAgICAgICAgICAgdmFyIG5hbWVFUSA9IG5hbWUgKyBcIj1cIjtcbiAgICAgICAgICAgIHZhciBjYSA9IGRvY3VtZW50LmNvb2tpZS5zcGxpdCgnOycpO1xuICAgICAgICAgICAgZm9yKHZhciBpPTA7aSA8IGNhLmxlbmd0aDtpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgYyA9IGNhW2ldO1xuICAgICAgICAgICAgICAgIHdoaWxlIChjLmNoYXJBdCgwKT09JyAnKSBjID0gYy5zdWJzdHJpbmcoMSxjLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgaWYgKGMuaW5kZXhPZihuYW1lRVEpID09PSAwKSByZXR1cm4gYy5zdWJzdHJpbmcobmFtZUVRLmxlbmd0aCxjLmxlbmd0aCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfSxcbiAgICBcbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbihuYW1lKSB7XG4gICAgICAgICAgICB0aGlzLmNyZWF0ZShuYW1lLFwiXCIsLTEpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBcbiAgICB2YXIgY29va2llX25vb3AgPSB7XG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24obmFtZSx2YWx1ZSxtaW51dGVzLGRvbWFpbikge30sXG4gICAgICAgIHJlYWQ6IGZ1bmN0aW9uKG5hbWUpIHsgcmV0dXJuIG51bGw7IH0sXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24obmFtZSkge31cbiAgICB9O1xuICAgIFxuICAgIFxuICAgIFxuICAgIC8vIG1vdmUgZGVwZW5kZW50IGZ1bmN0aW9ucyB0byBhIGNvbnRhaW5lciBzbyB0aGF0XG4gICAgLy8gdGhleSBjYW4gYmUgb3ZlcnJpZGVuIGVhc2llciBpbiBubyBqcXVlcnkgZW52aXJvbm1lbnQgKG5vZGUuanMpXG4gICAgdmFyIGYgPSB7XG4gICAgICAgIGV4dGVuZDogJCA/ICQuZXh0ZW5kIDogX2V4dGVuZCxcbiAgICAgICAgZGVlcEV4dGVuZDogX2RlZXBFeHRlbmQsXG4gICAgICAgIGVhY2g6ICQgPyAkLmVhY2ggOiBfZWFjaCxcbiAgICAgICAgYWpheDogJCA/ICQuYWpheCA6ICh0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnID8gX2FqYXggOiBmdW5jdGlvbigpIHt9KSxcbiAgICAgICAgY29va2llOiB0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnID8gX2Nvb2tpZSA6IGNvb2tpZV9ub29wLFxuICAgICAgICBkZXRlY3RMYW5ndWFnZTogZGV0ZWN0TGFuZ3VhZ2UsXG4gICAgICAgIGVzY2FwZTogX2VzY2FwZSxcbiAgICAgICAgbG9nOiBmdW5jdGlvbihzdHIpIHtcbiAgICAgICAgICAgIGlmIChvLmRlYnVnICYmIHR5cGVvZiBjb25zb2xlICE9PSBcInVuZGVmaW5lZFwiKSBjb25zb2xlLmxvZyhzdHIpO1xuICAgICAgICB9LFxuICAgICAgICBlcnJvcjogZnVuY3Rpb24oc3RyKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGNvbnNvbGUgIT09IFwidW5kZWZpbmVkXCIpIGNvbnNvbGUuZXJyb3Ioc3RyKTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0Q291bnR5SW5kZXhPZkxuZzogZnVuY3Rpb24obG5nKSB7XG4gICAgICAgICAgICB2YXIgbG5nX2luZGV4ID0gMDtcbiAgICAgICAgICAgIGlmIChsbmcgPT09ICduYi1OTycgfHwgbG5nID09PSAnbm4tTk8nIHx8IGxuZyA9PT0gJ25iLW5vJyB8fCBsbmcgPT09ICdubi1ubycpIGxuZ19pbmRleCA9IDE7XG4gICAgICAgICAgICByZXR1cm4gbG5nX2luZGV4O1xuICAgICAgICB9LFxuICAgICAgICB0b0xhbmd1YWdlczogZnVuY3Rpb24obG5nKSB7XG4gICAgICAgICAgICB2YXIgbG9nID0gdGhpcy5sb2c7XG4gICAgXG4gICAgICAgICAgICBmdW5jdGlvbiBhcHBseUNhc2UobCkge1xuICAgICAgICAgICAgICAgIHZhciByZXQgPSBsO1xuICAgIFxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgbCA9PT0gJ3N0cmluZycgJiYgbC5pbmRleE9mKCctJykgPiAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgcGFydHMgPSBsLnNwbGl0KCctJyk7XG4gICAgXG4gICAgICAgICAgICAgICAgICAgIHJldCA9IG8ubG93ZXJDYXNlTG5nID9cbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRzWzBdLnRvTG93ZXJDYXNlKCkgKyAgJy0nICsgcGFydHNbMV0udG9Mb3dlckNhc2UoKSA6XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJ0c1swXS50b0xvd2VyQ2FzZSgpICsgICctJyArIHBhcnRzWzFdLnRvVXBwZXJDYXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0ID0gby5sb3dlckNhc2VMbmcgPyBsLnRvTG93ZXJDYXNlKCkgOiBsO1xuICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0O1xuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgdmFyIGxhbmd1YWdlcyA9IFtdO1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IG8ubG5nV2hpdGVsaXN0IHx8IGZhbHNlO1xuICAgICAgICAgICAgdmFyIGFkZExhbmd1YWdlID0gZnVuY3Rpb24obGFuZ3VhZ2Upe1xuICAgICAgICAgICAgICAvL3JlamVjdCBsYW5ncyBub3Qgd2hpdGVsaXN0ZWRcbiAgICAgICAgICAgICAgaWYoIXdoaXRlbGlzdCB8fCB3aGl0ZWxpc3QuaW5kZXhPZihsYW5ndWFnZSkgPiAtMSl7XG4gICAgICAgICAgICAgICAgbGFuZ3VhZ2VzLnB1c2gobGFuZ3VhZ2UpO1xuICAgICAgICAgICAgICB9ZWxzZXtcbiAgICAgICAgICAgICAgICBsb2coJ3JlamVjdGluZyBub24td2hpdGVsaXN0ZWQgbGFuZ3VhZ2U6ICcgKyBsYW5ndWFnZSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAodHlwZW9mIGxuZyA9PT0gJ3N0cmluZycgJiYgbG5nLmluZGV4T2YoJy0nKSA+IC0xKSB7XG4gICAgICAgICAgICAgICAgdmFyIHBhcnRzID0gbG5nLnNwbGl0KCctJyk7XG4gICAgXG4gICAgICAgICAgICAgICAgaWYgKG8ubG9hZCAhPT0gJ3Vuc3BlY2lmaWMnKSBhZGRMYW5ndWFnZShhcHBseUNhc2UobG5nKSk7XG4gICAgICAgICAgICAgICAgaWYgKG8ubG9hZCAhPT0gJ2N1cnJlbnQnKSBhZGRMYW5ndWFnZShhcHBseUNhc2UocGFydHNbdGhpcy5nZXRDb3VudHlJbmRleE9mTG5nKGxuZyldKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGFkZExhbmd1YWdlKGFwcGx5Q2FzZShsbmcpKTtcbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgby5mYWxsYmFja0xuZy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChsYW5ndWFnZXMuaW5kZXhPZihvLmZhbGxiYWNrTG5nW2ldKSA9PT0gLTEgJiYgby5mYWxsYmFja0xuZ1tpXSkgbGFuZ3VhZ2VzLnB1c2goYXBwbHlDYXNlKG8uZmFsbGJhY2tMbmdbaV0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBsYW5ndWFnZXM7XG4gICAgICAgIH0sXG4gICAgICAgIHJlZ2V4RXNjYXBlOiBmdW5jdGlvbihzdHIpIHtcbiAgICAgICAgICAgIHJldHVybiBzdHIucmVwbGFjZSgvW1xcLVxcW1xcXVxcL1xce1xcfVxcKFxcKVxcKlxcK1xcP1xcLlxcXFxcXF5cXCRcXHxdL2csIFwiXFxcXCQmXCIpO1xuICAgICAgICB9LFxuICAgICAgICByZWdleFJlcGxhY2VtZW50RXNjYXBlOiBmdW5jdGlvbihzdHJPckZuKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHN0ck9yRm4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0ck9yRm4ucmVwbGFjZSgvXFwkL2csIFwiJCQkJFwiKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0ck9yRm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGxvY2FsU3RvcmFnZToge1xuICAgICAgICAgICAgc2V0SXRlbTogZnVuY3Rpb24oa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICh3aW5kb3cubG9jYWxTdG9yYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLnNldEl0ZW0oa2V5LCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGYubG9nKCdmYWlsZWQgdG8gc2V0IHZhbHVlIGZvciBrZXkgXCInICsga2V5ICsgJ1wiIHRvIGxvY2FsU3RvcmFnZS4nKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgZnVuY3Rpb24gaW5pdChvcHRpb25zLCBjYikge1xuICAgICAgICBcbiAgICAgICAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYiA9IG9wdGlvbnM7XG4gICAgICAgICAgICBvcHRpb25zID0ge307XG4gICAgICAgIH1cbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgIFxuICAgICAgICAvLyBvdmVycmlkZSBkZWZhdWx0cyB3aXRoIHBhc3NlZCBpbiBvcHRpb25zXG4gICAgICAgIGYuZXh0ZW5kKG8sIG9wdGlvbnMpO1xuICAgICAgICBkZWxldGUgby5maXhMbmc7IC8qIHBhc3NlZCBpbiBlYWNoIHRpbWUgKi9cbiAgICBcbiAgICAgICAgLy8gb3ZlcnJpZGUgZnVuY3Rpb25zOiAubG9nKCksIC5kZXRlY3RMYW5ndWFnZSgpLCBldGNcbiAgICAgICAgaWYgKG8uZnVuY3Rpb25zKSB7XG4gICAgICAgICAgICBkZWxldGUgby5mdW5jdGlvbnM7XG4gICAgICAgICAgICBmLmV4dGVuZChmLCBvcHRpb25zLmZ1bmN0aW9ucyk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gY3JlYXRlIG5hbWVzcGFjZSBvYmplY3QgaWYgbmFtZXNwYWNlIGlzIHBhc3NlZCBpbiBhcyBzdHJpbmdcbiAgICAgICAgaWYgKHR5cGVvZiBvLm5zID09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBvLm5zID0geyBuYW1lc3BhY2VzOiBbby5uc10sIGRlZmF1bHROczogby5uc307XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gZmFsbGJhY2sgbmFtZXNwYWNlc1xuICAgICAgICBpZiAodHlwZW9mIG8uZmFsbGJhY2tOUyA9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgby5mYWxsYmFja05TID0gW28uZmFsbGJhY2tOU107XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gZmFsbGJhY2sgbGFuZ3VhZ2VzXG4gICAgICAgIGlmICh0eXBlb2Ygby5mYWxsYmFja0xuZyA9PSAnc3RyaW5nJyB8fCB0eXBlb2Ygby5mYWxsYmFja0xuZyA9PSAnYm9vbGVhbicpIHtcbiAgICAgICAgICAgIG8uZmFsbGJhY2tMbmcgPSBbby5mYWxsYmFja0xuZ107XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gZXNjYXBlIHByZWZpeC9zdWZmaXhcbiAgICAgICAgby5pbnRlcnBvbGF0aW9uUHJlZml4RXNjYXBlZCA9IGYucmVnZXhFc2NhcGUoby5pbnRlcnBvbGF0aW9uUHJlZml4KTtcbiAgICAgICAgby5pbnRlcnBvbGF0aW9uU3VmZml4RXNjYXBlZCA9IGYucmVnZXhFc2NhcGUoby5pbnRlcnBvbGF0aW9uU3VmZml4KTtcbiAgICBcbiAgICAgICAgaWYgKCFvLmxuZykgby5sbmcgPSBmLmRldGVjdExhbmd1YWdlKCk7XG4gICAgXG4gICAgICAgIGxhbmd1YWdlcyA9IGYudG9MYW5ndWFnZXMoby5sbmcpO1xuICAgICAgICBjdXJyZW50TG5nID0gbGFuZ3VhZ2VzWzBdO1xuICAgICAgICBmLmxvZygnY3VycmVudExuZyBzZXQgdG86ICcgKyBjdXJyZW50TG5nKTtcbiAgICBcbiAgICAgICAgaWYgKG8udXNlQ29va2llICYmIGYuY29va2llLnJlYWQoby5jb29raWVOYW1lKSAhPT0gY3VycmVudExuZyl7IC8vY29va2llIGlzIHVuc2V0IG9yIGludmFsaWRcbiAgICAgICAgICAgIGYuY29va2llLmNyZWF0ZShvLmNvb2tpZU5hbWUsIGN1cnJlbnRMbmcsIG8uY29va2llRXhwaXJhdGlvblRpbWUsIG8uY29va2llRG9tYWluKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoby5kZXRlY3RMbmdGcm9tTG9jYWxTdG9yYWdlICYmIHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmxvY2FsU3RvcmFnZSkge1xuICAgICAgICAgICAgZi5sb2NhbFN0b3JhZ2Uuc2V0SXRlbSgnaTE4bmV4dF9sbmcnLCBjdXJyZW50TG5nKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICB2YXIgbG5nVHJhbnNsYXRlID0gdHJhbnNsYXRlO1xuICAgICAgICBpZiAob3B0aW9ucy5maXhMbmcpIHtcbiAgICAgICAgICAgIGxuZ1RyYW5zbGF0ZSA9IGZ1bmN0aW9uKGtleSwgb3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMubG5nID0gb3B0aW9ucy5sbmcgfHwgbG5nVHJhbnNsYXRlLmxuZztcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJhbnNsYXRlKGtleSwgb3B0aW9ucyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgbG5nVHJhbnNsYXRlLmxuZyA9IGN1cnJlbnRMbmc7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgcGx1cmFsRXh0ZW5zaW9ucy5zZXRDdXJyZW50TG5nKGN1cnJlbnRMbmcpO1xuICAgIFxuICAgICAgICAvLyBhZGQgSlF1ZXJ5IGV4dGVuc2lvbnNcbiAgICAgICAgaWYgKCQgJiYgby5zZXRKcXVlcnlFeHQpIGFkZEpxdWVyeUZ1bmN0KCk7XG4gICAgXG4gICAgICAgIC8vIGpRdWVyeSBkZWZlcnJlZFxuICAgICAgICB2YXIgZGVmZXJyZWQ7XG4gICAgICAgIGlmICgkICYmICQuRGVmZXJyZWQpIHtcbiAgICAgICAgICAgIGRlZmVycmVkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIC8vIHJldHVybiBpbW1pZGlhdGx5IGlmIHJlcyBhcmUgcGFzc2VkIGluXG4gICAgICAgIGlmIChvLnJlc1N0b3JlKSB7XG4gICAgICAgICAgICByZXNTdG9yZSA9IG8ucmVzU3RvcmU7XG4gICAgICAgICAgICBpbml0aWFsaXplZCA9IHRydWU7XG4gICAgICAgICAgICBpZiAoY2IpIGNiKGxuZ1RyYW5zbGF0ZSk7XG4gICAgICAgICAgICBpZiAoZGVmZXJyZWQpIGRlZmVycmVkLnJlc29sdmUobG5nVHJhbnNsYXRlKTtcbiAgICAgICAgICAgIGlmIChkZWZlcnJlZCkgcmV0dXJuIGRlZmVycmVkLnByb21pc2UoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBsYW5ndWFnZXMgdG8gbG9hZFxuICAgICAgICB2YXIgbG5nc1RvTG9hZCA9IGYudG9MYW5ndWFnZXMoby5sbmcpO1xuICAgICAgICBpZiAodHlwZW9mIG8ucHJlbG9hZCA9PT0gJ3N0cmluZycpIG8ucHJlbG9hZCA9IFtvLnByZWxvYWRdO1xuICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IG8ucHJlbG9hZC5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBwcmVzID0gZi50b0xhbmd1YWdlcyhvLnByZWxvYWRbaV0pO1xuICAgICAgICAgICAgZm9yICh2YXIgeSA9IDAsIGxlbiA9IHByZXMubGVuZ3RoOyB5IDwgbGVuOyB5KyspIHtcbiAgICAgICAgICAgICAgICBpZiAobG5nc1RvTG9hZC5pbmRleE9mKHByZXNbeV0pIDwgMCkge1xuICAgICAgICAgICAgICAgICAgICBsbmdzVG9Mb2FkLnB1c2gocHJlc1t5XSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIC8vIGVsc2UgbG9hZCB0aGVtXG4gICAgICAgIGkxOG4uc3luYy5sb2FkKGxuZ3NUb0xvYWQsIG8sIGZ1bmN0aW9uKGVyciwgc3RvcmUpIHtcbiAgICAgICAgICAgIHJlc1N0b3JlID0gc3RvcmU7XG4gICAgICAgICAgICBpbml0aWFsaXplZCA9IHRydWU7XG4gICAgXG4gICAgICAgICAgICBpZiAoY2IpIGNiKGxuZ1RyYW5zbGF0ZSk7XG4gICAgICAgICAgICBpZiAoZGVmZXJyZWQpIGRlZmVycmVkLnJlc29sdmUobG5nVHJhbnNsYXRlKTtcbiAgICAgICAgfSk7XG4gICAgXG4gICAgICAgIGlmIChkZWZlcnJlZCkgcmV0dXJuIGRlZmVycmVkLnByb21pc2UoKTtcbiAgICB9XG4gICAgZnVuY3Rpb24gcHJlbG9hZChsbmdzLCBjYikge1xuICAgICAgICBpZiAodHlwZW9mIGxuZ3MgPT09ICdzdHJpbmcnKSBsbmdzID0gW2xuZ3NdO1xuICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGxuZ3MubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoby5wcmVsb2FkLmluZGV4T2YobG5nc1tpXSkgPCAwKSB7XG4gICAgICAgICAgICAgICAgby5wcmVsb2FkLnB1c2gobG5nc1tpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGluaXQoY2IpO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBhZGRSZXNvdXJjZUJ1bmRsZShsbmcsIG5zLCByZXNvdXJjZXMsIGRlZXApIHtcbiAgICAgICAgaWYgKHR5cGVvZiBucyAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHJlc291cmNlcyA9IG5zO1xuICAgICAgICAgICAgbnMgPSBvLm5zLmRlZmF1bHROcztcbiAgICAgICAgfSBlbHNlIGlmIChvLm5zLm5hbWVzcGFjZXMuaW5kZXhPZihucykgPCAwKSB7XG4gICAgICAgICAgICBvLm5zLm5hbWVzcGFjZXMucHVzaChucyk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgcmVzU3RvcmVbbG5nXSA9IHJlc1N0b3JlW2xuZ10gfHwge307XG4gICAgICAgIHJlc1N0b3JlW2xuZ11bbnNdID0gcmVzU3RvcmVbbG5nXVtuc10gfHwge307XG4gICAgXG4gICAgICAgIGlmIChkZWVwKSB7XG4gICAgICAgICAgICBmLmRlZXBFeHRlbmQocmVzU3RvcmVbbG5nXVtuc10sIHJlc291cmNlcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmLmV4dGVuZChyZXNTdG9yZVtsbmddW25zXSwgcmVzb3VyY2VzKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBoYXNSZXNvdXJjZUJ1bmRsZShsbmcsIG5zKSB7XG4gICAgICAgIGlmICh0eXBlb2YgbnMgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBucyA9IG8ubnMuZGVmYXVsdE5zO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIHJlc1N0b3JlW2xuZ10gPSByZXNTdG9yZVtsbmddIHx8IHt9O1xuICAgICAgICB2YXIgcmVzID0gcmVzU3RvcmVbbG5nXVtuc10gfHwge307XG4gICAgXG4gICAgICAgIHZhciBoYXNWYWx1ZXMgPSBmYWxzZTtcbiAgICAgICAgZm9yKHZhciBwcm9wIGluIHJlcykge1xuICAgICAgICAgICAgaWYgKHJlcy5oYXNPd25Qcm9wZXJ0eShwcm9wKSkge1xuICAgICAgICAgICAgICAgIGhhc1ZhbHVlcyA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgcmV0dXJuIGhhc1ZhbHVlcztcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gcmVtb3ZlUmVzb3VyY2VCdW5kbGUobG5nLCBucykge1xuICAgICAgICBpZiAodHlwZW9mIG5zICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgbnMgPSBvLm5zLmRlZmF1bHROcztcbiAgICAgICAgfVxuICAgIFxuICAgICAgICByZXNTdG9yZVtsbmddID0gcmVzU3RvcmVbbG5nXSB8fCB7fTtcbiAgICAgICAgcmVzU3RvcmVbbG5nXVtuc10gPSB7fTtcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gYWRkUmVzb3VyY2UobG5nLCBucywga2V5LCB2YWx1ZSkge1xuICAgICAgICBpZiAodHlwZW9mIG5zICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgcmVzb3VyY2UgPSBucztcbiAgICAgICAgICAgIG5zID0gby5ucy5kZWZhdWx0TnM7XG4gICAgICAgIH0gZWxzZSBpZiAoby5ucy5uYW1lc3BhY2VzLmluZGV4T2YobnMpIDwgMCkge1xuICAgICAgICAgICAgby5ucy5uYW1lc3BhY2VzLnB1c2gobnMpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIHJlc1N0b3JlW2xuZ10gPSByZXNTdG9yZVtsbmddIHx8IHt9O1xuICAgICAgICByZXNTdG9yZVtsbmddW25zXSA9IHJlc1N0b3JlW2xuZ11bbnNdIHx8IHt9O1xuICAgIFxuICAgICAgICB2YXIga2V5cyA9IGtleS5zcGxpdChvLmtleXNlcGFyYXRvcik7XG4gICAgICAgIHZhciB4ID0gMDtcbiAgICAgICAgdmFyIG5vZGUgPSByZXNTdG9yZVtsbmddW25zXTtcbiAgICAgICAgdmFyIG9yaWdSZWYgPSBub2RlO1xuICAgIFxuICAgICAgICB3aGlsZSAoa2V5c1t4XSkge1xuICAgICAgICAgICAgaWYgKHggPT0ga2V5cy5sZW5ndGggLSAxKVxuICAgICAgICAgICAgICAgIG5vZGVba2V5c1t4XV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChub2RlW2tleXNbeF1dID09IG51bGwpXG4gICAgICAgICAgICAgICAgICAgIG5vZGVba2V5c1t4XV0gPSB7fTtcbiAgICBcbiAgICAgICAgICAgICAgICBub2RlID0gbm9kZVtrZXlzW3hdXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHgrKztcbiAgICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBhZGRSZXNvdXJjZXMobG5nLCBucywgcmVzb3VyY2VzKSB7XG4gICAgICAgIGlmICh0eXBlb2YgbnMgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXNvdXJjZSA9IG5zO1xuICAgICAgICAgICAgbnMgPSBvLm5zLmRlZmF1bHROcztcbiAgICAgICAgfSBlbHNlIGlmIChvLm5zLm5hbWVzcGFjZXMuaW5kZXhPZihucykgPCAwKSB7XG4gICAgICAgICAgICBvLm5zLm5hbWVzcGFjZXMucHVzaChucyk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgZm9yICh2YXIgbSBpbiByZXNvdXJjZXMpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcmVzb3VyY2VzW21dID09PSAnc3RyaW5nJykgYWRkUmVzb3VyY2UobG5nLCBucywgbSwgcmVzb3VyY2VzW21dKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBzZXREZWZhdWx0TmFtZXNwYWNlKG5zKSB7XG4gICAgICAgIG8ubnMuZGVmYXVsdE5zID0gbnM7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIGxvYWROYW1lc3BhY2UobmFtZXNwYWNlLCBjYikge1xuICAgICAgICBsb2FkTmFtZXNwYWNlcyhbbmFtZXNwYWNlXSwgY2IpO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBsb2FkTmFtZXNwYWNlcyhuYW1lc3BhY2VzLCBjYikge1xuICAgICAgICB2YXIgb3B0cyA9IHtcbiAgICAgICAgICAgIGR5bmFtaWNMb2FkOiBvLmR5bmFtaWNMb2FkLFxuICAgICAgICAgICAgcmVzR2V0UGF0aDogby5yZXNHZXRQYXRoLFxuICAgICAgICAgICAgZ2V0QXN5bmM6IG8uZ2V0QXN5bmMsXG4gICAgICAgICAgICBjdXN0b21Mb2FkOiBvLmN1c3RvbUxvYWQsXG4gICAgICAgICAgICBuczogeyBuYW1lc3BhY2VzOiBuYW1lc3BhY2VzLCBkZWZhdWx0TnM6ICcnfSAvKiBuZXcgbmFtZXNwYWNlcyB0byBsb2FkICovXG4gICAgICAgIH07XG4gICAgXG4gICAgICAgIC8vIGxhbmd1YWdlcyB0byBsb2FkXG4gICAgICAgIHZhciBsbmdzVG9Mb2FkID0gZi50b0xhbmd1YWdlcyhvLmxuZyk7XG4gICAgICAgIGlmICh0eXBlb2Ygby5wcmVsb2FkID09PSAnc3RyaW5nJykgby5wcmVsb2FkID0gW28ucHJlbG9hZF07XG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gby5wcmVsb2FkLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgdmFyIHByZXMgPSBmLnRvTGFuZ3VhZ2VzKG8ucHJlbG9hZFtpXSk7XG4gICAgICAgICAgICBmb3IgKHZhciB5ID0gMCwgbGVuID0gcHJlcy5sZW5ndGg7IHkgPCBsZW47IHkrKykge1xuICAgICAgICAgICAgICAgIGlmIChsbmdzVG9Mb2FkLmluZGV4T2YocHJlc1t5XSkgPCAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGxuZ3NUb0xvYWQucHVzaChwcmVzW3ldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gY2hlY2sgaWYgd2UgaGF2ZSB0byBsb2FkXG4gICAgICAgIHZhciBsbmdOZWVkTG9hZCA9IFtdO1xuICAgICAgICBmb3IgKHZhciBhID0gMCwgbGVuQSA9IGxuZ3NUb0xvYWQubGVuZ3RoOyBhIDwgbGVuQTsgYSsrKSB7XG4gICAgICAgICAgICB2YXIgbmVlZExvYWQgPSBmYWxzZTtcbiAgICAgICAgICAgIHZhciByZXNTZXQgPSByZXNTdG9yZVtsbmdzVG9Mb2FkW2FdXTtcbiAgICAgICAgICAgIGlmIChyZXNTZXQpIHtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBiID0gMCwgbGVuQiA9IG5hbWVzcGFjZXMubGVuZ3RoOyBiIDwgbGVuQjsgYisrKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghcmVzU2V0W25hbWVzcGFjZXNbYl1dKSBuZWVkTG9hZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZWVkTG9hZCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICBpZiAobmVlZExvYWQpIGxuZ05lZWRMb2FkLnB1c2gobG5nc1RvTG9hZFthXSk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKGxuZ05lZWRMb2FkLmxlbmd0aCkge1xuICAgICAgICAgICAgaTE4bi5zeW5jLl9mZXRjaChsbmdOZWVkTG9hZCwgb3B0cywgZnVuY3Rpb24oZXJyLCBzdG9yZSkge1xuICAgICAgICAgICAgICAgIHZhciB0b2RvID0gbmFtZXNwYWNlcy5sZW5ndGggKiBsbmdOZWVkTG9hZC5sZW5ndGg7XG4gICAgXG4gICAgICAgICAgICAgICAgLy8gbG9hZCBlYWNoIGZpbGUgaW5kaXZpZHVhbFxuICAgICAgICAgICAgICAgIGYuZWFjaChuYW1lc3BhY2VzLCBmdW5jdGlvbihuc0luZGV4LCBuc1ZhbHVlKSB7XG4gICAgXG4gICAgICAgICAgICAgICAgICAgIC8vIGFwcGVuZCBuYW1lc3BhY2UgdG8gbmFtZXNwYWNlIGFycmF5XG4gICAgICAgICAgICAgICAgICAgIGlmIChvLm5zLm5hbWVzcGFjZXMuaW5kZXhPZihuc1ZhbHVlKSA8IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG8ubnMubmFtZXNwYWNlcy5wdXNoKG5zVmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgICAgIGYuZWFjaChsbmdOZWVkTG9hZCwgZnVuY3Rpb24obG5nSW5kZXgsIGxuZ1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNTdG9yZVtsbmdWYWx1ZV0gPSByZXNTdG9yZVtsbmdWYWx1ZV0gfHwge307XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNTdG9yZVtsbmdWYWx1ZV1bbnNWYWx1ZV0gPSBzdG9yZVtsbmdWYWx1ZV1bbnNWYWx1ZV07XG4gICAgXG4gICAgICAgICAgICAgICAgICAgICAgICB0b2RvLS07IC8vIHdhaXQgZm9yIGFsbCBkb25lIGJlZm9yIGNhbGxiYWNrXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodG9kbyA9PT0gMCAmJiBjYikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChvLnVzZUxvY2FsU3RvcmFnZSkgaTE4bi5zeW5jLl9zdG9yZUxvY2FsKHJlc1N0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGNiKSBjYigpO1xuICAgICAgICB9XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIHNldExuZyhsbmcsIG9wdGlvbnMsIGNiKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY2IgPSBvcHRpb25zO1xuICAgICAgICAgICAgb3B0aW9ucyA9IHt9O1xuICAgICAgICB9IGVsc2UgaWYgKCFvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge307XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgb3B0aW9ucy5sbmcgPSBsbmc7XG4gICAgICAgIHJldHVybiBpbml0KG9wdGlvbnMsIGNiKTtcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gbG5nKCkge1xuICAgICAgICByZXR1cm4gY3VycmVudExuZztcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gcmVsb2FkKGNiKSB7XG4gICAgICAgIHJlc1N0b3JlID0ge307XG4gICAgICAgIHNldExuZyhjdXJyZW50TG5nLCBjYik7XG4gICAgfVxuICAgIGZ1bmN0aW9uIGFkZEpxdWVyeUZ1bmN0KCkge1xuICAgICAgICAvLyAkLnQgc2hvcnRjdXRcbiAgICAgICAgJC50ID0gJC50IHx8IHRyYW5zbGF0ZTtcbiAgICBcbiAgICAgICAgZnVuY3Rpb24gcGFyc2UoZWxlLCBrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChrZXkubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgXG4gICAgICAgICAgICB2YXIgYXR0ciA9ICd0ZXh0JztcbiAgICBcbiAgICAgICAgICAgIGlmIChrZXkuaW5kZXhPZignWycpID09PSAwKSB7XG4gICAgICAgICAgICAgICAgdmFyIHBhcnRzID0ga2V5LnNwbGl0KCddJyk7XG4gICAgICAgICAgICAgICAga2V5ID0gcGFydHNbMV07XG4gICAgICAgICAgICAgICAgYXR0ciA9IHBhcnRzWzBdLnN1YnN0cigxLCBwYXJ0c1swXS5sZW5ndGgtMSk7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICBpZiAoa2V5LmluZGV4T2YoJzsnKSA9PT0ga2V5Lmxlbmd0aC0xKSB7XG4gICAgICAgICAgICAgICAga2V5ID0ga2V5LnN1YnN0cigwLCBrZXkubGVuZ3RoLTIpO1xuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgdmFyIG9wdGlvbnNUb1VzZTtcbiAgICAgICAgICAgIGlmIChhdHRyID09PSAnaHRtbCcpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zVG9Vc2UgPSBvLmRlZmF1bHRWYWx1ZUZyb21Db250ZW50ID8gJC5leHRlbmQoeyBkZWZhdWx0VmFsdWU6IGVsZS5odG1sKCkgfSwgb3B0aW9ucykgOiBvcHRpb25zO1xuICAgICAgICAgICAgICAgIGVsZS5odG1sKCQudChrZXksIG9wdGlvbnNUb1VzZSkpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChhdHRyID09PSAndGV4dCcpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zVG9Vc2UgPSBvLmRlZmF1bHRWYWx1ZUZyb21Db250ZW50ID8gJC5leHRlbmQoeyBkZWZhdWx0VmFsdWU6IGVsZS50ZXh0KCkgfSwgb3B0aW9ucykgOiBvcHRpb25zO1xuICAgICAgICAgICAgICAgIGVsZS50ZXh0KCQudChrZXksIG9wdGlvbnNUb1VzZSkpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChhdHRyID09PSAncHJlcGVuZCcpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zVG9Vc2UgPSBvLmRlZmF1bHRWYWx1ZUZyb21Db250ZW50ID8gJC5leHRlbmQoeyBkZWZhdWx0VmFsdWU6IGVsZS5odG1sKCkgfSwgb3B0aW9ucykgOiBvcHRpb25zO1xuICAgICAgICAgICAgICAgIGVsZS5wcmVwZW5kKCQudChrZXksIG9wdGlvbnNUb1VzZSkpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChhdHRyID09PSAnYXBwZW5kJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNUb1VzZSA9IG8uZGVmYXVsdFZhbHVlRnJvbUNvbnRlbnQgPyAkLmV4dGVuZCh7IGRlZmF1bHRWYWx1ZTogZWxlLmh0bWwoKSB9LCBvcHRpb25zKSA6IG9wdGlvbnM7XG4gICAgICAgICAgICAgICAgZWxlLmFwcGVuZCgkLnQoa2V5LCBvcHRpb25zVG9Vc2UpKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXR0ci5pbmRleE9mKFwiZGF0YS1cIikgPT09IDApIHtcbiAgICAgICAgICAgICAgICB2YXIgZGF0YUF0dHIgPSBhdHRyLnN1YnN0cigoXCJkYXRhLVwiKS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIG9wdGlvbnNUb1VzZSA9IG8uZGVmYXVsdFZhbHVlRnJvbUNvbnRlbnQgPyAkLmV4dGVuZCh7IGRlZmF1bHRWYWx1ZTogZWxlLmRhdGEoZGF0YUF0dHIpIH0sIG9wdGlvbnMpIDogb3B0aW9ucztcbiAgICAgICAgICAgICAgICB2YXIgdHJhbnNsYXRlZCA9ICQudChrZXksIG9wdGlvbnNUb1VzZSk7XG4gICAgICAgICAgICAgICAgLy93ZSBjaGFuZ2UgaW50byB0aGUgZGF0YSBjYWNoZVxuICAgICAgICAgICAgICAgIGVsZS5kYXRhKGRhdGFBdHRyLCB0cmFuc2xhdGVkKTtcbiAgICAgICAgICAgICAgICAvL3dlIGNoYW5nZSBpbnRvIHRoZSBkb21cbiAgICAgICAgICAgICAgICBlbGUuYXR0cihhdHRyLCB0cmFuc2xhdGVkKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1RvVXNlID0gby5kZWZhdWx0VmFsdWVGcm9tQ29udGVudCA/ICQuZXh0ZW5kKHsgZGVmYXVsdFZhbHVlOiBlbGUuYXR0cihhdHRyKSB9LCBvcHRpb25zKSA6IG9wdGlvbnM7XG4gICAgICAgICAgICAgICAgZWxlLmF0dHIoYXR0ciwgJC50KGtleSwgb3B0aW9uc1RvVXNlKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgZnVuY3Rpb24gbG9jYWxpemUoZWxlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIga2V5ID0gZWxlLmF0dHIoby5zZWxlY3RvckF0dHIpO1xuICAgICAgICAgICAgaWYgKCFrZXkgJiYgdHlwZW9mIGtleSAhPT0gJ3VuZGVmaW5lZCcgJiYga2V5ICE9PSBmYWxzZSkga2V5ID0gZWxlLnRleHQoKSB8fCBlbGUudmFsKCk7XG4gICAgICAgICAgICBpZiAoIWtleSkgcmV0dXJuO1xuICAgIFxuICAgICAgICAgICAgdmFyIHRhcmdldCA9IGVsZVxuICAgICAgICAgICAgICAsIHRhcmdldFNlbGVjdG9yID0gZWxlLmRhdGEoXCJpMThuLXRhcmdldFwiKTtcbiAgICAgICAgICAgIGlmICh0YXJnZXRTZWxlY3Rvcikge1xuICAgICAgICAgICAgICAgIHRhcmdldCA9IGVsZS5maW5kKHRhcmdldFNlbGVjdG9yKSB8fCBlbGU7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICBpZiAoIW9wdGlvbnMgJiYgby51c2VEYXRhQXR0ck9wdGlvbnMgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gZWxlLmRhdGEoXCJpMThuLW9wdGlvbnNcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICBcbiAgICAgICAgICAgIGlmIChrZXkuaW5kZXhPZignOycpID49IDApIHtcbiAgICAgICAgICAgICAgICB2YXIga2V5cyA9IGtleS5zcGxpdCgnOycpO1xuICAgIFxuICAgICAgICAgICAgICAgICQuZWFjaChrZXlzLCBmdW5jdGlvbihtLCBrKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChrICE9PSAnJykgcGFyc2UodGFyZ2V0LCBrLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICBcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcGFyc2UodGFyZ2V0LCBrZXksIG9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgaWYgKG8udXNlRGF0YUF0dHJPcHRpb25zID09PSB0cnVlKSBlbGUuZGF0YShcImkxOG4tb3B0aW9uc1wiLCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBmblxuICAgICAgICAkLmZuLmkxOG4gPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAvLyBsb2NhbGl6ZSBlbGVtZW50IGl0c2VsZlxuICAgICAgICAgICAgICAgIGxvY2FsaXplKCQodGhpcyksIG9wdGlvbnMpO1xuICAgIFxuICAgICAgICAgICAgICAgIC8vIGxvY2FsaXplIGNoaWxkc1xuICAgICAgICAgICAgICAgIHZhciBlbGVtZW50cyA9ICAkKHRoaXMpLmZpbmQoJ1snICsgby5zZWxlY3RvckF0dHIgKyAnXScpO1xuICAgICAgICAgICAgICAgIGVsZW1lbnRzLmVhY2goZnVuY3Rpb24oKSB7IFxuICAgICAgICAgICAgICAgICAgICBsb2NhbGl6ZSgkKHRoaXMpLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuICAgIH1cbiAgICBmdW5jdGlvbiBhcHBseVJlcGxhY2VtZW50KHN0ciwgcmVwbGFjZW1lbnRIYXNoLCBuZXN0ZWRLZXksIG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKCFzdHIpIHJldHVybiBzdHI7XG4gICAgXG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHJlcGxhY2VtZW50SGFzaDsgLy8gZmlyc3QgY2FsbCB1c2VzIHJlcGxhY2VtZW50IGhhc2ggY29tYmluZWQgd2l0aCBvcHRpb25zXG4gICAgICAgIGlmIChzdHIuaW5kZXhPZihvcHRpb25zLmludGVycG9sYXRpb25QcmVmaXggfHwgby5pbnRlcnBvbGF0aW9uUHJlZml4KSA8IDApIHJldHVybiBzdHI7XG4gICAgXG4gICAgICAgIHZhciBwcmVmaXggPSBvcHRpb25zLmludGVycG9sYXRpb25QcmVmaXggPyBmLnJlZ2V4RXNjYXBlKG9wdGlvbnMuaW50ZXJwb2xhdGlvblByZWZpeCkgOiBvLmludGVycG9sYXRpb25QcmVmaXhFc2NhcGVkXG4gICAgICAgICAgLCBzdWZmaXggPSBvcHRpb25zLmludGVycG9sYXRpb25TdWZmaXggPyBmLnJlZ2V4RXNjYXBlKG9wdGlvbnMuaW50ZXJwb2xhdGlvblN1ZmZpeCkgOiBvLmludGVycG9sYXRpb25TdWZmaXhFc2NhcGVkXG4gICAgICAgICAgLCB1bkVzY2FwaW5nU3VmZml4ID0gJ0hUTUwnK3N1ZmZpeDtcbiAgICBcbiAgICAgICAgdmFyIGhhc2ggPSByZXBsYWNlbWVudEhhc2gucmVwbGFjZSAmJiB0eXBlb2YgcmVwbGFjZW1lbnRIYXNoLnJlcGxhY2UgPT09ICdvYmplY3QnID8gcmVwbGFjZW1lbnRIYXNoLnJlcGxhY2UgOiByZXBsYWNlbWVudEhhc2g7XG4gICAgICAgIGYuZWFjaChoYXNoLCBmdW5jdGlvbihrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICB2YXIgbmV4dEtleSA9IG5lc3RlZEtleSA/IG5lc3RlZEtleSArIG8ua2V5c2VwYXJhdG9yICsga2V5IDoga2V5O1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBzdHIgPSBhcHBseVJlcGxhY2VtZW50KHN0ciwgdmFsdWUsIG5leHRLZXksIG9wdGlvbnMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5lc2NhcGVJbnRlcnBvbGF0aW9uIHx8IG8uZXNjYXBlSW50ZXJwb2xhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICBzdHIgPSBzdHIucmVwbGFjZShuZXcgUmVnRXhwKFtwcmVmaXgsIG5leHRLZXksIHVuRXNjYXBpbmdTdWZmaXhdLmpvaW4oJycpLCAnZycpLCBmLnJlZ2V4UmVwbGFjZW1lbnRFc2NhcGUodmFsdWUpKTtcbiAgICAgICAgICAgICAgICAgICAgc3RyID0gc3RyLnJlcGxhY2UobmV3IFJlZ0V4cChbcHJlZml4LCBuZXh0S2V5LCBzdWZmaXhdLmpvaW4oJycpLCAnZycpLCBmLnJlZ2V4UmVwbGFjZW1lbnRFc2NhcGUoZi5lc2NhcGUodmFsdWUpKSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyID0gc3RyLnJlcGxhY2UobmV3IFJlZ0V4cChbcHJlZml4LCBuZXh0S2V5LCBzdWZmaXhdLmpvaW4oJycpLCAnZycpLCBmLnJlZ2V4UmVwbGFjZW1lbnRFc2NhcGUodmFsdWUpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gc3RyID0gb3B0aW9ucy5lc2NhcGVJbnRlcnBvbGF0aW9uO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG4gICAgXG4gICAgLy8gYXBwZW5kIGl0IHRvIGZ1bmN0aW9uc1xuICAgIGYuYXBwbHlSZXBsYWNlbWVudCA9IGFwcGx5UmVwbGFjZW1lbnQ7XG4gICAgXG4gICAgZnVuY3Rpb24gYXBwbHlSZXVzZSh0cmFuc2xhdGVkLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBjb21tYSA9ICcsJztcbiAgICAgICAgdmFyIG9wdGlvbnNfb3BlbiA9ICd7JztcbiAgICAgICAgdmFyIG9wdGlvbnNfY2xvc2UgPSAnfSc7XG4gICAgXG4gICAgICAgIHZhciBvcHRzID0gZi5leHRlbmQoe30sIG9wdGlvbnMpO1xuICAgICAgICBkZWxldGUgb3B0cy5wb3N0UHJvY2VzcztcbiAgICBcbiAgICAgICAgd2hpbGUgKHRyYW5zbGF0ZWQuaW5kZXhPZihvLnJldXNlUHJlZml4KSAhPSAtMSkge1xuICAgICAgICAgICAgcmVwbGFjZW1lbnRDb3VudGVyKys7XG4gICAgICAgICAgICBpZiAocmVwbGFjZW1lbnRDb3VudGVyID4gby5tYXhSZWN1cnNpb24pIHsgYnJlYWs7IH0gLy8gc2FmZXR5IG5ldCBmb3IgdG9vIG11Y2ggcmVjdXJzaW9uXG4gICAgICAgICAgICB2YXIgaW5kZXhfb2Zfb3BlbmluZyA9IHRyYW5zbGF0ZWQubGFzdEluZGV4T2Yoby5yZXVzZVByZWZpeCk7XG4gICAgICAgICAgICB2YXIgaW5kZXhfb2ZfZW5kX29mX2Nsb3NpbmcgPSB0cmFuc2xhdGVkLmluZGV4T2Yoby5yZXVzZVN1ZmZpeCwgaW5kZXhfb2Zfb3BlbmluZykgKyBvLnJldXNlU3VmZml4Lmxlbmd0aDtcbiAgICAgICAgICAgIHZhciB0b2tlbiA9IHRyYW5zbGF0ZWQuc3Vic3RyaW5nKGluZGV4X29mX29wZW5pbmcsIGluZGV4X29mX2VuZF9vZl9jbG9zaW5nKTtcbiAgICAgICAgICAgIHZhciB0b2tlbl93aXRob3V0X3N5bWJvbHMgPSB0b2tlbi5yZXBsYWNlKG8ucmV1c2VQcmVmaXgsICcnKS5yZXBsYWNlKG8ucmV1c2VTdWZmaXgsICcnKTtcbiAgICBcbiAgICAgICAgICAgIGlmIChpbmRleF9vZl9lbmRfb2ZfY2xvc2luZyA8PSBpbmRleF9vZl9vcGVuaW5nKSB7XG4gICAgICAgICAgICAgICAgZi5lcnJvcigndGhlcmUgaXMgYW4gbWlzc2luZyBjbG9zaW5nIGluIGZvbGxvd2luZyB0cmFuc2xhdGlvbiB2YWx1ZScsIHRyYW5zbGF0ZWQpO1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgIGlmICh0b2tlbl93aXRob3V0X3N5bWJvbHMuaW5kZXhPZihjb21tYSkgIT0gLTEpIHtcbiAgICAgICAgICAgICAgICB2YXIgaW5kZXhfb2ZfdG9rZW5fZW5kX29mX2Nsb3NpbmcgPSB0b2tlbl93aXRob3V0X3N5bWJvbHMuaW5kZXhPZihjb21tYSk7XG4gICAgICAgICAgICAgICAgaWYgKHRva2VuX3dpdGhvdXRfc3ltYm9scy5pbmRleE9mKG9wdGlvbnNfb3BlbiwgaW5kZXhfb2ZfdG9rZW5fZW5kX29mX2Nsb3NpbmcpICE9IC0xICYmIHRva2VuX3dpdGhvdXRfc3ltYm9scy5pbmRleE9mKG9wdGlvbnNfY2xvc2UsIGluZGV4X29mX3Rva2VuX2VuZF9vZl9jbG9zaW5nKSAhPSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgaW5kZXhfb2Zfb3B0c19vcGVuaW5nID0gdG9rZW5fd2l0aG91dF9zeW1ib2xzLmluZGV4T2Yob3B0aW9uc19vcGVuLCBpbmRleF9vZl90b2tlbl9lbmRfb2ZfY2xvc2luZyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmRleF9vZl9vcHRzX2VuZF9vZl9jbG9zaW5nID0gdG9rZW5fd2l0aG91dF9zeW1ib2xzLmluZGV4T2Yob3B0aW9uc19jbG9zZSwgaW5kZXhfb2Zfb3B0c19vcGVuaW5nKSArIG9wdGlvbnNfY2xvc2UubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb3B0cyA9IGYuZXh0ZW5kKG9wdHMsIEpTT04ucGFyc2UodG9rZW5fd2l0aG91dF9zeW1ib2xzLnN1YnN0cmluZyhpbmRleF9vZl9vcHRzX29wZW5pbmcsIGluZGV4X29mX29wdHNfZW5kX29mX2Nsb3NpbmcpKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0b2tlbl93aXRob3V0X3N5bWJvbHMgPSB0b2tlbl93aXRob3V0X3N5bWJvbHMuc3Vic3RyaW5nKDAsIGluZGV4X29mX3Rva2VuX2VuZF9vZl9jbG9zaW5nKTtcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgdmFyIHRyYW5zbGF0ZWRfdG9rZW4gPSBfdHJhbnNsYXRlKHRva2VuX3dpdGhvdXRfc3ltYm9scywgb3B0cyk7XG4gICAgICAgICAgICB0cmFuc2xhdGVkID0gdHJhbnNsYXRlZC5yZXBsYWNlKHRva2VuLCBmLnJlZ2V4UmVwbGFjZW1lbnRFc2NhcGUodHJhbnNsYXRlZF90b2tlbikpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cmFuc2xhdGVkO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBoYXNDb250ZXh0KG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIChvcHRpb25zLmNvbnRleHQgJiYgKHR5cGVvZiBvcHRpb25zLmNvbnRleHQgPT0gJ3N0cmluZycgfHwgdHlwZW9mIG9wdGlvbnMuY29udGV4dCA9PSAnbnVtYmVyJykpO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBuZWVkc1BsdXJhbChvcHRpb25zLCBsbmcpIHtcbiAgICAgICAgcmV0dXJuIChvcHRpb25zLmNvdW50ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIG9wdGlvbnMuY291bnQgIT0gJ3N0cmluZycvKiAmJiBwbHVyYWxFeHRlbnNpb25zLm5lZWRzUGx1cmFsKGxuZywgb3B0aW9ucy5jb3VudCkqLyk7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIG5lZWRzSW5kZWZpbml0ZUFydGljbGUob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gKG9wdGlvbnMuaW5kZWZpbml0ZV9hcnRpY2xlICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIG9wdGlvbnMuaW5kZWZpbml0ZV9hcnRpY2xlICE9ICdzdHJpbmcnICYmIG9wdGlvbnMuaW5kZWZpbml0ZV9hcnRpY2xlKTtcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gZXhpc3RzKGtleSwgb3B0aW9ucykge1xuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICBcbiAgICAgICAgdmFyIG5vdEZvdW5kID0gX2dldERlZmF1bHRWYWx1ZShrZXksIG9wdGlvbnMpXG4gICAgICAgICAgICAsIGZvdW5kID0gX2ZpbmQoa2V5LCBvcHRpb25zKTtcbiAgICBcbiAgICAgICAgcmV0dXJuIGZvdW5kICE9PSB1bmRlZmluZWQgfHwgZm91bmQgPT09IG5vdEZvdW5kO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiB0cmFuc2xhdGUoa2V5LCBvcHRpb25zKSB7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIFxuICAgICAgICBpZiAoIWluaXRpYWxpemVkKSB7XG4gICAgICAgICAgICBmLmxvZygnaTE4bmV4dCBub3QgZmluaXNoZWQgaW5pdGlhbGl6YXRpb24uIHlvdSBtaWdodCBoYXZlIGNhbGxlZCB0IGZ1bmN0aW9uIGJlZm9yZSBsb2FkaW5nIHJlc291cmNlcyBmaW5pc2hlZC4nKVxuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnMuZGVmYXVsdFZhbHVlIHx8ICcnO1xuICAgICAgICB9O1xuICAgICAgICByZXBsYWNlbWVudENvdW50ZXIgPSAwO1xuICAgICAgICByZXR1cm4gX3RyYW5zbGF0ZS5hcHBseShudWxsLCBhcmd1bWVudHMpO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBfZ2V0RGVmYXVsdFZhbHVlKGtleSwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gKG9wdGlvbnMuZGVmYXVsdFZhbHVlICE9PSB1bmRlZmluZWQpID8gb3B0aW9ucy5kZWZhdWx0VmFsdWUgOiBrZXk7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIF9pbmplY3RTcHJpbnRmUHJvY2Vzc29yKCkge1xuICAgIFxuICAgICAgICB2YXIgdmFsdWVzID0gW107XG4gICAgXG4gICAgICAgIC8vIG1oOiBidWlsZCBhcnJheSBmcm9tIHNlY29uZCBhcmd1bWVudCBvbndhcmRzXG4gICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YWx1ZXMucHVzaChhcmd1bWVudHNbaV0pO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBwb3N0UHJvY2VzczogJ3NwcmludGYnLFxuICAgICAgICAgICAgc3ByaW50ZjogICAgIHZhbHVlc1xuICAgICAgICB9O1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBfdHJhbnNsYXRlKHBvdGVudGlhbEtleXMsIG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMgJiYgdHlwZW9mIG9wdGlvbnMgIT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICBpZiAoby5zaG9ydGN1dEZ1bmN0aW9uID09PSAnc3ByaW50ZicpIHtcbiAgICAgICAgICAgICAgICAvLyBtaDogZ2V0dGV4dCBsaWtlIHNwcmludGYgc3ludGF4IGZvdW5kLCBhdXRvbWF0aWNhbGx5IGNyZWF0ZSBzcHJpbnRmIHByb2Nlc3NvclxuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSBfaW5qZWN0U3ByaW50ZlByb2Nlc3Nvci5hcHBseShudWxsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvLnNob3J0Y3V0RnVuY3Rpb24gPT09ICdkZWZhdWx0VmFsdWUnKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdFZhbHVlOiBvcHRpb25zXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKHR5cGVvZiBvLmRlZmF1bHRWYXJpYWJsZXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gZi5leHRlbmQoe30sIG8uZGVmYXVsdFZhcmlhYmxlcywgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKHBvdGVudGlhbEtleXMgPT09IHVuZGVmaW5lZCB8fCBwb3RlbnRpYWxLZXlzID09PSBudWxsIHx8IHBvdGVudGlhbEtleXMgPT09ICcnKSByZXR1cm4gJyc7XG4gICAgXG4gICAgICAgIGlmICh0eXBlb2YgcG90ZW50aWFsS2V5cyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHBvdGVudGlhbEtleXMgPSBbcG90ZW50aWFsS2V5c107XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgdmFyIGtleSA9IHBvdGVudGlhbEtleXNbMF07XG4gICAgXG4gICAgICAgIGlmIChwb3RlbnRpYWxLZXlzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG90ZW50aWFsS2V5cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGtleSA9IHBvdGVudGlhbEtleXNbaV07XG4gICAgICAgICAgICAgICAgaWYgKGV4aXN0cyhrZXksIG9wdGlvbnMpKSB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICB2YXIgbm90Rm91bmQgPSBfZ2V0RGVmYXVsdFZhbHVlKGtleSwgb3B0aW9ucylcbiAgICAgICAgICAgICwgZm91bmQgPSBfZmluZChrZXksIG9wdGlvbnMpXG4gICAgICAgICAgICAsIGxuZ3MgPSBvcHRpb25zLmxuZyA/IGYudG9MYW5ndWFnZXMob3B0aW9ucy5sbmcsIG9wdGlvbnMuZmFsbGJhY2tMbmcpIDogbGFuZ3VhZ2VzXG4gICAgICAgICAgICAsIG5zID0gb3B0aW9ucy5ucyB8fCBvLm5zLmRlZmF1bHROc1xuICAgICAgICAgICAgLCBwYXJ0cztcbiAgICBcbiAgICAgICAgLy8gc3BsaXQgbnMgYW5kIGtleVxuICAgICAgICBpZiAoa2V5LmluZGV4T2Yoby5uc3NlcGFyYXRvcikgPiAtMSkge1xuICAgICAgICAgICAgcGFydHMgPSBrZXkuc3BsaXQoby5uc3NlcGFyYXRvcik7XG4gICAgICAgICAgICBucyA9IHBhcnRzWzBdO1xuICAgICAgICAgICAga2V5ID0gcGFydHNbMV07XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKGZvdW5kID09PSB1bmRlZmluZWQgJiYgby5zZW5kTWlzc2luZyAmJiB0eXBlb2Ygby5taXNzaW5nS2V5SGFuZGxlciA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMubG5nKSB7XG4gICAgICAgICAgICAgICAgby5taXNzaW5nS2V5SGFuZGxlcihsbmdzWzBdLCBucywga2V5LCBub3RGb3VuZCwgbG5ncyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG8ubWlzc2luZ0tleUhhbmRsZXIoby5sbmcsIG5zLCBrZXksIG5vdEZvdW5kLCBsbmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICB2YXIgcG9zdFByb2Nlc3NvciA9IG9wdGlvbnMucG9zdFByb2Nlc3MgfHwgby5wb3N0UHJvY2VzcztcbiAgICAgICAgaWYgKGZvdW5kICE9PSB1bmRlZmluZWQgJiYgcG9zdFByb2Nlc3Nvcikge1xuICAgICAgICAgICAgaWYgKHBvc3RQcm9jZXNzb3JzW3Bvc3RQcm9jZXNzb3JdKSB7XG4gICAgICAgICAgICAgICAgZm91bmQgPSBwb3N0UHJvY2Vzc29yc1twb3N0UHJvY2Vzc29yXShmb3VuZCwga2V5LCBvcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBwcm9jZXNzIG5vdEZvdW5kIGlmIGZ1bmN0aW9uIGV4aXN0c1xuICAgICAgICB2YXIgc3BsaXROb3RGb3VuZCA9IG5vdEZvdW5kO1xuICAgICAgICBpZiAobm90Rm91bmQuaW5kZXhPZihvLm5zc2VwYXJhdG9yKSA+IC0xKSB7XG4gICAgICAgICAgICBwYXJ0cyA9IG5vdEZvdW5kLnNwbGl0KG8ubnNzZXBhcmF0b3IpO1xuICAgICAgICAgICAgc3BsaXROb3RGb3VuZCA9IHBhcnRzWzFdO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzcGxpdE5vdEZvdW5kID09PSBrZXkgJiYgby5wYXJzZU1pc3NpbmdLZXkpIHtcbiAgICAgICAgICAgIG5vdEZvdW5kID0gby5wYXJzZU1pc3NpbmdLZXkobm90Rm91bmQpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGlmIChmb3VuZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBub3RGb3VuZCA9IGFwcGx5UmVwbGFjZW1lbnQobm90Rm91bmQsIG9wdGlvbnMpO1xuICAgICAgICAgICAgbm90Rm91bmQgPSBhcHBseVJldXNlKG5vdEZvdW5kLCBvcHRpb25zKTtcbiAgICBcbiAgICAgICAgICAgIGlmIChwb3N0UHJvY2Vzc29yICYmIHBvc3RQcm9jZXNzb3JzW3Bvc3RQcm9jZXNzb3JdKSB7XG4gICAgICAgICAgICAgICAgdmFyIHZhbCA9IF9nZXREZWZhdWx0VmFsdWUoa2V5LCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICBmb3VuZCA9IHBvc3RQcm9jZXNzb3JzW3Bvc3RQcm9jZXNzb3JdKHZhbCwga2V5LCBvcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICByZXR1cm4gKGZvdW5kICE9PSB1bmRlZmluZWQpID8gZm91bmQgOiBub3RGb3VuZDtcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gX2ZpbmQoa2V5LCBvcHRpb25zKSB7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIFxuICAgICAgICB2YXIgb3B0aW9uV2l0aG91dENvdW50LCB0cmFuc2xhdGVkXG4gICAgICAgICAgICAsIG5vdEZvdW5kID0gX2dldERlZmF1bHRWYWx1ZShrZXksIG9wdGlvbnMpXG4gICAgICAgICAgICAsIGxuZ3MgPSBsYW5ndWFnZXM7XG4gICAgXG4gICAgICAgIGlmICghcmVzU3RvcmUpIHsgcmV0dXJuIG5vdEZvdW5kOyB9IC8vIG5vIHJlc1N0b3JlIHRvIHRyYW5zbGF0ZSBmcm9tXG4gICAgXG4gICAgICAgIC8vIENJIG1vZGVcbiAgICAgICAgaWYgKGxuZ3NbMF0udG9Mb3dlckNhc2UoKSA9PT0gJ2NpbW9kZScpIHJldHVybiBub3RGb3VuZDtcbiAgICBcbiAgICAgICAgLy8gcGFzc2VkIGluIGxuZ1xuICAgICAgICBpZiAob3B0aW9ucy5sbmdzKSBsbmdzID0gb3B0aW9ucy5sbmdzO1xuICAgICAgICBpZiAob3B0aW9ucy5sbmcpIHtcbiAgICAgICAgICAgIGxuZ3MgPSBmLnRvTGFuZ3VhZ2VzKG9wdGlvbnMubG5nLCBvcHRpb25zLmZhbGxiYWNrTG5nKTtcbiAgICBcbiAgICAgICAgICAgIGlmICghcmVzU3RvcmVbbG5nc1swXV0pIHtcbiAgICAgICAgICAgICAgICB2YXIgb2xkQXN5bmMgPSBvLmdldEFzeW5jO1xuICAgICAgICAgICAgICAgIG8uZ2V0QXN5bmMgPSBmYWxzZTtcbiAgICBcbiAgICAgICAgICAgICAgICBpMThuLnN5bmMubG9hZChsbmdzLCBvLCBmdW5jdGlvbihlcnIsIHN0b3JlKSB7XG4gICAgICAgICAgICAgICAgICAgIGYuZXh0ZW5kKHJlc1N0b3JlLCBzdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgIG8uZ2V0QXN5bmMgPSBvbGRBc3luYztcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICB2YXIgbnMgPSBvcHRpb25zLm5zIHx8IG8ubnMuZGVmYXVsdE5zO1xuICAgICAgICBpZiAoa2V5LmluZGV4T2Yoby5uc3NlcGFyYXRvcikgPiAtMSkge1xuICAgICAgICAgICAgdmFyIHBhcnRzID0ga2V5LnNwbGl0KG8ubnNzZXBhcmF0b3IpO1xuICAgICAgICAgICAgbnMgPSBwYXJ0c1swXTtcbiAgICAgICAgICAgIGtleSA9IHBhcnRzWzFdO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGlmIChoYXNDb250ZXh0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25XaXRob3V0Q291bnQgPSBmLmV4dGVuZCh7fSwgb3B0aW9ucyk7XG4gICAgICAgICAgICBkZWxldGUgb3B0aW9uV2l0aG91dENvdW50LmNvbnRleHQ7XG4gICAgICAgICAgICBvcHRpb25XaXRob3V0Q291bnQuZGVmYXVsdFZhbHVlID0gby5jb250ZXh0Tm90Rm91bmQ7XG4gICAgXG4gICAgICAgICAgICB2YXIgY29udGV4dEtleSA9IG5zICsgby5uc3NlcGFyYXRvciArIGtleSArICdfJyArIG9wdGlvbnMuY29udGV4dDtcbiAgICBcbiAgICAgICAgICAgIHRyYW5zbGF0ZWQgPSB0cmFuc2xhdGUoY29udGV4dEtleSwgb3B0aW9uV2l0aG91dENvdW50KTtcbiAgICAgICAgICAgIGlmICh0cmFuc2xhdGVkICE9IG8uY29udGV4dE5vdEZvdW5kKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFwcGx5UmVwbGFjZW1lbnQodHJhbnNsYXRlZCwgeyBjb250ZXh0OiBvcHRpb25zLmNvbnRleHQgfSk7IC8vIGFwcGx5IHJlcGxhY2VtZW50IGZvciBjb250ZXh0IG9ubHlcbiAgICAgICAgICAgIH0gLy8gZWxzZSBjb250aW51ZSB0cmFuc2xhdGlvbiB3aXRoIG9yaWdpbmFsL25vbkNvbnRleHQga2V5XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKG5lZWRzUGx1cmFsKG9wdGlvbnMsIGxuZ3NbMF0pKSB7XG4gICAgICAgICAgICBvcHRpb25XaXRob3V0Q291bnQgPSBmLmV4dGVuZCh7IGxuZ3M6IFtsbmdzWzBdXX0sIG9wdGlvbnMpO1xuICAgICAgICAgICAgZGVsZXRlIG9wdGlvbldpdGhvdXRDb3VudC5jb3VudDtcbiAgICAgICAgICAgIGRlbGV0ZSBvcHRpb25XaXRob3V0Q291bnQubG5nO1xuICAgICAgICAgICAgb3B0aW9uV2l0aG91dENvdW50LmRlZmF1bHRWYWx1ZSA9IG8ucGx1cmFsTm90Rm91bmQ7XG4gICAgXG4gICAgICAgICAgICB2YXIgcGx1cmFsS2V5O1xuICAgICAgICAgICAgaWYgKCFwbHVyYWxFeHRlbnNpb25zLm5lZWRzUGx1cmFsKGxuZ3NbMF0sIG9wdGlvbnMuY291bnQpKSB7XG4gICAgICAgICAgICAgICAgcGx1cmFsS2V5ID0gbnMgKyBvLm5zc2VwYXJhdG9yICsga2V5O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwbHVyYWxLZXkgPSBucyArIG8ubnNzZXBhcmF0b3IgKyBrZXkgKyBvLnBsdXJhbFN1ZmZpeDtcbiAgICAgICAgICAgICAgICB2YXIgcGx1cmFsRXh0ZW5zaW9uID0gcGx1cmFsRXh0ZW5zaW9ucy5nZXQobG5nc1swXSwgb3B0aW9ucy5jb3VudCk7XG4gICAgICAgICAgICAgICAgaWYgKHBsdXJhbEV4dGVuc2lvbiA+PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHBsdXJhbEtleSA9IHBsdXJhbEtleSArICdfJyArIHBsdXJhbEV4dGVuc2lvbjtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHBsdXJhbEV4dGVuc2lvbiA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICBwbHVyYWxLZXkgPSBucyArIG8ubnNzZXBhcmF0b3IgKyBrZXk7IC8vIHNpbmd1bGFyXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgdHJhbnNsYXRlZCA9IHRyYW5zbGF0ZShwbHVyYWxLZXksIG9wdGlvbldpdGhvdXRDb3VudCk7XG4gICAgXG4gICAgICAgICAgICBpZiAodHJhbnNsYXRlZCAhPSBvLnBsdXJhbE5vdEZvdW5kKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFwcGx5UmVwbGFjZW1lbnQodHJhbnNsYXRlZCwge1xuICAgICAgICAgICAgICAgICAgICBjb3VudDogb3B0aW9ucy5jb3VudCxcbiAgICAgICAgICAgICAgICAgICAgaW50ZXJwb2xhdGlvblByZWZpeDogb3B0aW9ucy5pbnRlcnBvbGF0aW9uUHJlZml4LFxuICAgICAgICAgICAgICAgICAgICBpbnRlcnBvbGF0aW9uU3VmZml4OiBvcHRpb25zLmludGVycG9sYXRpb25TdWZmaXhcbiAgICAgICAgICAgICAgICB9KTsgLy8gYXBwbHkgcmVwbGFjZW1lbnQgZm9yIGNvdW50IG9ubHlcbiAgICAgICAgICAgIH0gZWxzZSBpZiAobG5ncy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgLy8gcmVtb3ZlIGZhaWxlZCBsbmdcbiAgICAgICAgICAgICAgICB2YXIgY2xvbmUgPSBsbmdzLnNsaWNlKCk7XG4gICAgICAgICAgICAgICAgY2xvbmUuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gZi5leHRlbmQob3B0aW9ucywgeyBsbmdzOiBjbG9uZSB9KTtcbiAgICAgICAgICAgICAgICBkZWxldGUgb3B0aW9ucy5sbmc7XG4gICAgICAgICAgICAgICAgLy8gcmV0cnkgd2l0aCBmYWxsYmFja3NcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGVkID0gdHJhbnNsYXRlKG5zICsgby5uc3NlcGFyYXRvciArIGtleSwgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgaWYgKHRyYW5zbGF0ZWQgIT0gby5wbHVyYWxOb3RGb3VuZCkgcmV0dXJuIHRyYW5zbGF0ZWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cmFuc2xhdGVkO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIGlmIChuZWVkc0luZGVmaW5pdGVBcnRpY2xlKG9wdGlvbnMpKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9uc1dpdGhvdXRJbmRlZiA9IGYuZXh0ZW5kKHt9LCBvcHRpb25zKTtcbiAgICAgICAgICAgIGRlbGV0ZSBvcHRpb25zV2l0aG91dEluZGVmLmluZGVmaW5pdGVfYXJ0aWNsZTtcbiAgICAgICAgICAgIG9wdGlvbnNXaXRob3V0SW5kZWYuZGVmYXVsdFZhbHVlID0gby5pbmRlZmluaXRlTm90Rm91bmQ7XG4gICAgICAgICAgICAvLyBJZiB3ZSBkb24ndCBoYXZlIGEgY291bnQsIHdlIHdhbnQgdGhlIGluZGVmaW5pdGUsIGlmIHdlIGRvIGhhdmUgYSBjb3VudCwgYW5kIG5lZWRzUGx1cmFsIGlzIGZhbHNlXG4gICAgICAgICAgICB2YXIgaW5kZWZpbml0ZUtleSA9IG5zICsgby5uc3NlcGFyYXRvciArIGtleSArICgoKG9wdGlvbnMuY291bnQgJiYgIW5lZWRzUGx1cmFsKG9wdGlvbnMsIGxuZ3NbMF0pKSB8fCAhb3B0aW9ucy5jb3VudCkgPyBvLmluZGVmaW5pdGVTdWZmaXggOiBcIlwiKTtcbiAgICAgICAgICAgIHRyYW5zbGF0ZWQgPSB0cmFuc2xhdGUoaW5kZWZpbml0ZUtleSwgb3B0aW9uc1dpdGhvdXRJbmRlZik7XG4gICAgICAgICAgICBpZiAodHJhbnNsYXRlZCAhPSBvLmluZGVmaW5pdGVOb3RGb3VuZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cmFuc2xhdGVkO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIHZhciBmb3VuZDtcbiAgICAgICAgdmFyIGtleXMgPSBrZXkuc3BsaXQoby5rZXlzZXBhcmF0b3IpO1xuICAgICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gbG5ncy5sZW5ndGg7IGkgPCBsZW47IGkrKyApIHtcbiAgICAgICAgICAgIGlmIChmb3VuZCAhPT0gdW5kZWZpbmVkKSBicmVhaztcbiAgICBcbiAgICAgICAgICAgIHZhciBsID0gbG5nc1tpXTtcbiAgICBcbiAgICAgICAgICAgIHZhciB4ID0gMDtcbiAgICAgICAgICAgIHZhciB2YWx1ZSA9IHJlc1N0b3JlW2xdICYmIHJlc1N0b3JlW2xdW25zXTtcbiAgICAgICAgICAgIHdoaWxlIChrZXlzW3hdKSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZSAmJiB2YWx1ZVtrZXlzW3hdXTtcbiAgICAgICAgICAgICAgICB4Kys7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHZhciB2YWx1ZVR5cGUgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmFwcGx5KHZhbHVlKTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGFwcGx5UmVwbGFjZW1lbnQodmFsdWUsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGFwcGx5UmV1c2UodmFsdWUsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWVUeXBlID09PSAnW29iamVjdCBBcnJheV0nICYmICFvLnJldHVybk9iamVjdFRyZWVzICYmICFvcHRpb25zLnJldHVybk9iamVjdFRyZWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuam9pbignXFxuJyk7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gYXBwbHlSZXBsYWNlbWVudCh2YWx1ZSwgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gYXBwbHlSZXVzZSh2YWx1ZSwgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gbnVsbCAmJiBvLmZhbGxiYWNrT25OdWxsID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFvLnJldHVybk9iamVjdFRyZWVzICYmICFvcHRpb25zLnJldHVybk9iamVjdFRyZWVzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoby5vYmplY3RUcmVlS2V5SGFuZGxlciAmJiB0eXBlb2Ygby5vYmplY3RUcmVlS2V5SGFuZGxlciA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBvLm9iamVjdFRyZWVLZXlIYW5kbGVyKGtleSwgdmFsdWUsIGwsIG5zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAna2V5IFxcJycgKyBucyArICc6JyArIGtleSArICcgKCcgKyBsICsgJylcXCcgJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdyZXR1cm5lZCBhbiBvYmplY3QgaW5zdGVhZCBvZiBzdHJpbmcuJztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmLmxvZyh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWVUeXBlICE9PSAnW29iamVjdCBOdW1iZXJdJyAmJiB2YWx1ZVR5cGUgIT09ICdbb2JqZWN0IEZ1bmN0aW9uXScgJiYgdmFsdWVUeXBlICE9PSAnW29iamVjdCBSZWdFeHBdJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGNvcHkgPSAodmFsdWVUeXBlID09PSAnW29iamVjdCBBcnJheV0nKSA/IFtdIDoge307IC8vIGFwcGx5IGNoaWxkIHRyYW5zbGF0aW9uIG9uIGEgY29weVxuICAgICAgICAgICAgICAgICAgICAgICAgZi5lYWNoKHZhbHVlLCBmdW5jdGlvbihtKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29weVttXSA9IF90cmFuc2xhdGUobnMgKyBvLm5zc2VwYXJhdG9yICsga2V5ICsgby5rZXlzZXBhcmF0b3IgKyBtLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBjb3B5O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLnRyaW0oKSA9PT0gJycgJiYgby5mYWxsYmFja09uRW1wdHkgPT09IHRydWUpXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdW5kZWZpbmVkO1xuICAgIFxuICAgICAgICAgICAgICAgIGZvdW5kID0gdmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKGZvdW5kID09PSB1bmRlZmluZWQgJiYgIW9wdGlvbnMuaXNGYWxsYmFja0xvb2t1cCAmJiAoby5mYWxsYmFja1RvRGVmYXVsdE5TID09PSB0cnVlIHx8IChvLmZhbGxiYWNrTlMgJiYgby5mYWxsYmFja05TLmxlbmd0aCA+IDApKSkge1xuICAgICAgICAgICAgLy8gc2V0IGZsYWcgZm9yIGZhbGxiYWNrIGxvb2t1cCAtIGF2b2lkIHJlY3Vyc2lvblxuICAgICAgICAgICAgb3B0aW9ucy5pc0ZhbGxiYWNrTG9va3VwID0gdHJ1ZTtcbiAgICBcbiAgICAgICAgICAgIGlmIChvLmZhbGxiYWNrTlMubGVuZ3RoKSB7XG4gICAgXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgeSA9IDAsIGxlblkgPSBvLmZhbGxiYWNrTlMubGVuZ3RoOyB5IDwgbGVuWTsgeSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvdW5kID0gX2ZpbmQoby5mYWxsYmFja05TW3ldICsgby5uc3NlcGFyYXRvciArIGtleSwgb3B0aW9ucyk7XG4gICAgXG4gICAgICAgICAgICAgICAgICAgIGlmIChmb3VuZCB8fCAoZm91bmQ9PT1cIlwiICYmIG8uZmFsbGJhY2tPbkVtcHR5ID09PSBmYWxzZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8qIGNvbXBhcmUgdmFsdWUgd2l0aG91dCBuYW1lc3BhY2UgKi9cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmb3VuZFZhbHVlID0gZm91bmQuaW5kZXhPZihvLm5zc2VwYXJhdG9yKSA+IC0xID8gZm91bmQuc3BsaXQoby5uc3NlcGFyYXRvcilbMV0gOiBmb3VuZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAsIG5vdEZvdW5kVmFsdWUgPSBub3RGb3VuZC5pbmRleE9mKG8ubnNzZXBhcmF0b3IpID4gLTEgPyBub3RGb3VuZC5zcGxpdChvLm5zc2VwYXJhdG9yKVsxXSA6IG5vdEZvdW5kO1xuICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZvdW5kVmFsdWUgIT09IG5vdEZvdW5kVmFsdWUpIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmb3VuZCA9IF9maW5kKGtleSwgb3B0aW9ucyk7IC8vIGZhbGxiYWNrIHRvIGRlZmF1bHQgTlNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG9wdGlvbnMuaXNGYWxsYmFja0xvb2t1cCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIHJldHVybiBmb3VuZDtcbiAgICB9XG4gICAgZnVuY3Rpb24gZGV0ZWN0TGFuZ3VhZ2UoKSB7XG4gICAgICAgIHZhciBkZXRlY3RlZExuZztcbiAgICAgICAgdmFyIHdoaXRlbGlzdCA9IG8ubG5nV2hpdGVsaXN0IHx8IFtdO1xuICAgICAgICB2YXIgdXNlckxuZ0Nob2ljZXMgPSBbXTtcbiAgICBcbiAgICAgICAgLy8gZ2V0IGZyb20gcXNcbiAgICAgICAgdmFyIHFzUGFybSA9IFtdO1xuICAgICAgICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICB2YXIgcXVlcnkgPSB3aW5kb3cubG9jYXRpb24uc2VhcmNoLnN1YnN0cmluZygxKTtcbiAgICAgICAgICAgICAgICB2YXIgcGFyYW1zID0gcXVlcnkuc3BsaXQoJyYnKTtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8cGFyYW1zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwb3MgPSBwYXJhbXNbaV0uaW5kZXhPZignPScpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocG9zID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGtleSA9IHBhcmFtc1tpXS5zdWJzdHJpbmcoMCxwb3MpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGtleSA9PSBvLmRldGVjdExuZ1FTKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlckxuZ0Nob2ljZXMucHVzaChwYXJhbXNbaV0uc3Vic3RyaW5nKHBvcysxKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KSgpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIC8vIGdldCBmcm9tIGNvb2tpZVxuICAgICAgICBpZiAoby51c2VDb29raWUgJiYgdHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgdmFyIGMgPSBmLmNvb2tpZS5yZWFkKG8uY29va2llTmFtZSk7XG4gICAgICAgICAgICBpZiAoYykgdXNlckxuZ0Nob2ljZXMucHVzaChjKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBnZXQgZnJvbSBsb2NhbFN0b3JhZ2VcbiAgICAgICAgaWYgKG8uZGV0ZWN0TG5nRnJvbUxvY2FsU3RvcmFnZSAmJiB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB3aW5kb3cubG9jYWxTdG9yYWdlKSB7XG4gICAgICAgICAgICB1c2VyTG5nQ2hvaWNlcy5wdXNoKHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnaTE4bmV4dF9sbmcnKSk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gZ2V0IGZyb20gbmF2aWdhdG9yXG4gICAgICAgIGlmICh0eXBlb2YgbmF2aWdhdG9yICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgaWYgKG5hdmlnYXRvci5sYW5ndWFnZXMpIHsgLy8gY2hyb21lIG9ubHk7IG5vdCBhbiBhcnJheSwgc28gY2FuJ3QgdXNlIC5wdXNoLmFwcGx5IGluc3RlYWQgb2YgaXRlcmF0aW5nXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wO2k8bmF2aWdhdG9yLmxhbmd1YWdlcy5sZW5ndGg7aSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIHVzZXJMbmdDaG9pY2VzLnB1c2gobmF2aWdhdG9yLmxhbmd1YWdlc1tpXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG5hdmlnYXRvci51c2VyTGFuZ3VhZ2UpIHtcbiAgICAgICAgICAgICAgICB1c2VyTG5nQ2hvaWNlcy5wdXNoKG5hdmlnYXRvci51c2VyTGFuZ3VhZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG5hdmlnYXRvci5sYW5ndWFnZSkge1xuICAgICAgICAgICAgICAgIHVzZXJMbmdDaG9pY2VzLnB1c2gobmF2aWdhdG9yLmxhbmd1YWdlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICAoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBpPTA7aTx1c2VyTG5nQ2hvaWNlcy5sZW5ndGg7aSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGxuZyA9IHVzZXJMbmdDaG9pY2VzW2ldO1xuICAgIFxuICAgICAgICAgICAgICAgIGlmIChsbmcuaW5kZXhPZignLScpID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcnRzID0gbG5nLnNwbGl0KCctJyk7XG4gICAgICAgICAgICAgICAgICAgIGxuZyA9IG8ubG93ZXJDYXNlTG5nID9cbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRzWzBdLnRvTG93ZXJDYXNlKCkgKyAgJy0nICsgcGFydHNbMV0udG9Mb3dlckNhc2UoKSA6XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJ0c1swXS50b0xvd2VyQ2FzZSgpICsgICctJyArIHBhcnRzWzFdLnRvVXBwZXJDYXNlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgICAgIGlmICh3aGl0ZWxpc3QubGVuZ3RoID09PSAwIHx8IHdoaXRlbGlzdC5pbmRleE9mKGxuZykgPiAtMSkge1xuICAgICAgICAgICAgICAgICAgICBkZXRlY3RlZExuZyA9IGxuZztcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KSgpO1xuICAgIFxuICAgICAgICAvL2ZhbGxiYWNrXG4gICAgICAgIGlmICghZGV0ZWN0ZWRMbmcpe1xuICAgICAgICAgIGRldGVjdGVkTG5nID0gby5mYWxsYmFja0xuZ1swXTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgcmV0dXJuIGRldGVjdGVkTG5nO1xuICAgIH1cbiAgICAvLyBkZWZpbml0aW9uIGh0dHA6Ly90cmFuc2xhdGUuc291cmNlZm9yZ2UubmV0L3dpa2kvbDEwbi9wbHVyYWxmb3Jtc1xuICAgIFxuICAgIC8qIFtjb2RlLCBuYW1lLCBudW1iZXJzLCBwbHVyYWxzVHlwZV0gKi9cbiAgICB2YXIgX3J1bGVzID0gW1xuICAgICAgICBbXCJhY2hcIiwgXCJBY2hvbGlcIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJhZlwiLCBcIkFmcmlrYWFuc1wiLFsxLDJdLCAyXSxcbiAgICAgICAgW1wiYWtcIiwgXCJBa2FuXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wiYW1cIiwgXCJBbWhhcmljXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wiYW5cIiwgXCJBcmFnb25lc2VcIixbMSwyXSwgMl0sXG4gICAgICAgIFtcImFyXCIsIFwiQXJhYmljXCIsIFswLDEsMiwzLDExLDEwMF0sNV0sXG4gICAgICAgIFtcImFyblwiLCBcIk1hcHVkdW5ndW5cIixbMSwyXSwgMV0sXG4gICAgICAgIFtcImFzdFwiLCBcIkFzdHVyaWFuXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiYXlcIiwgXCJBeW1hcsOhXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImF6XCIsIFwiQXplcmJhaWphbmlcIixbMSwyXSwyXSxcbiAgICAgICAgW1wiYmVcIiwgXCJCZWxhcnVzaWFuXCIsWzEsMiw1XSw0XSxcbiAgICAgICAgW1wiYmdcIiwgXCJCdWxnYXJpYW5cIixbMSwyXSwgMl0sXG4gICAgICAgIFtcImJuXCIsIFwiQmVuZ2FsaVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImJvXCIsIFwiVGliZXRhblwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJiclwiLCBcIkJyZXRvblwiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcImJzXCIsIFwiQm9zbmlhblwiLCBbMSwyLDVdLDRdLFxuICAgICAgICBbXCJjYVwiLCBcIkNhdGFsYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJjZ2dcIiwgXCJDaGlnYVwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJjc1wiLCBcIkN6ZWNoXCIsIFsxLDIsNV0sNl0sXG4gICAgICAgIFtcImNzYlwiLCBcIkthc2h1YmlhblwiLFsxLDIsNV0sN10sXG4gICAgICAgIFtcImN5XCIsIFwiV2Vsc2hcIiwgWzEsMiwzLDhdLDhdLFxuICAgICAgICBbXCJkYVwiLCBcIkRhbmlzaFwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImRlXCIsIFwiR2VybWFuXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZGV2XCIsIFwiRGV2ZWxvcG1lbnQgRmFsbGJhY2tcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJkelwiLCBcIkR6b25na2hhXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImVsXCIsIFwiR3JlZWtcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJlblwiLCBcIkVuZ2xpc2hcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJlb1wiLCBcIkVzcGVyYW50b1wiLFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZXNcIiwgXCJTcGFuaXNoXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZXNfYXJcIixcIkFyZ2VudGluZWFuIFNwYW5pc2hcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJldFwiLCBcIkVzdG9uaWFuXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZXVcIiwgXCJCYXNxdWVcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJmYVwiLCBcIlBlcnNpYW5cIiwgWzFdLCAzXSxcbiAgICAgICAgW1wiZmlcIiwgXCJGaW5uaXNoXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZmlsXCIsIFwiRmlsaXBpbm9cIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJmb1wiLCBcIkZhcm9lc2VcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJmclwiLCBcIkZyZW5jaFwiLCBbMSwyXSwgOV0sXG4gICAgICAgIFtcImZ1clwiLCBcIkZyaXVsaWFuXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZnlcIiwgXCJGcmlzaWFuXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZ2FcIiwgXCJJcmlzaFwiLCBbMSwyLDMsNywxMV0sMTBdLFxuICAgICAgICBbXCJnZFwiLCBcIlNjb3R0aXNoIEdhZWxpY1wiLFsxLDIsMywyMF0sMTFdLFxuICAgICAgICBbXCJnbFwiLCBcIkdhbGljaWFuXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZ3VcIiwgXCJHdWphcmF0aVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImd1blwiLCBcIkd1blwiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcImhhXCIsIFwiSGF1c2FcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJoZVwiLCBcIkhlYnJld1wiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImhpXCIsIFwiSGluZGlcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJoclwiLCBcIkNyb2F0aWFuXCIsIFsxLDIsNV0sNF0sXG4gICAgICAgIFtcImh1XCIsIFwiSHVuZ2FyaWFuXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJoeVwiLCBcIkFybWVuaWFuXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiaWFcIiwgXCJJbnRlcmxpbmd1YVwiLFsxLDJdLDJdLFxuICAgICAgICBbXCJpZFwiLCBcIkluZG9uZXNpYW5cIixbMV0sIDNdLFxuICAgICAgICBbXCJpc1wiLCBcIkljZWxhbmRpY1wiLFsxLDJdLCAxMl0sXG4gICAgICAgIFtcIml0XCIsIFwiSXRhbGlhblwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImphXCIsIFwiSmFwYW5lc2VcIiwgWzFdLCAzXSxcbiAgICAgICAgW1wiamJvXCIsIFwiTG9qYmFuXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImp2XCIsIFwiSmF2YW5lc2VcIiwgWzAsMV0sIDEzXSxcbiAgICAgICAgW1wia2FcIiwgXCJHZW9yZ2lhblwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJra1wiLCBcIkthemFraFwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJrbVwiLCBcIktobWVyXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImtuXCIsIFwiS2FubmFkYVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImtvXCIsIFwiS29yZWFuXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImt1XCIsIFwiS3VyZGlzaFwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImt3XCIsIFwiQ29ybmlzaFwiLCBbMSwyLDMsNF0sMTRdLFxuICAgICAgICBbXCJreVwiLCBcIkt5cmd5elwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJsYlwiLCBcIkxldHplYnVyZ2VzY2hcIixbMSwyXSwyXSxcbiAgICAgICAgW1wibG5cIiwgXCJMaW5nYWxhXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wibG9cIiwgXCJMYW9cIiwgWzFdLCAzXSxcbiAgICAgICAgW1wibHRcIiwgXCJMaXRodWFuaWFuXCIsWzEsMiwxMF0sMTVdLFxuICAgICAgICBbXCJsdlwiLCBcIkxhdHZpYW5cIiwgWzEsMiwwXSwxNl0sXG4gICAgICAgIFtcIm1haVwiLCBcIk1haXRoaWxpXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wibWZlXCIsIFwiTWF1cml0aWFuIENyZW9sZVwiLFsxLDJdLDFdLFxuICAgICAgICBbXCJtZ1wiLCBcIk1hbGFnYXN5XCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wibWlcIiwgXCJNYW9yaVwiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcIm1rXCIsIFwiTWFjZWRvbmlhblwiLFsxLDJdLDE3XSxcbiAgICAgICAgW1wibWxcIiwgXCJNYWxheWFsYW1cIixbMSwyXSwgMl0sXG4gICAgICAgIFtcIm1uXCIsIFwiTW9uZ29saWFuXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJtbmtcIiwgXCJNYW5kaW5rYVwiLCBbMCwxLDJdLDE4XSxcbiAgICAgICAgW1wibXJcIiwgXCJNYXJhdGhpXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wibXNcIiwgXCJNYWxheVwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJtdFwiLCBcIk1hbHRlc2VcIiwgWzEsMiwxMSwyMF0sMTldLFxuICAgICAgICBbXCJuYWhcIiwgXCJOYWh1YXRsXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wibmFwXCIsIFwiTmVhcG9saXRhblwiLFsxLDJdLCAyXSxcbiAgICAgICAgW1wibmJcIiwgXCJOb3J3ZWdpYW4gQm9rbWFsXCIsWzEsMl0sMl0sXG4gICAgICAgIFtcIm5lXCIsIFwiTmVwYWxpXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wibmxcIiwgXCJEdXRjaFwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcIm5uXCIsIFwiTm9yd2VnaWFuIE55bm9yc2tcIixbMSwyXSwyXSxcbiAgICAgICAgW1wibm9cIiwgXCJOb3J3ZWdpYW5cIixbMSwyXSwgMl0sXG4gICAgICAgIFtcIm5zb1wiLCBcIk5vcnRoZXJuIFNvdGhvXCIsWzEsMl0sMl0sXG4gICAgICAgIFtcIm9jXCIsIFwiT2NjaXRhblwiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcIm9yXCIsIFwiT3JpeWFcIiwgWzIsMV0sIDJdLFxuICAgICAgICBbXCJwYVwiLCBcIlB1bmphYmlcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJwYXBcIiwgXCJQYXBpYW1lbnRvXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJwbFwiLCBcIlBvbGlzaFwiLCBbMSwyLDVdLDddLFxuICAgICAgICBbXCJwbXNcIiwgXCJQaWVtb250ZXNlXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJwc1wiLCBcIlBhc2h0b1wiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInB0XCIsIFwiUG9ydHVndWVzZVwiLFsxLDJdLCAyXSxcbiAgICAgICAgW1wicHRfYnJcIixcIkJyYXppbGlhbiBQb3J0dWd1ZXNlXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJybVwiLCBcIlJvbWFuc2hcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJyb1wiLCBcIlJvbWFuaWFuXCIsIFsxLDIsMjBdLDIwXSxcbiAgICAgICAgW1wicnVcIiwgXCJSdXNzaWFuXCIsIFsxLDIsNV0sNF0sXG4gICAgICAgIFtcInNhaFwiLCBcIllha3V0XCIsIFsxXSwgM10sXG4gICAgICAgIFtcInNjb1wiLCBcIlNjb3RzXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wic2VcIiwgXCJOb3J0aGVybiBTYW1pXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJzaVwiLCBcIlNpbmhhbGFcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJza1wiLCBcIlNsb3Zha1wiLCBbMSwyLDVdLDZdLFxuICAgICAgICBbXCJzbFwiLCBcIlNsb3ZlbmlhblwiLFs1LDEsMiwzXSwyMV0sXG4gICAgICAgIFtcInNvXCIsIFwiU29tYWxpXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wic29uXCIsIFwiU29uZ2hheVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInNxXCIsIFwiQWxiYW5pYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJzclwiLCBcIlNlcmJpYW5cIiwgWzEsMiw1XSw0XSxcbiAgICAgICAgW1wic3VcIiwgXCJTdW5kYW5lc2VcIixbMV0sIDNdLFxuICAgICAgICBbXCJzdlwiLCBcIlN3ZWRpc2hcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJzd1wiLCBcIlN3YWhpbGlcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJ0YVwiLCBcIlRhbWlsXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1widGVcIiwgXCJUZWx1Z3VcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJ0Z1wiLCBcIlRhamlrXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1widGhcIiwgXCJUaGFpXCIsIFsxXSwgM10sXG4gICAgICAgIFtcInRpXCIsIFwiVGlncmlueWFcIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJ0a1wiLCBcIlR1cmttZW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJ0clwiLCBcIlR1cmtpc2hcIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJ0dFwiLCBcIlRhdGFyXCIsIFsxXSwgM10sXG4gICAgICAgIFtcInVnXCIsIFwiVXlnaHVyXCIsIFsxXSwgM10sXG4gICAgICAgIFtcInVrXCIsIFwiVWtyYWluaWFuXCIsWzEsMiw1XSw0XSxcbiAgICAgICAgW1widXJcIiwgXCJVcmR1XCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1widXpcIiwgXCJVemJla1wiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcInZpXCIsIFwiVmlldG5hbWVzZVwiLFsxXSwgM10sXG4gICAgICAgIFtcIndhXCIsIFwiV2FsbG9vblwiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcIndvXCIsIFwiV29sb2ZcIiwgWzFdLCAzXSxcbiAgICAgICAgW1wieW9cIiwgXCJZb3J1YmFcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJ6aFwiLCBcIkNoaW5lc2VcIiwgWzFdLCAzXVxuICAgIF07XG4gICAgXG4gICAgdmFyIF9ydWxlc1BsdXJhbHNUeXBlcyA9IHtcbiAgICAgICAgMTogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobiA+IDEpO30sXG4gICAgICAgIDI6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG4gIT0gMSk7fSxcbiAgICAgICAgMzogZnVuY3Rpb24obikge3JldHVybiAwO30sXG4gICAgICAgIDQ6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG4lMTA9PTEgJiYgbiUxMDAhPTExID8gMCA6IG4lMTA+PTIgJiYgbiUxMDw9NCAmJiAobiUxMDA8MTAgfHwgbiUxMDA+PTIwKSA/IDEgOiAyKTt9LFxuICAgICAgICA1OiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcihuPT09MCA/IDAgOiBuPT0xID8gMSA6IG49PTIgPyAyIDogbiUxMDA+PTMgJiYgbiUxMDA8PTEwID8gMyA6IG4lMTAwPj0xMSA/IDQgOiA1KTt9LFxuICAgICAgICA2OiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcigobj09MSkgPyAwIDogKG4+PTIgJiYgbjw9NCkgPyAxIDogMik7fSxcbiAgICAgICAgNzogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobj09MSA/IDAgOiBuJTEwPj0yICYmIG4lMTA8PTQgJiYgKG4lMTAwPDEwIHx8IG4lMTAwPj0yMCkgPyAxIDogMik7fSxcbiAgICAgICAgODogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIoKG49PTEpID8gMCA6IChuPT0yKSA/IDEgOiAobiAhPSA4ICYmIG4gIT0gMTEpID8gMiA6IDMpO30sXG4gICAgICAgIDk6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG4gPj0gMik7fSxcbiAgICAgICAgMTA6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG49PTEgPyAwIDogbj09MiA/IDEgOiBuPDcgPyAyIDogbjwxMSA/IDMgOiA0KSA7fSxcbiAgICAgICAgMTE6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKChuPT0xIHx8IG49PTExKSA/IDAgOiAobj09MiB8fCBuPT0xMikgPyAxIDogKG4gPiAyICYmIG4gPCAyMCkgPyAyIDogMyk7fSxcbiAgICAgICAgMTI6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG4lMTAhPTEgfHwgbiUxMDA9PTExKTt9LFxuICAgICAgICAxMzogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobiAhPT0gMCk7fSxcbiAgICAgICAgMTQ6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKChuPT0xKSA/IDAgOiAobj09MikgPyAxIDogKG4gPT0gMykgPyAyIDogMyk7fSxcbiAgICAgICAgMTU6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG4lMTA9PTEgJiYgbiUxMDAhPTExID8gMCA6IG4lMTA+PTIgJiYgKG4lMTAwPDEwIHx8IG4lMTAwPj0yMCkgPyAxIDogMik7fSxcbiAgICAgICAgMTY6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG4lMTA9PTEgJiYgbiUxMDAhPTExID8gMCA6IG4gIT09IDAgPyAxIDogMik7fSxcbiAgICAgICAgMTc6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG49PTEgfHwgbiUxMD09MSA/IDAgOiAxKTt9LFxuICAgICAgICAxODogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIoMCA/IDAgOiBuPT0xID8gMSA6IDIpO30sXG4gICAgICAgIDE5OiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcihuPT0xID8gMCA6IG49PT0wIHx8ICggbiUxMDA+MSAmJiBuJTEwMDwxMSkgPyAxIDogKG4lMTAwPjEwICYmIG4lMTAwPDIwICkgPyAyIDogMyk7fSxcbiAgICAgICAgMjA6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG49PTEgPyAwIDogKG49PT0wIHx8IChuJTEwMCA+IDAgJiYgbiUxMDAgPCAyMCkpID8gMSA6IDIpO30sXG4gICAgICAgIDIxOiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcihuJTEwMD09MSA/IDEgOiBuJTEwMD09MiA/IDIgOiBuJTEwMD09MyB8fCBuJTEwMD09NCA/IDMgOiAwKTsgfVxuICAgIH07XG4gICAgXG4gICAgdmFyIHBsdXJhbEV4dGVuc2lvbnMgPSB7XG4gICAgXG4gICAgICAgIHJ1bGVzOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGwsIHJ1bGVzID0ge307XG4gICAgICAgICAgICBmb3IgKGw9X3J1bGVzLmxlbmd0aDsgbC0tIDspIHtcbiAgICAgICAgICAgICAgICBydWxlc1tfcnVsZXNbbF1bMF1dID0ge1xuICAgICAgICAgICAgICAgICAgICBuYW1lOiBfcnVsZXNbbF1bMV0sXG4gICAgICAgICAgICAgICAgICAgIG51bWJlcnM6IF9ydWxlc1tsXVsyXSxcbiAgICAgICAgICAgICAgICAgICAgcGx1cmFsczogX3J1bGVzUGx1cmFsc1R5cGVzW19ydWxlc1tsXVszXV1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcnVsZXM7XG4gICAgICAgIH0oKSksXG4gICAgXG4gICAgICAgIC8vIHlvdSBjYW4gYWRkIHlvdXIgb3duIHBsdXJhbEV4dGVuc2lvbnNcbiAgICAgICAgYWRkUnVsZTogZnVuY3Rpb24obG5nLCBvYmopIHtcbiAgICAgICAgICAgIHBsdXJhbEV4dGVuc2lvbnMucnVsZXNbbG5nXSA9IG9iajtcbiAgICAgICAgfSxcbiAgICBcbiAgICAgICAgc2V0Q3VycmVudExuZzogZnVuY3Rpb24obG5nKSB7XG4gICAgICAgICAgICBpZiAoIXBsdXJhbEV4dGVuc2lvbnMuY3VycmVudFJ1bGUgfHwgcGx1cmFsRXh0ZW5zaW9ucy5jdXJyZW50UnVsZS5sbmcgIT09IGxuZykge1xuICAgICAgICAgICAgICAgIHZhciBwYXJ0cyA9IGxuZy5zcGxpdCgnLScpO1xuICAgIFxuICAgICAgICAgICAgICAgIHBsdXJhbEV4dGVuc2lvbnMuY3VycmVudFJ1bGUgPSB7XG4gICAgICAgICAgICAgICAgICAgIGxuZzogbG5nLFxuICAgICAgICAgICAgICAgICAgICBydWxlOiBwbHVyYWxFeHRlbnNpb25zLnJ1bGVzW3BhcnRzWzBdXVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgXG4gICAgICAgIG5lZWRzUGx1cmFsOiBmdW5jdGlvbihsbmcsIGNvdW50KSB7XG4gICAgICAgICAgICB2YXIgcGFydHMgPSBsbmcuc3BsaXQoJy0nKTtcbiAgICBcbiAgICAgICAgICAgIHZhciBleHQ7XG4gICAgICAgICAgICBpZiAocGx1cmFsRXh0ZW5zaW9ucy5jdXJyZW50UnVsZSAmJiBwbHVyYWxFeHRlbnNpb25zLmN1cnJlbnRSdWxlLmxuZyA9PT0gbG5nKSB7XG4gICAgICAgICAgICAgICAgZXh0ID0gcGx1cmFsRXh0ZW5zaW9ucy5jdXJyZW50UnVsZS5ydWxlOyBcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXh0ID0gcGx1cmFsRXh0ZW5zaW9ucy5ydWxlc1twYXJ0c1tmLmdldENvdW50eUluZGV4T2ZMbmcobG5nKV1dO1xuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgaWYgKGV4dCAmJiBleHQubnVtYmVycy5sZW5ndGggPD0gMSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0KGxuZywgY291bnQpICE9PSAxO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgIFxuICAgICAgICBnZXQ6IGZ1bmN0aW9uKGxuZywgY291bnQpIHtcbiAgICAgICAgICAgIHZhciBwYXJ0cyA9IGxuZy5zcGxpdCgnLScpO1xuICAgIFxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0UmVzdWx0KGwsIGMpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXh0O1xuICAgICAgICAgICAgICAgIGlmIChwbHVyYWxFeHRlbnNpb25zLmN1cnJlbnRSdWxlICYmIHBsdXJhbEV4dGVuc2lvbnMuY3VycmVudFJ1bGUubG5nID09PSBsbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgZXh0ID0gcGx1cmFsRXh0ZW5zaW9ucy5jdXJyZW50UnVsZS5ydWxlOyBcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBleHQgPSBwbHVyYWxFeHRlbnNpb25zLnJ1bGVzW2xdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZXh0KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXh0Lm5vQWJzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpID0gZXh0LnBsdXJhbHMoYyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpID0gZXh0LnBsdXJhbHMoTWF0aC5hYnMoYykpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICB2YXIgbnVtYmVyID0gZXh0Lm51bWJlcnNbaV07XG4gICAgICAgICAgICAgICAgICAgIGlmIChleHQubnVtYmVycy5sZW5ndGggPT09IDIgJiYgZXh0Lm51bWJlcnNbMF0gPT09IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChudW1iZXIgPT09IDIpIHsgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyID0gLTE7IC8vIHJlZ3VsYXIgcGx1cmFsXG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG51bWJlciA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlciA9IDE7IC8vIHNpbmd1bGFyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0vL2NvbnNvbGUubG9nKGNvdW50ICsgJy0nICsgbnVtYmVyKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bWJlcjtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYyA9PT0gMSA/ICcxJyA6ICctMSc7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICByZXR1cm4gZ2V0UmVzdWx0KHBhcnRzW2YuZ2V0Q291bnR5SW5kZXhPZkxuZyhsbmcpXSwgY291bnQpO1xuICAgICAgICB9XG4gICAgXG4gICAgfTtcbiAgICB2YXIgcG9zdFByb2Nlc3NvcnMgPSB7fTtcbiAgICB2YXIgYWRkUG9zdFByb2Nlc3NvciA9IGZ1bmN0aW9uKG5hbWUsIGZjKSB7XG4gICAgICAgIHBvc3RQcm9jZXNzb3JzW25hbWVdID0gZmM7XG4gICAgfTtcbiAgICAvLyBzcHJpbnRmIHN1cHBvcnRcbiAgICB2YXIgc3ByaW50ZiA9IChmdW5jdGlvbigpIHtcbiAgICAgICAgZnVuY3Rpb24gZ2V0X3R5cGUodmFyaWFibGUpIHtcbiAgICAgICAgICAgIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFyaWFibGUpLnNsaWNlKDgsIC0xKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB9XG4gICAgICAgIGZ1bmN0aW9uIHN0cl9yZXBlYXQoaW5wdXQsIG11bHRpcGxpZXIpIHtcbiAgICAgICAgICAgIGZvciAodmFyIG91dHB1dCA9IFtdOyBtdWx0aXBsaWVyID4gMDsgb3V0cHV0Wy0tbXVsdGlwbGllcl0gPSBpbnB1dCkgey8qIGRvIG5vdGhpbmcgKi99XG4gICAgICAgICAgICByZXR1cm4gb3V0cHV0LmpvaW4oJycpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIHZhciBzdHJfZm9ybWF0ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBpZiAoIXN0cl9mb3JtYXQuY2FjaGUuaGFzT3duUHJvcGVydHkoYXJndW1lbnRzWzBdKSkge1xuICAgICAgICAgICAgICAgIHN0cl9mb3JtYXQuY2FjaGVbYXJndW1lbnRzWzBdXSA9IHN0cl9mb3JtYXQucGFyc2UoYXJndW1lbnRzWzBdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzdHJfZm9ybWF0LmZvcm1hdC5jYWxsKG51bGwsIHN0cl9mb3JtYXQuY2FjaGVbYXJndW1lbnRzWzBdXSwgYXJndW1lbnRzKTtcbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgc3RyX2Zvcm1hdC5mb3JtYXQgPSBmdW5jdGlvbihwYXJzZV90cmVlLCBhcmd2KSB7XG4gICAgICAgICAgICB2YXIgY3Vyc29yID0gMSwgdHJlZV9sZW5ndGggPSBwYXJzZV90cmVlLmxlbmd0aCwgbm9kZV90eXBlID0gJycsIGFyZywgb3V0cHV0ID0gW10sIGksIGssIG1hdGNoLCBwYWQsIHBhZF9jaGFyYWN0ZXIsIHBhZF9sZW5ndGg7XG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdHJlZV9sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIG5vZGVfdHlwZSA9IGdldF90eXBlKHBhcnNlX3RyZWVbaV0pO1xuICAgICAgICAgICAgICAgIGlmIChub2RlX3R5cGUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dHB1dC5wdXNoKHBhcnNlX3RyZWVbaV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChub2RlX3R5cGUgPT09ICdhcnJheScpIHtcbiAgICAgICAgICAgICAgICAgICAgbWF0Y2ggPSBwYXJzZV90cmVlW2ldOyAvLyBjb252ZW5pZW5jZSBwdXJwb3NlcyBvbmx5XG4gICAgICAgICAgICAgICAgICAgIGlmIChtYXRjaFsyXSkgeyAvLyBrZXl3b3JkIGFyZ3VtZW50XG4gICAgICAgICAgICAgICAgICAgICAgICBhcmcgPSBhcmd2W2N1cnNvcl07XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGsgPSAwOyBrIDwgbWF0Y2hbMl0ubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWFyZy5oYXNPd25Qcm9wZXJ0eShtYXRjaFsyXVtrXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3coc3ByaW50ZignW3NwcmludGZdIHByb3BlcnR5IFwiJXNcIiBkb2VzIG5vdCBleGlzdCcsIG1hdGNoWzJdW2tdKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZyA9IGFyZ1ttYXRjaFsyXVtrXV07XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAobWF0Y2hbMV0pIHsgLy8gcG9zaXRpb25hbCBhcmd1bWVudCAoZXhwbGljaXQpXG4gICAgICAgICAgICAgICAgICAgICAgICBhcmcgPSBhcmd2W21hdGNoWzFdXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHsgLy8gcG9zaXRpb25hbCBhcmd1bWVudCAoaW1wbGljaXQpXG4gICAgICAgICAgICAgICAgICAgICAgICBhcmcgPSBhcmd2W2N1cnNvcisrXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgICAgICAgICBpZiAoL1tec10vLnRlc3QobWF0Y2hbOF0pICYmIChnZXRfdHlwZShhcmcpICE9ICdudW1iZXInKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3coc3ByaW50ZignW3NwcmludGZdIGV4cGVjdGluZyBudW1iZXIgYnV0IGZvdW5kICVzJywgZ2V0X3R5cGUoYXJnKSkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHN3aXRjaCAobWF0Y2hbOF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2InOiBhcmcgPSBhcmcudG9TdHJpbmcoMik7IGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnYyc6IGFyZyA9IFN0cmluZy5mcm9tQ2hhckNvZGUoYXJnKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdkJzogYXJnID0gcGFyc2VJbnQoYXJnLCAxMCk7IGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnZSc6IGFyZyA9IG1hdGNoWzddID8gYXJnLnRvRXhwb25lbnRpYWwobWF0Y2hbN10pIDogYXJnLnRvRXhwb25lbnRpYWwoKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdmJzogYXJnID0gbWF0Y2hbN10gPyBwYXJzZUZsb2F0KGFyZykudG9GaXhlZChtYXRjaFs3XSkgOiBwYXJzZUZsb2F0KGFyZyk7IGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnbyc6IGFyZyA9IGFyZy50b1N0cmluZyg4KTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdzJzogYXJnID0gKChhcmcgPSBTdHJpbmcoYXJnKSkgJiYgbWF0Y2hbN10gPyBhcmcuc3Vic3RyaW5nKDAsIG1hdGNoWzddKSA6IGFyZyk7IGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAndSc6IGFyZyA9IE1hdGguYWJzKGFyZyk7IGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAneCc6IGFyZyA9IGFyZy50b1N0cmluZygxNik7IGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnWCc6IGFyZyA9IGFyZy50b1N0cmluZygxNikudG9VcHBlckNhc2UoKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYXJnID0gKC9bZGVmXS8udGVzdChtYXRjaFs4XSkgJiYgbWF0Y2hbM10gJiYgYXJnID49IDAgPyAnKycrIGFyZyA6IGFyZyk7XG4gICAgICAgICAgICAgICAgICAgIHBhZF9jaGFyYWN0ZXIgPSBtYXRjaFs0XSA/IG1hdGNoWzRdID09ICcwJyA/ICcwJyA6IG1hdGNoWzRdLmNoYXJBdCgxKSA6ICcgJztcbiAgICAgICAgICAgICAgICAgICAgcGFkX2xlbmd0aCA9IG1hdGNoWzZdIC0gU3RyaW5nKGFyZykubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICBwYWQgPSBtYXRjaFs2XSA/IHN0cl9yZXBlYXQocGFkX2NoYXJhY3RlciwgcGFkX2xlbmd0aCkgOiAnJztcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0LnB1c2gobWF0Y2hbNV0gPyBhcmcgKyBwYWQgOiBwYWQgKyBhcmcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBvdXRwdXQuam9pbignJyk7XG4gICAgICAgIH07XG4gICAgXG4gICAgICAgIHN0cl9mb3JtYXQuY2FjaGUgPSB7fTtcbiAgICBcbiAgICAgICAgc3RyX2Zvcm1hdC5wYXJzZSA9IGZ1bmN0aW9uKGZtdCkge1xuICAgICAgICAgICAgdmFyIF9mbXQgPSBmbXQsIG1hdGNoID0gW10sIHBhcnNlX3RyZWUgPSBbXSwgYXJnX25hbWVzID0gMDtcbiAgICAgICAgICAgIHdoaWxlIChfZm10KSB7XG4gICAgICAgICAgICAgICAgaWYgKChtYXRjaCA9IC9eW15cXHgyNV0rLy5leGVjKF9mbXQpKSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBwYXJzZV90cmVlLnB1c2gobWF0Y2hbMF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmICgobWF0Y2ggPSAvXlxceDI1ezJ9Ly5leGVjKF9mbXQpKSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBwYXJzZV90cmVlLnB1c2goJyUnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoKG1hdGNoID0gL15cXHgyNSg/OihbMS05XVxcZCopXFwkfFxcKChbXlxcKV0rKVxcKSk/KFxcKyk/KDB8J1teJF0pPygtKT8oXFxkKyk/KD86XFwuKFxcZCspKT8oW2ItZm9zdXhYXSkvLmV4ZWMoX2ZtdCkpICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChtYXRjaFsyXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYXJnX25hbWVzIHw9IDE7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmllbGRfbGlzdCA9IFtdLCByZXBsYWNlbWVudF9maWVsZCA9IG1hdGNoWzJdLCBmaWVsZF9tYXRjaCA9IFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKChmaWVsZF9tYXRjaCA9IC9eKFthLXpfXVthLXpfXFxkXSopL2kuZXhlYyhyZXBsYWNlbWVudF9maWVsZCkpICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZmllbGRfbGlzdC5wdXNoKGZpZWxkX21hdGNoWzFdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGlsZSAoKHJlcGxhY2VtZW50X2ZpZWxkID0gcmVwbGFjZW1lbnRfZmllbGQuc3Vic3RyaW5nKGZpZWxkX21hdGNoWzBdLmxlbmd0aCkpICE9PSAnJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoKGZpZWxkX21hdGNoID0gL15cXC4oW2Etel9dW2Etel9cXGRdKikvaS5leGVjKHJlcGxhY2VtZW50X2ZpZWxkKSkgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpZWxkX2xpc3QucHVzaChmaWVsZF9tYXRjaFsxXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoKGZpZWxkX21hdGNoID0gL15cXFsoXFxkKylcXF0vLmV4ZWMocmVwbGFjZW1lbnRfZmllbGQpKSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmllbGRfbGlzdC5wdXNoKGZpZWxkX21hdGNoWzFdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93KCdbc3ByaW50Zl0gaHVoPycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3coJ1tzcHJpbnRmXSBodWg/Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBtYXRjaFsyXSA9IGZpZWxkX2xpc3Q7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhcmdfbmFtZXMgfD0gMjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoYXJnX25hbWVzID09PSAzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdygnW3NwcmludGZdIG1peGluZyBwb3NpdGlvbmFsIGFuZCBuYW1lZCBwbGFjZWhvbGRlcnMgaXMgbm90ICh5ZXQpIHN1cHBvcnRlZCcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHBhcnNlX3RyZWUucHVzaChtYXRjaCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdygnW3NwcmludGZdIGh1aD8nKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgX2ZtdCA9IF9mbXQuc3Vic3RyaW5nKG1hdGNoWzBdLmxlbmd0aCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcGFyc2VfdHJlZTtcbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgcmV0dXJuIHN0cl9mb3JtYXQ7XG4gICAgfSkoKTtcbiAgICBcbiAgICB2YXIgdnNwcmludGYgPSBmdW5jdGlvbihmbXQsIGFyZ3YpIHtcbiAgICAgICAgYXJndi51bnNoaWZ0KGZtdCk7XG4gICAgICAgIHJldHVybiBzcHJpbnRmLmFwcGx5KG51bGwsIGFyZ3YpO1xuICAgIH07XG4gICAgXG4gICAgYWRkUG9zdFByb2Nlc3NvcihcInNwcmludGZcIiwgZnVuY3Rpb24odmFsLCBrZXksIG9wdHMpIHtcbiAgICAgICAgaWYgKCFvcHRzLnNwcmludGYpIHJldHVybiB2YWw7XG4gICAgXG4gICAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmFwcGx5KG9wdHMuc3ByaW50ZikgPT09ICdbb2JqZWN0IEFycmF5XScpIHtcbiAgICAgICAgICAgIHJldHVybiB2c3ByaW50Zih2YWwsIG9wdHMuc3ByaW50Zik7XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIG9wdHMuc3ByaW50ZiA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiBzcHJpbnRmKHZhbCwgb3B0cy5zcHJpbnRmKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH0pO1xuICAgIC8vIHB1YmxpYyBhcGkgaW50ZXJmYWNlXG4gICAgaTE4bi5pbml0ID0gaW5pdDtcbiAgICBpMThuLnNldExuZyA9IHNldExuZztcbiAgICBpMThuLnByZWxvYWQgPSBwcmVsb2FkO1xuICAgIGkxOG4uYWRkUmVzb3VyY2VCdW5kbGUgPSBhZGRSZXNvdXJjZUJ1bmRsZTtcbiAgICBpMThuLmhhc1Jlc291cmNlQnVuZGxlID0gaGFzUmVzb3VyY2VCdW5kbGU7XG4gICAgaTE4bi5hZGRSZXNvdXJjZSA9IGFkZFJlc291cmNlO1xuICAgIGkxOG4uYWRkUmVzb3VyY2VzID0gYWRkUmVzb3VyY2VzO1xuICAgIGkxOG4ucmVtb3ZlUmVzb3VyY2VCdW5kbGUgPSByZW1vdmVSZXNvdXJjZUJ1bmRsZTtcbiAgICBpMThuLmxvYWROYW1lc3BhY2UgPSBsb2FkTmFtZXNwYWNlO1xuICAgIGkxOG4ubG9hZE5hbWVzcGFjZXMgPSBsb2FkTmFtZXNwYWNlcztcbiAgICBpMThuLnNldERlZmF1bHROYW1lc3BhY2UgPSBzZXREZWZhdWx0TmFtZXNwYWNlO1xuICAgIGkxOG4udCA9IHRyYW5zbGF0ZTtcbiAgICBpMThuLnRyYW5zbGF0ZSA9IHRyYW5zbGF0ZTtcbiAgICBpMThuLmV4aXN0cyA9IGV4aXN0cztcbiAgICBpMThuLmRldGVjdExhbmd1YWdlID0gZi5kZXRlY3RMYW5ndWFnZTtcbiAgICBpMThuLnBsdXJhbEV4dGVuc2lvbnMgPSBwbHVyYWxFeHRlbnNpb25zO1xuICAgIGkxOG4uc3luYyA9IHN5bmM7XG4gICAgaTE4bi5mdW5jdGlvbnMgPSBmO1xuICAgIGkxOG4ubG5nID0gbG5nO1xuICAgIGkxOG4uYWRkUG9zdFByb2Nlc3NvciA9IGFkZFBvc3RQcm9jZXNzb3I7XG4gICAgaTE4bi5vcHRpb25zID0gbztcblxufSkoKTsiLCIvLyBUb3AgbGV2ZWwgZmlsZSBpcyBqdXN0IGEgbWl4aW4gb2Ygc3VibW9kdWxlcyAmIGNvbnN0YW50c1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgYXNzaWduICAgID0gcmVxdWlyZSgnLi9saWIvdXRpbHMvY29tbW9uJykuYXNzaWduO1xuXG52YXIgZGVmbGF0ZSAgID0gcmVxdWlyZSgnLi9saWIvZGVmbGF0ZScpO1xudmFyIGluZmxhdGUgICA9IHJlcXVpcmUoJy4vbGliL2luZmxhdGUnKTtcbnZhciBjb25zdGFudHMgPSByZXF1aXJlKCcuL2xpYi96bGliL2NvbnN0YW50cycpO1xuXG52YXIgcGFrbyA9IHt9O1xuXG5hc3NpZ24ocGFrbywgZGVmbGF0ZSwgaW5mbGF0ZSwgY29uc3RhbnRzKTtcblxubW9kdWxlLmV4cG9ydHMgPSBwYWtvOyIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgemxpYl9kZWZsYXRlID0gcmVxdWlyZSgnLi96bGliL2RlZmxhdGUuanMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvY29tbW9uJyk7XG52YXIgc3RyaW5ncyA9IHJlcXVpcmUoJy4vdXRpbHMvc3RyaW5ncycpO1xudmFyIG1zZyA9IHJlcXVpcmUoJy4vemxpYi9tZXNzYWdlcycpO1xudmFyIHpzdHJlYW0gPSByZXF1aXJlKCcuL3psaWIvenN0cmVhbScpO1xuXG52YXIgdG9TdHJpbmcgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO1xuXG4vKiBQdWJsaWMgY29uc3RhbnRzID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0qL1xuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cblxudmFyIFpfTk9fRkxVU0ggICAgICA9IDA7XG52YXIgWl9GSU5JU0ggICAgICAgID0gNDtcblxudmFyIFpfT0sgICAgICAgICAgICA9IDA7XG52YXIgWl9TVFJFQU1fRU5EICAgID0gMTtcblxudmFyIFpfREVGQVVMVF9DT01QUkVTU0lPTiA9IC0xO1xuXG52YXIgWl9ERUZBVUxUX1NUUkFURUdZICAgID0gMDtcblxudmFyIFpfREVGTEFURUQgID0gODtcblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cblxuXG4vKipcbiAqIGNsYXNzIERlZmxhdGVcbiAqXG4gKiBHZW5lcmljIEpTLXN0eWxlIHdyYXBwZXIgZm9yIHpsaWIgY2FsbHMuIElmIHlvdSBkb24ndCBuZWVkXG4gKiBzdHJlYW1pbmcgYmVoYXZpb3VyIC0gdXNlIG1vcmUgc2ltcGxlIGZ1bmN0aW9uczogW1tkZWZsYXRlXV0sXG4gKiBbW2RlZmxhdGVSYXddXSBhbmQgW1tnemlwXV0uXG4gKiovXG5cbi8qIGludGVybmFsXG4gKiBEZWZsYXRlLmNodW5rcyAtPiBBcnJheVxuICpcbiAqIENodW5rcyBvZiBvdXRwdXQgZGF0YSwgaWYgW1tEZWZsYXRlI29uRGF0YV1dIG5vdCBvdmVycmlkZW4uXG4gKiovXG5cbi8qKlxuICogRGVmbGF0ZS5yZXN1bHQgLT4gVWludDhBcnJheXxBcnJheVxuICpcbiAqIENvbXByZXNzZWQgcmVzdWx0LCBnZW5lcmF0ZWQgYnkgZGVmYXVsdCBbW0RlZmxhdGUjb25EYXRhXV1cbiAqIGFuZCBbW0RlZmxhdGUjb25FbmRdXSBoYW5kbGVycy4gRmlsbGVkIGFmdGVyIHlvdSBwdXNoIGxhc3QgY2h1bmtcbiAqIChjYWxsIFtbRGVmbGF0ZSNwdXNoXV0gd2l0aCBgWl9GSU5JU0hgIC8gYHRydWVgIHBhcmFtKS5cbiAqKi9cblxuLyoqXG4gKiBEZWZsYXRlLmVyciAtPiBOdW1iZXJcbiAqXG4gKiBFcnJvciBjb2RlIGFmdGVyIGRlZmxhdGUgZmluaXNoZWQuIDAgKFpfT0spIG9uIHN1Y2Nlc3MuXG4gKiBZb3Ugd2lsbCBub3QgbmVlZCBpdCBpbiByZWFsIGxpZmUsIGJlY2F1c2UgZGVmbGF0ZSBlcnJvcnNcbiAqIGFyZSBwb3NzaWJsZSBvbmx5IG9uIHdyb25nIG9wdGlvbnMgb3IgYmFkIGBvbkRhdGFgIC8gYG9uRW5kYFxuICogY3VzdG9tIGhhbmRsZXJzLlxuICoqL1xuXG4vKipcbiAqIERlZmxhdGUubXNnIC0+IFN0cmluZ1xuICpcbiAqIEVycm9yIG1lc3NhZ2UsIGlmIFtbRGVmbGF0ZS5lcnJdXSAhPSAwXG4gKiovXG5cblxuLyoqXG4gKiBuZXcgRGVmbGF0ZShvcHRpb25zKVxuICogLSBvcHRpb25zIChPYmplY3QpOiB6bGliIGRlZmxhdGUgb3B0aW9ucy5cbiAqXG4gKiBDcmVhdGVzIG5ldyBkZWZsYXRvciBpbnN0YW5jZSB3aXRoIHNwZWNpZmllZCBwYXJhbXMuIFRocm93cyBleGNlcHRpb25cbiAqIG9uIGJhZCBwYXJhbXMuIFN1cHBvcnRlZCBvcHRpb25zOlxuICpcbiAqIC0gYGxldmVsYFxuICogLSBgd2luZG93Qml0c2BcbiAqIC0gYG1lbUxldmVsYFxuICogLSBgc3RyYXRlZ3lgXG4gKlxuICogW2h0dHA6Ly96bGliLm5ldC9tYW51YWwuaHRtbCNBZHZhbmNlZF0oaHR0cDovL3psaWIubmV0L21hbnVhbC5odG1sI0FkdmFuY2VkKVxuICogZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdGhlc2UuXG4gKlxuICogQWRkaXRpb25hbCBvcHRpb25zLCBmb3IgaW50ZXJuYWwgbmVlZHM6XG4gKlxuICogLSBgY2h1bmtTaXplYCAtIHNpemUgb2YgZ2VuZXJhdGVkIGRhdGEgY2h1bmtzICgxNksgYnkgZGVmYXVsdClcbiAqIC0gYHJhd2AgKEJvb2xlYW4pIC0gZG8gcmF3IGRlZmxhdGVcbiAqIC0gYGd6aXBgIChCb29sZWFuKSAtIGNyZWF0ZSBnemlwIHdyYXBwZXJcbiAqIC0gYHRvYCAoU3RyaW5nKSAtIGlmIGVxdWFsIHRvICdzdHJpbmcnLCB0aGVuIHJlc3VsdCB3aWxsIGJlIFwiYmluYXJ5IHN0cmluZ1wiXG4gKiAgICAoZWFjaCBjaGFyIGNvZGUgWzAuLjI1NV0pXG4gKiAtIGBoZWFkZXJgIChPYmplY3QpIC0gY3VzdG9tIGhlYWRlciBmb3IgZ3ppcFxuICogICAtIGB0ZXh0YCAoQm9vbGVhbikgLSB0cnVlIGlmIGNvbXByZXNzZWQgZGF0YSBiZWxpZXZlZCB0byBiZSB0ZXh0XG4gKiAgIC0gYHRpbWVgIChOdW1iZXIpIC0gbW9kaWZpY2F0aW9uIHRpbWUsIHVuaXggdGltZXN0YW1wXG4gKiAgIC0gYG9zYCAoTnVtYmVyKSAtIG9wZXJhdGlvbiBzeXN0ZW0gY29kZVxuICogICAtIGBleHRyYWAgKEFycmF5KSAtIGFycmF5IG9mIGJ5dGVzIHdpdGggZXh0cmEgZGF0YSAobWF4IDY1NTM2KVxuICogICAtIGBuYW1lYCAoU3RyaW5nKSAtIGZpbGUgbmFtZSAoYmluYXJ5IHN0cmluZylcbiAqICAgLSBgY29tbWVudGAgKFN0cmluZykgLSBjb21tZW50IChiaW5hcnkgc3RyaW5nKVxuICogICAtIGBoY3JjYCAoQm9vbGVhbikgLSB0cnVlIGlmIGhlYWRlciBjcmMgc2hvdWxkIGJlIGFkZGVkXG4gKlxuICogIyMjIyMgRXhhbXBsZTpcbiAqXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgcGFrbyA9IHJlcXVpcmUoJ3Bha28nKVxuICogICAsIGNodW5rMSA9IFVpbnQ4QXJyYXkoWzEsMiwzLDQsNSw2LDcsOCw5XSlcbiAqICAgLCBjaHVuazIgPSBVaW50OEFycmF5KFsxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOV0pO1xuICpcbiAqIHZhciBkZWZsYXRlID0gbmV3IHBha28uRGVmbGF0ZSh7IGxldmVsOiAzfSk7XG4gKlxuICogZGVmbGF0ZS5wdXNoKGNodW5rMSwgZmFsc2UpO1xuICogZGVmbGF0ZS5wdXNoKGNodW5rMiwgdHJ1ZSk7ICAvLyB0cnVlIC0+IGxhc3QgY2h1bmtcbiAqXG4gKiBpZiAoZGVmbGF0ZS5lcnIpIHsgdGhyb3cgbmV3IEVycm9yKGRlZmxhdGUuZXJyKTsgfVxuICpcbiAqIGNvbnNvbGUubG9nKGRlZmxhdGUucmVzdWx0KTtcbiAqIGBgYFxuICoqL1xudmFyIERlZmxhdGUgPSBmdW5jdGlvbihvcHRpb25zKSB7XG5cbiAgdGhpcy5vcHRpb25zID0gdXRpbHMuYXNzaWduKHtcbiAgICBsZXZlbDogWl9ERUZBVUxUX0NPTVBSRVNTSU9OLFxuICAgIG1ldGhvZDogWl9ERUZMQVRFRCxcbiAgICBjaHVua1NpemU6IDE2Mzg0LFxuICAgIHdpbmRvd0JpdHM6IDE1LFxuICAgIG1lbUxldmVsOiA4LFxuICAgIHN0cmF0ZWd5OiBaX0RFRkFVTFRfU1RSQVRFR1ksXG4gICAgdG86ICcnXG4gIH0sIG9wdGlvbnMgfHwge30pO1xuXG4gIHZhciBvcHQgPSB0aGlzLm9wdGlvbnM7XG5cbiAgaWYgKG9wdC5yYXcgJiYgKG9wdC53aW5kb3dCaXRzID4gMCkpIHtcbiAgICBvcHQud2luZG93Qml0cyA9IC1vcHQud2luZG93Qml0cztcbiAgfVxuXG4gIGVsc2UgaWYgKG9wdC5nemlwICYmIChvcHQud2luZG93Qml0cyA+IDApICYmIChvcHQud2luZG93Qml0cyA8IDE2KSkge1xuICAgIG9wdC53aW5kb3dCaXRzICs9IDE2O1xuICB9XG5cbiAgdGhpcy5lcnIgICAgPSAwOyAgICAgIC8vIGVycm9yIGNvZGUsIGlmIGhhcHBlbnMgKDAgPSBaX09LKVxuICB0aGlzLm1zZyAgICA9ICcnOyAgICAgLy8gZXJyb3IgbWVzc2FnZVxuICB0aGlzLmVuZGVkICA9IGZhbHNlOyAgLy8gdXNlZCB0byBhdm9pZCBtdWx0aXBsZSBvbkVuZCgpIGNhbGxzXG4gIHRoaXMuY2h1bmtzID0gW107ICAgICAvLyBjaHVua3Mgb2YgY29tcHJlc3NlZCBkYXRhXG5cbiAgdGhpcy5zdHJtID0gbmV3IHpzdHJlYW0oKTtcbiAgdGhpcy5zdHJtLmF2YWlsX291dCA9IDA7XG5cbiAgdmFyIHN0YXR1cyA9IHpsaWJfZGVmbGF0ZS5kZWZsYXRlSW5pdDIoXG4gICAgdGhpcy5zdHJtLFxuICAgIG9wdC5sZXZlbCxcbiAgICBvcHQubWV0aG9kLFxuICAgIG9wdC53aW5kb3dCaXRzLFxuICAgIG9wdC5tZW1MZXZlbCxcbiAgICBvcHQuc3RyYXRlZ3lcbiAgKTtcblxuICBpZiAoc3RhdHVzICE9PSBaX09LKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKG1zZ1tzdGF0dXNdKTtcbiAgfVxuXG4gIGlmIChvcHQuaGVhZGVyKSB7XG4gICAgemxpYl9kZWZsYXRlLmRlZmxhdGVTZXRIZWFkZXIodGhpcy5zdHJtLCBvcHQuaGVhZGVyKTtcbiAgfVxufTtcblxuLyoqXG4gKiBEZWZsYXRlI3B1c2goZGF0YVssIG1vZGVdKSAtPiBCb29sZWFuXG4gKiAtIGRhdGEgKFVpbnQ4QXJyYXl8QXJyYXl8QXJyYXlCdWZmZXJ8U3RyaW5nKTogaW5wdXQgZGF0YS4gU3RyaW5ncyB3aWxsIGJlXG4gKiAgIGNvbnZlcnRlZCB0byB1dGY4IGJ5dGUgc2VxdWVuY2UuXG4gKiAtIG1vZGUgKE51bWJlcnxCb29sZWFuKTogMC4uNiBmb3IgY29ycmVzcG9uZGluZyBaX05PX0ZMVVNILi5aX1RSRUUgbW9kZXMuXG4gKiAgIFNlZSBjb25zdGFudHMuIFNraXBwZWQgb3IgYGZhbHNlYCBtZWFucyBaX05PX0ZMVVNILCBgdHJ1ZWAgbWVhbnNoIFpfRklOSVNILlxuICpcbiAqIFNlbmRzIGlucHV0IGRhdGEgdG8gZGVmbGF0ZSBwaXBlLCBnZW5lcmF0aW5nIFtbRGVmbGF0ZSNvbkRhdGFdXSBjYWxscyB3aXRoXG4gKiBuZXcgY29tcHJlc3NlZCBjaHVua3MuIFJldHVybnMgYHRydWVgIG9uIHN1Y2Nlc3MuIFRoZSBsYXN0IGRhdGEgYmxvY2sgbXVzdCBoYXZlXG4gKiBtb2RlIFpfRklOSVNIIChvciBgdHJ1ZWApLiBUaGF0IGZsdXNoIGludGVybmFsIHBlbmRpbmcgYnVmZmVycyBhbmQgY2FsbFxuICogW1tEZWZsYXRlI29uRW5kXV0uXG4gKlxuICogT24gZmFpbCBjYWxsIFtbRGVmbGF0ZSNvbkVuZF1dIHdpdGggZXJyb3IgY29kZSBhbmQgcmV0dXJuIGZhbHNlLlxuICpcbiAqIFdlIHN0cm9uZ2x5IHJlY29tbWVuZCB0byB1c2UgYFVpbnQ4QXJyYXlgIG9uIGlucHV0IGZvciBiZXN0IHNwZWVkIChvdXRwdXRcbiAqIGFycmF5IGZvcm1hdCBpcyBkZXRlY3RlZCBhdXRvbWF0aWNhbGx5KS4gQWxzbywgZG9uJ3Qgc2tpcCBsYXN0IHBhcmFtIGFuZCBhbHdheXNcbiAqIHVzZSB0aGUgc2FtZSB0eXBlIGluIHlvdXIgY29kZSAoYm9vbGVhbiBvciBudW1iZXIpLiBUaGF0IHdpbGwgaW1wcm92ZSBKUyBzcGVlZC5cbiAqXG4gKiBGb3IgcmVndWxhciBgQXJyYXlgLXMgbWFrZSBzdXJlIGFsbCBlbGVtZW50cyBhcmUgWzAuLjI1NV0uXG4gKlxuICogIyMjIyMgRXhhbXBsZVxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHB1c2goY2h1bmssIGZhbHNlKTsgLy8gcHVzaCBvbmUgb2YgZGF0YSBjaHVua3NcbiAqIC4uLlxuICogcHVzaChjaHVuaywgdHJ1ZSk7ICAvLyBwdXNoIGxhc3QgY2h1bmtcbiAqIGBgYFxuICoqL1xuRGVmbGF0ZS5wcm90b3R5cGUucHVzaCA9IGZ1bmN0aW9uKGRhdGEsIG1vZGUpIHtcbiAgdmFyIHN0cm0gPSB0aGlzLnN0cm07XG4gIHZhciBjaHVua1NpemUgPSB0aGlzLm9wdGlvbnMuY2h1bmtTaXplO1xuICB2YXIgc3RhdHVzLCBfbW9kZTtcblxuICBpZiAodGhpcy5lbmRlZCkgeyByZXR1cm4gZmFsc2U7IH1cblxuICBfbW9kZSA9IChtb2RlID09PSB+fm1vZGUpID8gbW9kZSA6ICgobW9kZSA9PT0gdHJ1ZSkgPyBaX0ZJTklTSCA6IFpfTk9fRkxVU0gpO1xuXG4gIC8vIENvbnZlcnQgZGF0YSBpZiBuZWVkZWRcbiAgaWYgKHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJykge1xuICAgIC8vIElmIHdlIG5lZWQgdG8gY29tcHJlc3MgdGV4dCwgY2hhbmdlIGVuY29kaW5nIHRvIHV0ZjguXG4gICAgc3RybS5pbnB1dCA9IHN0cmluZ3Muc3RyaW5nMmJ1ZihkYXRhKTtcbiAgfSBlbHNlIGlmICh0b1N0cmluZy5jYWxsKGRhdGEpID09PSAnW29iamVjdCBBcnJheUJ1ZmZlcl0nKSB7XG4gICAgc3RybS5pbnB1dCA9IG5ldyBVaW50OEFycmF5KGRhdGEpO1xuICB9IGVsc2Uge1xuICAgIHN0cm0uaW5wdXQgPSBkYXRhO1xuICB9XG5cbiAgc3RybS5uZXh0X2luID0gMDtcbiAgc3RybS5hdmFpbF9pbiA9IHN0cm0uaW5wdXQubGVuZ3RoO1xuXG4gIGRvIHtcbiAgICBpZiAoc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIHN0cm0ub3V0cHV0ID0gbmV3IHV0aWxzLkJ1ZjgoY2h1bmtTaXplKTtcbiAgICAgIHN0cm0ubmV4dF9vdXQgPSAwO1xuICAgICAgc3RybS5hdmFpbF9vdXQgPSBjaHVua1NpemU7XG4gICAgfVxuICAgIHN0YXR1cyA9IHpsaWJfZGVmbGF0ZS5kZWZsYXRlKHN0cm0sIF9tb2RlKTsgICAgLyogbm8gYmFkIHJldHVybiB2YWx1ZSAqL1xuXG4gICAgaWYgKHN0YXR1cyAhPT0gWl9TVFJFQU1fRU5EICYmIHN0YXR1cyAhPT0gWl9PSykge1xuICAgICAgdGhpcy5vbkVuZChzdGF0dXMpO1xuICAgICAgdGhpcy5lbmRlZCA9IHRydWU7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChzdHJtLmF2YWlsX291dCA9PT0gMCB8fCAoc3RybS5hdmFpbF9pbiA9PT0gMCAmJiBfbW9kZSA9PT0gWl9GSU5JU0gpKSB7XG4gICAgICBpZiAodGhpcy5vcHRpb25zLnRvID09PSAnc3RyaW5nJykge1xuICAgICAgICB0aGlzLm9uRGF0YShzdHJpbmdzLmJ1ZjJiaW5zdHJpbmcodXRpbHMuc2hyaW5rQnVmKHN0cm0ub3V0cHV0LCBzdHJtLm5leHRfb3V0KSkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5vbkRhdGEodXRpbHMuc2hyaW5rQnVmKHN0cm0ub3V0cHV0LCBzdHJtLm5leHRfb3V0KSk7XG4gICAgICB9XG4gICAgfVxuICB9IHdoaWxlICgoc3RybS5hdmFpbF9pbiA+IDAgfHwgc3RybS5hdmFpbF9vdXQgPT09IDApICYmIHN0YXR1cyAhPT0gWl9TVFJFQU1fRU5EKTtcblxuICAvLyBGaW5hbGl6ZSBvbiB0aGUgbGFzdCBjaHVuay5cbiAgaWYgKF9tb2RlID09PSBaX0ZJTklTSCkge1xuICAgIHN0YXR1cyA9IHpsaWJfZGVmbGF0ZS5kZWZsYXRlRW5kKHRoaXMuc3RybSk7XG4gICAgdGhpcy5vbkVuZChzdGF0dXMpO1xuICAgIHRoaXMuZW5kZWQgPSB0cnVlO1xuICAgIHJldHVybiBzdGF0dXMgPT09IFpfT0s7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cblxuLyoqXG4gKiBEZWZsYXRlI29uRGF0YShjaHVuaykgLT4gVm9pZFxuICogLSBjaHVuayAoVWludDhBcnJheXxBcnJheXxTdHJpbmcpOiBvdXB1dCBkYXRhLiBUeXBlIG9mIGFycmF5IGRlcGVuZHNcbiAqICAgb24ganMgZW5naW5lIHN1cHBvcnQuIFdoZW4gc3RyaW5nIG91dHB1dCByZXF1ZXN0ZWQsIGVhY2ggY2h1bmtcbiAqICAgd2lsbCBiZSBzdHJpbmcuXG4gKlxuICogQnkgZGVmYXVsdCwgc3RvcmVzIGRhdGEgYmxvY2tzIGluIGBjaHVua3NbXWAgcHJvcGVydHkgYW5kIGdsdWVcbiAqIHRob3NlIGluIGBvbkVuZGAuIE92ZXJyaWRlIHRoaXMgaGFuZGxlciwgaWYgeW91IG5lZWQgYW5vdGhlciBiZWhhdmlvdXIuXG4gKiovXG5EZWZsYXRlLnByb3RvdHlwZS5vbkRhdGEgPSBmdW5jdGlvbihjaHVuaykge1xuICB0aGlzLmNodW5rcy5wdXNoKGNodW5rKTtcbn07XG5cblxuLyoqXG4gKiBEZWZsYXRlI29uRW5kKHN0YXR1cykgLT4gVm9pZFxuICogLSBzdGF0dXMgKE51bWJlcik6IGRlZmxhdGUgc3RhdHVzLiAwIChaX09LKSBvbiBzdWNjZXNzLFxuICogICBvdGhlciBpZiBub3QuXG4gKlxuICogQ2FsbGVkIG9uY2UgYWZ0ZXIgeW91IHRlbGwgZGVmbGF0ZSB0aGF0IGlucHV0IHN0cmVhbSBjb21wbGV0ZVxuICogb3IgZXJyb3IgaGFwcGVubmVkLiBCeSBkZWZhdWx0IC0gam9pbiBjb2xsZWN0ZWQgY2h1bmtzLFxuICogZnJlZSBtZW1vcnkgYW5kIGZpbGwgYHJlc3VsdHNgIC8gYGVycmAgcHJvcGVydGllcy5cbiAqKi9cbkRlZmxhdGUucHJvdG90eXBlLm9uRW5kID0gZnVuY3Rpb24oc3RhdHVzKSB7XG4gIC8vIE9uIHN1Y2Nlc3MgLSBqb2luXG4gIGlmIChzdGF0dXMgPT09IFpfT0spIHtcbiAgICBpZiAodGhpcy5vcHRpb25zLnRvID09PSAnc3RyaW5nJykge1xuICAgICAgdGhpcy5yZXN1bHQgPSB0aGlzLmNodW5rcy5qb2luKCcnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5yZXN1bHQgPSB1dGlscy5mbGF0dGVuQ2h1bmtzKHRoaXMuY2h1bmtzKTtcbiAgICB9XG4gIH1cbiAgdGhpcy5jaHVua3MgPSBbXTtcbiAgdGhpcy5lcnIgPSBzdGF0dXM7XG4gIHRoaXMubXNnID0gdGhpcy5zdHJtLm1zZztcbn07XG5cblxuLyoqXG4gKiBkZWZsYXRlKGRhdGFbLCBvcHRpb25zXSkgLT4gVWludDhBcnJheXxBcnJheXxTdHJpbmdcbiAqIC0gZGF0YSAoVWludDhBcnJheXxBcnJheXxTdHJpbmcpOiBpbnB1dCBkYXRhIHRvIGNvbXByZXNzLlxuICogLSBvcHRpb25zIChPYmplY3QpOiB6bGliIGRlZmxhdGUgb3B0aW9ucy5cbiAqXG4gKiBDb21wcmVzcyBgZGF0YWAgd2l0aCBkZWZsYXRlIGFscm9yeXRobSBhbmQgYG9wdGlvbnNgLlxuICpcbiAqIFN1cHBvcnRlZCBvcHRpb25zIGFyZTpcbiAqXG4gKiAtIGxldmVsXG4gKiAtIHdpbmRvd0JpdHNcbiAqIC0gbWVtTGV2ZWxcbiAqIC0gc3RyYXRlZ3lcbiAqXG4gKiBbaHR0cDovL3psaWIubmV0L21hbnVhbC5odG1sI0FkdmFuY2VkXShodHRwOi8vemxpYi5uZXQvbWFudWFsLmh0bWwjQWR2YW5jZWQpXG4gKiBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGVzZS5cbiAqXG4gKiBTdWdhciAob3B0aW9ucyk6XG4gKlxuICogLSBgcmF3YCAoQm9vbGVhbikgLSBzYXkgdGhhdCB3ZSB3b3JrIHdpdGggcmF3IHN0cmVhbSwgaWYgeW91IGRvbid0IHdpc2ggdG8gc3BlY2lmeVxuICogICBuZWdhdGl2ZSB3aW5kb3dCaXRzIGltcGxpY2l0bHkuXG4gKiAtIGB0b2AgKFN0cmluZykgLSBpZiBlcXVhbCB0byAnc3RyaW5nJywgdGhlbiByZXN1bHQgd2lsbCBiZSBcImJpbmFyeSBzdHJpbmdcIlxuICogICAgKGVhY2ggY2hhciBjb2RlIFswLi4yNTVdKVxuICpcbiAqICMjIyMjIEV4YW1wbGU6XG4gKlxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIHBha28gPSByZXF1aXJlKCdwYWtvJylcbiAqICAgLCBkYXRhID0gVWludDhBcnJheShbMSwyLDMsNCw1LDYsNyw4LDldKTtcbiAqXG4gKiBjb25zb2xlLmxvZyhwYWtvLmRlZmxhdGUoZGF0YSkpO1xuICogYGBgXG4gKiovXG5mdW5jdGlvbiBkZWZsYXRlKGlucHV0LCBvcHRpb25zKSB7XG4gIHZhciBkZWZsYXRvciA9IG5ldyBEZWZsYXRlKG9wdGlvbnMpO1xuXG4gIGRlZmxhdG9yLnB1c2goaW5wdXQsIHRydWUpO1xuXG4gIC8vIFRoYXQgd2lsbCBuZXZlciBoYXBwZW5zLCBpZiB5b3UgZG9uJ3QgY2hlYXQgd2l0aCBvcHRpb25zIDopXG4gIGlmIChkZWZsYXRvci5lcnIpIHsgdGhyb3cgZGVmbGF0b3IubXNnOyB9XG5cbiAgcmV0dXJuIGRlZmxhdG9yLnJlc3VsdDtcbn1cblxuXG4vKipcbiAqIGRlZmxhdGVSYXcoZGF0YVssIG9wdGlvbnNdKSAtPiBVaW50OEFycmF5fEFycmF5fFN0cmluZ1xuICogLSBkYXRhIChVaW50OEFycmF5fEFycmF5fFN0cmluZyk6IGlucHV0IGRhdGEgdG8gY29tcHJlc3MuXG4gKiAtIG9wdGlvbnMgKE9iamVjdCk6IHpsaWIgZGVmbGF0ZSBvcHRpb25zLlxuICpcbiAqIFRoZSBzYW1lIGFzIFtbZGVmbGF0ZV1dLCBidXQgY3JlYXRlcyByYXcgZGF0YSwgd2l0aG91dCB3cmFwcGVyXG4gKiAoaGVhZGVyIGFuZCBhZGxlcjMyIGNyYykuXG4gKiovXG5mdW5jdGlvbiBkZWZsYXRlUmF3KGlucHV0LCBvcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICBvcHRpb25zLnJhdyA9IHRydWU7XG4gIHJldHVybiBkZWZsYXRlKGlucHV0LCBvcHRpb25zKTtcbn1cblxuXG4vKipcbiAqIGd6aXAoZGF0YVssIG9wdGlvbnNdKSAtPiBVaW50OEFycmF5fEFycmF5fFN0cmluZ1xuICogLSBkYXRhIChVaW50OEFycmF5fEFycmF5fFN0cmluZyk6IGlucHV0IGRhdGEgdG8gY29tcHJlc3MuXG4gKiAtIG9wdGlvbnMgKE9iamVjdCk6IHpsaWIgZGVmbGF0ZSBvcHRpb25zLlxuICpcbiAqIFRoZSBzYW1lIGFzIFtbZGVmbGF0ZV1dLCBidXQgY3JlYXRlIGd6aXAgd3JhcHBlciBpbnN0ZWFkIG9mXG4gKiBkZWZsYXRlIG9uZS5cbiAqKi9cbmZ1bmN0aW9uIGd6aXAoaW5wdXQsIG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIG9wdGlvbnMuZ3ppcCA9IHRydWU7XG4gIHJldHVybiBkZWZsYXRlKGlucHV0LCBvcHRpb25zKTtcbn1cblxuXG5leHBvcnRzLkRlZmxhdGUgPSBEZWZsYXRlO1xuZXhwb3J0cy5kZWZsYXRlID0gZGVmbGF0ZTtcbmV4cG9ydHMuZGVmbGF0ZVJhdyA9IGRlZmxhdGVSYXc7XG5leHBvcnRzLmd6aXAgPSBnemlwOyIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgemxpYl9pbmZsYXRlID0gcmVxdWlyZSgnLi96bGliL2luZmxhdGUuanMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvY29tbW9uJyk7XG52YXIgc3RyaW5ncyA9IHJlcXVpcmUoJy4vdXRpbHMvc3RyaW5ncycpO1xudmFyIGMgPSByZXF1aXJlKCcuL3psaWIvY29uc3RhbnRzJyk7XG52YXIgbXNnID0gcmVxdWlyZSgnLi96bGliL21lc3NhZ2VzJyk7XG52YXIgenN0cmVhbSA9IHJlcXVpcmUoJy4vemxpYi96c3RyZWFtJyk7XG52YXIgZ3poZWFkZXIgPSByZXF1aXJlKCcuL3psaWIvZ3poZWFkZXInKTtcblxudmFyIHRvU3RyaW5nID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcblxuLyoqXG4gKiBjbGFzcyBJbmZsYXRlXG4gKlxuICogR2VuZXJpYyBKUy1zdHlsZSB3cmFwcGVyIGZvciB6bGliIGNhbGxzLiBJZiB5b3UgZG9uJ3QgbmVlZFxuICogc3RyZWFtaW5nIGJlaGF2aW91ciAtIHVzZSBtb3JlIHNpbXBsZSBmdW5jdGlvbnM6IFtbaW5mbGF0ZV1dXG4gKiBhbmQgW1tpbmZsYXRlUmF3XV0uXG4gKiovXG5cbi8qIGludGVybmFsXG4gKiBpbmZsYXRlLmNodW5rcyAtPiBBcnJheVxuICpcbiAqIENodW5rcyBvZiBvdXRwdXQgZGF0YSwgaWYgW1tJbmZsYXRlI29uRGF0YV1dIG5vdCBvdmVycmlkZW4uXG4gKiovXG5cbi8qKlxuICogSW5mbGF0ZS5yZXN1bHQgLT4gVWludDhBcnJheXxBcnJheXxTdHJpbmdcbiAqXG4gKiBVbmNvbXByZXNzZWQgcmVzdWx0LCBnZW5lcmF0ZWQgYnkgZGVmYXVsdCBbW0luZmxhdGUjb25EYXRhXV1cbiAqIGFuZCBbW0luZmxhdGUjb25FbmRdXSBoYW5kbGVycy4gRmlsbGVkIGFmdGVyIHlvdSBwdXNoIGxhc3QgY2h1bmtcbiAqIChjYWxsIFtbSW5mbGF0ZSNwdXNoXV0gd2l0aCBgWl9GSU5JU0hgIC8gYHRydWVgIHBhcmFtKS5cbiAqKi9cblxuLyoqXG4gKiBJbmZsYXRlLmVyciAtPiBOdW1iZXJcbiAqXG4gKiBFcnJvciBjb2RlIGFmdGVyIGluZmxhdGUgZmluaXNoZWQuIDAgKFpfT0spIG9uIHN1Y2Nlc3MuXG4gKiBTaG91bGQgYmUgY2hlY2tlZCBpZiBicm9rZW4gZGF0YSBwb3NzaWJsZS5cbiAqKi9cblxuLyoqXG4gKiBJbmZsYXRlLm1zZyAtPiBTdHJpbmdcbiAqXG4gKiBFcnJvciBtZXNzYWdlLCBpZiBbW0luZmxhdGUuZXJyXV0gIT0gMFxuICoqL1xuXG5cbi8qKlxuICogbmV3IEluZmxhdGUob3B0aW9ucylcbiAqIC0gb3B0aW9ucyAoT2JqZWN0KTogemxpYiBpbmZsYXRlIG9wdGlvbnMuXG4gKlxuICogQ3JlYXRlcyBuZXcgaW5mbGF0b3IgaW5zdGFuY2Ugd2l0aCBzcGVjaWZpZWQgcGFyYW1zLiBUaHJvd3MgZXhjZXB0aW9uXG4gKiBvbiBiYWQgcGFyYW1zLiBTdXBwb3J0ZWQgb3B0aW9uczpcbiAqXG4gKiAtIGB3aW5kb3dCaXRzYFxuICpcbiAqIFtodHRwOi8vemxpYi5uZXQvbWFudWFsLmh0bWwjQWR2YW5jZWRdKGh0dHA6Ly96bGliLm5ldC9tYW51YWwuaHRtbCNBZHZhbmNlZClcbiAqIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZXNlLlxuICpcbiAqIEFkZGl0aW9uYWwgb3B0aW9ucywgZm9yIGludGVybmFsIG5lZWRzOlxuICpcbiAqIC0gYGNodW5rU2l6ZWAgLSBzaXplIG9mIGdlbmVyYXRlZCBkYXRhIGNodW5rcyAoMTZLIGJ5IGRlZmF1bHQpXG4gKiAtIGByYXdgIChCb29sZWFuKSAtIGRvIHJhdyBpbmZsYXRlXG4gKiAtIGB0b2AgKFN0cmluZykgLSBpZiBlcXVhbCB0byAnc3RyaW5nJywgdGhlbiByZXN1bHQgd2lsbCBiZSBjb252ZXJ0ZWRcbiAqICAgZnJvbSB1dGY4IHRvIHV0ZjE2IChqYXZhc2NyaXB0KSBzdHJpbmcuIFdoZW4gc3RyaW5nIG91dHB1dCByZXF1ZXN0ZWQsXG4gKiAgIGNodW5rIGxlbmd0aCBjYW4gZGlmZmVyIGZyb20gYGNodW5rU2l6ZWAsIGRlcGVuZGluZyBvbiBjb250ZW50LlxuICpcbiAqIEJ5IGRlZmF1bHQsIHdoZW4gbm8gb3B0aW9ucyBzZXQsIGF1dG9kZXRlY3QgZGVmbGF0ZS9nemlwIGRhdGEgZm9ybWF0IHZpYVxuICogd3JhcHBlciBoZWFkZXIuXG4gKlxuICogIyMjIyMgRXhhbXBsZTpcbiAqXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgcGFrbyA9IHJlcXVpcmUoJ3Bha28nKVxuICogICAsIGNodW5rMSA9IFVpbnQ4QXJyYXkoWzEsMiwzLDQsNSw2LDcsOCw5XSlcbiAqICAgLCBjaHVuazIgPSBVaW50OEFycmF5KFsxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOV0pO1xuICpcbiAqIHZhciBpbmZsYXRlID0gbmV3IHBha28uSW5mbGF0ZSh7IGxldmVsOiAzfSk7XG4gKlxuICogaW5mbGF0ZS5wdXNoKGNodW5rMSwgZmFsc2UpO1xuICogaW5mbGF0ZS5wdXNoKGNodW5rMiwgdHJ1ZSk7ICAvLyB0cnVlIC0+IGxhc3QgY2h1bmtcbiAqXG4gKiBpZiAoaW5mbGF0ZS5lcnIpIHsgdGhyb3cgbmV3IEVycm9yKGluZmxhdGUuZXJyKTsgfVxuICpcbiAqIGNvbnNvbGUubG9nKGluZmxhdGUucmVzdWx0KTtcbiAqIGBgYFxuICoqL1xudmFyIEluZmxhdGUgPSBmdW5jdGlvbihvcHRpb25zKSB7XG5cbiAgdGhpcy5vcHRpb25zID0gdXRpbHMuYXNzaWduKHtcbiAgICBjaHVua1NpemU6IDE2Mzg0LFxuICAgIHdpbmRvd0JpdHM6IDAsXG4gICAgdG86ICcnXG4gIH0sIG9wdGlvbnMgfHwge30pO1xuXG4gIHZhciBvcHQgPSB0aGlzLm9wdGlvbnM7XG5cbiAgLy8gRm9yY2Ugd2luZG93IHNpemUgZm9yIGByYXdgIGRhdGEsIGlmIG5vdCBzZXQgZGlyZWN0bHksXG4gIC8vIGJlY2F1c2Ugd2UgaGF2ZSBubyBoZWFkZXIgZm9yIGF1dG9kZXRlY3QuXG4gIGlmIChvcHQucmF3ICYmIChvcHQud2luZG93Qml0cyA+PSAwKSAmJiAob3B0LndpbmRvd0JpdHMgPCAxNikpIHtcbiAgICBvcHQud2luZG93Qml0cyA9IC1vcHQud2luZG93Qml0cztcbiAgICBpZiAob3B0LndpbmRvd0JpdHMgPT09IDApIHsgb3B0LndpbmRvd0JpdHMgPSAtMTU7IH1cbiAgfVxuXG4gIC8vIElmIGB3aW5kb3dCaXRzYCBub3QgZGVmaW5lZCAoYW5kIG1vZGUgbm90IHJhdykgLSBzZXQgYXV0b2RldGVjdCBmbGFnIGZvciBnemlwL2RlZmxhdGVcbiAgaWYgKChvcHQud2luZG93Qml0cyA+PSAwKSAmJiAob3B0LndpbmRvd0JpdHMgPCAxNikgJiZcbiAgICAgICEob3B0aW9ucyAmJiBvcHRpb25zLndpbmRvd0JpdHMpKSB7XG4gICAgb3B0LndpbmRvd0JpdHMgKz0gMzI7XG4gIH1cblxuICAvLyBHemlwIGhlYWRlciBoYXMgbm8gaW5mbyBhYm91dCB3aW5kb3dzIHNpemUsIHdlIGNhbiBkbyBhdXRvZGV0ZWN0IG9ubHlcbiAgLy8gZm9yIGRlZmxhdGUuIFNvLCBpZiB3aW5kb3cgc2l6ZSBub3Qgc2V0LCBmb3JjZSBpdCB0byBtYXggd2hlbiBnemlwIHBvc3NpYmxlXG4gIGlmICgob3B0LndpbmRvd0JpdHMgPiAxNSkgJiYgKG9wdC53aW5kb3dCaXRzIDwgNDgpKSB7XG4gICAgLy8gYml0IDMgKDE2KSAtPiBnemlwcGVkIGRhdGFcbiAgICAvLyBiaXQgNCAoMzIpIC0+IGF1dG9kZXRlY3QgZ3ppcC9kZWZsYXRlXG4gICAgaWYgKChvcHQud2luZG93Qml0cyAmIDE1KSA9PT0gMCkge1xuICAgICAgb3B0LndpbmRvd0JpdHMgfD0gMTU7XG4gICAgfVxuICB9XG5cbiAgdGhpcy5lcnIgICAgPSAwOyAgICAgIC8vIGVycm9yIGNvZGUsIGlmIGhhcHBlbnMgKDAgPSBaX09LKVxuICB0aGlzLm1zZyAgICA9ICcnOyAgICAgLy8gZXJyb3IgbWVzc2FnZVxuICB0aGlzLmVuZGVkICA9IGZhbHNlOyAgLy8gdXNlZCB0byBhdm9pZCBtdWx0aXBsZSBvbkVuZCgpIGNhbGxzXG4gIHRoaXMuY2h1bmtzID0gW107ICAgICAvLyBjaHVua3Mgb2YgY29tcHJlc3NlZCBkYXRhXG5cbiAgdGhpcy5zdHJtICAgPSBuZXcgenN0cmVhbSgpO1xuICB0aGlzLnN0cm0uYXZhaWxfb3V0ID0gMDtcblxuICB2YXIgc3RhdHVzICA9IHpsaWJfaW5mbGF0ZS5pbmZsYXRlSW5pdDIoXG4gICAgdGhpcy5zdHJtLFxuICAgIG9wdC53aW5kb3dCaXRzXG4gICk7XG5cbiAgaWYgKHN0YXR1cyAhPT0gYy5aX09LKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKG1zZ1tzdGF0dXNdKTtcbiAgfVxuXG4gIHRoaXMuaGVhZGVyID0gbmV3IGd6aGVhZGVyKCk7XG5cbiAgemxpYl9pbmZsYXRlLmluZmxhdGVHZXRIZWFkZXIodGhpcy5zdHJtLCB0aGlzLmhlYWRlcik7XG59O1xuXG4vKipcbiAqIEluZmxhdGUjcHVzaChkYXRhWywgbW9kZV0pIC0+IEJvb2xlYW5cbiAqIC0gZGF0YSAoVWludDhBcnJheXxBcnJheXxBcnJheUJ1ZmZlcnxTdHJpbmcpOiBpbnB1dCBkYXRhXG4gKiAtIG1vZGUgKE51bWJlcnxCb29sZWFuKTogMC4uNiBmb3IgY29ycmVzcG9uZGluZyBaX05PX0ZMVVNILi5aX1RSRUUgbW9kZXMuXG4gKiAgIFNlZSBjb25zdGFudHMuIFNraXBwZWQgb3IgYGZhbHNlYCBtZWFucyBaX05PX0ZMVVNILCBgdHJ1ZWAgbWVhbnNoIFpfRklOSVNILlxuICpcbiAqIFNlbmRzIGlucHV0IGRhdGEgdG8gaW5mbGF0ZSBwaXBlLCBnZW5lcmF0aW5nIFtbSW5mbGF0ZSNvbkRhdGFdXSBjYWxscyB3aXRoXG4gKiBuZXcgb3V0cHV0IGNodW5rcy4gUmV0dXJucyBgdHJ1ZWAgb24gc3VjY2Vzcy4gVGhlIGxhc3QgZGF0YSBibG9jayBtdXN0IGhhdmVcbiAqIG1vZGUgWl9GSU5JU0ggKG9yIGB0cnVlYCkuIFRoYXQgZmx1c2ggaW50ZXJuYWwgcGVuZGluZyBidWZmZXJzIGFuZCBjYWxsXG4gKiBbW0luZmxhdGUjb25FbmRdXS5cbiAqXG4gKiBPbiBmYWlsIGNhbGwgW1tJbmZsYXRlI29uRW5kXV0gd2l0aCBlcnJvciBjb2RlIGFuZCByZXR1cm4gZmFsc2UuXG4gKlxuICogV2Ugc3Ryb25nbHkgcmVjb21tZW5kIHRvIHVzZSBgVWludDhBcnJheWAgb24gaW5wdXQgZm9yIGJlc3Qgc3BlZWQgKG91dHB1dFxuICogZm9ybWF0IGlzIGRldGVjdGVkIGF1dG9tYXRpY2FsbHkpLiBBbHNvLCBkb24ndCBza2lwIGxhc3QgcGFyYW0gYW5kIGFsd2F5c1xuICogdXNlIHRoZSBzYW1lIHR5cGUgaW4geW91ciBjb2RlIChib29sZWFuIG9yIG51bWJlcikuIFRoYXQgd2lsbCBpbXByb3ZlIEpTIHNwZWVkLlxuICpcbiAqIEZvciByZWd1bGFyIGBBcnJheWAtcyBtYWtlIHN1cmUgYWxsIGVsZW1lbnRzIGFyZSBbMC4uMjU1XS5cbiAqXG4gKiAjIyMjIyBFeGFtcGxlXG4gKlxuICogYGBgamF2YXNjcmlwdFxuICogcHVzaChjaHVuaywgZmFsc2UpOyAvLyBwdXNoIG9uZSBvZiBkYXRhIGNodW5rc1xuICogLi4uXG4gKiBwdXNoKGNodW5rLCB0cnVlKTsgIC8vIHB1c2ggbGFzdCBjaHVua1xuICogYGBgXG4gKiovXG5JbmZsYXRlLnByb3RvdHlwZS5wdXNoID0gZnVuY3Rpb24oZGF0YSwgbW9kZSkge1xuICB2YXIgc3RybSA9IHRoaXMuc3RybTtcbiAgdmFyIGNodW5rU2l6ZSA9IHRoaXMub3B0aW9ucy5jaHVua1NpemU7XG4gIHZhciBzdGF0dXMsIF9tb2RlO1xuICB2YXIgbmV4dF9vdXRfdXRmOCwgdGFpbCwgdXRmOHN0cjtcblxuICBpZiAodGhpcy5lbmRlZCkgeyByZXR1cm4gZmFsc2U7IH1cbiAgX21vZGUgPSAobW9kZSA9PT0gfn5tb2RlKSA/IG1vZGUgOiAoKG1vZGUgPT09IHRydWUpID8gYy5aX0ZJTklTSCA6IGMuWl9OT19GTFVTSCk7XG5cbiAgLy8gQ29udmVydCBkYXRhIGlmIG5lZWRlZFxuICBpZiAodHlwZW9mIGRhdGEgPT09ICdzdHJpbmcnKSB7XG4gICAgLy8gT25seSBiaW5hcnkgc3RyaW5ncyBjYW4gYmUgZGVjb21wcmVzc2VkIG9uIHByYWN0aWNlXG4gICAgc3RybS5pbnB1dCA9IHN0cmluZ3MuYmluc3RyaW5nMmJ1ZihkYXRhKTtcbiAgfSBlbHNlIGlmICh0b1N0cmluZy5jYWxsKGRhdGEpID09PSAnW29iamVjdCBBcnJheUJ1ZmZlcl0nKSB7XG4gICAgc3RybS5pbnB1dCA9IG5ldyBVaW50OEFycmF5KGRhdGEpO1xuICB9IGVsc2Uge1xuICAgIHN0cm0uaW5wdXQgPSBkYXRhO1xuICB9XG5cbiAgc3RybS5uZXh0X2luID0gMDtcbiAgc3RybS5hdmFpbF9pbiA9IHN0cm0uaW5wdXQubGVuZ3RoO1xuXG4gIGRvIHtcbiAgICBpZiAoc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIHN0cm0ub3V0cHV0ID0gbmV3IHV0aWxzLkJ1ZjgoY2h1bmtTaXplKTtcbiAgICAgIHN0cm0ubmV4dF9vdXQgPSAwO1xuICAgICAgc3RybS5hdmFpbF9vdXQgPSBjaHVua1NpemU7XG4gICAgfVxuXG4gICAgc3RhdHVzID0gemxpYl9pbmZsYXRlLmluZmxhdGUoc3RybSwgYy5aX05PX0ZMVVNIKTsgICAgLyogbm8gYmFkIHJldHVybiB2YWx1ZSAqL1xuXG4gICAgaWYgKHN0YXR1cyAhPT0gYy5aX1NUUkVBTV9FTkQgJiYgc3RhdHVzICE9PSBjLlpfT0spIHtcbiAgICAgIHRoaXMub25FbmQoc3RhdHVzKTtcbiAgICAgIHRoaXMuZW5kZWQgPSB0cnVlO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChzdHJtLm5leHRfb3V0KSB7XG4gICAgICBpZiAoc3RybS5hdmFpbF9vdXQgPT09IDAgfHwgc3RhdHVzID09PSBjLlpfU1RSRUFNX0VORCB8fCAoc3RybS5hdmFpbF9pbiA9PT0gMCAmJiBfbW9kZSA9PT0gYy5aX0ZJTklTSCkpIHtcblxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLnRvID09PSAnc3RyaW5nJykge1xuXG4gICAgICAgICAgbmV4dF9vdXRfdXRmOCA9IHN0cmluZ3MudXRmOGJvcmRlcihzdHJtLm91dHB1dCwgc3RybS5uZXh0X291dCk7XG5cbiAgICAgICAgICB0YWlsID0gc3RybS5uZXh0X291dCAtIG5leHRfb3V0X3V0Zjg7XG4gICAgICAgICAgdXRmOHN0ciA9IHN0cmluZ3MuYnVmMnN0cmluZyhzdHJtLm91dHB1dCwgbmV4dF9vdXRfdXRmOCk7XG5cbiAgICAgICAgICAvLyBtb3ZlIHRhaWxcbiAgICAgICAgICBzdHJtLm5leHRfb3V0ID0gdGFpbDtcbiAgICAgICAgICBzdHJtLmF2YWlsX291dCA9IGNodW5rU2l6ZSAtIHRhaWw7XG4gICAgICAgICAgaWYgKHRhaWwpIHsgdXRpbHMuYXJyYXlTZXQoc3RybS5vdXRwdXQsIHN0cm0ub3V0cHV0LCBuZXh0X291dF91dGY4LCB0YWlsLCAwKTsgfVxuXG4gICAgICAgICAgdGhpcy5vbkRhdGEodXRmOHN0cik7XG5cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLm9uRGF0YSh1dGlscy5zaHJpbmtCdWYoc3RybS5vdXRwdXQsIHN0cm0ubmV4dF9vdXQpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSB3aGlsZSAoKHN0cm0uYXZhaWxfaW4gPiAwKSAmJiBzdGF0dXMgIT09IGMuWl9TVFJFQU1fRU5EKTtcblxuICBpZiAoc3RhdHVzID09PSBjLlpfU1RSRUFNX0VORCkge1xuICAgIF9tb2RlID0gYy5aX0ZJTklTSDtcbiAgfVxuICAvLyBGaW5hbGl6ZSBvbiB0aGUgbGFzdCBjaHVuay5cbiAgaWYgKF9tb2RlID09PSBjLlpfRklOSVNIKSB7XG4gICAgc3RhdHVzID0gemxpYl9pbmZsYXRlLmluZmxhdGVFbmQodGhpcy5zdHJtKTtcbiAgICB0aGlzLm9uRW5kKHN0YXR1cyk7XG4gICAgdGhpcy5lbmRlZCA9IHRydWU7XG4gICAgcmV0dXJuIHN0YXR1cyA9PT0gYy5aX09LO1xuICB9XG5cbiAgcmV0dXJuIHRydWU7XG59O1xuXG5cbi8qKlxuICogSW5mbGF0ZSNvbkRhdGEoY2h1bmspIC0+IFZvaWRcbiAqIC0gY2h1bmsgKFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nKTogb3VwdXQgZGF0YS4gVHlwZSBvZiBhcnJheSBkZXBlbmRzXG4gKiAgIG9uIGpzIGVuZ2luZSBzdXBwb3J0LiBXaGVuIHN0cmluZyBvdXRwdXQgcmVxdWVzdGVkLCBlYWNoIGNodW5rXG4gKiAgIHdpbGwgYmUgc3RyaW5nLlxuICpcbiAqIEJ5IGRlZmF1bHQsIHN0b3JlcyBkYXRhIGJsb2NrcyBpbiBgY2h1bmtzW11gIHByb3BlcnR5IGFuZCBnbHVlXG4gKiB0aG9zZSBpbiBgb25FbmRgLiBPdmVycmlkZSB0aGlzIGhhbmRsZXIsIGlmIHlvdSBuZWVkIGFub3RoZXIgYmVoYXZpb3VyLlxuICoqL1xuSW5mbGF0ZS5wcm90b3R5cGUub25EYXRhID0gZnVuY3Rpb24oY2h1bmspIHtcbiAgdGhpcy5jaHVua3MucHVzaChjaHVuayk7XG59O1xuXG5cbi8qKlxuICogSW5mbGF0ZSNvbkVuZChzdGF0dXMpIC0+IFZvaWRcbiAqIC0gc3RhdHVzIChOdW1iZXIpOiBpbmZsYXRlIHN0YXR1cy4gMCAoWl9PSykgb24gc3VjY2VzcyxcbiAqICAgb3RoZXIgaWYgbm90LlxuICpcbiAqIENhbGxlZCBvbmNlIGFmdGVyIHlvdSB0ZWxsIGluZmxhdGUgdGhhdCBpbnB1dCBzdHJlYW0gY29tcGxldGVcbiAqIG9yIGVycm9yIGhhcHBlbm5lZC4gQnkgZGVmYXVsdCAtIGpvaW4gY29sbGVjdGVkIGNodW5rcyxcbiAqIGZyZWUgbWVtb3J5IGFuZCBmaWxsIGByZXN1bHRzYCAvIGBlcnJgIHByb3BlcnRpZXMuXG4gKiovXG5JbmZsYXRlLnByb3RvdHlwZS5vbkVuZCA9IGZ1bmN0aW9uKHN0YXR1cykge1xuICAvLyBPbiBzdWNjZXNzIC0gam9pblxuICBpZiAoc3RhdHVzID09PSBjLlpfT0spIHtcbiAgICBpZiAodGhpcy5vcHRpb25zLnRvID09PSAnc3RyaW5nJykge1xuICAgICAgLy8gR2x1ZSAmIGNvbnZlcnQgaGVyZSwgdW50aWwgd2UgdGVhY2ggcGFrbyB0byBzZW5kXG4gICAgICAvLyB1dGY4IGFsbGlnbmVkIHN0cmluZ3MgdG8gb25EYXRhXG4gICAgICB0aGlzLnJlc3VsdCA9IHRoaXMuY2h1bmtzLmpvaW4oJycpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnJlc3VsdCA9IHV0aWxzLmZsYXR0ZW5DaHVua3ModGhpcy5jaHVua3MpO1xuICAgIH1cbiAgfVxuICB0aGlzLmNodW5rcyA9IFtdO1xuICB0aGlzLmVyciA9IHN0YXR1cztcbiAgdGhpcy5tc2cgPSB0aGlzLnN0cm0ubXNnO1xufTtcblxuXG4vKipcbiAqIGluZmxhdGUoZGF0YVssIG9wdGlvbnNdKSAtPiBVaW50OEFycmF5fEFycmF5fFN0cmluZ1xuICogLSBkYXRhIChVaW50OEFycmF5fEFycmF5fFN0cmluZyk6IGlucHV0IGRhdGEgdG8gZGVjb21wcmVzcy5cbiAqIC0gb3B0aW9ucyAoT2JqZWN0KTogemxpYiBpbmZsYXRlIG9wdGlvbnMuXG4gKlxuICogRGVjb21wcmVzcyBgZGF0YWAgd2l0aCBpbmZsYXRlL3VuZ3ppcCBhbmQgYG9wdGlvbnNgLiBBdXRvZGV0ZWN0XG4gKiBmb3JtYXQgdmlhIHdyYXBwZXIgaGVhZGVyIGJ5IGRlZmF1bHQuIFRoYXQncyB3aHkgd2UgZG9uJ3QgcHJvdmlkZVxuICogc2VwYXJhdGUgYHVuZ3ppcGAgbWV0aG9kLlxuICpcbiAqIFN1cHBvcnRlZCBvcHRpb25zIGFyZTpcbiAqXG4gKiAtIHdpbmRvd0JpdHNcbiAqXG4gKiBbaHR0cDovL3psaWIubmV0L21hbnVhbC5odG1sI0FkdmFuY2VkXShodHRwOi8vemxpYi5uZXQvbWFudWFsLmh0bWwjQWR2YW5jZWQpXG4gKiBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cbiAqXG4gKiBTdWdhciAob3B0aW9ucyk6XG4gKlxuICogLSBgcmF3YCAoQm9vbGVhbikgLSBzYXkgdGhhdCB3ZSB3b3JrIHdpdGggcmF3IHN0cmVhbSwgaWYgeW91IGRvbid0IHdpc2ggdG8gc3BlY2lmeVxuICogICBuZWdhdGl2ZSB3aW5kb3dCaXRzIGltcGxpY2l0bHkuXG4gKiAtIGB0b2AgKFN0cmluZykgLSBpZiBlcXVhbCB0byAnc3RyaW5nJywgdGhlbiByZXN1bHQgd2lsbCBiZSBjb252ZXJ0ZWRcbiAqICAgZnJvbSB1dGY4IHRvIHV0ZjE2IChqYXZhc2NyaXB0KSBzdHJpbmcuIFdoZW4gc3RyaW5nIG91dHB1dCByZXF1ZXN0ZWQsXG4gKiAgIGNodW5rIGxlbmd0aCBjYW4gZGlmZmVyIGZyb20gYGNodW5rU2l6ZWAsIGRlcGVuZGluZyBvbiBjb250ZW50LlxuICpcbiAqXG4gKiAjIyMjIyBFeGFtcGxlOlxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHZhciBwYWtvID0gcmVxdWlyZSgncGFrbycpXG4gKiAgICwgaW5wdXQgPSBwYWtvLmRlZmxhdGUoWzEsMiwzLDQsNSw2LDcsOCw5XSlcbiAqICAgLCBvdXRwdXQ7XG4gKlxuICogdHJ5IHtcbiAqICAgb3V0cHV0ID0gcGFrby5pbmZsYXRlKGlucHV0KTtcbiAqIH0gY2F0Y2ggKGVycilcbiAqICAgY29uc29sZS5sb2coZXJyKTtcbiAqIH1cbiAqIGBgYFxuICoqL1xuZnVuY3Rpb24gaW5mbGF0ZShpbnB1dCwgb3B0aW9ucykge1xuICB2YXIgaW5mbGF0b3IgPSBuZXcgSW5mbGF0ZShvcHRpb25zKTtcblxuICBpbmZsYXRvci5wdXNoKGlucHV0LCB0cnVlKTtcblxuICAvLyBUaGF0IHdpbGwgbmV2ZXIgaGFwcGVucywgaWYgeW91IGRvbid0IGNoZWF0IHdpdGggb3B0aW9ucyA6KVxuICBpZiAoaW5mbGF0b3IuZXJyKSB7IHRocm93IGluZmxhdG9yLm1zZzsgfVxuXG4gIHJldHVybiBpbmZsYXRvci5yZXN1bHQ7XG59XG5cblxuLyoqXG4gKiBpbmZsYXRlUmF3KGRhdGFbLCBvcHRpb25zXSkgLT4gVWludDhBcnJheXxBcnJheXxTdHJpbmdcbiAqIC0gZGF0YSAoVWludDhBcnJheXxBcnJheXxTdHJpbmcpOiBpbnB1dCBkYXRhIHRvIGRlY29tcHJlc3MuXG4gKiAtIG9wdGlvbnMgKE9iamVjdCk6IHpsaWIgaW5mbGF0ZSBvcHRpb25zLlxuICpcbiAqIFRoZSBzYW1lIGFzIFtbaW5mbGF0ZV1dLCBidXQgY3JlYXRlcyByYXcgZGF0YSwgd2l0aG91dCB3cmFwcGVyXG4gKiAoaGVhZGVyIGFuZCBhZGxlcjMyIGNyYykuXG4gKiovXG5mdW5jdGlvbiBpbmZsYXRlUmF3KGlucHV0LCBvcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICBvcHRpb25zLnJhdyA9IHRydWU7XG4gIHJldHVybiBpbmZsYXRlKGlucHV0LCBvcHRpb25zKTtcbn1cblxuXG4vKipcbiAqIHVuZ3ppcChkYXRhWywgb3B0aW9uc10pIC0+IFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nXG4gKiAtIGRhdGEgKFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nKTogaW5wdXQgZGF0YSB0byBkZWNvbXByZXNzLlxuICogLSBvcHRpb25zIChPYmplY3QpOiB6bGliIGluZmxhdGUgb3B0aW9ucy5cbiAqXG4gKiBKdXN0IHNob3J0Y3V0IHRvIFtbaW5mbGF0ZV1dLCBiZWNhdXNlIGl0IGF1dG9kZXRlY3RzIGZvcm1hdFxuICogYnkgaGVhZGVyLmNvbnRlbnQuIERvbmUgZm9yIGNvbnZlbmllbmNlLlxuICoqL1xuXG5cbmV4cG9ydHMuSW5mbGF0ZSA9IEluZmxhdGU7XG5leHBvcnRzLmluZmxhdGUgPSBpbmZsYXRlO1xuZXhwb3J0cy5pbmZsYXRlUmF3ID0gaW5mbGF0ZVJhdztcbmV4cG9ydHMudW5nemlwICA9IGluZmxhdGU7XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIFRZUEVEX09LID0gICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpICYmXG4gICAgICAgICAgICAgICAgKHR5cGVvZiBVaW50MTZBcnJheSAhPT0gJ3VuZGVmaW5lZCcpICYmXG4gICAgICAgICAgICAgICAgKHR5cGVvZiBJbnQzMkFycmF5ICE9PSAndW5kZWZpbmVkJyk7XG5cblxuZXhwb3J0cy5hc3NpZ24gPSBmdW5jdGlvbiAob2JqIC8qZnJvbTEsIGZyb20yLCBmcm9tMywgLi4uKi8pIHtcbiAgdmFyIHNvdXJjZXMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICB3aGlsZSAoc291cmNlcy5sZW5ndGgpIHtcbiAgICB2YXIgc291cmNlID0gc291cmNlcy5zaGlmdCgpO1xuICAgIGlmICghc291cmNlKSB7IGNvbnRpbnVlOyB9XG5cbiAgICBpZiAodHlwZW9mKHNvdXJjZSkgIT09ICdvYmplY3QnKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKHNvdXJjZSArICdtdXN0IGJlIG5vbi1vYmplY3QnKTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBwIGluIHNvdXJjZSkge1xuICAgICAgaWYgKHNvdXJjZS5oYXNPd25Qcm9wZXJ0eShwKSkge1xuICAgICAgICBvYmpbcF0gPSBzb3VyY2VbcF07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG9iajtcbn07XG5cblxuLy8gcmVkdWNlIGJ1ZmZlciBzaXplLCBhdm9pZGluZyBtZW0gY29weVxuZXhwb3J0cy5zaHJpbmtCdWYgPSBmdW5jdGlvbiAoYnVmLCBzaXplKSB7XG4gIGlmIChidWYubGVuZ3RoID09PSBzaXplKSB7IHJldHVybiBidWY7IH1cbiAgaWYgKGJ1Zi5zdWJhcnJheSkgeyByZXR1cm4gYnVmLnN1YmFycmF5KDAsIHNpemUpOyB9XG4gIGJ1Zi5sZW5ndGggPSBzaXplO1xuICByZXR1cm4gYnVmO1xufTtcblxuXG52YXIgZm5UeXBlZCA9IHtcbiAgYXJyYXlTZXQ6IGZ1bmN0aW9uIChkZXN0LCBzcmMsIHNyY19vZmZzLCBsZW4sIGRlc3Rfb2Zmcykge1xuICAgIGlmIChzcmMuc3ViYXJyYXkgJiYgZGVzdC5zdWJhcnJheSkge1xuICAgICAgZGVzdC5zZXQoc3JjLnN1YmFycmF5KHNyY19vZmZzLCBzcmNfb2ZmcytsZW4pLCBkZXN0X29mZnMpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBGYWxsYmFjayB0byBvcmRpbmFyeSBhcnJheVxuICAgIGZvcih2YXIgaT0wOyBpPGxlbjsgaSsrKSB7XG4gICAgICBkZXN0W2Rlc3Rfb2ZmcyArIGldID0gc3JjW3NyY19vZmZzICsgaV07XG4gICAgfVxuICB9LFxuICAvLyBKb2luIGFycmF5IG9mIGNodW5rcyB0byBzaW5nbGUgYXJyYXkuXG4gIGZsYXR0ZW5DaHVua3M6IGZ1bmN0aW9uKGNodW5rcykge1xuICAgIHZhciBpLCBsLCBsZW4sIHBvcywgY2h1bmssIHJlc3VsdDtcblxuICAgIC8vIGNhbGN1bGF0ZSBkYXRhIGxlbmd0aFxuICAgIGxlbiA9IDA7XG4gICAgZm9yIChpPTAsIGw9Y2h1bmtzLmxlbmd0aDsgaTxsOyBpKyspIHtcbiAgICAgIGxlbiArPSBjaHVua3NbaV0ubGVuZ3RoO1xuICAgIH1cblxuICAgIC8vIGpvaW4gY2h1bmtzXG4gICAgcmVzdWx0ID0gbmV3IFVpbnQ4QXJyYXkobGVuKTtcbiAgICBwb3MgPSAwO1xuICAgIGZvciAoaT0wLCBsPWNodW5rcy5sZW5ndGg7IGk8bDsgaSsrKSB7XG4gICAgICBjaHVuayA9IGNodW5rc1tpXTtcbiAgICAgIHJlc3VsdC5zZXQoY2h1bmssIHBvcyk7XG4gICAgICBwb3MgKz0gY2h1bmsubGVuZ3RoO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn07XG5cbnZhciBmblVudHlwZWQgPSB7XG4gIGFycmF5U2V0OiBmdW5jdGlvbiAoZGVzdCwgc3JjLCBzcmNfb2ZmcywgbGVuLCBkZXN0X29mZnMpIHtcbiAgICBmb3IodmFyIGk9MDsgaTxsZW47IGkrKykge1xuICAgICAgZGVzdFtkZXN0X29mZnMgKyBpXSA9IHNyY1tzcmNfb2ZmcyArIGldO1xuICAgIH1cbiAgfSxcbiAgLy8gSm9pbiBhcnJheSBvZiBjaHVua3MgdG8gc2luZ2xlIGFycmF5LlxuICBmbGF0dGVuQ2h1bmtzOiBmdW5jdGlvbihjaHVua3MpIHtcbiAgICByZXR1cm4gW10uY29uY2F0LmFwcGx5KFtdLCBjaHVua3MpO1xuICB9XG59O1xuXG5cbi8vIEVuYWJsZS9EaXNhYmxlIHR5cGVkIGFycmF5cyB1c2UsIGZvciB0ZXN0aW5nXG4vL1xuZXhwb3J0cy5zZXRUeXBlZCA9IGZ1bmN0aW9uIChvbikge1xuICBpZiAob24pIHtcbiAgICBleHBvcnRzLkJ1ZjggID0gVWludDhBcnJheTtcbiAgICBleHBvcnRzLkJ1ZjE2ID0gVWludDE2QXJyYXk7XG4gICAgZXhwb3J0cy5CdWYzMiA9IEludDMyQXJyYXk7XG4gICAgZXhwb3J0cy5hc3NpZ24oZXhwb3J0cywgZm5UeXBlZCk7XG4gIH0gZWxzZSB7XG4gICAgZXhwb3J0cy5CdWY4ICA9IEFycmF5O1xuICAgIGV4cG9ydHMuQnVmMTYgPSBBcnJheTtcbiAgICBleHBvcnRzLkJ1ZjMyID0gQXJyYXk7XG4gICAgZXhwb3J0cy5hc3NpZ24oZXhwb3J0cywgZm5VbnR5cGVkKTtcbiAgfVxufTtcblxuZXhwb3J0cy5zZXRUeXBlZChUWVBFRF9PSyk7IiwiLy8gU3RyaW5nIGVuY29kZS9kZWNvZGUgaGVscGVyc1xuJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4vY29tbW9uJyk7XG5cblxuLy8gUXVpY2sgY2hlY2sgaWYgd2UgY2FuIHVzZSBmYXN0IGFycmF5IHRvIGJpbiBzdHJpbmcgY29udmVyc2lvblxuLy9cbi8vIC0gYXBwbHkoQXJyYXkpIGNhbiBmYWlsIG9uIEFuZHJvaWQgMi4yXG4vLyAtIGFwcGx5KFVpbnQ4QXJyYXkpIGNhbiBmYWlsIG9uIGlPUyA1LjEgU2FmYXJ5XG4vL1xudmFyIFNUUl9BUFBMWV9PSyA9IHRydWU7XG52YXIgU1RSX0FQUExZX1VJQV9PSyA9IHRydWU7XG5cbnRyeSB7IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCwgWzBdKTsgfSBjYXRjaChfXykgeyBTVFJfQVBQTFlfT0sgPSBmYWxzZTsgfVxudHJ5IHsgU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLCBuZXcgVWludDhBcnJheSgxKSk7IH0gY2F0Y2goX18pIHsgU1RSX0FQUExZX1VJQV9PSyA9IGZhbHNlOyB9XG5cblxuLy8gVGFibGUgd2l0aCB1dGY4IGxlbmd0aHMgKGNhbGN1bGF0ZWQgYnkgZmlyc3QgYnl0ZSBvZiBzZXF1ZW5jZSlcbi8vIE5vdGUsIHRoYXQgNSAmIDYtYnl0ZSB2YWx1ZXMgYW5kIHNvbWUgNC1ieXRlIHZhbHVlcyBjYW4gbm90IGJlIHJlcHJlc2VudGVkIGluIEpTLFxuLy8gYmVjYXVzZSBtYXggcG9zc2libGUgY29kZXBvaW50IGlzIDB4MTBmZmZmXG52YXIgX3V0ZjhsZW4gPSBuZXcgdXRpbHMuQnVmOCgyNTYpO1xuZm9yICh2YXIgaT0wOyBpPDI1NjsgaSsrKSB7XG4gIF91dGY4bGVuW2ldID0gKGkgPj0gMjUyID8gNiA6IGkgPj0gMjQ4ID8gNSA6IGkgPj0gMjQwID8gNCA6IGkgPj0gMjI0ID8gMyA6IGkgPj0gMTkyID8gMiA6IDEpO1xufVxuX3V0ZjhsZW5bMjU0XT1fdXRmOGxlblsyNTRdPTE7IC8vIEludmFsaWQgc2VxdWVuY2Ugc3RhcnRcblxuXG4vLyBjb252ZXJ0IHN0cmluZyB0byBhcnJheSAodHlwZWQsIHdoZW4gcG9zc2libGUpXG5leHBvcnRzLnN0cmluZzJidWYgPSBmdW5jdGlvbiAoc3RyKSB7XG4gIHZhciBidWYsIGMsIGMyLCBtX3BvcywgaSwgc3RyX2xlbiA9IHN0ci5sZW5ndGgsIGJ1Zl9sZW4gPSAwO1xuXG4gIC8vIGNvdW50IGJpbmFyeSBzaXplXG4gIGZvciAobV9wb3MgPSAwOyBtX3BvcyA8IHN0cl9sZW47IG1fcG9zKyspIHtcbiAgICBjID0gc3RyLmNoYXJDb2RlQXQobV9wb3MpO1xuICAgIGlmICgoYyAmIDB4ZmMwMCkgPT09IDB4ZDgwMCAmJiAobV9wb3MrMSA8IHN0cl9sZW4pKSB7XG4gICAgICBjMiA9IHN0ci5jaGFyQ29kZUF0KG1fcG9zKzEpO1xuICAgICAgaWYgKChjMiAmIDB4ZmMwMCkgPT09IDB4ZGMwMCkge1xuICAgICAgICBjID0gMHgxMDAwMCArICgoYyAtIDB4ZDgwMCkgPDwgMTApICsgKGMyIC0gMHhkYzAwKTtcbiAgICAgICAgbV9wb3MrKztcbiAgICAgIH1cbiAgICB9XG4gICAgYnVmX2xlbiArPSBjIDwgMHg4MCA/IDEgOiBjIDwgMHg4MDAgPyAyIDogYyA8IDB4MTAwMDAgPyAzIDogNDtcbiAgfVxuXG4gIC8vIGFsbG9jYXRlIGJ1ZmZlclxuICBidWYgPSBuZXcgdXRpbHMuQnVmOChidWZfbGVuKTtcblxuICAvLyBjb252ZXJ0XG4gIGZvciAoaT0wLCBtX3BvcyA9IDA7IGkgPCBidWZfbGVuOyBtX3BvcysrKSB7XG4gICAgYyA9IHN0ci5jaGFyQ29kZUF0KG1fcG9zKTtcbiAgICBpZiAoKGMgJiAweGZjMDApID09PSAweGQ4MDAgJiYgKG1fcG9zKzEgPCBzdHJfbGVuKSkge1xuICAgICAgYzIgPSBzdHIuY2hhckNvZGVBdChtX3BvcysxKTtcbiAgICAgIGlmICgoYzIgJiAweGZjMDApID09PSAweGRjMDApIHtcbiAgICAgICAgYyA9IDB4MTAwMDAgKyAoKGMgLSAweGQ4MDApIDw8IDEwKSArIChjMiAtIDB4ZGMwMCk7XG4gICAgICAgIG1fcG9zKys7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChjIDwgMHg4MCkge1xuICAgICAgLyogb25lIGJ5dGUgKi9cbiAgICAgIGJ1ZltpKytdID0gYztcbiAgICB9IGVsc2UgaWYgKGMgPCAweDgwMCkge1xuICAgICAgLyogdHdvIGJ5dGVzICovXG4gICAgICBidWZbaSsrXSA9IDB4QzAgfCAoYyA+Pj4gNik7XG4gICAgICBidWZbaSsrXSA9IDB4ODAgfCAoYyAmIDB4M2YpO1xuICAgIH0gZWxzZSBpZiAoYyA8IDB4MTAwMDApIHtcbiAgICAgIC8qIHRocmVlIGJ5dGVzICovXG4gICAgICBidWZbaSsrXSA9IDB4RTAgfCAoYyA+Pj4gMTIpO1xuICAgICAgYnVmW2krK10gPSAweDgwIHwgKGMgPj4+IDYgJiAweDNmKTtcbiAgICAgIGJ1ZltpKytdID0gMHg4MCB8IChjICYgMHgzZik7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8qIGZvdXIgYnl0ZXMgKi9cbiAgICAgIGJ1ZltpKytdID0gMHhmMCB8IChjID4+PiAxOCk7XG4gICAgICBidWZbaSsrXSA9IDB4ODAgfCAoYyA+Pj4gMTIgJiAweDNmKTtcbiAgICAgIGJ1ZltpKytdID0gMHg4MCB8IChjID4+PiA2ICYgMHgzZik7XG4gICAgICBidWZbaSsrXSA9IDB4ODAgfCAoYyAmIDB4M2YpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBidWY7XG59O1xuXG4vLyBIZWxwZXIgKHVzZWQgaW4gMiBwbGFjZXMpXG5mdW5jdGlvbiBidWYyYmluc3RyaW5nKGJ1ZiwgbGVuKSB7XG4gIC8vIHVzZSBmYWxsYmFjayBmb3IgYmlnIGFycmF5cyB0byBhdm9pZCBzdGFjayBvdmVyZmxvd1xuICBpZiAobGVuIDwgNjU1MzcpIHtcbiAgICBpZiAoKGJ1Zi5zdWJhcnJheSAmJiBTVFJfQVBQTFlfVUlBX09LKSB8fCAoIWJ1Zi5zdWJhcnJheSAmJiBTVFJfQVBQTFlfT0spKSB7XG4gICAgICByZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLCB1dGlscy5zaHJpbmtCdWYoYnVmLCBsZW4pKTtcbiAgICB9XG4gIH1cblxuICB2YXIgcmVzdWx0ID0gJyc7XG4gIGZvcih2YXIgaT0wOyBpIDwgbGVuOyBpKyspIHtcbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0pO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cblxuLy8gQ29udmVydCBieXRlIGFycmF5IHRvIGJpbmFyeSBzdHJpbmdcbmV4cG9ydHMuYnVmMmJpbnN0cmluZyA9IGZ1bmN0aW9uKGJ1Zikge1xuICByZXR1cm4gYnVmMmJpbnN0cmluZyhidWYsIGJ1Zi5sZW5ndGgpO1xufTtcblxuXG4vLyBDb252ZXJ0IGJpbmFyeSBzdHJpbmcgKHR5cGVkLCB3aGVuIHBvc3NpYmxlKVxuZXhwb3J0cy5iaW5zdHJpbmcyYnVmID0gZnVuY3Rpb24oc3RyKSB7XG4gIHZhciBidWYgPSBuZXcgdXRpbHMuQnVmOChzdHIubGVuZ3RoKTtcbiAgZm9yKHZhciBpPTAsIGxlbj1idWYubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICBidWZbaV0gPSBzdHIuY2hhckNvZGVBdChpKTtcbiAgfVxuICByZXR1cm4gYnVmO1xufTtcblxuXG4vLyBjb252ZXJ0IGFycmF5IHRvIHN0cmluZ1xuZXhwb3J0cy5idWYyc3RyaW5nID0gZnVuY3Rpb24gKGJ1ZiwgbWF4KSB7XG4gIHZhciBpLCBvdXQsIGMsIGNfbGVuO1xuICB2YXIgbGVuID0gbWF4IHx8IGJ1Zi5sZW5ndGg7XG5cbiAgLy8gUmVzZXJ2ZSBtYXggcG9zc2libGUgbGVuZ3RoICgyIHdvcmRzIHBlciBjaGFyKVxuICAvLyBOQjogYnkgdW5rbm93biByZWFzb25zLCBBcnJheSBpcyBzaWduaWZpY2FudGx5IGZhc3RlciBmb3JcbiAgLy8gICAgIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkgdGhhbiBVaW50MTZBcnJheS5cbiAgdmFyIHV0ZjE2YnVmID0gbmV3IEFycmF5KGxlbioyKTtcblxuICBmb3IgKG91dD0wLCBpPTA7IGk8bGVuOykge1xuICAgIGMgPSBidWZbaSsrXTtcbiAgICAvLyBxdWljayBwcm9jZXNzIGFzY2lpXG4gICAgaWYgKGMgPCAweDgwKSB7IHV0ZjE2YnVmW291dCsrXSA9IGM7IGNvbnRpbnVlOyB9XG5cbiAgICBjX2xlbiA9IF91dGY4bGVuW2NdO1xuICAgIC8vIHNraXAgNSAmIDYgYnl0ZSBjb2Rlc1xuICAgIGlmIChjX2xlbiA+IDQpIHsgdXRmMTZidWZbb3V0KytdID0gMHhmZmZkOyBpICs9IGNfbGVuLTE7IGNvbnRpbnVlOyB9XG5cbiAgICAvLyBhcHBseSBtYXNrIG9uIGZpcnN0IGJ5dGVcbiAgICBjICY9IGNfbGVuID09PSAyID8gMHgxZiA6IGNfbGVuID09PSAzID8gMHgwZiA6IDB4MDc7XG4gICAgLy8gam9pbiB0aGUgcmVzdFxuICAgIHdoaWxlIChjX2xlbiA+IDEgJiYgaSA8IGxlbikge1xuICAgICAgYyA9IChjIDw8IDYpIHwgKGJ1ZltpKytdICYgMHgzZik7XG4gICAgICBjX2xlbi0tO1xuICAgIH1cblxuICAgIC8vIHRlcm1pbmF0ZWQgYnkgZW5kIG9mIHN0cmluZz9cbiAgICBpZiAoY19sZW4gPiAxKSB7IHV0ZjE2YnVmW291dCsrXSA9IDB4ZmZmZDsgY29udGludWU7IH1cblxuICAgIGlmIChjIDwgMHgxMDAwMCkge1xuICAgICAgdXRmMTZidWZbb3V0KytdID0gYztcbiAgICB9IGVsc2Uge1xuICAgICAgYyAtPSAweDEwMDAwO1xuICAgICAgdXRmMTZidWZbb3V0KytdID0gMHhkODAwIHwgKChjID4+IDEwKSAmIDB4M2ZmKTtcbiAgICAgIHV0ZjE2YnVmW291dCsrXSA9IDB4ZGMwMCB8IChjICYgMHgzZmYpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBidWYyYmluc3RyaW5nKHV0ZjE2YnVmLCBvdXQpO1xufTtcblxuXG4vLyBDYWxjdWxhdGUgbWF4IHBvc3NpYmxlIHBvc2l0aW9uIGluIHV0ZjggYnVmZmVyLFxuLy8gdGhhdCB3aWxsIG5vdCBicmVhayBzZXF1ZW5jZS4gSWYgdGhhdCdzIG5vdCBwb3NzaWJsZVxuLy8gLSAodmVyeSBzbWFsbCBsaW1pdHMpIHJldHVybiBtYXggc2l6ZSBhcyBpcy5cbi8vXG4vLyBidWZbXSAtIHV0ZjggYnl0ZXMgYXJyYXlcbi8vIG1heCAgIC0gbGVuZ3RoIGxpbWl0IChtYW5kYXRvcnkpO1xuZXhwb3J0cy51dGY4Ym9yZGVyID0gZnVuY3Rpb24oYnVmLCBtYXgpIHtcbiAgdmFyIHBvcztcblxuICBtYXggPSBtYXggfHwgYnVmLmxlbmd0aDtcbiAgaWYgKG1heCA+IGJ1Zi5sZW5ndGgpIHsgbWF4ID0gYnVmLmxlbmd0aDsgfVxuXG4gIC8vIGdvIGJhY2sgZnJvbSBsYXN0IHBvc2l0aW9uLCB1bnRpbCBzdGFydCBvZiBzZXF1ZW5jZSBmb3VuZFxuICBwb3MgPSBtYXgtMTtcbiAgd2hpbGUgKHBvcyA+PSAwICYmIChidWZbcG9zXSAmIDB4QzApID09PSAweDgwKSB7IHBvcy0tOyB9XG5cbiAgLy8gRnVja3VwIC0gdmVyeSBzbWFsbCBhbmQgYnJva2VuIHNlcXVlbmNlLFxuICAvLyByZXR1cm4gbWF4LCBiZWNhdXNlIHdlIHNob3VsZCByZXR1cm4gc29tZXRoaW5nIGFueXdheS5cbiAgaWYgKHBvcyA8IDApIHsgcmV0dXJuIG1heDsgfVxuXG4gIC8vIElmIHdlIGNhbWUgdG8gc3RhcnQgb2YgYnVmZmVyIC0gdGhhdCBtZWFucyB2dWZmZXIgaXMgdG9vIHNtYWxsLFxuICAvLyByZXR1cm4gbWF4IHRvby5cbiAgaWYgKHBvcyA9PT0gMCkgeyByZXR1cm4gbWF4OyB9XG5cbiAgcmV0dXJuIChwb3MgKyBfdXRmOGxlbltidWZbcG9zXV0gPiBtYXgpID8gcG9zIDogbWF4O1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gTm90ZTogYWRsZXIzMiB0YWtlcyAxMiUgZm9yIGxldmVsIDAgYW5kIDIlIGZvciBsZXZlbCA2LlxuLy8gSXQgZG9lc24ndCB3b3J0aCB0byBtYWtlIGFkZGl0aW9uYWwgb3B0aW1pemF0aW9uYSBhcyBpbiBvcmlnaW5hbC5cbi8vIFNtYWxsIHNpemUgaXMgcHJlZmVyYWJsZS5cblxuZnVuY3Rpb24gYWRsZXIzMihhZGxlciwgYnVmLCBsZW4sIHBvcykge1xuICB2YXIgczEgPSAoYWRsZXIgJiAweGZmZmYpIHwwXG4gICAgLCBzMiA9ICgoYWRsZXIgPj4+IDE2KSAmIDB4ZmZmZikgfDBcbiAgICAsIG4gPSAwO1xuXG4gIHdoaWxlIChsZW4gIT09IDApIHtcbiAgICAvLyBTZXQgbGltaXQgfiB0d2ljZSBsZXNzIHRoYW4gNTU1MiwgdG8ga2VlcFxuICAgIC8vIHMyIGluIDMxLWJpdHMsIGJlY2F1c2Ugd2UgZm9yY2Ugc2lnbmVkIGludHMuXG4gICAgLy8gaW4gb3RoZXIgY2FzZSAlPSB3aWxsIGZhaWwuXG4gICAgbiA9IGxlbiA+IDIwMDAgPyAyMDAwIDogbGVuO1xuICAgIGxlbiAtPSBuO1xuXG4gICAgZG8ge1xuICAgICAgczEgPSAoczEgKyBidWZbcG9zKytdKSB8MDtcbiAgICAgIHMyID0gKHMyICsgczEpIHwwO1xuICAgIH0gd2hpbGUgKC0tbik7XG5cbiAgICBzMSAlPSA2NTUyMTtcbiAgICBzMiAlPSA2NTUyMTtcbiAgfVxuXG4gIHJldHVybiAoczEgfCAoczIgPDwgMTYpKSB8MDtcbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IGFkbGVyMzI7IiwibW9kdWxlLmV4cG9ydHMgPSB7XG5cbiAgLyogQWxsb3dlZCBmbHVzaCB2YWx1ZXM7IHNlZSBkZWZsYXRlKCkgYW5kIGluZmxhdGUoKSBiZWxvdyBmb3IgZGV0YWlscyAqL1xuICBaX05PX0ZMVVNIOiAgICAgICAgIDAsXG4gIFpfUEFSVElBTF9GTFVTSDogICAgMSxcbiAgWl9TWU5DX0ZMVVNIOiAgICAgICAyLFxuICBaX0ZVTExfRkxVU0g6ICAgICAgIDMsXG4gIFpfRklOSVNIOiAgICAgICAgICAgNCxcbiAgWl9CTE9DSzogICAgICAgICAgICA1LFxuICBaX1RSRUVTOiAgICAgICAgICAgIDYsXG5cbiAgLyogUmV0dXJuIGNvZGVzIGZvciB0aGUgY29tcHJlc3Npb24vZGVjb21wcmVzc2lvbiBmdW5jdGlvbnMuIE5lZ2F0aXZlIHZhbHVlc1xuICAqIGFyZSBlcnJvcnMsIHBvc2l0aXZlIHZhbHVlcyBhcmUgdXNlZCBmb3Igc3BlY2lhbCBidXQgbm9ybWFsIGV2ZW50cy5cbiAgKi9cbiAgWl9PSzogICAgICAgICAgICAgICAwLFxuICBaX1NUUkVBTV9FTkQ6ICAgICAgIDEsXG4gIFpfTkVFRF9ESUNUOiAgICAgICAgMixcbiAgWl9FUlJOTzogICAgICAgICAgIC0xLFxuICBaX1NUUkVBTV9FUlJPUjogICAgLTIsXG4gIFpfREFUQV9FUlJPUjogICAgICAtMyxcbiAgLy9aX01FTV9FUlJPUjogICAgIC00LFxuICBaX0JVRl9FUlJPUjogICAgICAgLTUsXG4gIC8vWl9WRVJTSU9OX0VSUk9SOiAtNixcblxuICAvKiBjb21wcmVzc2lvbiBsZXZlbHMgKi9cbiAgWl9OT19DT01QUkVTU0lPTjogICAgICAgICAwLFxuICBaX0JFU1RfU1BFRUQ6ICAgICAgICAgICAgIDEsXG4gIFpfQkVTVF9DT01QUkVTU0lPTjogICAgICAgOSxcbiAgWl9ERUZBVUxUX0NPTVBSRVNTSU9OOiAgIC0xLFxuXG5cbiAgWl9GSUxURVJFRDogICAgICAgICAgICAgICAxLFxuICBaX0hVRkZNQU5fT05MWTogICAgICAgICAgIDIsXG4gIFpfUkxFOiAgICAgICAgICAgICAgICAgICAgMyxcbiAgWl9GSVhFRDogICAgICAgICAgICAgICAgICA0LFxuICBaX0RFRkFVTFRfU1RSQVRFR1k6ICAgICAgIDAsXG5cbiAgLyogUG9zc2libGUgdmFsdWVzIG9mIHRoZSBkYXRhX3R5cGUgZmllbGQgKHRob3VnaCBzZWUgaW5mbGF0ZSgpKSAqL1xuICBaX0JJTkFSWTogICAgICAgICAgICAgICAgIDAsXG4gIFpfVEVYVDogICAgICAgICAgICAgICAgICAgMSxcbiAgLy9aX0FTQ0lJOiAgICAgICAgICAgICAgICAxLCAvLyA9IFpfVEVYVCAoZGVwcmVjYXRlZClcbiAgWl9VTktOT1dOOiAgICAgICAgICAgICAgICAyLFxuXG4gIC8qIFRoZSBkZWZsYXRlIGNvbXByZXNzaW9uIG1ldGhvZCAqL1xuICBaX0RFRkxBVEVEOiAgICAgICAgICAgICAgIDhcbiAgLy9aX05VTEw6ICAgICAgICAgICAgICAgICBudWxsIC8vIFVzZSAtMSBvciBudWxsIGlubGluZSwgZGVwZW5kaW5nIG9uIHZhciB0eXBlXG59OyIsIid1c2Ugc3RyaWN0JztcblxuLy8gTm90ZTogd2UgY2FuJ3QgZ2V0IHNpZ25pZmljYW50IHNwZWVkIGJvb3N0IGhlcmUuXG4vLyBTbyB3cml0ZSBjb2RlIHRvIG1pbmltaXplIHNpemUgLSBubyBwcmVnZW5lcmF0ZWQgdGFibGVzXG4vLyBhbmQgYXJyYXkgdG9vbHMgZGVwZW5kZW5jaWVzLlxuXG5cbi8vIFVzZSBvcmRpbmFyeSBhcnJheSwgc2luY2UgdW50eXBlZCBtYWtlcyBubyBib29zdCBoZXJlXG5mdW5jdGlvbiBtYWtlVGFibGUoKSB7XG4gIHZhciBjLCB0YWJsZSA9IFtdO1xuXG4gIGZvcih2YXIgbiA9MDsgbiA8IDI1NjsgbisrKXtcbiAgICBjID0gbjtcbiAgICBmb3IodmFyIGsgPTA7IGsgPCA4OyBrKyspe1xuICAgICAgYyA9ICgoYyYxKSA/ICgweEVEQjg4MzIwIF4gKGMgPj4+IDEpKSA6IChjID4+PiAxKSk7XG4gICAgfVxuICAgIHRhYmxlW25dID0gYztcbiAgfVxuXG4gIHJldHVybiB0YWJsZTtcbn1cblxuLy8gQ3JlYXRlIHRhYmxlIG9uIGxvYWQuIEp1c3QgMjU1IHNpZ25lZCBsb25ncy4gTm90IGEgcHJvYmxlbS5cbnZhciBjcmNUYWJsZSA9IG1ha2VUYWJsZSgpO1xuXG5cbmZ1bmN0aW9uIGNyYzMyKGNyYywgYnVmLCBsZW4sIHBvcykge1xuICB2YXIgdCA9IGNyY1RhYmxlXG4gICAgLCBlbmQgPSBwb3MgKyBsZW47XG5cbiAgY3JjID0gY3JjIF4gKC0xKTtcblxuICBmb3IgKHZhciBpID0gcG9zOyBpIDwgZW5kOyBpKysgKSB7XG4gICAgY3JjID0gKGNyYyA+Pj4gOCkgXiB0WyhjcmMgXiBidWZbaV0pICYgMHhGRl07XG4gIH1cblxuICByZXR1cm4gKGNyYyBeICgtMSkpOyAvLyA+Pj4gMDtcbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IGNyYzMyOyIsIid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWxzICAgPSByZXF1aXJlKCcuLi91dGlscy9jb21tb24nKTtcbnZhciB0cmVlcyAgID0gcmVxdWlyZSgnLi90cmVlcycpO1xudmFyIGFkbGVyMzIgPSByZXF1aXJlKCcuL2FkbGVyMzInKTtcbnZhciBjcmMzMiAgID0gcmVxdWlyZSgnLi9jcmMzMicpO1xudmFyIG1zZyAgID0gcmVxdWlyZSgnLi9tZXNzYWdlcycpO1xuXG4vKiBQdWJsaWMgY29uc3RhbnRzID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0qL1xuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cblxuXG4vKiBBbGxvd2VkIGZsdXNoIHZhbHVlczsgc2VlIGRlZmxhdGUoKSBhbmQgaW5mbGF0ZSgpIGJlbG93IGZvciBkZXRhaWxzICovXG52YXIgWl9OT19GTFVTSCAgICAgID0gMDtcbnZhciBaX1BBUlRJQUxfRkxVU0ggPSAxO1xuLy92YXIgWl9TWU5DX0ZMVVNIICAgID0gMjtcbnZhciBaX0ZVTExfRkxVU0ggICAgPSAzO1xudmFyIFpfRklOSVNIICAgICAgICA9IDQ7XG52YXIgWl9CTE9DSyAgICAgICAgID0gNTtcbi8vdmFyIFpfVFJFRVMgICAgICAgICA9IDY7XG5cblxuLyogUmV0dXJuIGNvZGVzIGZvciB0aGUgY29tcHJlc3Npb24vZGVjb21wcmVzc2lvbiBmdW5jdGlvbnMuIE5lZ2F0aXZlIHZhbHVlc1xuICogYXJlIGVycm9ycywgcG9zaXRpdmUgdmFsdWVzIGFyZSB1c2VkIGZvciBzcGVjaWFsIGJ1dCBub3JtYWwgZXZlbnRzLlxuICovXG52YXIgWl9PSyAgICAgICAgICAgID0gMDtcbnZhciBaX1NUUkVBTV9FTkQgICAgPSAxO1xuLy92YXIgWl9ORUVEX0RJQ1QgICAgID0gMjtcbi8vdmFyIFpfRVJSTk8gICAgICAgICA9IC0xO1xudmFyIFpfU1RSRUFNX0VSUk9SICA9IC0yO1xudmFyIFpfREFUQV9FUlJPUiAgICA9IC0zO1xuLy92YXIgWl9NRU1fRVJST1IgICAgID0gLTQ7XG52YXIgWl9CVUZfRVJST1IgICAgID0gLTU7XG4vL3ZhciBaX1ZFUlNJT05fRVJST1IgPSAtNjtcblxuXG4vKiBjb21wcmVzc2lvbiBsZXZlbHMgKi9cbi8vdmFyIFpfTk9fQ09NUFJFU1NJT04gICAgICA9IDA7XG4vL3ZhciBaX0JFU1RfU1BFRUQgICAgICAgICAgPSAxO1xuLy92YXIgWl9CRVNUX0NPTVBSRVNTSU9OICAgID0gOTtcbnZhciBaX0RFRkFVTFRfQ09NUFJFU1NJT04gPSAtMTtcblxuXG52YXIgWl9GSUxURVJFRCAgICAgICAgICAgID0gMTtcbnZhciBaX0hVRkZNQU5fT05MWSAgICAgICAgPSAyO1xudmFyIFpfUkxFICAgICAgICAgICAgICAgICA9IDM7XG52YXIgWl9GSVhFRCAgICAgICAgICAgICAgID0gNDtcbnZhciBaX0RFRkFVTFRfU1RSQVRFR1kgICAgPSAwO1xuXG4vKiBQb3NzaWJsZSB2YWx1ZXMgb2YgdGhlIGRhdGFfdHlwZSBmaWVsZCAodGhvdWdoIHNlZSBpbmZsYXRlKCkpICovXG4vL3ZhciBaX0JJTkFSWSAgICAgICAgICAgICAgPSAwO1xuLy92YXIgWl9URVhUICAgICAgICAgICAgICAgID0gMTtcbi8vdmFyIFpfQVNDSUkgICAgICAgICAgICAgICA9IDE7IC8vID0gWl9URVhUXG52YXIgWl9VTktOT1dOICAgICAgICAgICAgID0gMjtcblxuXG4vKiBUaGUgZGVmbGF0ZSBjb21wcmVzc2lvbiBtZXRob2QgKi9cbnZhciBaX0RFRkxBVEVEICA9IDg7XG5cbi8qPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cblxudmFyIE1BWF9NRU1fTEVWRUwgPSA5O1xuLyogTWF4aW11bSB2YWx1ZSBmb3IgbWVtTGV2ZWwgaW4gZGVmbGF0ZUluaXQyICovXG52YXIgTUFYX1dCSVRTID0gMTU7XG4vKiAzMksgTFo3NyB3aW5kb3cgKi9cbnZhciBERUZfTUVNX0xFVkVMID0gODtcblxuXG52YXIgTEVOR1RIX0NPREVTICA9IDI5O1xuLyogbnVtYmVyIG9mIGxlbmd0aCBjb2Rlcywgbm90IGNvdW50aW5nIHRoZSBzcGVjaWFsIEVORF9CTE9DSyBjb2RlICovXG52YXIgTElURVJBTFMgICAgICA9IDI1Njtcbi8qIG51bWJlciBvZiBsaXRlcmFsIGJ5dGVzIDAuLjI1NSAqL1xudmFyIExfQ09ERVMgICAgICAgPSBMSVRFUkFMUyArIDEgKyBMRU5HVEhfQ09ERVM7XG4vKiBudW1iZXIgb2YgTGl0ZXJhbCBvciBMZW5ndGggY29kZXMsIGluY2x1ZGluZyB0aGUgRU5EX0JMT0NLIGNvZGUgKi9cbnZhciBEX0NPREVTICAgICAgID0gMzA7XG4vKiBudW1iZXIgb2YgZGlzdGFuY2UgY29kZXMgKi9cbnZhciBCTF9DT0RFUyAgICAgID0gMTk7XG4vKiBudW1iZXIgb2YgY29kZXMgdXNlZCB0byB0cmFuc2ZlciB0aGUgYml0IGxlbmd0aHMgKi9cbnZhciBIRUFQX1NJWkUgICAgID0gMipMX0NPREVTICsgMTtcbi8qIG1heGltdW0gaGVhcCBzaXplICovXG52YXIgTUFYX0JJVFMgID0gMTU7XG4vKiBBbGwgY29kZXMgbXVzdCBub3QgZXhjZWVkIE1BWF9CSVRTIGJpdHMgKi9cblxudmFyIE1JTl9NQVRDSCA9IDM7XG52YXIgTUFYX01BVENIID0gMjU4O1xudmFyIE1JTl9MT09LQUhFQUQgPSAoTUFYX01BVENIICsgTUlOX01BVENIICsgMSk7XG5cbnZhciBQUkVTRVRfRElDVCA9IDB4MjA7XG5cbnZhciBJTklUX1NUQVRFID0gNDI7XG52YXIgRVhUUkFfU1RBVEUgPSA2OTtcbnZhciBOQU1FX1NUQVRFID0gNzM7XG52YXIgQ09NTUVOVF9TVEFURSA9IDkxO1xudmFyIEhDUkNfU1RBVEUgPSAxMDM7XG52YXIgQlVTWV9TVEFURSA9IDExMztcbnZhciBGSU5JU0hfU1RBVEUgPSA2NjY7XG5cbnZhciBCU19ORUVEX01PUkUgICAgICA9IDE7IC8qIGJsb2NrIG5vdCBjb21wbGV0ZWQsIG5lZWQgbW9yZSBpbnB1dCBvciBtb3JlIG91dHB1dCAqL1xudmFyIEJTX0JMT0NLX0RPTkUgICAgID0gMjsgLyogYmxvY2sgZmx1c2ggcGVyZm9ybWVkICovXG52YXIgQlNfRklOSVNIX1NUQVJURUQgPSAzOyAvKiBmaW5pc2ggc3RhcnRlZCwgbmVlZCBvbmx5IG1vcmUgb3V0cHV0IGF0IG5leHQgZGVmbGF0ZSAqL1xudmFyIEJTX0ZJTklTSF9ET05FICAgID0gNDsgLyogZmluaXNoIGRvbmUsIGFjY2VwdCBubyBtb3JlIGlucHV0IG9yIG91dHB1dCAqL1xuXG52YXIgT1NfQ09ERSA9IDB4MDM7IC8vIFVuaXggOikgLiBEb24ndCBkZXRlY3QsIHVzZSB0aGlzIGRlZmF1bHQuXG5cbmZ1bmN0aW9uIGVycihzdHJtLCBlcnJvckNvZGUpIHtcbiAgc3RybS5tc2cgPSBtc2dbZXJyb3JDb2RlXTtcbiAgcmV0dXJuIGVycm9yQ29kZTtcbn1cblxuZnVuY3Rpb24gcmFuayhmKSB7XG4gIHJldHVybiAoKGYpIDw8IDEpIC0gKChmKSA+IDQgPyA5IDogMCk7XG59XG5cbmZ1bmN0aW9uIHplcm8oYnVmKSB7IHZhciBsZW4gPSBidWYubGVuZ3RoOyB3aGlsZSAoLS1sZW4gPj0gMCkgeyBidWZbbGVuXSA9IDA7IH0gfVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEZsdXNoIGFzIG11Y2ggcGVuZGluZyBvdXRwdXQgYXMgcG9zc2libGUuIEFsbCBkZWZsYXRlKCkgb3V0cHV0IGdvZXNcbiAqIHRocm91Z2ggdGhpcyBmdW5jdGlvbiBzbyBzb21lIGFwcGxpY2F0aW9ucyBtYXkgd2lzaCB0byBtb2RpZnkgaXRcbiAqIHRvIGF2b2lkIGFsbG9jYXRpbmcgYSBsYXJnZSBzdHJtLT5vdXRwdXQgYnVmZmVyIGFuZCBjb3B5aW5nIGludG8gaXQuXG4gKiAoU2VlIGFsc28gcmVhZF9idWYoKSkuXG4gKi9cbmZ1bmN0aW9uIGZsdXNoX3BlbmRpbmcoc3RybSkge1xuICB2YXIgcyA9IHN0cm0uc3RhdGU7XG5cbiAgLy9fdHJfZmx1c2hfYml0cyhzKTtcbiAgdmFyIGxlbiA9IHMucGVuZGluZztcbiAgaWYgKGxlbiA+IHN0cm0uYXZhaWxfb3V0KSB7XG4gICAgbGVuID0gc3RybS5hdmFpbF9vdXQ7XG4gIH1cbiAgaWYgKGxlbiA9PT0gMCkgeyByZXR1cm47IH1cblxuICB1dGlscy5hcnJheVNldChzdHJtLm91dHB1dCwgcy5wZW5kaW5nX2J1Ziwgcy5wZW5kaW5nX291dCwgbGVuLCBzdHJtLm5leHRfb3V0KTtcbiAgc3RybS5uZXh0X291dCArPSBsZW47XG4gIHMucGVuZGluZ19vdXQgKz0gbGVuO1xuICBzdHJtLnRvdGFsX291dCArPSBsZW47XG4gIHN0cm0uYXZhaWxfb3V0IC09IGxlbjtcbiAgcy5wZW5kaW5nIC09IGxlbjtcbiAgaWYgKHMucGVuZGluZyA9PT0gMCkge1xuICAgIHMucGVuZGluZ19vdXQgPSAwO1xuICB9XG59XG5cblxuZnVuY3Rpb24gZmx1c2hfYmxvY2tfb25seSAocywgbGFzdCkge1xuICB0cmVlcy5fdHJfZmx1c2hfYmxvY2socywgKHMuYmxvY2tfc3RhcnQgPj0gMCA/IHMuYmxvY2tfc3RhcnQgOiAtMSksIHMuc3Ryc3RhcnQgLSBzLmJsb2NrX3N0YXJ0LCBsYXN0KTtcbiAgcy5ibG9ja19zdGFydCA9IHMuc3Ryc3RhcnQ7XG4gIGZsdXNoX3BlbmRpbmcocy5zdHJtKTtcbn1cblxuXG5mdW5jdGlvbiBwdXRfYnl0ZShzLCBiKSB7XG4gIHMucGVuZGluZ19idWZbcy5wZW5kaW5nKytdID0gYjtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBQdXQgYSBzaG9ydCBpbiB0aGUgcGVuZGluZyBidWZmZXIuIFRoZSAxNi1iaXQgdmFsdWUgaXMgcHV0IGluIE1TQiBvcmRlci5cbiAqIElOIGFzc2VydGlvbjogdGhlIHN0cmVhbSBzdGF0ZSBpcyBjb3JyZWN0IGFuZCB0aGVyZSBpcyBlbm91Z2ggcm9vbSBpblxuICogcGVuZGluZ19idWYuXG4gKi9cbmZ1bmN0aW9uIHB1dFNob3J0TVNCKHMsIGIpIHtcbi8vICBwdXRfYnl0ZShzLCAoQnl0ZSkoYiA+PiA4KSk7XG4vLyAgcHV0X2J5dGUocywgKEJ5dGUpKGIgJiAweGZmKSk7XG4gIHMucGVuZGluZ19idWZbcy5wZW5kaW5nKytdID0gKGIgPj4+IDgpICYgMHhmZjtcbiAgcy5wZW5kaW5nX2J1ZltzLnBlbmRpbmcrK10gPSBiICYgMHhmZjtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFJlYWQgYSBuZXcgYnVmZmVyIGZyb20gdGhlIGN1cnJlbnQgaW5wdXQgc3RyZWFtLCB1cGRhdGUgdGhlIGFkbGVyMzJcbiAqIGFuZCB0b3RhbCBudW1iZXIgb2YgYnl0ZXMgcmVhZC4gIEFsbCBkZWZsYXRlKCkgaW5wdXQgZ29lcyB0aHJvdWdoXG4gKiB0aGlzIGZ1bmN0aW9uIHNvIHNvbWUgYXBwbGljYXRpb25zIG1heSB3aXNoIHRvIG1vZGlmeSBpdCB0byBhdm9pZFxuICogYWxsb2NhdGluZyBhIGxhcmdlIHN0cm0tPmlucHV0IGJ1ZmZlciBhbmQgY29weWluZyBmcm9tIGl0LlxuICogKFNlZSBhbHNvIGZsdXNoX3BlbmRpbmcoKSkuXG4gKi9cbmZ1bmN0aW9uIHJlYWRfYnVmKHN0cm0sIGJ1Ziwgc3RhcnQsIHNpemUpIHtcbiAgdmFyIGxlbiA9IHN0cm0uYXZhaWxfaW47XG5cbiAgaWYgKGxlbiA+IHNpemUpIHsgbGVuID0gc2l6ZTsgfVxuICBpZiAobGVuID09PSAwKSB7IHJldHVybiAwOyB9XG5cbiAgc3RybS5hdmFpbF9pbiAtPSBsZW47XG5cbiAgdXRpbHMuYXJyYXlTZXQoYnVmLCBzdHJtLmlucHV0LCBzdHJtLm5leHRfaW4sIGxlbiwgc3RhcnQpO1xuICBpZiAoc3RybS5zdGF0ZS53cmFwID09PSAxKSB7XG4gICAgc3RybS5hZGxlciA9IGFkbGVyMzIoc3RybS5hZGxlciwgYnVmLCBsZW4sIHN0YXJ0KTtcbiAgfVxuXG4gIGVsc2UgaWYgKHN0cm0uc3RhdGUud3JhcCA9PT0gMikge1xuICAgIHN0cm0uYWRsZXIgPSBjcmMzMihzdHJtLmFkbGVyLCBidWYsIGxlbiwgc3RhcnQpO1xuICB9XG5cbiAgc3RybS5uZXh0X2luICs9IGxlbjtcbiAgc3RybS50b3RhbF9pbiArPSBsZW47XG5cbiAgcmV0dXJuIGxlbjtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFNldCBtYXRjaF9zdGFydCB0byB0aGUgbG9uZ2VzdCBtYXRjaCBzdGFydGluZyBhdCB0aGUgZ2l2ZW4gc3RyaW5nIGFuZFxuICogcmV0dXJuIGl0cyBsZW5ndGguIE1hdGNoZXMgc2hvcnRlciBvciBlcXVhbCB0byBwcmV2X2xlbmd0aCBhcmUgZGlzY2FyZGVkLFxuICogaW4gd2hpY2ggY2FzZSB0aGUgcmVzdWx0IGlzIGVxdWFsIHRvIHByZXZfbGVuZ3RoIGFuZCBtYXRjaF9zdGFydCBpc1xuICogZ2FyYmFnZS5cbiAqIElOIGFzc2VydGlvbnM6IGN1cl9tYXRjaCBpcyB0aGUgaGVhZCBvZiB0aGUgaGFzaCBjaGFpbiBmb3IgdGhlIGN1cnJlbnRcbiAqICAgc3RyaW5nIChzdHJzdGFydCkgYW5kIGl0cyBkaXN0YW5jZSBpcyA8PSBNQVhfRElTVCwgYW5kIHByZXZfbGVuZ3RoID49IDFcbiAqIE9VVCBhc3NlcnRpb246IHRoZSBtYXRjaCBsZW5ndGggaXMgbm90IGdyZWF0ZXIgdGhhbiBzLT5sb29rYWhlYWQuXG4gKi9cbmZ1bmN0aW9uIGxvbmdlc3RfbWF0Y2gocywgY3VyX21hdGNoKSB7XG4gIHZhciBjaGFpbl9sZW5ndGggPSBzLm1heF9jaGFpbl9sZW5ndGg7ICAgICAgLyogbWF4IGhhc2ggY2hhaW4gbGVuZ3RoICovXG4gIHZhciBzY2FuID0gcy5zdHJzdGFydDsgLyogY3VycmVudCBzdHJpbmcgKi9cbiAgdmFyIG1hdGNoOyAgICAgICAgICAgICAgICAgICAgICAgLyogbWF0Y2hlZCBzdHJpbmcgKi9cbiAgdmFyIGxlbjsgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBsZW5ndGggb2YgY3VycmVudCBtYXRjaCAqL1xuICB2YXIgYmVzdF9sZW4gPSBzLnByZXZfbGVuZ3RoOyAgICAgICAgICAgICAgLyogYmVzdCBtYXRjaCBsZW5ndGggc28gZmFyICovXG4gIHZhciBuaWNlX21hdGNoID0gcy5uaWNlX21hdGNoOyAgICAgICAgICAgICAvKiBzdG9wIGlmIG1hdGNoIGxvbmcgZW5vdWdoICovXG4gIHZhciBsaW1pdCA9IChzLnN0cnN0YXJ0ID4gKHMud19zaXplIC0gTUlOX0xPT0tBSEVBRCkpID9cbiAgICAgIHMuc3Ryc3RhcnQgLSAocy53X3NpemUgLSBNSU5fTE9PS0FIRUFEKSA6IDAvKk5JTCovO1xuXG4gIHZhciBfd2luID0gcy53aW5kb3c7IC8vIHNob3J0Y3V0XG5cbiAgdmFyIHdtYXNrID0gcy53X21hc2s7XG4gIHZhciBwcmV2ICA9IHMucHJldjtcblxuICAvKiBTdG9wIHdoZW4gY3VyX21hdGNoIGJlY29tZXMgPD0gbGltaXQuIFRvIHNpbXBsaWZ5IHRoZSBjb2RlLFxuICAgKiB3ZSBwcmV2ZW50IG1hdGNoZXMgd2l0aCB0aGUgc3RyaW5nIG9mIHdpbmRvdyBpbmRleCAwLlxuICAgKi9cblxuICB2YXIgc3RyZW5kID0gcy5zdHJzdGFydCArIE1BWF9NQVRDSDtcbiAgdmFyIHNjYW5fZW5kMSAgPSBfd2luW3NjYW4gKyBiZXN0X2xlbiAtIDFdO1xuICB2YXIgc2Nhbl9lbmQgICA9IF93aW5bc2NhbiArIGJlc3RfbGVuXTtcblxuICAvKiBUaGUgY29kZSBpcyBvcHRpbWl6ZWQgZm9yIEhBU0hfQklUUyA+PSA4IGFuZCBNQVhfTUFUQ0gtMiBtdWx0aXBsZSBvZiAxNi5cbiAgICogSXQgaXMgZWFzeSB0byBnZXQgcmlkIG9mIHRoaXMgb3B0aW1pemF0aW9uIGlmIG5lY2Vzc2FyeS5cbiAgICovXG4gIC8vIEFzc2VydChzLT5oYXNoX2JpdHMgPj0gOCAmJiBNQVhfTUFUQ0ggPT0gMjU4LCBcIkNvZGUgdG9vIGNsZXZlclwiKTtcblxuICAvKiBEbyBub3Qgd2FzdGUgdG9vIG11Y2ggdGltZSBpZiB3ZSBhbHJlYWR5IGhhdmUgYSBnb29kIG1hdGNoOiAqL1xuICBpZiAocy5wcmV2X2xlbmd0aCA+PSBzLmdvb2RfbWF0Y2gpIHtcbiAgICBjaGFpbl9sZW5ndGggPj49IDI7XG4gIH1cbiAgLyogRG8gbm90IGxvb2sgZm9yIG1hdGNoZXMgYmV5b25kIHRoZSBlbmQgb2YgdGhlIGlucHV0LiBUaGlzIGlzIG5lY2Vzc2FyeVxuICAgKiB0byBtYWtlIGRlZmxhdGUgZGV0ZXJtaW5pc3RpYy5cbiAgICovXG4gIGlmIChuaWNlX21hdGNoID4gcy5sb29rYWhlYWQpIHsgbmljZV9tYXRjaCA9IHMubG9va2FoZWFkOyB9XG5cbiAgLy8gQXNzZXJ0KCh1bGcpcy0+c3Ryc3RhcnQgPD0gcy0+d2luZG93X3NpemUtTUlOX0xPT0tBSEVBRCwgXCJuZWVkIGxvb2thaGVhZFwiKTtcblxuICBkbyB7XG4gICAgLy8gQXNzZXJ0KGN1cl9tYXRjaCA8IHMtPnN0cnN0YXJ0LCBcIm5vIGZ1dHVyZVwiKTtcbiAgICBtYXRjaCA9IGN1cl9tYXRjaDtcblxuICAgIC8qIFNraXAgdG8gbmV4dCBtYXRjaCBpZiB0aGUgbWF0Y2ggbGVuZ3RoIGNhbm5vdCBpbmNyZWFzZVxuICAgICAqIG9yIGlmIHRoZSBtYXRjaCBsZW5ndGggaXMgbGVzcyB0aGFuIDIuICBOb3RlIHRoYXQgdGhlIGNoZWNrcyBiZWxvd1xuICAgICAqIGZvciBpbnN1ZmZpY2llbnQgbG9va2FoZWFkIG9ubHkgb2NjdXIgb2NjYXNpb25hbGx5IGZvciBwZXJmb3JtYW5jZVxuICAgICAqIHJlYXNvbnMuICBUaGVyZWZvcmUgdW5pbml0aWFsaXplZCBtZW1vcnkgd2lsbCBiZSBhY2Nlc3NlZCwgYW5kXG4gICAgICogY29uZGl0aW9uYWwganVtcHMgd2lsbCBiZSBtYWRlIHRoYXQgZGVwZW5kIG9uIHRob3NlIHZhbHVlcy5cbiAgICAgKiBIb3dldmVyIHRoZSBsZW5ndGggb2YgdGhlIG1hdGNoIGlzIGxpbWl0ZWQgdG8gdGhlIGxvb2thaGVhZCwgc29cbiAgICAgKiB0aGUgb3V0cHV0IG9mIGRlZmxhdGUgaXMgbm90IGFmZmVjdGVkIGJ5IHRoZSB1bmluaXRpYWxpemVkIHZhbHVlcy5cbiAgICAgKi9cblxuICAgIGlmIChfd2luW21hdGNoICsgYmVzdF9sZW5dICAgICAhPT0gc2Nhbl9lbmQgIHx8XG4gICAgICAgIF93aW5bbWF0Y2ggKyBiZXN0X2xlbiAtIDFdICE9PSBzY2FuX2VuZDEgfHxcbiAgICAgICAgX3dpblttYXRjaF0gICAgICAgICAgICAgICAgIT09IF93aW5bc2Nhbl0gfHxcbiAgICAgICAgX3dpblsrK21hdGNoXSAgICAgICAgICAgICAgIT09IF93aW5bc2NhbiArIDFdKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICAvKiBUaGUgY2hlY2sgYXQgYmVzdF9sZW4tMSBjYW4gYmUgcmVtb3ZlZCBiZWNhdXNlIGl0IHdpbGwgYmUgbWFkZVxuICAgICAqIGFnYWluIGxhdGVyLiAoVGhpcyBoZXVyaXN0aWMgaXMgbm90IGFsd2F5cyBhIHdpbi4pXG4gICAgICogSXQgaXMgbm90IG5lY2Vzc2FyeSB0byBjb21wYXJlIHNjYW5bMl0gYW5kIG1hdGNoWzJdIHNpbmNlIHRoZXlcbiAgICAgKiBhcmUgYWx3YXlzIGVxdWFsIHdoZW4gdGhlIG90aGVyIGJ5dGVzIG1hdGNoLCBnaXZlbiB0aGF0XG4gICAgICogdGhlIGhhc2gga2V5cyBhcmUgZXF1YWwgYW5kIHRoYXQgSEFTSF9CSVRTID49IDguXG4gICAgICovXG4gICAgc2NhbiArPSAyO1xuICAgIG1hdGNoKys7XG4gICAgLy8gQXNzZXJ0KCpzY2FuID09ICptYXRjaCwgXCJtYXRjaFsyXT9cIik7XG5cbiAgICAvKiBXZSBjaGVjayBmb3IgaW5zdWZmaWNpZW50IGxvb2thaGVhZCBvbmx5IGV2ZXJ5IDh0aCBjb21wYXJpc29uO1xuICAgICAqIHRoZSAyNTZ0aCBjaGVjayB3aWxsIGJlIG1hZGUgYXQgc3Ryc3RhcnQrMjU4LlxuICAgICAqL1xuICAgIGRvIHtcbiAgICAgIC8qanNoaW50IG5vZW1wdHk6ZmFsc2UqL1xuICAgIH0gd2hpbGUgKF93aW5bKytzY2FuXSA9PT0gX3dpblsrK21hdGNoXSAmJiBfd2luWysrc2Nhbl0gPT09IF93aW5bKyttYXRjaF0gJiZcbiAgICAgICAgICAgICBfd2luWysrc2Nhbl0gPT09IF93aW5bKyttYXRjaF0gJiYgX3dpblsrK3NjYW5dID09PSBfd2luWysrbWF0Y2hdICYmXG4gICAgICAgICAgICAgX3dpblsrK3NjYW5dID09PSBfd2luWysrbWF0Y2hdICYmIF93aW5bKytzY2FuXSA9PT0gX3dpblsrK21hdGNoXSAmJlxuICAgICAgICAgICAgIF93aW5bKytzY2FuXSA9PT0gX3dpblsrK21hdGNoXSAmJiBfd2luWysrc2Nhbl0gPT09IF93aW5bKyttYXRjaF0gJiZcbiAgICAgICAgICAgICBzY2FuIDwgc3RyZW5kKTtcblxuICAgIC8vIEFzc2VydChzY2FuIDw9IHMtPndpbmRvdysodW5zaWduZWQpKHMtPndpbmRvd19zaXplLTEpLCBcIndpbGQgc2NhblwiKTtcblxuICAgIGxlbiA9IE1BWF9NQVRDSCAtIChzdHJlbmQgLSBzY2FuKTtcbiAgICBzY2FuID0gc3RyZW5kIC0gTUFYX01BVENIO1xuXG4gICAgaWYgKGxlbiA+IGJlc3RfbGVuKSB7XG4gICAgICBzLm1hdGNoX3N0YXJ0ID0gY3VyX21hdGNoO1xuICAgICAgYmVzdF9sZW4gPSBsZW47XG4gICAgICBpZiAobGVuID49IG5pY2VfbWF0Y2gpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBzY2FuX2VuZDEgID0gX3dpbltzY2FuICsgYmVzdF9sZW4gLSAxXTtcbiAgICAgIHNjYW5fZW5kICAgPSBfd2luW3NjYW4gKyBiZXN0X2xlbl07XG4gICAgfVxuICB9IHdoaWxlICgoY3VyX21hdGNoID0gcHJldltjdXJfbWF0Y2ggJiB3bWFza10pID4gbGltaXQgJiYgLS1jaGFpbl9sZW5ndGggIT09IDApO1xuXG4gIGlmIChiZXN0X2xlbiA8PSBzLmxvb2thaGVhZCkge1xuICAgIHJldHVybiBiZXN0X2xlbjtcbiAgfVxuICByZXR1cm4gcy5sb29rYWhlYWQ7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBGaWxsIHRoZSB3aW5kb3cgd2hlbiB0aGUgbG9va2FoZWFkIGJlY29tZXMgaW5zdWZmaWNpZW50LlxuICogVXBkYXRlcyBzdHJzdGFydCBhbmQgbG9va2FoZWFkLlxuICpcbiAqIElOIGFzc2VydGlvbjogbG9va2FoZWFkIDwgTUlOX0xPT0tBSEVBRFxuICogT1VUIGFzc2VydGlvbnM6IHN0cnN0YXJ0IDw9IHdpbmRvd19zaXplLU1JTl9MT09LQUhFQURcbiAqICAgIEF0IGxlYXN0IG9uZSBieXRlIGhhcyBiZWVuIHJlYWQsIG9yIGF2YWlsX2luID09IDA7IHJlYWRzIGFyZVxuICogICAgcGVyZm9ybWVkIGZvciBhdCBsZWFzdCB0d28gYnl0ZXMgKHJlcXVpcmVkIGZvciB0aGUgemlwIHRyYW5zbGF0ZV9lb2xcbiAqICAgIG9wdGlvbiAtLSBub3Qgc3VwcG9ydGVkIGhlcmUpLlxuICovXG5mdW5jdGlvbiBmaWxsX3dpbmRvdyhzKSB7XG4gIHZhciBfd19zaXplID0gcy53X3NpemU7XG4gIHZhciBwLCBuLCBtLCBtb3JlLCBzdHI7XG5cbiAgLy9Bc3NlcnQocy0+bG9va2FoZWFkIDwgTUlOX0xPT0tBSEVBRCwgXCJhbHJlYWR5IGVub3VnaCBsb29rYWhlYWRcIik7XG5cbiAgZG8ge1xuICAgIG1vcmUgPSBzLndpbmRvd19zaXplIC0gcy5sb29rYWhlYWQgLSBzLnN0cnN0YXJ0O1xuXG4gICAgLy8gSlMgaW50cyBoYXZlIDMyIGJpdCwgYmxvY2sgYmVsb3cgbm90IG5lZWRlZFxuICAgIC8qIERlYWwgd2l0aCAhQCMkJSA2NEsgbGltaXQ6ICovXG4gICAgLy9pZiAoc2l6ZW9mKGludCkgPD0gMikge1xuICAgIC8vICAgIGlmIChtb3JlID09IDAgJiYgcy0+c3Ryc3RhcnQgPT0gMCAmJiBzLT5sb29rYWhlYWQgPT0gMCkge1xuICAgIC8vICAgICAgICBtb3JlID0gd3NpemU7XG4gICAgLy9cbiAgICAvLyAgfSBlbHNlIGlmIChtb3JlID09ICh1bnNpZ25lZCkoLTEpKSB7XG4gICAgLy8gICAgICAgIC8qIFZlcnkgdW5saWtlbHksIGJ1dCBwb3NzaWJsZSBvbiAxNiBiaXQgbWFjaGluZSBpZlxuICAgIC8vICAgICAgICAgKiBzdHJzdGFydCA9PSAwICYmIGxvb2thaGVhZCA9PSAxIChpbnB1dCBkb25lIGEgYnl0ZSBhdCB0aW1lKVxuICAgIC8vICAgICAgICAgKi9cbiAgICAvLyAgICAgICAgbW9yZS0tO1xuICAgIC8vICAgIH1cbiAgICAvL31cblxuXG4gICAgLyogSWYgdGhlIHdpbmRvdyBpcyBhbG1vc3QgZnVsbCBhbmQgdGhlcmUgaXMgaW5zdWZmaWNpZW50IGxvb2thaGVhZCxcbiAgICAgKiBtb3ZlIHRoZSB1cHBlciBoYWxmIHRvIHRoZSBsb3dlciBvbmUgdG8gbWFrZSByb29tIGluIHRoZSB1cHBlciBoYWxmLlxuICAgICAqL1xuICAgIGlmIChzLnN0cnN0YXJ0ID49IF93X3NpemUgKyAoX3dfc2l6ZSAtIE1JTl9MT09LQUhFQUQpKSB7XG5cbiAgICAgIHV0aWxzLmFycmF5U2V0KHMud2luZG93LCBzLndpbmRvdywgX3dfc2l6ZSwgX3dfc2l6ZSwgMCk7XG4gICAgICBzLm1hdGNoX3N0YXJ0IC09IF93X3NpemU7XG4gICAgICBzLnN0cnN0YXJ0IC09IF93X3NpemU7XG4gICAgICAvKiB3ZSBub3cgaGF2ZSBzdHJzdGFydCA+PSBNQVhfRElTVCAqL1xuICAgICAgcy5ibG9ja19zdGFydCAtPSBfd19zaXplO1xuXG4gICAgICAvKiBTbGlkZSB0aGUgaGFzaCB0YWJsZSAoY291bGQgYmUgYXZvaWRlZCB3aXRoIDMyIGJpdCB2YWx1ZXNcbiAgICAgICBhdCB0aGUgZXhwZW5zZSBvZiBtZW1vcnkgdXNhZ2UpLiBXZSBzbGlkZSBldmVuIHdoZW4gbGV2ZWwgPT0gMFxuICAgICAgIHRvIGtlZXAgdGhlIGhhc2ggdGFibGUgY29uc2lzdGVudCBpZiB3ZSBzd2l0Y2ggYmFjayB0byBsZXZlbCA+IDBcbiAgICAgICBsYXRlci4gKFVzaW5nIGxldmVsIDAgcGVybWFuZW50bHkgaXMgbm90IGFuIG9wdGltYWwgdXNhZ2Ugb2ZcbiAgICAgICB6bGliLCBzbyB3ZSBkb24ndCBjYXJlIGFib3V0IHRoaXMgcGF0aG9sb2dpY2FsIGNhc2UuKVxuICAgICAgICovXG5cbiAgICAgIG4gPSBzLmhhc2hfc2l6ZTtcbiAgICAgIHAgPSBuO1xuICAgICAgZG8ge1xuICAgICAgICBtID0gcy5oZWFkWy0tcF07XG4gICAgICAgIHMuaGVhZFtwXSA9IChtID49IF93X3NpemUgPyBtIC0gX3dfc2l6ZSA6IDApO1xuICAgICAgfSB3aGlsZSAoLS1uKTtcblxuICAgICAgbiA9IF93X3NpemU7XG4gICAgICBwID0gbjtcbiAgICAgIGRvIHtcbiAgICAgICAgbSA9IHMucHJldlstLXBdO1xuICAgICAgICBzLnByZXZbcF0gPSAobSA+PSBfd19zaXplID8gbSAtIF93X3NpemUgOiAwKTtcbiAgICAgICAgLyogSWYgbiBpcyBub3Qgb24gYW55IGhhc2ggY2hhaW4sIHByZXZbbl0gaXMgZ2FyYmFnZSBidXRcbiAgICAgICAgICogaXRzIHZhbHVlIHdpbGwgbmV2ZXIgYmUgdXNlZC5cbiAgICAgICAgICovXG4gICAgICB9IHdoaWxlICgtLW4pO1xuXG4gICAgICBtb3JlICs9IF93X3NpemU7XG4gICAgfVxuICAgIGlmIChzLnN0cm0uYXZhaWxfaW4gPT09IDApIHtcbiAgICAgIGJyZWFrO1xuICAgIH1cblxuICAgIC8qIElmIHRoZXJlIHdhcyBubyBzbGlkaW5nOlxuICAgICAqICAgIHN0cnN0YXJ0IDw9IFdTSVpFK01BWF9ESVNULTEgJiYgbG9va2FoZWFkIDw9IE1JTl9MT09LQUhFQUQgLSAxICYmXG4gICAgICogICAgbW9yZSA9PSB3aW5kb3dfc2l6ZSAtIGxvb2thaGVhZCAtIHN0cnN0YXJ0XG4gICAgICogPT4gbW9yZSA+PSB3aW5kb3dfc2l6ZSAtIChNSU5fTE9PS0FIRUFELTEgKyBXU0laRSArIE1BWF9ESVNULTEpXG4gICAgICogPT4gbW9yZSA+PSB3aW5kb3dfc2l6ZSAtIDIqV1NJWkUgKyAyXG4gICAgICogSW4gdGhlIEJJR19NRU0gb3IgTU1BUCBjYXNlIChub3QgeWV0IHN1cHBvcnRlZCksXG4gICAgICogICB3aW5kb3dfc2l6ZSA9PSBpbnB1dF9zaXplICsgTUlOX0xPT0tBSEVBRCAgJiZcbiAgICAgKiAgIHN0cnN0YXJ0ICsgcy0+bG9va2FoZWFkIDw9IGlucHV0X3NpemUgPT4gbW9yZSA+PSBNSU5fTE9PS0FIRUFELlxuICAgICAqIE90aGVyd2lzZSwgd2luZG93X3NpemUgPT0gMipXU0laRSBzbyBtb3JlID49IDIuXG4gICAgICogSWYgdGhlcmUgd2FzIHNsaWRpbmcsIG1vcmUgPj0gV1NJWkUuIFNvIGluIGFsbCBjYXNlcywgbW9yZSA+PSAyLlxuICAgICAqL1xuICAgIC8vQXNzZXJ0KG1vcmUgPj0gMiwgXCJtb3JlIDwgMlwiKTtcbiAgICBuID0gcmVhZF9idWYocy5zdHJtLCBzLndpbmRvdywgcy5zdHJzdGFydCArIHMubG9va2FoZWFkLCBtb3JlKTtcbiAgICBzLmxvb2thaGVhZCArPSBuO1xuXG4gICAgLyogSW5pdGlhbGl6ZSB0aGUgaGFzaCB2YWx1ZSBub3cgdGhhdCB3ZSBoYXZlIHNvbWUgaW5wdXQ6ICovXG4gICAgaWYgKHMubG9va2FoZWFkICsgcy5pbnNlcnQgPj0gTUlOX01BVENIKSB7XG4gICAgICBzdHIgPSBzLnN0cnN0YXJ0IC0gcy5pbnNlcnQ7XG4gICAgICBzLmluc19oID0gcy53aW5kb3dbc3RyXTtcblxuICAgICAgLyogVVBEQVRFX0hBU0gocywgcy0+aW5zX2gsIHMtPndpbmRvd1tzdHIgKyAxXSk7ICovXG4gICAgICBzLmluc19oID0gKChzLmluc19oIDw8IHMuaGFzaF9zaGlmdCkgXiBzLndpbmRvd1tzdHIgKyAxXSkgJiBzLmhhc2hfbWFzaztcbi8vI2lmIE1JTl9NQVRDSCAhPSAzXG4vLyAgICAgICAgQ2FsbCB1cGRhdGVfaGFzaCgpIE1JTl9NQVRDSC0zIG1vcmUgdGltZXNcbi8vI2VuZGlmXG4gICAgICB3aGlsZSAocy5pbnNlcnQpIHtcbiAgICAgICAgLyogVVBEQVRFX0hBU0gocywgcy0+aW5zX2gsIHMtPndpbmRvd1tzdHIgKyBNSU5fTUFUQ0gtMV0pOyAqL1xuICAgICAgICBzLmluc19oID0gKChzLmluc19oIDw8IHMuaGFzaF9zaGlmdCkgXiBzLndpbmRvd1tzdHIgKyBNSU5fTUFUQ0gtMV0pICYgcy5oYXNoX21hc2s7XG5cbiAgICAgICAgcy5wcmV2W3N0ciAmIHMud19tYXNrXSA9IHMuaGVhZFtzLmluc19oXTtcbiAgICAgICAgcy5oZWFkW3MuaW5zX2hdID0gc3RyO1xuICAgICAgICBzdHIrKztcbiAgICAgICAgcy5pbnNlcnQtLTtcbiAgICAgICAgaWYgKHMubG9va2FoZWFkICsgcy5pbnNlcnQgPCBNSU5fTUFUQ0gpIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICAvKiBJZiB0aGUgd2hvbGUgaW5wdXQgaGFzIGxlc3MgdGhhbiBNSU5fTUFUQ0ggYnl0ZXMsIGluc19oIGlzIGdhcmJhZ2UsXG4gICAgICogYnV0IHRoaXMgaXMgbm90IGltcG9ydGFudCBzaW5jZSBvbmx5IGxpdGVyYWwgYnl0ZXMgd2lsbCBiZSBlbWl0dGVkLlxuICAgICAqL1xuXG4gIH0gd2hpbGUgKHMubG9va2FoZWFkIDwgTUlOX0xPT0tBSEVBRCAmJiBzLnN0cm0uYXZhaWxfaW4gIT09IDApO1xuXG4gIC8qIElmIHRoZSBXSU5fSU5JVCBieXRlcyBhZnRlciB0aGUgZW5kIG9mIHRoZSBjdXJyZW50IGRhdGEgaGF2ZSBuZXZlciBiZWVuXG4gICAqIHdyaXR0ZW4sIHRoZW4gemVybyB0aG9zZSBieXRlcyBpbiBvcmRlciB0byBhdm9pZCBtZW1vcnkgY2hlY2sgcmVwb3J0cyBvZlxuICAgKiB0aGUgdXNlIG9mIHVuaW5pdGlhbGl6ZWQgKG9yIHVuaW5pdGlhbGlzZWQgYXMgSnVsaWFuIHdyaXRlcykgYnl0ZXMgYnlcbiAgICogdGhlIGxvbmdlc3QgbWF0Y2ggcm91dGluZXMuICBVcGRhdGUgdGhlIGhpZ2ggd2F0ZXIgbWFyayBmb3IgdGhlIG5leHRcbiAgICogdGltZSB0aHJvdWdoIGhlcmUuICBXSU5fSU5JVCBpcyBzZXQgdG8gTUFYX01BVENIIHNpbmNlIHRoZSBsb25nZXN0IG1hdGNoXG4gICAqIHJvdXRpbmVzIGFsbG93IHNjYW5uaW5nIHRvIHN0cnN0YXJ0ICsgTUFYX01BVENILCBpZ25vcmluZyBsb29rYWhlYWQuXG4gICAqL1xuLy8gIGlmIChzLmhpZ2hfd2F0ZXIgPCBzLndpbmRvd19zaXplKSB7XG4vLyAgICB2YXIgY3VyciA9IHMuc3Ryc3RhcnQgKyBzLmxvb2thaGVhZDtcbi8vICAgIHZhciBpbml0ID0gMDtcbi8vXG4vLyAgICBpZiAocy5oaWdoX3dhdGVyIDwgY3Vycikge1xuLy8gICAgICAvKiBQcmV2aW91cyBoaWdoIHdhdGVyIG1hcmsgYmVsb3cgY3VycmVudCBkYXRhIC0tIHplcm8gV0lOX0lOSVRcbi8vICAgICAgICogYnl0ZXMgb3IgdXAgdG8gZW5kIG9mIHdpbmRvdywgd2hpY2hldmVyIGlzIGxlc3MuXG4vLyAgICAgICAqL1xuLy8gICAgICBpbml0ID0gcy53aW5kb3dfc2l6ZSAtIGN1cnI7XG4vLyAgICAgIGlmIChpbml0ID4gV0lOX0lOSVQpXG4vLyAgICAgICAgaW5pdCA9IFdJTl9JTklUO1xuLy8gICAgICB6bWVtemVybyhzLT53aW5kb3cgKyBjdXJyLCAodW5zaWduZWQpaW5pdCk7XG4vLyAgICAgIHMtPmhpZ2hfd2F0ZXIgPSBjdXJyICsgaW5pdDtcbi8vICAgIH1cbi8vICAgIGVsc2UgaWYgKHMtPmhpZ2hfd2F0ZXIgPCAodWxnKWN1cnIgKyBXSU5fSU5JVCkge1xuLy8gICAgICAvKiBIaWdoIHdhdGVyIG1hcmsgYXQgb3IgYWJvdmUgY3VycmVudCBkYXRhLCBidXQgYmVsb3cgY3VycmVudCBkYXRhXG4vLyAgICAgICAqIHBsdXMgV0lOX0lOSVQgLS0gemVybyBvdXQgdG8gY3VycmVudCBkYXRhIHBsdXMgV0lOX0lOSVQsIG9yIHVwXG4vLyAgICAgICAqIHRvIGVuZCBvZiB3aW5kb3csIHdoaWNoZXZlciBpcyBsZXNzLlxuLy8gICAgICAgKi9cbi8vICAgICAgaW5pdCA9ICh1bGcpY3VyciArIFdJTl9JTklUIC0gcy0+aGlnaF93YXRlcjtcbi8vICAgICAgaWYgKGluaXQgPiBzLT53aW5kb3dfc2l6ZSAtIHMtPmhpZ2hfd2F0ZXIpXG4vLyAgICAgICAgaW5pdCA9IHMtPndpbmRvd19zaXplIC0gcy0+aGlnaF93YXRlcjtcbi8vICAgICAgem1lbXplcm8ocy0+d2luZG93ICsgcy0+aGlnaF93YXRlciwgKHVuc2lnbmVkKWluaXQpO1xuLy8gICAgICBzLT5oaWdoX3dhdGVyICs9IGluaXQ7XG4vLyAgICB9XG4vLyAgfVxuLy9cbi8vICBBc3NlcnQoKHVsZylzLT5zdHJzdGFydCA8PSBzLT53aW5kb3dfc2l6ZSAtIE1JTl9MT09LQUhFQUQsXG4vLyAgICBcIm5vdCBlbm91Z2ggcm9vbSBmb3Igc2VhcmNoXCIpO1xufVxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvcHkgd2l0aG91dCBjb21wcmVzc2lvbiBhcyBtdWNoIGFzIHBvc3NpYmxlIGZyb20gdGhlIGlucHV0IHN0cmVhbSwgcmV0dXJuXG4gKiB0aGUgY3VycmVudCBibG9jayBzdGF0ZS5cbiAqIFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgaW5zZXJ0IG5ldyBzdHJpbmdzIGluIHRoZSBkaWN0aW9uYXJ5IHNpbmNlXG4gKiB1bmNvbXByZXNzaWJsZSBkYXRhIGlzIHByb2JhYmx5IG5vdCB1c2VmdWwuIFRoaXMgZnVuY3Rpb24gaXMgdXNlZFxuICogb25seSBmb3IgdGhlIGxldmVsPTAgY29tcHJlc3Npb24gb3B0aW9uLlxuICogTk9URTogdGhpcyBmdW5jdGlvbiBzaG91bGQgYmUgb3B0aW1pemVkIHRvIGF2b2lkIGV4dHJhIGNvcHlpbmcgZnJvbVxuICogd2luZG93IHRvIHBlbmRpbmdfYnVmLlxuICovXG5mdW5jdGlvbiBkZWZsYXRlX3N0b3JlZChzLCBmbHVzaCkge1xuICAvKiBTdG9yZWQgYmxvY2tzIGFyZSBsaW1pdGVkIHRvIDB4ZmZmZiBieXRlcywgcGVuZGluZ19idWYgaXMgbGltaXRlZFxuICAgKiB0byBwZW5kaW5nX2J1Zl9zaXplLCBhbmQgZWFjaCBzdG9yZWQgYmxvY2sgaGFzIGEgNSBieXRlIGhlYWRlcjpcbiAgICovXG4gIHZhciBtYXhfYmxvY2tfc2l6ZSA9IDB4ZmZmZjtcblxuICBpZiAobWF4X2Jsb2NrX3NpemUgPiBzLnBlbmRpbmdfYnVmX3NpemUgLSA1KSB7XG4gICAgbWF4X2Jsb2NrX3NpemUgPSBzLnBlbmRpbmdfYnVmX3NpemUgLSA1O1xuICB9XG5cbiAgLyogQ29weSBhcyBtdWNoIGFzIHBvc3NpYmxlIGZyb20gaW5wdXQgdG8gb3V0cHV0OiAqL1xuICBmb3IgKDs7KSB7XG4gICAgLyogRmlsbCB0aGUgd2luZG93IGFzIG11Y2ggYXMgcG9zc2libGU6ICovXG4gICAgaWYgKHMubG9va2FoZWFkIDw9IDEpIHtcblxuICAgICAgLy9Bc3NlcnQocy0+c3Ryc3RhcnQgPCBzLT53X3NpemUrTUFYX0RJU1QocykgfHxcbiAgICAgIC8vICBzLT5ibG9ja19zdGFydCA+PSAobG9uZylzLT53X3NpemUsIFwic2xpZGUgdG9vIGxhdGVcIik7XG4vLyAgICAgIGlmICghKHMuc3Ryc3RhcnQgPCBzLndfc2l6ZSArIChzLndfc2l6ZSAtIE1JTl9MT09LQUhFQUQpIHx8XG4vLyAgICAgICAgcy5ibG9ja19zdGFydCA+PSBzLndfc2l6ZSkpIHtcbi8vICAgICAgICB0aHJvdyAgbmV3IEVycm9yKFwic2xpZGUgdG9vIGxhdGVcIik7XG4vLyAgICAgIH1cblxuICAgICAgZmlsbF93aW5kb3cocyk7XG4gICAgICBpZiAocy5sb29rYWhlYWQgPT09IDAgJiYgZmx1c2ggPT09IFpfTk9fRkxVU0gpIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cblxuICAgICAgaWYgKHMubG9va2FoZWFkID09PSAwKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgLyogZmx1c2ggdGhlIGN1cnJlbnQgYmxvY2sgKi9cbiAgICB9XG4gICAgLy9Bc3NlcnQocy0+YmxvY2tfc3RhcnQgPj0gMEwsIFwiYmxvY2sgZ29uZVwiKTtcbi8vICAgIGlmIChzLmJsb2NrX3N0YXJ0IDwgMCkgdGhyb3cgbmV3IEVycm9yKFwiYmxvY2sgZ29uZVwiKTtcblxuICAgIHMuc3Ryc3RhcnQgKz0gcy5sb29rYWhlYWQ7XG4gICAgcy5sb29rYWhlYWQgPSAwO1xuXG4gICAgLyogRW1pdCBhIHN0b3JlZCBibG9jayBpZiBwZW5kaW5nX2J1ZiB3aWxsIGJlIGZ1bGw6ICovXG4gICAgdmFyIG1heF9zdGFydCA9IHMuYmxvY2tfc3RhcnQgKyBtYXhfYmxvY2tfc2l6ZTtcblxuICAgIGlmIChzLnN0cnN0YXJ0ID09PSAwIHx8IHMuc3Ryc3RhcnQgPj0gbWF4X3N0YXJ0KSB7XG4gICAgICAvKiBzdHJzdGFydCA9PSAwIGlzIHBvc3NpYmxlIHdoZW4gd3JhcGFyb3VuZCBvbiAxNi1iaXQgbWFjaGluZSAqL1xuICAgICAgcy5sb29rYWhlYWQgPSBzLnN0cnN0YXJ0IC0gbWF4X3N0YXJ0O1xuICAgICAgcy5zdHJzdGFydCA9IG1heF9zdGFydDtcbiAgICAgIC8qKiogRkxVU0hfQkxPQ0socywgMCk7ICoqKi9cbiAgICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cbiAgICAgIC8qKiovXG5cblxuICAgIH1cbiAgICAvKiBGbHVzaCBpZiB3ZSBtYXkgaGF2ZSB0byBzbGlkZSwgb3RoZXJ3aXNlIGJsb2NrX3N0YXJ0IG1heSBiZWNvbWVcbiAgICAgKiBuZWdhdGl2ZSBhbmQgdGhlIGRhdGEgd2lsbCBiZSBnb25lOlxuICAgICAqL1xuICAgIGlmIChzLnN0cnN0YXJ0IC0gcy5ibG9ja19zdGFydCA+PSAocy53X3NpemUgLSBNSU5fTE9PS0FIRUFEKSkge1xuICAgICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgfVxuICAgICAgLyoqKi9cbiAgICB9XG4gIH1cblxuICBzLmluc2VydCA9IDA7XG5cbiAgaWYgKGZsdXNoID09PSBaX0ZJTklTSCkge1xuICAgIC8qKiogRkxVU0hfQkxPQ0socywgMSk7ICoqKi9cbiAgICBmbHVzaF9ibG9ja19vbmx5KHMsIHRydWUpO1xuICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICByZXR1cm4gQlNfRklOSVNIX1NUQVJURUQ7XG4gICAgfVxuICAgIC8qKiovXG4gICAgcmV0dXJuIEJTX0ZJTklTSF9ET05FO1xuICB9XG5cbiAgaWYgKHMuc3Ryc3RhcnQgPiBzLmJsb2NrX3N0YXJ0KSB7XG4gICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgIH1cbiAgICAvKioqL1xuICB9XG5cbiAgcmV0dXJuIEJTX05FRURfTU9SRTtcbn1cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb21wcmVzcyBhcyBtdWNoIGFzIHBvc3NpYmxlIGZyb20gdGhlIGlucHV0IHN0cmVhbSwgcmV0dXJuIHRoZSBjdXJyZW50XG4gKiBibG9jayBzdGF0ZS5cbiAqIFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcGVyZm9ybSBsYXp5IGV2YWx1YXRpb24gb2YgbWF0Y2hlcyBhbmQgaW5zZXJ0c1xuICogbmV3IHN0cmluZ3MgaW4gdGhlIGRpY3Rpb25hcnkgb25seSBmb3IgdW5tYXRjaGVkIHN0cmluZ3Mgb3IgZm9yIHNob3J0XG4gKiBtYXRjaGVzLiBJdCBpcyB1c2VkIG9ubHkgZm9yIHRoZSBmYXN0IGNvbXByZXNzaW9uIG9wdGlvbnMuXG4gKi9cbmZ1bmN0aW9uIGRlZmxhdGVfZmFzdChzLCBmbHVzaCkge1xuICB2YXIgaGFzaF9oZWFkOyAgICAgICAgLyogaGVhZCBvZiB0aGUgaGFzaCBjaGFpbiAqL1xuICB2YXIgYmZsdXNoOyAgICAgICAgICAgLyogc2V0IGlmIGN1cnJlbnQgYmxvY2sgbXVzdCBiZSBmbHVzaGVkICovXG5cbiAgZm9yICg7Oykge1xuICAgIC8qIE1ha2Ugc3VyZSB0aGF0IHdlIGFsd2F5cyBoYXZlIGVub3VnaCBsb29rYWhlYWQsIGV4Y2VwdFxuICAgICAqIGF0IHRoZSBlbmQgb2YgdGhlIGlucHV0IGZpbGUuIFdlIG5lZWQgTUFYX01BVENIIGJ5dGVzXG4gICAgICogZm9yIHRoZSBuZXh0IG1hdGNoLCBwbHVzIE1JTl9NQVRDSCBieXRlcyB0byBpbnNlcnQgdGhlXG4gICAgICogc3RyaW5nIGZvbGxvd2luZyB0aGUgbmV4dCBtYXRjaC5cbiAgICAgKi9cbiAgICBpZiAocy5sb29rYWhlYWQgPCBNSU5fTE9PS0FIRUFEKSB7XG4gICAgICBmaWxsX3dpbmRvdyhzKTtcbiAgICAgIGlmIChzLmxvb2thaGVhZCA8IE1JTl9MT09LQUhFQUQgJiYgZmx1c2ggPT09IFpfTk9fRkxVU0gpIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cbiAgICAgIGlmIChzLmxvb2thaGVhZCA9PT0gMCkge1xuICAgICAgICBicmVhazsgLyogZmx1c2ggdGhlIGN1cnJlbnQgYmxvY2sgKi9cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiBJbnNlcnQgdGhlIHN0cmluZyB3aW5kb3dbc3Ryc3RhcnQgLi4gc3Ryc3RhcnQrMl0gaW4gdGhlXG4gICAgICogZGljdGlvbmFyeSwgYW5kIHNldCBoYXNoX2hlYWQgdG8gdGhlIGhlYWQgb2YgdGhlIGhhc2ggY2hhaW46XG4gICAgICovXG4gICAgaGFzaF9oZWFkID0gMC8qTklMKi87XG4gICAgaWYgKHMubG9va2FoZWFkID49IE1JTl9NQVRDSCkge1xuICAgICAgLyoqKiBJTlNFUlRfU1RSSU5HKHMsIHMuc3Ryc3RhcnQsIGhhc2hfaGVhZCk7ICoqKi9cbiAgICAgIHMuaW5zX2ggPSAoKHMuaW5zX2ggPDwgcy5oYXNoX3NoaWZ0KSBeIHMud2luZG93W3Muc3Ryc3RhcnQgKyBNSU5fTUFUQ0ggLSAxXSkgJiBzLmhhc2hfbWFzaztcbiAgICAgIGhhc2hfaGVhZCA9IHMucHJldltzLnN0cnN0YXJ0ICYgcy53X21hc2tdID0gcy5oZWFkW3MuaW5zX2hdO1xuICAgICAgcy5oZWFkW3MuaW5zX2hdID0gcy5zdHJzdGFydDtcbiAgICAgIC8qKiovXG4gICAgfVxuXG4gICAgLyogRmluZCB0aGUgbG9uZ2VzdCBtYXRjaCwgZGlzY2FyZGluZyB0aG9zZSA8PSBwcmV2X2xlbmd0aC5cbiAgICAgKiBBdCB0aGlzIHBvaW50IHdlIGhhdmUgYWx3YXlzIG1hdGNoX2xlbmd0aCA8IE1JTl9NQVRDSFxuICAgICAqL1xuICAgIGlmIChoYXNoX2hlYWQgIT09IDAvKk5JTCovICYmICgocy5zdHJzdGFydCAtIGhhc2hfaGVhZCkgPD0gKHMud19zaXplIC0gTUlOX0xPT0tBSEVBRCkpKSB7XG4gICAgICAvKiBUbyBzaW1wbGlmeSB0aGUgY29kZSwgd2UgcHJldmVudCBtYXRjaGVzIHdpdGggdGhlIHN0cmluZ1xuICAgICAgICogb2Ygd2luZG93IGluZGV4IDAgKGluIHBhcnRpY3VsYXIgd2UgaGF2ZSB0byBhdm9pZCBhIG1hdGNoXG4gICAgICAgKiBvZiB0aGUgc3RyaW5nIHdpdGggaXRzZWxmIGF0IHRoZSBzdGFydCBvZiB0aGUgaW5wdXQgZmlsZSkuXG4gICAgICAgKi9cbiAgICAgIHMubWF0Y2hfbGVuZ3RoID0gbG9uZ2VzdF9tYXRjaChzLCBoYXNoX2hlYWQpO1xuICAgICAgLyogbG9uZ2VzdF9tYXRjaCgpIHNldHMgbWF0Y2hfc3RhcnQgKi9cbiAgICB9XG4gICAgaWYgKHMubWF0Y2hfbGVuZ3RoID49IE1JTl9NQVRDSCkge1xuICAgICAgLy8gY2hlY2tfbWF0Y2gocywgcy5zdHJzdGFydCwgcy5tYXRjaF9zdGFydCwgcy5tYXRjaF9sZW5ndGgpOyAvLyBmb3IgZGVidWcgb25seVxuXG4gICAgICAvKioqIF90cl90YWxseV9kaXN0KHMsIHMuc3Ryc3RhcnQgLSBzLm1hdGNoX3N0YXJ0LFxuICAgICAgICAgICAgICAgICAgICAgcy5tYXRjaF9sZW5ndGggLSBNSU5fTUFUQ0gsIGJmbHVzaCk7ICoqKi9cbiAgICAgIGJmbHVzaCA9IHRyZWVzLl90cl90YWxseShzLCBzLnN0cnN0YXJ0IC0gcy5tYXRjaF9zdGFydCwgcy5tYXRjaF9sZW5ndGggLSBNSU5fTUFUQ0gpO1xuXG4gICAgICBzLmxvb2thaGVhZCAtPSBzLm1hdGNoX2xlbmd0aDtcblxuICAgICAgLyogSW5zZXJ0IG5ldyBzdHJpbmdzIGluIHRoZSBoYXNoIHRhYmxlIG9ubHkgaWYgdGhlIG1hdGNoIGxlbmd0aFxuICAgICAgICogaXMgbm90IHRvbyBsYXJnZS4gVGhpcyBzYXZlcyB0aW1lIGJ1dCBkZWdyYWRlcyBjb21wcmVzc2lvbi5cbiAgICAgICAqL1xuICAgICAgaWYgKHMubWF0Y2hfbGVuZ3RoIDw9IHMubWF4X2xhenlfbWF0Y2gvKm1heF9pbnNlcnRfbGVuZ3RoKi8gJiYgcy5sb29rYWhlYWQgPj0gTUlOX01BVENIKSB7XG4gICAgICAgIHMubWF0Y2hfbGVuZ3RoLS07IC8qIHN0cmluZyBhdCBzdHJzdGFydCBhbHJlYWR5IGluIHRhYmxlICovXG4gICAgICAgIGRvIHtcbiAgICAgICAgICBzLnN0cnN0YXJ0Kys7XG4gICAgICAgICAgLyoqKiBJTlNFUlRfU1RSSU5HKHMsIHMuc3Ryc3RhcnQsIGhhc2hfaGVhZCk7ICoqKi9cbiAgICAgICAgICBzLmluc19oID0gKChzLmluc19oIDw8IHMuaGFzaF9zaGlmdCkgXiBzLndpbmRvd1tzLnN0cnN0YXJ0ICsgTUlOX01BVENIIC0gMV0pICYgcy5oYXNoX21hc2s7XG4gICAgICAgICAgaGFzaF9oZWFkID0gcy5wcmV2W3Muc3Ryc3RhcnQgJiBzLndfbWFza10gPSBzLmhlYWRbcy5pbnNfaF07XG4gICAgICAgICAgcy5oZWFkW3MuaW5zX2hdID0gcy5zdHJzdGFydDtcbiAgICAgICAgICAvKioqL1xuICAgICAgICAgIC8qIHN0cnN0YXJ0IG5ldmVyIGV4Y2VlZHMgV1NJWkUtTUFYX01BVENILCBzbyB0aGVyZSBhcmVcbiAgICAgICAgICAgKiBhbHdheXMgTUlOX01BVENIIGJ5dGVzIGFoZWFkLlxuICAgICAgICAgICAqL1xuICAgICAgICB9IHdoaWxlICgtLXMubWF0Y2hfbGVuZ3RoICE9PSAwKTtcbiAgICAgICAgcy5zdHJzdGFydCsrO1xuICAgICAgfSBlbHNlXG4gICAgICB7XG4gICAgICAgIHMuc3Ryc3RhcnQgKz0gcy5tYXRjaF9sZW5ndGg7XG4gICAgICAgIHMubWF0Y2hfbGVuZ3RoID0gMDtcbiAgICAgICAgcy5pbnNfaCA9IHMud2luZG93W3Muc3Ryc3RhcnRdO1xuICAgICAgICAvKiBVUERBVEVfSEFTSChzLCBzLmluc19oLCBzLndpbmRvd1tzLnN0cnN0YXJ0KzFdKTsgKi9cbiAgICAgICAgcy5pbnNfaCA9ICgocy5pbnNfaCA8PCBzLmhhc2hfc2hpZnQpIF4gcy53aW5kb3dbcy5zdHJzdGFydCArIDFdKSAmIHMuaGFzaF9tYXNrO1xuXG4vLyNpZiBNSU5fTUFUQ0ggIT0gM1xuLy8gICAgICAgICAgICAgICAgQ2FsbCBVUERBVEVfSEFTSCgpIE1JTl9NQVRDSC0zIG1vcmUgdGltZXNcbi8vI2VuZGlmXG4gICAgICAgIC8qIElmIGxvb2thaGVhZCA8IE1JTl9NQVRDSCwgaW5zX2ggaXMgZ2FyYmFnZSwgYnV0IGl0IGRvZXMgbm90XG4gICAgICAgICAqIG1hdHRlciBzaW5jZSBpdCB3aWxsIGJlIHJlY29tcHV0ZWQgYXQgbmV4dCBkZWZsYXRlIGNhbGwuXG4gICAgICAgICAqL1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvKiBObyBtYXRjaCwgb3V0cHV0IGEgbGl0ZXJhbCBieXRlICovXG4gICAgICAvL1RyYWNldnYoKHN0ZGVycixcIiVjXCIsIHMud2luZG93W3Muc3Ryc3RhcnRdKSk7XG4gICAgICAvKioqIF90cl90YWxseV9saXQocywgcy53aW5kb3dbcy5zdHJzdGFydF0sIGJmbHVzaCk7ICoqKi9cbiAgICAgIGJmbHVzaCA9IHRyZWVzLl90cl90YWxseShzLCAwLCBzLndpbmRvd1tzLnN0cnN0YXJ0XSk7XG5cbiAgICAgIHMubG9va2FoZWFkLS07XG4gICAgICBzLnN0cnN0YXJ0Kys7XG4gICAgfVxuICAgIGlmIChiZmx1c2gpIHtcbiAgICAgIC8qKiogRkxVU0hfQkxPQ0socywgMCk7ICoqKi9cbiAgICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cbiAgICAgIC8qKiovXG4gICAgfVxuICB9XG4gIHMuaW5zZXJ0ID0gKChzLnN0cnN0YXJ0IDwgKE1JTl9NQVRDSC0xKSkgPyBzLnN0cnN0YXJ0IDogTUlOX01BVENILTEpO1xuICBpZiAoZmx1c2ggPT09IFpfRklOSVNIKSB7XG4gICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAxKTsgKioqL1xuICAgIGZsdXNoX2Jsb2NrX29ubHkocywgdHJ1ZSk7XG4gICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIHJldHVybiBCU19GSU5JU0hfU1RBUlRFRDtcbiAgICB9XG4gICAgLyoqKi9cbiAgICByZXR1cm4gQlNfRklOSVNIX0RPTkU7XG4gIH1cbiAgaWYgKHMubGFzdF9saXQpIHtcbiAgICAvKioqIEZMVVNIX0JMT0NLKHMsIDApOyAqKiovXG4gICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIHJldHVybiBCU19ORUVEX01PUkU7XG4gICAgfVxuICAgIC8qKiovXG4gIH1cbiAgcmV0dXJuIEJTX0JMT0NLX0RPTkU7XG59XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogU2FtZSBhcyBhYm92ZSwgYnV0IGFjaGlldmVzIGJldHRlciBjb21wcmVzc2lvbi4gV2UgdXNlIGEgbGF6eVxuICogZXZhbHVhdGlvbiBmb3IgbWF0Y2hlczogYSBtYXRjaCBpcyBmaW5hbGx5IGFkb3B0ZWQgb25seSBpZiB0aGVyZSBpc1xuICogbm8gYmV0dGVyIG1hdGNoIGF0IHRoZSBuZXh0IHdpbmRvdyBwb3NpdGlvbi5cbiAqL1xuZnVuY3Rpb24gZGVmbGF0ZV9zbG93KHMsIGZsdXNoKSB7XG4gIHZhciBoYXNoX2hlYWQ7ICAgICAgICAgIC8qIGhlYWQgb2YgaGFzaCBjaGFpbiAqL1xuICB2YXIgYmZsdXNoOyAgICAgICAgICAgICAgLyogc2V0IGlmIGN1cnJlbnQgYmxvY2sgbXVzdCBiZSBmbHVzaGVkICovXG5cbiAgdmFyIG1heF9pbnNlcnQ7XG5cbiAgLyogUHJvY2VzcyB0aGUgaW5wdXQgYmxvY2suICovXG4gIGZvciAoOzspIHtcbiAgICAvKiBNYWtlIHN1cmUgdGhhdCB3ZSBhbHdheXMgaGF2ZSBlbm91Z2ggbG9va2FoZWFkLCBleGNlcHRcbiAgICAgKiBhdCB0aGUgZW5kIG9mIHRoZSBpbnB1dCBmaWxlLiBXZSBuZWVkIE1BWF9NQVRDSCBieXRlc1xuICAgICAqIGZvciB0aGUgbmV4dCBtYXRjaCwgcGx1cyBNSU5fTUFUQ0ggYnl0ZXMgdG8gaW5zZXJ0IHRoZVxuICAgICAqIHN0cmluZyBmb2xsb3dpbmcgdGhlIG5leHQgbWF0Y2guXG4gICAgICovXG4gICAgaWYgKHMubG9va2FoZWFkIDwgTUlOX0xPT0tBSEVBRCkge1xuICAgICAgZmlsbF93aW5kb3cocyk7XG4gICAgICBpZiAocy5sb29rYWhlYWQgPCBNSU5fTE9PS0FIRUFEICYmIGZsdXNoID09PSBaX05PX0ZMVVNIKSB7XG4gICAgICAgIHJldHVybiBCU19ORUVEX01PUkU7XG4gICAgICB9XG4gICAgICBpZiAocy5sb29rYWhlYWQgPT09IDApIHsgYnJlYWs7IH0gLyogZmx1c2ggdGhlIGN1cnJlbnQgYmxvY2sgKi9cbiAgICB9XG5cbiAgICAvKiBJbnNlcnQgdGhlIHN0cmluZyB3aW5kb3dbc3Ryc3RhcnQgLi4gc3Ryc3RhcnQrMl0gaW4gdGhlXG4gICAgICogZGljdGlvbmFyeSwgYW5kIHNldCBoYXNoX2hlYWQgdG8gdGhlIGhlYWQgb2YgdGhlIGhhc2ggY2hhaW46XG4gICAgICovXG4gICAgaGFzaF9oZWFkID0gMC8qTklMKi87XG4gICAgaWYgKHMubG9va2FoZWFkID49IE1JTl9NQVRDSCkge1xuICAgICAgLyoqKiBJTlNFUlRfU1RSSU5HKHMsIHMuc3Ryc3RhcnQsIGhhc2hfaGVhZCk7ICoqKi9cbiAgICAgIHMuaW5zX2ggPSAoKHMuaW5zX2ggPDwgcy5oYXNoX3NoaWZ0KSBeIHMud2luZG93W3Muc3Ryc3RhcnQgKyBNSU5fTUFUQ0ggLSAxXSkgJiBzLmhhc2hfbWFzaztcbiAgICAgIGhhc2hfaGVhZCA9IHMucHJldltzLnN0cnN0YXJ0ICYgcy53X21hc2tdID0gcy5oZWFkW3MuaW5zX2hdO1xuICAgICAgcy5oZWFkW3MuaW5zX2hdID0gcy5zdHJzdGFydDtcbiAgICAgIC8qKiovXG4gICAgfVxuXG4gICAgLyogRmluZCB0aGUgbG9uZ2VzdCBtYXRjaCwgZGlzY2FyZGluZyB0aG9zZSA8PSBwcmV2X2xlbmd0aC5cbiAgICAgKi9cbiAgICBzLnByZXZfbGVuZ3RoID0gcy5tYXRjaF9sZW5ndGg7XG4gICAgcy5wcmV2X21hdGNoID0gcy5tYXRjaF9zdGFydDtcbiAgICBzLm1hdGNoX2xlbmd0aCA9IE1JTl9NQVRDSC0xO1xuXG4gICAgaWYgKGhhc2hfaGVhZCAhPT0gMC8qTklMKi8gJiYgcy5wcmV2X2xlbmd0aCA8IHMubWF4X2xhenlfbWF0Y2ggJiZcbiAgICAgICAgcy5zdHJzdGFydCAtIGhhc2hfaGVhZCA8PSAocy53X3NpemUtTUlOX0xPT0tBSEVBRCkvKk1BWF9ESVNUKHMpKi8pIHtcbiAgICAgIC8qIFRvIHNpbXBsaWZ5IHRoZSBjb2RlLCB3ZSBwcmV2ZW50IG1hdGNoZXMgd2l0aCB0aGUgc3RyaW5nXG4gICAgICAgKiBvZiB3aW5kb3cgaW5kZXggMCAoaW4gcGFydGljdWxhciB3ZSBoYXZlIHRvIGF2b2lkIGEgbWF0Y2hcbiAgICAgICAqIG9mIHRoZSBzdHJpbmcgd2l0aCBpdHNlbGYgYXQgdGhlIHN0YXJ0IG9mIHRoZSBpbnB1dCBmaWxlKS5cbiAgICAgICAqL1xuICAgICAgcy5tYXRjaF9sZW5ndGggPSBsb25nZXN0X21hdGNoKHMsIGhhc2hfaGVhZCk7XG4gICAgICAvKiBsb25nZXN0X21hdGNoKCkgc2V0cyBtYXRjaF9zdGFydCAqL1xuXG4gICAgICBpZiAocy5tYXRjaF9sZW5ndGggPD0gNSAmJlxuICAgICAgICAgKHMuc3RyYXRlZ3kgPT09IFpfRklMVEVSRUQgfHwgKHMubWF0Y2hfbGVuZ3RoID09PSBNSU5fTUFUQ0ggJiYgcy5zdHJzdGFydCAtIHMubWF0Y2hfc3RhcnQgPiA0MDk2LypUT09fRkFSKi8pKSkge1xuXG4gICAgICAgIC8qIElmIHByZXZfbWF0Y2ggaXMgYWxzbyBNSU5fTUFUQ0gsIG1hdGNoX3N0YXJ0IGlzIGdhcmJhZ2VcbiAgICAgICAgICogYnV0IHdlIHdpbGwgaWdub3JlIHRoZSBjdXJyZW50IG1hdGNoIGFueXdheS5cbiAgICAgICAgICovXG4gICAgICAgIHMubWF0Y2hfbGVuZ3RoID0gTUlOX01BVENILTE7XG4gICAgICB9XG4gICAgfVxuICAgIC8qIElmIHRoZXJlIHdhcyBhIG1hdGNoIGF0IHRoZSBwcmV2aW91cyBzdGVwIGFuZCB0aGUgY3VycmVudFxuICAgICAqIG1hdGNoIGlzIG5vdCBiZXR0ZXIsIG91dHB1dCB0aGUgcHJldmlvdXMgbWF0Y2g6XG4gICAgICovXG4gICAgaWYgKHMucHJldl9sZW5ndGggPj0gTUlOX01BVENIICYmIHMubWF0Y2hfbGVuZ3RoIDw9IHMucHJldl9sZW5ndGgpIHtcbiAgICAgIG1heF9pbnNlcnQgPSBzLnN0cnN0YXJ0ICsgcy5sb29rYWhlYWQgLSBNSU5fTUFUQ0g7XG4gICAgICAvKiBEbyBub3QgaW5zZXJ0IHN0cmluZ3MgaW4gaGFzaCB0YWJsZSBiZXlvbmQgdGhpcy4gKi9cblxuICAgICAgLy9jaGVja19tYXRjaChzLCBzLnN0cnN0YXJ0LTEsIHMucHJldl9tYXRjaCwgcy5wcmV2X2xlbmd0aCk7XG5cbiAgICAgIC8qKipfdHJfdGFsbHlfZGlzdChzLCBzLnN0cnN0YXJ0IC0gMSAtIHMucHJldl9tYXRjaCxcbiAgICAgICAgICAgICAgICAgICAgIHMucHJldl9sZW5ndGggLSBNSU5fTUFUQ0gsIGJmbHVzaCk7KioqL1xuICAgICAgYmZsdXNoID0gdHJlZXMuX3RyX3RhbGx5KHMsIHMuc3Ryc3RhcnQgLSAxLSBzLnByZXZfbWF0Y2gsIHMucHJldl9sZW5ndGggLSBNSU5fTUFUQ0gpO1xuICAgICAgLyogSW5zZXJ0IGluIGhhc2ggdGFibGUgYWxsIHN0cmluZ3MgdXAgdG8gdGhlIGVuZCBvZiB0aGUgbWF0Y2guXG4gICAgICAgKiBzdHJzdGFydC0xIGFuZCBzdHJzdGFydCBhcmUgYWxyZWFkeSBpbnNlcnRlZC4gSWYgdGhlcmUgaXMgbm90XG4gICAgICAgKiBlbm91Z2ggbG9va2FoZWFkLCB0aGUgbGFzdCB0d28gc3RyaW5ncyBhcmUgbm90IGluc2VydGVkIGluXG4gICAgICAgKiB0aGUgaGFzaCB0YWJsZS5cbiAgICAgICAqL1xuICAgICAgcy5sb29rYWhlYWQgLT0gcy5wcmV2X2xlbmd0aC0xO1xuICAgICAgcy5wcmV2X2xlbmd0aCAtPSAyO1xuICAgICAgZG8ge1xuICAgICAgICBpZiAoKytzLnN0cnN0YXJ0IDw9IG1heF9pbnNlcnQpIHtcbiAgICAgICAgICAvKioqIElOU0VSVF9TVFJJTkcocywgcy5zdHJzdGFydCwgaGFzaF9oZWFkKTsgKioqL1xuICAgICAgICAgIHMuaW5zX2ggPSAoKHMuaW5zX2ggPDwgcy5oYXNoX3NoaWZ0KSBeIHMud2luZG93W3Muc3Ryc3RhcnQgKyBNSU5fTUFUQ0ggLSAxXSkgJiBzLmhhc2hfbWFzaztcbiAgICAgICAgICBoYXNoX2hlYWQgPSBzLnByZXZbcy5zdHJzdGFydCAmIHMud19tYXNrXSA9IHMuaGVhZFtzLmluc19oXTtcbiAgICAgICAgICBzLmhlYWRbcy5pbnNfaF0gPSBzLnN0cnN0YXJ0O1xuICAgICAgICAgIC8qKiovXG4gICAgICAgIH1cbiAgICAgIH0gd2hpbGUgKC0tcy5wcmV2X2xlbmd0aCAhPT0gMCk7XG4gICAgICBzLm1hdGNoX2F2YWlsYWJsZSA9IDA7XG4gICAgICBzLm1hdGNoX2xlbmd0aCA9IE1JTl9NQVRDSC0xO1xuICAgICAgcy5zdHJzdGFydCsrO1xuXG4gICAgICBpZiAoYmZsdXNoKSB7XG4gICAgICAgIC8qKiogRkxVU0hfQkxPQ0socywgMCk7ICoqKi9cbiAgICAgICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgICAgfVxuICAgICAgICAvKioqL1xuICAgICAgfVxuXG4gICAgfSBlbHNlIGlmIChzLm1hdGNoX2F2YWlsYWJsZSkge1xuICAgICAgLyogSWYgdGhlcmUgd2FzIG5vIG1hdGNoIGF0IHRoZSBwcmV2aW91cyBwb3NpdGlvbiwgb3V0cHV0IGFcbiAgICAgICAqIHNpbmdsZSBsaXRlcmFsLiBJZiB0aGVyZSB3YXMgYSBtYXRjaCBidXQgdGhlIGN1cnJlbnQgbWF0Y2hcbiAgICAgICAqIGlzIGxvbmdlciwgdHJ1bmNhdGUgdGhlIHByZXZpb3VzIG1hdGNoIHRvIGEgc2luZ2xlIGxpdGVyYWwuXG4gICAgICAgKi9cbiAgICAgIC8vVHJhY2V2digoc3RkZXJyLFwiJWNcIiwgcy0+d2luZG93W3MtPnN0cnN0YXJ0LTFdKSk7XG4gICAgICAvKioqIF90cl90YWxseV9saXQocywgcy53aW5kb3dbcy5zdHJzdGFydC0xXSwgYmZsdXNoKTsgKioqL1xuICAgICAgYmZsdXNoID0gdHJlZXMuX3RyX3RhbGx5KHMsIDAsIHMud2luZG93W3Muc3Ryc3RhcnQtMV0pO1xuXG4gICAgICBpZiAoYmZsdXNoKSB7XG4gICAgICAgIC8qKiogRkxVU0hfQkxPQ0tfT05MWShzLCAwKSAqKiovXG4gICAgICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgICAgICAvKioqL1xuICAgICAgfVxuICAgICAgcy5zdHJzdGFydCsrO1xuICAgICAgcy5sb29rYWhlYWQtLTtcbiAgICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICAgIHJldHVybiBCU19ORUVEX01PUkU7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8qIFRoZXJlIGlzIG5vIHByZXZpb3VzIG1hdGNoIHRvIGNvbXBhcmUgd2l0aCwgd2FpdCBmb3JcbiAgICAgICAqIHRoZSBuZXh0IHN0ZXAgdG8gZGVjaWRlLlxuICAgICAgICovXG4gICAgICBzLm1hdGNoX2F2YWlsYWJsZSA9IDE7XG4gICAgICBzLnN0cnN0YXJ0Kys7XG4gICAgICBzLmxvb2thaGVhZC0tO1xuICAgIH1cbiAgfVxuICAvL0Fzc2VydCAoZmx1c2ggIT0gWl9OT19GTFVTSCwgXCJubyBmbHVzaD9cIik7XG4gIGlmIChzLm1hdGNoX2F2YWlsYWJsZSkge1xuICAgIC8vVHJhY2V2digoc3RkZXJyLFwiJWNcIiwgcy0+d2luZG93W3MtPnN0cnN0YXJ0LTFdKSk7XG4gICAgLyoqKiBfdHJfdGFsbHlfbGl0KHMsIHMud2luZG93W3Muc3Ryc3RhcnQtMV0sIGJmbHVzaCk7ICoqKi9cbiAgICBiZmx1c2ggPSB0cmVlcy5fdHJfdGFsbHkocywgMCwgcy53aW5kb3dbcy5zdHJzdGFydC0xXSk7XG5cbiAgICBzLm1hdGNoX2F2YWlsYWJsZSA9IDA7XG4gIH1cbiAgcy5pbnNlcnQgPSBzLnN0cnN0YXJ0IDwgTUlOX01BVENILTEgPyBzLnN0cnN0YXJ0IDogTUlOX01BVENILTE7XG4gIGlmIChmbHVzaCA9PT0gWl9GSU5JU0gpIHtcbiAgICAvKioqIEZMVVNIX0JMT0NLKHMsIDEpOyAqKiovXG4gICAgZmx1c2hfYmxvY2tfb25seShzLCB0cnVlKTtcbiAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgcmV0dXJuIEJTX0ZJTklTSF9TVEFSVEVEO1xuICAgIH1cbiAgICAvKioqL1xuICAgIHJldHVybiBCU19GSU5JU0hfRE9ORTtcbiAgfVxuICBpZiAocy5sYXN0X2xpdCkge1xuICAgIC8qKiogRkxVU0hfQkxPQ0socywgMCk7ICoqKi9cbiAgICBmbHVzaF9ibG9ja19vbmx5KHMsIGZhbHNlKTtcbiAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICB9XG4gICAgLyoqKi9cbiAgfVxuXG4gIHJldHVybiBCU19CTE9DS19ET05FO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogRm9yIFpfUkxFLCBzaW1wbHkgbG9vayBmb3IgcnVucyBvZiBieXRlcywgZ2VuZXJhdGUgbWF0Y2hlcyBvbmx5IG9mIGRpc3RhbmNlXG4gKiBvbmUuICBEbyBub3QgbWFpbnRhaW4gYSBoYXNoIHRhYmxlLiAgKEl0IHdpbGwgYmUgcmVnZW5lcmF0ZWQgaWYgdGhpcyBydW4gb2ZcbiAqIGRlZmxhdGUgc3dpdGNoZXMgYXdheSBmcm9tIFpfUkxFLilcbiAqL1xuZnVuY3Rpb24gZGVmbGF0ZV9ybGUocywgZmx1c2gpIHtcbiAgdmFyIGJmbHVzaDsgICAgICAgICAgICAvKiBzZXQgaWYgY3VycmVudCBibG9jayBtdXN0IGJlIGZsdXNoZWQgKi9cbiAgdmFyIHByZXY7ICAgICAgICAgICAgICAvKiBieXRlIGF0IGRpc3RhbmNlIG9uZSB0byBtYXRjaCAqL1xuICB2YXIgc2Nhbiwgc3RyZW5kOyAgICAgIC8qIHNjYW4gZ29lcyB1cCB0byBzdHJlbmQgZm9yIGxlbmd0aCBvZiBydW4gKi9cblxuICB2YXIgX3dpbiA9IHMud2luZG93O1xuXG4gIGZvciAoOzspIHtcbiAgICAvKiBNYWtlIHN1cmUgdGhhdCB3ZSBhbHdheXMgaGF2ZSBlbm91Z2ggbG9va2FoZWFkLCBleGNlcHRcbiAgICAgKiBhdCB0aGUgZW5kIG9mIHRoZSBpbnB1dCBmaWxlLiBXZSBuZWVkIE1BWF9NQVRDSCBieXRlc1xuICAgICAqIGZvciB0aGUgbG9uZ2VzdCBydW4sIHBsdXMgb25lIGZvciB0aGUgdW5yb2xsZWQgbG9vcC5cbiAgICAgKi9cbiAgICBpZiAocy5sb29rYWhlYWQgPD0gTUFYX01BVENIKSB7XG4gICAgICBmaWxsX3dpbmRvdyhzKTtcbiAgICAgIGlmIChzLmxvb2thaGVhZCA8PSBNQVhfTUFUQ0ggJiYgZmx1c2ggPT09IFpfTk9fRkxVU0gpIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cbiAgICAgIGlmIChzLmxvb2thaGVhZCA9PT0gMCkgeyBicmVhazsgfSAvKiBmbHVzaCB0aGUgY3VycmVudCBibG9jayAqL1xuICAgIH1cblxuICAgIC8qIFNlZSBob3cgbWFueSB0aW1lcyB0aGUgcHJldmlvdXMgYnl0ZSByZXBlYXRzICovXG4gICAgcy5tYXRjaF9sZW5ndGggPSAwO1xuICAgIGlmIChzLmxvb2thaGVhZCA+PSBNSU5fTUFUQ0ggJiYgcy5zdHJzdGFydCA+IDApIHtcbiAgICAgIHNjYW4gPSBzLnN0cnN0YXJ0IC0gMTtcbiAgICAgIHByZXYgPSBfd2luW3NjYW5dO1xuICAgICAgaWYgKHByZXYgPT09IF93aW5bKytzY2FuXSAmJiBwcmV2ID09PSBfd2luWysrc2Nhbl0gJiYgcHJldiA9PT0gX3dpblsrK3NjYW5dKSB7XG4gICAgICAgIHN0cmVuZCA9IHMuc3Ryc3RhcnQgKyBNQVhfTUFUQ0g7XG4gICAgICAgIGRvIHtcbiAgICAgICAgICAvKmpzaGludCBub2VtcHR5OmZhbHNlKi9cbiAgICAgICAgfSB3aGlsZSAocHJldiA9PT0gX3dpblsrK3NjYW5dICYmIHByZXYgPT09IF93aW5bKytzY2FuXSAmJlxuICAgICAgICAgICAgICAgICBwcmV2ID09PSBfd2luWysrc2Nhbl0gJiYgcHJldiA9PT0gX3dpblsrK3NjYW5dICYmXG4gICAgICAgICAgICAgICAgIHByZXYgPT09IF93aW5bKytzY2FuXSAmJiBwcmV2ID09PSBfd2luWysrc2Nhbl0gJiZcbiAgICAgICAgICAgICAgICAgcHJldiA9PT0gX3dpblsrK3NjYW5dICYmIHByZXYgPT09IF93aW5bKytzY2FuXSAmJlxuICAgICAgICAgICAgICAgICBzY2FuIDwgc3RyZW5kKTtcbiAgICAgICAgcy5tYXRjaF9sZW5ndGggPSBNQVhfTUFUQ0ggLSAoc3RyZW5kIC0gc2Nhbik7XG4gICAgICAgIGlmIChzLm1hdGNoX2xlbmd0aCA+IHMubG9va2FoZWFkKSB7XG4gICAgICAgICAgcy5tYXRjaF9sZW5ndGggPSBzLmxvb2thaGVhZDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy9Bc3NlcnQoc2NhbiA8PSBzLT53aW5kb3crKHVJbnQpKHMtPndpbmRvd19zaXplLTEpLCBcIndpbGQgc2NhblwiKTtcbiAgICB9XG5cbiAgICAvKiBFbWl0IG1hdGNoIGlmIGhhdmUgcnVuIG9mIE1JTl9NQVRDSCBvciBsb25nZXIsIGVsc2UgZW1pdCBsaXRlcmFsICovXG4gICAgaWYgKHMubWF0Y2hfbGVuZ3RoID49IE1JTl9NQVRDSCkge1xuICAgICAgLy9jaGVja19tYXRjaChzLCBzLnN0cnN0YXJ0LCBzLnN0cnN0YXJ0IC0gMSwgcy5tYXRjaF9sZW5ndGgpO1xuXG4gICAgICAvKioqIF90cl90YWxseV9kaXN0KHMsIDEsIHMubWF0Y2hfbGVuZ3RoIC0gTUlOX01BVENILCBiZmx1c2gpOyAqKiovXG4gICAgICBiZmx1c2ggPSB0cmVlcy5fdHJfdGFsbHkocywgMSwgcy5tYXRjaF9sZW5ndGggLSBNSU5fTUFUQ0gpO1xuXG4gICAgICBzLmxvb2thaGVhZCAtPSBzLm1hdGNoX2xlbmd0aDtcbiAgICAgIHMuc3Ryc3RhcnQgKz0gcy5tYXRjaF9sZW5ndGg7XG4gICAgICBzLm1hdGNoX2xlbmd0aCA9IDA7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8qIE5vIG1hdGNoLCBvdXRwdXQgYSBsaXRlcmFsIGJ5dGUgKi9cbiAgICAgIC8vVHJhY2V2digoc3RkZXJyLFwiJWNcIiwgcy0+d2luZG93W3MtPnN0cnN0YXJ0XSkpO1xuICAgICAgLyoqKiBfdHJfdGFsbHlfbGl0KHMsIHMud2luZG93W3Muc3Ryc3RhcnRdLCBiZmx1c2gpOyAqKiovXG4gICAgICBiZmx1c2ggPSB0cmVlcy5fdHJfdGFsbHkocywgMCwgcy53aW5kb3dbcy5zdHJzdGFydF0pO1xuXG4gICAgICBzLmxvb2thaGVhZC0tO1xuICAgICAgcy5zdHJzdGFydCsrO1xuICAgIH1cbiAgICBpZiAoYmZsdXNoKSB7XG4gICAgICAvKioqIEZMVVNIX0JMT0NLKHMsIDApOyAqKiovXG4gICAgICBmbHVzaF9ibG9ja19vbmx5KHMsIGZhbHNlKTtcbiAgICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICAgIHJldHVybiBCU19ORUVEX01PUkU7XG4gICAgICB9XG4gICAgICAvKioqL1xuICAgIH1cbiAgfVxuICBzLmluc2VydCA9IDA7XG4gIGlmIChmbHVzaCA9PT0gWl9GSU5JU0gpIHtcbiAgICAvKioqIEZMVVNIX0JMT0NLKHMsIDEpOyAqKiovXG4gICAgZmx1c2hfYmxvY2tfb25seShzLCB0cnVlKTtcbiAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgcmV0dXJuIEJTX0ZJTklTSF9TVEFSVEVEO1xuICAgIH1cbiAgICAvKioqL1xuICAgIHJldHVybiBCU19GSU5JU0hfRE9ORTtcbiAgfVxuICBpZiAocy5sYXN0X2xpdCkge1xuICAgIC8qKiogRkxVU0hfQkxPQ0socywgMCk7ICoqKi9cbiAgICBmbHVzaF9ibG9ja19vbmx5KHMsIGZhbHNlKTtcbiAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICB9XG4gICAgLyoqKi9cbiAgfVxuICByZXR1cm4gQlNfQkxPQ0tfRE9ORTtcbn1cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBGb3IgWl9IVUZGTUFOX09OTFksIGRvIG5vdCBsb29rIGZvciBtYXRjaGVzLiAgRG8gbm90IG1haW50YWluIGEgaGFzaCB0YWJsZS5cbiAqIChJdCB3aWxsIGJlIHJlZ2VuZXJhdGVkIGlmIHRoaXMgcnVuIG9mIGRlZmxhdGUgc3dpdGNoZXMgYXdheSBmcm9tIEh1ZmZtYW4uKVxuICovXG5mdW5jdGlvbiBkZWZsYXRlX2h1ZmYocywgZmx1c2gpIHtcbiAgdmFyIGJmbHVzaDsgICAgICAgICAgICAgLyogc2V0IGlmIGN1cnJlbnQgYmxvY2sgbXVzdCBiZSBmbHVzaGVkICovXG5cbiAgZm9yICg7Oykge1xuICAgIC8qIE1ha2Ugc3VyZSB0aGF0IHdlIGhhdmUgYSBsaXRlcmFsIHRvIHdyaXRlLiAqL1xuICAgIGlmIChzLmxvb2thaGVhZCA9PT0gMCkge1xuICAgICAgZmlsbF93aW5kb3cocyk7XG4gICAgICBpZiAocy5sb29rYWhlYWQgPT09IDApIHtcbiAgICAgICAgaWYgKGZsdXNoID09PSBaX05PX0ZMVVNIKSB7XG4gICAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgICAgfVxuICAgICAgICBicmVhazsgICAgICAvKiBmbHVzaCB0aGUgY3VycmVudCBibG9jayAqL1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qIE91dHB1dCBhIGxpdGVyYWwgYnl0ZSAqL1xuICAgIHMubWF0Y2hfbGVuZ3RoID0gMDtcbiAgICAvL1RyYWNldnYoKHN0ZGVycixcIiVjXCIsIHMtPndpbmRvd1tzLT5zdHJzdGFydF0pKTtcbiAgICAvKioqIF90cl90YWxseV9saXQocywgcy53aW5kb3dbcy5zdHJzdGFydF0sIGJmbHVzaCk7ICoqKi9cbiAgICBiZmx1c2ggPSB0cmVlcy5fdHJfdGFsbHkocywgMCwgcy53aW5kb3dbcy5zdHJzdGFydF0pO1xuICAgIHMubG9va2FoZWFkLS07XG4gICAgcy5zdHJzdGFydCsrO1xuICAgIGlmIChiZmx1c2gpIHtcbiAgICAgIC8qKiogRkxVU0hfQkxPQ0socywgMCk7ICoqKi9cbiAgICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cbiAgICAgIC8qKiovXG4gICAgfVxuICB9XG4gIHMuaW5zZXJ0ID0gMDtcbiAgaWYgKGZsdXNoID09PSBaX0ZJTklTSCkge1xuICAgIC8qKiogRkxVU0hfQkxPQ0socywgMSk7ICoqKi9cbiAgICBmbHVzaF9ibG9ja19vbmx5KHMsIHRydWUpO1xuICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICByZXR1cm4gQlNfRklOSVNIX1NUQVJURUQ7XG4gICAgfVxuICAgIC8qKiovXG4gICAgcmV0dXJuIEJTX0ZJTklTSF9ET05FO1xuICB9XG4gIGlmIChzLmxhc3RfbGl0KSB7XG4gICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgIH1cbiAgICAvKioqL1xuICB9XG4gIHJldHVybiBCU19CTE9DS19ET05FO1xufVxuXG4vKiBWYWx1ZXMgZm9yIG1heF9sYXp5X21hdGNoLCBnb29kX21hdGNoIGFuZCBtYXhfY2hhaW5fbGVuZ3RoLCBkZXBlbmRpbmcgb25cbiAqIHRoZSBkZXNpcmVkIHBhY2sgbGV2ZWwgKDAuLjkpLiBUaGUgdmFsdWVzIGdpdmVuIGJlbG93IGhhdmUgYmVlbiB0dW5lZCB0b1xuICogZXhjbHVkZSB3b3JzdCBjYXNlIHBlcmZvcm1hbmNlIGZvciBwYXRob2xvZ2ljYWwgZmlsZXMuIEJldHRlciB2YWx1ZXMgbWF5IGJlXG4gKiBmb3VuZCBmb3Igc3BlY2lmaWMgZmlsZXMuXG4gKi9cbnZhciBDb25maWcgPSBmdW5jdGlvbiAoZ29vZF9sZW5ndGgsIG1heF9sYXp5LCBuaWNlX2xlbmd0aCwgbWF4X2NoYWluLCBmdW5jKSB7XG4gIHRoaXMuZ29vZF9sZW5ndGggPSBnb29kX2xlbmd0aDtcbiAgdGhpcy5tYXhfbGF6eSA9IG1heF9sYXp5O1xuICB0aGlzLm5pY2VfbGVuZ3RoID0gbmljZV9sZW5ndGg7XG4gIHRoaXMubWF4X2NoYWluID0gbWF4X2NoYWluO1xuICB0aGlzLmZ1bmMgPSBmdW5jO1xufTtcblxudmFyIGNvbmZpZ3VyYXRpb25fdGFibGU7XG5cbmNvbmZpZ3VyYXRpb25fdGFibGUgPSBbXG4gIC8qICAgICAgZ29vZCBsYXp5IG5pY2UgY2hhaW4gKi9cbiAgbmV3IENvbmZpZygwLCAwLCAwLCAwLCBkZWZsYXRlX3N0b3JlZCksICAgICAgICAgIC8qIDAgc3RvcmUgb25seSAqL1xuICBuZXcgQ29uZmlnKDQsIDQsIDgsIDQsIGRlZmxhdGVfZmFzdCksICAgICAgICAgICAgLyogMSBtYXggc3BlZWQsIG5vIGxhenkgbWF0Y2hlcyAqL1xuICBuZXcgQ29uZmlnKDQsIDUsIDE2LCA4LCBkZWZsYXRlX2Zhc3QpLCAgICAgICAgICAgLyogMiAqL1xuICBuZXcgQ29uZmlnKDQsIDYsIDMyLCAzMiwgZGVmbGF0ZV9mYXN0KSwgICAgICAgICAgLyogMyAqL1xuXG4gIG5ldyBDb25maWcoNCwgNCwgMTYsIDE2LCBkZWZsYXRlX3Nsb3cpLCAgICAgICAgICAvKiA0IGxhenkgbWF0Y2hlcyAqL1xuICBuZXcgQ29uZmlnKDgsIDE2LCAzMiwgMzIsIGRlZmxhdGVfc2xvdyksICAgICAgICAgLyogNSAqL1xuICBuZXcgQ29uZmlnKDgsIDE2LCAxMjgsIDEyOCwgZGVmbGF0ZV9zbG93KSwgICAgICAgLyogNiAqL1xuICBuZXcgQ29uZmlnKDgsIDMyLCAxMjgsIDI1NiwgZGVmbGF0ZV9zbG93KSwgICAgICAgLyogNyAqL1xuICBuZXcgQ29uZmlnKDMyLCAxMjgsIDI1OCwgMTAyNCwgZGVmbGF0ZV9zbG93KSwgICAgLyogOCAqL1xuICBuZXcgQ29uZmlnKDMyLCAyNTgsIDI1OCwgNDA5NiwgZGVmbGF0ZV9zbG93KSAgICAgLyogOSBtYXggY29tcHJlc3Npb24gKi9cbl07XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBJbml0aWFsaXplIHRoZSBcImxvbmdlc3QgbWF0Y2hcIiByb3V0aW5lcyBmb3IgYSBuZXcgemxpYiBzdHJlYW1cbiAqL1xuZnVuY3Rpb24gbG1faW5pdChzKSB7XG4gIHMud2luZG93X3NpemUgPSAyICogcy53X3NpemU7XG5cbiAgLyoqKiBDTEVBUl9IQVNIKHMpOyAqKiovXG4gIHplcm8ocy5oZWFkKTsgLy8gRmlsbCB3aXRoIE5JTCAoPSAwKTtcblxuICAvKiBTZXQgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJzOlxuICAgKi9cbiAgcy5tYXhfbGF6eV9tYXRjaCA9IGNvbmZpZ3VyYXRpb25fdGFibGVbcy5sZXZlbF0ubWF4X2xhenk7XG4gIHMuZ29vZF9tYXRjaCA9IGNvbmZpZ3VyYXRpb25fdGFibGVbcy5sZXZlbF0uZ29vZF9sZW5ndGg7XG4gIHMubmljZV9tYXRjaCA9IGNvbmZpZ3VyYXRpb25fdGFibGVbcy5sZXZlbF0ubmljZV9sZW5ndGg7XG4gIHMubWF4X2NoYWluX2xlbmd0aCA9IGNvbmZpZ3VyYXRpb25fdGFibGVbcy5sZXZlbF0ubWF4X2NoYWluO1xuXG4gIHMuc3Ryc3RhcnQgPSAwO1xuICBzLmJsb2NrX3N0YXJ0ID0gMDtcbiAgcy5sb29rYWhlYWQgPSAwO1xuICBzLmluc2VydCA9IDA7XG4gIHMubWF0Y2hfbGVuZ3RoID0gcy5wcmV2X2xlbmd0aCA9IE1JTl9NQVRDSCAtIDE7XG4gIHMubWF0Y2hfYXZhaWxhYmxlID0gMDtcbiAgcy5pbnNfaCA9IDA7XG59XG5cblxuZnVuY3Rpb24gRGVmbGF0ZVN0YXRlKCkge1xuICB0aGlzLnN0cm0gPSBudWxsOyAgICAgICAgICAgIC8qIHBvaW50ZXIgYmFjayB0byB0aGlzIHpsaWIgc3RyZWFtICovXG4gIHRoaXMuc3RhdHVzID0gMDsgICAgICAgICAgICAvKiBhcyB0aGUgbmFtZSBpbXBsaWVzICovXG4gIHRoaXMucGVuZGluZ19idWYgPSBudWxsOyAgICAgIC8qIG91dHB1dCBzdGlsbCBwZW5kaW5nICovXG4gIHRoaXMucGVuZGluZ19idWZfc2l6ZSA9IDA7ICAvKiBzaXplIG9mIHBlbmRpbmdfYnVmICovXG4gIHRoaXMucGVuZGluZ19vdXQgPSAwOyAgICAgICAvKiBuZXh0IHBlbmRpbmcgYnl0ZSB0byBvdXRwdXQgdG8gdGhlIHN0cmVhbSAqL1xuICB0aGlzLnBlbmRpbmcgPSAwOyAgICAgICAgICAgLyogbmIgb2YgYnl0ZXMgaW4gdGhlIHBlbmRpbmcgYnVmZmVyICovXG4gIHRoaXMud3JhcCA9IDA7ICAgICAgICAgICAgICAvKiBiaXQgMCB0cnVlIGZvciB6bGliLCBiaXQgMSB0cnVlIGZvciBnemlwICovXG4gIHRoaXMuZ3poZWFkID0gbnVsbDsgICAgICAgICAvKiBnemlwIGhlYWRlciBpbmZvcm1hdGlvbiB0byB3cml0ZSAqL1xuICB0aGlzLmd6aW5kZXggPSAwOyAgICAgICAgICAgLyogd2hlcmUgaW4gZXh0cmEsIG5hbWUsIG9yIGNvbW1lbnQgKi9cbiAgdGhpcy5tZXRob2QgPSBaX0RFRkxBVEVEOyAvKiBjYW4gb25seSBiZSBERUZMQVRFRCAqL1xuICB0aGlzLmxhc3RfZmx1c2ggPSAtMTsgICAvKiB2YWx1ZSBvZiBmbHVzaCBwYXJhbSBmb3IgcHJldmlvdXMgZGVmbGF0ZSBjYWxsICovXG5cbiAgdGhpcy53X3NpemUgPSAwOyAgLyogTFo3NyB3aW5kb3cgc2l6ZSAoMzJLIGJ5IGRlZmF1bHQpICovXG4gIHRoaXMud19iaXRzID0gMDsgIC8qIGxvZzIod19zaXplKSAgKDguLjE2KSAqL1xuICB0aGlzLndfbWFzayA9IDA7ICAvKiB3X3NpemUgLSAxICovXG5cbiAgdGhpcy53aW5kb3cgPSBudWxsO1xuICAvKiBTbGlkaW5nIHdpbmRvdy4gSW5wdXQgYnl0ZXMgYXJlIHJlYWQgaW50byB0aGUgc2Vjb25kIGhhbGYgb2YgdGhlIHdpbmRvdyxcbiAgICogYW5kIG1vdmUgdG8gdGhlIGZpcnN0IGhhbGYgbGF0ZXIgdG8ga2VlcCBhIGRpY3Rpb25hcnkgb2YgYXQgbGVhc3Qgd1NpemVcbiAgICogYnl0ZXMuIFdpdGggdGhpcyBvcmdhbml6YXRpb24sIG1hdGNoZXMgYXJlIGxpbWl0ZWQgdG8gYSBkaXN0YW5jZSBvZlxuICAgKiB3U2l6ZS1NQVhfTUFUQ0ggYnl0ZXMsIGJ1dCB0aGlzIGVuc3VyZXMgdGhhdCBJTyBpcyBhbHdheXNcbiAgICogcGVyZm9ybWVkIHdpdGggYSBsZW5ndGggbXVsdGlwbGUgb2YgdGhlIGJsb2NrIHNpemUuXG4gICAqL1xuXG4gIHRoaXMud2luZG93X3NpemUgPSAwO1xuICAvKiBBY3R1YWwgc2l6ZSBvZiB3aW5kb3c6IDIqd1NpemUsIGV4Y2VwdCB3aGVuIHRoZSB1c2VyIGlucHV0IGJ1ZmZlclxuICAgKiBpcyBkaXJlY3RseSB1c2VkIGFzIHNsaWRpbmcgd2luZG93LlxuICAgKi9cblxuICB0aGlzLnByZXYgPSBudWxsO1xuICAvKiBMaW5rIHRvIG9sZGVyIHN0cmluZyB3aXRoIHNhbWUgaGFzaCBpbmRleC4gVG8gbGltaXQgdGhlIHNpemUgb2YgdGhpc1xuICAgKiBhcnJheSB0byA2NEssIHRoaXMgbGluayBpcyBtYWludGFpbmVkIG9ubHkgZm9yIHRoZSBsYXN0IDMySyBzdHJpbmdzLlxuICAgKiBBbiBpbmRleCBpbiB0aGlzIGFycmF5IGlzIHRodXMgYSB3aW5kb3cgaW5kZXggbW9kdWxvIDMySy5cbiAgICovXG5cbiAgdGhpcy5oZWFkID0gbnVsbDsgICAvKiBIZWFkcyBvZiB0aGUgaGFzaCBjaGFpbnMgb3IgTklMLiAqL1xuXG4gIHRoaXMuaW5zX2ggPSAwOyAgICAgICAvKiBoYXNoIGluZGV4IG9mIHN0cmluZyB0byBiZSBpbnNlcnRlZCAqL1xuICB0aGlzLmhhc2hfc2l6ZSA9IDA7ICAgLyogbnVtYmVyIG9mIGVsZW1lbnRzIGluIGhhc2ggdGFibGUgKi9cbiAgdGhpcy5oYXNoX2JpdHMgPSAwOyAgIC8qIGxvZzIoaGFzaF9zaXplKSAqL1xuICB0aGlzLmhhc2hfbWFzayA9IDA7ICAgLyogaGFzaF9zaXplLTEgKi9cblxuICB0aGlzLmhhc2hfc2hpZnQgPSAwO1xuICAvKiBOdW1iZXIgb2YgYml0cyBieSB3aGljaCBpbnNfaCBtdXN0IGJlIHNoaWZ0ZWQgYXQgZWFjaCBpbnB1dFxuICAgKiBzdGVwLiBJdCBtdXN0IGJlIHN1Y2ggdGhhdCBhZnRlciBNSU5fTUFUQ0ggc3RlcHMsIHRoZSBvbGRlc3RcbiAgICogYnl0ZSBubyBsb25nZXIgdGFrZXMgcGFydCBpbiB0aGUgaGFzaCBrZXksIHRoYXQgaXM6XG4gICAqICAgaGFzaF9zaGlmdCAqIE1JTl9NQVRDSCA+PSBoYXNoX2JpdHNcbiAgICovXG5cbiAgdGhpcy5ibG9ja19zdGFydCA9IDA7XG4gIC8qIFdpbmRvdyBwb3NpdGlvbiBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBjdXJyZW50IG91dHB1dCBibG9jay4gR2V0c1xuICAgKiBuZWdhdGl2ZSB3aGVuIHRoZSB3aW5kb3cgaXMgbW92ZWQgYmFja3dhcmRzLlxuICAgKi9cblxuICB0aGlzLm1hdGNoX2xlbmd0aCA9IDA7ICAgICAgLyogbGVuZ3RoIG9mIGJlc3QgbWF0Y2ggKi9cbiAgdGhpcy5wcmV2X21hdGNoID0gMDsgICAgICAgIC8qIHByZXZpb3VzIG1hdGNoICovXG4gIHRoaXMubWF0Y2hfYXZhaWxhYmxlID0gMDsgICAvKiBzZXQgaWYgcHJldmlvdXMgbWF0Y2ggZXhpc3RzICovXG4gIHRoaXMuc3Ryc3RhcnQgPSAwOyAgICAgICAgICAvKiBzdGFydCBvZiBzdHJpbmcgdG8gaW5zZXJ0ICovXG4gIHRoaXMubWF0Y2hfc3RhcnQgPSAwOyAgICAgICAvKiBzdGFydCBvZiBtYXRjaGluZyBzdHJpbmcgKi9cbiAgdGhpcy5sb29rYWhlYWQgPSAwOyAgICAgICAgIC8qIG51bWJlciBvZiB2YWxpZCBieXRlcyBhaGVhZCBpbiB3aW5kb3cgKi9cblxuICB0aGlzLnByZXZfbGVuZ3RoID0gMDtcbiAgLyogTGVuZ3RoIG9mIHRoZSBiZXN0IG1hdGNoIGF0IHByZXZpb3VzIHN0ZXAuIE1hdGNoZXMgbm90IGdyZWF0ZXIgdGhhbiB0aGlzXG4gICAqIGFyZSBkaXNjYXJkZWQuIFRoaXMgaXMgdXNlZCBpbiB0aGUgbGF6eSBtYXRjaCBldmFsdWF0aW9uLlxuICAgKi9cblxuICB0aGlzLm1heF9jaGFpbl9sZW5ndGggPSAwO1xuICAvKiBUbyBzcGVlZCB1cCBkZWZsYXRpb24sIGhhc2ggY2hhaW5zIGFyZSBuZXZlciBzZWFyY2hlZCBiZXlvbmQgdGhpc1xuICAgKiBsZW5ndGguICBBIGhpZ2hlciBsaW1pdCBpbXByb3ZlcyBjb21wcmVzc2lvbiByYXRpbyBidXQgZGVncmFkZXMgdGhlXG4gICAqIHNwZWVkLlxuICAgKi9cblxuICB0aGlzLm1heF9sYXp5X21hdGNoID0gMDtcbiAgLyogQXR0ZW1wdCB0byBmaW5kIGEgYmV0dGVyIG1hdGNoIG9ubHkgd2hlbiB0aGUgY3VycmVudCBtYXRjaCBpcyBzdHJpY3RseVxuICAgKiBzbWFsbGVyIHRoYW4gdGhpcyB2YWx1ZS4gVGhpcyBtZWNoYW5pc20gaXMgdXNlZCBvbmx5IGZvciBjb21wcmVzc2lvblxuICAgKiBsZXZlbHMgPj0gNC5cbiAgICovXG4gIC8vIFRoYXQncyBhbGlhcyB0byBtYXhfbGF6eV9tYXRjaCwgZG9uJ3QgdXNlIGRpcmVjdGx5XG4gIC8vdGhpcy5tYXhfaW5zZXJ0X2xlbmd0aCA9IDA7XG4gIC8qIEluc2VydCBuZXcgc3RyaW5ncyBpbiB0aGUgaGFzaCB0YWJsZSBvbmx5IGlmIHRoZSBtYXRjaCBsZW5ndGggaXMgbm90XG4gICAqIGdyZWF0ZXIgdGhhbiB0aGlzIGxlbmd0aC4gVGhpcyBzYXZlcyB0aW1lIGJ1dCBkZWdyYWRlcyBjb21wcmVzc2lvbi5cbiAgICogbWF4X2luc2VydF9sZW5ndGggaXMgdXNlZCBvbmx5IGZvciBjb21wcmVzc2lvbiBsZXZlbHMgPD0gMy5cbiAgICovXG5cbiAgdGhpcy5sZXZlbCA9IDA7ICAgICAvKiBjb21wcmVzc2lvbiBsZXZlbCAoMS4uOSkgKi9cbiAgdGhpcy5zdHJhdGVneSA9IDA7ICAvKiBmYXZvciBvciBmb3JjZSBIdWZmbWFuIGNvZGluZyovXG5cbiAgdGhpcy5nb29kX21hdGNoID0gMDtcbiAgLyogVXNlIGEgZmFzdGVyIHNlYXJjaCB3aGVuIHRoZSBwcmV2aW91cyBtYXRjaCBpcyBsb25nZXIgdGhhbiB0aGlzICovXG5cbiAgdGhpcy5uaWNlX21hdGNoID0gMDsgLyogU3RvcCBzZWFyY2hpbmcgd2hlbiBjdXJyZW50IG1hdGNoIGV4Y2VlZHMgdGhpcyAqL1xuXG4gICAgICAgICAgICAgIC8qIHVzZWQgYnkgdHJlZXMuYzogKi9cblxuICAvKiBEaWRuJ3QgdXNlIGN0X2RhdGEgdHlwZWRlZiBiZWxvdyB0byBzdXBwcmVzcyBjb21waWxlciB3YXJuaW5nICovXG5cbiAgLy8gc3RydWN0IGN0X2RhdGFfcyBkeW5fbHRyZWVbSEVBUF9TSVpFXTsgICAvKiBsaXRlcmFsIGFuZCBsZW5ndGggdHJlZSAqL1xuICAvLyBzdHJ1Y3QgY3RfZGF0YV9zIGR5bl9kdHJlZVsyKkRfQ09ERVMrMV07IC8qIGRpc3RhbmNlIHRyZWUgKi9cbiAgLy8gc3RydWN0IGN0X2RhdGFfcyBibF90cmVlWzIqQkxfQ09ERVMrMV07ICAvKiBIdWZmbWFuIHRyZWUgZm9yIGJpdCBsZW5ndGhzICovXG5cbiAgLy8gVXNlIGZsYXQgYXJyYXkgb2YgRE9VQkxFIHNpemUsIHdpdGggaW50ZXJsZWF2ZWQgZmF0YSxcbiAgLy8gYmVjYXVzZSBKUyBkb2VzIG5vdCBzdXBwb3J0IGVmZmVjdGl2ZVxuICB0aGlzLmR5bl9sdHJlZSAgPSBuZXcgdXRpbHMuQnVmMTYoSEVBUF9TSVpFICogMik7XG4gIHRoaXMuZHluX2R0cmVlICA9IG5ldyB1dGlscy5CdWYxNigoMipEX0NPREVTKzEpICogMik7XG4gIHRoaXMuYmxfdHJlZSAgICA9IG5ldyB1dGlscy5CdWYxNigoMipCTF9DT0RFUysxKSAqIDIpO1xuICB6ZXJvKHRoaXMuZHluX2x0cmVlKTtcbiAgemVybyh0aGlzLmR5bl9kdHJlZSk7XG4gIHplcm8odGhpcy5ibF90cmVlKTtcblxuICB0aGlzLmxfZGVzYyAgID0gbnVsbDsgICAgICAgICAvKiBkZXNjLiBmb3IgbGl0ZXJhbCB0cmVlICovXG4gIHRoaXMuZF9kZXNjICAgPSBudWxsOyAgICAgICAgIC8qIGRlc2MuIGZvciBkaXN0YW5jZSB0cmVlICovXG4gIHRoaXMuYmxfZGVzYyAgPSBudWxsOyAgICAgICAgIC8qIGRlc2MuIGZvciBiaXQgbGVuZ3RoIHRyZWUgKi9cblxuICAvL3VzaCBibF9jb3VudFtNQVhfQklUUysxXTtcbiAgdGhpcy5ibF9jb3VudCA9IG5ldyB1dGlscy5CdWYxNihNQVhfQklUUysxKTtcbiAgLyogbnVtYmVyIG9mIGNvZGVzIGF0IGVhY2ggYml0IGxlbmd0aCBmb3IgYW4gb3B0aW1hbCB0cmVlICovXG5cbiAgLy9pbnQgaGVhcFsyKkxfQ09ERVMrMV07ICAgICAgLyogaGVhcCB1c2VkIHRvIGJ1aWxkIHRoZSBIdWZmbWFuIHRyZWVzICovXG4gIHRoaXMuaGVhcCA9IG5ldyB1dGlscy5CdWYxNigyKkxfQ09ERVMrMSk7ICAvKiBoZWFwIHVzZWQgdG8gYnVpbGQgdGhlIEh1ZmZtYW4gdHJlZXMgKi9cbiAgemVybyh0aGlzLmhlYXApO1xuXG4gIHRoaXMuaGVhcF9sZW4gPSAwOyAgICAgICAgICAgICAgIC8qIG51bWJlciBvZiBlbGVtZW50cyBpbiB0aGUgaGVhcCAqL1xuICB0aGlzLmhlYXBfbWF4ID0gMDsgICAgICAgICAgICAgICAvKiBlbGVtZW50IG9mIGxhcmdlc3QgZnJlcXVlbmN5ICovXG4gIC8qIFRoZSBzb25zIG9mIGhlYXBbbl0gYXJlIGhlYXBbMipuXSBhbmQgaGVhcFsyKm4rMV0uIGhlYXBbMF0gaXMgbm90IHVzZWQuXG4gICAqIFRoZSBzYW1lIGhlYXAgYXJyYXkgaXMgdXNlZCB0byBidWlsZCBhbGwgdHJlZXMuXG4gICAqL1xuXG4gIHRoaXMuZGVwdGggPSBuZXcgdXRpbHMuQnVmMTYoMipMX0NPREVTKzEpOyAvL3VjaCBkZXB0aFsyKkxfQ09ERVMrMV07XG4gIHplcm8odGhpcy5kZXB0aCk7XG4gIC8qIERlcHRoIG9mIGVhY2ggc3VidHJlZSB1c2VkIGFzIHRpZSBicmVha2VyIGZvciB0cmVlcyBvZiBlcXVhbCBmcmVxdWVuY3lcbiAgICovXG5cbiAgdGhpcy5sX2J1ZiA9IDA7ICAgICAgICAgIC8qIGJ1ZmZlciBpbmRleCBmb3IgbGl0ZXJhbHMgb3IgbGVuZ3RocyAqL1xuXG4gIHRoaXMubGl0X2J1ZnNpemUgPSAwO1xuICAvKiBTaXplIG9mIG1hdGNoIGJ1ZmZlciBmb3IgbGl0ZXJhbHMvbGVuZ3Rocy4gIFRoZXJlIGFyZSA0IHJlYXNvbnMgZm9yXG4gICAqIGxpbWl0aW5nIGxpdF9idWZzaXplIHRvIDY0SzpcbiAgICogICAtIGZyZXF1ZW5jaWVzIGNhbiBiZSBrZXB0IGluIDE2IGJpdCBjb3VudGVyc1xuICAgKiAgIC0gaWYgY29tcHJlc3Npb24gaXMgbm90IHN1Y2Nlc3NmdWwgZm9yIHRoZSBmaXJzdCBibG9jaywgYWxsIGlucHV0XG4gICAqICAgICBkYXRhIGlzIHN0aWxsIGluIHRoZSB3aW5kb3cgc28gd2UgY2FuIHN0aWxsIGVtaXQgYSBzdG9yZWQgYmxvY2sgZXZlblxuICAgKiAgICAgd2hlbiBpbnB1dCBjb21lcyBmcm9tIHN0YW5kYXJkIGlucHV0LiAgKFRoaXMgY2FuIGFsc28gYmUgZG9uZSBmb3JcbiAgICogICAgIGFsbCBibG9ja3MgaWYgbGl0X2J1ZnNpemUgaXMgbm90IGdyZWF0ZXIgdGhhbiAzMksuKVxuICAgKiAgIC0gaWYgY29tcHJlc3Npb24gaXMgbm90IHN1Y2Nlc3NmdWwgZm9yIGEgZmlsZSBzbWFsbGVyIHRoYW4gNjRLLCB3ZSBjYW5cbiAgICogICAgIGV2ZW4gZW1pdCBhIHN0b3JlZCBmaWxlIGluc3RlYWQgb2YgYSBzdG9yZWQgYmxvY2sgKHNhdmluZyA1IGJ5dGVzKS5cbiAgICogICAgIFRoaXMgaXMgYXBwbGljYWJsZSBvbmx5IGZvciB6aXAgKG5vdCBnemlwIG9yIHpsaWIpLlxuICAgKiAgIC0gY3JlYXRpbmcgbmV3IEh1ZmZtYW4gdHJlZXMgbGVzcyBmcmVxdWVudGx5IG1heSBub3QgcHJvdmlkZSBmYXN0XG4gICAqICAgICBhZGFwdGF0aW9uIHRvIGNoYW5nZXMgaW4gdGhlIGlucHV0IGRhdGEgc3RhdGlzdGljcy4gKFRha2UgZm9yXG4gICAqICAgICBleGFtcGxlIGEgYmluYXJ5IGZpbGUgd2l0aCBwb29ybHkgY29tcHJlc3NpYmxlIGNvZGUgZm9sbG93ZWQgYnlcbiAgICogICAgIGEgaGlnaGx5IGNvbXByZXNzaWJsZSBzdHJpbmcgdGFibGUuKSBTbWFsbGVyIGJ1ZmZlciBzaXplcyBnaXZlXG4gICAqICAgICBmYXN0IGFkYXB0YXRpb24gYnV0IGhhdmUgb2YgY291cnNlIHRoZSBvdmVyaGVhZCBvZiB0cmFuc21pdHRpbmdcbiAgICogICAgIHRyZWVzIG1vcmUgZnJlcXVlbnRseS5cbiAgICogICAtIEkgY2FuJ3QgY291bnQgYWJvdmUgNFxuICAgKi9cblxuICB0aGlzLmxhc3RfbGl0ID0gMDsgICAgICAvKiBydW5uaW5nIGluZGV4IGluIGxfYnVmICovXG5cbiAgdGhpcy5kX2J1ZiA9IDA7XG4gIC8qIEJ1ZmZlciBpbmRleCBmb3IgZGlzdGFuY2VzLiBUbyBzaW1wbGlmeSB0aGUgY29kZSwgZF9idWYgYW5kIGxfYnVmIGhhdmVcbiAgICogdGhlIHNhbWUgbnVtYmVyIG9mIGVsZW1lbnRzLiBUbyB1c2UgZGlmZmVyZW50IGxlbmd0aHMsIGFuIGV4dHJhIGZsYWdcbiAgICogYXJyYXkgd291bGQgYmUgbmVjZXNzYXJ5LlxuICAgKi9cblxuICB0aGlzLm9wdF9sZW4gPSAwOyAgICAgICAvKiBiaXQgbGVuZ3RoIG9mIGN1cnJlbnQgYmxvY2sgd2l0aCBvcHRpbWFsIHRyZWVzICovXG4gIHRoaXMuc3RhdGljX2xlbiA9IDA7ICAgIC8qIGJpdCBsZW5ndGggb2YgY3VycmVudCBibG9jayB3aXRoIHN0YXRpYyB0cmVlcyAqL1xuICB0aGlzLm1hdGNoZXMgPSAwOyAgICAgICAvKiBudW1iZXIgb2Ygc3RyaW5nIG1hdGNoZXMgaW4gY3VycmVudCBibG9jayAqL1xuICB0aGlzLmluc2VydCA9IDA7ICAgICAgICAvKiBieXRlcyBhdCBlbmQgb2Ygd2luZG93IGxlZnQgdG8gaW5zZXJ0ICovXG5cblxuICB0aGlzLmJpX2J1ZiA9IDA7XG4gIC8qIE91dHB1dCBidWZmZXIuIGJpdHMgYXJlIGluc2VydGVkIHN0YXJ0aW5nIGF0IHRoZSBib3R0b20gKGxlYXN0XG4gICAqIHNpZ25pZmljYW50IGJpdHMpLlxuICAgKi9cbiAgdGhpcy5iaV92YWxpZCA9IDA7XG4gIC8qIE51bWJlciBvZiB2YWxpZCBiaXRzIGluIGJpX2J1Zi4gIEFsbCBiaXRzIGFib3ZlIHRoZSBsYXN0IHZhbGlkIGJpdFxuICAgKiBhcmUgYWx3YXlzIHplcm8uXG4gICAqL1xuXG4gIC8vIFVzZWQgZm9yIHdpbmRvdyBtZW1vcnkgaW5pdC4gV2Ugc2FmZWx5IGlnbm9yZSBpdCBmb3IgSlMuIFRoYXQgbWFrZXNcbiAgLy8gc2Vuc2Ugb25seSBmb3IgcG9pbnRlcnMgYW5kIG1lbW9yeSBjaGVjayB0b29scy5cbiAgLy90aGlzLmhpZ2hfd2F0ZXIgPSAwO1xuICAvKiBIaWdoIHdhdGVyIG1hcmsgb2Zmc2V0IGluIHdpbmRvdyBmb3IgaW5pdGlhbGl6ZWQgYnl0ZXMgLS0gYnl0ZXMgYWJvdmVcbiAgICogdGhpcyBhcmUgc2V0IHRvIHplcm8gaW4gb3JkZXIgdG8gYXZvaWQgbWVtb3J5IGNoZWNrIHdhcm5pbmdzIHdoZW5cbiAgICogbG9uZ2VzdCBtYXRjaCByb3V0aW5lcyBhY2Nlc3MgYnl0ZXMgcGFzdCB0aGUgaW5wdXQuICBUaGlzIGlzIHRoZW5cbiAgICogdXBkYXRlZCB0byB0aGUgbmV3IGhpZ2ggd2F0ZXIgbWFyay5cbiAgICovXG59XG5cblxuZnVuY3Rpb24gZGVmbGF0ZVJlc2V0S2VlcChzdHJtKSB7XG4gIHZhciBzO1xuXG4gIGlmICghc3RybSB8fCAhc3RybS5zdGF0ZSkge1xuICAgIHJldHVybiBlcnIoc3RybSwgWl9TVFJFQU1fRVJST1IpO1xuICB9XG5cbiAgc3RybS50b3RhbF9pbiA9IHN0cm0udG90YWxfb3V0ID0gMDtcbiAgc3RybS5kYXRhX3R5cGUgPSBaX1VOS05PV047XG5cbiAgcyA9IHN0cm0uc3RhdGU7XG4gIHMucGVuZGluZyA9IDA7XG4gIHMucGVuZGluZ19vdXQgPSAwO1xuXG4gIGlmIChzLndyYXAgPCAwKSB7XG4gICAgcy53cmFwID0gLXMud3JhcDtcbiAgICAvKiB3YXMgbWFkZSBuZWdhdGl2ZSBieSBkZWZsYXRlKC4uLiwgWl9GSU5JU0gpOyAqL1xuICB9XG4gIHMuc3RhdHVzID0gKHMud3JhcCA/IElOSVRfU1RBVEUgOiBCVVNZX1NUQVRFKTtcbiAgc3RybS5hZGxlciA9IChzLndyYXAgPT09IDIpID9cbiAgICAwICAvLyBjcmMzMigwLCBaX05VTEwsIDApXG4gIDpcbiAgICAxOyAvLyBhZGxlcjMyKDAsIFpfTlVMTCwgMClcbiAgcy5sYXN0X2ZsdXNoID0gWl9OT19GTFVTSDtcbiAgdHJlZXMuX3RyX2luaXQocyk7XG4gIHJldHVybiBaX09LO1xufVxuXG5cbmZ1bmN0aW9uIGRlZmxhdGVSZXNldChzdHJtKSB7XG4gIHZhciByZXQgPSBkZWZsYXRlUmVzZXRLZWVwKHN0cm0pO1xuICBpZiAocmV0ID09PSBaX09LKSB7XG4gICAgbG1faW5pdChzdHJtLnN0YXRlKTtcbiAgfVxuICByZXR1cm4gcmV0O1xufVxuXG5cbmZ1bmN0aW9uIGRlZmxhdGVTZXRIZWFkZXIoc3RybSwgaGVhZCkge1xuICBpZiAoIXN0cm0gfHwgIXN0cm0uc3RhdGUpIHsgcmV0dXJuIFpfU1RSRUFNX0VSUk9SOyB9XG4gIGlmIChzdHJtLnN0YXRlLndyYXAgIT09IDIpIHsgcmV0dXJuIFpfU1RSRUFNX0VSUk9SOyB9XG4gIHN0cm0uc3RhdGUuZ3poZWFkID0gaGVhZDtcbiAgcmV0dXJuIFpfT0s7XG59XG5cblxuZnVuY3Rpb24gZGVmbGF0ZUluaXQyKHN0cm0sIGxldmVsLCBtZXRob2QsIHdpbmRvd0JpdHMsIG1lbUxldmVsLCBzdHJhdGVneSkge1xuICBpZiAoIXN0cm0pIHsgLy8gPT09IFpfTlVMTFxuICAgIHJldHVybiBaX1NUUkVBTV9FUlJPUjtcbiAgfVxuICB2YXIgd3JhcCA9IDE7XG5cbiAgaWYgKGxldmVsID09PSBaX0RFRkFVTFRfQ09NUFJFU1NJT04pIHtcbiAgICBsZXZlbCA9IDY7XG4gIH1cblxuICBpZiAod2luZG93Qml0cyA8IDApIHsgLyogc3VwcHJlc3MgemxpYiB3cmFwcGVyICovXG4gICAgd3JhcCA9IDA7XG4gICAgd2luZG93Qml0cyA9IC13aW5kb3dCaXRzO1xuICB9XG5cbiAgZWxzZSBpZiAod2luZG93Qml0cyA+IDE1KSB7XG4gICAgd3JhcCA9IDI7ICAgICAgICAgICAvKiB3cml0ZSBnemlwIHdyYXBwZXIgaW5zdGVhZCAqL1xuICAgIHdpbmRvd0JpdHMgLT0gMTY7XG4gIH1cblxuXG4gIGlmIChtZW1MZXZlbCA8IDEgfHwgbWVtTGV2ZWwgPiBNQVhfTUVNX0xFVkVMIHx8IG1ldGhvZCAhPT0gWl9ERUZMQVRFRCB8fFxuICAgIHdpbmRvd0JpdHMgPCA4IHx8IHdpbmRvd0JpdHMgPiAxNSB8fCBsZXZlbCA8IDAgfHwgbGV2ZWwgPiA5IHx8XG4gICAgc3RyYXRlZ3kgPCAwIHx8IHN0cmF0ZWd5ID4gWl9GSVhFRCkge1xuICAgIHJldHVybiBlcnIoc3RybSwgWl9TVFJFQU1fRVJST1IpO1xuICB9XG5cblxuICBpZiAod2luZG93Qml0cyA9PT0gOCkge1xuICAgIHdpbmRvd0JpdHMgPSA5O1xuICB9XG4gIC8qIHVudGlsIDI1Ni1ieXRlIHdpbmRvdyBidWcgZml4ZWQgKi9cblxuICB2YXIgcyA9IG5ldyBEZWZsYXRlU3RhdGUoKTtcblxuICBzdHJtLnN0YXRlID0gcztcbiAgcy5zdHJtID0gc3RybTtcblxuICBzLndyYXAgPSB3cmFwO1xuICBzLmd6aGVhZCA9IG51bGw7XG4gIHMud19iaXRzID0gd2luZG93Qml0cztcbiAgcy53X3NpemUgPSAxIDw8IHMud19iaXRzO1xuICBzLndfbWFzayA9IHMud19zaXplIC0gMTtcblxuICBzLmhhc2hfYml0cyA9IG1lbUxldmVsICsgNztcbiAgcy5oYXNoX3NpemUgPSAxIDw8IHMuaGFzaF9iaXRzO1xuICBzLmhhc2hfbWFzayA9IHMuaGFzaF9zaXplIC0gMTtcbiAgcy5oYXNoX3NoaWZ0ID0gfn4oKHMuaGFzaF9iaXRzICsgTUlOX01BVENIIC0gMSkgLyBNSU5fTUFUQ0gpO1xuXG4gIHMud2luZG93ID0gbmV3IHV0aWxzLkJ1Zjgocy53X3NpemUgKiAyKTtcbiAgcy5oZWFkID0gbmV3IHV0aWxzLkJ1ZjE2KHMuaGFzaF9zaXplKTtcbiAgcy5wcmV2ID0gbmV3IHV0aWxzLkJ1ZjE2KHMud19zaXplKTtcblxuICAvLyBEb24ndCBuZWVkIG1lbSBpbml0IG1hZ2ljIGZvciBKUy5cbiAgLy9zLmhpZ2hfd2F0ZXIgPSAwOyAgLyogbm90aGluZyB3cml0dGVuIHRvIHMtPndpbmRvdyB5ZXQgKi9cblxuICBzLmxpdF9idWZzaXplID0gMSA8PCAobWVtTGV2ZWwgKyA2KTsgLyogMTZLIGVsZW1lbnRzIGJ5IGRlZmF1bHQgKi9cblxuICBzLnBlbmRpbmdfYnVmX3NpemUgPSBzLmxpdF9idWZzaXplICogNDtcbiAgcy5wZW5kaW5nX2J1ZiA9IG5ldyB1dGlscy5CdWY4KHMucGVuZGluZ19idWZfc2l6ZSk7XG5cbiAgcy5kX2J1ZiA9IHMubGl0X2J1ZnNpemUgPj4gMTtcbiAgcy5sX2J1ZiA9ICgxICsgMikgKiBzLmxpdF9idWZzaXplO1xuXG4gIHMubGV2ZWwgPSBsZXZlbDtcbiAgcy5zdHJhdGVneSA9IHN0cmF0ZWd5O1xuICBzLm1ldGhvZCA9IG1ldGhvZDtcblxuICByZXR1cm4gZGVmbGF0ZVJlc2V0KHN0cm0pO1xufVxuXG5mdW5jdGlvbiBkZWZsYXRlSW5pdChzdHJtLCBsZXZlbCkge1xuICByZXR1cm4gZGVmbGF0ZUluaXQyKHN0cm0sIGxldmVsLCBaX0RFRkxBVEVELCBNQVhfV0JJVFMsIERFRl9NRU1fTEVWRUwsIFpfREVGQVVMVF9TVFJBVEVHWSk7XG59XG5cblxuZnVuY3Rpb24gZGVmbGF0ZShzdHJtLCBmbHVzaCkge1xuICB2YXIgb2xkX2ZsdXNoLCBzO1xuICB2YXIgYmVnLCB2YWw7IC8vIGZvciBnemlwIGhlYWRlciB3cml0ZSBvbmx5XG5cbiAgaWYgKCFzdHJtIHx8ICFzdHJtLnN0YXRlIHx8XG4gICAgZmx1c2ggPiBaX0JMT0NLIHx8IGZsdXNoIDwgMCkge1xuICAgIHJldHVybiBzdHJtID8gZXJyKHN0cm0sIFpfU1RSRUFNX0VSUk9SKSA6IFpfU1RSRUFNX0VSUk9SO1xuICB9XG5cbiAgcyA9IHN0cm0uc3RhdGU7XG5cbiAgaWYgKCFzdHJtLm91dHB1dCB8fFxuICAgICAgKCFzdHJtLmlucHV0ICYmIHN0cm0uYXZhaWxfaW4gIT09IDApIHx8XG4gICAgICAocy5zdGF0dXMgPT09IEZJTklTSF9TVEFURSAmJiBmbHVzaCAhPT0gWl9GSU5JU0gpKSB7XG4gICAgcmV0dXJuIGVycihzdHJtLCAoc3RybS5hdmFpbF9vdXQgPT09IDApID8gWl9CVUZfRVJST1IgOiBaX1NUUkVBTV9FUlJPUik7XG4gIH1cblxuICBzLnN0cm0gPSBzdHJtOyAvKiBqdXN0IGluIGNhc2UgKi9cbiAgb2xkX2ZsdXNoID0gcy5sYXN0X2ZsdXNoO1xuICBzLmxhc3RfZmx1c2ggPSBmbHVzaDtcblxuICAvKiBXcml0ZSB0aGUgaGVhZGVyICovXG4gIGlmIChzLnN0YXR1cyA9PT0gSU5JVF9TVEFURSkge1xuXG4gICAgaWYgKHMud3JhcCA9PT0gMikgeyAvLyBHWklQIGhlYWRlclxuICAgICAgc3RybS5hZGxlciA9IDA7ICAvL2NyYzMyKDBMLCBaX05VTEwsIDApO1xuICAgICAgcHV0X2J5dGUocywgMzEpO1xuICAgICAgcHV0X2J5dGUocywgMTM5KTtcbiAgICAgIHB1dF9ieXRlKHMsIDgpO1xuICAgICAgaWYgKCFzLmd6aGVhZCkgeyAvLyBzLT5nemhlYWQgPT0gWl9OVUxMXG4gICAgICAgIHB1dF9ieXRlKHMsIDApO1xuICAgICAgICBwdXRfYnl0ZShzLCAwKTtcbiAgICAgICAgcHV0X2J5dGUocywgMCk7XG4gICAgICAgIHB1dF9ieXRlKHMsIDApO1xuICAgICAgICBwdXRfYnl0ZShzLCAwKTtcbiAgICAgICAgcHV0X2J5dGUocywgcy5sZXZlbCA9PT0gOSA/IDIgOlxuICAgICAgICAgICAgICAgICAgICAocy5zdHJhdGVneSA+PSBaX0hVRkZNQU5fT05MWSB8fCBzLmxldmVsIDwgMiA/XG4gICAgICAgICAgICAgICAgICAgICA0IDogMCkpO1xuICAgICAgICBwdXRfYnl0ZShzLCBPU19DT0RFKTtcbiAgICAgICAgcy5zdGF0dXMgPSBCVVNZX1NUQVRFO1xuICAgICAgfVxuICAgICAgZWxzZSB7XG4gICAgICAgIHB1dF9ieXRlKHMsIChzLmd6aGVhZC50ZXh0ID8gMSA6IDApICtcbiAgICAgICAgICAgICAgICAgICAgKHMuZ3poZWFkLmhjcmMgPyAyIDogMCkgK1xuICAgICAgICAgICAgICAgICAgICAoIXMuZ3poZWFkLmV4dHJhID8gMCA6IDQpICtcbiAgICAgICAgICAgICAgICAgICAgKCFzLmd6aGVhZC5uYW1lID8gMCA6IDgpICtcbiAgICAgICAgICAgICAgICAgICAgKCFzLmd6aGVhZC5jb21tZW50ID8gMCA6IDE2KVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgIHB1dF9ieXRlKHMsIHMuZ3poZWFkLnRpbWUgJiAweGZmKTtcbiAgICAgICAgcHV0X2J5dGUocywgKHMuZ3poZWFkLnRpbWUgPj4gOCkgJiAweGZmKTtcbiAgICAgICAgcHV0X2J5dGUocywgKHMuZ3poZWFkLnRpbWUgPj4gMTYpICYgMHhmZik7XG4gICAgICAgIHB1dF9ieXRlKHMsIChzLmd6aGVhZC50aW1lID4+IDI0KSAmIDB4ZmYpO1xuICAgICAgICBwdXRfYnl0ZShzLCBzLmxldmVsID09PSA5ID8gMiA6XG4gICAgICAgICAgICAgICAgICAgIChzLnN0cmF0ZWd5ID49IFpfSFVGRk1BTl9PTkxZIHx8IHMubGV2ZWwgPCAyID9cbiAgICAgICAgICAgICAgICAgICAgIDQgOiAwKSk7XG4gICAgICAgIHB1dF9ieXRlKHMsIHMuZ3poZWFkLm9zICYgMHhmZik7XG4gICAgICAgIGlmIChzLmd6aGVhZC5leHRyYSAmJiBzLmd6aGVhZC5leHRyYS5sZW5ndGgpIHtcbiAgICAgICAgICBwdXRfYnl0ZShzLCBzLmd6aGVhZC5leHRyYS5sZW5ndGggJiAweGZmKTtcbiAgICAgICAgICBwdXRfYnl0ZShzLCAocy5nemhlYWQuZXh0cmEubGVuZ3RoID4+IDgpICYgMHhmZik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHMuZ3poZWFkLmhjcmMpIHtcbiAgICAgICAgICBzdHJtLmFkbGVyID0gY3JjMzIoc3RybS5hZGxlciwgcy5wZW5kaW5nX2J1Ziwgcy5wZW5kaW5nLCAwKTtcbiAgICAgICAgfVxuICAgICAgICBzLmd6aW5kZXggPSAwO1xuICAgICAgICBzLnN0YXR1cyA9IEVYVFJBX1NUQVRFO1xuICAgICAgfVxuICAgIH1cbiAgICBlbHNlIC8vIERFRkxBVEUgaGVhZGVyXG4gICAge1xuICAgICAgdmFyIGhlYWRlciA9IChaX0RFRkxBVEVEICsgKChzLndfYml0cyAtIDgpIDw8IDQpKSA8PCA4O1xuICAgICAgdmFyIGxldmVsX2ZsYWdzID0gLTE7XG5cbiAgICAgIGlmIChzLnN0cmF0ZWd5ID49IFpfSFVGRk1BTl9PTkxZIHx8IHMubGV2ZWwgPCAyKSB7XG4gICAgICAgIGxldmVsX2ZsYWdzID0gMDtcbiAgICAgIH0gZWxzZSBpZiAocy5sZXZlbCA8IDYpIHtcbiAgICAgICAgbGV2ZWxfZmxhZ3MgPSAxO1xuICAgICAgfSBlbHNlIGlmIChzLmxldmVsID09PSA2KSB7XG4gICAgICAgIGxldmVsX2ZsYWdzID0gMjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldmVsX2ZsYWdzID0gMztcbiAgICAgIH1cbiAgICAgIGhlYWRlciB8PSAobGV2ZWxfZmxhZ3MgPDwgNik7XG4gICAgICBpZiAocy5zdHJzdGFydCAhPT0gMCkgeyBoZWFkZXIgfD0gUFJFU0VUX0RJQ1Q7IH1cbiAgICAgIGhlYWRlciArPSAzMSAtIChoZWFkZXIgJSAzMSk7XG5cbiAgICAgIHMuc3RhdHVzID0gQlVTWV9TVEFURTtcbiAgICAgIHB1dFNob3J0TVNCKHMsIGhlYWRlcik7XG5cbiAgICAgIC8qIFNhdmUgdGhlIGFkbGVyMzIgb2YgdGhlIHByZXNldCBkaWN0aW9uYXJ5OiAqL1xuICAgICAgaWYgKHMuc3Ryc3RhcnQgIT09IDApIHtcbiAgICAgICAgcHV0U2hvcnRNU0Iocywgc3RybS5hZGxlciA+Pj4gMTYpO1xuICAgICAgICBwdXRTaG9ydE1TQihzLCBzdHJtLmFkbGVyICYgMHhmZmZmKTtcbiAgICAgIH1cbiAgICAgIHN0cm0uYWRsZXIgPSAxOyAvLyBhZGxlcjMyKDBMLCBaX05VTEwsIDApO1xuICAgIH1cbiAgfVxuXG4vLyNpZmRlZiBHWklQXG4gIGlmIChzLnN0YXR1cyA9PT0gRVhUUkFfU1RBVEUpIHtcbiAgICBpZiAocy5nemhlYWQuZXh0cmEvKiAhPSBaX05VTEwqLykge1xuICAgICAgYmVnID0gcy5wZW5kaW5nOyAgLyogc3RhcnQgb2YgYnl0ZXMgdG8gdXBkYXRlIGNyYyAqL1xuXG4gICAgICB3aGlsZSAocy5nemluZGV4IDwgKHMuZ3poZWFkLmV4dHJhLmxlbmd0aCAmIDB4ZmZmZikpIHtcbiAgICAgICAgaWYgKHMucGVuZGluZyA9PT0gcy5wZW5kaW5nX2J1Zl9zaXplKSB7XG4gICAgICAgICAgaWYgKHMuZ3poZWFkLmhjcmMgJiYgcy5wZW5kaW5nID4gYmVnKSB7XG4gICAgICAgICAgICBzdHJtLmFkbGVyID0gY3JjMzIoc3RybS5hZGxlciwgcy5wZW5kaW5nX2J1Ziwgcy5wZW5kaW5nIC0gYmVnLCBiZWcpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBmbHVzaF9wZW5kaW5nKHN0cm0pO1xuICAgICAgICAgIGJlZyA9IHMucGVuZGluZztcbiAgICAgICAgICBpZiAocy5wZW5kaW5nID09PSBzLnBlbmRpbmdfYnVmX3NpemUpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBwdXRfYnl0ZShzLCBzLmd6aGVhZC5leHRyYVtzLmd6aW5kZXhdICYgMHhmZik7XG4gICAgICAgIHMuZ3ppbmRleCsrO1xuICAgICAgfVxuICAgICAgaWYgKHMuZ3poZWFkLmhjcmMgJiYgcy5wZW5kaW5nID4gYmVnKSB7XG4gICAgICAgIHN0cm0uYWRsZXIgPSBjcmMzMihzdHJtLmFkbGVyLCBzLnBlbmRpbmdfYnVmLCBzLnBlbmRpbmcgLSBiZWcsIGJlZyk7XG4gICAgICB9XG4gICAgICBpZiAocy5nemluZGV4ID09PSBzLmd6aGVhZC5leHRyYS5sZW5ndGgpIHtcbiAgICAgICAgcy5nemluZGV4ID0gMDtcbiAgICAgICAgcy5zdGF0dXMgPSBOQU1FX1NUQVRFO1xuICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHMuc3RhdHVzID0gTkFNRV9TVEFURTtcbiAgICB9XG4gIH1cbiAgaWYgKHMuc3RhdHVzID09PSBOQU1FX1NUQVRFKSB7XG4gICAgaWYgKHMuZ3poZWFkLm5hbWUvKiAhPSBaX05VTEwqLykge1xuICAgICAgYmVnID0gcy5wZW5kaW5nOyAgLyogc3RhcnQgb2YgYnl0ZXMgdG8gdXBkYXRlIGNyYyAqL1xuICAgICAgLy9pbnQgdmFsO1xuXG4gICAgICBkbyB7XG4gICAgICAgIGlmIChzLnBlbmRpbmcgPT09IHMucGVuZGluZ19idWZfc2l6ZSkge1xuICAgICAgICAgIGlmIChzLmd6aGVhZC5oY3JjICYmIHMucGVuZGluZyA+IGJlZykge1xuICAgICAgICAgICAgc3RybS5hZGxlciA9IGNyYzMyKHN0cm0uYWRsZXIsIHMucGVuZGluZ19idWYsIHMucGVuZGluZyAtIGJlZywgYmVnKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgZmx1c2hfcGVuZGluZyhzdHJtKTtcbiAgICAgICAgICBiZWcgPSBzLnBlbmRpbmc7XG4gICAgICAgICAgaWYgKHMucGVuZGluZyA9PT0gcy5wZW5kaW5nX2J1Zl9zaXplKSB7XG4gICAgICAgICAgICB2YWwgPSAxO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIEpTIHNwZWNpZmljOiBsaXR0bGUgbWFnaWMgdG8gYWRkIHplcm8gdGVybWluYXRvciB0byBlbmQgb2Ygc3RyaW5nXG4gICAgICAgIGlmIChzLmd6aW5kZXggPCBzLmd6aGVhZC5uYW1lLmxlbmd0aCkge1xuICAgICAgICAgIHZhbCA9IHMuZ3poZWFkLm5hbWUuY2hhckNvZGVBdChzLmd6aW5kZXgrKykgJiAweGZmO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhbCA9IDA7XG4gICAgICAgIH1cbiAgICAgICAgcHV0X2J5dGUocywgdmFsKTtcbiAgICAgIH0gd2hpbGUgKHZhbCAhPT0gMCk7XG5cbiAgICAgIGlmIChzLmd6aGVhZC5oY3JjICYmIHMucGVuZGluZyA+IGJlZyl7XG4gICAgICAgIHN0cm0uYWRsZXIgPSBjcmMzMihzdHJtLmFkbGVyLCBzLnBlbmRpbmdfYnVmLCBzLnBlbmRpbmcgLSBiZWcsIGJlZyk7XG4gICAgICB9XG4gICAgICBpZiAodmFsID09PSAwKSB7XG4gICAgICAgIHMuZ3ppbmRleCA9IDA7XG4gICAgICAgIHMuc3RhdHVzID0gQ09NTUVOVF9TVEFURTtcbiAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICBzLnN0YXR1cyA9IENPTU1FTlRfU1RBVEU7XG4gICAgfVxuICB9XG4gIGlmIChzLnN0YXR1cyA9PT0gQ09NTUVOVF9TVEFURSkge1xuICAgIGlmIChzLmd6aGVhZC5jb21tZW50LyogIT0gWl9OVUxMKi8pIHtcbiAgICAgIGJlZyA9IHMucGVuZGluZzsgIC8qIHN0YXJ0IG9mIGJ5dGVzIHRvIHVwZGF0ZSBjcmMgKi9cbiAgICAgIC8vaW50IHZhbDtcblxuICAgICAgZG8ge1xuICAgICAgICBpZiAocy5wZW5kaW5nID09PSBzLnBlbmRpbmdfYnVmX3NpemUpIHtcbiAgICAgICAgICBpZiAocy5nemhlYWQuaGNyYyAmJiBzLnBlbmRpbmcgPiBiZWcpIHtcbiAgICAgICAgICAgIHN0cm0uYWRsZXIgPSBjcmMzMihzdHJtLmFkbGVyLCBzLnBlbmRpbmdfYnVmLCBzLnBlbmRpbmcgLSBiZWcsIGJlZyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGZsdXNoX3BlbmRpbmcoc3RybSk7XG4gICAgICAgICAgYmVnID0gcy5wZW5kaW5nO1xuICAgICAgICAgIGlmIChzLnBlbmRpbmcgPT09IHMucGVuZGluZ19idWZfc2l6ZSkge1xuICAgICAgICAgICAgdmFsID0gMTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBKUyBzcGVjaWZpYzogbGl0dGxlIG1hZ2ljIHRvIGFkZCB6ZXJvIHRlcm1pbmF0b3IgdG8gZW5kIG9mIHN0cmluZ1xuICAgICAgICBpZiAocy5nemluZGV4IDwgcy5nemhlYWQuY29tbWVudC5sZW5ndGgpIHtcbiAgICAgICAgICB2YWwgPSBzLmd6aGVhZC5jb21tZW50LmNoYXJDb2RlQXQocy5nemluZGV4KyspICYgMHhmZjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB2YWwgPSAwO1xuICAgICAgICB9XG4gICAgICAgIHB1dF9ieXRlKHMsIHZhbCk7XG4gICAgICB9IHdoaWxlICh2YWwgIT09IDApO1xuXG4gICAgICBpZiAocy5nemhlYWQuaGNyYyAmJiBzLnBlbmRpbmcgPiBiZWcpIHtcbiAgICAgICAgc3RybS5hZGxlciA9IGNyYzMyKHN0cm0uYWRsZXIsIHMucGVuZGluZ19idWYsIHMucGVuZGluZyAtIGJlZywgYmVnKTtcbiAgICAgIH1cbiAgICAgIGlmICh2YWwgPT09IDApIHtcbiAgICAgICAgcy5zdGF0dXMgPSBIQ1JDX1NUQVRFO1xuICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHMuc3RhdHVzID0gSENSQ19TVEFURTtcbiAgICB9XG4gIH1cbiAgaWYgKHMuc3RhdHVzID09PSBIQ1JDX1NUQVRFKSB7XG4gICAgaWYgKHMuZ3poZWFkLmhjcmMpIHtcbiAgICAgIGlmIChzLnBlbmRpbmcgKyAyID4gcy5wZW5kaW5nX2J1Zl9zaXplKSB7XG4gICAgICAgIGZsdXNoX3BlbmRpbmcoc3RybSk7XG4gICAgICB9XG4gICAgICBpZiAocy5wZW5kaW5nICsgMiA8PSBzLnBlbmRpbmdfYnVmX3NpemUpIHtcbiAgICAgICAgcHV0X2J5dGUocywgc3RybS5hZGxlciAmIDB4ZmYpO1xuICAgICAgICBwdXRfYnl0ZShzLCAoc3RybS5hZGxlciA+PiA4KSAmIDB4ZmYpO1xuICAgICAgICBzdHJtLmFkbGVyID0gMDsgLy9jcmMzMigwTCwgWl9OVUxMLCAwKTtcbiAgICAgICAgcy5zdGF0dXMgPSBCVVNZX1NUQVRFO1xuICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHMuc3RhdHVzID0gQlVTWV9TVEFURTtcbiAgICB9XG4gIH1cbi8vI2VuZGlmXG5cbiAgLyogRmx1c2ggYXMgbXVjaCBwZW5kaW5nIG91dHB1dCBhcyBwb3NzaWJsZSAqL1xuICBpZiAocy5wZW5kaW5nICE9PSAwKSB7XG4gICAgZmx1c2hfcGVuZGluZyhzdHJtKTtcbiAgICBpZiAoc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIC8qIFNpbmNlIGF2YWlsX291dCBpcyAwLCBkZWZsYXRlIHdpbGwgYmUgY2FsbGVkIGFnYWluIHdpdGhcbiAgICAgICAqIG1vcmUgb3V0cHV0IHNwYWNlLCBidXQgcG9zc2libHkgd2l0aCBib3RoIHBlbmRpbmcgYW5kXG4gICAgICAgKiBhdmFpbF9pbiBlcXVhbCB0byB6ZXJvLiBUaGVyZSB3b24ndCBiZSBhbnl0aGluZyB0byBkbyxcbiAgICAgICAqIGJ1dCB0aGlzIGlzIG5vdCBhbiBlcnJvciBzaXR1YXRpb24gc28gbWFrZSBzdXJlIHdlXG4gICAgICAgKiByZXR1cm4gT0sgaW5zdGVhZCBvZiBCVUZfRVJST1IgYXQgbmV4dCBjYWxsIG9mIGRlZmxhdGU6XG4gICAgICAgKi9cbiAgICAgIHMubGFzdF9mbHVzaCA9IC0xO1xuICAgICAgcmV0dXJuIFpfT0s7XG4gICAgfVxuXG4gICAgLyogTWFrZSBzdXJlIHRoZXJlIGlzIHNvbWV0aGluZyB0byBkbyBhbmQgYXZvaWQgZHVwbGljYXRlIGNvbnNlY3V0aXZlXG4gICAgICogZmx1c2hlcy4gRm9yIHJlcGVhdGVkIGFuZCB1c2VsZXNzIGNhbGxzIHdpdGggWl9GSU5JU0gsIHdlIGtlZXBcbiAgICAgKiByZXR1cm5pbmcgWl9TVFJFQU1fRU5EIGluc3RlYWQgb2YgWl9CVUZfRVJST1IuXG4gICAgICovXG4gIH0gZWxzZSBpZiAoc3RybS5hdmFpbF9pbiA9PT0gMCAmJiByYW5rKGZsdXNoKSA8PSByYW5rKG9sZF9mbHVzaCkgJiZcbiAgICBmbHVzaCAhPT0gWl9GSU5JU0gpIHtcbiAgICByZXR1cm4gZXJyKHN0cm0sIFpfQlVGX0VSUk9SKTtcbiAgfVxuXG4gIC8qIFVzZXIgbXVzdCBub3QgcHJvdmlkZSBtb3JlIGlucHV0IGFmdGVyIHRoZSBmaXJzdCBGSU5JU0g6ICovXG4gIGlmIChzLnN0YXR1cyA9PT0gRklOSVNIX1NUQVRFICYmIHN0cm0uYXZhaWxfaW4gIT09IDApIHtcbiAgICByZXR1cm4gZXJyKHN0cm0sIFpfQlVGX0VSUk9SKTtcbiAgfVxuXG4gIC8qIFN0YXJ0IGEgbmV3IGJsb2NrIG9yIGNvbnRpbnVlIHRoZSBjdXJyZW50IG9uZS5cbiAgICovXG4gIGlmIChzdHJtLmF2YWlsX2luICE9PSAwIHx8IHMubG9va2FoZWFkICE9PSAwIHx8XG4gICAgKGZsdXNoICE9PSBaX05PX0ZMVVNIICYmIHMuc3RhdHVzICE9PSBGSU5JU0hfU1RBVEUpKSB7XG4gICAgdmFyIGJzdGF0ZSA9IChzLnN0cmF0ZWd5ID09PSBaX0hVRkZNQU5fT05MWSkgPyBkZWZsYXRlX2h1ZmYocywgZmx1c2gpIDpcbiAgICAgIChzLnN0cmF0ZWd5ID09PSBaX1JMRSA/IGRlZmxhdGVfcmxlKHMsIGZsdXNoKSA6XG4gICAgICAgIGNvbmZpZ3VyYXRpb25fdGFibGVbcy5sZXZlbF0uZnVuYyhzLCBmbHVzaCkpO1xuXG4gICAgaWYgKGJzdGF0ZSA9PT0gQlNfRklOSVNIX1NUQVJURUQgfHwgYnN0YXRlID09PSBCU19GSU5JU0hfRE9ORSkge1xuICAgICAgcy5zdGF0dXMgPSBGSU5JU0hfU1RBVEU7XG4gICAgfVxuICAgIGlmIChic3RhdGUgPT09IEJTX05FRURfTU9SRSB8fCBic3RhdGUgPT09IEJTX0ZJTklTSF9TVEFSVEVEKSB7XG4gICAgICBpZiAoc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgICAgcy5sYXN0X2ZsdXNoID0gLTE7XG4gICAgICAgIC8qIGF2b2lkIEJVRl9FUlJPUiBuZXh0IGNhbGwsIHNlZSBhYm92ZSAqL1xuICAgICAgfVxuICAgICAgcmV0dXJuIFpfT0s7XG4gICAgICAvKiBJZiBmbHVzaCAhPSBaX05PX0ZMVVNIICYmIGF2YWlsX291dCA9PSAwLCB0aGUgbmV4dCBjYWxsXG4gICAgICAgKiBvZiBkZWZsYXRlIHNob3VsZCB1c2UgdGhlIHNhbWUgZmx1c2ggcGFyYW1ldGVyIHRvIG1ha2Ugc3VyZVxuICAgICAgICogdGhhdCB0aGUgZmx1c2ggaXMgY29tcGxldGUuIFNvIHdlIGRvbid0IGhhdmUgdG8gb3V0cHV0IGFuXG4gICAgICAgKiBlbXB0eSBibG9jayBoZXJlLCB0aGlzIHdpbGwgYmUgZG9uZSBhdCBuZXh0IGNhbGwuIFRoaXMgYWxzb1xuICAgICAgICogZW5zdXJlcyB0aGF0IGZvciBhIHZlcnkgc21hbGwgb3V0cHV0IGJ1ZmZlciwgd2UgZW1pdCBhdCBtb3N0XG4gICAgICAgKiBvbmUgZW1wdHkgYmxvY2suXG4gICAgICAgKi9cbiAgICB9XG4gICAgaWYgKGJzdGF0ZSA9PT0gQlNfQkxPQ0tfRE9ORSkge1xuICAgICAgaWYgKGZsdXNoID09PSBaX1BBUlRJQUxfRkxVU0gpIHtcbiAgICAgICAgdHJlZXMuX3RyX2FsaWduKHMpO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAoZmx1c2ggIT09IFpfQkxPQ0spIHsgLyogRlVMTF9GTFVTSCBvciBTWU5DX0ZMVVNIICovXG5cbiAgICAgICAgdHJlZXMuX3RyX3N0b3JlZF9ibG9jayhzLCAwLCAwLCBmYWxzZSk7XG4gICAgICAgIC8qIEZvciBhIGZ1bGwgZmx1c2gsIHRoaXMgZW1wdHkgYmxvY2sgd2lsbCBiZSByZWNvZ25pemVkXG4gICAgICAgICAqIGFzIGEgc3BlY2lhbCBtYXJrZXIgYnkgaW5mbGF0ZV9zeW5jKCkuXG4gICAgICAgICAqL1xuICAgICAgICBpZiAoZmx1c2ggPT09IFpfRlVMTF9GTFVTSCkge1xuICAgICAgICAgIC8qKiogQ0xFQVJfSEFTSChzKTsgKioqLyAgICAgICAgICAgICAvKiBmb3JnZXQgaGlzdG9yeSAqL1xuICAgICAgICAgIHplcm8ocy5oZWFkKTsgLy8gRmlsbCB3aXRoIE5JTCAoPSAwKTtcblxuICAgICAgICAgIGlmIChzLmxvb2thaGVhZCA9PT0gMCkge1xuICAgICAgICAgICAgcy5zdHJzdGFydCA9IDA7XG4gICAgICAgICAgICBzLmJsb2NrX3N0YXJ0ID0gMDtcbiAgICAgICAgICAgIHMuaW5zZXJ0ID0gMDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGZsdXNoX3BlbmRpbmcoc3RybSk7XG4gICAgICBpZiAoc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgICAgcy5sYXN0X2ZsdXNoID0gLTE7IC8qIGF2b2lkIEJVRl9FUlJPUiBhdCBuZXh0IGNhbGwsIHNlZSBhYm92ZSAqL1xuICAgICAgICByZXR1cm4gWl9PSztcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgLy9Bc3NlcnQoc3RybS0+YXZhaWxfb3V0ID4gMCwgXCJidWcyXCIpO1xuICAvL2lmIChzdHJtLmF2YWlsX291dCA8PSAwKSB7IHRocm93IG5ldyBFcnJvcihcImJ1ZzJcIik7fVxuXG4gIGlmIChmbHVzaCAhPT0gWl9GSU5JU0gpIHsgcmV0dXJuIFpfT0s7IH1cbiAgaWYgKHMud3JhcCA8PSAwKSB7IHJldHVybiBaX1NUUkVBTV9FTkQ7IH1cblxuICAvKiBXcml0ZSB0aGUgdHJhaWxlciAqL1xuICBpZiAocy53cmFwID09PSAyKSB7XG4gICAgcHV0X2J5dGUocywgc3RybS5hZGxlciAmIDB4ZmYpO1xuICAgIHB1dF9ieXRlKHMsIChzdHJtLmFkbGVyID4+IDgpICYgMHhmZik7XG4gICAgcHV0X2J5dGUocywgKHN0cm0uYWRsZXIgPj4gMTYpICYgMHhmZik7XG4gICAgcHV0X2J5dGUocywgKHN0cm0uYWRsZXIgPj4gMjQpICYgMHhmZik7XG4gICAgcHV0X2J5dGUocywgc3RybS50b3RhbF9pbiAmIDB4ZmYpO1xuICAgIHB1dF9ieXRlKHMsIChzdHJtLnRvdGFsX2luID4+IDgpICYgMHhmZik7XG4gICAgcHV0X2J5dGUocywgKHN0cm0udG90YWxfaW4gPj4gMTYpICYgMHhmZik7XG4gICAgcHV0X2J5dGUocywgKHN0cm0udG90YWxfaW4gPj4gMjQpICYgMHhmZik7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgcHV0U2hvcnRNU0Iocywgc3RybS5hZGxlciA+Pj4gMTYpO1xuICAgIHB1dFNob3J0TVNCKHMsIHN0cm0uYWRsZXIgJiAweGZmZmYpO1xuICB9XG5cbiAgZmx1c2hfcGVuZGluZyhzdHJtKTtcbiAgLyogSWYgYXZhaWxfb3V0IGlzIHplcm8sIHRoZSBhcHBsaWNhdGlvbiB3aWxsIGNhbGwgZGVmbGF0ZSBhZ2FpblxuICAgKiB0byBmbHVzaCB0aGUgcmVzdC5cbiAgICovXG4gIGlmIChzLndyYXAgPiAwKSB7IHMud3JhcCA9IC1zLndyYXA7IH1cbiAgLyogd3JpdGUgdGhlIHRyYWlsZXIgb25seSBvbmNlISAqL1xuICByZXR1cm4gcy5wZW5kaW5nICE9PSAwID8gWl9PSyA6IFpfU1RSRUFNX0VORDtcbn1cblxuZnVuY3Rpb24gZGVmbGF0ZUVuZChzdHJtKSB7XG4gIHZhciBzdGF0dXM7XG5cbiAgaWYgKCFzdHJtLyo9PSBaX05VTEwqLyB8fCAhc3RybS5zdGF0ZS8qPT0gWl9OVUxMKi8pIHtcbiAgICByZXR1cm4gWl9TVFJFQU1fRVJST1I7XG4gIH1cblxuICBzdGF0dXMgPSBzdHJtLnN0YXRlLnN0YXR1cztcbiAgaWYgKHN0YXR1cyAhPT0gSU5JVF9TVEFURSAmJlxuICAgIHN0YXR1cyAhPT0gRVhUUkFfU1RBVEUgJiZcbiAgICBzdGF0dXMgIT09IE5BTUVfU1RBVEUgJiZcbiAgICBzdGF0dXMgIT09IENPTU1FTlRfU1RBVEUgJiZcbiAgICBzdGF0dXMgIT09IEhDUkNfU1RBVEUgJiZcbiAgICBzdGF0dXMgIT09IEJVU1lfU1RBVEUgJiZcbiAgICBzdGF0dXMgIT09IEZJTklTSF9TVEFURVxuICApIHtcbiAgICByZXR1cm4gZXJyKHN0cm0sIFpfU1RSRUFNX0VSUk9SKTtcbiAgfVxuXG4gIHN0cm0uc3RhdGUgPSBudWxsO1xuXG4gIHJldHVybiBzdGF0dXMgPT09IEJVU1lfU1RBVEUgPyBlcnIoc3RybSwgWl9EQVRBX0VSUk9SKSA6IFpfT0s7XG59XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvcHkgdGhlIHNvdXJjZSBzdGF0ZSB0byB0aGUgZGVzdGluYXRpb24gc3RhdGVcbiAqL1xuLy9mdW5jdGlvbiBkZWZsYXRlQ29weShkZXN0LCBzb3VyY2UpIHtcbi8vXG4vL31cblxuZXhwb3J0cy5kZWZsYXRlSW5pdCA9IGRlZmxhdGVJbml0O1xuZXhwb3J0cy5kZWZsYXRlSW5pdDIgPSBkZWZsYXRlSW5pdDI7XG5leHBvcnRzLmRlZmxhdGVSZXNldCA9IGRlZmxhdGVSZXNldDtcbmV4cG9ydHMuZGVmbGF0ZVJlc2V0S2VlcCA9IGRlZmxhdGVSZXNldEtlZXA7XG5leHBvcnRzLmRlZmxhdGVTZXRIZWFkZXIgPSBkZWZsYXRlU2V0SGVhZGVyO1xuZXhwb3J0cy5kZWZsYXRlID0gZGVmbGF0ZTtcbmV4cG9ydHMuZGVmbGF0ZUVuZCA9IGRlZmxhdGVFbmQ7XG5leHBvcnRzLmRlZmxhdGVJbmZvID0gJ3Bha28gZGVmbGF0ZSAoZnJvbSBOb2RlY2EgcHJvamVjdCknO1xuXG4vKiBOb3QgaW1wbGVtZW50ZWRcbmV4cG9ydHMuZGVmbGF0ZUJvdW5kID0gZGVmbGF0ZUJvdW5kO1xuZXhwb3J0cy5kZWZsYXRlQ29weSA9IGRlZmxhdGVDb3B5O1xuZXhwb3J0cy5kZWZsYXRlU2V0RGljdGlvbmFyeSA9IGRlZmxhdGVTZXREaWN0aW9uYXJ5O1xuZXhwb3J0cy5kZWZsYXRlUGFyYW1zID0gZGVmbGF0ZVBhcmFtcztcbmV4cG9ydHMuZGVmbGF0ZVBlbmRpbmcgPSBkZWZsYXRlUGVuZGluZztcbmV4cG9ydHMuZGVmbGF0ZVByaW1lID0gZGVmbGF0ZVByaW1lO1xuZXhwb3J0cy5kZWZsYXRlVHVuZSA9IGRlZmxhdGVUdW5lO1xuKi8iLCIndXNlIHN0cmljdCc7XG5cblxuZnVuY3Rpb24gR1poZWFkZXIoKSB7XG4gIC8qIHRydWUgaWYgY29tcHJlc3NlZCBkYXRhIGJlbGlldmVkIHRvIGJlIHRleHQgKi9cbiAgdGhpcy50ZXh0ICAgICAgID0gMDtcbiAgLyogbW9kaWZpY2F0aW9uIHRpbWUgKi9cbiAgdGhpcy50aW1lICAgICAgID0gMDtcbiAgLyogZXh0cmEgZmxhZ3MgKG5vdCB1c2VkIHdoZW4gd3JpdGluZyBhIGd6aXAgZmlsZSkgKi9cbiAgdGhpcy54ZmxhZ3MgICAgID0gMDtcbiAgLyogb3BlcmF0aW5nIHN5c3RlbSAqL1xuICB0aGlzLm9zICAgICAgICAgPSAwO1xuICAvKiBwb2ludGVyIHRvIGV4dHJhIGZpZWxkIG9yIFpfTlVMTCBpZiBub25lICovXG4gIHRoaXMuZXh0cmEgICAgICA9IG51bGw7XG4gIC8qIGV4dHJhIGZpZWxkIGxlbmd0aCAodmFsaWQgaWYgZXh0cmEgIT0gWl9OVUxMKSAqL1xuICB0aGlzLmV4dHJhX2xlbiAgPSAwOyAvLyBBY3R1YWxseSwgd2UgZG9uJ3QgbmVlZCBpdCBpbiBKUyxcbiAgICAgICAgICAgICAgICAgICAgICAgLy8gYnV0IGxlYXZlIGZvciBmZXcgY29kZSBtb2RpZmljYXRpb25zXG5cbiAgLy9cbiAgLy8gU2V0dXAgbGltaXRzIGlzIG5vdCBuZWNlc3NhcnkgYmVjYXVzZSBpbiBqcyB3ZSBzaG91bGQgbm90IHByZWFsbG9jYXRlIG1lbW9yeSBcbiAgLy8gZm9yIGluZmxhdGUgdXNlIGNvbnN0YW50IGxpbWl0IGluIDY1NTM2IGJ5dGVzXG4gIC8vXG5cbiAgLyogc3BhY2UgYXQgZXh0cmEgKG9ubHkgd2hlbiByZWFkaW5nIGhlYWRlcikgKi9cbiAgLy8gdGhpcy5leHRyYV9tYXggID0gMDtcbiAgLyogcG9pbnRlciB0byB6ZXJvLXRlcm1pbmF0ZWQgZmlsZSBuYW1lIG9yIFpfTlVMTCAqL1xuICB0aGlzLm5hbWUgICAgICAgPSAnJztcbiAgLyogc3BhY2UgYXQgbmFtZSAob25seSB3aGVuIHJlYWRpbmcgaGVhZGVyKSAqL1xuICAvLyB0aGlzLm5hbWVfbWF4ICAgPSAwO1xuICAvKiBwb2ludGVyIHRvIHplcm8tdGVybWluYXRlZCBjb21tZW50IG9yIFpfTlVMTCAqL1xuICB0aGlzLmNvbW1lbnQgICAgPSAnJztcbiAgLyogc3BhY2UgYXQgY29tbWVudCAob25seSB3aGVuIHJlYWRpbmcgaGVhZGVyKSAqL1xuICAvLyB0aGlzLmNvbW1fbWF4ICAgPSAwO1xuICAvKiB0cnVlIGlmIHRoZXJlIHdhcyBvciB3aWxsIGJlIGEgaGVhZGVyIGNyYyAqL1xuICB0aGlzLmhjcmMgICAgICAgPSAwO1xuICAvKiB0cnVlIHdoZW4gZG9uZSByZWFkaW5nIGd6aXAgaGVhZGVyIChub3QgdXNlZCB3aGVuIHdyaXRpbmcgYSBnemlwIGZpbGUpICovXG4gIHRoaXMuZG9uZSAgICAgICA9IGZhbHNlO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IEdaaGVhZGVyOyIsIid1c2Ugc3RyaWN0JztcblxuLy8gU2VlIHN0YXRlIGRlZnMgZnJvbSBpbmZsYXRlLmpzXG52YXIgQkFEID0gMzA7ICAgICAgIC8qIGdvdCBhIGRhdGEgZXJyb3IgLS0gcmVtYWluIGhlcmUgdW50aWwgcmVzZXQgKi9cbnZhciBUWVBFID0gMTI7ICAgICAgLyogaTogd2FpdGluZyBmb3IgdHlwZSBiaXRzLCBpbmNsdWRpbmcgbGFzdC1mbGFnIGJpdCAqL1xuXG4vKlxuICAgRGVjb2RlIGxpdGVyYWwsIGxlbmd0aCwgYW5kIGRpc3RhbmNlIGNvZGVzIGFuZCB3cml0ZSBvdXQgdGhlIHJlc3VsdGluZ1xuICAgbGl0ZXJhbCBhbmQgbWF0Y2ggYnl0ZXMgdW50aWwgZWl0aGVyIG5vdCBlbm91Z2ggaW5wdXQgb3Igb3V0cHV0IGlzXG4gICBhdmFpbGFibGUsIGFuIGVuZC1vZi1ibG9jayBpcyBlbmNvdW50ZXJlZCwgb3IgYSBkYXRhIGVycm9yIGlzIGVuY291bnRlcmVkLlxuICAgV2hlbiBsYXJnZSBlbm91Z2ggaW5wdXQgYW5kIG91dHB1dCBidWZmZXJzIGFyZSBzdXBwbGllZCB0byBpbmZsYXRlKCksIGZvclxuICAgZXhhbXBsZSwgYSAxNksgaW5wdXQgYnVmZmVyIGFuZCBhIDY0SyBvdXRwdXQgYnVmZmVyLCBtb3JlIHRoYW4gOTUlIG9mIHRoZVxuICAgaW5mbGF0ZSBleGVjdXRpb24gdGltZSBpcyBzcGVudCBpbiB0aGlzIHJvdXRpbmUuXG5cbiAgIEVudHJ5IGFzc3VtcHRpb25zOlxuXG4gICAgICAgIHN0YXRlLm1vZGUgPT09IExFTlxuICAgICAgICBzdHJtLmF2YWlsX2luID49IDZcbiAgICAgICAgc3RybS5hdmFpbF9vdXQgPj0gMjU4XG4gICAgICAgIHN0YXJ0ID49IHN0cm0uYXZhaWxfb3V0XG4gICAgICAgIHN0YXRlLmJpdHMgPCA4XG5cbiAgIE9uIHJldHVybiwgc3RhdGUubW9kZSBpcyBvbmUgb2Y6XG5cbiAgICAgICAgTEVOIC0tIHJhbiBvdXQgb2YgZW5vdWdoIG91dHB1dCBzcGFjZSBvciBlbm91Z2ggYXZhaWxhYmxlIGlucHV0XG4gICAgICAgIFRZUEUgLS0gcmVhY2hlZCBlbmQgb2YgYmxvY2sgY29kZSwgaW5mbGF0ZSgpIHRvIGludGVycHJldCBuZXh0IGJsb2NrXG4gICAgICAgIEJBRCAtLSBlcnJvciBpbiBibG9jayBkYXRhXG5cbiAgIE5vdGVzOlxuXG4gICAgLSBUaGUgbWF4aW11bSBpbnB1dCBiaXRzIHVzZWQgYnkgYSBsZW5ndGgvZGlzdGFuY2UgcGFpciBpcyAxNSBiaXRzIGZvciB0aGVcbiAgICAgIGxlbmd0aCBjb2RlLCA1IGJpdHMgZm9yIHRoZSBsZW5ndGggZXh0cmEsIDE1IGJpdHMgZm9yIHRoZSBkaXN0YW5jZSBjb2RlLFxuICAgICAgYW5kIDEzIGJpdHMgZm9yIHRoZSBkaXN0YW5jZSBleHRyYS4gIFRoaXMgdG90YWxzIDQ4IGJpdHMsIG9yIHNpeCBieXRlcy5cbiAgICAgIFRoZXJlZm9yZSBpZiBzdHJtLmF2YWlsX2luID49IDYsIHRoZW4gdGhlcmUgaXMgZW5vdWdoIGlucHV0IHRvIGF2b2lkXG4gICAgICBjaGVja2luZyBmb3IgYXZhaWxhYmxlIGlucHV0IHdoaWxlIGRlY29kaW5nLlxuXG4gICAgLSBUaGUgbWF4aW11bSBieXRlcyB0aGF0IGEgc2luZ2xlIGxlbmd0aC9kaXN0YW5jZSBwYWlyIGNhbiBvdXRwdXQgaXMgMjU4XG4gICAgICBieXRlcywgd2hpY2ggaXMgdGhlIG1heGltdW0gbGVuZ3RoIHRoYXQgY2FuIGJlIGNvZGVkLiAgaW5mbGF0ZV9mYXN0KClcbiAgICAgIHJlcXVpcmVzIHN0cm0uYXZhaWxfb3V0ID49IDI1OCBmb3IgZWFjaCBsb29wIHRvIGF2b2lkIGNoZWNraW5nIGZvclxuICAgICAgb3V0cHV0IHNwYWNlLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGluZmxhdGVfZmFzdChzdHJtLCBzdGFydCkge1xuICB2YXIgc3RhdGU7XG4gIHZhciBfaW47ICAgICAgICAgICAgICAgICAgICAvKiBsb2NhbCBzdHJtLmlucHV0ICovXG4gIHZhciBsYXN0OyAgICAgICAgICAgICAgICAgICAvKiBoYXZlIGVub3VnaCBpbnB1dCB3aGlsZSBpbiA8IGxhc3QgKi9cbiAgdmFyIF9vdXQ7ICAgICAgICAgICAgICAgICAgIC8qIGxvY2FsIHN0cm0ub3V0cHV0ICovXG4gIHZhciBiZWc7ICAgICAgICAgICAgICAgICAgICAvKiBpbmZsYXRlKCkncyBpbml0aWFsIHN0cm0ub3V0cHV0ICovXG4gIHZhciBlbmQ7ICAgICAgICAgICAgICAgICAgICAvKiB3aGlsZSBvdXQgPCBlbmQsIGVub3VnaCBzcGFjZSBhdmFpbGFibGUgKi9cbi8vI2lmZGVmIElORkxBVEVfU1RSSUNUXG4gIHZhciBkbWF4OyAgICAgICAgICAgICAgICAgICAvKiBtYXhpbXVtIGRpc3RhbmNlIGZyb20gemxpYiBoZWFkZXIgKi9cbi8vI2VuZGlmXG4gIHZhciB3c2l6ZTsgICAgICAgICAgICAgICAgICAvKiB3aW5kb3cgc2l6ZSBvciB6ZXJvIGlmIG5vdCB1c2luZyB3aW5kb3cgKi9cbiAgdmFyIHdoYXZlOyAgICAgICAgICAgICAgICAgIC8qIHZhbGlkIGJ5dGVzIGluIHRoZSB3aW5kb3cgKi9cbiAgdmFyIHduZXh0OyAgICAgICAgICAgICAgICAgIC8qIHdpbmRvdyB3cml0ZSBpbmRleCAqL1xuICB2YXIgd2luZG93OyAgICAgICAgICAgICAgICAgLyogYWxsb2NhdGVkIHNsaWRpbmcgd2luZG93LCBpZiB3c2l6ZSAhPSAwICovXG4gIHZhciBob2xkOyAgICAgICAgICAgICAgICAgICAvKiBsb2NhbCBzdHJtLmhvbGQgKi9cbiAgdmFyIGJpdHM7ICAgICAgICAgICAgICAgICAgIC8qIGxvY2FsIHN0cm0uYml0cyAqL1xuICB2YXIgbGNvZGU7ICAgICAgICAgICAgICAgICAgLyogbG9jYWwgc3RybS5sZW5jb2RlICovXG4gIHZhciBkY29kZTsgICAgICAgICAgICAgICAgICAvKiBsb2NhbCBzdHJtLmRpc3Rjb2RlICovXG4gIHZhciBsbWFzazsgICAgICAgICAgICAgICAgICAvKiBtYXNrIGZvciBmaXJzdCBsZXZlbCBvZiBsZW5ndGggY29kZXMgKi9cbiAgdmFyIGRtYXNrOyAgICAgICAgICAgICAgICAgIC8qIG1hc2sgZm9yIGZpcnN0IGxldmVsIG9mIGRpc3RhbmNlIGNvZGVzICovXG4gIHZhciBoZXJlOyAgICAgICAgICAgICAgICAgICAvKiByZXRyaWV2ZWQgdGFibGUgZW50cnkgKi9cbiAgdmFyIG9wOyAgICAgICAgICAgICAgICAgICAgIC8qIGNvZGUgYml0cywgb3BlcmF0aW9uLCBleHRyYSBiaXRzLCBvciAqL1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogIHdpbmRvdyBwb3NpdGlvbiwgd2luZG93IGJ5dGVzIHRvIGNvcHkgKi9cbiAgdmFyIGxlbjsgICAgICAgICAgICAgICAgICAgIC8qIG1hdGNoIGxlbmd0aCwgdW51c2VkIGJ5dGVzICovXG4gIHZhciBkaXN0OyAgICAgICAgICAgICAgICAgICAvKiBtYXRjaCBkaXN0YW5jZSAqL1xuICB2YXIgZnJvbTsgICAgICAgICAgICAgICAgICAgLyogd2hlcmUgdG8gY29weSBtYXRjaCBmcm9tICovXG4gIHZhciBmcm9tX3NvdXJjZTtcblxuXG4gIHZhciBpbnB1dCwgb3V0cHV0OyAvLyBKUyBzcGVjaWZpYywgYmVjYXVzZSB3ZSBoYXZlIG5vIHBvaW50ZXJzXG5cbiAgLyogY29weSBzdGF0ZSB0byBsb2NhbCB2YXJpYWJsZXMgKi9cbiAgc3RhdGUgPSBzdHJtLnN0YXRlO1xuICAvL2hlcmUgPSBzdGF0ZS5oZXJlO1xuICBfaW4gPSBzdHJtLm5leHRfaW47XG4gIGlucHV0ID0gc3RybS5pbnB1dDtcbiAgbGFzdCA9IF9pbiArIChzdHJtLmF2YWlsX2luIC0gNSk7XG4gIF9vdXQgPSBzdHJtLm5leHRfb3V0O1xuICBvdXRwdXQgPSBzdHJtLm91dHB1dDtcbiAgYmVnID0gX291dCAtIChzdGFydCAtIHN0cm0uYXZhaWxfb3V0KTtcbiAgZW5kID0gX291dCArIChzdHJtLmF2YWlsX291dCAtIDI1Nyk7XG4vLyNpZmRlZiBJTkZMQVRFX1NUUklDVFxuICBkbWF4ID0gc3RhdGUuZG1heDtcbi8vI2VuZGlmXG4gIHdzaXplID0gc3RhdGUud3NpemU7XG4gIHdoYXZlID0gc3RhdGUud2hhdmU7XG4gIHduZXh0ID0gc3RhdGUud25leHQ7XG4gIHdpbmRvdyA9IHN0YXRlLndpbmRvdztcbiAgaG9sZCA9IHN0YXRlLmhvbGQ7XG4gIGJpdHMgPSBzdGF0ZS5iaXRzO1xuICBsY29kZSA9IHN0YXRlLmxlbmNvZGU7XG4gIGRjb2RlID0gc3RhdGUuZGlzdGNvZGU7XG4gIGxtYXNrID0gKDEgPDwgc3RhdGUubGVuYml0cykgLSAxO1xuICBkbWFzayA9ICgxIDw8IHN0YXRlLmRpc3RiaXRzKSAtIDE7XG5cblxuICAvKiBkZWNvZGUgbGl0ZXJhbHMgYW5kIGxlbmd0aC9kaXN0YW5jZXMgdW50aWwgZW5kLW9mLWJsb2NrIG9yIG5vdCBlbm91Z2hcbiAgICAgaW5wdXQgZGF0YSBvciBvdXRwdXQgc3BhY2UgKi9cblxuICB0b3A6XG4gIGRvIHtcbiAgICBpZiAoYml0cyA8IDE1KSB7XG4gICAgICBob2xkICs9IGlucHV0W19pbisrXSA8PCBiaXRzO1xuICAgICAgYml0cyArPSA4O1xuICAgICAgaG9sZCArPSBpbnB1dFtfaW4rK10gPDwgYml0cztcbiAgICAgIGJpdHMgKz0gODtcbiAgICB9XG5cbiAgICBoZXJlID0gbGNvZGVbaG9sZCAmIGxtYXNrXTtcblxuICAgIGRvbGVuOlxuICAgIGZvciAoOzspIHsgLy8gR290byBlbXVsYXRpb25cbiAgICAgIG9wID0gaGVyZSA+Pj4gMjQvKmhlcmUuYml0cyovO1xuICAgICAgaG9sZCA+Pj49IG9wO1xuICAgICAgYml0cyAtPSBvcDtcbiAgICAgIG9wID0gKGhlcmUgPj4+IDE2KSAmIDB4ZmYvKmhlcmUub3AqLztcbiAgICAgIGlmIChvcCA9PT0gMCkgeyAgICAgICAgICAgICAgICAgICAgICAgICAgLyogbGl0ZXJhbCAqL1xuICAgICAgICAvL1RyYWNldnYoKHN0ZGVyciwgaGVyZS52YWwgPj0gMHgyMCAmJiBoZXJlLnZhbCA8IDB4N2YgP1xuICAgICAgICAvLyAgICAgICAgXCJpbmZsYXRlOiAgICAgICAgIGxpdGVyYWwgJyVjJ1xcblwiIDpcbiAgICAgICAgLy8gICAgICAgIFwiaW5mbGF0ZTogICAgICAgICBsaXRlcmFsIDB4JTAyeFxcblwiLCBoZXJlLnZhbCkpO1xuICAgICAgICBvdXRwdXRbX291dCsrXSA9IGhlcmUgJiAweGZmZmYvKmhlcmUudmFsKi87XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChvcCAmIDE2KSB7ICAgICAgICAgICAgICAgICAgICAgLyogbGVuZ3RoIGJhc2UgKi9cbiAgICAgICAgbGVuID0gaGVyZSAmIDB4ZmZmZi8qaGVyZS52YWwqLztcbiAgICAgICAgb3AgJj0gMTU7ICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogbnVtYmVyIG9mIGV4dHJhIGJpdHMgKi9cbiAgICAgICAgaWYgKG9wKSB7XG4gICAgICAgICAgaWYgKGJpdHMgPCBvcCkge1xuICAgICAgICAgICAgaG9sZCArPSBpbnB1dFtfaW4rK10gPDwgYml0cztcbiAgICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgICB9XG4gICAgICAgICAgbGVuICs9IGhvbGQgJiAoKDEgPDwgb3ApIC0gMSk7XG4gICAgICAgICAgaG9sZCA+Pj49IG9wO1xuICAgICAgICAgIGJpdHMgLT0gb3A7XG4gICAgICAgIH1cbiAgICAgICAgLy9UcmFjZXZ2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgICAgICBsZW5ndGggJXVcXG5cIiwgbGVuKSk7XG4gICAgICAgIGlmIChiaXRzIDwgMTUpIHtcbiAgICAgICAgICBob2xkICs9IGlucHV0W19pbisrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgICBob2xkICs9IGlucHV0W19pbisrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgfVxuICAgICAgICBoZXJlID0gZGNvZGVbaG9sZCAmIGRtYXNrXTtcblxuICAgICAgICBkb2Rpc3Q6XG4gICAgICAgIGZvciAoOzspIHsgLy8gZ290byBlbXVsYXRpb25cbiAgICAgICAgICBvcCA9IGhlcmUgPj4+IDI0LypoZXJlLmJpdHMqLztcbiAgICAgICAgICBob2xkID4+Pj0gb3A7XG4gICAgICAgICAgYml0cyAtPSBvcDtcbiAgICAgICAgICBvcCA9IChoZXJlID4+PiAxNikgJiAweGZmLypoZXJlLm9wKi87XG5cbiAgICAgICAgICBpZiAob3AgJiAxNikgeyAgICAgICAgICAgICAgICAgICAgICAvKiBkaXN0YW5jZSBiYXNlICovXG4gICAgICAgICAgICBkaXN0ID0gaGVyZSAmIDB4ZmZmZi8qaGVyZS52YWwqLztcbiAgICAgICAgICAgIG9wICY9IDE1OyAgICAgICAgICAgICAgICAgICAgICAgLyogbnVtYmVyIG9mIGV4dHJhIGJpdHMgKi9cbiAgICAgICAgICAgIGlmIChiaXRzIDwgb3ApIHtcbiAgICAgICAgICAgICAgaG9sZCArPSBpbnB1dFtfaW4rK10gPDwgYml0cztcbiAgICAgICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAgICAgICBpZiAoYml0cyA8IG9wKSB7XG4gICAgICAgICAgICAgICAgaG9sZCArPSBpbnB1dFtfaW4rK10gPDwgYml0cztcbiAgICAgICAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRpc3QgKz0gaG9sZCAmICgoMSA8PCBvcCkgLSAxKTtcbi8vI2lmZGVmIElORkxBVEVfU1RSSUNUXG4gICAgICAgICAgICBpZiAoZGlzdCA+IGRtYXgpIHtcbiAgICAgICAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBkaXN0YW5jZSB0b28gZmFyIGJhY2snO1xuICAgICAgICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICAgICAgICBicmVhayB0b3A7XG4gICAgICAgICAgICB9XG4vLyNlbmRpZlxuICAgICAgICAgICAgaG9sZCA+Pj49IG9wO1xuICAgICAgICAgICAgYml0cyAtPSBvcDtcbiAgICAgICAgICAgIC8vVHJhY2V2digoc3RkZXJyLCBcImluZmxhdGU6ICAgICAgICAgZGlzdGFuY2UgJXVcXG5cIiwgZGlzdCkpO1xuICAgICAgICAgICAgb3AgPSBfb3V0IC0gYmVnOyAgICAgICAgICAgICAgICAvKiBtYXggZGlzdGFuY2UgaW4gb3V0cHV0ICovXG4gICAgICAgICAgICBpZiAoZGlzdCA+IG9wKSB7ICAgICAgICAgICAgICAgIC8qIHNlZSBpZiBjb3B5IGZyb20gd2luZG93ICovXG4gICAgICAgICAgICAgIG9wID0gZGlzdCAtIG9wOyAgICAgICAgICAgICAgIC8qIGRpc3RhbmNlIGJhY2sgaW4gd2luZG93ICovXG4gICAgICAgICAgICAgIGlmIChvcCA+IHdoYXZlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHN0YXRlLnNhbmUpIHtcbiAgICAgICAgICAgICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrJztcbiAgICAgICAgICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgICAgICAgICBicmVhayB0b3A7XG4gICAgICAgICAgICAgICAgfVxuXG4vLyAoISkgVGhpcyBibG9jayBpcyBkaXNhYmxlZCBpbiB6bGliIGRlZmFpbHRzLFxuLy8gZG9uJ3QgZW5hYmxlIGl0IGZvciBiaW5hcnkgY29tcGF0aWJpbGl0eVxuLy8jaWZkZWYgSU5GTEFURV9BTExPV19JTlZBTElEX0RJU1RBTkNFX1RPT0ZBUl9BUlJSXG4vLyAgICAgICAgICAgICAgICBpZiAobGVuIDw9IG9wIC0gd2hhdmUpIHtcbi8vICAgICAgICAgICAgICAgICAgZG8ge1xuLy8gICAgICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gMDtcbi8vICAgICAgICAgICAgICAgICAgfSB3aGlsZSAoLS1sZW4pO1xuLy8gICAgICAgICAgICAgICAgICBjb250aW51ZSB0b3A7XG4vLyAgICAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgICAgICBsZW4gLT0gb3AgLSB3aGF2ZTtcbi8vICAgICAgICAgICAgICAgIGRvIHtcbi8vICAgICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSAwO1xuLy8gICAgICAgICAgICAgICAgfSB3aGlsZSAoLS1vcCA+IHdoYXZlKTtcbi8vICAgICAgICAgICAgICAgIGlmIChvcCA9PT0gMCkge1xuLy8gICAgICAgICAgICAgICAgICBmcm9tID0gX291dCAtIGRpc3Q7XG4vLyAgICAgICAgICAgICAgICAgIGRvIHtcbi8vICAgICAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IG91dHB1dFtmcm9tKytdO1xuLy8gICAgICAgICAgICAgICAgICB9IHdoaWxlICgtLWxlbik7XG4vLyAgICAgICAgICAgICAgICAgIGNvbnRpbnVlIHRvcDtcbi8vICAgICAgICAgICAgICAgIH1cbi8vI2VuZGlmXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgZnJvbSA9IDA7IC8vIHdpbmRvdyBpbmRleFxuICAgICAgICAgICAgICBmcm9tX3NvdXJjZSA9IHdpbmRvdztcbiAgICAgICAgICAgICAgaWYgKHduZXh0ID09PSAwKSB7ICAgICAgICAgICAvKiB2ZXJ5IGNvbW1vbiBjYXNlICovXG4gICAgICAgICAgICAgICAgZnJvbSArPSB3c2l6ZSAtIG9wO1xuICAgICAgICAgICAgICAgIGlmIChvcCA8IGxlbikgeyAgICAgICAgIC8qIHNvbWUgZnJvbSB3aW5kb3cgKi9cbiAgICAgICAgICAgICAgICAgIGxlbiAtPSBvcDtcbiAgICAgICAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSB3aW5kb3dbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICAgIH0gd2hpbGUgKC0tb3ApO1xuICAgICAgICAgICAgICAgICAgZnJvbSA9IF9vdXQgLSBkaXN0OyAgLyogcmVzdCBmcm9tIG91dHB1dCAqL1xuICAgICAgICAgICAgICAgICAgZnJvbV9zb3VyY2UgPSBvdXRwdXQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGVsc2UgaWYgKHduZXh0IDwgb3ApIHsgICAgICAvKiB3cmFwIGFyb3VuZCB3aW5kb3cgKi9cbiAgICAgICAgICAgICAgICBmcm9tICs9IHdzaXplICsgd25leHQgLSBvcDtcbiAgICAgICAgICAgICAgICBvcCAtPSB3bmV4dDtcbiAgICAgICAgICAgICAgICBpZiAob3AgPCBsZW4pIHsgICAgICAgICAvKiBzb21lIGZyb20gZW5kIG9mIHdpbmRvdyAqL1xuICAgICAgICAgICAgICAgICAgbGVuIC09IG9wO1xuICAgICAgICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IHdpbmRvd1tmcm9tKytdO1xuICAgICAgICAgICAgICAgICAgfSB3aGlsZSAoLS1vcCk7XG4gICAgICAgICAgICAgICAgICBmcm9tID0gMDtcbiAgICAgICAgICAgICAgICAgIGlmICh3bmV4dCA8IGxlbikgeyAgLyogc29tZSBmcm9tIHN0YXJ0IG9mIHdpbmRvdyAqL1xuICAgICAgICAgICAgICAgICAgICBvcCA9IHduZXh0O1xuICAgICAgICAgICAgICAgICAgICBsZW4gLT0gb3A7XG4gICAgICAgICAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IHdpbmRvd1tmcm9tKytdO1xuICAgICAgICAgICAgICAgICAgICB9IHdoaWxlICgtLW9wKTtcbiAgICAgICAgICAgICAgICAgICAgZnJvbSA9IF9vdXQgLSBkaXN0OyAgICAgIC8qIHJlc3QgZnJvbSBvdXRwdXQgKi9cbiAgICAgICAgICAgICAgICAgICAgZnJvbV9zb3VyY2UgPSBvdXRwdXQ7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGVsc2UgeyAgICAgICAgICAgICAgICAgICAgICAvKiBjb250aWd1b3VzIGluIHdpbmRvdyAqL1xuICAgICAgICAgICAgICAgIGZyb20gKz0gd25leHQgLSBvcDtcbiAgICAgICAgICAgICAgICBpZiAob3AgPCBsZW4pIHsgICAgICAgICAvKiBzb21lIGZyb20gd2luZG93ICovXG4gICAgICAgICAgICAgICAgICBsZW4gLT0gb3A7XG4gICAgICAgICAgICAgICAgICBkbyB7XG4gICAgICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gd2luZG93W2Zyb20rK107XG4gICAgICAgICAgICAgICAgICB9IHdoaWxlICgtLW9wKTtcbiAgICAgICAgICAgICAgICAgIGZyb20gPSBfb3V0IC0gZGlzdDsgIC8qIHJlc3QgZnJvbSBvdXRwdXQgKi9cbiAgICAgICAgICAgICAgICAgIGZyb21fc291cmNlID0gb3V0cHV0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB3aGlsZSAobGVuID4gMikge1xuICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gZnJvbV9zb3VyY2VbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IGZyb21fc291cmNlW2Zyb20rK107XG4gICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSBmcm9tX3NvdXJjZVtmcm9tKytdO1xuICAgICAgICAgICAgICAgIGxlbiAtPSAzO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChsZW4pIHtcbiAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IGZyb21fc291cmNlW2Zyb20rK107XG4gICAgICAgICAgICAgICAgaWYgKGxlbiA+IDEpIHtcbiAgICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gZnJvbV9zb3VyY2VbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICBmcm9tID0gX291dCAtIGRpc3Q7ICAgICAgICAgIC8qIGNvcHkgZGlyZWN0IGZyb20gb3V0cHV0ICovXG4gICAgICAgICAgICAgIGRvIHsgICAgICAgICAgICAgICAgICAgICAgICAvKiBtaW5pbXVtIGxlbmd0aCBpcyB0aHJlZSAqL1xuICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gb3V0cHV0W2Zyb20rK107XG4gICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSBvdXRwdXRbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IG91dHB1dFtmcm9tKytdO1xuICAgICAgICAgICAgICAgIGxlbiAtPSAzO1xuICAgICAgICAgICAgICB9IHdoaWxlIChsZW4gPiAyKTtcbiAgICAgICAgICAgICAgaWYgKGxlbikge1xuICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gb3V0cHV0W2Zyb20rK107XG4gICAgICAgICAgICAgICAgaWYgKGxlbiA+IDEpIHtcbiAgICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gb3V0cHV0W2Zyb20rK107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGVsc2UgaWYgKChvcCAmIDY0KSA9PT0gMCkgeyAgICAgICAgICAvKiAybmQgbGV2ZWwgZGlzdGFuY2UgY29kZSAqL1xuICAgICAgICAgICAgaGVyZSA9IGRjb2RlWyhoZXJlICYgMHhmZmZmKS8qaGVyZS52YWwqLyArIChob2xkICYgKCgxIDw8IG9wKSAtIDEpKV07XG4gICAgICAgICAgICBjb250aW51ZSBkb2Rpc3Q7XG4gICAgICAgICAgfVxuICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBkaXN0YW5jZSBjb2RlJztcbiAgICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgICBicmVhayB0b3A7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgYnJlYWs7IC8vIG5lZWQgdG8gZW11bGF0ZSBnb3RvIHZpYSBcImNvbnRpbnVlXCJcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoKG9wICYgNjQpID09PSAwKSB7ICAgICAgICAgICAgICAvKiAybmQgbGV2ZWwgbGVuZ3RoIGNvZGUgKi9cbiAgICAgICAgaGVyZSA9IGxjb2RlWyhoZXJlICYgMHhmZmZmKS8qaGVyZS52YWwqLyArIChob2xkICYgKCgxIDw8IG9wKSAtIDEpKV07XG4gICAgICAgIGNvbnRpbnVlIGRvbGVuO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAob3AgJiAzMikgeyAgICAgICAgICAgICAgICAgICAgIC8qIGVuZC1vZi1ibG9jayAqL1xuICAgICAgICAvL1RyYWNldnYoKHN0ZGVyciwgXCJpbmZsYXRlOiAgICAgICAgIGVuZCBvZiBibG9ja1xcblwiKSk7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBUWVBFO1xuICAgICAgICBicmVhayB0b3A7XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBsaXRlcmFsL2xlbmd0aCBjb2RlJztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWsgdG9wO1xuICAgICAgfVxuXG4gICAgICBicmVhazsgLy8gbmVlZCB0byBlbXVsYXRlIGdvdG8gdmlhIFwiY29udGludWVcIlxuICAgIH1cbiAgfSB3aGlsZSAoX2luIDwgbGFzdCAmJiBfb3V0IDwgZW5kKTtcblxuICAvKiByZXR1cm4gdW51c2VkIGJ5dGVzIChvbiBlbnRyeSwgYml0cyA8IDgsIHNvIGluIHdvbid0IGdvIHRvbyBmYXIgYmFjaykgKi9cbiAgbGVuID0gYml0cyA+PiAzO1xuICBfaW4gLT0gbGVuO1xuICBiaXRzIC09IGxlbiA8PCAzO1xuICBob2xkICY9ICgxIDw8IGJpdHMpIC0gMTtcblxuICAvKiB1cGRhdGUgc3RhdGUgYW5kIHJldHVybiAqL1xuICBzdHJtLm5leHRfaW4gPSBfaW47XG4gIHN0cm0ubmV4dF9vdXQgPSBfb3V0O1xuICBzdHJtLmF2YWlsX2luID0gKF9pbiA8IGxhc3QgPyA1ICsgKGxhc3QgLSBfaW4pIDogNSAtIChfaW4gLSBsYXN0KSk7XG4gIHN0cm0uYXZhaWxfb3V0ID0gKF9vdXQgPCBlbmQgPyAyNTcgKyAoZW5kIC0gX291dCkgOiAyNTcgLSAoX291dCAtIGVuZCkpO1xuICBzdGF0ZS5ob2xkID0gaG9sZDtcbiAgc3RhdGUuYml0cyA9IGJpdHM7XG4gIHJldHVybjtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvY29tbW9uJyk7XG52YXIgYWRsZXIzMiA9IHJlcXVpcmUoJy4vYWRsZXIzMicpO1xudmFyIGNyYzMyICAgPSByZXF1aXJlKCcuL2NyYzMyJyk7XG52YXIgaW5mbGF0ZV9mYXN0ID0gcmVxdWlyZSgnLi9pbmZmYXN0Jyk7XG52YXIgaW5mbGF0ZV90YWJsZSA9IHJlcXVpcmUoJy4vaW5mdHJlZXMnKTtcblxudmFyIENPREVTID0gMDtcbnZhciBMRU5TID0gMTtcbnZhciBESVNUUyA9IDI7XG5cbi8qIFB1YmxpYyBjb25zdGFudHMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0qL1xuXG5cbi8qIEFsbG93ZWQgZmx1c2ggdmFsdWVzOyBzZWUgZGVmbGF0ZSgpIGFuZCBpbmZsYXRlKCkgYmVsb3cgZm9yIGRldGFpbHMgKi9cbi8vdmFyIFpfTk9fRkxVU0ggICAgICA9IDA7XG4vL3ZhciBaX1BBUlRJQUxfRkxVU0ggPSAxO1xuLy92YXIgWl9TWU5DX0ZMVVNIICAgID0gMjtcbi8vdmFyIFpfRlVMTF9GTFVTSCAgICA9IDM7XG52YXIgWl9GSU5JU0ggICAgICAgID0gNDtcbnZhciBaX0JMT0NLICAgICAgICAgPSA1O1xudmFyIFpfVFJFRVMgICAgICAgICA9IDY7XG5cblxuLyogUmV0dXJuIGNvZGVzIGZvciB0aGUgY29tcHJlc3Npb24vZGVjb21wcmVzc2lvbiBmdW5jdGlvbnMuIE5lZ2F0aXZlIHZhbHVlc1xuICogYXJlIGVycm9ycywgcG9zaXRpdmUgdmFsdWVzIGFyZSB1c2VkIGZvciBzcGVjaWFsIGJ1dCBub3JtYWwgZXZlbnRzLlxuICovXG52YXIgWl9PSyAgICAgICAgICAgID0gMDtcbnZhciBaX1NUUkVBTV9FTkQgICAgPSAxO1xudmFyIFpfTkVFRF9ESUNUICAgICA9IDI7XG4vL3ZhciBaX0VSUk5PICAgICAgICAgPSAtMTtcbnZhciBaX1NUUkVBTV9FUlJPUiAgPSAtMjtcbnZhciBaX0RBVEFfRVJST1IgICAgPSAtMztcbnZhciBaX01FTV9FUlJPUiAgICAgPSAtNDtcbnZhciBaX0JVRl9FUlJPUiAgICAgPSAtNTtcbi8vdmFyIFpfVkVSU0lPTl9FUlJPUiA9IC02O1xuXG4vKiBUaGUgZGVmbGF0ZSBjb21wcmVzc2lvbiBtZXRob2QgKi9cbnZhciBaX0RFRkxBVEVEICA9IDg7XG5cblxuLyogU1RBVEVTID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cblxudmFyICAgIEhFQUQgPSAxOyAgICAgICAvKiBpOiB3YWl0aW5nIGZvciBtYWdpYyBoZWFkZXIgKi9cbnZhciAgICBGTEFHUyA9IDI7ICAgICAgLyogaTogd2FpdGluZyBmb3IgbWV0aG9kIGFuZCBmbGFncyAoZ3ppcCkgKi9cbnZhciAgICBUSU1FID0gMzsgICAgICAgLyogaTogd2FpdGluZyBmb3IgbW9kaWZpY2F0aW9uIHRpbWUgKGd6aXApICovXG52YXIgICAgT1MgPSA0OyAgICAgICAgIC8qIGk6IHdhaXRpbmcgZm9yIGV4dHJhIGZsYWdzIGFuZCBvcGVyYXRpbmcgc3lzdGVtIChnemlwKSAqL1xudmFyICAgIEVYTEVOID0gNTsgICAgICAvKiBpOiB3YWl0aW5nIGZvciBleHRyYSBsZW5ndGggKGd6aXApICovXG52YXIgICAgRVhUUkEgPSA2OyAgICAgIC8qIGk6IHdhaXRpbmcgZm9yIGV4dHJhIGJ5dGVzIChnemlwKSAqL1xudmFyICAgIE5BTUUgPSA3OyAgICAgICAvKiBpOiB3YWl0aW5nIGZvciBlbmQgb2YgZmlsZSBuYW1lIChnemlwKSAqL1xudmFyICAgIENPTU1FTlQgPSA4OyAgICAvKiBpOiB3YWl0aW5nIGZvciBlbmQgb2YgY29tbWVudCAoZ3ppcCkgKi9cbnZhciAgICBIQ1JDID0gOTsgICAgICAgLyogaTogd2FpdGluZyBmb3IgaGVhZGVyIGNyYyAoZ3ppcCkgKi9cbnZhciAgICBESUNUSUQgPSAxMDsgICAgLyogaTogd2FpdGluZyBmb3IgZGljdGlvbmFyeSBjaGVjayB2YWx1ZSAqL1xudmFyICAgIERJQ1QgPSAxMTsgICAgICAvKiB3YWl0aW5nIGZvciBpbmZsYXRlU2V0RGljdGlvbmFyeSgpIGNhbGwgKi9cbnZhciAgICAgICAgVFlQRSA9IDEyOyAgICAgIC8qIGk6IHdhaXRpbmcgZm9yIHR5cGUgYml0cywgaW5jbHVkaW5nIGxhc3QtZmxhZyBiaXQgKi9cbnZhciAgICAgICAgVFlQRURPID0gMTM7ICAgIC8qIGk6IHNhbWUsIGJ1dCBza2lwIGNoZWNrIHRvIGV4aXQgaW5mbGF0ZSBvbiBuZXcgYmxvY2sgKi9cbnZhciAgICAgICAgU1RPUkVEID0gMTQ7ICAgIC8qIGk6IHdhaXRpbmcgZm9yIHN0b3JlZCBzaXplIChsZW5ndGggYW5kIGNvbXBsZW1lbnQpICovXG52YXIgICAgICAgIENPUFlfID0gMTU7ICAgICAvKiBpL286IHNhbWUgYXMgQ09QWSBiZWxvdywgYnV0IG9ubHkgZmlyc3QgdGltZSBpbiAqL1xudmFyICAgICAgICBDT1BZID0gMTY7ICAgICAgLyogaS9vOiB3YWl0aW5nIGZvciBpbnB1dCBvciBvdXRwdXQgdG8gY29weSBzdG9yZWQgYmxvY2sgKi9cbnZhciAgICAgICAgVEFCTEUgPSAxNzsgICAgIC8qIGk6IHdhaXRpbmcgZm9yIGR5bmFtaWMgYmxvY2sgdGFibGUgbGVuZ3RocyAqL1xudmFyICAgICAgICBMRU5MRU5TID0gMTg7ICAgLyogaTogd2FpdGluZyBmb3IgY29kZSBsZW5ndGggY29kZSBsZW5ndGhzICovXG52YXIgICAgICAgIENPREVMRU5TID0gMTk7ICAvKiBpOiB3YWl0aW5nIGZvciBsZW5ndGgvbGl0IGFuZCBkaXN0YW5jZSBjb2RlIGxlbmd0aHMgKi9cbnZhciAgICAgICAgICAgIExFTl8gPSAyMDsgICAgICAvKiBpOiBzYW1lIGFzIExFTiBiZWxvdywgYnV0IG9ubHkgZmlyc3QgdGltZSBpbiAqL1xudmFyICAgICAgICAgICAgTEVOID0gMjE7ICAgICAgIC8qIGk6IHdhaXRpbmcgZm9yIGxlbmd0aC9saXQvZW9iIGNvZGUgKi9cbnZhciAgICAgICAgICAgIExFTkVYVCA9IDIyOyAgICAvKiBpOiB3YWl0aW5nIGZvciBsZW5ndGggZXh0cmEgYml0cyAqL1xudmFyICAgICAgICAgICAgRElTVCA9IDIzOyAgICAgIC8qIGk6IHdhaXRpbmcgZm9yIGRpc3RhbmNlIGNvZGUgKi9cbnZhciAgICAgICAgICAgIERJU1RFWFQgPSAyNDsgICAvKiBpOiB3YWl0aW5nIGZvciBkaXN0YW5jZSBleHRyYSBiaXRzICovXG52YXIgICAgICAgICAgICBNQVRDSCA9IDI1OyAgICAgLyogbzogd2FpdGluZyBmb3Igb3V0cHV0IHNwYWNlIHRvIGNvcHkgc3RyaW5nICovXG52YXIgICAgICAgICAgICBMSVQgPSAyNjsgICAgICAgLyogbzogd2FpdGluZyBmb3Igb3V0cHV0IHNwYWNlIHRvIHdyaXRlIGxpdGVyYWwgKi9cbnZhciAgICBDSEVDSyA9IDI3OyAgICAgLyogaTogd2FpdGluZyBmb3IgMzItYml0IGNoZWNrIHZhbHVlICovXG52YXIgICAgTEVOR1RIID0gMjg7ICAgIC8qIGk6IHdhaXRpbmcgZm9yIDMyLWJpdCBsZW5ndGggKGd6aXApICovXG52YXIgICAgRE9ORSA9IDI5OyAgICAgIC8qIGZpbmlzaGVkIGNoZWNrLCBkb25lIC0tIHJlbWFpbiBoZXJlIHVudGlsIHJlc2V0ICovXG52YXIgICAgQkFEID0gMzA7ICAgICAgIC8qIGdvdCBhIGRhdGEgZXJyb3IgLS0gcmVtYWluIGhlcmUgdW50aWwgcmVzZXQgKi9cbnZhciAgICBNRU0gPSAzMTsgICAgICAgLyogZ290IGFuIGluZmxhdGUoKSBtZW1vcnkgZXJyb3IgLS0gcmVtYWluIGhlcmUgdW50aWwgcmVzZXQgKi9cbnZhciAgICBTWU5DID0gMzI7ICAgICAgLyogbG9va2luZyBmb3Igc3luY2hyb25pemF0aW9uIGJ5dGVzIHRvIHJlc3RhcnQgaW5mbGF0ZSgpICovXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cblxuXG52YXIgRU5PVUdIX0xFTlMgPSA4NTI7XG52YXIgRU5PVUdIX0RJU1RTID0gNTkyO1xuLy92YXIgRU5PVUdIID0gIChFTk9VR0hfTEVOUytFTk9VR0hfRElTVFMpO1xuXG52YXIgTUFYX1dCSVRTID0gMTU7XG4vKiAzMksgTFo3NyB3aW5kb3cgKi9cbnZhciBERUZfV0JJVFMgPSBNQVhfV0JJVFM7XG5cblxuZnVuY3Rpb24gWlNXQVAzMihxKSB7XG4gIHJldHVybiAgKCgocSA+Pj4gMjQpICYgMHhmZikgK1xuICAgICAgICAgICgocSA+Pj4gOCkgJiAweGZmMDApICtcbiAgICAgICAgICAoKHEgJiAweGZmMDApIDw8IDgpICtcbiAgICAgICAgICAoKHEgJiAweGZmKSA8PCAyNCkpO1xufVxuXG5cbmZ1bmN0aW9uIEluZmxhdGVTdGF0ZSgpIHtcbiAgdGhpcy5tb2RlID0gMDsgICAgICAgICAgICAgLyogY3VycmVudCBpbmZsYXRlIG1vZGUgKi9cbiAgdGhpcy5sYXN0ID0gZmFsc2U7ICAgICAgICAgIC8qIHRydWUgaWYgcHJvY2Vzc2luZyBsYXN0IGJsb2NrICovXG4gIHRoaXMud3JhcCA9IDA7ICAgICAgICAgICAgICAvKiBiaXQgMCB0cnVlIGZvciB6bGliLCBiaXQgMSB0cnVlIGZvciBnemlwICovXG4gIHRoaXMuaGF2ZWRpY3QgPSBmYWxzZTsgICAgICAvKiB0cnVlIGlmIGRpY3Rpb25hcnkgcHJvdmlkZWQgKi9cbiAgdGhpcy5mbGFncyA9IDA7ICAgICAgICAgICAgIC8qIGd6aXAgaGVhZGVyIG1ldGhvZCBhbmQgZmxhZ3MgKDAgaWYgemxpYikgKi9cbiAgdGhpcy5kbWF4ID0gMDsgICAgICAgICAgICAgIC8qIHpsaWIgaGVhZGVyIG1heCBkaXN0YW5jZSAoSU5GTEFURV9TVFJJQ1QpICovXG4gIHRoaXMuY2hlY2sgPSAwOyAgICAgICAgICAgICAvKiBwcm90ZWN0ZWQgY29weSBvZiBjaGVjayB2YWx1ZSAqL1xuICB0aGlzLnRvdGFsID0gMDsgICAgICAgICAgICAgLyogcHJvdGVjdGVkIGNvcHkgb2Ygb3V0cHV0IGNvdW50ICovXG4gIC8vIFRPRE86IG1heSBiZSB7fVxuICB0aGlzLmhlYWQgPSBudWxsOyAgICAgICAgICAgLyogd2hlcmUgdG8gc2F2ZSBnemlwIGhlYWRlciBpbmZvcm1hdGlvbiAqL1xuXG4gIC8qIHNsaWRpbmcgd2luZG93ICovXG4gIHRoaXMud2JpdHMgPSAwOyAgICAgICAgICAgICAvKiBsb2cgYmFzZSAyIG9mIHJlcXVlc3RlZCB3aW5kb3cgc2l6ZSAqL1xuICB0aGlzLndzaXplID0gMDsgICAgICAgICAgICAgLyogd2luZG93IHNpemUgb3IgemVybyBpZiBub3QgdXNpbmcgd2luZG93ICovXG4gIHRoaXMud2hhdmUgPSAwOyAgICAgICAgICAgICAvKiB2YWxpZCBieXRlcyBpbiB0aGUgd2luZG93ICovXG4gIHRoaXMud25leHQgPSAwOyAgICAgICAgICAgICAvKiB3aW5kb3cgd3JpdGUgaW5kZXggKi9cbiAgdGhpcy53aW5kb3cgPSBudWxsOyAgICAgICAgIC8qIGFsbG9jYXRlZCBzbGlkaW5nIHdpbmRvdywgaWYgbmVlZGVkICovXG5cbiAgLyogYml0IGFjY3VtdWxhdG9yICovXG4gIHRoaXMuaG9sZCA9IDA7ICAgICAgICAgICAgICAvKiBpbnB1dCBiaXQgYWNjdW11bGF0b3IgKi9cbiAgdGhpcy5iaXRzID0gMDsgICAgICAgICAgICAgIC8qIG51bWJlciBvZiBiaXRzIGluIFwiaW5cIiAqL1xuXG4gIC8qIGZvciBzdHJpbmcgYW5kIHN0b3JlZCBibG9jayBjb3B5aW5nICovXG4gIHRoaXMubGVuZ3RoID0gMDsgICAgICAgICAgICAvKiBsaXRlcmFsIG9yIGxlbmd0aCBvZiBkYXRhIHRvIGNvcHkgKi9cbiAgdGhpcy5vZmZzZXQgPSAwOyAgICAgICAgICAgIC8qIGRpc3RhbmNlIGJhY2sgdG8gY29weSBzdHJpbmcgZnJvbSAqL1xuXG4gIC8qIGZvciB0YWJsZSBhbmQgY29kZSBkZWNvZGluZyAqL1xuICB0aGlzLmV4dHJhID0gMDsgICAgICAgICAgICAgLyogZXh0cmEgYml0cyBuZWVkZWQgKi9cblxuICAvKiBmaXhlZCBhbmQgZHluYW1pYyBjb2RlIHRhYmxlcyAqL1xuICB0aGlzLmxlbmNvZGUgPSBudWxsOyAgICAgICAgICAvKiBzdGFydGluZyB0YWJsZSBmb3IgbGVuZ3RoL2xpdGVyYWwgY29kZXMgKi9cbiAgdGhpcy5kaXN0Y29kZSA9IG51bGw7ICAgICAgICAgLyogc3RhcnRpbmcgdGFibGUgZm9yIGRpc3RhbmNlIGNvZGVzICovXG4gIHRoaXMubGVuYml0cyA9IDA7ICAgICAgICAgICAvKiBpbmRleCBiaXRzIGZvciBsZW5jb2RlICovXG4gIHRoaXMuZGlzdGJpdHMgPSAwOyAgICAgICAgICAvKiBpbmRleCBiaXRzIGZvciBkaXN0Y29kZSAqL1xuXG4gIC8qIGR5bmFtaWMgdGFibGUgYnVpbGRpbmcgKi9cbiAgdGhpcy5uY29kZSA9IDA7ICAgICAgICAgICAgIC8qIG51bWJlciBvZiBjb2RlIGxlbmd0aCBjb2RlIGxlbmd0aHMgKi9cbiAgdGhpcy5ubGVuID0gMDsgICAgICAgICAgICAgIC8qIG51bWJlciBvZiBsZW5ndGggY29kZSBsZW5ndGhzICovXG4gIHRoaXMubmRpc3QgPSAwOyAgICAgICAgICAgICAvKiBudW1iZXIgb2YgZGlzdGFuY2UgY29kZSBsZW5ndGhzICovXG4gIHRoaXMuaGF2ZSA9IDA7ICAgICAgICAgICAgICAvKiBudW1iZXIgb2YgY29kZSBsZW5ndGhzIGluIGxlbnNbXSAqL1xuICB0aGlzLm5leHQgPSBudWxsOyAgICAgICAgICAgICAgLyogbmV4dCBhdmFpbGFibGUgc3BhY2UgaW4gY29kZXNbXSAqL1xuXG4gIHRoaXMubGVucyA9IG5ldyB1dGlscy5CdWYxNigzMjApOyAvKiB0ZW1wb3Jhcnkgc3RvcmFnZSBmb3IgY29kZSBsZW5ndGhzICovXG4gIHRoaXMud29yayA9IG5ldyB1dGlscy5CdWYxNigyODgpOyAvKiB3b3JrIGFyZWEgZm9yIGNvZGUgdGFibGUgYnVpbGRpbmcgKi9cblxuICAvKlxuICAgYmVjYXVzZSB3ZSBkb24ndCBoYXZlIHBvaW50ZXJzIGluIGpzLCB3ZSB1c2UgbGVuY29kZSBhbmQgZGlzdGNvZGUgZGlyZWN0bHlcbiAgIGFzIGJ1ZmZlcnMgc28gd2UgZG9uJ3QgbmVlZCBjb2Rlc1xuICAqL1xuICAvL3RoaXMuY29kZXMgPSBuZXcgdXRpbHMuQnVmMzIoRU5PVUdIKTsgICAgICAgLyogc3BhY2UgZm9yIGNvZGUgdGFibGVzICovXG4gIHRoaXMubGVuZHluID0gbnVsbDsgICAgICAgICAgICAgIC8qIGR5bmFtaWMgdGFibGUgZm9yIGxlbmd0aC9saXRlcmFsIGNvZGVzIChKUyBzcGVjaWZpYykgKi9cbiAgdGhpcy5kaXN0ZHluID0gbnVsbDsgICAgICAgICAgICAgLyogZHluYW1pYyB0YWJsZSBmb3IgZGlzdGFuY2UgY29kZXMgKEpTIHNwZWNpZmljKSAqL1xuICB0aGlzLnNhbmUgPSAwOyAgICAgICAgICAgICAgICAgICAvKiBpZiBmYWxzZSwgYWxsb3cgaW52YWxpZCBkaXN0YW5jZSB0b28gZmFyICovXG4gIHRoaXMuYmFjayA9IDA7ICAgICAgICAgICAgICAgICAgIC8qIGJpdHMgYmFjayBvZiBsYXN0IHVucHJvY2Vzc2VkIGxlbmd0aC9saXQgKi9cbiAgdGhpcy53YXMgPSAwOyAgICAgICAgICAgICAgICAgICAgLyogaW5pdGlhbCBsZW5ndGggb2YgbWF0Y2ggKi9cbn1cblxuZnVuY3Rpb24gaW5mbGF0ZVJlc2V0S2VlcChzdHJtKSB7XG4gIHZhciBzdGF0ZTtcblxuICBpZiAoIXN0cm0gfHwgIXN0cm0uc3RhdGUpIHsgcmV0dXJuIFpfU1RSRUFNX0VSUk9SOyB9XG4gIHN0YXRlID0gc3RybS5zdGF0ZTtcbiAgc3RybS50b3RhbF9pbiA9IHN0cm0udG90YWxfb3V0ID0gc3RhdGUudG90YWwgPSAwO1xuICBzdHJtLm1zZyA9ICcnOyAvKlpfTlVMTCovXG4gIGlmIChzdGF0ZS53cmFwKSB7ICAgICAgIC8qIHRvIHN1cHBvcnQgaWxsLWNvbmNlaXZlZCBKYXZhIHRlc3Qgc3VpdGUgKi9cbiAgICBzdHJtLmFkbGVyID0gc3RhdGUud3JhcCAmIDE7XG4gIH1cbiAgc3RhdGUubW9kZSA9IEhFQUQ7XG4gIHN0YXRlLmxhc3QgPSAwO1xuICBzdGF0ZS5oYXZlZGljdCA9IDA7XG4gIHN0YXRlLmRtYXggPSAzMjc2ODtcbiAgc3RhdGUuaGVhZCA9IG51bGwvKlpfTlVMTCovO1xuICBzdGF0ZS5ob2xkID0gMDtcbiAgc3RhdGUuYml0cyA9IDA7XG4gIC8vc3RhdGUubGVuY29kZSA9IHN0YXRlLmRpc3Rjb2RlID0gc3RhdGUubmV4dCA9IHN0YXRlLmNvZGVzO1xuICBzdGF0ZS5sZW5jb2RlID0gc3RhdGUubGVuZHluID0gbmV3IHV0aWxzLkJ1ZjMyKEVOT1VHSF9MRU5TKTtcbiAgc3RhdGUuZGlzdGNvZGUgPSBzdGF0ZS5kaXN0ZHluID0gbmV3IHV0aWxzLkJ1ZjMyKEVOT1VHSF9ESVNUUyk7XG5cbiAgc3RhdGUuc2FuZSA9IDE7XG4gIHN0YXRlLmJhY2sgPSAtMTtcbiAgLy9UcmFjZXYoKHN0ZGVyciwgXCJpbmZsYXRlOiByZXNldFxcblwiKSk7XG4gIHJldHVybiBaX09LO1xufVxuXG5mdW5jdGlvbiBpbmZsYXRlUmVzZXQoc3RybSkge1xuICB2YXIgc3RhdGU7XG5cbiAgaWYgKCFzdHJtIHx8ICFzdHJtLnN0YXRlKSB7IHJldHVybiBaX1NUUkVBTV9FUlJPUjsgfVxuICBzdGF0ZSA9IHN0cm0uc3RhdGU7XG4gIHN0YXRlLndzaXplID0gMDtcbiAgc3RhdGUud2hhdmUgPSAwO1xuICBzdGF0ZS53bmV4dCA9IDA7XG4gIHJldHVybiBpbmZsYXRlUmVzZXRLZWVwKHN0cm0pO1xuXG59XG5cbmZ1bmN0aW9uIGluZmxhdGVSZXNldDIoc3RybSwgd2luZG93Qml0cykge1xuICB2YXIgd3JhcDtcbiAgdmFyIHN0YXRlO1xuXG4gIC8qIGdldCB0aGUgc3RhdGUgKi9cbiAgaWYgKCFzdHJtIHx8ICFzdHJtLnN0YXRlKSB7IHJldHVybiBaX1NUUkVBTV9FUlJPUjsgfVxuICBzdGF0ZSA9IHN0cm0uc3RhdGU7XG5cbiAgLyogZXh0cmFjdCB3cmFwIHJlcXVlc3QgZnJvbSB3aW5kb3dCaXRzIHBhcmFtZXRlciAqL1xuICBpZiAod2luZG93Qml0cyA8IDApIHtcbiAgICB3cmFwID0gMDtcbiAgICB3aW5kb3dCaXRzID0gLXdpbmRvd0JpdHM7XG4gIH1cbiAgZWxzZSB7XG4gICAgd3JhcCA9ICh3aW5kb3dCaXRzID4+IDQpICsgMTtcbiAgICBpZiAod2luZG93Qml0cyA8IDQ4KSB7XG4gICAgICB3aW5kb3dCaXRzICY9IDE1O1xuICAgIH1cbiAgfVxuXG4gIC8qIHNldCBudW1iZXIgb2Ygd2luZG93IGJpdHMsIGZyZWUgd2luZG93IGlmIGRpZmZlcmVudCAqL1xuICBpZiAod2luZG93Qml0cyAmJiAod2luZG93Qml0cyA8IDggfHwgd2luZG93Qml0cyA+IDE1KSkge1xuICAgIHJldHVybiBaX1NUUkVBTV9FUlJPUjtcbiAgfVxuICBpZiAoc3RhdGUud2luZG93ICE9PSBudWxsICYmIHN0YXRlLndiaXRzICE9PSB3aW5kb3dCaXRzKSB7XG4gICAgc3RhdGUud2luZG93ID0gbnVsbDtcbiAgfVxuXG4gIC8qIHVwZGF0ZSBzdGF0ZSBhbmQgcmVzZXQgdGhlIHJlc3Qgb2YgaXQgKi9cbiAgc3RhdGUud3JhcCA9IHdyYXA7XG4gIHN0YXRlLndiaXRzID0gd2luZG93Qml0cztcbiAgcmV0dXJuIGluZmxhdGVSZXNldChzdHJtKTtcbn1cblxuZnVuY3Rpb24gaW5mbGF0ZUluaXQyKHN0cm0sIHdpbmRvd0JpdHMpIHtcbiAgdmFyIHJldDtcbiAgdmFyIHN0YXRlO1xuXG4gIGlmICghc3RybSkgeyByZXR1cm4gWl9TVFJFQU1fRVJST1I7IH1cbiAgLy9zdHJtLm1zZyA9IFpfTlVMTDsgICAgICAgICAgICAgICAgIC8qIGluIGNhc2Ugd2UgcmV0dXJuIGFuIGVycm9yICovXG5cbiAgc3RhdGUgPSBuZXcgSW5mbGF0ZVN0YXRlKCk7XG5cbiAgLy9pZiAoc3RhdGUgPT09IFpfTlVMTCkgcmV0dXJuIFpfTUVNX0VSUk9SO1xuICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6IGFsbG9jYXRlZFxcblwiKSk7XG4gIHN0cm0uc3RhdGUgPSBzdGF0ZTtcbiAgc3RhdGUud2luZG93ID0gbnVsbC8qWl9OVUxMKi87XG4gIHJldCA9IGluZmxhdGVSZXNldDIoc3RybSwgd2luZG93Qml0cyk7XG4gIGlmIChyZXQgIT09IFpfT0spIHtcbiAgICBzdHJtLnN0YXRlID0gbnVsbC8qWl9OVUxMKi87XG4gIH1cbiAgcmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gaW5mbGF0ZUluaXQoc3RybSkge1xuICByZXR1cm4gaW5mbGF0ZUluaXQyKHN0cm0sIERFRl9XQklUUyk7XG59XG5cblxuLypcbiBSZXR1cm4gc3RhdGUgd2l0aCBsZW5ndGggYW5kIGRpc3RhbmNlIGRlY29kaW5nIHRhYmxlcyBhbmQgaW5kZXggc2l6ZXMgc2V0IHRvXG4gZml4ZWQgY29kZSBkZWNvZGluZy4gIE5vcm1hbGx5IHRoaXMgcmV0dXJucyBmaXhlZCB0YWJsZXMgZnJvbSBpbmZmaXhlZC5oLlxuIElmIEJVSUxERklYRUQgaXMgZGVmaW5lZCwgdGhlbiBpbnN0ZWFkIHRoaXMgcm91dGluZSBidWlsZHMgdGhlIHRhYmxlcyB0aGVcbiBmaXJzdCB0aW1lIGl0J3MgY2FsbGVkLCBhbmQgcmV0dXJucyB0aG9zZSB0YWJsZXMgdGhlIGZpcnN0IHRpbWUgYW5kXG4gdGhlcmVhZnRlci4gIFRoaXMgcmVkdWNlcyB0aGUgc2l6ZSBvZiB0aGUgY29kZSBieSBhYm91dCAySyBieXRlcywgaW5cbiBleGNoYW5nZSBmb3IgYSBsaXR0bGUgZXhlY3V0aW9uIHRpbWUuICBIb3dldmVyLCBCVUlMREZJWEVEIHNob3VsZCBub3QgYmVcbiB1c2VkIGZvciB0aHJlYWRlZCBhcHBsaWNhdGlvbnMsIHNpbmNlIHRoZSByZXdyaXRpbmcgb2YgdGhlIHRhYmxlcyBhbmQgdmlyZ2luXG4gbWF5IG5vdCBiZSB0aHJlYWQtc2FmZS5cbiAqL1xudmFyIHZpcmdpbiA9IHRydWU7XG5cbnZhciBsZW5maXgsIGRpc3RmaXg7IC8vIFdlIGhhdmUgbm8gcG9pbnRlcnMgaW4gSlMsIHNvIGtlZXAgdGFibGVzIHNlcGFyYXRlXG5cbmZ1bmN0aW9uIGZpeGVkdGFibGVzKHN0YXRlKSB7XG4gIC8qIGJ1aWxkIGZpeGVkIGh1ZmZtYW4gdGFibGVzIGlmIGZpcnN0IGNhbGwgKG1heSBub3QgYmUgdGhyZWFkIHNhZmUpICovXG4gIGlmICh2aXJnaW4pIHtcbiAgICB2YXIgc3ltO1xuXG4gICAgbGVuZml4ID0gbmV3IHV0aWxzLkJ1ZjMyKDUxMik7XG4gICAgZGlzdGZpeCA9IG5ldyB1dGlscy5CdWYzMigzMik7XG5cbiAgICAvKiBsaXRlcmFsL2xlbmd0aCB0YWJsZSAqL1xuICAgIHN5bSA9IDA7XG4gICAgd2hpbGUgKHN5bSA8IDE0NCkgeyBzdGF0ZS5sZW5zW3N5bSsrXSA9IDg7IH1cbiAgICB3aGlsZSAoc3ltIDwgMjU2KSB7IHN0YXRlLmxlbnNbc3ltKytdID0gOTsgfVxuICAgIHdoaWxlIChzeW0gPCAyODApIHsgc3RhdGUubGVuc1tzeW0rK10gPSA3OyB9XG4gICAgd2hpbGUgKHN5bSA8IDI4OCkgeyBzdGF0ZS5sZW5zW3N5bSsrXSA9IDg7IH1cblxuICAgIGluZmxhdGVfdGFibGUoTEVOUywgIHN0YXRlLmxlbnMsIDAsIDI4OCwgbGVuZml4LCAgIDAsIHN0YXRlLndvcmssIHtiaXRzOiA5fSk7XG5cbiAgICAvKiBkaXN0YW5jZSB0YWJsZSAqL1xuICAgIHN5bSA9IDA7XG4gICAgd2hpbGUgKHN5bSA8IDMyKSB7IHN0YXRlLmxlbnNbc3ltKytdID0gNTsgfVxuXG4gICAgaW5mbGF0ZV90YWJsZShESVNUUywgc3RhdGUubGVucywgMCwgMzIsICAgZGlzdGZpeCwgMCwgc3RhdGUud29yaywge2JpdHM6IDV9KTtcblxuICAgIC8qIGRvIHRoaXMganVzdCBvbmNlICovXG4gICAgdmlyZ2luID0gZmFsc2U7XG4gIH1cblxuICBzdGF0ZS5sZW5jb2RlID0gbGVuZml4O1xuICBzdGF0ZS5sZW5iaXRzID0gOTtcbiAgc3RhdGUuZGlzdGNvZGUgPSBkaXN0Zml4O1xuICBzdGF0ZS5kaXN0Yml0cyA9IDU7XG59XG5cblxuLypcbiBVcGRhdGUgdGhlIHdpbmRvdyB3aXRoIHRoZSBsYXN0IHdzaXplIChub3JtYWxseSAzMkspIGJ5dGVzIHdyaXR0ZW4gYmVmb3JlXG4gcmV0dXJuaW5nLiAgSWYgd2luZG93IGRvZXMgbm90IGV4aXN0IHlldCwgY3JlYXRlIGl0LiAgVGhpcyBpcyBvbmx5IGNhbGxlZFxuIHdoZW4gYSB3aW5kb3cgaXMgYWxyZWFkeSBpbiB1c2UsIG9yIHdoZW4gb3V0cHV0IGhhcyBiZWVuIHdyaXR0ZW4gZHVyaW5nIHRoaXNcbiBpbmZsYXRlIGNhbGwsIGJ1dCB0aGUgZW5kIG9mIHRoZSBkZWZsYXRlIHN0cmVhbSBoYXMgbm90IGJlZW4gcmVhY2hlZCB5ZXQuXG4gSXQgaXMgYWxzbyBjYWxsZWQgdG8gY3JlYXRlIGEgd2luZG93IGZvciBkaWN0aW9uYXJ5IGRhdGEgd2hlbiBhIGRpY3Rpb25hcnlcbiBpcyBsb2FkZWQuXG5cbiBQcm92aWRpbmcgb3V0cHV0IGJ1ZmZlcnMgbGFyZ2VyIHRoYW4gMzJLIHRvIGluZmxhdGUoKSBzaG91bGQgcHJvdmlkZSBhIHNwZWVkXG4gYWR2YW50YWdlLCBzaW5jZSBvbmx5IHRoZSBsYXN0IDMySyBvZiBvdXRwdXQgaXMgY29waWVkIHRvIHRoZSBzbGlkaW5nIHdpbmRvd1xuIHVwb24gcmV0dXJuIGZyb20gaW5mbGF0ZSgpLCBhbmQgc2luY2UgYWxsIGRpc3RhbmNlcyBhZnRlciB0aGUgZmlyc3QgMzJLIG9mXG4gb3V0cHV0IHdpbGwgZmFsbCBpbiB0aGUgb3V0cHV0IGRhdGEsIG1ha2luZyBtYXRjaCBjb3BpZXMgc2ltcGxlciBhbmQgZmFzdGVyLlxuIFRoZSBhZHZhbnRhZ2UgbWF5IGJlIGRlcGVuZGVudCBvbiB0aGUgc2l6ZSBvZiB0aGUgcHJvY2Vzc29yJ3MgZGF0YSBjYWNoZXMuXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZXdpbmRvdyhzdHJtLCBzcmMsIGVuZCwgY29weSkge1xuICB2YXIgZGlzdDtcbiAgdmFyIHN0YXRlID0gc3RybS5zdGF0ZTtcblxuICAvKiBpZiBpdCBoYXNuJ3QgYmVlbiBkb25lIGFscmVhZHksIGFsbG9jYXRlIHNwYWNlIGZvciB0aGUgd2luZG93ICovXG4gIGlmIChzdGF0ZS53aW5kb3cgPT09IG51bGwpIHtcbiAgICBzdGF0ZS53c2l6ZSA9IDEgPDwgc3RhdGUud2JpdHM7XG4gICAgc3RhdGUud25leHQgPSAwO1xuICAgIHN0YXRlLndoYXZlID0gMDtcblxuICAgIHN0YXRlLndpbmRvdyA9IG5ldyB1dGlscy5CdWY4KHN0YXRlLndzaXplKTtcbiAgfVxuXG4gIC8qIGNvcHkgc3RhdGUtPndzaXplIG9yIGxlc3Mgb3V0cHV0IGJ5dGVzIGludG8gdGhlIGNpcmN1bGFyIHdpbmRvdyAqL1xuICBpZiAoY29weSA+PSBzdGF0ZS53c2l6ZSkge1xuICAgIHV0aWxzLmFycmF5U2V0KHN0YXRlLndpbmRvdyxzcmMsIGVuZCAtIHN0YXRlLndzaXplLCBzdGF0ZS53c2l6ZSwgMCk7XG4gICAgc3RhdGUud25leHQgPSAwO1xuICAgIHN0YXRlLndoYXZlID0gc3RhdGUud3NpemU7XG4gIH1cbiAgZWxzZSB7XG4gICAgZGlzdCA9IHN0YXRlLndzaXplIC0gc3RhdGUud25leHQ7XG4gICAgaWYgKGRpc3QgPiBjb3B5KSB7XG4gICAgICBkaXN0ID0gY29weTtcbiAgICB9XG4gICAgLy96bWVtY3B5KHN0YXRlLT53aW5kb3cgKyBzdGF0ZS0+d25leHQsIGVuZCAtIGNvcHksIGRpc3QpO1xuICAgIHV0aWxzLmFycmF5U2V0KHN0YXRlLndpbmRvdyxzcmMsIGVuZCAtIGNvcHksIGRpc3QsIHN0YXRlLnduZXh0KTtcbiAgICBjb3B5IC09IGRpc3Q7XG4gICAgaWYgKGNvcHkpIHtcbiAgICAgIC8vem1lbWNweShzdGF0ZS0+d2luZG93LCBlbmQgLSBjb3B5LCBjb3B5KTtcbiAgICAgIHV0aWxzLmFycmF5U2V0KHN0YXRlLndpbmRvdyxzcmMsIGVuZCAtIGNvcHksIGNvcHksIDApO1xuICAgICAgc3RhdGUud25leHQgPSBjb3B5O1xuICAgICAgc3RhdGUud2hhdmUgPSBzdGF0ZS53c2l6ZTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICBzdGF0ZS53bmV4dCArPSBkaXN0O1xuICAgICAgaWYgKHN0YXRlLnduZXh0ID09PSBzdGF0ZS53c2l6ZSkgeyBzdGF0ZS53bmV4dCA9IDA7IH1cbiAgICAgIGlmIChzdGF0ZS53aGF2ZSA8IHN0YXRlLndzaXplKSB7IHN0YXRlLndoYXZlICs9IGRpc3Q7IH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIDA7XG59XG5cbmZ1bmN0aW9uIGluZmxhdGUoc3RybSwgZmx1c2gpIHtcbiAgdmFyIHN0YXRlO1xuICB2YXIgaW5wdXQsIG91dHB1dDsgICAgICAgICAgLy8gaW5wdXQvb3V0cHV0IGJ1ZmZlcnNcbiAgdmFyIG5leHQ7ICAgICAgICAgICAgICAgICAgIC8qIG5leHQgaW5wdXQgSU5ERVggKi9cbiAgdmFyIHB1dDsgICAgICAgICAgICAgICAgICAgIC8qIG5leHQgb3V0cHV0IElOREVYICovXG4gIHZhciBoYXZlLCBsZWZ0OyAgICAgICAgICAgICAvKiBhdmFpbGFibGUgaW5wdXQgYW5kIG91dHB1dCAqL1xuICB2YXIgaG9sZDsgICAgICAgICAgICAgICAgICAgLyogYml0IGJ1ZmZlciAqL1xuICB2YXIgYml0czsgICAgICAgICAgICAgICAgICAgLyogYml0cyBpbiBiaXQgYnVmZmVyICovXG4gIHZhciBfaW4sIF9vdXQ7ICAgICAgICAgICAgICAvKiBzYXZlIHN0YXJ0aW5nIGF2YWlsYWJsZSBpbnB1dCBhbmQgb3V0cHV0ICovXG4gIHZhciBjb3B5OyAgICAgICAgICAgICAgICAgICAvKiBudW1iZXIgb2Ygc3RvcmVkIG9yIG1hdGNoIGJ5dGVzIHRvIGNvcHkgKi9cbiAgdmFyIGZyb207ICAgICAgICAgICAgICAgICAgIC8qIHdoZXJlIHRvIGNvcHkgbWF0Y2ggYnl0ZXMgZnJvbSAqL1xuICB2YXIgZnJvbV9zb3VyY2U7XG4gIHZhciBoZXJlID0gMDsgICAgICAgICAgICAgICAvKiBjdXJyZW50IGRlY29kaW5nIHRhYmxlIGVudHJ5ICovXG4gIHZhciBoZXJlX2JpdHMsIGhlcmVfb3AsIGhlcmVfdmFsOyAvLyBwYWtlZCBcImhlcmVcIiBkZW5vcm1hbGl6ZWQgKEpTIHNwZWNpZmljKVxuICAvL3ZhciBsYXN0OyAgICAgICAgICAgICAgICAgICAvKiBwYXJlbnQgdGFibGUgZW50cnkgKi9cbiAgdmFyIGxhc3RfYml0cywgbGFzdF9vcCwgbGFzdF92YWw7IC8vIHBha2VkIFwibGFzdFwiIGRlbm9ybWFsaXplZCAoSlMgc3BlY2lmaWMpXG4gIHZhciBsZW47ICAgICAgICAgICAgICAgICAgICAvKiBsZW5ndGggdG8gY29weSBmb3IgcmVwZWF0cywgYml0cyB0byBkcm9wICovXG4gIHZhciByZXQ7ICAgICAgICAgICAgICAgICAgICAvKiByZXR1cm4gY29kZSAqL1xuICB2YXIgaGJ1ZiA9IG5ldyB1dGlscy5CdWY4KDQpOyAgICAvKiBidWZmZXIgZm9yIGd6aXAgaGVhZGVyIGNyYyBjYWxjdWxhdGlvbiAqL1xuICB2YXIgb3B0cztcblxuICB2YXIgbjsgLy8gdGVtcG9yYXJ5IHZhciBmb3IgTkVFRF9CSVRTXG5cbiAgdmFyIG9yZGVyID0gLyogcGVybXV0YXRpb24gb2YgY29kZSBsZW5ndGhzICovXG4gICAgWzE2LCAxNywgMTgsIDAsIDgsIDcsIDksIDYsIDEwLCA1LCAxMSwgNCwgMTIsIDMsIDEzLCAyLCAxNCwgMSwgMTVdO1xuXG5cbiAgaWYgKCFzdHJtIHx8ICFzdHJtLnN0YXRlIHx8ICFzdHJtLm91dHB1dCB8fFxuICAgICAgKCFzdHJtLmlucHV0ICYmIHN0cm0uYXZhaWxfaW4gIT09IDApKSB7XG4gICAgcmV0dXJuIFpfU1RSRUFNX0VSUk9SO1xuICB9XG5cbiAgc3RhdGUgPSBzdHJtLnN0YXRlO1xuICBpZiAoc3RhdGUubW9kZSA9PT0gVFlQRSkgeyBzdGF0ZS5tb2RlID0gVFlQRURPOyB9ICAgIC8qIHNraXAgY2hlY2sgKi9cblxuXG4gIC8vLS0tIExPQUQoKSAtLS1cbiAgcHV0ID0gc3RybS5uZXh0X291dDtcbiAgb3V0cHV0ID0gc3RybS5vdXRwdXQ7XG4gIGxlZnQgPSBzdHJtLmF2YWlsX291dDtcbiAgbmV4dCA9IHN0cm0ubmV4dF9pbjtcbiAgaW5wdXQgPSBzdHJtLmlucHV0O1xuICBoYXZlID0gc3RybS5hdmFpbF9pbjtcbiAgaG9sZCA9IHN0YXRlLmhvbGQ7XG4gIGJpdHMgPSBzdGF0ZS5iaXRzO1xuICAvLy0tLVxuXG4gIF9pbiA9IGhhdmU7XG4gIF9vdXQgPSBsZWZ0O1xuICByZXQgPSBaX09LO1xuXG4gIGluZl9sZWF2ZTogLy8gZ290byBlbXVsYXRpb25cbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoc3RhdGUubW9kZSkge1xuICAgIGNhc2UgSEVBRDpcbiAgICAgIGlmIChzdGF0ZS53cmFwID09PSAwKSB7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBUWVBFRE87XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgLy89PT0gTkVFREJJVFMoMTYpO1xuICAgICAgd2hpbGUgKGJpdHMgPCAxNikge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgfVxuICAgICAgLy89PT0vL1xuICAgICAgaWYgKChzdGF0ZS53cmFwICYgMikgJiYgaG9sZCA9PT0gMHg4YjFmKSB7ICAvKiBnemlwIGhlYWRlciAqL1xuICAgICAgICBzdGF0ZS5jaGVjayA9IDAvKmNyYzMyKDBMLCBaX05VTEwsIDApKi87XG4gICAgICAgIC8vPT09IENSQzIoc3RhdGUuY2hlY2ssIGhvbGQpO1xuICAgICAgICBoYnVmWzBdID0gaG9sZCAmIDB4ZmY7XG4gICAgICAgIGhidWZbMV0gPSAoaG9sZCA+Pj4gOCkgJiAweGZmO1xuICAgICAgICBzdGF0ZS5jaGVjayA9IGNyYzMyKHN0YXRlLmNoZWNrLCBoYnVmLCAyLCAwKTtcbiAgICAgICAgLy89PT0vL1xuXG4gICAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICAgIGhvbGQgPSAwO1xuICAgICAgICBiaXRzID0gMDtcbiAgICAgICAgLy89PT0vL1xuICAgICAgICBzdGF0ZS5tb2RlID0gRkxBR1M7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgc3RhdGUuZmxhZ3MgPSAwOyAgICAgICAgICAgLyogZXhwZWN0IHpsaWIgaGVhZGVyICovXG4gICAgICBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICBzdGF0ZS5oZWFkLmRvbmUgPSBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGlmICghKHN0YXRlLndyYXAgJiAxKSB8fCAgIC8qIGNoZWNrIGlmIHpsaWIgaGVhZGVyIGFsbG93ZWQgKi9cbiAgICAgICAgKCgoaG9sZCAmIDB4ZmYpLypCSVRTKDgpKi8gPDwgOCkgKyAoaG9sZCA+PiA4KSkgJSAzMSkge1xuICAgICAgICBzdHJtLm1zZyA9ICdpbmNvcnJlY3QgaGVhZGVyIGNoZWNrJztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoKGhvbGQgJiAweDBmKS8qQklUUyg0KSovICE9PSBaX0RFRkxBVEVEKSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ3Vua25vd24gY29tcHJlc3Npb24gbWV0aG9kJztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAvLy0tLSBEUk9QQklUUyg0KSAtLS0vL1xuICAgICAgaG9sZCA+Pj49IDQ7XG4gICAgICBiaXRzIC09IDQ7XG4gICAgICAvLy0tLS8vXG4gICAgICBsZW4gPSAoaG9sZCAmIDB4MGYpLypCSVRTKDQpKi8gKyA4O1xuICAgICAgaWYgKHN0YXRlLndiaXRzID09PSAwKSB7XG4gICAgICAgIHN0YXRlLndiaXRzID0gbGVuO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAobGVuID4gc3RhdGUud2JpdHMpIHtcbiAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCB3aW5kb3cgc2l6ZSc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgc3RhdGUuZG1heCA9IDEgPDwgbGVuO1xuICAgICAgLy9UcmFjZXYoKHN0ZGVyciwgXCJpbmZsYXRlOiAgIHpsaWIgaGVhZGVyIG9rXFxuXCIpKTtcbiAgICAgIHN0cm0uYWRsZXIgPSBzdGF0ZS5jaGVjayA9IDEvKmFkbGVyMzIoMEwsIFpfTlVMTCwgMCkqLztcbiAgICAgIHN0YXRlLm1vZGUgPSBob2xkICYgMHgyMDAgPyBESUNUSUQgOiBUWVBFO1xuICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgIGhvbGQgPSAwO1xuICAgICAgYml0cyA9IDA7XG4gICAgICAvLz09PS8vXG4gICAgICBicmVhaztcbiAgICBjYXNlIEZMQUdTOlxuICAgICAgLy89PT0gTkVFREJJVFMoMTYpOyAqL1xuICAgICAgd2hpbGUgKGJpdHMgPCAxNikge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgfVxuICAgICAgLy89PT0vL1xuICAgICAgc3RhdGUuZmxhZ3MgPSBob2xkO1xuICAgICAgaWYgKChzdGF0ZS5mbGFncyAmIDB4ZmYpICE9PSBaX0RFRkxBVEVEKSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ3Vua25vd24gY29tcHJlc3Npb24gbWV0aG9kJztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoc3RhdGUuZmxhZ3MgJiAweGUwMDApIHtcbiAgICAgICAgc3RybS5tc2cgPSAndW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0JztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICBzdGF0ZS5oZWFkLnRleHQgPSAoKGhvbGQgPj4gOCkgJiAxKTtcbiAgICAgIH1cbiAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDIwMCkge1xuICAgICAgICAvLz09PSBDUkMyKHN0YXRlLmNoZWNrLCBob2xkKTtcbiAgICAgICAgaGJ1ZlswXSA9IGhvbGQgJiAweGZmO1xuICAgICAgICBoYnVmWzFdID0gKGhvbGQgPj4+IDgpICYgMHhmZjtcbiAgICAgICAgc3RhdGUuY2hlY2sgPSBjcmMzMihzdGF0ZS5jaGVjaywgaGJ1ZiwgMiwgMCk7XG4gICAgICAgIC8vPT09Ly9cbiAgICAgIH1cbiAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICBob2xkID0gMDtcbiAgICAgIGJpdHMgPSAwO1xuICAgICAgLy89PT0vL1xuICAgICAgc3RhdGUubW9kZSA9IFRJTUU7XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBUSU1FOlxuICAgICAgLy89PT0gTkVFREJJVFMoMzIpOyAqL1xuICAgICAgd2hpbGUgKGJpdHMgPCAzMikge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgfVxuICAgICAgLy89PT0vL1xuICAgICAgaWYgKHN0YXRlLmhlYWQpIHtcbiAgICAgICAgc3RhdGUuaGVhZC50aW1lID0gaG9sZDtcbiAgICAgIH1cbiAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDIwMCkge1xuICAgICAgICAvLz09PSBDUkM0KHN0YXRlLmNoZWNrLCBob2xkKVxuICAgICAgICBoYnVmWzBdID0gaG9sZCAmIDB4ZmY7XG4gICAgICAgIGhidWZbMV0gPSAoaG9sZCA+Pj4gOCkgJiAweGZmO1xuICAgICAgICBoYnVmWzJdID0gKGhvbGQgPj4+IDE2KSAmIDB4ZmY7XG4gICAgICAgIGhidWZbM10gPSAoaG9sZCA+Pj4gMjQpICYgMHhmZjtcbiAgICAgICAgc3RhdGUuY2hlY2sgPSBjcmMzMihzdGF0ZS5jaGVjaywgaGJ1ZiwgNCwgMCk7XG4gICAgICAgIC8vPT09XG4gICAgICB9XG4gICAgICAvLz09PSBJTklUQklUUygpO1xuICAgICAgaG9sZCA9IDA7XG4gICAgICBiaXRzID0gMDtcbiAgICAgIC8vPT09Ly9cbiAgICAgIHN0YXRlLm1vZGUgPSBPUztcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIE9TOlxuICAgICAgLy89PT0gTkVFREJJVFMoMTYpOyAqL1xuICAgICAgd2hpbGUgKGJpdHMgPCAxNikge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgfVxuICAgICAgLy89PT0vL1xuICAgICAgaWYgKHN0YXRlLmhlYWQpIHtcbiAgICAgICAgc3RhdGUuaGVhZC54ZmxhZ3MgPSAoaG9sZCAmIDB4ZmYpO1xuICAgICAgICBzdGF0ZS5oZWFkLm9zID0gKGhvbGQgPj4gOCk7XG4gICAgICB9XG4gICAgICBpZiAoc3RhdGUuZmxhZ3MgJiAweDAyMDApIHtcbiAgICAgICAgLy89PT0gQ1JDMihzdGF0ZS5jaGVjaywgaG9sZCk7XG4gICAgICAgIGhidWZbMF0gPSBob2xkICYgMHhmZjtcbiAgICAgICAgaGJ1ZlsxXSA9IChob2xkID4+PiA4KSAmIDB4ZmY7XG4gICAgICAgIHN0YXRlLmNoZWNrID0gY3JjMzIoc3RhdGUuY2hlY2ssIGhidWYsIDIsIDApO1xuICAgICAgICAvLz09PS8vXG4gICAgICB9XG4gICAgICAvLz09PSBJTklUQklUUygpO1xuICAgICAgaG9sZCA9IDA7XG4gICAgICBiaXRzID0gMDtcbiAgICAgIC8vPT09Ly9cbiAgICAgIHN0YXRlLm1vZGUgPSBFWExFTjtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIEVYTEVOOlxuICAgICAgaWYgKHN0YXRlLmZsYWdzICYgMHgwNDAwKSB7XG4gICAgICAgIC8vPT09IE5FRURCSVRTKDE2KTsgKi9cbiAgICAgICAgd2hpbGUgKGJpdHMgPCAxNikge1xuICAgICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICAgIGhhdmUtLTtcbiAgICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgIH1cbiAgICAgICAgLy89PT0vL1xuICAgICAgICBzdGF0ZS5sZW5ndGggPSBob2xkO1xuICAgICAgICBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICAgIHN0YXRlLmhlYWQuZXh0cmFfbGVuID0gaG9sZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3RhdGUuZmxhZ3MgJiAweDAyMDApIHtcbiAgICAgICAgICAvLz09PSBDUkMyKHN0YXRlLmNoZWNrLCBob2xkKTtcbiAgICAgICAgICBoYnVmWzBdID0gaG9sZCAmIDB4ZmY7XG4gICAgICAgICAgaGJ1ZlsxXSA9IChob2xkID4+PiA4KSAmIDB4ZmY7XG4gICAgICAgICAgc3RhdGUuY2hlY2sgPSBjcmMzMihzdGF0ZS5jaGVjaywgaGJ1ZiwgMiwgMCk7XG4gICAgICAgICAgLy89PT0vL1xuICAgICAgICB9XG4gICAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICAgIGhvbGQgPSAwO1xuICAgICAgICBiaXRzID0gMDtcbiAgICAgICAgLy89PT0vL1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICBzdGF0ZS5oZWFkLmV4dHJhID0gbnVsbC8qWl9OVUxMKi87XG4gICAgICB9XG4gICAgICBzdGF0ZS5tb2RlID0gRVhUUkE7XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBFWFRSQTpcbiAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDQwMCkge1xuICAgICAgICBjb3B5ID0gc3RhdGUubGVuZ3RoO1xuICAgICAgICBpZiAoY29weSA+IGhhdmUpIHsgY29weSA9IGhhdmU7IH1cbiAgICAgICAgaWYgKGNvcHkpIHtcbiAgICAgICAgICBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICAgICAgbGVuID0gc3RhdGUuaGVhZC5leHRyYV9sZW4gLSBzdGF0ZS5sZW5ndGg7XG4gICAgICAgICAgICBpZiAoIXN0YXRlLmhlYWQuZXh0cmEpIHtcbiAgICAgICAgICAgICAgLy8gVXNlIHVudHlwZWQgYXJyYXkgZm9yIG1vcmUgY29udmVuaWVuZCBwcm9jZXNzaW5nIGxhdGVyXG4gICAgICAgICAgICAgIHN0YXRlLmhlYWQuZXh0cmEgPSBuZXcgQXJyYXkoc3RhdGUuaGVhZC5leHRyYV9sZW4pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdXRpbHMuYXJyYXlTZXQoXG4gICAgICAgICAgICAgIHN0YXRlLmhlYWQuZXh0cmEsXG4gICAgICAgICAgICAgIGlucHV0LFxuICAgICAgICAgICAgICBuZXh0LFxuICAgICAgICAgICAgICAvLyBleHRyYSBmaWVsZCBpcyBsaW1pdGVkIHRvIDY1NTM2IGJ5dGVzXG4gICAgICAgICAgICAgIC8vIC0gbm8gbmVlZCBmb3IgYWRkaXRpb25hbCBzaXplIGNoZWNrXG4gICAgICAgICAgICAgIGNvcHksXG4gICAgICAgICAgICAgIC8qbGVuICsgY29weSA+IHN0YXRlLmhlYWQuZXh0cmFfbWF4IC0gbGVuID8gc3RhdGUuaGVhZC5leHRyYV9tYXggOiBjb3B5LCovXG4gICAgICAgICAgICAgIGxlblxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIC8vem1lbWNweShzdGF0ZS5oZWFkLmV4dHJhICsgbGVuLCBuZXh0LFxuICAgICAgICAgICAgLy8gICAgICAgIGxlbiArIGNvcHkgPiBzdGF0ZS5oZWFkLmV4dHJhX21heCA/XG4gICAgICAgICAgICAvLyAgICAgICAgc3RhdGUuaGVhZC5leHRyYV9tYXggLSBsZW4gOiBjb3B5KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHN0YXRlLmZsYWdzICYgMHgwMjAwKSB7XG4gICAgICAgICAgICBzdGF0ZS5jaGVjayA9IGNyYzMyKHN0YXRlLmNoZWNrLCBpbnB1dCwgY29weSwgbmV4dCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGhhdmUgLT0gY29weTtcbiAgICAgICAgICBuZXh0ICs9IGNvcHk7XG4gICAgICAgICAgc3RhdGUubGVuZ3RoIC09IGNvcHk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHN0YXRlLmxlbmd0aCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgIH1cbiAgICAgIHN0YXRlLmxlbmd0aCA9IDA7XG4gICAgICBzdGF0ZS5tb2RlID0gTkFNRTtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIE5BTUU6XG4gICAgICBpZiAoc3RhdGUuZmxhZ3MgJiAweDA4MDApIHtcbiAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgIGNvcHkgPSAwO1xuICAgICAgICBkbyB7XG4gICAgICAgICAgLy8gVE9ETzogMiBvciAxIGJ5dGVzP1xuICAgICAgICAgIGxlbiA9IGlucHV0W25leHQgKyBjb3B5KytdO1xuICAgICAgICAgIC8qIHVzZSBjb25zdGFudCBsaW1pdCBiZWNhdXNlIGluIGpzIHdlIHNob3VsZCBub3QgcHJlYWxsb2NhdGUgbWVtb3J5ICovXG4gICAgICAgICAgaWYgKHN0YXRlLmhlYWQgJiYgbGVuICYmXG4gICAgICAgICAgICAgIChzdGF0ZS5sZW5ndGggPCA2NTUzNiAvKnN0YXRlLmhlYWQubmFtZV9tYXgqLykpIHtcbiAgICAgICAgICAgIHN0YXRlLmhlYWQubmFtZSArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGxlbik7XG4gICAgICAgICAgfVxuICAgICAgICB9IHdoaWxlIChsZW4gJiYgY29weSA8IGhhdmUpO1xuXG4gICAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDIwMCkge1xuICAgICAgICAgIHN0YXRlLmNoZWNrID0gY3JjMzIoc3RhdGUuY2hlY2ssIGlucHV0LCBjb3B5LCBuZXh0KTtcbiAgICAgICAgfVxuICAgICAgICBoYXZlIC09IGNvcHk7XG4gICAgICAgIG5leHQgKz0gY29weTtcbiAgICAgICAgaWYgKGxlbikgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKHN0YXRlLmhlYWQpIHtcbiAgICAgICAgc3RhdGUuaGVhZC5uYW1lID0gbnVsbDtcbiAgICAgIH1cbiAgICAgIHN0YXRlLmxlbmd0aCA9IDA7XG4gICAgICBzdGF0ZS5tb2RlID0gQ09NTUVOVDtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIENPTU1FTlQ6XG4gICAgICBpZiAoc3RhdGUuZmxhZ3MgJiAweDEwMDApIHtcbiAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgIGNvcHkgPSAwO1xuICAgICAgICBkbyB7XG4gICAgICAgICAgbGVuID0gaW5wdXRbbmV4dCArIGNvcHkrK107XG4gICAgICAgICAgLyogdXNlIGNvbnN0YW50IGxpbWl0IGJlY2F1c2UgaW4ganMgd2Ugc2hvdWxkIG5vdCBwcmVhbGxvY2F0ZSBtZW1vcnkgKi9cbiAgICAgICAgICBpZiAoc3RhdGUuaGVhZCAmJiBsZW4gJiZcbiAgICAgICAgICAgICAgKHN0YXRlLmxlbmd0aCA8IDY1NTM2IC8qc3RhdGUuaGVhZC5jb21tX21heCovKSkge1xuICAgICAgICAgICAgc3RhdGUuaGVhZC5jb21tZW50ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUobGVuKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gd2hpbGUgKGxlbiAmJiBjb3B5IDwgaGF2ZSk7XG4gICAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDIwMCkge1xuICAgICAgICAgIHN0YXRlLmNoZWNrID0gY3JjMzIoc3RhdGUuY2hlY2ssIGlucHV0LCBjb3B5LCBuZXh0KTtcbiAgICAgICAgfVxuICAgICAgICBoYXZlIC09IGNvcHk7XG4gICAgICAgIG5leHQgKz0gY29weTtcbiAgICAgICAgaWYgKGxlbikgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKHN0YXRlLmhlYWQpIHtcbiAgICAgICAgc3RhdGUuaGVhZC5jb21tZW50ID0gbnVsbDtcbiAgICAgIH1cbiAgICAgIHN0YXRlLm1vZGUgPSBIQ1JDO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgSENSQzpcbiAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDIwMCkge1xuICAgICAgICAvLz09PSBORUVEQklUUygxNik7ICovXG4gICAgICAgIHdoaWxlIChiaXRzIDwgMTYpIHtcbiAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICBoYXZlLS07XG4gICAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICB9XG4gICAgICAgIC8vPT09Ly9cbiAgICAgICAgaWYgKGhvbGQgIT09IChzdGF0ZS5jaGVjayAmIDB4ZmZmZikpIHtcbiAgICAgICAgICBzdHJtLm1zZyA9ICdoZWFkZXIgY3JjIG1pc21hdGNoJztcbiAgICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICAgIGhvbGQgPSAwO1xuICAgICAgICBiaXRzID0gMDtcbiAgICAgICAgLy89PT0vL1xuICAgICAgfVxuICAgICAgaWYgKHN0YXRlLmhlYWQpIHtcbiAgICAgICAgc3RhdGUuaGVhZC5oY3JjID0gKChzdGF0ZS5mbGFncyA+PiA5KSAmIDEpO1xuICAgICAgICBzdGF0ZS5oZWFkLmRvbmUgPSB0cnVlO1xuICAgICAgfVxuICAgICAgc3RybS5hZGxlciA9IHN0YXRlLmNoZWNrID0gMCAvKmNyYzMyKDBMLCBaX05VTEwsIDApKi87XG4gICAgICBzdGF0ZS5tb2RlID0gVFlQRTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgRElDVElEOlxuICAgICAgLy89PT0gTkVFREJJVFMoMzIpOyAqL1xuICAgICAgd2hpbGUgKGJpdHMgPCAzMikge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgfVxuICAgICAgLy89PT0vL1xuICAgICAgc3RybS5hZGxlciA9IHN0YXRlLmNoZWNrID0gWlNXQVAzMihob2xkKTtcbiAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICBob2xkID0gMDtcbiAgICAgIGJpdHMgPSAwO1xuICAgICAgLy89PT0vL1xuICAgICAgc3RhdGUubW9kZSA9IERJQ1Q7XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBESUNUOlxuICAgICAgaWYgKHN0YXRlLmhhdmVkaWN0ID09PSAwKSB7XG4gICAgICAgIC8vLS0tIFJFU1RPUkUoKSAtLS1cbiAgICAgICAgc3RybS5uZXh0X291dCA9IHB1dDtcbiAgICAgICAgc3RybS5hdmFpbF9vdXQgPSBsZWZ0O1xuICAgICAgICBzdHJtLm5leHRfaW4gPSBuZXh0O1xuICAgICAgICBzdHJtLmF2YWlsX2luID0gaGF2ZTtcbiAgICAgICAgc3RhdGUuaG9sZCA9IGhvbGQ7XG4gICAgICAgIHN0YXRlLmJpdHMgPSBiaXRzO1xuICAgICAgICAvLy0tLVxuICAgICAgICByZXR1cm4gWl9ORUVEX0RJQ1Q7XG4gICAgICB9XG4gICAgICBzdHJtLmFkbGVyID0gc3RhdGUuY2hlY2sgPSAxLyphZGxlcjMyKDBMLCBaX05VTEwsIDApKi87XG4gICAgICBzdGF0ZS5tb2RlID0gVFlQRTtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIFRZUEU6XG4gICAgICBpZiAoZmx1c2ggPT09IFpfQkxPQ0sgfHwgZmx1c2ggPT09IFpfVFJFRVMpIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBUWVBFRE86XG4gICAgICBpZiAoc3RhdGUubGFzdCkge1xuICAgICAgICAvLy0tLSBCWVRFQklUUygpIC0tLS8vXG4gICAgICAgIGhvbGQgPj4+PSBiaXRzICYgNztcbiAgICAgICAgYml0cyAtPSBiaXRzICYgNztcbiAgICAgICAgLy8tLS0vL1xuICAgICAgICBzdGF0ZS5tb2RlID0gQ0hFQ0s7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgLy89PT0gTkVFREJJVFMoMyk7ICovXG4gICAgICB3aGlsZSAoYml0cyA8IDMpIHtcbiAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgIGhhdmUtLTtcbiAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgIGJpdHMgKz0gODtcbiAgICAgIH1cbiAgICAgIC8vPT09Ly9cbiAgICAgIHN0YXRlLmxhc3QgPSAoaG9sZCAmIDB4MDEpLypCSVRTKDEpKi87XG4gICAgICAvLy0tLSBEUk9QQklUUygxKSAtLS0vL1xuICAgICAgaG9sZCA+Pj49IDE7XG4gICAgICBiaXRzIC09IDE7XG4gICAgICAvLy0tLS8vXG5cbiAgICAgIHN3aXRjaCAoKGhvbGQgJiAweDAzKS8qQklUUygyKSovKSB7XG4gICAgICBjYXNlIDA6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBzdG9yZWQgYmxvY2sgKi9cbiAgICAgICAgLy9UcmFjZXYoKHN0ZGVyciwgXCJpbmZsYXRlOiAgICAgc3RvcmVkIGJsb2NrJXNcXG5cIixcbiAgICAgICAgLy8gICAgICAgIHN0YXRlLmxhc3QgPyBcIiAobGFzdClcIiA6IFwiXCIpKTtcbiAgICAgICAgc3RhdGUubW9kZSA9IFNUT1JFRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDE6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBmaXhlZCBibG9jayAqL1xuICAgICAgICBmaXhlZHRhYmxlcyhzdGF0ZSk7XG4gICAgICAgIC8vVHJhY2V2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgIGZpeGVkIGNvZGVzIGJsb2NrJXNcXG5cIixcbiAgICAgICAgLy8gICAgICAgIHN0YXRlLmxhc3QgPyBcIiAobGFzdClcIiA6IFwiXCIpKTtcbiAgICAgICAgc3RhdGUubW9kZSA9IExFTl87ICAgICAgICAgICAgIC8qIGRlY29kZSBjb2RlcyAqL1xuICAgICAgICBpZiAoZmx1c2ggPT09IFpfVFJFRVMpIHtcbiAgICAgICAgICAvLy0tLSBEUk9QQklUUygyKSAtLS0vL1xuICAgICAgICAgIGhvbGQgPj4+PSAyO1xuICAgICAgICAgIGJpdHMgLT0gMjtcbiAgICAgICAgICAvLy0tLS8vXG4gICAgICAgICAgYnJlYWsgaW5mX2xlYXZlO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogZHluYW1pYyBibG9jayAqL1xuICAgICAgICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6ICAgICBkeW5hbWljIGNvZGVzIGJsb2NrJXNcXG5cIixcbiAgICAgICAgLy8gICAgICAgIHN0YXRlLmxhc3QgPyBcIiAobGFzdClcIiA6IFwiXCIpKTtcbiAgICAgICAgc3RhdGUubW9kZSA9IFRBQkxFO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBibG9jayB0eXBlJztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgIH1cbiAgICAgIC8vLS0tIERST1BCSVRTKDIpIC0tLS8vXG4gICAgICBob2xkID4+Pj0gMjtcbiAgICAgIGJpdHMgLT0gMjtcbiAgICAgIC8vLS0tLy9cbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgU1RPUkVEOlxuICAgICAgLy8tLS0gQllURUJJVFMoKSAtLS0vLyAvKiBnbyB0byBieXRlIGJvdW5kYXJ5ICovXG4gICAgICBob2xkID4+Pj0gYml0cyAmIDc7XG4gICAgICBiaXRzIC09IGJpdHMgJiA3O1xuICAgICAgLy8tLS0vL1xuICAgICAgLy89PT0gTkVFREJJVFMoMzIpOyAqL1xuICAgICAgd2hpbGUgKGJpdHMgPCAzMikge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgfVxuICAgICAgLy89PT0vL1xuICAgICAgaWYgKChob2xkICYgMHhmZmZmKSAhPT0gKChob2xkID4+PiAxNikgXiAweGZmZmYpKSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgc3RvcmVkIGJsb2NrIGxlbmd0aHMnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIHN0YXRlLmxlbmd0aCA9IGhvbGQgJiAweGZmZmY7XG4gICAgICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6ICAgICAgIHN0b3JlZCBsZW5ndGggJXVcXG5cIixcbiAgICAgIC8vICAgICAgICBzdGF0ZS5sZW5ndGgpKTtcbiAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICBob2xkID0gMDtcbiAgICAgIGJpdHMgPSAwO1xuICAgICAgLy89PT0vL1xuICAgICAgc3RhdGUubW9kZSA9IENPUFlfO1xuICAgICAgaWYgKGZsdXNoID09PSBaX1RSRUVTKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgQ09QWV86XG4gICAgICBzdGF0ZS5tb2RlID0gQ09QWTtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIENPUFk6XG4gICAgICBjb3B5ID0gc3RhdGUubGVuZ3RoO1xuICAgICAgaWYgKGNvcHkpIHtcbiAgICAgICAgaWYgKGNvcHkgPiBoYXZlKSB7IGNvcHkgPSBoYXZlOyB9XG4gICAgICAgIGlmIChjb3B5ID4gbGVmdCkgeyBjb3B5ID0gbGVmdDsgfVxuICAgICAgICBpZiAoY29weSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgLy8tLS0gem1lbWNweShwdXQsIG5leHQsIGNvcHkpOyAtLS1cbiAgICAgICAgdXRpbHMuYXJyYXlTZXQob3V0cHV0LCBpbnB1dCwgbmV4dCwgY29weSwgcHV0KTtcbiAgICAgICAgLy8tLS0vL1xuICAgICAgICBoYXZlIC09IGNvcHk7XG4gICAgICAgIG5leHQgKz0gY29weTtcbiAgICAgICAgbGVmdCAtPSBjb3B5O1xuICAgICAgICBwdXQgKz0gY29weTtcbiAgICAgICAgc3RhdGUubGVuZ3RoIC09IGNvcHk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgLy9UcmFjZXYoKHN0ZGVyciwgXCJpbmZsYXRlOiAgICAgICBzdG9yZWQgZW5kXFxuXCIpKTtcbiAgICAgIHN0YXRlLm1vZGUgPSBUWVBFO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBUQUJMRTpcbiAgICAgIC8vPT09IE5FRURCSVRTKDE0KTsgKi9cbiAgICAgIHdoaWxlIChiaXRzIDwgMTQpIHtcbiAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgIGhhdmUtLTtcbiAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgIGJpdHMgKz0gODtcbiAgICAgIH1cbiAgICAgIC8vPT09Ly9cbiAgICAgIHN0YXRlLm5sZW4gPSAoaG9sZCAmIDB4MWYpLypCSVRTKDUpKi8gKyAyNTc7XG4gICAgICAvLy0tLSBEUk9QQklUUyg1KSAtLS0vL1xuICAgICAgaG9sZCA+Pj49IDU7XG4gICAgICBiaXRzIC09IDU7XG4gICAgICAvLy0tLS8vXG4gICAgICBzdGF0ZS5uZGlzdCA9IChob2xkICYgMHgxZikvKkJJVFMoNSkqLyArIDE7XG4gICAgICAvLy0tLSBEUk9QQklUUyg1KSAtLS0vL1xuICAgICAgaG9sZCA+Pj49IDU7XG4gICAgICBiaXRzIC09IDU7XG4gICAgICAvLy0tLS8vXG4gICAgICBzdGF0ZS5uY29kZSA9IChob2xkICYgMHgwZikvKkJJVFMoNCkqLyArIDQ7XG4gICAgICAvLy0tLSBEUk9QQklUUyg0KSAtLS0vL1xuICAgICAgaG9sZCA+Pj49IDQ7XG4gICAgICBiaXRzIC09IDQ7XG4gICAgICAvLy0tLS8vXG4vLyNpZm5kZWYgUEtaSVBfQlVHX1dPUktBUk9VTkRcbiAgICAgIGlmIChzdGF0ZS5ubGVuID4gMjg2IHx8IHN0YXRlLm5kaXN0ID4gMzApIHtcbiAgICAgICAgc3RybS5tc2cgPSAndG9vIG1hbnkgbGVuZ3RoIG9yIGRpc3RhbmNlIHN5bWJvbHMnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbi8vI2VuZGlmXG4gICAgICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6ICAgICAgIHRhYmxlIHNpemVzIG9rXFxuXCIpKTtcbiAgICAgIHN0YXRlLmhhdmUgPSAwO1xuICAgICAgc3RhdGUubW9kZSA9IExFTkxFTlM7XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBMRU5MRU5TOlxuICAgICAgd2hpbGUgKHN0YXRlLmhhdmUgPCBzdGF0ZS5uY29kZSkge1xuICAgICAgICAvLz09PSBORUVEQklUUygzKTtcbiAgICAgICAgd2hpbGUgKGJpdHMgPCAzKSB7XG4gICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgfVxuICAgICAgICAvLz09PS8vXG4gICAgICAgIHN0YXRlLmxlbnNbb3JkZXJbc3RhdGUuaGF2ZSsrXV0gPSAoaG9sZCAmIDB4MDcpOy8vQklUUygzKTtcbiAgICAgICAgLy8tLS0gRFJPUEJJVFMoMykgLS0tLy9cbiAgICAgICAgaG9sZCA+Pj49IDM7XG4gICAgICAgIGJpdHMgLT0gMztcbiAgICAgICAgLy8tLS0vL1xuICAgICAgfVxuICAgICAgd2hpbGUgKHN0YXRlLmhhdmUgPCAxOSkge1xuICAgICAgICBzdGF0ZS5sZW5zW29yZGVyW3N0YXRlLmhhdmUrK11dID0gMDtcbiAgICAgIH1cbiAgICAgIC8vIFdlIGhhdmUgc2VwYXJhdGUgdGFibGVzICYgbm8gcG9pbnRlcnMuIDIgY29tbWVudGVkIGxpbmVzIGJlbG93IG5vdCBuZWVkZWQuXG4gICAgICAvL3N0YXRlLm5leHQgPSBzdGF0ZS5jb2RlcztcbiAgICAgIC8vc3RhdGUubGVuY29kZSA9IHN0YXRlLm5leHQ7XG4gICAgICAvLyBTd2l0Y2ggdG8gdXNlIGR5bmFtaWMgdGFibGVcbiAgICAgIHN0YXRlLmxlbmNvZGUgPSBzdGF0ZS5sZW5keW47XG4gICAgICBzdGF0ZS5sZW5iaXRzID0gNztcblxuICAgICAgb3B0cyA9IHtiaXRzOiBzdGF0ZS5sZW5iaXRzfTtcbiAgICAgIHJldCA9IGluZmxhdGVfdGFibGUoQ09ERVMsIHN0YXRlLmxlbnMsIDAsIDE5LCBzdGF0ZS5sZW5jb2RlLCAwLCBzdGF0ZS53b3JrLCBvcHRzKTtcbiAgICAgIHN0YXRlLmxlbmJpdHMgPSBvcHRzLmJpdHM7XG5cbiAgICAgIGlmIChyZXQpIHtcbiAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBjb2RlIGxlbmd0aHMgc2V0JztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6ICAgICAgIGNvZGUgbGVuZ3RocyBva1xcblwiKSk7XG4gICAgICBzdGF0ZS5oYXZlID0gMDtcbiAgICAgIHN0YXRlLm1vZGUgPSBDT0RFTEVOUztcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIENPREVMRU5TOlxuICAgICAgd2hpbGUgKHN0YXRlLmhhdmUgPCBzdGF0ZS5ubGVuICsgc3RhdGUubmRpc3QpIHtcbiAgICAgICAgZm9yICg7Oykge1xuICAgICAgICAgIGhlcmUgPSBzdGF0ZS5sZW5jb2RlW2hvbGQgJiAoKDEgPDwgc3RhdGUubGVuYml0cykgLSAxKV07LypCSVRTKHN0YXRlLmxlbmJpdHMpKi9cbiAgICAgICAgICBoZXJlX2JpdHMgPSBoZXJlID4+PiAyNDtcbiAgICAgICAgICBoZXJlX29wID0gKGhlcmUgPj4+IDE2KSAmIDB4ZmY7XG4gICAgICAgICAgaGVyZV92YWwgPSBoZXJlICYgMHhmZmZmO1xuXG4gICAgICAgICAgaWYgKChoZXJlX2JpdHMpIDw9IGJpdHMpIHsgYnJlYWs7IH1cbiAgICAgICAgICAvLy0tLSBQVUxMQllURSgpIC0tLS8vXG4gICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgICAvLy0tLS8vXG4gICAgICAgIH1cbiAgICAgICAgaWYgKGhlcmVfdmFsIDwgMTYpIHtcbiAgICAgICAgICAvLy0tLSBEUk9QQklUUyhoZXJlLmJpdHMpIC0tLS8vXG4gICAgICAgICAgaG9sZCA+Pj49IGhlcmVfYml0cztcbiAgICAgICAgICBiaXRzIC09IGhlcmVfYml0cztcbiAgICAgICAgICAvLy0tLS8vXG4gICAgICAgICAgc3RhdGUubGVuc1tzdGF0ZS5oYXZlKytdID0gaGVyZV92YWw7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgaWYgKGhlcmVfdmFsID09PSAxNikge1xuICAgICAgICAgICAgLy89PT0gTkVFREJJVFMoaGVyZS5iaXRzICsgMik7XG4gICAgICAgICAgICBuID0gaGVyZV9iaXRzICsgMjtcbiAgICAgICAgICAgIHdoaWxlIChiaXRzIDwgbikge1xuICAgICAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy89PT0vL1xuICAgICAgICAgICAgLy8tLS0gRFJPUEJJVFMoaGVyZS5iaXRzKSAtLS0vL1xuICAgICAgICAgICAgaG9sZCA+Pj49IGhlcmVfYml0cztcbiAgICAgICAgICAgIGJpdHMgLT0gaGVyZV9iaXRzO1xuICAgICAgICAgICAgLy8tLS0vL1xuICAgICAgICAgICAgaWYgKHN0YXRlLmhhdmUgPT09IDApIHtcbiAgICAgICAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBiaXQgbGVuZ3RoIHJlcGVhdCc7XG4gICAgICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGVuID0gc3RhdGUubGVuc1tzdGF0ZS5oYXZlIC0gMV07XG4gICAgICAgICAgICBjb3B5ID0gMyArIChob2xkICYgMHgwMyk7Ly9CSVRTKDIpO1xuICAgICAgICAgICAgLy8tLS0gRFJPUEJJVFMoMikgLS0tLy9cbiAgICAgICAgICAgIGhvbGQgPj4+PSAyO1xuICAgICAgICAgICAgYml0cyAtPSAyO1xuICAgICAgICAgICAgLy8tLS0vL1xuICAgICAgICAgIH1cbiAgICAgICAgICBlbHNlIGlmIChoZXJlX3ZhbCA9PT0gMTcpIHtcbiAgICAgICAgICAgIC8vPT09IE5FRURCSVRTKGhlcmUuYml0cyArIDMpO1xuICAgICAgICAgICAgbiA9IGhlcmVfYml0cyArIDM7XG4gICAgICAgICAgICB3aGlsZSAoYml0cyA8IG4pIHtcbiAgICAgICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgICAgIGhhdmUtLTtcbiAgICAgICAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vPT09Ly9cbiAgICAgICAgICAgIC8vLS0tIERST1BCSVRTKGhlcmUuYml0cykgLS0tLy9cbiAgICAgICAgICAgIGhvbGQgPj4+PSBoZXJlX2JpdHM7XG4gICAgICAgICAgICBiaXRzIC09IGhlcmVfYml0cztcbiAgICAgICAgICAgIC8vLS0tLy9cbiAgICAgICAgICAgIGxlbiA9IDA7XG4gICAgICAgICAgICBjb3B5ID0gMyArIChob2xkICYgMHgwNyk7Ly9CSVRTKDMpO1xuICAgICAgICAgICAgLy8tLS0gRFJPUEJJVFMoMykgLS0tLy9cbiAgICAgICAgICAgIGhvbGQgPj4+PSAzO1xuICAgICAgICAgICAgYml0cyAtPSAzO1xuICAgICAgICAgICAgLy8tLS0vL1xuICAgICAgICAgIH1cbiAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vPT09IE5FRURCSVRTKGhlcmUuYml0cyArIDcpO1xuICAgICAgICAgICAgbiA9IGhlcmVfYml0cyArIDc7XG4gICAgICAgICAgICB3aGlsZSAoYml0cyA8IG4pIHtcbiAgICAgICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgICAgIGhhdmUtLTtcbiAgICAgICAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vPT09Ly9cbiAgICAgICAgICAgIC8vLS0tIERST1BCSVRTKGhlcmUuYml0cykgLS0tLy9cbiAgICAgICAgICAgIGhvbGQgPj4+PSBoZXJlX2JpdHM7XG4gICAgICAgICAgICBiaXRzIC09IGhlcmVfYml0cztcbiAgICAgICAgICAgIC8vLS0tLy9cbiAgICAgICAgICAgIGxlbiA9IDA7XG4gICAgICAgICAgICBjb3B5ID0gMTEgKyAoaG9sZCAmIDB4N2YpOy8vQklUUyg3KTtcbiAgICAgICAgICAgIC8vLS0tIERST1BCSVRTKDcpIC0tLS8vXG4gICAgICAgICAgICBob2xkID4+Pj0gNztcbiAgICAgICAgICAgIGJpdHMgLT0gNztcbiAgICAgICAgICAgIC8vLS0tLy9cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHN0YXRlLmhhdmUgKyBjb3B5ID4gc3RhdGUubmxlbiArIHN0YXRlLm5kaXN0KSB7XG4gICAgICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGJpdCBsZW5ndGggcmVwZWF0JztcbiAgICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgd2hpbGUgKGNvcHktLSkge1xuICAgICAgICAgICAgc3RhdGUubGVuc1tzdGF0ZS5oYXZlKytdID0gbGVuO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvKiBoYW5kbGUgZXJyb3IgYnJlYWtzIGluIHdoaWxlICovXG4gICAgICBpZiAoc3RhdGUubW9kZSA9PT0gQkFEKSB7IGJyZWFrOyB9XG5cbiAgICAgIC8qIGNoZWNrIGZvciBlbmQtb2YtYmxvY2sgY29kZSAoYmV0dGVyIGhhdmUgb25lKSAqL1xuICAgICAgaWYgKHN0YXRlLmxlbnNbMjU2XSA9PT0gMCkge1xuICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGNvZGUgLS0gbWlzc2luZyBlbmQtb2YtYmxvY2snO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgLyogYnVpbGQgY29kZSB0YWJsZXMgLS0gbm90ZTogZG8gbm90IGNoYW5nZSB0aGUgbGVuYml0cyBvciBkaXN0Yml0c1xuICAgICAgICAgdmFsdWVzIGhlcmUgKDkgYW5kIDYpIHdpdGhvdXQgcmVhZGluZyB0aGUgY29tbWVudHMgaW4gaW5mdHJlZXMuaFxuICAgICAgICAgY29uY2VybmluZyB0aGUgRU5PVUdIIGNvbnN0YW50cywgd2hpY2ggZGVwZW5kIG9uIHRob3NlIHZhbHVlcyAqL1xuICAgICAgc3RhdGUubGVuYml0cyA9IDk7XG5cbiAgICAgIG9wdHMgPSB7Yml0czogc3RhdGUubGVuYml0c307XG4gICAgICByZXQgPSBpbmZsYXRlX3RhYmxlKExFTlMsIHN0YXRlLmxlbnMsIDAsIHN0YXRlLm5sZW4sIHN0YXRlLmxlbmNvZGUsIDAsIHN0YXRlLndvcmssIG9wdHMpO1xuICAgICAgLy8gV2UgaGF2ZSBzZXBhcmF0ZSB0YWJsZXMgJiBubyBwb2ludGVycy4gMiBjb21tZW50ZWQgbGluZXMgYmVsb3cgbm90IG5lZWRlZC5cbiAgICAgIC8vIHN0YXRlLm5leHRfaW5kZXggPSBvcHRzLnRhYmxlX2luZGV4O1xuICAgICAgc3RhdGUubGVuYml0cyA9IG9wdHMuYml0cztcbiAgICAgIC8vIHN0YXRlLmxlbmNvZGUgPSBzdGF0ZS5uZXh0O1xuXG4gICAgICBpZiAocmV0KSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgbGl0ZXJhbC9sZW5ndGhzIHNldCc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICBzdGF0ZS5kaXN0Yml0cyA9IDY7XG4gICAgICAvL3N0YXRlLmRpc3Rjb2RlLmNvcHkoc3RhdGUuY29kZXMpO1xuICAgICAgLy8gU3dpdGNoIHRvIHVzZSBkeW5hbWljIHRhYmxlXG4gICAgICBzdGF0ZS5kaXN0Y29kZSA9IHN0YXRlLmRpc3RkeW47XG4gICAgICBvcHRzID0ge2JpdHM6IHN0YXRlLmRpc3RiaXRzfTtcbiAgICAgIHJldCA9IGluZmxhdGVfdGFibGUoRElTVFMsIHN0YXRlLmxlbnMsIHN0YXRlLm5sZW4sIHN0YXRlLm5kaXN0LCBzdGF0ZS5kaXN0Y29kZSwgMCwgc3RhdGUud29yaywgb3B0cyk7XG4gICAgICAvLyBXZSBoYXZlIHNlcGFyYXRlIHRhYmxlcyAmIG5vIHBvaW50ZXJzLiAyIGNvbW1lbnRlZCBsaW5lcyBiZWxvdyBub3QgbmVlZGVkLlxuICAgICAgLy8gc3RhdGUubmV4dF9pbmRleCA9IG9wdHMudGFibGVfaW5kZXg7XG4gICAgICBzdGF0ZS5kaXN0Yml0cyA9IG9wdHMuYml0cztcbiAgICAgIC8vIHN0YXRlLmRpc3Rjb2RlID0gc3RhdGUubmV4dDtcblxuICAgICAgaWYgKHJldCkge1xuICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGRpc3RhbmNlcyBzZXQnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIC8vVHJhY2V2KChzdGRlcnIsICdpbmZsYXRlOiAgICAgICBjb2RlcyBva1xcbicpKTtcbiAgICAgIHN0YXRlLm1vZGUgPSBMRU5fO1xuICAgICAgaWYgKGZsdXNoID09PSBaX1RSRUVTKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgTEVOXzpcbiAgICAgIHN0YXRlLm1vZGUgPSBMRU47XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBMRU46XG4gICAgICBpZiAoaGF2ZSA+PSA2ICYmIGxlZnQgPj0gMjU4KSB7XG4gICAgICAgIC8vLS0tIFJFU1RPUkUoKSAtLS1cbiAgICAgICAgc3RybS5uZXh0X291dCA9IHB1dDtcbiAgICAgICAgc3RybS5hdmFpbF9vdXQgPSBsZWZ0O1xuICAgICAgICBzdHJtLm5leHRfaW4gPSBuZXh0O1xuICAgICAgICBzdHJtLmF2YWlsX2luID0gaGF2ZTtcbiAgICAgICAgc3RhdGUuaG9sZCA9IGhvbGQ7XG4gICAgICAgIHN0YXRlLmJpdHMgPSBiaXRzO1xuICAgICAgICAvLy0tLVxuICAgICAgICBpbmZsYXRlX2Zhc3Qoc3RybSwgX291dCk7XG4gICAgICAgIC8vLS0tIExPQUQoKSAtLS1cbiAgICAgICAgcHV0ID0gc3RybS5uZXh0X291dDtcbiAgICAgICAgb3V0cHV0ID0gc3RybS5vdXRwdXQ7XG4gICAgICAgIGxlZnQgPSBzdHJtLmF2YWlsX291dDtcbiAgICAgICAgbmV4dCA9IHN0cm0ubmV4dF9pbjtcbiAgICAgICAgaW5wdXQgPSBzdHJtLmlucHV0O1xuICAgICAgICBoYXZlID0gc3RybS5hdmFpbF9pbjtcbiAgICAgICAgaG9sZCA9IHN0YXRlLmhvbGQ7XG4gICAgICAgIGJpdHMgPSBzdGF0ZS5iaXRzO1xuICAgICAgICAvLy0tLVxuXG4gICAgICAgIGlmIChzdGF0ZS5tb2RlID09PSBUWVBFKSB7XG4gICAgICAgICAgc3RhdGUuYmFjayA9IC0xO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgc3RhdGUuYmFjayA9IDA7XG4gICAgICBmb3IgKDs7KSB7XG4gICAgICAgIGhlcmUgPSBzdGF0ZS5sZW5jb2RlW2hvbGQgJiAoKDEgPDwgc3RhdGUubGVuYml0cykgLTEpXTsgIC8qQklUUyhzdGF0ZS5sZW5iaXRzKSovXG4gICAgICAgIGhlcmVfYml0cyA9IGhlcmUgPj4+IDI0O1xuICAgICAgICBoZXJlX29wID0gKGhlcmUgPj4+IDE2KSAmIDB4ZmY7XG4gICAgICAgIGhlcmVfdmFsID0gaGVyZSAmIDB4ZmZmZjtcblxuICAgICAgICBpZiAoaGVyZV9iaXRzIDw9IGJpdHMpIHsgYnJlYWs7IH1cbiAgICAgICAgLy8tLS0gUFVMTEJZVEUoKSAtLS0vL1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAvLy0tLS8vXG4gICAgICB9XG4gICAgICBpZiAoaGVyZV9vcCAmJiAoaGVyZV9vcCAmIDB4ZjApID09PSAwKSB7XG4gICAgICAgIGxhc3RfYml0cyA9IGhlcmVfYml0cztcbiAgICAgICAgbGFzdF9vcCA9IGhlcmVfb3A7XG4gICAgICAgIGxhc3RfdmFsID0gaGVyZV92YWw7XG4gICAgICAgIGZvciAoOzspIHtcbiAgICAgICAgICBoZXJlID0gc3RhdGUubGVuY29kZVtsYXN0X3ZhbCArXG4gICAgICAgICAgICAgICAgICAoKGhvbGQgJiAoKDEgPDwgKGxhc3RfYml0cyArIGxhc3Rfb3ApKSAtMSkpLypCSVRTKGxhc3QuYml0cyArIGxhc3Qub3ApKi8gPj4gbGFzdF9iaXRzKV07XG4gICAgICAgICAgaGVyZV9iaXRzID0gaGVyZSA+Pj4gMjQ7XG4gICAgICAgICAgaGVyZV9vcCA9IChoZXJlID4+PiAxNikgJiAweGZmO1xuICAgICAgICAgIGhlcmVfdmFsID0gaGVyZSAmIDB4ZmZmZjtcblxuICAgICAgICAgIGlmICgobGFzdF9iaXRzICsgaGVyZV9iaXRzKSA8PSBiaXRzKSB7IGJyZWFrOyB9XG4gICAgICAgICAgLy8tLS0gUFVMTEJZVEUoKSAtLS0vL1xuICAgICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICAgIGhhdmUtLTtcbiAgICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgICAgLy8tLS0vL1xuICAgICAgICB9XG4gICAgICAgIC8vLS0tIERST1BCSVRTKGxhc3QuYml0cykgLS0tLy9cbiAgICAgICAgaG9sZCA+Pj49IGxhc3RfYml0cztcbiAgICAgICAgYml0cyAtPSBsYXN0X2JpdHM7XG4gICAgICAgIC8vLS0tLy9cbiAgICAgICAgc3RhdGUuYmFjayArPSBsYXN0X2JpdHM7XG4gICAgICB9XG4gICAgICAvLy0tLSBEUk9QQklUUyhoZXJlLmJpdHMpIC0tLS8vXG4gICAgICBob2xkID4+Pj0gaGVyZV9iaXRzO1xuICAgICAgYml0cyAtPSBoZXJlX2JpdHM7XG4gICAgICAvLy0tLS8vXG4gICAgICBzdGF0ZS5iYWNrICs9IGhlcmVfYml0cztcbiAgICAgIHN0YXRlLmxlbmd0aCA9IGhlcmVfdmFsO1xuICAgICAgaWYgKGhlcmVfb3AgPT09IDApIHtcbiAgICAgICAgLy9UcmFjZXZ2KChzdGRlcnIsIGhlcmUudmFsID49IDB4MjAgJiYgaGVyZS52YWwgPCAweDdmID9cbiAgICAgICAgLy8gICAgICAgIFwiaW5mbGF0ZTogICAgICAgICBsaXRlcmFsICclYydcXG5cIiA6XG4gICAgICAgIC8vICAgICAgICBcImluZmxhdGU6ICAgICAgICAgbGl0ZXJhbCAweCUwMnhcXG5cIiwgaGVyZS52YWwpKTtcbiAgICAgICAgc3RhdGUubW9kZSA9IExJVDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoaGVyZV9vcCAmIDMyKSB7XG4gICAgICAgIC8vVHJhY2V2digoc3RkZXJyLCBcImluZmxhdGU6ICAgICAgICAgZW5kIG9mIGJsb2NrXFxuXCIpKTtcbiAgICAgICAgc3RhdGUuYmFjayA9IC0xO1xuICAgICAgICBzdGF0ZS5tb2RlID0gVFlQRTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoaGVyZV9vcCAmIDY0KSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgbGl0ZXJhbC9sZW5ndGggY29kZSc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgc3RhdGUuZXh0cmEgPSBoZXJlX29wICYgMTU7XG4gICAgICBzdGF0ZS5tb2RlID0gTEVORVhUO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgTEVORVhUOlxuICAgICAgaWYgKHN0YXRlLmV4dHJhKSB7XG4gICAgICAgIC8vPT09IE5FRURCSVRTKHN0YXRlLmV4dHJhKTtcbiAgICAgICAgbiA9IHN0YXRlLmV4dHJhO1xuICAgICAgICB3aGlsZSAoYml0cyA8IG4pIHtcbiAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICBoYXZlLS07XG4gICAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICB9XG4gICAgICAgIC8vPT09Ly9cbiAgICAgICAgc3RhdGUubGVuZ3RoICs9IGhvbGQgJiAoKDEgPDwgc3RhdGUuZXh0cmEpIC0xKS8qQklUUyhzdGF0ZS5leHRyYSkqLztcbiAgICAgICAgLy8tLS0gRFJPUEJJVFMoc3RhdGUuZXh0cmEpIC0tLS8vXG4gICAgICAgIGhvbGQgPj4+PSBzdGF0ZS5leHRyYTtcbiAgICAgICAgYml0cyAtPSBzdGF0ZS5leHRyYTtcbiAgICAgICAgLy8tLS0vL1xuICAgICAgICBzdGF0ZS5iYWNrICs9IHN0YXRlLmV4dHJhO1xuICAgICAgfVxuICAgICAgLy9UcmFjZXZ2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgICAgICBsZW5ndGggJXVcXG5cIiwgc3RhdGUubGVuZ3RoKSk7XG4gICAgICBzdGF0ZS53YXMgPSBzdGF0ZS5sZW5ndGg7XG4gICAgICBzdGF0ZS5tb2RlID0gRElTVDtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIERJU1Q6XG4gICAgICBmb3IgKDs7KSB7XG4gICAgICAgIGhlcmUgPSBzdGF0ZS5kaXN0Y29kZVtob2xkICYgKCgxIDw8IHN0YXRlLmRpc3RiaXRzKSAtMSldOy8qQklUUyhzdGF0ZS5kaXN0Yml0cykqL1xuICAgICAgICBoZXJlX2JpdHMgPSBoZXJlID4+PiAyNDtcbiAgICAgICAgaGVyZV9vcCA9IChoZXJlID4+PiAxNikgJiAweGZmO1xuICAgICAgICBoZXJlX3ZhbCA9IGhlcmUgJiAweGZmZmY7XG5cbiAgICAgICAgaWYgKChoZXJlX2JpdHMpIDw9IGJpdHMpIHsgYnJlYWs7IH1cbiAgICAgICAgLy8tLS0gUFVMTEJZVEUoKSAtLS0vL1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAvLy0tLS8vXG4gICAgICB9XG4gICAgICBpZiAoKGhlcmVfb3AgJiAweGYwKSA9PT0gMCkge1xuICAgICAgICBsYXN0X2JpdHMgPSBoZXJlX2JpdHM7XG4gICAgICAgIGxhc3Rfb3AgPSBoZXJlX29wO1xuICAgICAgICBsYXN0X3ZhbCA9IGhlcmVfdmFsO1xuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgaGVyZSA9IHN0YXRlLmRpc3Rjb2RlW2xhc3RfdmFsICtcbiAgICAgICAgICAgICAgICAgICgoaG9sZCAmICgoMSA8PCAobGFzdF9iaXRzICsgbGFzdF9vcCkpIC0xKSkvKkJJVFMobGFzdC5iaXRzICsgbGFzdC5vcCkqLyA+PiBsYXN0X2JpdHMpXTtcbiAgICAgICAgICBoZXJlX2JpdHMgPSBoZXJlID4+PiAyNDtcbiAgICAgICAgICBoZXJlX29wID0gKGhlcmUgPj4+IDE2KSAmIDB4ZmY7XG4gICAgICAgICAgaGVyZV92YWwgPSBoZXJlICYgMHhmZmZmO1xuXG4gICAgICAgICAgaWYgKChsYXN0X2JpdHMgKyBoZXJlX2JpdHMpIDw9IGJpdHMpIHsgYnJlYWs7IH1cbiAgICAgICAgICAvLy0tLSBQVUxMQllURSgpIC0tLS8vXG4gICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgICAvLy0tLS8vXG4gICAgICAgIH1cbiAgICAgICAgLy8tLS0gRFJPUEJJVFMobGFzdC5iaXRzKSAtLS0vL1xuICAgICAgICBob2xkID4+Pj0gbGFzdF9iaXRzO1xuICAgICAgICBiaXRzIC09IGxhc3RfYml0cztcbiAgICAgICAgLy8tLS0vL1xuICAgICAgICBzdGF0ZS5iYWNrICs9IGxhc3RfYml0cztcbiAgICAgIH1cbiAgICAgIC8vLS0tIERST1BCSVRTKGhlcmUuYml0cykgLS0tLy9cbiAgICAgIGhvbGQgPj4+PSBoZXJlX2JpdHM7XG4gICAgICBiaXRzIC09IGhlcmVfYml0cztcbiAgICAgIC8vLS0tLy9cbiAgICAgIHN0YXRlLmJhY2sgKz0gaGVyZV9iaXRzO1xuICAgICAgaWYgKGhlcmVfb3AgJiA2NCkge1xuICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGRpc3RhbmNlIGNvZGUnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIHN0YXRlLm9mZnNldCA9IGhlcmVfdmFsO1xuICAgICAgc3RhdGUuZXh0cmEgPSAoaGVyZV9vcCkgJiAxNTtcbiAgICAgIHN0YXRlLm1vZGUgPSBESVNURVhUO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgRElTVEVYVDpcbiAgICAgIGlmIChzdGF0ZS5leHRyYSkge1xuICAgICAgICAvLz09PSBORUVEQklUUyhzdGF0ZS5leHRyYSk7XG4gICAgICAgIG4gPSBzdGF0ZS5leHRyYTtcbiAgICAgICAgd2hpbGUgKGJpdHMgPCBuKSB7XG4gICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgfVxuICAgICAgICAvLz09PS8vXG4gICAgICAgIHN0YXRlLm9mZnNldCArPSBob2xkICYgKCgxIDw8IHN0YXRlLmV4dHJhKSAtMSkvKkJJVFMoc3RhdGUuZXh0cmEpKi87XG4gICAgICAgIC8vLS0tIERST1BCSVRTKHN0YXRlLmV4dHJhKSAtLS0vL1xuICAgICAgICBob2xkID4+Pj0gc3RhdGUuZXh0cmE7XG4gICAgICAgIGJpdHMgLT0gc3RhdGUuZXh0cmE7XG4gICAgICAgIC8vLS0tLy9cbiAgICAgICAgc3RhdGUuYmFjayArPSBzdGF0ZS5leHRyYTtcbiAgICAgIH1cbi8vI2lmZGVmIElORkxBVEVfU1RSSUNUXG4gICAgICBpZiAoc3RhdGUub2Zmc2V0ID4gc3RhdGUuZG1heCkge1xuICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjayc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuLy8jZW5kaWZcbiAgICAgIC8vVHJhY2V2digoc3RkZXJyLCBcImluZmxhdGU6ICAgICAgICAgZGlzdGFuY2UgJXVcXG5cIiwgc3RhdGUub2Zmc2V0KSk7XG4gICAgICBzdGF0ZS5tb2RlID0gTUFUQ0g7XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBNQVRDSDpcbiAgICAgIGlmIChsZWZ0ID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgY29weSA9IF9vdXQgLSBsZWZ0O1xuICAgICAgaWYgKHN0YXRlLm9mZnNldCA+IGNvcHkpIHsgICAgICAgICAvKiBjb3B5IGZyb20gd2luZG93ICovXG4gICAgICAgIGNvcHkgPSBzdGF0ZS5vZmZzZXQgLSBjb3B5O1xuICAgICAgICBpZiAoY29weSA+IHN0YXRlLndoYXZlKSB7XG4gICAgICAgICAgaWYgKHN0YXRlLnNhbmUpIHtcbiAgICAgICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrJztcbiAgICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4vLyAoISkgVGhpcyBibG9jayBpcyBkaXNhYmxlZCBpbiB6bGliIGRlZmFpbHRzLFxuLy8gZG9uJ3QgZW5hYmxlIGl0IGZvciBiaW5hcnkgY29tcGF0aWJpbGl0eVxuLy8jaWZkZWYgSU5GTEFURV9BTExPV19JTlZBTElEX0RJU1RBTkNFX1RPT0ZBUl9BUlJSXG4vLyAgICAgICAgICBUcmFjZSgoc3RkZXJyLCBcImluZmxhdGUuYyB0b28gZmFyXFxuXCIpKTtcbi8vICAgICAgICAgIGNvcHkgLT0gc3RhdGUud2hhdmU7XG4vLyAgICAgICAgICBpZiAoY29weSA+IHN0YXRlLmxlbmd0aCkgeyBjb3B5ID0gc3RhdGUubGVuZ3RoOyB9XG4vLyAgICAgICAgICBpZiAoY29weSA+IGxlZnQpIHsgY29weSA9IGxlZnQ7IH1cbi8vICAgICAgICAgIGxlZnQgLT0gY29weTtcbi8vICAgICAgICAgIHN0YXRlLmxlbmd0aCAtPSBjb3B5O1xuLy8gICAgICAgICAgZG8ge1xuLy8gICAgICAgICAgICBvdXRwdXRbcHV0KytdID0gMDtcbi8vICAgICAgICAgIH0gd2hpbGUgKC0tY29weSk7XG4vLyAgICAgICAgICBpZiAoc3RhdGUubGVuZ3RoID09PSAwKSB7IHN0YXRlLm1vZGUgPSBMRU47IH1cbi8vICAgICAgICAgIGJyZWFrO1xuLy8jZW5kaWZcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29weSA+IHN0YXRlLnduZXh0KSB7XG4gICAgICAgICAgY29weSAtPSBzdGF0ZS53bmV4dDtcbiAgICAgICAgICBmcm9tID0gc3RhdGUud3NpemUgLSBjb3B5O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIGZyb20gPSBzdGF0ZS53bmV4dCAtIGNvcHk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNvcHkgPiBzdGF0ZS5sZW5ndGgpIHsgY29weSA9IHN0YXRlLmxlbmd0aDsgfVxuICAgICAgICBmcm9tX3NvdXJjZSA9IHN0YXRlLndpbmRvdztcbiAgICAgIH1cbiAgICAgIGVsc2UgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qIGNvcHkgZnJvbSBvdXRwdXQgKi9cbiAgICAgICAgZnJvbV9zb3VyY2UgPSBvdXRwdXQ7XG4gICAgICAgIGZyb20gPSBwdXQgLSBzdGF0ZS5vZmZzZXQ7XG4gICAgICAgIGNvcHkgPSBzdGF0ZS5sZW5ndGg7XG4gICAgICB9XG4gICAgICBpZiAoY29weSA+IGxlZnQpIHsgY29weSA9IGxlZnQ7IH1cbiAgICAgIGxlZnQgLT0gY29weTtcbiAgICAgIHN0YXRlLmxlbmd0aCAtPSBjb3B5O1xuICAgICAgZG8ge1xuICAgICAgICBvdXRwdXRbcHV0KytdID0gZnJvbV9zb3VyY2VbZnJvbSsrXTtcbiAgICAgIH0gd2hpbGUgKC0tY29weSk7XG4gICAgICBpZiAoc3RhdGUubGVuZ3RoID09PSAwKSB7IHN0YXRlLm1vZGUgPSBMRU47IH1cbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgTElUOlxuICAgICAgaWYgKGxlZnQgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICBvdXRwdXRbcHV0KytdID0gc3RhdGUubGVuZ3RoO1xuICAgICAgbGVmdC0tO1xuICAgICAgc3RhdGUubW9kZSA9IExFTjtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgQ0hFQ0s6XG4gICAgICBpZiAoc3RhdGUud3JhcCkge1xuICAgICAgICAvLz09PSBORUVEQklUUygzMik7XG4gICAgICAgIHdoaWxlIChiaXRzIDwgMzIpIHtcbiAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICBoYXZlLS07XG4gICAgICAgICAgLy8gVXNlICd8JyBpbnNkZWFkIG9mICcrJyB0byBtYWtlIHN1cmUgdGhhdCByZXN1bHQgaXMgc2lnbmVkXG4gICAgICAgICAgaG9sZCB8PSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICB9XG4gICAgICAgIC8vPT09Ly9cbiAgICAgICAgX291dCAtPSBsZWZ0O1xuICAgICAgICBzdHJtLnRvdGFsX291dCArPSBfb3V0O1xuICAgICAgICBzdGF0ZS50b3RhbCArPSBfb3V0O1xuICAgICAgICBpZiAoX291dCkge1xuICAgICAgICAgIHN0cm0uYWRsZXIgPSBzdGF0ZS5jaGVjayA9XG4gICAgICAgICAgICAgIC8qVVBEQVRFKHN0YXRlLmNoZWNrLCBwdXQgLSBfb3V0LCBfb3V0KTsqL1xuICAgICAgICAgICAgICAoc3RhdGUuZmxhZ3MgPyBjcmMzMihzdGF0ZS5jaGVjaywgb3V0cHV0LCBfb3V0LCBwdXQgLSBfb3V0KSA6IGFkbGVyMzIoc3RhdGUuY2hlY2ssIG91dHB1dCwgX291dCwgcHV0IC0gX291dCkpO1xuXG4gICAgICAgIH1cbiAgICAgICAgX291dCA9IGxlZnQ7XG4gICAgICAgIC8vIE5COiBjcmMzMiBzdG9yZWQgYXMgc2lnbmVkIDMyLWJpdCBpbnQsIFpTV0FQMzIgcmV0dXJucyBzaWduZWQgdG9vXG4gICAgICAgIGlmICgoc3RhdGUuZmxhZ3MgPyBob2xkIDogWlNXQVAzMihob2xkKSkgIT09IHN0YXRlLmNoZWNrKSB7XG4gICAgICAgICAgc3RybS5tc2cgPSAnaW5jb3JyZWN0IGRhdGEgY2hlY2snO1xuICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgICAgaG9sZCA9IDA7XG4gICAgICAgIGJpdHMgPSAwO1xuICAgICAgICAvLz09PS8vXG4gICAgICAgIC8vVHJhY2V2KChzdGRlcnIsIFwiaW5mbGF0ZTogICBjaGVjayBtYXRjaGVzIHRyYWlsZXJcXG5cIikpO1xuICAgICAgfVxuICAgICAgc3RhdGUubW9kZSA9IExFTkdUSDtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIExFTkdUSDpcbiAgICAgIGlmIChzdGF0ZS53cmFwICYmIHN0YXRlLmZsYWdzKSB7XG4gICAgICAgIC8vPT09IE5FRURCSVRTKDMyKTtcbiAgICAgICAgd2hpbGUgKGJpdHMgPCAzMikge1xuICAgICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICAgIGhhdmUtLTtcbiAgICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgIH1cbiAgICAgICAgLy89PT0vL1xuICAgICAgICBpZiAoaG9sZCAhPT0gKHN0YXRlLnRvdGFsICYgMHhmZmZmZmZmZikpIHtcbiAgICAgICAgICBzdHJtLm1zZyA9ICdpbmNvcnJlY3QgbGVuZ3RoIGNoZWNrJztcbiAgICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICAgIGhvbGQgPSAwO1xuICAgICAgICBiaXRzID0gMDtcbiAgICAgICAgLy89PT0vL1xuICAgICAgICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6ICAgbGVuZ3RoIG1hdGNoZXMgdHJhaWxlclxcblwiKSk7XG4gICAgICB9XG4gICAgICBzdGF0ZS5tb2RlID0gRE9ORTtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIERPTkU6XG4gICAgICByZXQgPSBaX1NUUkVBTV9FTkQ7XG4gICAgICBicmVhayBpbmZfbGVhdmU7XG4gICAgY2FzZSBCQUQ6XG4gICAgICByZXQgPSBaX0RBVEFfRVJST1I7XG4gICAgICBicmVhayBpbmZfbGVhdmU7XG4gICAgY2FzZSBNRU06XG4gICAgICByZXR1cm4gWl9NRU1fRVJST1I7XG4gICAgY2FzZSBTWU5DOlxuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gWl9TVFJFQU1fRVJST1I7XG4gICAgfVxuICB9XG5cbiAgLy8gaW5mX2xlYXZlIDwtIGhlcmUgaXMgcmVhbCBwbGFjZSBmb3IgXCJnb3RvIGluZl9sZWF2ZVwiLCBlbXVsYXRlZCB2aWEgXCJicmVhayBpbmZfbGVhdmVcIlxuXG4gIC8qXG4gICAgIFJldHVybiBmcm9tIGluZmxhdGUoKSwgdXBkYXRpbmcgdGhlIHRvdGFsIGNvdW50cyBhbmQgdGhlIGNoZWNrIHZhbHVlLlxuICAgICBJZiB0aGVyZSB3YXMgbm8gcHJvZ3Jlc3MgZHVyaW5nIHRoZSBpbmZsYXRlKCkgY2FsbCwgcmV0dXJuIGEgYnVmZmVyXG4gICAgIGVycm9yLiAgQ2FsbCB1cGRhdGV3aW5kb3coKSB0byBjcmVhdGUgYW5kL29yIHVwZGF0ZSB0aGUgd2luZG93IHN0YXRlLlxuICAgICBOb3RlOiBhIG1lbW9yeSBlcnJvciBmcm9tIGluZmxhdGUoKSBpcyBub24tcmVjb3ZlcmFibGUuXG4gICAqL1xuXG4gIC8vLS0tIFJFU1RPUkUoKSAtLS1cbiAgc3RybS5uZXh0X291dCA9IHB1dDtcbiAgc3RybS5hdmFpbF9vdXQgPSBsZWZ0O1xuICBzdHJtLm5leHRfaW4gPSBuZXh0O1xuICBzdHJtLmF2YWlsX2luID0gaGF2ZTtcbiAgc3RhdGUuaG9sZCA9IGhvbGQ7XG4gIHN0YXRlLmJpdHMgPSBiaXRzO1xuICAvLy0tLVxuXG4gIGlmIChzdGF0ZS53c2l6ZSB8fCAoX291dCAhPT0gc3RybS5hdmFpbF9vdXQgJiYgc3RhdGUubW9kZSA8IEJBRCAmJlxuICAgICAgICAgICAgICAgICAgICAgIChzdGF0ZS5tb2RlIDwgQ0hFQ0sgfHwgZmx1c2ggIT09IFpfRklOSVNIKSkpIHtcbiAgICBpZiAodXBkYXRld2luZG93KHN0cm0sIHN0cm0ub3V0cHV0LCBzdHJtLm5leHRfb3V0LCBfb3V0IC0gc3RybS5hdmFpbF9vdXQpKSB7XG4gICAgICBzdGF0ZS5tb2RlID0gTUVNO1xuICAgICAgcmV0dXJuIFpfTUVNX0VSUk9SO1xuICAgIH1cbiAgfVxuICBfaW4gLT0gc3RybS5hdmFpbF9pbjtcbiAgX291dCAtPSBzdHJtLmF2YWlsX291dDtcbiAgc3RybS50b3RhbF9pbiArPSBfaW47XG4gIHN0cm0udG90YWxfb3V0ICs9IF9vdXQ7XG4gIHN0YXRlLnRvdGFsICs9IF9vdXQ7XG4gIGlmIChzdGF0ZS53cmFwICYmIF9vdXQpIHtcbiAgICBzdHJtLmFkbGVyID0gc3RhdGUuY2hlY2sgPSAvKlVQREFURShzdGF0ZS5jaGVjaywgc3RybS5uZXh0X291dCAtIF9vdXQsIF9vdXQpOyovXG4gICAgICAoc3RhdGUuZmxhZ3MgPyBjcmMzMihzdGF0ZS5jaGVjaywgb3V0cHV0LCBfb3V0LCBzdHJtLm5leHRfb3V0IC0gX291dCkgOiBhZGxlcjMyKHN0YXRlLmNoZWNrLCBvdXRwdXQsIF9vdXQsIHN0cm0ubmV4dF9vdXQgLSBfb3V0KSk7XG4gIH1cbiAgc3RybS5kYXRhX3R5cGUgPSBzdGF0ZS5iaXRzICsgKHN0YXRlLmxhc3QgPyA2NCA6IDApICtcbiAgICAgICAgICAgICAgICAgICAgKHN0YXRlLm1vZGUgPT09IFRZUEUgPyAxMjggOiAwKSArXG4gICAgICAgICAgICAgICAgICAgIChzdGF0ZS5tb2RlID09PSBMRU5fIHx8IHN0YXRlLm1vZGUgPT09IENPUFlfID8gMjU2IDogMCk7XG4gIGlmICgoKF9pbiA9PT0gMCAmJiBfb3V0ID09PSAwKSB8fCBmbHVzaCA9PT0gWl9GSU5JU0gpICYmIHJldCA9PT0gWl9PSykge1xuICAgIHJldCA9IFpfQlVGX0VSUk9SO1xuICB9XG4gIHJldHVybiByZXQ7XG59XG5cbmZ1bmN0aW9uIGluZmxhdGVFbmQoc3RybSkge1xuXG4gIGlmICghc3RybSB8fCAhc3RybS5zdGF0ZSAvKnx8IHN0cm0tPnpmcmVlID09IChmcmVlX2Z1bmMpMCovKSB7XG4gICAgcmV0dXJuIFpfU1RSRUFNX0VSUk9SO1xuICB9XG5cbiAgdmFyIHN0YXRlID0gc3RybS5zdGF0ZTtcbiAgaWYgKHN0YXRlLndpbmRvdykge1xuICAgIHN0YXRlLndpbmRvdyA9IG51bGw7XG4gIH1cbiAgc3RybS5zdGF0ZSA9IG51bGw7XG4gIHJldHVybiBaX09LO1xufVxuXG5mdW5jdGlvbiBpbmZsYXRlR2V0SGVhZGVyKHN0cm0sIGhlYWQpIHtcbiAgdmFyIHN0YXRlO1xuXG4gIC8qIGNoZWNrIHN0YXRlICovXG4gIGlmICghc3RybSB8fCAhc3RybS5zdGF0ZSkgeyByZXR1cm4gWl9TVFJFQU1fRVJST1I7IH1cbiAgc3RhdGUgPSBzdHJtLnN0YXRlO1xuICBpZiAoKHN0YXRlLndyYXAgJiAyKSA9PT0gMCkgeyByZXR1cm4gWl9TVFJFQU1fRVJST1I7IH1cblxuICAvKiBzYXZlIGhlYWRlciBzdHJ1Y3R1cmUgKi9cbiAgc3RhdGUuaGVhZCA9IGhlYWQ7XG4gIGhlYWQuZG9uZSA9IGZhbHNlO1xuICByZXR1cm4gWl9PSztcbn1cblxuXG5leHBvcnRzLmluZmxhdGVSZXNldCA9IGluZmxhdGVSZXNldDtcbmV4cG9ydHMuaW5mbGF0ZVJlc2V0MiA9IGluZmxhdGVSZXNldDI7XG5leHBvcnRzLmluZmxhdGVSZXNldEtlZXAgPSBpbmZsYXRlUmVzZXRLZWVwO1xuZXhwb3J0cy5pbmZsYXRlSW5pdCA9IGluZmxhdGVJbml0O1xuZXhwb3J0cy5pbmZsYXRlSW5pdDIgPSBpbmZsYXRlSW5pdDI7XG5leHBvcnRzLmluZmxhdGUgPSBpbmZsYXRlO1xuZXhwb3J0cy5pbmZsYXRlRW5kID0gaW5mbGF0ZUVuZDtcbmV4cG9ydHMuaW5mbGF0ZUdldEhlYWRlciA9IGluZmxhdGVHZXRIZWFkZXI7XG5leHBvcnRzLmluZmxhdGVJbmZvID0gJ3Bha28gaW5mbGF0ZSAoZnJvbSBOb2RlY2EgcHJvamVjdCknO1xuXG4vKiBOb3QgaW1wbGVtZW50ZWRcbmV4cG9ydHMuaW5mbGF0ZUNvcHkgPSBpbmZsYXRlQ29weTtcbmV4cG9ydHMuaW5mbGF0ZUdldERpY3Rpb25hcnkgPSBpbmZsYXRlR2V0RGljdGlvbmFyeTtcbmV4cG9ydHMuaW5mbGF0ZU1hcmsgPSBpbmZsYXRlTWFyaztcbmV4cG9ydHMuaW5mbGF0ZVByaW1lID0gaW5mbGF0ZVByaW1lO1xuZXhwb3J0cy5pbmZsYXRlU2V0RGljdGlvbmFyeSA9IGluZmxhdGVTZXREaWN0aW9uYXJ5O1xuZXhwb3J0cy5pbmZsYXRlU3luYyA9IGluZmxhdGVTeW5jO1xuZXhwb3J0cy5pbmZsYXRlU3luY1BvaW50ID0gaW5mbGF0ZVN5bmNQb2ludDtcbmV4cG9ydHMuaW5mbGF0ZVVuZGVybWluZSA9IGluZmxhdGVVbmRlcm1pbmU7XG4qLyIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy9jb21tb24nKTtcblxudmFyIE1BWEJJVFMgPSAxNTtcbnZhciBFTk9VR0hfTEVOUyA9IDg1MjtcbnZhciBFTk9VR0hfRElTVFMgPSA1OTI7XG4vL3ZhciBFTk9VR0ggPSAoRU5PVUdIX0xFTlMrRU5PVUdIX0RJU1RTKTtcblxudmFyIENPREVTID0gMDtcbnZhciBMRU5TID0gMTtcbnZhciBESVNUUyA9IDI7XG5cbnZhciBsYmFzZSA9IFsgLyogTGVuZ3RoIGNvZGVzIDI1Ny4uMjg1IGJhc2UgKi9cbiAgMywgNCwgNSwgNiwgNywgOCwgOSwgMTAsIDExLCAxMywgMTUsIDE3LCAxOSwgMjMsIDI3LCAzMSxcbiAgMzUsIDQzLCA1MSwgNTksIDY3LCA4MywgOTksIDExNSwgMTMxLCAxNjMsIDE5NSwgMjI3LCAyNTgsIDAsIDBcbl07XG5cbnZhciBsZXh0ID0gWyAvKiBMZW5ndGggY29kZXMgMjU3Li4yODUgZXh0cmEgKi9cbiAgMTYsIDE2LCAxNiwgMTYsIDE2LCAxNiwgMTYsIDE2LCAxNywgMTcsIDE3LCAxNywgMTgsIDE4LCAxOCwgMTgsXG4gIDE5LCAxOSwgMTksIDE5LCAyMCwgMjAsIDIwLCAyMCwgMjEsIDIxLCAyMSwgMjEsIDE2LCA3MiwgNzhcbl07XG5cbnZhciBkYmFzZSA9IFsgLyogRGlzdGFuY2UgY29kZXMgMC4uMjkgYmFzZSAqL1xuICAxLCAyLCAzLCA0LCA1LCA3LCA5LCAxMywgMTcsIDI1LCAzMywgNDksIDY1LCA5NywgMTI5LCAxOTMsXG4gIDI1NywgMzg1LCA1MTMsIDc2OSwgMTAyNSwgMTUzNywgMjA0OSwgMzA3MywgNDA5NywgNjE0NSxcbiAgODE5MywgMTIyODksIDE2Mzg1LCAyNDU3NywgMCwgMFxuXTtcblxudmFyIGRleHQgPSBbIC8qIERpc3RhbmNlIGNvZGVzIDAuLjI5IGV4dHJhICovXG4gIDE2LCAxNiwgMTYsIDE2LCAxNywgMTcsIDE4LCAxOCwgMTksIDE5LCAyMCwgMjAsIDIxLCAyMSwgMjIsIDIyLFxuICAyMywgMjMsIDI0LCAyNCwgMjUsIDI1LCAyNiwgMjYsIDI3LCAyNyxcbiAgMjgsIDI4LCAyOSwgMjksIDY0LCA2NFxuXTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBpbmZsYXRlX3RhYmxlKHR5cGUsIGxlbnMsIGxlbnNfaW5kZXgsIGNvZGVzLCB0YWJsZSwgdGFibGVfaW5kZXgsIHdvcmssIG9wdHMpXG57XG4gIHZhciBiaXRzID0gb3B0cy5iaXRzO1xuICAgICAgLy9oZXJlID0gb3B0cy5oZXJlOyAvKiB0YWJsZSBlbnRyeSBmb3IgZHVwbGljYXRpb24gKi9cblxuICB2YXIgbGVuID0gMDsgICAgICAgICAgICAgICAvKiBhIGNvZGUncyBsZW5ndGggaW4gYml0cyAqL1xuICB2YXIgc3ltID0gMDsgICAgICAgICAgICAgICAvKiBpbmRleCBvZiBjb2RlIHN5bWJvbHMgKi9cbiAgdmFyIG1pbiA9IDAsIG1heCA9IDA7ICAgICAgICAgIC8qIG1pbmltdW0gYW5kIG1heGltdW0gY29kZSBsZW5ndGhzICovXG4gIHZhciByb290ID0gMDsgICAgICAgICAgICAgIC8qIG51bWJlciBvZiBpbmRleCBiaXRzIGZvciByb290IHRhYmxlICovXG4gIHZhciBjdXJyID0gMDsgICAgICAgICAgICAgIC8qIG51bWJlciBvZiBpbmRleCBiaXRzIGZvciBjdXJyZW50IHRhYmxlICovXG4gIHZhciBkcm9wID0gMDsgICAgICAgICAgICAgIC8qIGNvZGUgYml0cyB0byBkcm9wIGZvciBzdWItdGFibGUgKi9cbiAgdmFyIGxlZnQgPSAwOyAgICAgICAgICAgICAgICAgICAvKiBudW1iZXIgb2YgcHJlZml4IGNvZGVzIGF2YWlsYWJsZSAqL1xuICB2YXIgdXNlZCA9IDA7ICAgICAgICAgICAgICAvKiBjb2RlIGVudHJpZXMgaW4gdGFibGUgdXNlZCAqL1xuICB2YXIgaHVmZiA9IDA7ICAgICAgICAgICAgICAvKiBIdWZmbWFuIGNvZGUgKi9cbiAgdmFyIGluY3I7ICAgICAgICAgICAgICAvKiBmb3IgaW5jcmVtZW50aW5nIGNvZGUsIGluZGV4ICovXG4gIHZhciBmaWxsOyAgICAgICAgICAgICAgLyogaW5kZXggZm9yIHJlcGxpY2F0aW5nIGVudHJpZXMgKi9cbiAgdmFyIGxvdzsgICAgICAgICAgICAgICAvKiBsb3cgYml0cyBmb3IgY3VycmVudCByb290IGVudHJ5ICovXG4gIHZhciBtYXNrOyAgICAgICAgICAgICAgLyogbWFzayBmb3IgbG93IHJvb3QgYml0cyAqL1xuICB2YXIgbmV4dDsgICAgICAgICAgICAgLyogbmV4dCBhdmFpbGFibGUgc3BhY2UgaW4gdGFibGUgKi9cbiAgdmFyIGJhc2UgPSBudWxsOyAgICAgLyogYmFzZSB2YWx1ZSB0YWJsZSB0byB1c2UgKi9cbiAgdmFyIGJhc2VfaW5kZXggPSAwO1xuLy8gIHZhciBzaG9leHRyYTsgICAgLyogZXh0cmEgYml0cyB0YWJsZSB0byB1c2UgKi9cbiAgdmFyIGVuZDsgICAgICAgICAgICAgICAgICAgIC8qIHVzZSBiYXNlIGFuZCBleHRyYSBmb3Igc3ltYm9sID4gZW5kICovXG4gIHZhciBjb3VudCA9IG5ldyB1dGlscy5CdWYxNihNQVhCSVRTKzEpOyAvL1tNQVhCSVRTKzFdOyAgICAvKiBudW1iZXIgb2YgY29kZXMgb2YgZWFjaCBsZW5ndGggKi9cbiAgdmFyIG9mZnMgPSBuZXcgdXRpbHMuQnVmMTYoTUFYQklUUysxKTsgLy9bTUFYQklUUysxXTsgICAgIC8qIG9mZnNldHMgaW4gdGFibGUgZm9yIGVhY2ggbGVuZ3RoICovXG4gIHZhciBleHRyYSA9IG51bGw7XG4gIHZhciBleHRyYV9pbmRleCA9IDA7XG5cbiAgdmFyIGhlcmVfYml0cywgaGVyZV9vcCwgaGVyZV92YWw7XG5cbiAgLypcbiAgIFByb2Nlc3MgYSBzZXQgb2YgY29kZSBsZW5ndGhzIHRvIGNyZWF0ZSBhIGNhbm9uaWNhbCBIdWZmbWFuIGNvZGUuICBUaGVcbiAgIGNvZGUgbGVuZ3RocyBhcmUgbGVuc1swLi5jb2Rlcy0xXS4gIEVhY2ggbGVuZ3RoIGNvcnJlc3BvbmRzIHRvIHRoZVxuICAgc3ltYm9scyAwLi5jb2Rlcy0xLiAgVGhlIEh1ZmZtYW4gY29kZSBpcyBnZW5lcmF0ZWQgYnkgZmlyc3Qgc29ydGluZyB0aGVcbiAgIHN5bWJvbHMgYnkgbGVuZ3RoIGZyb20gc2hvcnQgdG8gbG9uZywgYW5kIHJldGFpbmluZyB0aGUgc3ltYm9sIG9yZGVyXG4gICBmb3IgY29kZXMgd2l0aCBlcXVhbCBsZW5ndGhzLiAgVGhlbiB0aGUgY29kZSBzdGFydHMgd2l0aCBhbGwgemVybyBiaXRzXG4gICBmb3IgdGhlIGZpcnN0IGNvZGUgb2YgdGhlIHNob3J0ZXN0IGxlbmd0aCwgYW5kIHRoZSBjb2RlcyBhcmUgaW50ZWdlclxuICAgaW5jcmVtZW50cyBmb3IgdGhlIHNhbWUgbGVuZ3RoLCBhbmQgemVyb3MgYXJlIGFwcGVuZGVkIGFzIHRoZSBsZW5ndGhcbiAgIGluY3JlYXNlcy4gIEZvciB0aGUgZGVmbGF0ZSBmb3JtYXQsIHRoZXNlIGJpdHMgYXJlIHN0b3JlZCBiYWNrd2FyZHNcbiAgIGZyb20gdGhlaXIgbW9yZSBuYXR1cmFsIGludGVnZXIgaW5jcmVtZW50IG9yZGVyaW5nLCBhbmQgc28gd2hlbiB0aGVcbiAgIGRlY29kaW5nIHRhYmxlcyBhcmUgYnVpbHQgaW4gdGhlIGxhcmdlIGxvb3AgYmVsb3csIHRoZSBpbnRlZ2VyIGNvZGVzXG4gICBhcmUgaW5jcmVtZW50ZWQgYmFja3dhcmRzLlxuXG4gICBUaGlzIHJvdXRpbmUgYXNzdW1lcywgYnV0IGRvZXMgbm90IGNoZWNrLCB0aGF0IGFsbCBvZiB0aGUgZW50cmllcyBpblxuICAgbGVuc1tdIGFyZSBpbiB0aGUgcmFuZ2UgMC4uTUFYQklUUy4gIFRoZSBjYWxsZXIgbXVzdCBhc3N1cmUgdGhpcy5cbiAgIDEuLk1BWEJJVFMgaXMgaW50ZXJwcmV0ZWQgYXMgdGhhdCBjb2RlIGxlbmd0aC4gIHplcm8gbWVhbnMgdGhhdCB0aGF0XG4gICBzeW1ib2wgZG9lcyBub3Qgb2NjdXIgaW4gdGhpcyBjb2RlLlxuXG4gICBUaGUgY29kZXMgYXJlIHNvcnRlZCBieSBjb21wdXRpbmcgYSBjb3VudCBvZiBjb2RlcyBmb3IgZWFjaCBsZW5ndGgsXG4gICBjcmVhdGluZyBmcm9tIHRoYXQgYSB0YWJsZSBvZiBzdGFydGluZyBpbmRpY2VzIGZvciBlYWNoIGxlbmd0aCBpbiB0aGVcbiAgIHNvcnRlZCB0YWJsZSwgYW5kIHRoZW4gZW50ZXJpbmcgdGhlIHN5bWJvbHMgaW4gb3JkZXIgaW4gdGhlIHNvcnRlZFxuICAgdGFibGUuICBUaGUgc29ydGVkIHRhYmxlIGlzIHdvcmtbXSwgd2l0aCB0aGF0IHNwYWNlIGJlaW5nIHByb3ZpZGVkIGJ5XG4gICB0aGUgY2FsbGVyLlxuXG4gICBUaGUgbGVuZ3RoIGNvdW50cyBhcmUgdXNlZCBmb3Igb3RoZXIgcHVycG9zZXMgYXMgd2VsbCwgaS5lLiBmaW5kaW5nXG4gICB0aGUgbWluaW11bSBhbmQgbWF4aW11bSBsZW5ndGggY29kZXMsIGRldGVybWluaW5nIGlmIHRoZXJlIGFyZSBhbnlcbiAgIGNvZGVzIGF0IGFsbCwgY2hlY2tpbmcgZm9yIGEgdmFsaWQgc2V0IG9mIGxlbmd0aHMsIGFuZCBsb29raW5nIGFoZWFkXG4gICBhdCBsZW5ndGggY291bnRzIHRvIGRldGVybWluZSBzdWItdGFibGUgc2l6ZXMgd2hlbiBidWlsZGluZyB0aGVcbiAgIGRlY29kaW5nIHRhYmxlcy5cbiAgICovXG5cbiAgLyogYWNjdW11bGF0ZSBsZW5ndGhzIGZvciBjb2RlcyAoYXNzdW1lcyBsZW5zW10gYWxsIGluIDAuLk1BWEJJVFMpICovXG4gIGZvciAobGVuID0gMDsgbGVuIDw9IE1BWEJJVFM7IGxlbisrKSB7XG4gICAgY291bnRbbGVuXSA9IDA7XG4gIH1cbiAgZm9yIChzeW0gPSAwOyBzeW0gPCBjb2Rlczsgc3ltKyspIHtcbiAgICBjb3VudFtsZW5zW2xlbnNfaW5kZXggKyBzeW1dXSsrO1xuICB9XG5cbiAgLyogYm91bmQgY29kZSBsZW5ndGhzLCBmb3JjZSByb290IHRvIGJlIHdpdGhpbiBjb2RlIGxlbmd0aHMgKi9cbiAgcm9vdCA9IGJpdHM7XG4gIGZvciAobWF4ID0gTUFYQklUUzsgbWF4ID49IDE7IG1heC0tKSB7XG4gICAgaWYgKGNvdW50W21heF0gIT09IDApIHsgYnJlYWs7IH1cbiAgfVxuICBpZiAocm9vdCA+IG1heCkge1xuICAgIHJvb3QgPSBtYXg7XG4gIH1cbiAgaWYgKG1heCA9PT0gMCkgeyAgICAgICAgICAgICAgICAgICAgIC8qIG5vIHN5bWJvbHMgdG8gY29kZSBhdCBhbGwgKi9cbiAgICAvL3RhYmxlLm9wW29wdHMudGFibGVfaW5kZXhdID0gNjQ7ICAvL2hlcmUub3AgPSAodmFyIGNoYXIpNjQ7ICAgIC8qIGludmFsaWQgY29kZSBtYXJrZXIgKi9cbiAgICAvL3RhYmxlLmJpdHNbb3B0cy50YWJsZV9pbmRleF0gPSAxOyAgIC8vaGVyZS5iaXRzID0gKHZhciBjaGFyKTE7XG4gICAgLy90YWJsZS52YWxbb3B0cy50YWJsZV9pbmRleCsrXSA9IDA7ICAgLy9oZXJlLnZhbCA9ICh2YXIgc2hvcnQpMDtcbiAgICB0YWJsZVt0YWJsZV9pbmRleCsrXSA9ICgxIDw8IDI0KSB8ICg2NCA8PCAxNikgfCAwO1xuXG5cbiAgICAvL3RhYmxlLm9wW29wdHMudGFibGVfaW5kZXhdID0gNjQ7XG4gICAgLy90YWJsZS5iaXRzW29wdHMudGFibGVfaW5kZXhdID0gMTtcbiAgICAvL3RhYmxlLnZhbFtvcHRzLnRhYmxlX2luZGV4KytdID0gMDtcbiAgICB0YWJsZVt0YWJsZV9pbmRleCsrXSA9ICgxIDw8IDI0KSB8ICg2NCA8PCAxNikgfCAwO1xuXG4gICAgb3B0cy5iaXRzID0gMTtcbiAgICByZXR1cm4gMDsgICAgIC8qIG5vIHN5bWJvbHMsIGJ1dCB3YWl0IGZvciBkZWNvZGluZyB0byByZXBvcnQgZXJyb3IgKi9cbiAgfVxuICBmb3IgKG1pbiA9IDE7IG1pbiA8IG1heDsgbWluKyspIHtcbiAgICBpZiAoY291bnRbbWluXSAhPT0gMCkgeyBicmVhazsgfVxuICB9XG4gIGlmIChyb290IDwgbWluKSB7XG4gICAgcm9vdCA9IG1pbjtcbiAgfVxuXG4gIC8qIGNoZWNrIGZvciBhbiBvdmVyLXN1YnNjcmliZWQgb3IgaW5jb21wbGV0ZSBzZXQgb2YgbGVuZ3RocyAqL1xuICBsZWZ0ID0gMTtcbiAgZm9yIChsZW4gPSAxOyBsZW4gPD0gTUFYQklUUzsgbGVuKyspIHtcbiAgICBsZWZ0IDw8PSAxO1xuICAgIGxlZnQgLT0gY291bnRbbGVuXTtcbiAgICBpZiAobGVmdCA8IDApIHtcbiAgICAgIHJldHVybiAtMTtcbiAgICB9ICAgICAgICAvKiBvdmVyLXN1YnNjcmliZWQgKi9cbiAgfVxuICBpZiAobGVmdCA+IDAgJiYgKHR5cGUgPT09IENPREVTIHx8IG1heCAhPT0gMSkpIHtcbiAgICByZXR1cm4gLTE7ICAgICAgICAgICAgICAgICAgICAgIC8qIGluY29tcGxldGUgc2V0ICovXG4gIH1cblxuICAvKiBnZW5lcmF0ZSBvZmZzZXRzIGludG8gc3ltYm9sIHRhYmxlIGZvciBlYWNoIGxlbmd0aCBmb3Igc29ydGluZyAqL1xuICBvZmZzWzFdID0gMDtcbiAgZm9yIChsZW4gPSAxOyBsZW4gPCBNQVhCSVRTOyBsZW4rKykge1xuICAgIG9mZnNbbGVuICsgMV0gPSBvZmZzW2xlbl0gKyBjb3VudFtsZW5dO1xuICB9XG5cbiAgLyogc29ydCBzeW1ib2xzIGJ5IGxlbmd0aCwgYnkgc3ltYm9sIG9yZGVyIHdpdGhpbiBlYWNoIGxlbmd0aCAqL1xuICBmb3IgKHN5bSA9IDA7IHN5bSA8IGNvZGVzOyBzeW0rKykge1xuICAgIGlmIChsZW5zW2xlbnNfaW5kZXggKyBzeW1dICE9PSAwKSB7XG4gICAgICB3b3JrW29mZnNbbGVuc1tsZW5zX2luZGV4ICsgc3ltXV0rK10gPSBzeW07XG4gICAgfVxuICB9XG5cbiAgLypcbiAgIENyZWF0ZSBhbmQgZmlsbCBpbiBkZWNvZGluZyB0YWJsZXMuICBJbiB0aGlzIGxvb3AsIHRoZSB0YWJsZSBiZWluZ1xuICAgZmlsbGVkIGlzIGF0IG5leHQgYW5kIGhhcyBjdXJyIGluZGV4IGJpdHMuICBUaGUgY29kZSBiZWluZyB1c2VkIGlzIGh1ZmZcbiAgIHdpdGggbGVuZ3RoIGxlbi4gIFRoYXQgY29kZSBpcyBjb252ZXJ0ZWQgdG8gYW4gaW5kZXggYnkgZHJvcHBpbmcgZHJvcFxuICAgYml0cyBvZmYgb2YgdGhlIGJvdHRvbS4gIEZvciBjb2RlcyB3aGVyZSBsZW4gaXMgbGVzcyB0aGFuIGRyb3AgKyBjdXJyLFxuICAgdGhvc2UgdG9wIGRyb3AgKyBjdXJyIC0gbGVuIGJpdHMgYXJlIGluY3JlbWVudGVkIHRocm91Z2ggYWxsIHZhbHVlcyB0b1xuICAgZmlsbCB0aGUgdGFibGUgd2l0aCByZXBsaWNhdGVkIGVudHJpZXMuXG5cbiAgIHJvb3QgaXMgdGhlIG51bWJlciBvZiBpbmRleCBiaXRzIGZvciB0aGUgcm9vdCB0YWJsZS4gIFdoZW4gbGVuIGV4Y2VlZHNcbiAgIHJvb3QsIHN1Yi10YWJsZXMgYXJlIGNyZWF0ZWQgcG9pbnRlZCB0byBieSB0aGUgcm9vdCBlbnRyeSB3aXRoIGFuIGluZGV4XG4gICBvZiB0aGUgbG93IHJvb3QgYml0cyBvZiBodWZmLiAgVGhpcyBpcyBzYXZlZCBpbiBsb3cgdG8gY2hlY2sgZm9yIHdoZW4gYVxuICAgbmV3IHN1Yi10YWJsZSBzaG91bGQgYmUgc3RhcnRlZC4gIGRyb3AgaXMgemVybyB3aGVuIHRoZSByb290IHRhYmxlIGlzXG4gICBiZWluZyBmaWxsZWQsIGFuZCBkcm9wIGlzIHJvb3Qgd2hlbiBzdWItdGFibGVzIGFyZSBiZWluZyBmaWxsZWQuXG5cbiAgIFdoZW4gYSBuZXcgc3ViLXRhYmxlIGlzIG5lZWRlZCwgaXQgaXMgbmVjZXNzYXJ5IHRvIGxvb2sgYWhlYWQgaW4gdGhlXG4gICBjb2RlIGxlbmd0aHMgdG8gZGV0ZXJtaW5lIHdoYXQgc2l6ZSBzdWItdGFibGUgaXMgbmVlZGVkLiAgVGhlIGxlbmd0aFxuICAgY291bnRzIGFyZSB1c2VkIGZvciB0aGlzLCBhbmQgc28gY291bnRbXSBpcyBkZWNyZW1lbnRlZCBhcyBjb2RlcyBhcmVcbiAgIGVudGVyZWQgaW4gdGhlIHRhYmxlcy5cblxuICAgdXNlZCBrZWVwcyB0cmFjayBvZiBob3cgbWFueSB0YWJsZSBlbnRyaWVzIGhhdmUgYmVlbiBhbGxvY2F0ZWQgZnJvbSB0aGVcbiAgIHByb3ZpZGVkICp0YWJsZSBzcGFjZS4gIEl0IGlzIGNoZWNrZWQgZm9yIExFTlMgYW5kIERJU1QgdGFibGVzIGFnYWluc3RcbiAgIHRoZSBjb25zdGFudHMgRU5PVUdIX0xFTlMgYW5kIEVOT1VHSF9ESVNUUyB0byBndWFyZCBhZ2FpbnN0IGNoYW5nZXMgaW5cbiAgIHRoZSBpbml0aWFsIHJvb3QgdGFibGUgc2l6ZSBjb25zdGFudHMuICBTZWUgdGhlIGNvbW1lbnRzIGluIGluZnRyZWVzLmhcbiAgIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuXG4gICBzeW0gaW5jcmVtZW50cyB0aHJvdWdoIGFsbCBzeW1ib2xzLCBhbmQgdGhlIGxvb3AgdGVybWluYXRlcyB3aGVuXG4gICBhbGwgY29kZXMgb2YgbGVuZ3RoIG1heCwgaS5lLiBhbGwgY29kZXMsIGhhdmUgYmVlbiBwcm9jZXNzZWQuICBUaGlzXG4gICByb3V0aW5lIHBlcm1pdHMgaW5jb21wbGV0ZSBjb2Rlcywgc28gYW5vdGhlciBsb29wIGFmdGVyIHRoaXMgb25lIGZpbGxzXG4gICBpbiB0aGUgcmVzdCBvZiB0aGUgZGVjb2RpbmcgdGFibGVzIHdpdGggaW52YWxpZCBjb2RlIG1hcmtlcnMuXG4gICAqL1xuXG4gIC8qIHNldCB1cCBmb3IgY29kZSB0eXBlICovXG4gIC8vIHBvb3IgbWFuIG9wdGltaXphdGlvbiAtIHVzZSBpZi1lbHNlIGluc3RlYWQgb2Ygc3dpdGNoLFxuICAvLyB0byBhdm9pZCBkZW9wdHMgaW4gb2xkIHY4XG4gIGlmICh0eXBlID09PSBDT0RFUykge1xuICAgICAgYmFzZSA9IGV4dHJhID0gd29yazsgICAgLyogZHVtbXkgdmFsdWUtLW5vdCB1c2VkICovXG4gICAgICBlbmQgPSAxOTtcbiAgfSBlbHNlIGlmICh0eXBlID09PSBMRU5TKSB7XG4gICAgICBiYXNlID0gbGJhc2U7XG4gICAgICBiYXNlX2luZGV4IC09IDI1NztcbiAgICAgIGV4dHJhID0gbGV4dDtcbiAgICAgIGV4dHJhX2luZGV4IC09IDI1NztcbiAgICAgIGVuZCA9IDI1NjtcbiAgfSBlbHNlIHsgICAgICAgICAgICAgICAgICAgIC8qIERJU1RTICovXG4gICAgICBiYXNlID0gZGJhc2U7XG4gICAgICBleHRyYSA9IGRleHQ7XG4gICAgICBlbmQgPSAtMTtcbiAgfVxuXG4gIC8qIGluaXRpYWxpemUgb3B0cyBmb3IgbG9vcCAqL1xuICBodWZmID0gMDsgICAgICAgICAgICAgICAgICAgLyogc3RhcnRpbmcgY29kZSAqL1xuICBzeW0gPSAwOyAgICAgICAgICAgICAgICAgICAgLyogc3RhcnRpbmcgY29kZSBzeW1ib2wgKi9cbiAgbGVuID0gbWluOyAgICAgICAgICAgICAgICAgIC8qIHN0YXJ0aW5nIGNvZGUgbGVuZ3RoICovXG4gIG5leHQgPSB0YWJsZV9pbmRleDsgICAgICAgICAgICAgIC8qIGN1cnJlbnQgdGFibGUgdG8gZmlsbCBpbiAqL1xuICBjdXJyID0gcm9vdDsgICAgICAgICAgICAgICAgLyogY3VycmVudCB0YWJsZSBpbmRleCBiaXRzICovXG4gIGRyb3AgPSAwOyAgICAgICAgICAgICAgICAgICAvKiBjdXJyZW50IGJpdHMgdG8gZHJvcCBmcm9tIGNvZGUgZm9yIGluZGV4ICovXG4gIGxvdyA9IC0xOyAgICAgICAgICAgICAgICAgICAvKiB0cmlnZ2VyIG5ldyBzdWItdGFibGUgd2hlbiBsZW4gPiByb290ICovXG4gIHVzZWQgPSAxIDw8IHJvb3Q7ICAgICAgICAgIC8qIHVzZSByb290IHRhYmxlIGVudHJpZXMgKi9cbiAgbWFzayA9IHVzZWQgLSAxOyAgICAgICAgICAgIC8qIG1hc2sgZm9yIGNvbXBhcmluZyBsb3cgKi9cblxuICAvKiBjaGVjayBhdmFpbGFibGUgdGFibGUgc3BhY2UgKi9cbiAgaWYgKCh0eXBlID09PSBMRU5TICYmIHVzZWQgPiBFTk9VR0hfTEVOUykgfHxcbiAgICAodHlwZSA9PT0gRElTVFMgJiYgdXNlZCA+IEVOT1VHSF9ESVNUUykpIHtcbiAgICByZXR1cm4gMTtcbiAgfVxuXG4gIHZhciBpPTA7XG4gIC8qIHByb2Nlc3MgYWxsIGNvZGVzIGFuZCBtYWtlIHRhYmxlIGVudHJpZXMgKi9cbiAgZm9yICg7Oykge1xuICAgIGkrKztcbiAgICAvKiBjcmVhdGUgdGFibGUgZW50cnkgKi9cbiAgICBoZXJlX2JpdHMgPSBsZW4gLSBkcm9wO1xuICAgIGlmICh3b3JrW3N5bV0gPCBlbmQpIHtcbiAgICAgIGhlcmVfb3AgPSAwO1xuICAgICAgaGVyZV92YWwgPSB3b3JrW3N5bV07XG4gICAgfVxuICAgIGVsc2UgaWYgKHdvcmtbc3ltXSA+IGVuZCkge1xuICAgICAgaGVyZV9vcCA9IGV4dHJhW2V4dHJhX2luZGV4ICsgd29ya1tzeW1dXTtcbiAgICAgIGhlcmVfdmFsID0gYmFzZVtiYXNlX2luZGV4ICsgd29ya1tzeW1dXTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICBoZXJlX29wID0gMzIgKyA2NDsgICAgICAgICAvKiBlbmQgb2YgYmxvY2sgKi9cbiAgICAgIGhlcmVfdmFsID0gMDtcbiAgICB9XG5cbiAgICAvKiByZXBsaWNhdGUgZm9yIHRob3NlIGluZGljZXMgd2l0aCBsb3cgbGVuIGJpdHMgZXF1YWwgdG8gaHVmZiAqL1xuICAgIGluY3IgPSAxIDw8IChsZW4gLSBkcm9wKTtcbiAgICBmaWxsID0gMSA8PCBjdXJyO1xuICAgIG1pbiA9IGZpbGw7ICAgICAgICAgICAgICAgICAvKiBzYXZlIG9mZnNldCB0byBuZXh0IHRhYmxlICovXG4gICAgZG8ge1xuICAgICAgZmlsbCAtPSBpbmNyO1xuICAgICAgdGFibGVbbmV4dCArIChodWZmID4+IGRyb3ApICsgZmlsbF0gPSAoaGVyZV9iaXRzIDw8IDI0KSB8IChoZXJlX29wIDw8IDE2KSB8IGhlcmVfdmFsIHwwO1xuICAgIH0gd2hpbGUgKGZpbGwgIT09IDApO1xuXG4gICAgLyogYmFja3dhcmRzIGluY3JlbWVudCB0aGUgbGVuLWJpdCBjb2RlIGh1ZmYgKi9cbiAgICBpbmNyID0gMSA8PCAobGVuIC0gMSk7XG4gICAgd2hpbGUgKGh1ZmYgJiBpbmNyKSB7XG4gICAgICBpbmNyID4+PSAxO1xuICAgIH1cbiAgICBpZiAoaW5jciAhPT0gMCkge1xuICAgICAgaHVmZiAmPSBpbmNyIC0gMTtcbiAgICAgIGh1ZmYgKz0gaW5jcjtcbiAgICB9IGVsc2Uge1xuICAgICAgaHVmZiA9IDA7XG4gICAgfVxuXG4gICAgLyogZ28gdG8gbmV4dCBzeW1ib2wsIHVwZGF0ZSBjb3VudCwgbGVuICovXG4gICAgc3ltKys7XG4gICAgaWYgKC0tY291bnRbbGVuXSA9PT0gMCkge1xuICAgICAgaWYgKGxlbiA9PT0gbWF4KSB7IGJyZWFrOyB9XG4gICAgICBsZW4gPSBsZW5zW2xlbnNfaW5kZXggKyB3b3JrW3N5bV1dO1xuICAgIH1cblxuICAgIC8qIGNyZWF0ZSBuZXcgc3ViLXRhYmxlIGlmIG5lZWRlZCAqL1xuICAgIGlmIChsZW4gPiByb290ICYmIChodWZmICYgbWFzaykgIT09IGxvdykge1xuICAgICAgLyogaWYgZmlyc3QgdGltZSwgdHJhbnNpdGlvbiB0byBzdWItdGFibGVzICovXG4gICAgICBpZiAoZHJvcCA9PT0gMCkge1xuICAgICAgICBkcm9wID0gcm9vdDtcbiAgICAgIH1cblxuICAgICAgLyogaW5jcmVtZW50IHBhc3QgbGFzdCB0YWJsZSAqL1xuICAgICAgbmV4dCArPSBtaW47ICAgICAgICAgICAgLyogaGVyZSBtaW4gaXMgMSA8PCBjdXJyICovXG5cbiAgICAgIC8qIGRldGVybWluZSBsZW5ndGggb2YgbmV4dCB0YWJsZSAqL1xuICAgICAgY3VyciA9IGxlbiAtIGRyb3A7XG4gICAgICBsZWZ0ID0gMSA8PCBjdXJyO1xuICAgICAgd2hpbGUgKGN1cnIgKyBkcm9wIDwgbWF4KSB7XG4gICAgICAgIGxlZnQgLT0gY291bnRbY3VyciArIGRyb3BdO1xuICAgICAgICBpZiAobGVmdCA8PSAwKSB7IGJyZWFrOyB9XG4gICAgICAgIGN1cnIrKztcbiAgICAgICAgbGVmdCA8PD0gMTtcbiAgICAgIH1cblxuICAgICAgLyogY2hlY2sgZm9yIGVub3VnaCBzcGFjZSAqL1xuICAgICAgdXNlZCArPSAxIDw8IGN1cnI7XG4gICAgICBpZiAoKHR5cGUgPT09IExFTlMgJiYgdXNlZCA+IEVOT1VHSF9MRU5TKSB8fFxuICAgICAgICAodHlwZSA9PT0gRElTVFMgJiYgdXNlZCA+IEVOT1VHSF9ESVNUUykpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9XG5cbiAgICAgIC8qIHBvaW50IGVudHJ5IGluIHJvb3QgdGFibGUgdG8gc3ViLXRhYmxlICovXG4gICAgICBsb3cgPSBodWZmICYgbWFzaztcbiAgICAgIC8qdGFibGUub3BbbG93XSA9IGN1cnI7XG4gICAgICB0YWJsZS5iaXRzW2xvd10gPSByb290O1xuICAgICAgdGFibGUudmFsW2xvd10gPSBuZXh0IC0gb3B0cy50YWJsZV9pbmRleDsqL1xuICAgICAgdGFibGVbbG93XSA9IChyb290IDw8IDI0KSB8IChjdXJyIDw8IDE2KSB8IChuZXh0IC0gdGFibGVfaW5kZXgpIHwwO1xuICAgIH1cbiAgfVxuXG4gIC8qIGZpbGwgaW4gcmVtYWluaW5nIHRhYmxlIGVudHJ5IGlmIGNvZGUgaXMgaW5jb21wbGV0ZSAoZ3VhcmFudGVlZCB0byBoYXZlXG4gICBhdCBtb3N0IG9uZSByZW1haW5pbmcgZW50cnksIHNpbmNlIGlmIHRoZSBjb2RlIGlzIGluY29tcGxldGUsIHRoZVxuICAgbWF4aW11bSBjb2RlIGxlbmd0aCB0aGF0IHdhcyBhbGxvd2VkIHRvIGdldCB0aGlzIGZhciBpcyBvbmUgYml0KSAqL1xuICBpZiAoaHVmZiAhPT0gMCkge1xuICAgIC8vdGFibGUub3BbbmV4dCArIGh1ZmZdID0gNjQ7ICAgICAgICAgICAgLyogaW52YWxpZCBjb2RlIG1hcmtlciAqL1xuICAgIC8vdGFibGUuYml0c1tuZXh0ICsgaHVmZl0gPSBsZW4gLSBkcm9wO1xuICAgIC8vdGFibGUudmFsW25leHQgKyBodWZmXSA9IDA7XG4gICAgdGFibGVbbmV4dCArIGh1ZmZdID0gKChsZW4gLSBkcm9wKSA8PCAyNCkgfCAoNjQgPDwgMTYpIHwwO1xuICB9XG5cbiAgLyogc2V0IHJldHVybiBwYXJhbWV0ZXJzICovXG4gIC8vb3B0cy50YWJsZV9pbmRleCArPSB1c2VkO1xuICBvcHRzLmJpdHMgPSByb290O1xuICByZXR1cm4gMDtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAnMic6ICAgICduZWVkIGRpY3Rpb25hcnknLCAgICAgLyogWl9ORUVEX0RJQ1QgICAgICAgMiAgKi9cbiAgJzEnOiAgICAnc3RyZWFtIGVuZCcsICAgICAgICAgIC8qIFpfU1RSRUFNX0VORCAgICAgIDEgICovXG4gICcwJzogICAgJycsICAgICAgICAgICAgICAgICAgICAvKiBaX09LICAgICAgICAgICAgICAwICAqL1xuICAnLTEnOiAgICdmaWxlIGVycm9yJywgICAgICAgICAgLyogWl9FUlJOTyAgICAgICAgICgtMSkgKi9cbiAgJy0yJzogICAnc3RyZWFtIGVycm9yJywgICAgICAgIC8qIFpfU1RSRUFNX0VSUk9SICAoLTIpICovXG4gICctMyc6ICAgJ2RhdGEgZXJyb3InLCAgICAgICAgICAvKiBaX0RBVEFfRVJST1IgICAgKC0zKSAqL1xuICAnLTQnOiAgICdpbnN1ZmZpY2llbnQgbWVtb3J5JywgLyogWl9NRU1fRVJST1IgICAgICgtNCkgKi9cbiAgJy01JzogICAnYnVmZmVyIGVycm9yJywgICAgICAgIC8qIFpfQlVGX0VSUk9SICAgICAoLTUpICovXG4gICctNic6ICAgJ2luY29tcGF0aWJsZSB2ZXJzaW9uJyAvKiBaX1ZFUlNJT05fRVJST1IgKC02KSAqL1xufTsiLCIndXNlIHN0cmljdCc7XG5cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvY29tbW9uJyk7XG5cbi8qIFB1YmxpYyBjb25zdGFudHMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0qL1xuXG5cbi8vdmFyIFpfRklMVEVSRUQgICAgICAgICAgPSAxO1xuLy92YXIgWl9IVUZGTUFOX09OTFkgICAgICA9IDI7XG4vL3ZhciBaX1JMRSAgICAgICAgICAgICAgID0gMztcbnZhciBaX0ZJWEVEICAgICAgICAgICAgICAgPSA0O1xuLy92YXIgWl9ERUZBVUxUX1NUUkFURUdZICA9IDA7XG5cbi8qIFBvc3NpYmxlIHZhbHVlcyBvZiB0aGUgZGF0YV90eXBlIGZpZWxkICh0aG91Z2ggc2VlIGluZmxhdGUoKSkgKi9cbnZhciBaX0JJTkFSWSAgICAgICAgICAgICAgPSAwO1xudmFyIFpfVEVYVCAgICAgICAgICAgICAgICA9IDE7XG4vL3ZhciBaX0FTQ0lJICAgICAgICAgICAgID0gMTsgLy8gPSBaX1RFWFRcbnZhciBaX1VOS05PV04gICAgICAgICAgICAgPSAyO1xuXG4vKj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0qL1xuXG5cbmZ1bmN0aW9uIHplcm8oYnVmKSB7IHZhciBsZW4gPSBidWYubGVuZ3RoOyB3aGlsZSAoLS1sZW4gPj0gMCkgeyBidWZbbGVuXSA9IDA7IH0gfVxuXG4vLyBGcm9tIHp1dGlsLmhcblxudmFyIFNUT1JFRF9CTE9DSyA9IDA7XG52YXIgU1RBVElDX1RSRUVTID0gMTtcbnZhciBEWU5fVFJFRVMgICAgPSAyO1xuLyogVGhlIHRocmVlIGtpbmRzIG9mIGJsb2NrIHR5cGUgKi9cblxudmFyIE1JTl9NQVRDSCAgICA9IDM7XG52YXIgTUFYX01BVENIICAgID0gMjU4O1xuLyogVGhlIG1pbmltdW0gYW5kIG1heGltdW0gbWF0Y2ggbGVuZ3RocyAqL1xuXG4vLyBGcm9tIGRlZmxhdGUuaFxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBJbnRlcm5hbCBjb21wcmVzc2lvbiBzdGF0ZS5cbiAqL1xuXG52YXIgTEVOR1RIX0NPREVTICA9IDI5O1xuLyogbnVtYmVyIG9mIGxlbmd0aCBjb2Rlcywgbm90IGNvdW50aW5nIHRoZSBzcGVjaWFsIEVORF9CTE9DSyBjb2RlICovXG5cbnZhciBMSVRFUkFMUyAgICAgID0gMjU2O1xuLyogbnVtYmVyIG9mIGxpdGVyYWwgYnl0ZXMgMC4uMjU1ICovXG5cbnZhciBMX0NPREVTICAgICAgID0gTElURVJBTFMgKyAxICsgTEVOR1RIX0NPREVTO1xuLyogbnVtYmVyIG9mIExpdGVyYWwgb3IgTGVuZ3RoIGNvZGVzLCBpbmNsdWRpbmcgdGhlIEVORF9CTE9DSyBjb2RlICovXG5cbnZhciBEX0NPREVTICAgICAgID0gMzA7XG4vKiBudW1iZXIgb2YgZGlzdGFuY2UgY29kZXMgKi9cblxudmFyIEJMX0NPREVTICAgICAgPSAxOTtcbi8qIG51bWJlciBvZiBjb2RlcyB1c2VkIHRvIHRyYW5zZmVyIHRoZSBiaXQgbGVuZ3RocyAqL1xuXG52YXIgSEVBUF9TSVpFICAgICA9IDIqTF9DT0RFUyArIDE7XG4vKiBtYXhpbXVtIGhlYXAgc2l6ZSAqL1xuXG52YXIgTUFYX0JJVFMgICAgICA9IDE1O1xuLyogQWxsIGNvZGVzIG11c3Qgbm90IGV4Y2VlZCBNQVhfQklUUyBiaXRzICovXG5cbnZhciBCdWZfc2l6ZSAgICAgID0gMTY7XG4vKiBzaXplIG9mIGJpdCBidWZmZXIgaW4gYmlfYnVmICovXG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb25zdGFudHNcbiAqL1xuXG52YXIgTUFYX0JMX0JJVFMgPSA3O1xuLyogQml0IGxlbmd0aCBjb2RlcyBtdXN0IG5vdCBleGNlZWQgTUFYX0JMX0JJVFMgYml0cyAqL1xuXG52YXIgRU5EX0JMT0NLICAgPSAyNTY7XG4vKiBlbmQgb2YgYmxvY2sgbGl0ZXJhbCBjb2RlICovXG5cbnZhciBSRVBfM182ICAgICA9IDE2O1xuLyogcmVwZWF0IHByZXZpb3VzIGJpdCBsZW5ndGggMy02IHRpbWVzICgyIGJpdHMgb2YgcmVwZWF0IGNvdW50KSAqL1xuXG52YXIgUkVQWl8zXzEwICAgPSAxNztcbi8qIHJlcGVhdCBhIHplcm8gbGVuZ3RoIDMtMTAgdGltZXMgICgzIGJpdHMgb2YgcmVwZWF0IGNvdW50KSAqL1xuXG52YXIgUkVQWl8xMV8xMzggPSAxODtcbi8qIHJlcGVhdCBhIHplcm8gbGVuZ3RoIDExLTEzOCB0aW1lcyAgKDcgYml0cyBvZiByZXBlYXQgY291bnQpICovXG5cbnZhciBleHRyYV9sYml0cyA9ICAgLyogZXh0cmEgYml0cyBmb3IgZWFjaCBsZW5ndGggY29kZSAqL1xuICBbMCwwLDAsMCwwLDAsMCwwLDEsMSwxLDEsMiwyLDIsMiwzLDMsMywzLDQsNCw0LDQsNSw1LDUsNSwwXTtcblxudmFyIGV4dHJhX2RiaXRzID0gICAvKiBleHRyYSBiaXRzIGZvciBlYWNoIGRpc3RhbmNlIGNvZGUgKi9cbiAgWzAsMCwwLDAsMSwxLDIsMiwzLDMsNCw0LDUsNSw2LDYsNyw3LDgsOCw5LDksMTAsMTAsMTEsMTEsMTIsMTIsMTMsMTNdO1xuXG52YXIgZXh0cmFfYmxiaXRzID0gIC8qIGV4dHJhIGJpdHMgZm9yIGVhY2ggYml0IGxlbmd0aCBjb2RlICovXG4gIFswLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDIsMyw3XTtcblxudmFyIGJsX29yZGVyID1cbiAgWzE2LDE3LDE4LDAsOCw3LDksNiwxMCw1LDExLDQsMTIsMywxMywyLDE0LDEsMTVdO1xuLyogVGhlIGxlbmd0aHMgb2YgdGhlIGJpdCBsZW5ndGggY29kZXMgYXJlIHNlbnQgaW4gb3JkZXIgb2YgZGVjcmVhc2luZ1xuICogcHJvYmFiaWxpdHksIHRvIGF2b2lkIHRyYW5zbWl0dGluZyB0aGUgbGVuZ3RocyBmb3IgdW51c2VkIGJpdCBsZW5ndGggY29kZXMuXG4gKi9cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBMb2NhbCBkYXRhLiBUaGVzZSBhcmUgaW5pdGlhbGl6ZWQgb25seSBvbmNlLlxuICovXG5cbi8vIFdlIHByZS1maWxsIGFycmF5cyB3aXRoIDAgdG8gYXZvaWQgdW5pbml0aWFsaXplZCBnYXBzXG5cbnZhciBESVNUX0NPREVfTEVOID0gNTEyOyAvKiBzZWUgZGVmaW5pdGlvbiBvZiBhcnJheSBkaXN0X2NvZGUgYmVsb3cgKi9cblxuLy8gISEhISBVc2UgZmxhdCBhcnJheSBpbnNkZWFkIG9mIHN0cnVjdHVyZSwgRnJlcSA9IGkqMiwgTGVuID0gaSoyKzFcbnZhciBzdGF0aWNfbHRyZWUgID0gbmV3IEFycmF5KChMX0NPREVTKzIpICogMik7XG56ZXJvKHN0YXRpY19sdHJlZSk7XG4vKiBUaGUgc3RhdGljIGxpdGVyYWwgdHJlZS4gU2luY2UgdGhlIGJpdCBsZW5ndGhzIGFyZSBpbXBvc2VkLCB0aGVyZSBpcyBub1xuICogbmVlZCBmb3IgdGhlIExfQ09ERVMgZXh0cmEgY29kZXMgdXNlZCBkdXJpbmcgaGVhcCBjb25zdHJ1Y3Rpb24uIEhvd2V2ZXJcbiAqIFRoZSBjb2RlcyAyODYgYW5kIDI4NyBhcmUgbmVlZGVkIHRvIGJ1aWxkIGEgY2Fub25pY2FsIHRyZWUgKHNlZSBfdHJfaW5pdFxuICogYmVsb3cpLlxuICovXG5cbnZhciBzdGF0aWNfZHRyZWUgID0gbmV3IEFycmF5KERfQ09ERVMgKiAyKTtcbnplcm8oc3RhdGljX2R0cmVlKTtcbi8qIFRoZSBzdGF0aWMgZGlzdGFuY2UgdHJlZS4gKEFjdHVhbGx5IGEgdHJpdmlhbCB0cmVlIHNpbmNlIGFsbCBjb2RlcyB1c2VcbiAqIDUgYml0cy4pXG4gKi9cblxudmFyIF9kaXN0X2NvZGUgICAgPSBuZXcgQXJyYXkoRElTVF9DT0RFX0xFTik7XG56ZXJvKF9kaXN0X2NvZGUpO1xuLyogRGlzdGFuY2UgY29kZXMuIFRoZSBmaXJzdCAyNTYgdmFsdWVzIGNvcnJlc3BvbmQgdG8gdGhlIGRpc3RhbmNlc1xuICogMyAuLiAyNTgsIHRoZSBsYXN0IDI1NiB2YWx1ZXMgY29ycmVzcG9uZCB0byB0aGUgdG9wIDggYml0cyBvZlxuICogdGhlIDE1IGJpdCBkaXN0YW5jZXMuXG4gKi9cblxudmFyIF9sZW5ndGhfY29kZSAgPSBuZXcgQXJyYXkoTUFYX01BVENILU1JTl9NQVRDSCsxKTtcbnplcm8oX2xlbmd0aF9jb2RlKTtcbi8qIGxlbmd0aCBjb2RlIGZvciBlYWNoIG5vcm1hbGl6ZWQgbWF0Y2ggbGVuZ3RoICgwID09IE1JTl9NQVRDSCkgKi9cblxudmFyIGJhc2VfbGVuZ3RoICAgPSBuZXcgQXJyYXkoTEVOR1RIX0NPREVTKTtcbnplcm8oYmFzZV9sZW5ndGgpO1xuLyogRmlyc3Qgbm9ybWFsaXplZCBsZW5ndGggZm9yIGVhY2ggY29kZSAoMCA9IE1JTl9NQVRDSCkgKi9cblxudmFyIGJhc2VfZGlzdCAgICAgPSBuZXcgQXJyYXkoRF9DT0RFUyk7XG56ZXJvKGJhc2VfZGlzdCk7XG4vKiBGaXJzdCBub3JtYWxpemVkIGRpc3RhbmNlIGZvciBlYWNoIGNvZGUgKDAgPSBkaXN0YW5jZSBvZiAxKSAqL1xuXG5cbnZhciBTdGF0aWNUcmVlRGVzYyA9IGZ1bmN0aW9uIChzdGF0aWNfdHJlZSwgZXh0cmFfYml0cywgZXh0cmFfYmFzZSwgZWxlbXMsIG1heF9sZW5ndGgpIHtcblxuICB0aGlzLnN0YXRpY190cmVlICA9IHN0YXRpY190cmVlOyAgLyogc3RhdGljIHRyZWUgb3IgTlVMTCAqL1xuICB0aGlzLmV4dHJhX2JpdHMgICA9IGV4dHJhX2JpdHM7ICAgLyogZXh0cmEgYml0cyBmb3IgZWFjaCBjb2RlIG9yIE5VTEwgKi9cbiAgdGhpcy5leHRyYV9iYXNlICAgPSBleHRyYV9iYXNlOyAgIC8qIGJhc2UgaW5kZXggZm9yIGV4dHJhX2JpdHMgKi9cbiAgdGhpcy5lbGVtcyAgICAgICAgPSBlbGVtczsgICAgICAgIC8qIG1heCBudW1iZXIgb2YgZWxlbWVudHMgaW4gdGhlIHRyZWUgKi9cbiAgdGhpcy5tYXhfbGVuZ3RoICAgPSBtYXhfbGVuZ3RoOyAgIC8qIG1heCBiaXQgbGVuZ3RoIGZvciB0aGUgY29kZXMgKi9cblxuICAvLyBzaG93IGlmIGBzdGF0aWNfdHJlZWAgaGFzIGRhdGEgb3IgZHVtbXkgLSBuZWVkZWQgZm9yIG1vbm9tb3JwaGljIG9iamVjdHNcbiAgdGhpcy5oYXNfc3RyZWUgICAgPSBzdGF0aWNfdHJlZSAmJiBzdGF0aWNfdHJlZS5sZW5ndGg7XG59O1xuXG5cbnZhciBzdGF0aWNfbF9kZXNjO1xudmFyIHN0YXRpY19kX2Rlc2M7XG52YXIgc3RhdGljX2JsX2Rlc2M7XG5cblxudmFyIFRyZWVEZXNjID0gZnVuY3Rpb24oZHluX3RyZWUsIHN0YXRfZGVzYykge1xuICB0aGlzLmR5bl90cmVlID0gZHluX3RyZWU7ICAgICAvKiB0aGUgZHluYW1pYyB0cmVlICovXG4gIHRoaXMubWF4X2NvZGUgPSAwOyAgICAgICAgICAgIC8qIGxhcmdlc3QgY29kZSB3aXRoIG5vbiB6ZXJvIGZyZXF1ZW5jeSAqL1xuICB0aGlzLnN0YXRfZGVzYyA9IHN0YXRfZGVzYzsgICAvKiB0aGUgY29ycmVzcG9uZGluZyBzdGF0aWMgdHJlZSAqL1xufTtcblxuXG5cbmZ1bmN0aW9uIGRfY29kZShkaXN0KSB7XG4gIHJldHVybiBkaXN0IDwgMjU2ID8gX2Rpc3RfY29kZVtkaXN0XSA6IF9kaXN0X2NvZGVbMjU2ICsgKGRpc3QgPj4+IDcpXTtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIE91dHB1dCBhIHNob3J0IExTQiBmaXJzdCBvbiB0aGUgc3RyZWFtLlxuICogSU4gYXNzZXJ0aW9uOiB0aGVyZSBpcyBlbm91Z2ggcm9vbSBpbiBwZW5kaW5nQnVmLlxuICovXG5mdW5jdGlvbiBwdXRfc2hvcnQgKHMsIHcpIHtcbi8vICAgIHB1dF9ieXRlKHMsICh1Y2gpKCh3KSAmIDB4ZmYpKTtcbi8vICAgIHB1dF9ieXRlKHMsICh1Y2gpKCh1c2gpKHcpID4+IDgpKTtcbiAgcy5wZW5kaW5nX2J1ZltzLnBlbmRpbmcrK10gPSAodykgJiAweGZmO1xuICBzLnBlbmRpbmdfYnVmW3MucGVuZGluZysrXSA9ICh3ID4+PiA4KSAmIDB4ZmY7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBTZW5kIGEgdmFsdWUgb24gYSBnaXZlbiBudW1iZXIgb2YgYml0cy5cbiAqIElOIGFzc2VydGlvbjogbGVuZ3RoIDw9IDE2IGFuZCB2YWx1ZSBmaXRzIGluIGxlbmd0aCBiaXRzLlxuICovXG5mdW5jdGlvbiBzZW5kX2JpdHMocywgdmFsdWUsIGxlbmd0aCkge1xuICBpZiAocy5iaV92YWxpZCA+IChCdWZfc2l6ZSAtIGxlbmd0aCkpIHtcbiAgICBzLmJpX2J1ZiB8PSAodmFsdWUgPDwgcy5iaV92YWxpZCkgJiAweGZmZmY7XG4gICAgcHV0X3Nob3J0KHMsIHMuYmlfYnVmKTtcbiAgICBzLmJpX2J1ZiA9IHZhbHVlID4+IChCdWZfc2l6ZSAtIHMuYmlfdmFsaWQpO1xuICAgIHMuYmlfdmFsaWQgKz0gbGVuZ3RoIC0gQnVmX3NpemU7XG4gIH0gZWxzZSB7XG4gICAgcy5iaV9idWYgfD0gKHZhbHVlIDw8IHMuYmlfdmFsaWQpICYgMHhmZmZmO1xuICAgIHMuYmlfdmFsaWQgKz0gbGVuZ3RoO1xuICB9XG59XG5cblxuZnVuY3Rpb24gc2VuZF9jb2RlKHMsIGMsIHRyZWUpIHtcbiAgc2VuZF9iaXRzKHMsIHRyZWVbYyoyXS8qLkNvZGUqLywgdHJlZVtjKjIgKyAxXS8qLkxlbiovKTtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFJldmVyc2UgdGhlIGZpcnN0IGxlbiBiaXRzIG9mIGEgY29kZSwgdXNpbmcgc3RyYWlnaHRmb3J3YXJkIGNvZGUgKGEgZmFzdGVyXG4gKiBtZXRob2Qgd291bGQgdXNlIGEgdGFibGUpXG4gKiBJTiBhc3NlcnRpb246IDEgPD0gbGVuIDw9IDE1XG4gKi9cbmZ1bmN0aW9uIGJpX3JldmVyc2UoY29kZSwgbGVuKSB7XG4gIHZhciByZXMgPSAwO1xuICBkbyB7XG4gICAgcmVzIHw9IGNvZGUgJiAxO1xuICAgIGNvZGUgPj4+PSAxO1xuICAgIHJlcyA8PD0gMTtcbiAgfSB3aGlsZSAoLS1sZW4gPiAwKTtcbiAgcmV0dXJuIHJlcyA+Pj4gMTtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEZsdXNoIHRoZSBiaXQgYnVmZmVyLCBrZWVwaW5nIGF0IG1vc3QgNyBiaXRzIGluIGl0LlxuICovXG5mdW5jdGlvbiBiaV9mbHVzaChzKSB7XG4gIGlmIChzLmJpX3ZhbGlkID09PSAxNikge1xuICAgIHB1dF9zaG9ydChzLCBzLmJpX2J1Zik7XG4gICAgcy5iaV9idWYgPSAwO1xuICAgIHMuYmlfdmFsaWQgPSAwO1xuXG4gIH0gZWxzZSBpZiAocy5iaV92YWxpZCA+PSA4KSB7XG4gICAgcy5wZW5kaW5nX2J1ZltzLnBlbmRpbmcrK10gPSBzLmJpX2J1ZiAmIDB4ZmY7XG4gICAgcy5iaV9idWYgPj49IDg7XG4gICAgcy5iaV92YWxpZCAtPSA4O1xuICB9XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb21wdXRlIHRoZSBvcHRpbWFsIGJpdCBsZW5ndGhzIGZvciBhIHRyZWUgYW5kIHVwZGF0ZSB0aGUgdG90YWwgYml0IGxlbmd0aFxuICogZm9yIHRoZSBjdXJyZW50IGJsb2NrLlxuICogSU4gYXNzZXJ0aW9uOiB0aGUgZmllbGRzIGZyZXEgYW5kIGRhZCBhcmUgc2V0LCBoZWFwW2hlYXBfbWF4XSBhbmRcbiAqICAgIGFib3ZlIGFyZSB0aGUgdHJlZSBub2RlcyBzb3J0ZWQgYnkgaW5jcmVhc2luZyBmcmVxdWVuY3kuXG4gKiBPVVQgYXNzZXJ0aW9uczogdGhlIGZpZWxkIGxlbiBpcyBzZXQgdG8gdGhlIG9wdGltYWwgYml0IGxlbmd0aCwgdGhlXG4gKiAgICAgYXJyYXkgYmxfY291bnQgY29udGFpbnMgdGhlIGZyZXF1ZW5jaWVzIGZvciBlYWNoIGJpdCBsZW5ndGguXG4gKiAgICAgVGhlIGxlbmd0aCBvcHRfbGVuIGlzIHVwZGF0ZWQ7IHN0YXRpY19sZW4gaXMgYWxzbyB1cGRhdGVkIGlmIHN0cmVlIGlzXG4gKiAgICAgbm90IG51bGwuXG4gKi9cbmZ1bmN0aW9uIGdlbl9iaXRsZW4ocywgZGVzYylcbi8vICAgIGRlZmxhdGVfc3RhdGUgKnM7XG4vLyAgICB0cmVlX2Rlc2MgKmRlc2M7ICAgIC8qIHRoZSB0cmVlIGRlc2NyaXB0b3IgKi9cbntcbiAgdmFyIHRyZWUgICAgICAgICAgICA9IGRlc2MuZHluX3RyZWU7XG4gIHZhciBtYXhfY29kZSAgICAgICAgPSBkZXNjLm1heF9jb2RlO1xuICB2YXIgc3RyZWUgICAgICAgICAgID0gZGVzYy5zdGF0X2Rlc2Muc3RhdGljX3RyZWU7XG4gIHZhciBoYXNfc3RyZWUgICAgICAgPSBkZXNjLnN0YXRfZGVzYy5oYXNfc3RyZWU7XG4gIHZhciBleHRyYSAgICAgICAgICAgPSBkZXNjLnN0YXRfZGVzYy5leHRyYV9iaXRzO1xuICB2YXIgYmFzZSAgICAgICAgICAgID0gZGVzYy5zdGF0X2Rlc2MuZXh0cmFfYmFzZTtcbiAgdmFyIG1heF9sZW5ndGggICAgICA9IGRlc2Muc3RhdF9kZXNjLm1heF9sZW5ndGg7XG4gIHZhciBoOyAgICAgICAgICAgICAgLyogaGVhcCBpbmRleCAqL1xuICB2YXIgbiwgbTsgICAgICAgICAgIC8qIGl0ZXJhdGUgb3ZlciB0aGUgdHJlZSBlbGVtZW50cyAqL1xuICB2YXIgYml0czsgICAgICAgICAgIC8qIGJpdCBsZW5ndGggKi9cbiAgdmFyIHhiaXRzOyAgICAgICAgICAvKiBleHRyYSBiaXRzICovXG4gIHZhciBmOyAgICAgICAgICAgICAgLyogZnJlcXVlbmN5ICovXG4gIHZhciBvdmVyZmxvdyA9IDA7ICAgLyogbnVtYmVyIG9mIGVsZW1lbnRzIHdpdGggYml0IGxlbmd0aCB0b28gbGFyZ2UgKi9cblxuICBmb3IgKGJpdHMgPSAwOyBiaXRzIDw9IE1BWF9CSVRTOyBiaXRzKyspIHtcbiAgICBzLmJsX2NvdW50W2JpdHNdID0gMDtcbiAgfVxuXG4gIC8qIEluIGEgZmlyc3QgcGFzcywgY29tcHV0ZSB0aGUgb3B0aW1hbCBiaXQgbGVuZ3RocyAod2hpY2ggbWF5XG4gICAqIG92ZXJmbG93IGluIHRoZSBjYXNlIG9mIHRoZSBiaXQgbGVuZ3RoIHRyZWUpLlxuICAgKi9cbiAgdHJlZVtzLmhlYXBbcy5oZWFwX21heF0qMiArIDFdLyouTGVuKi8gPSAwOyAvKiByb290IG9mIHRoZSBoZWFwICovXG5cbiAgZm9yIChoID0gcy5oZWFwX21heCsxOyBoIDwgSEVBUF9TSVpFOyBoKyspIHtcbiAgICBuID0gcy5oZWFwW2hdO1xuICAgIGJpdHMgPSB0cmVlW3RyZWVbbioyICsxXS8qLkRhZCovICogMiArIDFdLyouTGVuKi8gKyAxO1xuICAgIGlmIChiaXRzID4gbWF4X2xlbmd0aCkge1xuICAgICAgYml0cyA9IG1heF9sZW5ndGg7XG4gICAgICBvdmVyZmxvdysrO1xuICAgIH1cbiAgICB0cmVlW24qMiArIDFdLyouTGVuKi8gPSBiaXRzO1xuICAgIC8qIFdlIG92ZXJ3cml0ZSB0cmVlW25dLkRhZCB3aGljaCBpcyBubyBsb25nZXIgbmVlZGVkICovXG5cbiAgICBpZiAobiA+IG1heF9jb2RlKSB7IGNvbnRpbnVlOyB9IC8qIG5vdCBhIGxlYWYgbm9kZSAqL1xuXG4gICAgcy5ibF9jb3VudFtiaXRzXSsrO1xuICAgIHhiaXRzID0gMDtcbiAgICBpZiAobiA+PSBiYXNlKSB7XG4gICAgICB4Yml0cyA9IGV4dHJhW24tYmFzZV07XG4gICAgfVxuICAgIGYgPSB0cmVlW24gKiAyXS8qLkZyZXEqLztcbiAgICBzLm9wdF9sZW4gKz0gZiAqIChiaXRzICsgeGJpdHMpO1xuICAgIGlmIChoYXNfc3RyZWUpIHtcbiAgICAgIHMuc3RhdGljX2xlbiArPSBmICogKHN0cmVlW24qMiArIDFdLyouTGVuKi8gKyB4Yml0cyk7XG4gICAgfVxuICB9XG4gIGlmIChvdmVyZmxvdyA9PT0gMCkgeyByZXR1cm47IH1cblxuICAvLyBUcmFjZSgoc3RkZXJyLFwiXFxuYml0IGxlbmd0aCBvdmVyZmxvd1xcblwiKSk7XG4gIC8qIFRoaXMgaGFwcGVucyBmb3IgZXhhbXBsZSBvbiBvYmoyIGFuZCBwaWMgb2YgdGhlIENhbGdhcnkgY29ycHVzICovXG5cbiAgLyogRmluZCB0aGUgZmlyc3QgYml0IGxlbmd0aCB3aGljaCBjb3VsZCBpbmNyZWFzZTogKi9cbiAgZG8ge1xuICAgIGJpdHMgPSBtYXhfbGVuZ3RoLTE7XG4gICAgd2hpbGUgKHMuYmxfY291bnRbYml0c10gPT09IDApIHsgYml0cy0tOyB9XG4gICAgcy5ibF9jb3VudFtiaXRzXS0tOyAgICAgIC8qIG1vdmUgb25lIGxlYWYgZG93biB0aGUgdHJlZSAqL1xuICAgIHMuYmxfY291bnRbYml0cysxXSArPSAyOyAvKiBtb3ZlIG9uZSBvdmVyZmxvdyBpdGVtIGFzIGl0cyBicm90aGVyICovXG4gICAgcy5ibF9jb3VudFttYXhfbGVuZ3RoXS0tO1xuICAgIC8qIFRoZSBicm90aGVyIG9mIHRoZSBvdmVyZmxvdyBpdGVtIGFsc28gbW92ZXMgb25lIHN0ZXAgdXAsXG4gICAgICogYnV0IHRoaXMgZG9lcyBub3QgYWZmZWN0IGJsX2NvdW50W21heF9sZW5ndGhdXG4gICAgICovXG4gICAgb3ZlcmZsb3cgLT0gMjtcbiAgfSB3aGlsZSAob3ZlcmZsb3cgPiAwKTtcblxuICAvKiBOb3cgcmVjb21wdXRlIGFsbCBiaXQgbGVuZ3Rocywgc2Nhbm5pbmcgaW4gaW5jcmVhc2luZyBmcmVxdWVuY3kuXG4gICAqIGggaXMgc3RpbGwgZXF1YWwgdG8gSEVBUF9TSVpFLiAoSXQgaXMgc2ltcGxlciB0byByZWNvbnN0cnVjdCBhbGxcbiAgICogbGVuZ3RocyBpbnN0ZWFkIG9mIGZpeGluZyBvbmx5IHRoZSB3cm9uZyBvbmVzLiBUaGlzIGlkZWEgaXMgdGFrZW5cbiAgICogZnJvbSAnYXInIHdyaXR0ZW4gYnkgSGFydWhpa28gT2t1bXVyYS4pXG4gICAqL1xuICBmb3IgKGJpdHMgPSBtYXhfbGVuZ3RoOyBiaXRzICE9PSAwOyBiaXRzLS0pIHtcbiAgICBuID0gcy5ibF9jb3VudFtiaXRzXTtcbiAgICB3aGlsZSAobiAhPT0gMCkge1xuICAgICAgbSA9IHMuaGVhcFstLWhdO1xuICAgICAgaWYgKG0gPiBtYXhfY29kZSkgeyBjb250aW51ZTsgfVxuICAgICAgaWYgKHRyZWVbbSoyICsgMV0vKi5MZW4qLyAhPT0gYml0cykge1xuICAgICAgICAvLyBUcmFjZSgoc3RkZXJyLFwiY29kZSAlZCBiaXRzICVkLT4lZFxcblwiLCBtLCB0cmVlW21dLkxlbiwgYml0cykpO1xuICAgICAgICBzLm9wdF9sZW4gKz0gKGJpdHMgLSB0cmVlW20qMiArIDFdLyouTGVuKi8pKnRyZWVbbSoyXS8qLkZyZXEqLztcbiAgICAgICAgdHJlZVttKjIgKyAxXS8qLkxlbiovID0gYml0cztcbiAgICAgIH1cbiAgICAgIG4tLTtcbiAgICB9XG4gIH1cbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEdlbmVyYXRlIHRoZSBjb2RlcyBmb3IgYSBnaXZlbiB0cmVlIGFuZCBiaXQgY291bnRzICh3aGljaCBuZWVkIG5vdCBiZVxuICogb3B0aW1hbCkuXG4gKiBJTiBhc3NlcnRpb246IHRoZSBhcnJheSBibF9jb3VudCBjb250YWlucyB0aGUgYml0IGxlbmd0aCBzdGF0aXN0aWNzIGZvclxuICogdGhlIGdpdmVuIHRyZWUgYW5kIHRoZSBmaWVsZCBsZW4gaXMgc2V0IGZvciBhbGwgdHJlZSBlbGVtZW50cy5cbiAqIE9VVCBhc3NlcnRpb246IHRoZSBmaWVsZCBjb2RlIGlzIHNldCBmb3IgYWxsIHRyZWUgZWxlbWVudHMgb2Ygbm9uXG4gKiAgICAgemVybyBjb2RlIGxlbmd0aC5cbiAqL1xuZnVuY3Rpb24gZ2VuX2NvZGVzKHRyZWUsIG1heF9jb2RlLCBibF9jb3VudClcbi8vICAgIGN0X2RhdGEgKnRyZWU7ICAgICAgICAgICAgIC8qIHRoZSB0cmVlIHRvIGRlY29yYXRlICovXG4vLyAgICBpbnQgbWF4X2NvZGU7ICAgICAgICAgICAgICAvKiBsYXJnZXN0IGNvZGUgd2l0aCBub24gemVybyBmcmVxdWVuY3kgKi9cbi8vICAgIHVzaGYgKmJsX2NvdW50OyAgICAgICAgICAgIC8qIG51bWJlciBvZiBjb2RlcyBhdCBlYWNoIGJpdCBsZW5ndGggKi9cbntcbiAgdmFyIG5leHRfY29kZSA9IG5ldyBBcnJheShNQVhfQklUUysxKTsgLyogbmV4dCBjb2RlIHZhbHVlIGZvciBlYWNoIGJpdCBsZW5ndGggKi9cbiAgdmFyIGNvZGUgPSAwOyAgICAgICAgICAgICAgLyogcnVubmluZyBjb2RlIHZhbHVlICovXG4gIHZhciBiaXRzOyAgICAgICAgICAgICAgICAgIC8qIGJpdCBpbmRleCAqL1xuICB2YXIgbjsgICAgICAgICAgICAgICAgICAgICAvKiBjb2RlIGluZGV4ICovXG5cbiAgLyogVGhlIGRpc3RyaWJ1dGlvbiBjb3VudHMgYXJlIGZpcnN0IHVzZWQgdG8gZ2VuZXJhdGUgdGhlIGNvZGUgdmFsdWVzXG4gICAqIHdpdGhvdXQgYml0IHJldmVyc2FsLlxuICAgKi9cbiAgZm9yIChiaXRzID0gMTsgYml0cyA8PSBNQVhfQklUUzsgYml0cysrKSB7XG4gICAgbmV4dF9jb2RlW2JpdHNdID0gY29kZSA9IChjb2RlICsgYmxfY291bnRbYml0cy0xXSkgPDwgMTtcbiAgfVxuICAvKiBDaGVjayB0aGF0IHRoZSBiaXQgY291bnRzIGluIGJsX2NvdW50IGFyZSBjb25zaXN0ZW50LiBUaGUgbGFzdCBjb2RlXG4gICAqIG11c3QgYmUgYWxsIG9uZXMuXG4gICAqL1xuICAvL0Fzc2VydCAoY29kZSArIGJsX2NvdW50W01BWF9CSVRTXS0xID09ICgxPDxNQVhfQklUUyktMSxcbiAgLy8gICAgICAgIFwiaW5jb25zaXN0ZW50IGJpdCBjb3VudHNcIik7XG4gIC8vVHJhY2V2KChzdGRlcnIsXCJcXG5nZW5fY29kZXM6IG1heF9jb2RlICVkIFwiLCBtYXhfY29kZSkpO1xuXG4gIGZvciAobiA9IDA7ICBuIDw9IG1heF9jb2RlOyBuKyspIHtcbiAgICB2YXIgbGVuID0gdHJlZVtuKjIgKyAxXS8qLkxlbiovO1xuICAgIGlmIChsZW4gPT09IDApIHsgY29udGludWU7IH1cbiAgICAvKiBOb3cgcmV2ZXJzZSB0aGUgYml0cyAqL1xuICAgIHRyZWVbbioyXS8qLkNvZGUqLyA9IGJpX3JldmVyc2UobmV4dF9jb2RlW2xlbl0rKywgbGVuKTtcblxuICAgIC8vVHJhY2Vjdih0cmVlICE9IHN0YXRpY19sdHJlZSwgKHN0ZGVycixcIlxcbm4gJTNkICVjIGwgJTJkIGMgJTR4ICgleCkgXCIsXG4gICAgLy8gICAgIG4sIChpc2dyYXBoKG4pID8gbiA6ICcgJyksIGxlbiwgdHJlZVtuXS5Db2RlLCBuZXh0X2NvZGVbbGVuXS0xKSk7XG4gIH1cbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEluaXRpYWxpemUgdGhlIHZhcmlvdXMgJ2NvbnN0YW50JyB0YWJsZXMuXG4gKi9cbmZ1bmN0aW9uIHRyX3N0YXRpY19pbml0KCkge1xuICB2YXIgbjsgICAgICAgIC8qIGl0ZXJhdGVzIG92ZXIgdHJlZSBlbGVtZW50cyAqL1xuICB2YXIgYml0czsgICAgIC8qIGJpdCBjb3VudGVyICovXG4gIHZhciBsZW5ndGg7ICAgLyogbGVuZ3RoIHZhbHVlICovXG4gIHZhciBjb2RlOyAgICAgLyogY29kZSB2YWx1ZSAqL1xuICB2YXIgZGlzdDsgICAgIC8qIGRpc3RhbmNlIGluZGV4ICovXG4gIHZhciBibF9jb3VudCA9IG5ldyBBcnJheShNQVhfQklUUysxKTtcbiAgLyogbnVtYmVyIG9mIGNvZGVzIGF0IGVhY2ggYml0IGxlbmd0aCBmb3IgYW4gb3B0aW1hbCB0cmVlICovXG5cbiAgLy8gZG8gY2hlY2sgaW4gX3RyX2luaXQoKVxuICAvL2lmIChzdGF0aWNfaW5pdF9kb25lKSByZXR1cm47XG5cbiAgLyogRm9yIHNvbWUgZW1iZWRkZWQgdGFyZ2V0cywgZ2xvYmFsIHZhcmlhYmxlcyBhcmUgbm90IGluaXRpYWxpemVkOiAqL1xuLyojaWZkZWYgTk9fSU5JVF9HTE9CQUxfUE9JTlRFUlNcbiAgc3RhdGljX2xfZGVzYy5zdGF0aWNfdHJlZSA9IHN0YXRpY19sdHJlZTtcbiAgc3RhdGljX2xfZGVzYy5leHRyYV9iaXRzID0gZXh0cmFfbGJpdHM7XG4gIHN0YXRpY19kX2Rlc2Muc3RhdGljX3RyZWUgPSBzdGF0aWNfZHRyZWU7XG4gIHN0YXRpY19kX2Rlc2MuZXh0cmFfYml0cyA9IGV4dHJhX2RiaXRzO1xuICBzdGF0aWNfYmxfZGVzYy5leHRyYV9iaXRzID0gZXh0cmFfYmxiaXRzO1xuI2VuZGlmKi9cblxuICAvKiBJbml0aWFsaXplIHRoZSBtYXBwaW5nIGxlbmd0aCAoMC4uMjU1KSAtPiBsZW5ndGggY29kZSAoMC4uMjgpICovXG4gIGxlbmd0aCA9IDA7XG4gIGZvciAoY29kZSA9IDA7IGNvZGUgPCBMRU5HVEhfQ09ERVMtMTsgY29kZSsrKSB7XG4gICAgYmFzZV9sZW5ndGhbY29kZV0gPSBsZW5ndGg7XG4gICAgZm9yIChuID0gMDsgbiA8ICgxPDxleHRyYV9sYml0c1tjb2RlXSk7IG4rKykge1xuICAgICAgX2xlbmd0aF9jb2RlW2xlbmd0aCsrXSA9IGNvZGU7XG4gICAgfVxuICB9XG4gIC8vQXNzZXJ0IChsZW5ndGggPT0gMjU2LCBcInRyX3N0YXRpY19pbml0OiBsZW5ndGggIT0gMjU2XCIpO1xuICAvKiBOb3RlIHRoYXQgdGhlIGxlbmd0aCAyNTUgKG1hdGNoIGxlbmd0aCAyNTgpIGNhbiBiZSByZXByZXNlbnRlZFxuICAgKiBpbiB0d28gZGlmZmVyZW50IHdheXM6IGNvZGUgMjg0ICsgNSBiaXRzIG9yIGNvZGUgMjg1LCBzbyB3ZVxuICAgKiBvdmVyd3JpdGUgbGVuZ3RoX2NvZGVbMjU1XSB0byB1c2UgdGhlIGJlc3QgZW5jb2Rpbmc6XG4gICAqL1xuICBfbGVuZ3RoX2NvZGVbbGVuZ3RoLTFdID0gY29kZTtcblxuICAvKiBJbml0aWFsaXplIHRoZSBtYXBwaW5nIGRpc3QgKDAuLjMySykgLT4gZGlzdCBjb2RlICgwLi4yOSkgKi9cbiAgZGlzdCA9IDA7XG4gIGZvciAoY29kZSA9IDAgOyBjb2RlIDwgMTY7IGNvZGUrKykge1xuICAgIGJhc2VfZGlzdFtjb2RlXSA9IGRpc3Q7XG4gICAgZm9yIChuID0gMDsgbiA8ICgxPDxleHRyYV9kYml0c1tjb2RlXSk7IG4rKykge1xuICAgICAgX2Rpc3RfY29kZVtkaXN0KytdID0gY29kZTtcbiAgICB9XG4gIH1cbiAgLy9Bc3NlcnQgKGRpc3QgPT0gMjU2LCBcInRyX3N0YXRpY19pbml0OiBkaXN0ICE9IDI1NlwiKTtcbiAgZGlzdCA+Pj0gNzsgLyogZnJvbSBub3cgb24sIGFsbCBkaXN0YW5jZXMgYXJlIGRpdmlkZWQgYnkgMTI4ICovXG4gIGZvciAoIDsgY29kZSA8IERfQ09ERVM7IGNvZGUrKykge1xuICAgIGJhc2VfZGlzdFtjb2RlXSA9IGRpc3QgPDwgNztcbiAgICBmb3IgKG4gPSAwOyBuIDwgKDE8PChleHRyYV9kYml0c1tjb2RlXS03KSk7IG4rKykge1xuICAgICAgX2Rpc3RfY29kZVsyNTYgKyBkaXN0KytdID0gY29kZTtcbiAgICB9XG4gIH1cbiAgLy9Bc3NlcnQgKGRpc3QgPT0gMjU2LCBcInRyX3N0YXRpY19pbml0OiAyNTYrZGlzdCAhPSA1MTJcIik7XG5cbiAgLyogQ29uc3RydWN0IHRoZSBjb2RlcyBvZiB0aGUgc3RhdGljIGxpdGVyYWwgdHJlZSAqL1xuICBmb3IgKGJpdHMgPSAwOyBiaXRzIDw9IE1BWF9CSVRTOyBiaXRzKyspIHtcbiAgICBibF9jb3VudFtiaXRzXSA9IDA7XG4gIH1cblxuICBuID0gMDtcbiAgd2hpbGUgKG4gPD0gMTQzKSB7XG4gICAgc3RhdGljX2x0cmVlW24qMiArIDFdLyouTGVuKi8gPSA4O1xuICAgIG4rKztcbiAgICBibF9jb3VudFs4XSsrO1xuICB9XG4gIHdoaWxlIChuIDw9IDI1NSkge1xuICAgIHN0YXRpY19sdHJlZVtuKjIgKyAxXS8qLkxlbiovID0gOTtcbiAgICBuKys7XG4gICAgYmxfY291bnRbOV0rKztcbiAgfVxuICB3aGlsZSAobiA8PSAyNzkpIHtcbiAgICBzdGF0aWNfbHRyZWVbbioyICsgMV0vKi5MZW4qLyA9IDc7XG4gICAgbisrO1xuICAgIGJsX2NvdW50WzddKys7XG4gIH1cbiAgd2hpbGUgKG4gPD0gMjg3KSB7XG4gICAgc3RhdGljX2x0cmVlW24qMiArIDFdLyouTGVuKi8gPSA4O1xuICAgIG4rKztcbiAgICBibF9jb3VudFs4XSsrO1xuICB9XG4gIC8qIENvZGVzIDI4NiBhbmQgMjg3IGRvIG5vdCBleGlzdCwgYnV0IHdlIG11c3QgaW5jbHVkZSB0aGVtIGluIHRoZVxuICAgKiB0cmVlIGNvbnN0cnVjdGlvbiB0byBnZXQgYSBjYW5vbmljYWwgSHVmZm1hbiB0cmVlIChsb25nZXN0IGNvZGVcbiAgICogYWxsIG9uZXMpXG4gICAqL1xuICBnZW5fY29kZXMoc3RhdGljX2x0cmVlLCBMX0NPREVTKzEsIGJsX2NvdW50KTtcblxuICAvKiBUaGUgc3RhdGljIGRpc3RhbmNlIHRyZWUgaXMgdHJpdmlhbDogKi9cbiAgZm9yIChuID0gMDsgbiA8IERfQ09ERVM7IG4rKykge1xuICAgIHN0YXRpY19kdHJlZVtuKjIgKyAxXS8qLkxlbiovID0gNTtcbiAgICBzdGF0aWNfZHRyZWVbbioyXS8qLkNvZGUqLyA9IGJpX3JldmVyc2UobiwgNSk7XG4gIH1cblxuICAvLyBOb3cgZGF0YSByZWFkeSBhbmQgd2UgY2FuIGluaXQgc3RhdGljIHRyZWVzXG4gIHN0YXRpY19sX2Rlc2MgPSBuZXcgU3RhdGljVHJlZURlc2Moc3RhdGljX2x0cmVlLCBleHRyYV9sYml0cywgTElURVJBTFMrMSwgTF9DT0RFUywgTUFYX0JJVFMpO1xuICBzdGF0aWNfZF9kZXNjID0gbmV3IFN0YXRpY1RyZWVEZXNjKHN0YXRpY19kdHJlZSwgZXh0cmFfZGJpdHMsIDAsICAgICAgICAgIERfQ09ERVMsIE1BWF9CSVRTKTtcbiAgc3RhdGljX2JsX2Rlc2MgPW5ldyBTdGF0aWNUcmVlRGVzYyhuZXcgQXJyYXkoMCksIGV4dHJhX2JsYml0cywgMCwgICAgICAgICBCTF9DT0RFUywgTUFYX0JMX0JJVFMpO1xuXG4gIC8vc3RhdGljX2luaXRfZG9uZSA9IHRydWU7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBJbml0aWFsaXplIGEgbmV3IGJsb2NrLlxuICovXG5mdW5jdGlvbiBpbml0X2Jsb2NrKHMpIHtcbiAgdmFyIG47IC8qIGl0ZXJhdGVzIG92ZXIgdHJlZSBlbGVtZW50cyAqL1xuXG4gIC8qIEluaXRpYWxpemUgdGhlIHRyZWVzLiAqL1xuICBmb3IgKG4gPSAwOyBuIDwgTF9DT0RFUzsgIG4rKykgeyBzLmR5bl9sdHJlZVtuKjJdLyouRnJlcSovID0gMDsgfVxuICBmb3IgKG4gPSAwOyBuIDwgRF9DT0RFUzsgIG4rKykgeyBzLmR5bl9kdHJlZVtuKjJdLyouRnJlcSovID0gMDsgfVxuICBmb3IgKG4gPSAwOyBuIDwgQkxfQ09ERVM7IG4rKykgeyBzLmJsX3RyZWVbbioyXS8qLkZyZXEqLyA9IDA7IH1cblxuICBzLmR5bl9sdHJlZVtFTkRfQkxPQ0sqMl0vKi5GcmVxKi8gPSAxO1xuICBzLm9wdF9sZW4gPSBzLnN0YXRpY19sZW4gPSAwO1xuICBzLmxhc3RfbGl0ID0gcy5tYXRjaGVzID0gMDtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEZsdXNoIHRoZSBiaXQgYnVmZmVyIGFuZCBhbGlnbiB0aGUgb3V0cHV0IG9uIGEgYnl0ZSBib3VuZGFyeVxuICovXG5mdW5jdGlvbiBiaV93aW5kdXAocylcbntcbiAgaWYgKHMuYmlfdmFsaWQgPiA4KSB7XG4gICAgcHV0X3Nob3J0KHMsIHMuYmlfYnVmKTtcbiAgfSBlbHNlIGlmIChzLmJpX3ZhbGlkID4gMCkge1xuICAgIC8vcHV0X2J5dGUocywgKEJ5dGUpcy0+YmlfYnVmKTtcbiAgICBzLnBlbmRpbmdfYnVmW3MucGVuZGluZysrXSA9IHMuYmlfYnVmO1xuICB9XG4gIHMuYmlfYnVmID0gMDtcbiAgcy5iaV92YWxpZCA9IDA7XG59XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29weSBhIHN0b3JlZCBibG9jaywgc3RvcmluZyBmaXJzdCB0aGUgbGVuZ3RoIGFuZCBpdHNcbiAqIG9uZSdzIGNvbXBsZW1lbnQgaWYgcmVxdWVzdGVkLlxuICovXG5mdW5jdGlvbiBjb3B5X2Jsb2NrKHMsIGJ1ZiwgbGVuLCBoZWFkZXIpXG4vL0RlZmxhdGVTdGF0ZSAqcztcbi8vY2hhcmYgICAgKmJ1ZjsgICAgLyogdGhlIGlucHV0IGRhdGEgKi9cbi8vdW5zaWduZWQgbGVuOyAgICAgLyogaXRzIGxlbmd0aCAqL1xuLy9pbnQgICAgICBoZWFkZXI7ICAvKiB0cnVlIGlmIGJsb2NrIGhlYWRlciBtdXN0IGJlIHdyaXR0ZW4gKi9cbntcbiAgYmlfd2luZHVwKHMpOyAgICAgICAgLyogYWxpZ24gb24gYnl0ZSBib3VuZGFyeSAqL1xuXG4gIGlmIChoZWFkZXIpIHtcbiAgICBwdXRfc2hvcnQocywgbGVuKTtcbiAgICBwdXRfc2hvcnQocywgfmxlbik7XG4gIH1cbi8vICB3aGlsZSAobGVuLS0pIHtcbi8vICAgIHB1dF9ieXRlKHMsICpidWYrKyk7XG4vLyAgfVxuICB1dGlscy5hcnJheVNldChzLnBlbmRpbmdfYnVmLCBzLndpbmRvdywgYnVmLCBsZW4sIHMucGVuZGluZyk7XG4gIHMucGVuZGluZyArPSBsZW47XG59XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29tcGFyZXMgdG8gc3VidHJlZXMsIHVzaW5nIHRoZSB0cmVlIGRlcHRoIGFzIHRpZSBicmVha2VyIHdoZW5cbiAqIHRoZSBzdWJ0cmVlcyBoYXZlIGVxdWFsIGZyZXF1ZW5jeS4gVGhpcyBtaW5pbWl6ZXMgdGhlIHdvcnN0IGNhc2UgbGVuZ3RoLlxuICovXG5mdW5jdGlvbiBzbWFsbGVyKHRyZWUsIG4sIG0sIGRlcHRoKSB7XG4gIHZhciBfbjIgPSBuKjI7XG4gIHZhciBfbTIgPSBtKjI7XG4gIHJldHVybiAodHJlZVtfbjJdLyouRnJlcSovIDwgdHJlZVtfbTJdLyouRnJlcSovIHx8XG4gICAgICAgICAodHJlZVtfbjJdLyouRnJlcSovID09PSB0cmVlW19tMl0vKi5GcmVxKi8gJiYgZGVwdGhbbl0gPD0gZGVwdGhbbV0pKTtcbn1cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBSZXN0b3JlIHRoZSBoZWFwIHByb3BlcnR5IGJ5IG1vdmluZyBkb3duIHRoZSB0cmVlIHN0YXJ0aW5nIGF0IG5vZGUgayxcbiAqIGV4Y2hhbmdpbmcgYSBub2RlIHdpdGggdGhlIHNtYWxsZXN0IG9mIGl0cyB0d28gc29ucyBpZiBuZWNlc3NhcnksIHN0b3BwaW5nXG4gKiB3aGVuIHRoZSBoZWFwIHByb3BlcnR5IGlzIHJlLWVzdGFibGlzaGVkIChlYWNoIGZhdGhlciBzbWFsbGVyIHRoYW4gaXRzXG4gKiB0d28gc29ucykuXG4gKi9cbmZ1bmN0aW9uIHBxZG93bmhlYXAocywgdHJlZSwgaylcbi8vICAgIGRlZmxhdGVfc3RhdGUgKnM7XG4vLyAgICBjdF9kYXRhICp0cmVlOyAgLyogdGhlIHRyZWUgdG8gcmVzdG9yZSAqL1xuLy8gICAgaW50IGs7ICAgICAgICAgICAgICAgLyogbm9kZSB0byBtb3ZlIGRvd24gKi9cbntcbiAgdmFyIHYgPSBzLmhlYXBba107XG4gIHZhciBqID0gayA8PCAxOyAgLyogbGVmdCBzb24gb2YgayAqL1xuICB3aGlsZSAoaiA8PSBzLmhlYXBfbGVuKSB7XG4gICAgLyogU2V0IGogdG8gdGhlIHNtYWxsZXN0IG9mIHRoZSB0d28gc29uczogKi9cbiAgICBpZiAoaiA8IHMuaGVhcF9sZW4gJiZcbiAgICAgIHNtYWxsZXIodHJlZSwgcy5oZWFwW2orMV0sIHMuaGVhcFtqXSwgcy5kZXB0aCkpIHtcbiAgICAgIGorKztcbiAgICB9XG4gICAgLyogRXhpdCBpZiB2IGlzIHNtYWxsZXIgdGhhbiBib3RoIHNvbnMgKi9cbiAgICBpZiAoc21hbGxlcih0cmVlLCB2LCBzLmhlYXBbal0sIHMuZGVwdGgpKSB7IGJyZWFrOyB9XG5cbiAgICAvKiBFeGNoYW5nZSB2IHdpdGggdGhlIHNtYWxsZXN0IHNvbiAqL1xuICAgIHMuaGVhcFtrXSA9IHMuaGVhcFtqXTtcbiAgICBrID0gajtcblxuICAgIC8qIEFuZCBjb250aW51ZSBkb3duIHRoZSB0cmVlLCBzZXR0aW5nIGogdG8gdGhlIGxlZnQgc29uIG9mIGsgKi9cbiAgICBqIDw8PSAxO1xuICB9XG4gIHMuaGVhcFtrXSA9IHY7XG59XG5cblxuLy8gaW5saW5lZCBtYW51YWxseVxuLy8gdmFyIFNNQUxMRVNUID0gMTtcblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBTZW5kIHRoZSBibG9jayBkYXRhIGNvbXByZXNzZWQgdXNpbmcgdGhlIGdpdmVuIEh1ZmZtYW4gdHJlZXNcbiAqL1xuZnVuY3Rpb24gY29tcHJlc3NfYmxvY2socywgbHRyZWUsIGR0cmVlKVxuLy8gICAgZGVmbGF0ZV9zdGF0ZSAqcztcbi8vICAgIGNvbnN0IGN0X2RhdGEgKmx0cmVlOyAvKiBsaXRlcmFsIHRyZWUgKi9cbi8vICAgIGNvbnN0IGN0X2RhdGEgKmR0cmVlOyAvKiBkaXN0YW5jZSB0cmVlICovXG57XG4gIHZhciBkaXN0OyAgICAgICAgICAgLyogZGlzdGFuY2Ugb2YgbWF0Y2hlZCBzdHJpbmcgKi9cbiAgdmFyIGxjOyAgICAgICAgICAgICAvKiBtYXRjaCBsZW5ndGggb3IgdW5tYXRjaGVkIGNoYXIgKGlmIGRpc3QgPT0gMCkgKi9cbiAgdmFyIGx4ID0gMDsgICAgICAgICAvKiBydW5uaW5nIGluZGV4IGluIGxfYnVmICovXG4gIHZhciBjb2RlOyAgICAgICAgICAgLyogdGhlIGNvZGUgdG8gc2VuZCAqL1xuICB2YXIgZXh0cmE7ICAgICAgICAgIC8qIG51bWJlciBvZiBleHRyYSBiaXRzIHRvIHNlbmQgKi9cblxuICBpZiAocy5sYXN0X2xpdCAhPT0gMCkge1xuICAgIGRvIHtcbiAgICAgIGRpc3QgPSAocy5wZW5kaW5nX2J1ZltzLmRfYnVmICsgbHgqMl0gPDwgOCkgfCAocy5wZW5kaW5nX2J1ZltzLmRfYnVmICsgbHgqMiArIDFdKTtcbiAgICAgIGxjID0gcy5wZW5kaW5nX2J1ZltzLmxfYnVmICsgbHhdO1xuICAgICAgbHgrKztcblxuICAgICAgaWYgKGRpc3QgPT09IDApIHtcbiAgICAgICAgc2VuZF9jb2RlKHMsIGxjLCBsdHJlZSk7IC8qIHNlbmQgYSBsaXRlcmFsIGJ5dGUgKi9cbiAgICAgICAgLy9UcmFjZWN2KGlzZ3JhcGgobGMpLCAoc3RkZXJyLFwiICclYycgXCIsIGxjKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvKiBIZXJlLCBsYyBpcyB0aGUgbWF0Y2ggbGVuZ3RoIC0gTUlOX01BVENIICovXG4gICAgICAgIGNvZGUgPSBfbGVuZ3RoX2NvZGVbbGNdO1xuICAgICAgICBzZW5kX2NvZGUocywgY29kZStMSVRFUkFMUysxLCBsdHJlZSk7IC8qIHNlbmQgdGhlIGxlbmd0aCBjb2RlICovXG4gICAgICAgIGV4dHJhID0gZXh0cmFfbGJpdHNbY29kZV07XG4gICAgICAgIGlmIChleHRyYSAhPT0gMCkge1xuICAgICAgICAgIGxjIC09IGJhc2VfbGVuZ3RoW2NvZGVdO1xuICAgICAgICAgIHNlbmRfYml0cyhzLCBsYywgZXh0cmEpOyAgICAgICAvKiBzZW5kIHRoZSBleHRyYSBsZW5ndGggYml0cyAqL1xuICAgICAgICB9XG4gICAgICAgIGRpc3QtLTsgLyogZGlzdCBpcyBub3cgdGhlIG1hdGNoIGRpc3RhbmNlIC0gMSAqL1xuICAgICAgICBjb2RlID0gZF9jb2RlKGRpc3QpO1xuICAgICAgICAvL0Fzc2VydCAoY29kZSA8IERfQ09ERVMsIFwiYmFkIGRfY29kZVwiKTtcblxuICAgICAgICBzZW5kX2NvZGUocywgY29kZSwgZHRyZWUpOyAgICAgICAvKiBzZW5kIHRoZSBkaXN0YW5jZSBjb2RlICovXG4gICAgICAgIGV4dHJhID0gZXh0cmFfZGJpdHNbY29kZV07XG4gICAgICAgIGlmIChleHRyYSAhPT0gMCkge1xuICAgICAgICAgIGRpc3QgLT0gYmFzZV9kaXN0W2NvZGVdO1xuICAgICAgICAgIHNlbmRfYml0cyhzLCBkaXN0LCBleHRyYSk7ICAgLyogc2VuZCB0aGUgZXh0cmEgZGlzdGFuY2UgYml0cyAqL1xuICAgICAgICB9XG4gICAgICB9IC8qIGxpdGVyYWwgb3IgbWF0Y2ggcGFpciA/ICovXG5cbiAgICAgIC8qIENoZWNrIHRoYXQgdGhlIG92ZXJsYXkgYmV0d2VlbiBwZW5kaW5nX2J1ZiBhbmQgZF9idWYrbF9idWYgaXMgb2s6ICovXG4gICAgICAvL0Fzc2VydCgodUludCkocy0+cGVuZGluZykgPCBzLT5saXRfYnVmc2l6ZSArIDIqbHgsXG4gICAgICAvLyAgICAgICBcInBlbmRpbmdCdWYgb3ZlcmZsb3dcIik7XG5cbiAgICB9IHdoaWxlIChseCA8IHMubGFzdF9saXQpO1xuICB9XG5cbiAgc2VuZF9jb2RlKHMsIEVORF9CTE9DSywgbHRyZWUpO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29uc3RydWN0IG9uZSBIdWZmbWFuIHRyZWUgYW5kIGFzc2lnbnMgdGhlIGNvZGUgYml0IHN0cmluZ3MgYW5kIGxlbmd0aHMuXG4gKiBVcGRhdGUgdGhlIHRvdGFsIGJpdCBsZW5ndGggZm9yIHRoZSBjdXJyZW50IGJsb2NrLlxuICogSU4gYXNzZXJ0aW9uOiB0aGUgZmllbGQgZnJlcSBpcyBzZXQgZm9yIGFsbCB0cmVlIGVsZW1lbnRzLlxuICogT1VUIGFzc2VydGlvbnM6IHRoZSBmaWVsZHMgbGVuIGFuZCBjb2RlIGFyZSBzZXQgdG8gdGhlIG9wdGltYWwgYml0IGxlbmd0aFxuICogICAgIGFuZCBjb3JyZXNwb25kaW5nIGNvZGUuIFRoZSBsZW5ndGggb3B0X2xlbiBpcyB1cGRhdGVkOyBzdGF0aWNfbGVuIGlzXG4gKiAgICAgYWxzbyB1cGRhdGVkIGlmIHN0cmVlIGlzIG5vdCBudWxsLiBUaGUgZmllbGQgbWF4X2NvZGUgaXMgc2V0LlxuICovXG5mdW5jdGlvbiBidWlsZF90cmVlKHMsIGRlc2MpXG4vLyAgICBkZWZsYXRlX3N0YXRlICpzO1xuLy8gICAgdHJlZV9kZXNjICpkZXNjOyAvKiB0aGUgdHJlZSBkZXNjcmlwdG9yICovXG57XG4gIHZhciB0cmVlICAgICA9IGRlc2MuZHluX3RyZWU7XG4gIHZhciBzdHJlZSAgICA9IGRlc2Muc3RhdF9kZXNjLnN0YXRpY190cmVlO1xuICB2YXIgaGFzX3N0cmVlID0gZGVzYy5zdGF0X2Rlc2MuaGFzX3N0cmVlO1xuICB2YXIgZWxlbXMgICAgPSBkZXNjLnN0YXRfZGVzYy5lbGVtcztcbiAgdmFyIG4sIG07ICAgICAgICAgIC8qIGl0ZXJhdGUgb3ZlciBoZWFwIGVsZW1lbnRzICovXG4gIHZhciBtYXhfY29kZSA9IC0xOyAvKiBsYXJnZXN0IGNvZGUgd2l0aCBub24gemVybyBmcmVxdWVuY3kgKi9cbiAgdmFyIG5vZGU7ICAgICAgICAgIC8qIG5ldyBub2RlIGJlaW5nIGNyZWF0ZWQgKi9cblxuICAvKiBDb25zdHJ1Y3QgdGhlIGluaXRpYWwgaGVhcCwgd2l0aCBsZWFzdCBmcmVxdWVudCBlbGVtZW50IGluXG4gICAqIGhlYXBbU01BTExFU1RdLiBUaGUgc29ucyBvZiBoZWFwW25dIGFyZSBoZWFwWzIqbl0gYW5kIGhlYXBbMipuKzFdLlxuICAgKiBoZWFwWzBdIGlzIG5vdCB1c2VkLlxuICAgKi9cbiAgcy5oZWFwX2xlbiA9IDA7XG4gIHMuaGVhcF9tYXggPSBIRUFQX1NJWkU7XG5cbiAgZm9yIChuID0gMDsgbiA8IGVsZW1zOyBuKyspIHtcbiAgICBpZiAodHJlZVtuICogMl0vKi5GcmVxKi8gIT09IDApIHtcbiAgICAgIHMuaGVhcFsrK3MuaGVhcF9sZW5dID0gbWF4X2NvZGUgPSBuO1xuICAgICAgcy5kZXB0aFtuXSA9IDA7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgdHJlZVtuKjIgKyAxXS8qLkxlbiovID0gMDtcbiAgICB9XG4gIH1cblxuICAvKiBUaGUgcGt6aXAgZm9ybWF0IHJlcXVpcmVzIHRoYXQgYXQgbGVhc3Qgb25lIGRpc3RhbmNlIGNvZGUgZXhpc3RzLFxuICAgKiBhbmQgdGhhdCBhdCBsZWFzdCBvbmUgYml0IHNob3VsZCBiZSBzZW50IGV2ZW4gaWYgdGhlcmUgaXMgb25seSBvbmVcbiAgICogcG9zc2libGUgY29kZS4gU28gdG8gYXZvaWQgc3BlY2lhbCBjaGVja3MgbGF0ZXIgb24gd2UgZm9yY2UgYXQgbGVhc3RcbiAgICogdHdvIGNvZGVzIG9mIG5vbiB6ZXJvIGZyZXF1ZW5jeS5cbiAgICovXG4gIHdoaWxlIChzLmhlYXBfbGVuIDwgMikge1xuICAgIG5vZGUgPSBzLmhlYXBbKytzLmhlYXBfbGVuXSA9IChtYXhfY29kZSA8IDIgPyArK21heF9jb2RlIDogMCk7XG4gICAgdHJlZVtub2RlICogMl0vKi5GcmVxKi8gPSAxO1xuICAgIHMuZGVwdGhbbm9kZV0gPSAwO1xuICAgIHMub3B0X2xlbi0tO1xuXG4gICAgaWYgKGhhc19zdHJlZSkge1xuICAgICAgcy5zdGF0aWNfbGVuIC09IHN0cmVlW25vZGUqMiArIDFdLyouTGVuKi87XG4gICAgfVxuICAgIC8qIG5vZGUgaXMgMCBvciAxIHNvIGl0IGRvZXMgbm90IGhhdmUgZXh0cmEgYml0cyAqL1xuICB9XG4gIGRlc2MubWF4X2NvZGUgPSBtYXhfY29kZTtcblxuICAvKiBUaGUgZWxlbWVudHMgaGVhcFtoZWFwX2xlbi8yKzEgLi4gaGVhcF9sZW5dIGFyZSBsZWF2ZXMgb2YgdGhlIHRyZWUsXG4gICAqIGVzdGFibGlzaCBzdWItaGVhcHMgb2YgaW5jcmVhc2luZyBsZW5ndGhzOlxuICAgKi9cbiAgZm9yIChuID0gKHMuaGVhcF9sZW4gPj4gMS8qaW50IC8yKi8pOyBuID49IDE7IG4tLSkgeyBwcWRvd25oZWFwKHMsIHRyZWUsIG4pOyB9XG5cbiAgLyogQ29uc3RydWN0IHRoZSBIdWZmbWFuIHRyZWUgYnkgcmVwZWF0ZWRseSBjb21iaW5pbmcgdGhlIGxlYXN0IHR3b1xuICAgKiBmcmVxdWVudCBub2Rlcy5cbiAgICovXG4gIG5vZGUgPSBlbGVtczsgICAgICAgICAgICAgIC8qIG5leHQgaW50ZXJuYWwgbm9kZSBvZiB0aGUgdHJlZSAqL1xuICBkbyB7XG4gICAgLy9wcXJlbW92ZShzLCB0cmVlLCBuKTsgIC8qIG4gPSBub2RlIG9mIGxlYXN0IGZyZXF1ZW5jeSAqL1xuICAgIC8qKiogcHFyZW1vdmUgKioqL1xuICAgIG4gPSBzLmhlYXBbMS8qU01BTExFU1QqL107XG4gICAgcy5oZWFwWzEvKlNNQUxMRVNUKi9dID0gcy5oZWFwW3MuaGVhcF9sZW4tLV07XG4gICAgcHFkb3duaGVhcChzLCB0cmVlLCAxLypTTUFMTEVTVCovKTtcbiAgICAvKioqL1xuXG4gICAgbSA9IHMuaGVhcFsxLypTTUFMTEVTVCovXTsgLyogbSA9IG5vZGUgb2YgbmV4dCBsZWFzdCBmcmVxdWVuY3kgKi9cblxuICAgIHMuaGVhcFstLXMuaGVhcF9tYXhdID0gbjsgLyoga2VlcCB0aGUgbm9kZXMgc29ydGVkIGJ5IGZyZXF1ZW5jeSAqL1xuICAgIHMuaGVhcFstLXMuaGVhcF9tYXhdID0gbTtcblxuICAgIC8qIENyZWF0ZSBhIG5ldyBub2RlIGZhdGhlciBvZiBuIGFuZCBtICovXG4gICAgdHJlZVtub2RlICogMl0vKi5GcmVxKi8gPSB0cmVlW24gKiAyXS8qLkZyZXEqLyArIHRyZWVbbSAqIDJdLyouRnJlcSovO1xuICAgIHMuZGVwdGhbbm9kZV0gPSAocy5kZXB0aFtuXSA+PSBzLmRlcHRoW21dID8gcy5kZXB0aFtuXSA6IHMuZGVwdGhbbV0pICsgMTtcbiAgICB0cmVlW24qMiArIDFdLyouRGFkKi8gPSB0cmVlW20qMiArIDFdLyouRGFkKi8gPSBub2RlO1xuXG4gICAgLyogYW5kIGluc2VydCB0aGUgbmV3IG5vZGUgaW4gdGhlIGhlYXAgKi9cbiAgICBzLmhlYXBbMS8qU01BTExFU1QqL10gPSBub2RlKys7XG4gICAgcHFkb3duaGVhcChzLCB0cmVlLCAxLypTTUFMTEVTVCovKTtcblxuICB9IHdoaWxlIChzLmhlYXBfbGVuID49IDIpO1xuXG4gIHMuaGVhcFstLXMuaGVhcF9tYXhdID0gcy5oZWFwWzEvKlNNQUxMRVNUKi9dO1xuXG4gIC8qIEF0IHRoaXMgcG9pbnQsIHRoZSBmaWVsZHMgZnJlcSBhbmQgZGFkIGFyZSBzZXQuIFdlIGNhbiBub3dcbiAgICogZ2VuZXJhdGUgdGhlIGJpdCBsZW5ndGhzLlxuICAgKi9cbiAgZ2VuX2JpdGxlbihzLCBkZXNjKTtcblxuICAvKiBUaGUgZmllbGQgbGVuIGlzIG5vdyBzZXQsIHdlIGNhbiBnZW5lcmF0ZSB0aGUgYml0IGNvZGVzICovXG4gIGdlbl9jb2Rlcyh0cmVlLCBtYXhfY29kZSwgcy5ibF9jb3VudCk7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBTY2FuIGEgbGl0ZXJhbCBvciBkaXN0YW5jZSB0cmVlIHRvIGRldGVybWluZSB0aGUgZnJlcXVlbmNpZXMgb2YgdGhlIGNvZGVzXG4gKiBpbiB0aGUgYml0IGxlbmd0aCB0cmVlLlxuICovXG5mdW5jdGlvbiBzY2FuX3RyZWUocywgdHJlZSwgbWF4X2NvZGUpXG4vLyAgICBkZWZsYXRlX3N0YXRlICpzO1xuLy8gICAgY3RfZGF0YSAqdHJlZTsgICAvKiB0aGUgdHJlZSB0byBiZSBzY2FubmVkICovXG4vLyAgICBpbnQgbWF4X2NvZGU7ICAgIC8qIGFuZCBpdHMgbGFyZ2VzdCBjb2RlIG9mIG5vbiB6ZXJvIGZyZXF1ZW5jeSAqL1xue1xuICB2YXIgbjsgICAgICAgICAgICAgICAgICAgICAvKiBpdGVyYXRlcyBvdmVyIGFsbCB0cmVlIGVsZW1lbnRzICovXG4gIHZhciBwcmV2bGVuID0gLTE7ICAgICAgICAgIC8qIGxhc3QgZW1pdHRlZCBsZW5ndGggKi9cbiAgdmFyIGN1cmxlbjsgICAgICAgICAgICAgICAgLyogbGVuZ3RoIG9mIGN1cnJlbnQgY29kZSAqL1xuXG4gIHZhciBuZXh0bGVuID0gdHJlZVswKjIgKyAxXS8qLkxlbiovOyAvKiBsZW5ndGggb2YgbmV4dCBjb2RlICovXG5cbiAgdmFyIGNvdW50ID0gMDsgICAgICAgICAgICAgLyogcmVwZWF0IGNvdW50IG9mIHRoZSBjdXJyZW50IGNvZGUgKi9cbiAgdmFyIG1heF9jb3VudCA9IDc7ICAgICAgICAgLyogbWF4IHJlcGVhdCBjb3VudCAqL1xuICB2YXIgbWluX2NvdW50ID0gNDsgICAgICAgICAvKiBtaW4gcmVwZWF0IGNvdW50ICovXG5cbiAgaWYgKG5leHRsZW4gPT09IDApIHtcbiAgICBtYXhfY291bnQgPSAxMzg7XG4gICAgbWluX2NvdW50ID0gMztcbiAgfVxuICB0cmVlWyhtYXhfY29kZSsxKSoyICsgMV0vKi5MZW4qLyA9IDB4ZmZmZjsgLyogZ3VhcmQgKi9cblxuICBmb3IgKG4gPSAwOyBuIDw9IG1heF9jb2RlOyBuKyspIHtcbiAgICBjdXJsZW4gPSBuZXh0bGVuO1xuICAgIG5leHRsZW4gPSB0cmVlWyhuKzEpKjIgKyAxXS8qLkxlbiovO1xuXG4gICAgaWYgKCsrY291bnQgPCBtYXhfY291bnQgJiYgY3VybGVuID09PSBuZXh0bGVuKSB7XG4gICAgICBjb250aW51ZTtcblxuICAgIH0gZWxzZSBpZiAoY291bnQgPCBtaW5fY291bnQpIHtcbiAgICAgIHMuYmxfdHJlZVtjdXJsZW4gKiAyXS8qLkZyZXEqLyArPSBjb3VudDtcblxuICAgIH0gZWxzZSBpZiAoY3VybGVuICE9PSAwKSB7XG5cbiAgICAgIGlmIChjdXJsZW4gIT09IHByZXZsZW4pIHsgcy5ibF90cmVlW2N1cmxlbiAqIDJdLyouRnJlcSovKys7IH1cbiAgICAgIHMuYmxfdHJlZVtSRVBfM182KjJdLyouRnJlcSovKys7XG5cbiAgICB9IGVsc2UgaWYgKGNvdW50IDw9IDEwKSB7XG4gICAgICBzLmJsX3RyZWVbUkVQWl8zXzEwKjJdLyouRnJlcSovKys7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgcy5ibF90cmVlW1JFUFpfMTFfMTM4KjJdLyouRnJlcSovKys7XG4gICAgfVxuXG4gICAgY291bnQgPSAwO1xuICAgIHByZXZsZW4gPSBjdXJsZW47XG5cbiAgICBpZiAobmV4dGxlbiA9PT0gMCkge1xuICAgICAgbWF4X2NvdW50ID0gMTM4O1xuICAgICAgbWluX2NvdW50ID0gMztcblxuICAgIH0gZWxzZSBpZiAoY3VybGVuID09PSBuZXh0bGVuKSB7XG4gICAgICBtYXhfY291bnQgPSA2O1xuICAgICAgbWluX2NvdW50ID0gMztcblxuICAgIH0gZWxzZSB7XG4gICAgICBtYXhfY291bnQgPSA3O1xuICAgICAgbWluX2NvdW50ID0gNDtcbiAgICB9XG4gIH1cbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFNlbmQgYSBsaXRlcmFsIG9yIGRpc3RhbmNlIHRyZWUgaW4gY29tcHJlc3NlZCBmb3JtLCB1c2luZyB0aGUgY29kZXMgaW5cbiAqIGJsX3RyZWUuXG4gKi9cbmZ1bmN0aW9uIHNlbmRfdHJlZShzLCB0cmVlLCBtYXhfY29kZSlcbi8vICAgIGRlZmxhdGVfc3RhdGUgKnM7XG4vLyAgICBjdF9kYXRhICp0cmVlOyAvKiB0aGUgdHJlZSB0byBiZSBzY2FubmVkICovXG4vLyAgICBpbnQgbWF4X2NvZGU7ICAgICAgIC8qIGFuZCBpdHMgbGFyZ2VzdCBjb2RlIG9mIG5vbiB6ZXJvIGZyZXF1ZW5jeSAqL1xue1xuICB2YXIgbjsgICAgICAgICAgICAgICAgICAgICAvKiBpdGVyYXRlcyBvdmVyIGFsbCB0cmVlIGVsZW1lbnRzICovXG4gIHZhciBwcmV2bGVuID0gLTE7ICAgICAgICAgIC8qIGxhc3QgZW1pdHRlZCBsZW5ndGggKi9cbiAgdmFyIGN1cmxlbjsgICAgICAgICAgICAgICAgLyogbGVuZ3RoIG9mIGN1cnJlbnQgY29kZSAqL1xuXG4gIHZhciBuZXh0bGVuID0gdHJlZVswKjIgKyAxXS8qLkxlbiovOyAvKiBsZW5ndGggb2YgbmV4dCBjb2RlICovXG5cbiAgdmFyIGNvdW50ID0gMDsgICAgICAgICAgICAgLyogcmVwZWF0IGNvdW50IG9mIHRoZSBjdXJyZW50IGNvZGUgKi9cbiAgdmFyIG1heF9jb3VudCA9IDc7ICAgICAgICAgLyogbWF4IHJlcGVhdCBjb3VudCAqL1xuICB2YXIgbWluX2NvdW50ID0gNDsgICAgICAgICAvKiBtaW4gcmVwZWF0IGNvdW50ICovXG5cbiAgLyogdHJlZVttYXhfY29kZSsxXS5MZW4gPSAtMTsgKi8gIC8qIGd1YXJkIGFscmVhZHkgc2V0ICovXG4gIGlmIChuZXh0bGVuID09PSAwKSB7XG4gICAgbWF4X2NvdW50ID0gMTM4O1xuICAgIG1pbl9jb3VudCA9IDM7XG4gIH1cblxuICBmb3IgKG4gPSAwOyBuIDw9IG1heF9jb2RlOyBuKyspIHtcbiAgICBjdXJsZW4gPSBuZXh0bGVuO1xuICAgIG5leHRsZW4gPSB0cmVlWyhuKzEpKjIgKyAxXS8qLkxlbiovO1xuXG4gICAgaWYgKCsrY291bnQgPCBtYXhfY291bnQgJiYgY3VybGVuID09PSBuZXh0bGVuKSB7XG4gICAgICBjb250aW51ZTtcblxuICAgIH0gZWxzZSBpZiAoY291bnQgPCBtaW5fY291bnQpIHtcbiAgICAgIGRvIHsgc2VuZF9jb2RlKHMsIGN1cmxlbiwgcy5ibF90cmVlKTsgfSB3aGlsZSAoLS1jb3VudCAhPT0gMCk7XG5cbiAgICB9IGVsc2UgaWYgKGN1cmxlbiAhPT0gMCkge1xuICAgICAgaWYgKGN1cmxlbiAhPT0gcHJldmxlbikge1xuICAgICAgICBzZW5kX2NvZGUocywgY3VybGVuLCBzLmJsX3RyZWUpO1xuICAgICAgICBjb3VudC0tO1xuICAgICAgfVxuICAgICAgLy9Bc3NlcnQoY291bnQgPj0gMyAmJiBjb3VudCA8PSA2LCBcIiAzXzY/XCIpO1xuICAgICAgc2VuZF9jb2RlKHMsIFJFUF8zXzYsIHMuYmxfdHJlZSk7XG4gICAgICBzZW5kX2JpdHMocywgY291bnQtMywgMik7XG5cbiAgICB9IGVsc2UgaWYgKGNvdW50IDw9IDEwKSB7XG4gICAgICBzZW5kX2NvZGUocywgUkVQWl8zXzEwLCBzLmJsX3RyZWUpO1xuICAgICAgc2VuZF9iaXRzKHMsIGNvdW50LTMsIDMpO1xuXG4gICAgfSBlbHNlIHtcbiAgICAgIHNlbmRfY29kZShzLCBSRVBaXzExXzEzOCwgcy5ibF90cmVlKTtcbiAgICAgIHNlbmRfYml0cyhzLCBjb3VudC0xMSwgNyk7XG4gICAgfVxuXG4gICAgY291bnQgPSAwO1xuICAgIHByZXZsZW4gPSBjdXJsZW47XG4gICAgaWYgKG5leHRsZW4gPT09IDApIHtcbiAgICAgIG1heF9jb3VudCA9IDEzODtcbiAgICAgIG1pbl9jb3VudCA9IDM7XG5cbiAgICB9IGVsc2UgaWYgKGN1cmxlbiA9PT0gbmV4dGxlbikge1xuICAgICAgbWF4X2NvdW50ID0gNjtcbiAgICAgIG1pbl9jb3VudCA9IDM7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgbWF4X2NvdW50ID0gNztcbiAgICAgIG1pbl9jb3VudCA9IDQ7XG4gICAgfVxuICB9XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb25zdHJ1Y3QgdGhlIEh1ZmZtYW4gdHJlZSBmb3IgdGhlIGJpdCBsZW5ndGhzIGFuZCByZXR1cm4gdGhlIGluZGV4IGluXG4gKiBibF9vcmRlciBvZiB0aGUgbGFzdCBiaXQgbGVuZ3RoIGNvZGUgdG8gc2VuZC5cbiAqL1xuZnVuY3Rpb24gYnVpbGRfYmxfdHJlZShzKSB7XG4gIHZhciBtYXhfYmxpbmRleDsgIC8qIGluZGV4IG9mIGxhc3QgYml0IGxlbmd0aCBjb2RlIG9mIG5vbiB6ZXJvIGZyZXEgKi9cblxuICAvKiBEZXRlcm1pbmUgdGhlIGJpdCBsZW5ndGggZnJlcXVlbmNpZXMgZm9yIGxpdGVyYWwgYW5kIGRpc3RhbmNlIHRyZWVzICovXG4gIHNjYW5fdHJlZShzLCBzLmR5bl9sdHJlZSwgcy5sX2Rlc2MubWF4X2NvZGUpO1xuICBzY2FuX3RyZWUocywgcy5keW5fZHRyZWUsIHMuZF9kZXNjLm1heF9jb2RlKTtcblxuICAvKiBCdWlsZCB0aGUgYml0IGxlbmd0aCB0cmVlOiAqL1xuICBidWlsZF90cmVlKHMsIHMuYmxfZGVzYyk7XG4gIC8qIG9wdF9sZW4gbm93IGluY2x1ZGVzIHRoZSBsZW5ndGggb2YgdGhlIHRyZWUgcmVwcmVzZW50YXRpb25zLCBleGNlcHRcbiAgICogdGhlIGxlbmd0aHMgb2YgdGhlIGJpdCBsZW5ndGhzIGNvZGVzIGFuZCB0aGUgNSs1KzQgYml0cyBmb3IgdGhlIGNvdW50cy5cbiAgICovXG5cbiAgLyogRGV0ZXJtaW5lIHRoZSBudW1iZXIgb2YgYml0IGxlbmd0aCBjb2RlcyB0byBzZW5kLiBUaGUgcGt6aXAgZm9ybWF0XG4gICAqIHJlcXVpcmVzIHRoYXQgYXQgbGVhc3QgNCBiaXQgbGVuZ3RoIGNvZGVzIGJlIHNlbnQuIChhcHBub3RlLnR4dCBzYXlzXG4gICAqIDMgYnV0IHRoZSBhY3R1YWwgdmFsdWUgdXNlZCBpcyA0LilcbiAgICovXG4gIGZvciAobWF4X2JsaW5kZXggPSBCTF9DT0RFUy0xOyBtYXhfYmxpbmRleCA+PSAzOyBtYXhfYmxpbmRleC0tKSB7XG4gICAgaWYgKHMuYmxfdHJlZVtibF9vcmRlclttYXhfYmxpbmRleF0qMiArIDFdLyouTGVuKi8gIT09IDApIHtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuICAvKiBVcGRhdGUgb3B0X2xlbiB0byBpbmNsdWRlIHRoZSBiaXQgbGVuZ3RoIHRyZWUgYW5kIGNvdW50cyAqL1xuICBzLm9wdF9sZW4gKz0gMyoobWF4X2JsaW5kZXgrMSkgKyA1KzUrNDtcbiAgLy9UcmFjZXYoKHN0ZGVyciwgXCJcXG5keW4gdHJlZXM6IGR5biAlbGQsIHN0YXQgJWxkXCIsXG4gIC8vICAgICAgICBzLT5vcHRfbGVuLCBzLT5zdGF0aWNfbGVuKSk7XG5cbiAgcmV0dXJuIG1heF9ibGluZGV4O1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogU2VuZCB0aGUgaGVhZGVyIGZvciBhIGJsb2NrIHVzaW5nIGR5bmFtaWMgSHVmZm1hbiB0cmVlczogdGhlIGNvdW50cywgdGhlXG4gKiBsZW5ndGhzIG9mIHRoZSBiaXQgbGVuZ3RoIGNvZGVzLCB0aGUgbGl0ZXJhbCB0cmVlIGFuZCB0aGUgZGlzdGFuY2UgdHJlZS5cbiAqIElOIGFzc2VydGlvbjogbGNvZGVzID49IDI1NywgZGNvZGVzID49IDEsIGJsY29kZXMgPj0gNC5cbiAqL1xuZnVuY3Rpb24gc2VuZF9hbGxfdHJlZXMocywgbGNvZGVzLCBkY29kZXMsIGJsY29kZXMpXG4vLyAgICBkZWZsYXRlX3N0YXRlICpzO1xuLy8gICAgaW50IGxjb2RlcywgZGNvZGVzLCBibGNvZGVzOyAvKiBudW1iZXIgb2YgY29kZXMgZm9yIGVhY2ggdHJlZSAqL1xue1xuICB2YXIgcmFuazsgICAgICAgICAgICAgICAgICAgIC8qIGluZGV4IGluIGJsX29yZGVyICovXG5cbiAgLy9Bc3NlcnQgKGxjb2RlcyA+PSAyNTcgJiYgZGNvZGVzID49IDEgJiYgYmxjb2RlcyA+PSA0LCBcIm5vdCBlbm91Z2ggY29kZXNcIik7XG4gIC8vQXNzZXJ0IChsY29kZXMgPD0gTF9DT0RFUyAmJiBkY29kZXMgPD0gRF9DT0RFUyAmJiBibGNvZGVzIDw9IEJMX0NPREVTLFxuICAvLyAgICAgICAgXCJ0b28gbWFueSBjb2Rlc1wiKTtcbiAgLy9UcmFjZXYoKHN0ZGVyciwgXCJcXG5ibCBjb3VudHM6IFwiKSk7XG4gIHNlbmRfYml0cyhzLCBsY29kZXMtMjU3LCA1KTsgLyogbm90ICsyNTUgYXMgc3RhdGVkIGluIGFwcG5vdGUudHh0ICovXG4gIHNlbmRfYml0cyhzLCBkY29kZXMtMSwgICA1KTtcbiAgc2VuZF9iaXRzKHMsIGJsY29kZXMtNCwgIDQpOyAvKiBub3QgLTMgYXMgc3RhdGVkIGluIGFwcG5vdGUudHh0ICovXG4gIGZvciAocmFuayA9IDA7IHJhbmsgPCBibGNvZGVzOyByYW5rKyspIHtcbiAgICAvL1RyYWNldigoc3RkZXJyLCBcIlxcbmJsIGNvZGUgJTJkIFwiLCBibF9vcmRlcltyYW5rXSkpO1xuICAgIHNlbmRfYml0cyhzLCBzLmJsX3RyZWVbYmxfb3JkZXJbcmFua10qMiArIDFdLyouTGVuKi8sIDMpO1xuICB9XG4gIC8vVHJhY2V2KChzdGRlcnIsIFwiXFxuYmwgdHJlZTogc2VudCAlbGRcIiwgcy0+Yml0c19zZW50KSk7XG5cbiAgc2VuZF90cmVlKHMsIHMuZHluX2x0cmVlLCBsY29kZXMtMSk7IC8qIGxpdGVyYWwgdHJlZSAqL1xuICAvL1RyYWNldigoc3RkZXJyLCBcIlxcbmxpdCB0cmVlOiBzZW50ICVsZFwiLCBzLT5iaXRzX3NlbnQpKTtcblxuICBzZW5kX3RyZWUocywgcy5keW5fZHRyZWUsIGRjb2Rlcy0xKTsgLyogZGlzdGFuY2UgdHJlZSAqL1xuICAvL1RyYWNldigoc3RkZXJyLCBcIlxcbmRpc3QgdHJlZTogc2VudCAlbGRcIiwgcy0+Yml0c19zZW50KSk7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDaGVjayBpZiB0aGUgZGF0YSB0eXBlIGlzIFRFWFQgb3IgQklOQVJZLCB1c2luZyB0aGUgZm9sbG93aW5nIGFsZ29yaXRobTpcbiAqIC0gVEVYVCBpZiB0aGUgdHdvIGNvbmRpdGlvbnMgYmVsb3cgYXJlIHNhdGlzZmllZDpcbiAqICAgIGEpIFRoZXJlIGFyZSBubyBub24tcG9ydGFibGUgY29udHJvbCBjaGFyYWN0ZXJzIGJlbG9uZ2luZyB0byB0aGVcbiAqICAgICAgIFwiYmxhY2sgbGlzdFwiICgwLi42LCAxNC4uMjUsIDI4Li4zMSkuXG4gKiAgICBiKSBUaGVyZSBpcyBhdCBsZWFzdCBvbmUgcHJpbnRhYmxlIGNoYXJhY3RlciBiZWxvbmdpbmcgdG8gdGhlXG4gKiAgICAgICBcIndoaXRlIGxpc3RcIiAoOSB7VEFCfSwgMTAge0xGfSwgMTMge0NSfSwgMzIuLjI1NSkuXG4gKiAtIEJJTkFSWSBvdGhlcndpc2UuXG4gKiAtIFRoZSBmb2xsb3dpbmcgcGFydGlhbGx5LXBvcnRhYmxlIGNvbnRyb2wgY2hhcmFjdGVycyBmb3JtIGFcbiAqICAgXCJncmF5IGxpc3RcIiB0aGF0IGlzIGlnbm9yZWQgaW4gdGhpcyBkZXRlY3Rpb24gYWxnb3JpdGhtOlxuICogICAoNyB7QkVMfSwgOCB7QlN9LCAxMSB7VlR9LCAxMiB7RkZ9LCAyNiB7U1VCfSwgMjcge0VTQ30pLlxuICogSU4gYXNzZXJ0aW9uOiB0aGUgZmllbGRzIEZyZXEgb2YgZHluX2x0cmVlIGFyZSBzZXQuXG4gKi9cbmZ1bmN0aW9uIGRldGVjdF9kYXRhX3R5cGUocykge1xuICAvKiBibGFja19tYXNrIGlzIHRoZSBiaXQgbWFzayBvZiBibGFjay1saXN0ZWQgYnl0ZXNcbiAgICogc2V0IGJpdHMgMC4uNiwgMTQuLjI1LCBhbmQgMjguLjMxXG4gICAqIDB4ZjNmZmMwN2YgPSBiaW5hcnkgMTExMTAwMTExMTExMTExMTExMDAwMDAwMDExMTExMTFcbiAgICovXG4gIHZhciBibGFja19tYXNrID0gMHhmM2ZmYzA3ZjtcbiAgdmFyIG47XG5cbiAgLyogQ2hlY2sgZm9yIG5vbi10ZXh0dWFsIChcImJsYWNrLWxpc3RlZFwiKSBieXRlcy4gKi9cbiAgZm9yIChuID0gMDsgbiA8PSAzMTsgbisrLCBibGFja19tYXNrID4+Pj0gMSkge1xuICAgIGlmICgoYmxhY2tfbWFzayAmIDEpICYmIChzLmR5bl9sdHJlZVtuKjJdLyouRnJlcSovICE9PSAwKSkge1xuICAgICAgcmV0dXJuIFpfQklOQVJZO1xuICAgIH1cbiAgfVxuXG4gIC8qIENoZWNrIGZvciB0ZXh0dWFsIChcIndoaXRlLWxpc3RlZFwiKSBieXRlcy4gKi9cbiAgaWYgKHMuZHluX2x0cmVlWzkgKiAyXS8qLkZyZXEqLyAhPT0gMCB8fCBzLmR5bl9sdHJlZVsxMCAqIDJdLyouRnJlcSovICE9PSAwIHx8XG4gICAgICBzLmR5bl9sdHJlZVsxMyAqIDJdLyouRnJlcSovICE9PSAwKSB7XG4gICAgcmV0dXJuIFpfVEVYVDtcbiAgfVxuICBmb3IgKG4gPSAzMjsgbiA8IExJVEVSQUxTOyBuKyspIHtcbiAgICBpZiAocy5keW5fbHRyZWVbbiAqIDJdLyouRnJlcSovICE9PSAwKSB7XG4gICAgICByZXR1cm4gWl9URVhUO1xuICAgIH1cbiAgfVxuXG4gIC8qIFRoZXJlIGFyZSBubyBcImJsYWNrLWxpc3RlZFwiIG9yIFwid2hpdGUtbGlzdGVkXCIgYnl0ZXM6XG4gICAqIHRoaXMgc3RyZWFtIGVpdGhlciBpcyBlbXB0eSBvciBoYXMgdG9sZXJhdGVkIChcImdyYXktbGlzdGVkXCIpIGJ5dGVzIG9ubHkuXG4gICAqL1xuICByZXR1cm4gWl9CSU5BUlk7XG59XG5cblxudmFyIHN0YXRpY19pbml0X2RvbmUgPSBmYWxzZTtcblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBJbml0aWFsaXplIHRoZSB0cmVlIGRhdGEgc3RydWN0dXJlcyBmb3IgYSBuZXcgemxpYiBzdHJlYW0uXG4gKi9cbmZ1bmN0aW9uIF90cl9pbml0KHMpXG57XG5cbiAgaWYgKCFzdGF0aWNfaW5pdF9kb25lKSB7XG4gICAgdHJfc3RhdGljX2luaXQoKTtcbiAgICBzdGF0aWNfaW5pdF9kb25lID0gdHJ1ZTtcbiAgfVxuXG4gIHMubF9kZXNjICA9IG5ldyBUcmVlRGVzYyhzLmR5bl9sdHJlZSwgc3RhdGljX2xfZGVzYyk7XG4gIHMuZF9kZXNjICA9IG5ldyBUcmVlRGVzYyhzLmR5bl9kdHJlZSwgc3RhdGljX2RfZGVzYyk7XG4gIHMuYmxfZGVzYyA9IG5ldyBUcmVlRGVzYyhzLmJsX3RyZWUsIHN0YXRpY19ibF9kZXNjKTtcblxuICBzLmJpX2J1ZiA9IDA7XG4gIHMuYmlfdmFsaWQgPSAwO1xuXG4gIC8qIEluaXRpYWxpemUgdGhlIGZpcnN0IGJsb2NrIG9mIHRoZSBmaXJzdCBmaWxlOiAqL1xuICBpbml0X2Jsb2NrKHMpO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogU2VuZCBhIHN0b3JlZCBibG9ja1xuICovXG5mdW5jdGlvbiBfdHJfc3RvcmVkX2Jsb2NrKHMsIGJ1Ziwgc3RvcmVkX2xlbiwgbGFzdClcbi8vRGVmbGF0ZVN0YXRlICpzO1xuLy9jaGFyZiAqYnVmOyAgICAgICAvKiBpbnB1dCBibG9jayAqL1xuLy91bGcgc3RvcmVkX2xlbjsgICAvKiBsZW5ndGggb2YgaW5wdXQgYmxvY2sgKi9cbi8vaW50IGxhc3Q7ICAgICAgICAgLyogb25lIGlmIHRoaXMgaXMgdGhlIGxhc3QgYmxvY2sgZm9yIGEgZmlsZSAqL1xue1xuICBzZW5kX2JpdHMocywgKFNUT1JFRF9CTE9DSzw8MSkrKGxhc3QgPyAxIDogMCksIDMpOyAgICAvKiBzZW5kIGJsb2NrIHR5cGUgKi9cbiAgY29weV9ibG9jayhzLCBidWYsIHN0b3JlZF9sZW4sIHRydWUpOyAvKiB3aXRoIGhlYWRlciAqL1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogU2VuZCBvbmUgZW1wdHkgc3RhdGljIGJsb2NrIHRvIGdpdmUgZW5vdWdoIGxvb2thaGVhZCBmb3IgaW5mbGF0ZS5cbiAqIFRoaXMgdGFrZXMgMTAgYml0cywgb2Ygd2hpY2ggNyBtYXkgcmVtYWluIGluIHRoZSBiaXQgYnVmZmVyLlxuICovXG5mdW5jdGlvbiBfdHJfYWxpZ24ocykge1xuICBzZW5kX2JpdHMocywgU1RBVElDX1RSRUVTPDwxLCAzKTtcbiAgc2VuZF9jb2RlKHMsIEVORF9CTE9DSywgc3RhdGljX2x0cmVlKTtcbiAgYmlfZmx1c2gocyk7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBEZXRlcm1pbmUgdGhlIGJlc3QgZW5jb2RpbmcgZm9yIHRoZSBjdXJyZW50IGJsb2NrOiBkeW5hbWljIHRyZWVzLCBzdGF0aWNcbiAqIHRyZWVzIG9yIHN0b3JlLCBhbmQgb3V0cHV0IHRoZSBlbmNvZGVkIGJsb2NrIHRvIHRoZSB6aXAgZmlsZS5cbiAqL1xuZnVuY3Rpb24gX3RyX2ZsdXNoX2Jsb2NrKHMsIGJ1Ziwgc3RvcmVkX2xlbiwgbGFzdClcbi8vRGVmbGF0ZVN0YXRlICpzO1xuLy9jaGFyZiAqYnVmOyAgICAgICAvKiBpbnB1dCBibG9jaywgb3IgTlVMTCBpZiB0b28gb2xkICovXG4vL3VsZyBzdG9yZWRfbGVuOyAgIC8qIGxlbmd0aCBvZiBpbnB1dCBibG9jayAqL1xuLy9pbnQgbGFzdDsgICAgICAgICAvKiBvbmUgaWYgdGhpcyBpcyB0aGUgbGFzdCBibG9jayBmb3IgYSBmaWxlICovXG57XG4gIHZhciBvcHRfbGVuYiwgc3RhdGljX2xlbmI7ICAvKiBvcHRfbGVuIGFuZCBzdGF0aWNfbGVuIGluIGJ5dGVzICovXG4gIHZhciBtYXhfYmxpbmRleCA9IDA7ICAgICAgICAvKiBpbmRleCBvZiBsYXN0IGJpdCBsZW5ndGggY29kZSBvZiBub24gemVybyBmcmVxICovXG5cbiAgLyogQnVpbGQgdGhlIEh1ZmZtYW4gdHJlZXMgdW5sZXNzIGEgc3RvcmVkIGJsb2NrIGlzIGZvcmNlZCAqL1xuICBpZiAocy5sZXZlbCA+IDApIHtcblxuICAgIC8qIENoZWNrIGlmIHRoZSBmaWxlIGlzIGJpbmFyeSBvciB0ZXh0ICovXG4gICAgaWYgKHMuc3RybS5kYXRhX3R5cGUgPT09IFpfVU5LTk9XTikge1xuICAgICAgcy5zdHJtLmRhdGFfdHlwZSA9IGRldGVjdF9kYXRhX3R5cGUocyk7XG4gICAgfVxuXG4gICAgLyogQ29uc3RydWN0IHRoZSBsaXRlcmFsIGFuZCBkaXN0YW5jZSB0cmVlcyAqL1xuICAgIGJ1aWxkX3RyZWUocywgcy5sX2Rlc2MpO1xuICAgIC8vIFRyYWNldigoc3RkZXJyLCBcIlxcbmxpdCBkYXRhOiBkeW4gJWxkLCBzdGF0ICVsZFwiLCBzLT5vcHRfbGVuLFxuICAgIC8vICAgICAgICBzLT5zdGF0aWNfbGVuKSk7XG5cbiAgICBidWlsZF90cmVlKHMsIHMuZF9kZXNjKTtcbiAgICAvLyBUcmFjZXYoKHN0ZGVyciwgXCJcXG5kaXN0IGRhdGE6IGR5biAlbGQsIHN0YXQgJWxkXCIsIHMtPm9wdF9sZW4sXG4gICAgLy8gICAgICAgIHMtPnN0YXRpY19sZW4pKTtcbiAgICAvKiBBdCB0aGlzIHBvaW50LCBvcHRfbGVuIGFuZCBzdGF0aWNfbGVuIGFyZSB0aGUgdG90YWwgYml0IGxlbmd0aHMgb2ZcbiAgICAgKiB0aGUgY29tcHJlc3NlZCBibG9jayBkYXRhLCBleGNsdWRpbmcgdGhlIHRyZWUgcmVwcmVzZW50YXRpb25zLlxuICAgICAqL1xuXG4gICAgLyogQnVpbGQgdGhlIGJpdCBsZW5ndGggdHJlZSBmb3IgdGhlIGFib3ZlIHR3byB0cmVlcywgYW5kIGdldCB0aGUgaW5kZXhcbiAgICAgKiBpbiBibF9vcmRlciBvZiB0aGUgbGFzdCBiaXQgbGVuZ3RoIGNvZGUgdG8gc2VuZC5cbiAgICAgKi9cbiAgICBtYXhfYmxpbmRleCA9IGJ1aWxkX2JsX3RyZWUocyk7XG5cbiAgICAvKiBEZXRlcm1pbmUgdGhlIGJlc3QgZW5jb2RpbmcuIENvbXB1dGUgdGhlIGJsb2NrIGxlbmd0aHMgaW4gYnl0ZXMuICovXG4gICAgb3B0X2xlbmIgPSAocy5vcHRfbGVuKzMrNykgPj4+IDM7XG4gICAgc3RhdGljX2xlbmIgPSAocy5zdGF0aWNfbGVuKzMrNykgPj4+IDM7XG5cbiAgICAvLyBUcmFjZXYoKHN0ZGVyciwgXCJcXG5vcHQgJWx1KCVsdSkgc3RhdCAlbHUoJWx1KSBzdG9yZWQgJWx1IGxpdCAldSBcIixcbiAgICAvLyAgICAgICAgb3B0X2xlbmIsIHMtPm9wdF9sZW4sIHN0YXRpY19sZW5iLCBzLT5zdGF0aWNfbGVuLCBzdG9yZWRfbGVuLFxuICAgIC8vICAgICAgICBzLT5sYXN0X2xpdCkpO1xuXG4gICAgaWYgKHN0YXRpY19sZW5iIDw9IG9wdF9sZW5iKSB7IG9wdF9sZW5iID0gc3RhdGljX2xlbmI7IH1cblxuICB9IGVsc2Uge1xuICAgIC8vIEFzc2VydChidWYgIT0gKGNoYXIqKTAsIFwibG9zdCBidWZcIik7XG4gICAgb3B0X2xlbmIgPSBzdGF0aWNfbGVuYiA9IHN0b3JlZF9sZW4gKyA1OyAvKiBmb3JjZSBhIHN0b3JlZCBibG9jayAqL1xuICB9XG5cbiAgaWYgKChzdG9yZWRfbGVuKzQgPD0gb3B0X2xlbmIpICYmIChidWYgIT09IC0xKSkge1xuICAgIC8qIDQ6IHR3byB3b3JkcyBmb3IgdGhlIGxlbmd0aHMgKi9cblxuICAgIC8qIFRoZSB0ZXN0IGJ1ZiAhPSBOVUxMIGlzIG9ubHkgbmVjZXNzYXJ5IGlmIExJVF9CVUZTSVpFID4gV1NJWkUuXG4gICAgICogT3RoZXJ3aXNlIHdlIGNhbid0IGhhdmUgcHJvY2Vzc2VkIG1vcmUgdGhhbiBXU0laRSBpbnB1dCBieXRlcyBzaW5jZVxuICAgICAqIHRoZSBsYXN0IGJsb2NrIGZsdXNoLCBiZWNhdXNlIGNvbXByZXNzaW9uIHdvdWxkIGhhdmUgYmVlblxuICAgICAqIHN1Y2Nlc3NmdWwuIElmIExJVF9CVUZTSVpFIDw9IFdTSVpFLCBpdCBpcyBuZXZlciB0b28gbGF0ZSB0b1xuICAgICAqIHRyYW5zZm9ybSBhIGJsb2NrIGludG8gYSBzdG9yZWQgYmxvY2suXG4gICAgICovXG4gICAgX3RyX3N0b3JlZF9ibG9jayhzLCBidWYsIHN0b3JlZF9sZW4sIGxhc3QpO1xuXG4gIH0gZWxzZSBpZiAocy5zdHJhdGVneSA9PT0gWl9GSVhFRCB8fCBzdGF0aWNfbGVuYiA9PT0gb3B0X2xlbmIpIHtcblxuICAgIHNlbmRfYml0cyhzLCAoU1RBVElDX1RSRUVTPDwxKSArIChsYXN0ID8gMSA6IDApLCAzKTtcbiAgICBjb21wcmVzc19ibG9jayhzLCBzdGF0aWNfbHRyZWUsIHN0YXRpY19kdHJlZSk7XG5cbiAgfSBlbHNlIHtcbiAgICBzZW5kX2JpdHMocywgKERZTl9UUkVFUzw8MSkgKyAobGFzdCA/IDEgOiAwKSwgMyk7XG4gICAgc2VuZF9hbGxfdHJlZXMocywgcy5sX2Rlc2MubWF4X2NvZGUrMSwgcy5kX2Rlc2MubWF4X2NvZGUrMSwgbWF4X2JsaW5kZXgrMSk7XG4gICAgY29tcHJlc3NfYmxvY2socywgcy5keW5fbHRyZWUsIHMuZHluX2R0cmVlKTtcbiAgfVxuICAvLyBBc3NlcnQgKHMtPmNvbXByZXNzZWRfbGVuID09IHMtPmJpdHNfc2VudCwgXCJiYWQgY29tcHJlc3NlZCBzaXplXCIpO1xuICAvKiBUaGUgYWJvdmUgY2hlY2sgaXMgbWFkZSBtb2QgMl4zMiwgZm9yIGZpbGVzIGxhcmdlciB0aGFuIDUxMiBNQlxuICAgKiBhbmQgdUxvbmcgaW1wbGVtZW50ZWQgb24gMzIgYml0cy5cbiAgICovXG4gIGluaXRfYmxvY2socyk7XG5cbiAgaWYgKGxhc3QpIHtcbiAgICBiaV93aW5kdXAocyk7XG4gIH1cbiAgLy8gVHJhY2V2KChzdGRlcnIsXCJcXG5jb21wcmxlbiAlbHUoJWx1KSBcIiwgcy0+Y29tcHJlc3NlZF9sZW4+PjMsXG4gIC8vICAgICAgIHMtPmNvbXByZXNzZWRfbGVuLTcqbGFzdCkpO1xufVxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFNhdmUgdGhlIG1hdGNoIGluZm8gYW5kIHRhbGx5IHRoZSBmcmVxdWVuY3kgY291bnRzLiBSZXR1cm4gdHJ1ZSBpZlxuICogdGhlIGN1cnJlbnQgYmxvY2sgbXVzdCBiZSBmbHVzaGVkLlxuICovXG5mdW5jdGlvbiBfdHJfdGFsbHkocywgZGlzdCwgbGMpXG4vLyAgICBkZWZsYXRlX3N0YXRlICpzO1xuLy8gICAgdW5zaWduZWQgZGlzdDsgIC8qIGRpc3RhbmNlIG9mIG1hdGNoZWQgc3RyaW5nICovXG4vLyAgICB1bnNpZ25lZCBsYzsgICAgLyogbWF0Y2ggbGVuZ3RoLU1JTl9NQVRDSCBvciB1bm1hdGNoZWQgY2hhciAoaWYgZGlzdD09MCkgKi9cbntcbiAgLy92YXIgb3V0X2xlbmd0aCwgaW5fbGVuZ3RoLCBkY29kZTtcblxuICBzLnBlbmRpbmdfYnVmW3MuZF9idWYgKyBzLmxhc3RfbGl0ICogMl0gICAgID0gKGRpc3QgPj4+IDgpICYgMHhmZjtcbiAgcy5wZW5kaW5nX2J1ZltzLmRfYnVmICsgcy5sYXN0X2xpdCAqIDIgKyAxXSA9IGRpc3QgJiAweGZmO1xuXG4gIHMucGVuZGluZ19idWZbcy5sX2J1ZiArIHMubGFzdF9saXRdID0gbGMgJiAweGZmO1xuICBzLmxhc3RfbGl0Kys7XG5cbiAgaWYgKGRpc3QgPT09IDApIHtcbiAgICAvKiBsYyBpcyB0aGUgdW5tYXRjaGVkIGNoYXIgKi9cbiAgICBzLmR5bl9sdHJlZVtsYyoyXS8qLkZyZXEqLysrO1xuICB9IGVsc2Uge1xuICAgIHMubWF0Y2hlcysrO1xuICAgIC8qIEhlcmUsIGxjIGlzIHRoZSBtYXRjaCBsZW5ndGggLSBNSU5fTUFUQ0ggKi9cbiAgICBkaXN0LS07ICAgICAgICAgICAgIC8qIGRpc3QgPSBtYXRjaCBkaXN0YW5jZSAtIDEgKi9cbiAgICAvL0Fzc2VydCgodXNoKWRpc3QgPCAodXNoKU1BWF9ESVNUKHMpICYmXG4gICAgLy8gICAgICAgKHVzaClsYyA8PSAodXNoKShNQVhfTUFUQ0gtTUlOX01BVENIKSAmJlxuICAgIC8vICAgICAgICh1c2gpZF9jb2RlKGRpc3QpIDwgKHVzaClEX0NPREVTLCAgXCJfdHJfdGFsbHk6IGJhZCBtYXRjaFwiKTtcblxuICAgIHMuZHluX2x0cmVlWyhfbGVuZ3RoX2NvZGVbbGNdK0xJVEVSQUxTKzEpICogMl0vKi5GcmVxKi8rKztcbiAgICBzLmR5bl9kdHJlZVtkX2NvZGUoZGlzdCkgKiAyXS8qLkZyZXEqLysrO1xuICB9XG5cbi8vICghKSBUaGlzIGJsb2NrIGlzIGRpc2FibGVkIGluIHpsaWIgZGVmYWlsdHMsXG4vLyBkb24ndCBlbmFibGUgaXQgZm9yIGJpbmFyeSBjb21wYXRpYmlsaXR5XG5cbi8vI2lmZGVmIFRSVU5DQVRFX0JMT0NLXG4vLyAgLyogVHJ5IHRvIGd1ZXNzIGlmIGl0IGlzIHByb2ZpdGFibGUgdG8gc3RvcCB0aGUgY3VycmVudCBibG9jayBoZXJlICovXG4vLyAgaWYgKChzLmxhc3RfbGl0ICYgMHgxZmZmKSA9PT0gMCAmJiBzLmxldmVsID4gMikge1xuLy8gICAgLyogQ29tcHV0ZSBhbiB1cHBlciBib3VuZCBmb3IgdGhlIGNvbXByZXNzZWQgbGVuZ3RoICovXG4vLyAgICBvdXRfbGVuZ3RoID0gcy5sYXN0X2xpdCo4O1xuLy8gICAgaW5fbGVuZ3RoID0gcy5zdHJzdGFydCAtIHMuYmxvY2tfc3RhcnQ7XG4vL1xuLy8gICAgZm9yIChkY29kZSA9IDA7IGRjb2RlIDwgRF9DT0RFUzsgZGNvZGUrKykge1xuLy8gICAgICBvdXRfbGVuZ3RoICs9IHMuZHluX2R0cmVlW2Rjb2RlKjJdLyouRnJlcSovICogKDUgKyBleHRyYV9kYml0c1tkY29kZV0pO1xuLy8gICAgfVxuLy8gICAgb3V0X2xlbmd0aCA+Pj49IDM7XG4vLyAgICAvL1RyYWNldigoc3RkZXJyLFwiXFxubGFzdF9saXQgJXUsIGluICVsZCwgb3V0IH4lbGQoJWxkJSUpIFwiLFxuLy8gICAgLy8gICAgICAgcy0+bGFzdF9saXQsIGluX2xlbmd0aCwgb3V0X2xlbmd0aCxcbi8vICAgIC8vICAgICAgIDEwMEwgLSBvdXRfbGVuZ3RoKjEwMEwvaW5fbGVuZ3RoKSk7XG4vLyAgICBpZiAocy5tYXRjaGVzIDwgKHMubGFzdF9saXQ+PjEpLyppbnQgLzIqLyAmJiBvdXRfbGVuZ3RoIDwgKGluX2xlbmd0aD4+MSkvKmludCAvMiovKSB7XG4vLyAgICAgIHJldHVybiB0cnVlO1xuLy8gICAgfVxuLy8gIH1cbi8vI2VuZGlmXG5cbiAgcmV0dXJuIChzLmxhc3RfbGl0ID09PSBzLmxpdF9idWZzaXplLTEpO1xuICAvKiBXZSBhdm9pZCBlcXVhbGl0eSB3aXRoIGxpdF9idWZzaXplIGJlY2F1c2Ugb2Ygd3JhcGFyb3VuZCBhdCA2NEtcbiAgICogb24gMTYgYml0IG1hY2hpbmVzIGFuZCBiZWNhdXNlIHN0b3JlZCBibG9ja3MgYXJlIHJlc3RyaWN0ZWQgdG9cbiAgICogNjRLLTEgYnl0ZXMuXG4gICAqL1xufVxuXG5leHBvcnRzLl90cl9pbml0ICA9IF90cl9pbml0O1xuZXhwb3J0cy5fdHJfc3RvcmVkX2Jsb2NrID0gX3RyX3N0b3JlZF9ibG9jaztcbmV4cG9ydHMuX3RyX2ZsdXNoX2Jsb2NrICA9IF90cl9mbHVzaF9ibG9jaztcbmV4cG9ydHMuX3RyX3RhbGx5ID0gX3RyX3RhbGx5O1xuZXhwb3J0cy5fdHJfYWxpZ24gPSBfdHJfYWxpZ247IiwiJ3VzZSBzdHJpY3QnO1xuXG5cbmZ1bmN0aW9uIFpTdHJlYW0oKSB7XG4gIC8qIG5leHQgaW5wdXQgYnl0ZSAqL1xuICB0aGlzLmlucHV0ID0gbnVsbDsgLy8gSlMgc3BlY2lmaWMsIGJlY2F1c2Ugd2UgaGF2ZSBubyBwb2ludGVyc1xuICB0aGlzLm5leHRfaW4gPSAwO1xuICAvKiBudW1iZXIgb2YgYnl0ZXMgYXZhaWxhYmxlIGF0IGlucHV0ICovXG4gIHRoaXMuYXZhaWxfaW4gPSAwO1xuICAvKiB0b3RhbCBudW1iZXIgb2YgaW5wdXQgYnl0ZXMgcmVhZCBzbyBmYXIgKi9cbiAgdGhpcy50b3RhbF9pbiA9IDA7XG4gIC8qIG5leHQgb3V0cHV0IGJ5dGUgc2hvdWxkIGJlIHB1dCB0aGVyZSAqL1xuICB0aGlzLm91dHB1dCA9IG51bGw7IC8vIEpTIHNwZWNpZmljLCBiZWNhdXNlIHdlIGhhdmUgbm8gcG9pbnRlcnNcbiAgdGhpcy5uZXh0X291dCA9IDA7XG4gIC8qIHJlbWFpbmluZyBmcmVlIHNwYWNlIGF0IG91dHB1dCAqL1xuICB0aGlzLmF2YWlsX291dCA9IDA7XG4gIC8qIHRvdGFsIG51bWJlciBvZiBieXRlcyBvdXRwdXQgc28gZmFyICovXG4gIHRoaXMudG90YWxfb3V0ID0gMDtcbiAgLyogbGFzdCBlcnJvciBtZXNzYWdlLCBOVUxMIGlmIG5vIGVycm9yICovXG4gIHRoaXMubXNnID0gJycvKlpfTlVMTCovO1xuICAvKiBub3QgdmlzaWJsZSBieSBhcHBsaWNhdGlvbnMgKi9cbiAgdGhpcy5zdGF0ZSA9IG51bGw7XG4gIC8qIGJlc3QgZ3Vlc3MgYWJvdXQgdGhlIGRhdGEgdHlwZTogYmluYXJ5IG9yIHRleHQgKi9cbiAgdGhpcy5kYXRhX3R5cGUgPSAyLypaX1VOS05PV04qLztcbiAgLyogYWRsZXIzMiB2YWx1ZSBvZiB0aGUgdW5jb21wcmVzc2VkIGRhdGEgKi9cbiAgdGhpcy5hZGxlciA9IDA7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gWlN0cmVhbTsiLCJtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGFycmF5RXF1YWxzKGFycmF5KSB7XG4gICAgLy8gaWYgdGhlIG90aGVyIGFycmF5IGlzIGEgZmFsc3kgdmFsdWUsIHJldHVyblxuICAgIGlmICghYXJyYXkpXG4gICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgIC8vIGNvbXBhcmUgbGVuZ3RocyAtIGNhbiBzYXZlIGEgbG90IG9mIHRpbWVcbiAgICBpZiAodGhpcy5sZW5ndGggIT0gYXJyYXkubGVuZ3RoKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgbCA9IHRoaXMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgIC8vIENoZWNrIGlmIHdlIGhhdmUgbmVzdGVkIGFycmF5c1xuICAgICAgICBpZiAodGhpc1tpXSBpbnN0YW5jZW9mIEFycmF5ICYmIGFycmF5W2ldIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgICAgIC8vIHJlY3Vyc2UgaW50byB0aGUgbmVzdGVkIGFycmF5c1xuICAgICAgICAgICAgaWYgKCFhcnJheUVxdWFscy5hcHBseSh0aGlzW2ldLCBbYXJyYXlbaV1dKSlcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpc1tpXSAhPSBhcnJheVtpXSkge1xuICAgICAgICAgICAgLy8gV2FybmluZyAtIHR3byBkaWZmZXJlbnQgb2JqZWN0IGluc3RhbmNlcyB3aWxsIG5ldmVyIGJlIGVxdWFsOlxuICAgICAgICAgICAgLy8ge3g6MjB9ICE9IHt4OjIwfVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuXG4iLCJleHBvcnRzLkludGVyb3AgPSByZXF1aXJlKCcuL2ludGVyb3AnKTtcbiIsInZhciB0cmFuc2Zvcm0gPSByZXF1aXJlKCcuL3RyYW5zZm9ybScpO1xudmFyIGFycmF5RXF1YWxzID0gcmVxdWlyZSgnLi9hcnJheS1lcXVhbHMnKTtcblxuZnVuY3Rpb24gSW50ZXJvcCgpIHsgfVxubW9kdWxlLmV4cG9ydHMgPSBJbnRlcm9wO1xuXG4vKipcbiAqIFRoaXMgbWFwIGhvbGRzIHRoZSBtb3N0IHJlY2VudCBQbGFuIEEgb2ZmZXIvYW5zd2VyIFNEUCB0aGF0IHdhcyBjb252ZXJ0ZWRcbiAqIHRvIFBsYW4gQiwgd2l0aCB0aGUgU0RQIHR5cGUgKCdvZmZlcicgb3IgJ2Fuc3dlcicpIGFzIGtleXMgYW5kIHRoZSBTRFBcbiAqIHN0cmluZyBhcyB2YWx1ZXMuXG4gKlxuICogQHR5cGUge3t9fVxuICovXG52YXIgY2FjaGUgPSB7fTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCB0cmFuc2Zvcm1zIGEgUGxhbiBBIFNEUCB0byBhbiBlcXVpdmFsZW50IFBsYW4gQiBTRFAuIEFcbiAqIFBlZXJDb25uZWN0aW9uIHdyYXBwZXIgdHJhbnNmb3JtcyB0aGUgU0RQIHRvIFBsYW4gQiBiZWZvcmUgcGFzc2luZyBpdCB0byB0aGVcbiAqIGFwcGxpY2F0aW9uLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuSW50ZXJvcC5wcm90b3R5cGUudG9QbGFuQiA9IGZ1bmN0aW9uKGRlc2MpIHtcblxuICAgIC8vI3JlZ2lvbiBQcmVsaW1pbmFyeSBpbnB1dCB2YWxpZGF0aW9uLlxuXG4gICAgaWYgKHR5cGVvZiBkZXNjICE9PSAnb2JqZWN0JyB8fCBkZXNjID09PSBudWxsIHx8XG4gICAgICAgIHR5cGVvZiBkZXNjLnNkcCAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdBbiBlbXB0eSBkZXNjcmlwdGlvbiB3YXMgcGFzc2VkIGFzIGFuIGFyZ3VtZW50LicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICAvLyBPYmplY3RpZnkgdGhlIFNEUCBmb3IgZWFzaWVyIG1hbmlwdWxhdGlvbi5cbiAgICB2YXIgc2Vzc2lvbiA9IHRyYW5zZm9ybS5wYXJzZShkZXNjLnNkcCk7XG5cbiAgICAvLyBJZiB0aGUgU0RQIGNvbnRhaW5zIG5vIG1lZGlhLCB0aGVyZSdzIG5vdGhpbmcgdG8gdHJhbnNmb3JtLlxuICAgIGlmICh0eXBlb2Ygc2Vzc2lvbi5tZWRpYSA9PT0gJ3VuZGVmaW5lZCcgfHxcbiAgICAgICAgIUFycmF5LmlzQXJyYXkoc2Vzc2lvbi5tZWRpYSkgfHwgc2Vzc2lvbi5tZWRpYS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdUaGUgZGVzY3JpcHRpb24gaGFzIG5vIG1lZGlhLicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICAvLyBUcnkgc29tZSBoZXVyaXN0aWNzIHRvIFwibWFrZSBzdXJlXCIgdGhpcyBpcyBhIFBsYW4gQSBTRFAuIFBsYW4gQiBTRFAgaGFzXG4gICAgLy8gYSB2aWRlbywgYW4gYXVkaW8gYW5kIGEgZGF0YSBcImNoYW5uZWxcIiBhdCBtb3N0LlxuICAgIGlmIChzZXNzaW9uLm1lZGlhLmxlbmd0aCA8PSAzICYmIHNlc3Npb24ubWVkaWEuZXZlcnkoZnVuY3Rpb24obSkge1xuICAgICAgICAgICAgcmV0dXJuIFsndmlkZW8nLCAnYXVkaW8nLCAnZGF0YSddLmluZGV4T2YobS5taWQpICE9PSAtMTtcbiAgICAgICAgfSkpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdUaGlzIGRlc2NyaXB0aW9uIGRvZXMgbm90IGxvb2sgbGlrZSBQbGFuIEEuJyk7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuICAgIC8vI2VuZHJlZ2lvblxuXG4gICAgLy8gUGxhbiBBIFNEUCBpcyBvdXIgXCJwcmVjaW91c1wiLiBDYWNoZSBpdCBmb3IgbGF0ZXIgdXNlIGluIHRoZSBQbGFuIEIgLT5cbiAgICAvLyBQbGFuIEEgdHJhbnNmb3JtYXRpb24uXG4gICAgY2FjaGVbZGVzYy50eXBlXSA9IGRlc2Muc2RwO1xuXG4gICAgLy8jcmVnaW9uIENvbnZlcnQgZnJvbSBQbGFuIEEgdG8gUGxhbiBCLlxuXG4gICAgLy8gV2UgcmVidWlsZCB0aGUgc2Vzc2lvbi5tZWRpYSBhcnJheS5cbiAgICB2YXIgbWVkaWEgPSBzZXNzaW9uLm1lZGlhO1xuICAgIHNlc3Npb24ubWVkaWEgPSBbXTtcblxuICAgIC8vIEFzc29jaWF0aXZlIGFycmF5IHRoYXQgbWFwcyBjaGFubmVsIHR5cGVzIHRvIGNoYW5uZWwgb2JqZWN0cyBmb3IgZmFzdFxuICAgIC8vIGFjY2VzcyB0byBjaGFubmVsIG9iamVjdHMgYnkgdGhlaXIgdHlwZSwgZS5nLiBjaGFubmVsc1snYXVkaW8nXS0+Y2hhbm5lbFxuICAgIC8vIG9iai5cbiAgICB2YXIgY2hhbm5lbHMgPSB7fTtcblxuICAgIC8vIFVzZWQgdG8gYnVpbGQgdGhlIGdyb3VwOkJVTkRMRSB2YWx1ZSBhZnRlciB0aGUgY2hhbm5lbHMgY29uc3RydWN0aW9uXG4gICAgLy8gbG9vcC5cbiAgICB2YXIgdHlwZXMgPSBbXTtcblxuICAgIC8vIEltcGxvZGUgdGhlIFBsYW4gQSBtLWxpbmVzL3RyYWNrcyBpbnRvIFBsYW4gQiBcImNoYW5uZWxzXCIuXG4gICAgbWVkaWEuZm9yRWFjaChmdW5jdGlvbihtTGluZSkge1xuXG4gICAgICAgIC8vIHJ0Y3AtbXV4IGlzIHJlcXVpcmVkIGluIHRoZSBQbGFuIEIgU0RQLlxuICAgICAgICBpZiAodHlwZW9mIG1MaW5lLnJ0Y3BNdXggIT09ICdzdHJpbmcnIHx8XG4gICAgICAgICAgICBtTGluZS5ydGNwTXV4ICE9PSAncnRjcC1tdXgnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjb252ZXJ0IHRvIFBsYW4gQiBiZWNhdXNlIG0tbGluZXMgJyArXG4gICAgICAgICAgICAgICAgJ3dpdGhvdXQgdGhlIHJ0Y3AtbXV4IGF0dHJpYnV0ZSB3ZXJlIGZvdW5kLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgd2UgZG9uJ3QgaGF2ZSBhIGNoYW5uZWwgZm9yIHRoaXMgbUxpbmUudHlwZSwgdGhlbiB1c2UgdGhpcyBtTGluZVxuICAgICAgICAvLyBhcyB0aGUgY2hhbm5lbCBiYXNpcy5cbiAgICAgICAgaWYgKHR5cGVvZiBjaGFubmVsc1ttTGluZS50eXBlXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIGNoYW5uZWxzW21MaW5lLnR5cGVdID0gbUxpbmU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBZGQgc291cmNlcyB0byB0aGUgY2hhbm5lbCBhbmQgaGFuZGxlIGE9bXNpZC5cbiAgICAgICAgaWYgKHR5cGVvZiBtTGluZS5zb3VyY2VzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgT2JqZWN0LmtleXMobUxpbmUuc291cmNlcykuZm9yRWFjaChmdW5jdGlvbihzc3JjKSB7XG4gICAgICAgICAgICAgICAgLy8gQXNzaWduIHRoZSBzb3VyY2VzIHRvIHRoZSBjaGFubmVsLlxuICAgICAgICAgICAgICAgIGNoYW5uZWxzW21MaW5lLnR5cGVdLnNvdXJjZXNbc3NyY10gPSBtTGluZS5zb3VyY2VzW3NzcmNdO1xuXG4gICAgICAgICAgICAgICAgLy8gSW4gUGxhbiBCIHRoZSBtc2lkIGlzIGFuIFNTUkMgYXR0cmlidXRlLiBBbHNvLCB3ZSBkb24ndCBjYXJlXG4gICAgICAgICAgICAgICAgLy8gYWJvdXQgdGhlIG9ic29sZXRlIGxhYmVsIGFuZCBtc2xhYmVsIGF0dHJpYnV0ZXMuXG4gICAgICAgICAgICAgICAgY2hhbm5lbHNbbUxpbmUudHlwZV0uc291cmNlc1tzc3JjXS5tc2lkID0gbUxpbmUubXNpZDtcblxuICAgICAgICAgICAgICAgIC8vIE5PVEUgc3NyY3MgaW4gc3NyYyBncm91cHMgd2lsbCBzaGFyZSBtc2lkcywgYXNcbiAgICAgICAgICAgICAgICAvLyBkcmFmdC11YmVydGktcnRjd2ViLXBsYW4tMDAgbWFuZGF0ZXMuXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFkZCBzc3JjIGdyb3VwcyB0byB0aGUgY2hhbm5lbC5cbiAgICAgICAgaWYgKHR5cGVvZiBtTGluZS5zc3JjR3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgICAgIEFycmF5LmlzQXJyYXkobUxpbmUuc3NyY0dyb3VwcykpIHtcblxuICAgICAgICAgICAgLy8gQ3JlYXRlIHRoZSBzc3JjR3JvdXBzIGFycmF5LCBpZiBpdCdzIG5vdCBkZWZpbmVkLlxuICAgICAgICAgICAgaWYgKHR5cGVvZiBjaGFubmVsLnNzcmNHcm91cHMgPT09ICd1bmRlZmluZWQnIHx8XG4gICAgICAgICAgICAgICAgICAgICFBcnJheS5pc0FycmF5KGNoYW5uZWwuc3NyY0dyb3VwcykpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnNzcmNHcm91cHMgPSBbXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY2hhbm5lbC5zc3JjR3JvdXBzID0gY2hhbm5lbC5zc3JjR3JvdXBzLmNvbmNhdChtTGluZS5zc3JjR3JvdXBzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjaGFubmVsc1ttTGluZS50eXBlXSA9PT0gbUxpbmUpIHtcbiAgICAgICAgICAgIC8vIENvcHkgSUNFIHJlbGF0ZWQgc3R1ZmYgZnJvbSB0aGUgcHJpbmNpcGFsIG1lZGlhIGxpbmUuXG4gICAgICAgICAgICBtTGluZS5jYW5kaWRhdGVzID0gbWVkaWFbMF0uY2FuZGlkYXRlcztcbiAgICAgICAgICAgIG1MaW5lLmljZVVmcmFnID0gbWVkaWFbMF0uaWNlVWZyYWc7XG4gICAgICAgICAgICBtTGluZS5pY2VQd2QgPSBtZWRpYVswXS5pY2VQd2Q7XG4gICAgICAgICAgICBtTGluZS5maW5nZXJwcmludCA9IG1lZGlhWzBdLmZpbmdlcnByaW50O1xuXG4gICAgICAgICAgICAvLyBQbGFuIEIgbWlkcyBhcmUgaW4gWydhdWRpbycsICd2aWRlbycsICdkYXRhJ11cbiAgICAgICAgICAgIG1MaW5lLm1pZCA9IG1MaW5lLnR5cGU7XG5cbiAgICAgICAgICAgIC8vIFBsYW4gQiBkb2Vzbid0IHN1cHBvcnQvbmVlZCB0aGUgYnVuZGxlLW9ubHkgYXR0cmlidXRlLlxuICAgICAgICAgICAgZGVsZXRlIG1MaW5lLmJ1bmRsZU9ubHk7XG5cbiAgICAgICAgICAgIC8vIEluIFBsYW4gQiB0aGUgbXNpZCBpcyBhbiBTU1JDIGF0dHJpYnV0ZS5cbiAgICAgICAgICAgIGRlbGV0ZSBtTGluZS5tc2lkO1xuXG4gICAgICAgICAgICAvLyBVc2VkIHRvIGJ1aWxkIHRoZSBncm91cDpCVU5ETEUgdmFsdWUgYWZ0ZXIgdGhpcyBsb29wLlxuICAgICAgICAgICAgdHlwZXMucHVzaChtTGluZS50eXBlKTtcblxuICAgICAgICAgICAgLy8gQWRkIHRoZSBjaGFubmVsIHRvIHRoZSBuZXcgbWVkaWEgYXJyYXkuXG4gICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2gobUxpbmUpO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBXZSByZWdlbmVyYXRlIHRoZSBCVU5ETEUgZ3JvdXAgd2l0aCB0aGUgbmV3IG1pZHMuXG4gICAgc2Vzc2lvbi5ncm91cHMuZXZlcnkoZnVuY3Rpb24oZ3JvdXApIHtcbiAgICAgICAgaWYgKGdyb3VwLnR5cGUgPT09ICdCVU5ETEUnKSB7XG4gICAgICAgICAgICBncm91cC5taWRzID0gdHlwZXMuam9pbignICcpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIG1zaWQgc2VtYW50aWNcbiAgICBzZXNzaW9uLm1zaWRTZW1hbnRpYyA9IHtcbiAgICAgICAgc2VtYW50aWM6ICdXTVMnLFxuICAgICAgICB0b2tlbjogJyonXG4gICAgfTtcblxuICAgIHZhciByZXNTdHIgPSB0cmFuc2Zvcm0ud3JpdGUoc2Vzc2lvbik7XG5cbiAgICByZXR1cm4gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgIHR5cGU6IGRlc2MudHlwZSxcbiAgICAgICAgc2RwOiByZXNTdHJcbiAgICB9KTtcblxuICAgIC8vI2VuZHJlZ2lvblxufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCB0cmFuc2Zvcm1zIGEgUGxhbiBCIFNEUCB0byBhbiBlcXVpdmFsZW50IFBsYW4gQSBTRFAuIEFcbiAqIFBlZXJDb25uZWN0aW9uIHdyYXBwZXIgdHJhbnNmb3JtcyB0aGUgU0RQIHRvIFBsYW4gQSBiZWZvcmUgcGFzc2luZyBpdCB0byBGRi5cbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cbkludGVyb3AucHJvdG90eXBlLnRvUGxhbkEgPSBmdW5jdGlvbihkZXNjKSB7XG5cbiAgICAvLyNyZWdpb24gUHJlbGltaW5hcnkgaW5wdXQgdmFsaWRhdGlvbi5cblxuICAgIGlmICh0eXBlb2YgZGVzYyAhPT0gJ29iamVjdCcgfHwgZGVzYyA9PT0gbnVsbCB8fFxuICAgICAgICB0eXBlb2YgZGVzYy5zZHAgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignQW4gZW1wdHkgZGVzY3JpcHRpb24gd2FzIHBhc3NlZCBhcyBhbiBhcmd1bWVudC4nKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgdmFyIHNlc3Npb24gPSB0cmFuc2Zvcm0ucGFyc2UoZGVzYy5zZHApO1xuXG4gICAgLy8gSWYgdGhlIFNEUCBjb250YWlucyBubyBtZWRpYSwgdGhlcmUncyBub3RoaW5nIHRvIHRyYW5zZm9ybS5cbiAgICBpZiAodHlwZW9mIHNlc3Npb24ubWVkaWEgPT09ICd1bmRlZmluZWQnIHx8XG4gICAgICAgICFBcnJheS5pc0FycmF5KHNlc3Npb24ubWVkaWEpIHx8IHNlc3Npb24ubWVkaWEubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignVGhlIGRlc2NyaXB0aW9uIGhhcyBubyBtZWRpYS4nKTtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHNvbWUgaGV1cmlzdGljcyB0byBcIm1ha2Ugc3VyZVwiIHRoaXMgaXMgYSBQbGFuIEIgU0RQLiBQbGFuIEIgU0RQIGhhc1xuICAgIC8vIGEgdmlkZW8sIGFuIGF1ZGlvIGFuZCBhIGRhdGEgXCJjaGFubmVsXCIgYXQgbW9zdC5cbiAgICBpZiAoc2Vzc2lvbi5tZWRpYS5sZW5ndGggPiAzIHx8ICFzZXNzaW9uLm1lZGlhLmV2ZXJ5KGZ1bmN0aW9uKG0pIHtcbiAgICAgICAgICAgIHJldHVybiBbJ3ZpZGVvJywgJ2F1ZGlvJywgJ2RhdGEnXS5pbmRleE9mKG0ubWlkKSAhPT0gLTE7XG4gICAgICAgIH0pKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignVGhpcyBkZXNjcmlwdGlvbiBkb2VzIG5vdCBsb29rIGxpa2UgUGxhbiBCLicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICAvLyBNYWtlIHN1cmUgdGhpcyBQbGFuIEIgU0RQIGNhbiBiZSBjb252ZXJ0ZWQgdG8gYSBQbGFuIEEgU0RQLlxuICAgIHZhciBtaWRzID0gW107XG4gICAgc2Vzc2lvbi5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKG0pIHtcbiAgICAgICAgbWlkcy5wdXNoKG0ubWlkKTtcbiAgICB9KTtcblxuICAgIHZhciBoYXNCdW5kbGUgPSBmYWxzZTtcbiAgICBpZiAodHlwZW9mIHNlc3Npb24uZ3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBBcnJheS5pc0FycmF5KHNlc3Npb24uZ3JvdXBzKSkge1xuICAgICAgICBoYXNCdW5kbGUgPSBzZXNzaW9uLmdyb3Vwcy5ldmVyeShmdW5jdGlvbihnKSB7XG4gICAgICAgICAgICByZXR1cm4gZy50eXBlICE9PSAnQlVORExFJyB8fFxuICAgICAgICAgICAgICAgIGFycmF5RXF1YWxzLmFwcGx5KGcubWlkcy5zb3J0KCksIFttaWRzLnNvcnQoKV0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoIWhhc0J1bmRsZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY29udmVydCB0byBQbGFuIEEgYmVjYXVzZSBtLWxpbmVzIHRoYXQgYXJlIFwiICtcbiAgICAgICAgICAgIFwibm90IGJ1bmRsZWQgd2VyZSBmb3VuZC5cIik7XG4gICAgfVxuXG4gICAgLy8jZW5kcmVnaW9uXG5cblxuICAgIC8vI3JlZ2lvbiBDb252ZXJ0IGZyb20gUGxhbiBCIHRvIFBsYW4gQS5cblxuICAgIC8vIFVuZm9ydHVuYXRlbHksIGEgUGxhbiBCIG9mZmVyL2Fuc3dlciBkb2Vzbid0IGhhdmUgZW5vdWdoIGluZm9ybWF0aW9uIHRvXG4gICAgLy8gcmVidWlsZCBhbiBlcXVpdmFsZW50IFBsYW4gQSBvZmZlci9hbnN3ZXIuXG4gICAgLy9cbiAgICAvLyBGb3IgZXhhbXBsZSwgaWYgdGhpcyBpcyBhIGxvY2FsIGFuc3dlciAoaW4gUGxhbiBBIHN0eWxlKSB0aGF0IHdlIGNvbnZlcnRcbiAgICAvLyB0byBQbGFuIEIgcHJpb3IgdG8gaGFuZGluZyBpdCBvdmVyIHRvIHRoZSBhcHBsaWNhdGlvbiAodGhlXG4gICAgLy8gUGVlckNvbm5lY3Rpb24gd3JhcHBlciBjYWxsZWQgdXMsIGZvciBpbnN0YW5jZSwgYWZ0ZXIgYSBzdWNjZXNzZnVsXG4gICAgLy8gY3JlYXRlQW5zd2VyKSwgd2Ugd2FudCB0byByZW1lbWJlciB0aGUgbS1saW5lIGF0IHdoaWNoIHdlJ3ZlIHNlZW4gdGhlXG4gICAgLy8gKGxvY2FsKSBTU1JDLiBUaGF0J3MgYmVjYXVzZSB3aGVuIHRoZSBhcHBsaWNhdGlvbiB3YW50cyB0byBkbyBjYWxsIHRoZVxuICAgIC8vIFNMRCBtZXRob2QsIGZvcmNpbmcgdXMgdG8gZG8gdGhlIGludmVyc2UgdHJhbnNmb3JtYXRpb24gKGZyb20gUGxhbiBCIHRvXG4gICAgLy8gUGxhbiBBKSwgd2UgbmVlZCB0byBrbm93IHRvIHdoaWNoIG0tbGluZSB0byBhc3NpZ24gdGhlIChsb2NhbCkgU1NSQy4gV2VcbiAgICAvLyBhbHNvIG5lZWQgdG8ga25vdyBhbGwgdGhlIG90aGVyIG0tbGluZXMgdGhhdCB0aGUgb3JpZ2luYWwgYW5zd2VyIGhhZCBhbmRcbiAgICAvLyBpbmNsdWRlIHRoZW0gaW4gdGhlIHRyYW5zZm9ybWVkIGFuc3dlciBhcyB3ZWxsLlxuICAgIC8vXG4gICAgLy8gQW5vdGhlciBleGFtcGxlIGlzIGlmIHRoaXMgaXMgYSByZW1vdGUgb2ZmZXIgdGhhdCB3ZSBjb252ZXJ0IHRvIFBsYW4gQlxuICAgIC8vIHByaW9yIHRvIGdpdmluZyBpdCB0byB0aGUgYXBwbGljYXRpb24sIHdlIHdhbnQgdG8gcmVtZW1iZXIgdGhlIG1pZCBhdFxuICAgIC8vIHdoaWNoIHdlJ3ZlIHNlZW4gdGhlIChyZW1vdGUpIFNTUkMuXG4gICAgLy9cbiAgICAvLyBJbiB0aGUgaXRlcmF0aW9uIHRoYXQgZm9sbG93cywgd2UgdXNlIHRoZSBjYWNoZWQgUGxhbiBBIChpZiBpdCBleGlzdHMpXG4gICAgLy8gdG8gYXNzaWduIG1pZHMgdG8gc3NyY3MuXG5cbiAgICB2YXIgY2FjaGVkO1xuICAgIGlmICh0eXBlb2YgY2FjaGVbZGVzYy50eXBlXSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgY2FjaGVkID0gdHJhbnNmb3JtLnBhcnNlKGNhY2hlW2Rlc2MudHlwZV0pO1xuICAgIH1cblxuICAgIC8vIEEgaGVscGVyIG1hcCB0aGF0IHNlbmRzIG1pZHMgdG8gbS1saW5lIG9iamVjdHMuIFdlIHVzZSBpdCBsYXRlciB0b1xuICAgIC8vIHJlYnVpbGQgdGhlIFBsYW4gQSBzdHlsZSBzZXNzaW9uLm1lZGlhIGFycmF5LlxuICAgIHZhciBtZWRpYSA9IHt9O1xuICAgIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbihjaGFubmVsKSB7XG4gICAgICAgIGlmICh0eXBlb2YgY2hhbm5lbC5ydGNwTXV4ICE9PSAnc3RyaW5nJyB8fFxuICAgICAgICAgICAgY2hhbm5lbC5ydGNwTXV4ICE9PSAncnRjcC1tdXgnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY29udmVydCB0byBQbGFuIEEgYmVjYXVzZSBtLWxpbmVzIFwiICtcbiAgICAgICAgICAgICAgICBcIndpdGhvdXQgdGhlIHJ0Y3AtbXV4IGF0dHJpYnV0ZSB3ZXJlIGZvdW5kLlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFdpdGggcnRjcC1tdXggYW5kIGJ1bmRsZSBhbGwgdGhlIGNoYW5uZWxzIHNob3VsZCBoYXZlIHRoZSBzYW1lIElDRVxuICAgICAgICAvLyBzdHVmZi5cbiAgICAgICAgdmFyIHNvdXJjZXMgPSBjaGFubmVsLnNvdXJjZXM7XG4gICAgICAgIHZhciBzc3JjR3JvdXBzID0gY2hhbm5lbC5zc3JjR3JvdXBzO1xuICAgICAgICB2YXIgY2FuZGlkYXRlcyA9IGNoYW5uZWwuY2FuZGlkYXRlcztcbiAgICAgICAgdmFyIGljZVVmcmFnID0gY2hhbm5lbC5pY2VVZnJhZztcbiAgICAgICAgdmFyIGljZVB3ZCA9IGNoYW5uZWwuaWNlUHdkO1xuICAgICAgICB2YXIgZmluZ2VycHJpbnQgPSBjaGFubmVsLmZpbmdlcnByaW50O1xuICAgICAgICB2YXIgcG9ydCA9IGNoYW5uZWwucG9ydDtcblxuICAgICAgICAvLyBXZSdsbCB1c2UgdGhlIFwiY2hhbm5lbFwiIG9iamVjdCBhcyBhIHByb3RvdHlwZSBmb3IgZWFjaCBuZXcgXCJtTGluZVwiXG4gICAgICAgIC8vIHRoYXQgd2UgY3JlYXRlLCBidXQgZmlyc3Qgd2UgbmVlZCB0byBjbGVhbiBpdCB1cCBhIGJpdC5cbiAgICAgICAgZGVsZXRlIGNoYW5uZWwuc291cmNlcztcbiAgICAgICAgZGVsZXRlIGNoYW5uZWwuc3NyY0dyb3VwcztcbiAgICAgICAgZGVsZXRlIGNoYW5uZWwuY2FuZGlkYXRlcztcbiAgICAgICAgZGVsZXRlIGNoYW5uZWwuaWNlVWZyYWc7XG4gICAgICAgIGRlbGV0ZSBjaGFubmVsLmljZVB3ZDtcbiAgICAgICAgZGVsZXRlIGNoYW5uZWwuZmluZ2VycHJpbnQ7XG4gICAgICAgIGRlbGV0ZSBjaGFubmVsLnBvcnQ7XG4gICAgICAgIGRlbGV0ZSBjaGFubmVsLm1pZDtcblxuICAgICAgICAvLyBpbnZlcnRlZCBzc3JjIGdyb3VwIG1hcFxuICAgICAgICB2YXIgaW52ZXJ0ZWRHcm91cHMgPSB7fTtcbiAgICAgICAgaWYgKHR5cGVvZiBzc3JjR3JvdXBzICE9PSAndW5kZWZpbmVkJyAmJiBBcnJheS5pc0FycmF5KHNzcmNHcm91cHMpKSB7XG4gICAgICAgICAgICBzc3JjR3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKHNzcmNHcm91cCkge1xuXG4gICAgICAgICAgICAgICAgLy8gVE9ETyhncCkgZmluZCBvdXQgaG93IHRvIHJlY2VpdmUgc2ltdWxjYXN0IHdpdGggRkYuIEZvciB0aGVcbiAgICAgICAgICAgICAgICAvLyB0aW1lIGJlaW5nLCBoaWRlIGl0LlxuICAgICAgICAgICAgICAgIGlmIChzc3JjR3JvdXAuc2VtYW50aWNzID09PSAnU0lNJykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjR3JvdXAuc3NyY3MgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgICAgIEFycmF5LmlzQXJyYXkoc3NyY0dyb3VwLnNzcmNzKSkge1xuICAgICAgICAgICAgICAgICAgICBzc3JjR3JvdXAuc3NyY3MuZm9yRWFjaChmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpbnZlcnRlZEdyb3Vwc1tzc3JjXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnZlcnRlZEdyb3Vwc1tzc3JjXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBpbnZlcnRlZEdyb3Vwc1tzc3JjXS5wdXNoKHNzcmNHcm91cCk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc3NyYyB0byBtLWxpbmUgaW5kZXguXG4gICAgICAgIHZhciBtTGluZXMgPSB7fTtcblxuICAgICAgICBpZiAodHlwZW9mIHNvdXJjZXMgPT09ICdvYmplY3QnKSB7XG5cbiAgICAgICAgICAgIC8vIEV4cGxvZGUgdGhlIFBsYW4gQiBjaGFubmVsIHNvdXJjZXMgd2l0aCBvbmUgbS1saW5lIHBlciBzb3VyY2UuXG4gICAgICAgICAgICBPYmplY3Qua2V5cyhzb3VyY2VzKS5mb3JFYWNoKGZ1bmN0aW9uKHNzcmMpIHtcblxuICAgICAgICAgICAgICAgIHZhciBtTGluZTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGludmVydGVkR3JvdXBzW3NzcmNdICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgICAgICAgICBBcnJheS5pc0FycmF5KGludmVydGVkR3JvdXBzW3NzcmNdKSkge1xuICAgICAgICAgICAgICAgICAgICBpbnZlcnRlZEdyb3Vwc1tzc3JjXS5ldmVyeShmdW5jdGlvbiAoc3NyY0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzc3JjR3JvdXAuc3NyY3MgKmlzKiBhbiBBcnJheSwgbm8gbmVlZCB0byBjaGVja1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdhaW4gaGVyZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBzc3JjR3JvdXAuc3NyY3MuZXZlcnkoZnVuY3Rpb24gKHJlbGF0ZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIG1MaW5lc1tyZWxhdGVkXSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbUxpbmUgPSBtTGluZXNbcmVsYXRlZF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtTGluZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gdGhlIG0tbGluZSBhbHJlYWR5IGV4aXN0cy4gSnVzdCBhZGQgdGhlIHNvdXJjZS5cbiAgICAgICAgICAgICAgICAgICAgbUxpbmUuc291cmNlc1tzc3JjXSA9IHNvdXJjZXNbc3NyY107XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBzb3VyY2VzW3NzcmNdLm1zaWQ7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBVc2UgdGhlIFwiY2hhbm5lbFwiIGFzIGEgcHJvdG90eXBlIGZvciB0aGUgXCJtTGluZVwiLlxuICAgICAgICAgICAgICAgIG1MaW5lID0gT2JqZWN0LmNyZWF0ZShjaGFubmVsKTtcbiAgICAgICAgICAgICAgICBtTGluZXNbc3NyY10gPSBtTGluZTtcblxuICAgICAgICAgICAgICAgIC8vIEFzc2lnbiB0aGUgbXNpZCBvZiB0aGUgc291cmNlIHRvIHRoZSBtLWxpbmUuXG4gICAgICAgICAgICAgICAgbUxpbmUubXNpZCA9IHNvdXJjZXNbc3NyY10ubXNpZDtcbiAgICAgICAgICAgICAgICBkZWxldGUgc291cmNlc1tzc3JjXS5tc2lkO1xuXG4gICAgICAgICAgICAgICAgLy8gV2UgYXNzaWduIG9uZSBTU1JDIHBlciBtZWRpYSBsaW5lLlxuICAgICAgICAgICAgICAgIG1MaW5lLnNvdXJjZXMgPSB7fTtcbiAgICAgICAgICAgICAgICBtTGluZS5zb3VyY2VzW3NzcmNdID0gc291cmNlc1tzc3JjXTtcbiAgICAgICAgICAgICAgICBtTGluZS5zc3JjR3JvdXBzID0gaW52ZXJ0ZWRHcm91cHNbc3NyY107XG5cbiAgICAgICAgICAgICAgICAvLyBVc2UgdGhlIGNhY2hlZCBQbGFuIEEgU0RQIChpZiBpdCBleGlzdHMpIHRvIGFzc2lnbiBTU1JDcyB0b1xuICAgICAgICAgICAgICAgIC8vIG1pZHMuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBjYWNoZWQgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgICAgIHR5cGVvZiBjYWNoZWQubWVkaWEgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgICAgIEFycmF5LmlzQXJyYXkoY2FjaGVkLm1lZGlhKSkge1xuXG4gICAgICAgICAgICAgICAgICAgIGNhY2hlZC5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKG0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgbS5zb3VyY2VzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9iamVjdC5rZXlzKG0uc291cmNlcykuZm9yRWFjaChmdW5jdGlvbihzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzID09PSBzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtTGluZS5taWQgPSBtLm1pZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIG1MaW5lLm1pZCA9PT0gJ3VuZGVmaW5lZCcpIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGlzIGlzIGFuIFNTUkMgdGhhdCB3ZSBzZWUgZm9yIHRoZSBmaXJzdCB0aW1lIGFzc2lnblxuICAgICAgICAgICAgICAgICAgICAvLyBpdCBhIG5ldyBtaWQuIFRoaXMgaXMgdHlwaWNhbGx5IHRoZSBjYXNlIHdoZW4gdGhpc1xuICAgICAgICAgICAgICAgICAgICAvLyBtZXRob2QgaXMgY2FsbGVkIHRvIHRyYW5zZm9ybSBhIHJlbW90ZSBkZXNjcmlwdGlvbiBmb3JcbiAgICAgICAgICAgICAgICAgICAgLy8gdGhlIGZpcnN0IHRpbWUgb3Igd2hlbiB0aGVyZSBpcyBhIG5ldyBTU1JDIGluIHRoZSByZW1vdGVcbiAgICAgICAgICAgICAgICAgICAgLy8gZGVzY3JpcHRpb24gYmVjYXVzZSBhIG5ldyBwZWVyIGhhcyBqb2luZWQgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbmZlcmVuY2UuIExvY2FsIFNTUkNzIHNob3VsZCBoYXZlIGFscmVhZHkgYmVlbiBhZGRlZFxuICAgICAgICAgICAgICAgICAgICAvLyB0byB0aGUgbWFwIGluIHRoZSB0b1BsYW5CIG1ldGhvZC5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gQmVjYXVzZSBGRiBnZW5lcmF0ZXMgYW5zd2VycyBpbiBQbGFuIEEgc3R5bGUsIHdlIE1VU1RcbiAgICAgICAgICAgICAgICAgICAgLy8gYWxyZWFkeSBoYXZlIGEgY2FjaGVkIGFuc3dlciB3aXRoIGFsbCB0aGUgbG9jYWwgU1NSQ3NcbiAgICAgICAgICAgICAgICAgICAgLy8gbWFwcGVkIHRvIHNvbWUgbUxpbmUvbWlkLlxuXG4gICAgICAgICAgICAgICAgICAgIGlmIChkZXNjLnR5cGUgPT09ICdhbnN3ZXInKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBbiB1bm1hcHBlZCBTU1JDIHdhcyBmb3VuZC5cIik7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBtTGluZS5taWQgPSBbY2hhbm5lbC50eXBlLCAnLScsIHNzcmNdLmpvaW4oJycpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIEluY2x1ZGUgdGhlIGNhbmRpZGF0ZXMgaW4gdGhlIDFzdCBtZWRpYSBsaW5lLlxuICAgICAgICAgICAgICAgIG1MaW5lLmNhbmRpZGF0ZXMgPSBjYW5kaWRhdGVzO1xuICAgICAgICAgICAgICAgIG1MaW5lLmljZVVmcmFnID0gaWNlVWZyYWc7XG4gICAgICAgICAgICAgICAgbUxpbmUuaWNlUHdkID0gaWNlUHdkO1xuICAgICAgICAgICAgICAgIG1MaW5lLmZpbmdlcnByaW50ID0gZmluZ2VycHJpbnQ7XG4gICAgICAgICAgICAgICAgbUxpbmUucG9ydCA9IHBvcnQ7XG5cbiAgICAgICAgICAgICAgICBtZWRpYVttTGluZS5taWRdID0gbUxpbmU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIFJlYnVpbGQgdGhlIG1lZGlhIGFycmF5IGluIHRoZSByaWdodCBvcmRlciBhbmQgYWRkIHRoZSBtaXNzaW5nIG1MaW5lc1xuICAgIC8vIChtaXNzaW5nIGZyb20gdGhlIFBsYW4gQiBTRFApLlxuICAgIHNlc3Npb24ubWVkaWEgPSBbXTtcbiAgICBtaWRzID0gW107IC8vIHJldXNlXG5cbiAgICBpZiAoZGVzYy50eXBlID09PSAnYW5zd2VyJykge1xuXG4gICAgICAgIC8vIFRoZSBtZWRpYSBsaW5lcyBpbiB0aGUgYW5zd2VyIG11c3QgbWF0Y2ggdGhlIG1lZGlhIGxpbmVzIGluIHRoZVxuICAgICAgICAvLyBvZmZlci4gVGhlIG9yZGVyIGlzIGltcG9ydGFudCB0b28uIEhlcmUgd2UgdXNlIHRoZSBjYWNoZWQgb2ZmZXIgdG9cbiAgICAgICAgLy8gZmluZCB0aGUgbS1saW5lcyB0aGF0IGFyZSBtaXNzaW5nIChmcm9tIHRoZSBjb252ZXJ0ZWQgYW5zd2VyKSwgYW5kXG4gICAgICAgIC8vIHVzZSB0aGUgY2FjaGVkIGFuc3dlciB0byBjb21wbGV0ZSB0aGUgY29udmVydGVkIGFuc3dlci5cblxuICAgICAgICBpZiAodHlwZW9mIGNhY2hlWydvZmZlciddID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQW4gYW5zd2VyIGlzIGJlaW5nIHByb2Nlc3NlZCBidXQgd2UgY291bGRuJ3QgXCIgK1xuICAgICAgICAgICAgICAgICAgICBcImZpbmQgYSBjYWNoZWQgb2ZmZXIuXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNhY2hlZE9mZmVyID0gdHJhbnNmb3JtLnBhcnNlKGNhY2hlWydvZmZlciddKTtcblxuICAgICAgICBpZiAodHlwZW9mIGNhY2hlZE9mZmVyID09PSAndW5kZWZpbmVkJyB8fFxuICAgICAgICAgICAgdHlwZW9mIGNhY2hlZE9mZmVyLm1lZGlhID09PSAndW5kZWZpbmVkJyB8fFxuICAgICAgICAgICAgIUFycmF5LmlzQXJyYXkoY2FjaGVkT2ZmZXIubWVkaWEpKSB7XG4gICAgICAgICAgICAgICAgLy8gRklYTUUoZ3ApIGlzIHRoaXMgcmVhbGx5IGEgcHJvYmxlbSBpbiB0aGUgZ2VuZXJhbCBjYXNlP1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoZSBjYWNoZWQgb2ZmZXIgaGFzIG5vIG1lZGlhLlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNhY2hlZE9mZmVyLm1lZGlhLmZvckVhY2goZnVuY3Rpb24obW8pIHtcblxuICAgICAgICAgICAgdmFyIG1MaW5lO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBtZWRpYVttby5taWRdID09PSAndW5kZWZpbmVkJykge1xuXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBpcyBwcm9iYWJseSBhbiBtLWxpbmUgY29udGFpbmluZyBhIHJlbW90ZSB0cmFjayBvbmx5LlxuICAgICAgICAgICAgICAgIC8vIEl0IE1VU1QgZXhpc3QgaW4gdGhlIGNhY2hlZCBhbnN3ZXIgYXMgYSByZW1vdGUgdHJhY2sgb25seVxuICAgICAgICAgICAgICAgIC8vIG1MaW5lLlxuXG4gICAgICAgICAgICAgICAgY2FjaGVkLm1lZGlhLmV2ZXJ5KGZ1bmN0aW9uKG1hKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChtby5taWQgPT0gbWEubWlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtTGluZSA9IG1hO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbUxpbmUgPSBtZWRpYVttby5taWRdO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHlwZW9mIG1MaW5lID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoZSBjYWNoZWQgb2ZmZXIgY29udGFpbnMgYW4gbS1saW5lIHRoYXQgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJkb2Vzbid0IGV4aXN0IG5laXRoZXIgaW4gdGhlIGNhY2hlZCBhbnN3ZXIgbm9yIGluIFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidGhlIGNvbnZlcnRlZCBhbnN3ZXIuXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2gobUxpbmUpO1xuICAgICAgICAgICAgbWlkcy5wdXNoKG1MaW5lLm1pZCk7XG4gICAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG5cbiAgICAgICAgLy8gU0RQIG9mZmVyL2Fuc3dlciAoYW5kIHRoZSBKU0VQIHNwZWMpIGZvcmJpZHMgcmVtb3ZpbmcgYW4gbS1zZWN0aW9uXG4gICAgICAgIC8vIHVuZGVyIGFueSBjaXJjdW1zdGFuY2VzLiBJZiB3ZSBhcmUgbm8gbG9uZ2VyIGludGVyZXN0ZWQgaW4gc2VuZGluZyBhXG4gICAgICAgIC8vIHRyYWNrLCB3ZSBqdXN0IHJlbW92ZSB0aGUgbXNpZCBhbmQgc3NyYyBhdHRyaWJ1dGVzIGFuZCBzZXQgaXQgdG9cbiAgICAgICAgLy8gZWl0aGVyIGE9cmVjdm9ubHkgKGFzIHRoZSByZW9mZmVyZXIsIHdlIG11c3QgdXNlIHJlY3Zvbmx5IGlmIHRoZVxuICAgICAgICAvLyBvdGhlciBzaWRlIHdhcyBwcmV2aW91c2x5IHNlbmRpbmcgb24gdGhlIG0tc2VjdGlvbiwgYnV0IHdlIGNhbiBhbHNvXG4gICAgICAgIC8vIGxlYXZlIHRoZSBwb3NzaWJpbGl0eSBvcGVuIGlmIGl0IHdhc24ndCBwcmV2aW91c2x5IGluIHVzZSksIG9yXG4gICAgICAgIC8vIGE9aW5hY2l2ZS5cblxuICAgICAgICBpZiAodHlwZW9mIGNhY2hlZCAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgIHR5cGVvZiBjYWNoZWQubWVkaWEgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICBBcnJheS5pc0FycmF5KGNhY2hlZC5tZWRpYSkpIHtcbiAgICAgICAgICAgIGNhY2hlZC5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKHBtKSB7XG4gICAgICAgICAgICAgICAgbWlkcy5wdXNoKHBtLm1pZCk7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtZWRpYVtwbS5taWRdICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2gobWVkaWFbcG0ubWlkXSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBtLm1zaWQ7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBwbS5zb3VyY2VzO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgcG0uc3NyY0dyb3VwcztcbiAgICAgICAgICAgICAgICAgICAgcG0uZGlyZWN0aW9uID0gJ3JlY3Zvbmx5JztcbiAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYS5wdXNoKHBtKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFkZCBhbGwgdGhlIHJlbWFpbmluZyAobmV3KSBtLWxpbmVzIG9mIHRoZSB0cmFuc2Zvcm1lZCBTRFAuXG4gICAgICAgIE9iamVjdC5rZXlzKG1lZGlhKS5mb3JFYWNoKGZ1bmN0aW9uKG1pZCkge1xuICAgICAgICAgICAgaWYgKG1pZHMuaW5kZXhPZihtaWQpID09PSAtMSkge1xuICAgICAgICAgICAgICAgIG1pZHMucHVzaChtaWQpO1xuICAgICAgICAgICAgICAgIHNlc3Npb24ubWVkaWEucHVzaChtZWRpYVttaWRdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gV2UgcmVnZW5lcmF0ZSB0aGUgQlVORExFIGdyb3VwIChzaW5jZSB3ZSByZWdlbmVyYXRlZCB0aGUgbWlkcylcbiAgICBzZXNzaW9uLmdyb3Vwcy5ldmVyeShmdW5jdGlvbihncm91cCkge1xuICAgICAgICBpZiAoZ3JvdXAudHlwZSA9PT0gJ0JVTkRMRScpIHtcbiAgICAgICAgICAgIGdyb3VwLm1pZHMgPSBtaWRzLmpvaW4oJyAnKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBtc2lkIHNlbWFudGljXG4gICAgc2Vzc2lvbi5tc2lkU2VtYW50aWMgPSB7XG4gICAgICAgIHNlbWFudGljOiAnV01TJyxcbiAgICAgICAgdG9rZW46ICcqJ1xuICAgIH07XG5cbiAgICB2YXIgcmVzU3RyID0gdHJhbnNmb3JtLndyaXRlKHNlc3Npb24pO1xuXG4gICAgLy8gQ2FjaGUgdGhlIHRyYW5zZm9ybWVkIFNEUCAoUGxhbiBBKSBmb3IgbGF0ZXIgcmUtdXNlIGluIHRoaXMgZnVuY3Rpb24uXG4gICAgY2FjaGVbZGVzYy50eXBlXSA9IHJlc1N0cjtcblxuICAgIHJldHVybiBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgdHlwZTogZGVzYy50eXBlLFxuICAgICAgICBzZHA6IHJlc1N0clxuICAgIH0pO1xuXG4gICAgLy8jZW5kcmVnaW9uXG59O1xuIiwidmFyIHRyYW5zZm9ybSA9IHJlcXVpcmUoJ3NkcC10cmFuc2Zvcm0nKTtcblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uKHNlc3Npb24sIG9wdHMpIHtcblxuICBpZiAodHlwZW9mIHNlc3Npb24gIT09ICd1bmRlZmluZWQnICYmXG4gICAgICB0eXBlb2Ygc2Vzc2lvbi5tZWRpYSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5tZWRpYSkpIHtcblxuICAgIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbiAobUxpbmUpIHtcbiAgICAgIC8vIGV4cGFuZCBzb3VyY2VzIHRvIHNzcmNzXG4gICAgICBpZiAodHlwZW9mIG1MaW5lLnNvdXJjZXMgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgIE9iamVjdC5rZXlzKG1MaW5lLnNvdXJjZXMpLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgIG1MaW5lLnNzcmNzID0gW107XG4gICAgICAgICAgT2JqZWN0LmtleXMobUxpbmUuc291cmNlcykuZm9yRWFjaChmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgdmFyIHNvdXJjZSA9IG1MaW5lLnNvdXJjZXNbc3NyY107XG4gICAgICAgICAgICBPYmplY3Qua2V5cyhzb3VyY2UpLmZvckVhY2goZnVuY3Rpb24gKGF0dHJpYnV0ZSkge1xuICAgICAgICAgICAgICBtTGluZS5zc3Jjcy5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogc3NyYyxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6IGF0dHJpYnV0ZSxcbiAgICAgICAgICAgICAgICB2YWx1ZTogc291cmNlW2F0dHJpYnV0ZV1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBkZWxldGUgbUxpbmUuc291cmNlcztcbiAgICAgICAgfVxuXG4gICAgICAvLyBqb2luIHNzcmNzIGluIHNzcmMgZ3JvdXBzXG4gICAgICBpZiAodHlwZW9mIG1MaW5lLnNzcmNHcm91cHMgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgIEFycmF5LmlzQXJyYXkobUxpbmUuc3NyY0dyb3VwcykpIHtcbiAgICAgICAgICBtTGluZS5zc3JjR3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKHNzcmNHcm91cCkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjR3JvdXAuc3NyY3MgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgQXJyYXkuaXNBcnJheShzc3JjR3JvdXAuc3NyY3MpKSB7XG4gICAgICAgICAgICAgIHNzcmNHcm91cC5zc3JjcyA9IHNzcmNHcm91cC5zc3Jjcy5qb2luKCcgJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8vIGpvaW4gZ3JvdXAgbWlkc1xuICBpZiAodHlwZW9mIHNlc3Npb24gIT09ICd1bmRlZmluZWQnICYmXG4gICAgICB0eXBlb2Ygc2Vzc2lvbi5ncm91cHMgIT09ICd1bmRlZmluZWQnICYmIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5ncm91cHMpKSB7XG5cbiAgICBzZXNzaW9uLmdyb3Vwcy5mb3JFYWNoKGZ1bmN0aW9uIChnKSB7XG4gICAgICBpZiAodHlwZW9mIGcubWlkcyAhPT0gJ3VuZGVmaW5lZCcgJiYgQXJyYXkuaXNBcnJheShnLm1pZHMpKSB7XG4gICAgICAgIGcubWlkcyA9IGcubWlkcy5qb2luKCcgJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gdHJhbnNmb3JtLndyaXRlKHNlc3Npb24sIG9wdHMpO1xufTtcblxuZXhwb3J0cy5wYXJzZSA9IGZ1bmN0aW9uKHNkcCkge1xuICB2YXIgc2Vzc2lvbiA9IHRyYW5zZm9ybS5wYXJzZShzZHApO1xuXG4gIGlmICh0eXBlb2Ygc2Vzc2lvbiAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIHNlc3Npb24ubWVkaWEgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICBBcnJheS5pc0FycmF5KHNlc3Npb24ubWVkaWEpKSB7XG5cbiAgICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG1MaW5lKSB7XG4gICAgICAvLyBncm91cCBzb3VyY2VzIGF0dHJpYnV0ZXMgYnkgc3NyY1xuICAgICAgaWYgKHR5cGVvZiBtTGluZS5zc3JjcyAhPT0gJ3VuZGVmaW5lZCcgJiYgQXJyYXkuaXNBcnJheShtTGluZS5zc3JjcykpIHtcbiAgICAgICAgbUxpbmUuc291cmNlcyA9IHt9O1xuICAgICAgICBtTGluZS5zc3Jjcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgaWYgKCFtTGluZS5zb3VyY2VzW3NzcmMuaWRdKVxuICAgICAgICAgIG1MaW5lLnNvdXJjZXNbc3NyYy5pZF0gPSB7fTtcbiAgICAgICAgbUxpbmUuc291cmNlc1tzc3JjLmlkXVtzc3JjLmF0dHJpYnV0ZV0gPSBzc3JjLnZhbHVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBkZWxldGUgbUxpbmUuc3NyY3M7XG4gICAgICB9XG5cbiAgICAgIC8vIHNwbGl0IHNzcmNzIGluIHNzcmMgZ3JvdXBzXG4gICAgICBpZiAodHlwZW9mIG1MaW5lLnNzcmNHcm91cHMgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgIEFycmF5LmlzQXJyYXkobUxpbmUuc3NyY0dyb3VwcykpIHtcbiAgICAgICAgICBtTGluZS5zc3JjR3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKHNzcmNHcm91cCkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjR3JvdXAuc3NyY3MgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgIHNzcmNHcm91cC5zc3JjcyA9IHNzcmNHcm91cC5zc3Jjcy5zcGxpdCgnICcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfSk7XG4gIH1cbiAgLy8gc3BsaXQgZ3JvdXAgbWlkc1xuICBpZiAodHlwZW9mIHNlc3Npb24gIT09ICd1bmRlZmluZWQnICYmXG4gICAgICB0eXBlb2Ygc2Vzc2lvbi5ncm91cHMgIT09ICd1bmRlZmluZWQnICYmIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5ncm91cHMpKSB7XG5cbiAgICBzZXNzaW9uLmdyb3Vwcy5mb3JFYWNoKGZ1bmN0aW9uIChnKSB7XG4gICAgICBpZiAodHlwZW9mIGcubWlkcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgZy5taWRzID0gZy5taWRzLnNwbGl0KCcgJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gc2Vzc2lvbjtcbn07XG5cbiIsInZhciBncmFtbWFyID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gIHY6IFt7XG4gICAgICBuYW1lOiAndmVyc2lvbicsXG4gICAgICByZWc6IC9eKFxcZCopJC9cbiAgfV0sXG4gIG86IFt7IC8vbz0tIDIwNTE4IDAgSU4gSVA0IDIwMy4wLjExMy4xXG4gICAgLy8gTkI6IHNlc3Npb25JZCB3aWxsIGJlIGEgU3RyaW5nIGluIG1vc3QgY2FzZXMgYmVjYXVzZSBpdCBpcyBodWdlXG4gICAgbmFtZTogJ29yaWdpbicsXG4gICAgcmVnOiAvXihcXFMqKSAoXFxkKikgKFxcZCopIChcXFMqKSBJUChcXGQpIChcXFMqKS8sXG4gICAgbmFtZXM6IFsndXNlcm5hbWUnLCAnc2Vzc2lvbklkJywgJ3Nlc3Npb25WZXJzaW9uJywgJ25ldFR5cGUnLCAnaXBWZXInLCAnYWRkcmVzcyddLFxuICAgIGZvcm1hdDogXCIlcyAlcyAlZCAlcyBJUCVkICVzXCJcbiAgfV0sXG4gIC8vIGRlZmF1bHQgcGFyc2luZyBvZiB0aGVzZSBvbmx5ICh0aG91Z2ggc29tZSBvZiB0aGVzZSBmZWVsIG91dGRhdGVkKVxuICBzOiBbeyBuYW1lOiAnbmFtZScgfV0sXG4gIGk6IFt7IG5hbWU6ICdkZXNjcmlwdGlvbicgfV0sXG4gIHU6IFt7IG5hbWU6ICd1cmknIH1dLFxuICBlOiBbeyBuYW1lOiAnZW1haWwnIH1dLFxuICBwOiBbeyBuYW1lOiAncGhvbmUnIH1dLFxuICB6OiBbeyBuYW1lOiAndGltZXpvbmVzJyB9XSwgLy8gVE9ETzogdGhpcyBvbmUgY2FuIGFjdHVhbGx5IGJlIHBhcnNlZCBwcm9wZXJseS4uXG4gIHI6IFt7IG5hbWU6ICdyZXBlYXRzJyB9XSwgICAvLyBUT0RPOiB0aGlzIG9uZSBjYW4gYWxzbyBiZSBwYXJzZWQgcHJvcGVybHlcbiAgLy9rOiBbe31dLCAvLyBvdXRkYXRlZCB0aGluZyBpZ25vcmVkXG4gIHQ6IFt7IC8vdD0wIDBcbiAgICBuYW1lOiAndGltaW5nJyxcbiAgICByZWc6IC9eKFxcZCopIChcXGQqKS8sXG4gICAgbmFtZXM6IFsnc3RhcnQnLCAnc3RvcCddLFxuICAgIGZvcm1hdDogXCIlZCAlZFwiXG4gIH1dLFxuICBjOiBbeyAvL2M9SU4gSVA0IDEwLjQ3LjE5Ny4yNlxuICAgICAgbmFtZTogJ2Nvbm5lY3Rpb24nLFxuICAgICAgcmVnOiAvXklOIElQKFxcZCkgKFxcUyopLyxcbiAgICAgIG5hbWVzOiBbJ3ZlcnNpb24nLCAnaXAnXSxcbiAgICAgIGZvcm1hdDogXCJJTiBJUCVkICVzXCJcbiAgfV0sXG4gIGI6IFt7IC8vYj1BUzo0MDAwXG4gICAgICBwdXNoOiAnYmFuZHdpZHRoJyxcbiAgICAgIHJlZzogL14oVElBU3xBU3xDVHxSUnxSUyk6KFxcZCopLyxcbiAgICAgIG5hbWVzOiBbJ3R5cGUnLCAnbGltaXQnXSxcbiAgICAgIGZvcm1hdDogXCIlczolc1wiXG4gIH1dLFxuICBtOiBbeyAvL209dmlkZW8gNTE3NDQgUlRQL0FWUCAxMjYgOTcgOTggMzQgMzFcbiAgICAgIC8vIE5COiBzcGVjaWFsIC0gcHVzaGVzIHRvIHNlc3Npb25cbiAgICAgIC8vIFRPRE86IHJ0cC9mbXRwIHNob3VsZCBiZSBmaWx0ZXJlZCBieSB0aGUgcGF5bG9hZHMgZm91bmQgaGVyZT9cbiAgICAgIHJlZzogL14oXFx3KikgKFxcZCopIChbXFx3XFwvXSopKD86ICguKikpPy8sXG4gICAgICBuYW1lczogWyd0eXBlJywgJ3BvcnQnLCAncHJvdG9jb2wnLCAncGF5bG9hZHMnXSxcbiAgICAgIGZvcm1hdDogXCIlcyAlZCAlcyAlc1wiXG4gIH1dLFxuICBhOiBbXG4gICAgeyAvL2E9cnRwbWFwOjExMCBvcHVzLzQ4MDAwLzJcbiAgICAgIHB1c2g6ICdydHAnLFxuICAgICAgcmVnOiAvXnJ0cG1hcDooXFxkKikgKFtcXHdcXC1dKilcXC8oXFxkKikoPzpcXHMqXFwvKFxcUyopKT8vLFxuICAgICAgbmFtZXM6IFsncGF5bG9hZCcsICdjb2RlYycsICdyYXRlJywgJ2VuY29kaW5nJ10sXG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHJldHVybiAoby5lbmNvZGluZykgP1xuICAgICAgICAgIFwicnRwbWFwOiVkICVzLyVzLyVzXCI6XG4gICAgICAgICAgXCJydHBtYXA6JWQgJXMvJXNcIjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgLy9hPWZtdHA6MTA4IHByb2ZpbGUtbGV2ZWwtaWQ9MjQ7b2JqZWN0PTIzO2JpdHJhdGU9NjQwMDBcbiAgICAgIHB1c2g6ICdmbXRwJyxcbiAgICAgIHJlZzogL15mbXRwOihcXGQqKSAoXFxTKikvLFxuICAgICAgbmFtZXM6IFsncGF5bG9hZCcsICdjb25maWcnXSxcbiAgICAgIGZvcm1hdDogXCJmbXRwOiVkICVzXCJcbiAgICB9LFxuICAgIHsgLy9hPWNvbnRyb2w6c3RyZWFtaWQ9MFxuICAgICAgICBuYW1lOiAnY29udHJvbCcsXG4gICAgICAgIHJlZzogL15jb250cm9sOiguKikvLFxuICAgICAgICBmb3JtYXQ6IFwiY29udHJvbDolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1ydGNwOjY1MTc5IElOIElQNCAxOTMuODQuNzcuMTk0XG4gICAgICBuYW1lOiAncnRjcCcsXG4gICAgICByZWc6IC9ecnRjcDooXFxkKikoPzogKFxcUyopIElQKFxcZCkgKFxcUyopKT8vLFxuICAgICAgbmFtZXM6IFsncG9ydCcsICduZXRUeXBlJywgJ2lwVmVyJywgJ2FkZHJlc3MnXSxcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgcmV0dXJuIChvLmFkZHJlc3MgIT0gbnVsbCkgP1xuICAgICAgICAgIFwicnRjcDolZCAlcyBJUCVkICVzXCI6XG4gICAgICAgICAgXCJydGNwOiVkXCI7XG4gICAgICB9XG4gICAgfSxcbiAgICB7IC8vYT1ydGNwLWZiOjk4IHRyci1pbnQgMTAwXG4gICAgICBwdXNoOiAncnRjcEZiVHJySW50JyxcbiAgICAgIHJlZzogL15ydGNwLWZiOihcXCp8XFxkKikgdHJyLWludCAoXFxkKikvLFxuICAgICAgbmFtZXM6IFsncGF5bG9hZCcsICd2YWx1ZSddLFxuICAgICAgZm9ybWF0OiBcInJ0Y3AtZmI6JWQgdHJyLWludCAlZFwiXG4gICAgfSxcbiAgICB7IC8vYT1ydGNwLWZiOjk4IG5hY2sgcnBzaVxuICAgICAgcHVzaDogJ3J0Y3BGYicsXG4gICAgICByZWc6IC9ecnRjcC1mYjooXFwqfFxcZCopIChbXFx3LV9dKikoPzogKFtcXHctX10qKSk/LyxcbiAgICAgIG5hbWVzOiBbJ3BheWxvYWQnLCAndHlwZScsICdzdWJ0eXBlJ10sXG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHJldHVybiAoby5zdWJ0eXBlICE9IG51bGwpID9cbiAgICAgICAgICBcInJ0Y3AtZmI6JXMgJXMgJXNcIjpcbiAgICAgICAgICBcInJ0Y3AtZmI6JXMgJXNcIjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgLy9hPWV4dG1hcDoyIHVybjppZXRmOnBhcmFtczpydHAtaGRyZXh0OnRvZmZzZXRcbiAgICAgIC8vYT1leHRtYXA6MS9yZWN2b25seSBVUkktZ3BzLXN0cmluZ1xuICAgICAgcHVzaDogJ2V4dCcsXG4gICAgICByZWc6IC9eZXh0bWFwOihbXFx3X1xcL10qKSAoXFxTKikoPzogKFxcUyopKT8vLFxuICAgICAgbmFtZXM6IFsndmFsdWUnLCAndXJpJywgJ2NvbmZpZyddLCAvLyB2YWx1ZSBtYXkgaW5jbHVkZSBcIi9kaXJlY3Rpb25cIiBzdWZmaXhcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgcmV0dXJuIChvLmNvbmZpZyAhPSBudWxsKSA/XG4gICAgICAgICAgXCJleHRtYXA6JXMgJXMgJXNcIjpcbiAgICAgICAgICBcImV4dG1hcDolcyAlc1wiO1xuICAgICAgfVxuICAgIH0sXG4gICAge1xuICAgICAgLy9hPWNyeXB0bzoxIEFFU19DTV8xMjhfSE1BQ19TSEExXzgwIGlubGluZTpQUzF1UUNWZWVDRkNhblZtY2prcFB5d2pOV2hjWUQwbVhYdHhhVkJSfDJeMjB8MTozMlxuICAgICAgcHVzaDogJ2NyeXB0bycsXG4gICAgICByZWc6IC9eY3J5cHRvOihcXGQqKSAoW1xcd19dKikgKFxcUyopKD86IChcXFMqKSk/LyxcbiAgICAgIG5hbWVzOiBbJ2lkJywgJ3N1aXRlJywgJ2NvbmZpZycsICdzZXNzaW9uQ29uZmlnJ10sXG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHJldHVybiAoby5zZXNzaW9uQ29uZmlnICE9IG51bGwpID9cbiAgICAgICAgICBcImNyeXB0bzolZCAlcyAlcyAlc1wiOlxuICAgICAgICAgIFwiY3J5cHRvOiVkICVzICVzXCI7XG4gICAgICB9XG4gICAgfSxcbiAgICB7IC8vYT1zZXR1cDphY3RwYXNzXG4gICAgICBuYW1lOiAnc2V0dXAnLFxuICAgICAgcmVnOiAvXnNldHVwOihcXHcqKS8sXG4gICAgICBmb3JtYXQ6IFwic2V0dXA6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9bWlkOjFcbiAgICAgIG5hbWU6ICdtaWQnLFxuICAgICAgcmVnOiAvXm1pZDooW15cXHNdKikvLFxuICAgICAgZm9ybWF0OiBcIm1pZDolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1tc2lkOjBjOGIwNjRkLWQ4MDctNDNiNC1iNDM0LWY5MmE4ODlkODU4NyA5ODE3ODY4NS1kNDA5LTQ2ZTAtOGUxNi03ZWYwZGIwZGI2NGFcbiAgICAgIG5hbWU6ICdtc2lkJyxcbiAgICAgIHJlZzogL15tc2lkOiguKikvLFxuICAgICAgZm9ybWF0OiBcIm1zaWQ6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9cHRpbWU6MjBcbiAgICAgIG5hbWU6ICdwdGltZScsXG4gICAgICByZWc6IC9ecHRpbWU6KFxcZCopLyxcbiAgICAgIGZvcm1hdDogXCJwdGltZTolZFwiXG4gICAgfSxcbiAgICB7IC8vYT1tYXhwdGltZTo2MFxuICAgICAgbmFtZTogJ21heHB0aW1lJyxcbiAgICAgIHJlZzogL15tYXhwdGltZTooXFxkKikvLFxuICAgICAgZm9ybWF0OiBcIm1heHB0aW1lOiVkXCJcbiAgICB9LFxuICAgIHsgLy9hPXNlbmRyZWN2XG4gICAgICBuYW1lOiAnZGlyZWN0aW9uJyxcbiAgICAgIHJlZzogL14oc2VuZHJlY3Z8cmVjdm9ubHl8c2VuZG9ubHl8aW5hY3RpdmUpL1xuICAgIH0sXG4gICAgeyAvL2E9aWNlLWxpdGVcbiAgICAgIG5hbWU6ICdpY2VsaXRlJyxcbiAgICAgIHJlZzogL14oaWNlLWxpdGUpL1xuICAgIH0sXG4gICAgeyAvL2E9aWNlLXVmcmFnOkY3Z0lcbiAgICAgIG5hbWU6ICdpY2VVZnJhZycsXG4gICAgICByZWc6IC9eaWNlLXVmcmFnOihcXFMqKS8sXG4gICAgICBmb3JtYXQ6IFwiaWNlLXVmcmFnOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPWljZS1wd2Q6eDljbWwvWXppY2hWMitYbGhpTXU4Z1xuICAgICAgbmFtZTogJ2ljZVB3ZCcsXG4gICAgICByZWc6IC9eaWNlLXB3ZDooXFxTKikvLFxuICAgICAgZm9ybWF0OiBcImljZS1wd2Q6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9ZmluZ2VycHJpbnQ6U0hBLTEgMDA6MTE6MjI6MzM6NDQ6NTU6NjY6Nzc6ODg6OTk6QUE6QkI6Q0M6REQ6RUU6RkY6MDA6MTE6MjI6MzNcbiAgICAgIG5hbWU6ICdmaW5nZXJwcmludCcsXG4gICAgICByZWc6IC9eZmluZ2VycHJpbnQ6KFxcUyopIChcXFMqKS8sXG4gICAgICBuYW1lczogWyd0eXBlJywgJ2hhc2gnXSxcbiAgICAgIGZvcm1hdDogXCJmaW5nZXJwcmludDolcyAlc1wiXG4gICAgfSxcbiAgICB7XG4gICAgICAvL2E9Y2FuZGlkYXRlOjAgMSBVRFAgMjExMzY2NzMyNyAyMDMuMC4xMTMuMSA1NDQwMCB0eXAgaG9zdFxuICAgICAgLy9hPWNhbmRpZGF0ZToxMTYyODc1MDgxIDEgdWRwIDIxMTM5MzcxNTEgMTkyLjE2OC4zNC43NSA2MDAxNyB0eXAgaG9zdCBnZW5lcmF0aW9uIDBcbiAgICAgIC8vYT1jYW5kaWRhdGU6MzI4OTkxMjk1NyAyIHVkcCAxODQ1NTAxNjk1IDE5My44NC43Ny4xOTQgNjAwMTcgdHlwIHNyZmx4IHJhZGRyIDE5Mi4xNjguMzQuNzUgcnBvcnQgNjAwMTcgZ2VuZXJhdGlvbiAwXG4gICAgICBwdXNoOidjYW5kaWRhdGVzJyxcbiAgICAgIHJlZzogL15jYW5kaWRhdGU6KFxcUyopIChcXGQqKSAoXFxTKikgKFxcZCopIChcXFMqKSAoXFxkKikgdHlwIChcXFMqKSg/OiByYWRkciAoXFxTKikgcnBvcnQgKFxcZCopKT8oPzogZ2VuZXJhdGlvbiAoXFxkKikpPy8sXG4gICAgICBuYW1lczogWydmb3VuZGF0aW9uJywgJ2NvbXBvbmVudCcsICd0cmFuc3BvcnQnLCAncHJpb3JpdHknLCAnaXAnLCAncG9ydCcsICd0eXBlJywgJ3JhZGRyJywgJ3Jwb3J0JywgJ2dlbmVyYXRpb24nXSxcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgdmFyIHN0ciA9IFwiY2FuZGlkYXRlOiVzICVkICVzICVkICVzICVkIHR5cCAlc1wiO1xuICAgICAgICAvLyBOQjogY2FuZGlkYXRlIGhhcyB0d28gb3B0aW9uYWwgY2h1bmtzLCBzbyAldm9pZCBtaWRkbGUgb25lIGlmIGl0J3MgbWlzc2luZ1xuICAgICAgICBzdHIgKz0gKG8ucmFkZHIgIT0gbnVsbCkgPyBcIiByYWRkciAlcyBycG9ydCAlZFwiIDogXCIldiV2XCI7XG4gICAgICAgIGlmIChvLmdlbmVyYXRpb24gIT0gbnVsbCkge1xuICAgICAgICAgIHN0ciArPSBcIiBnZW5lcmF0aW9uICVkXCI7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0cjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgLy9hPWVuZC1vZi1jYW5kaWRhdGVzIChrZWVwIGFmdGVyIHRoZSBjYW5kaWRhdGVzIGxpbmUgZm9yIHJlYWRhYmlsaXR5KVxuICAgICAgbmFtZTogJ2VuZE9mQ2FuZGlkYXRlcycsXG4gICAgICByZWc6IC9eKGVuZC1vZi1jYW5kaWRhdGVzKS9cbiAgICB9LFxuICAgIHsgLy9hPXJlbW90ZS1jYW5kaWRhdGVzOjEgMjAzLjAuMTEzLjEgNTQ0MDAgMiAyMDMuMC4xMTMuMSA1NDQwMSAuLi5cbiAgICAgIG5hbWU6ICdyZW1vdGVDYW5kaWRhdGVzJyxcbiAgICAgIHJlZzogL15yZW1vdGUtY2FuZGlkYXRlczooLiopLyxcbiAgICAgIGZvcm1hdDogXCJyZW1vdGUtY2FuZGlkYXRlczolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1pY2Utb3B0aW9uczpnb29nbGUtaWNlXG4gICAgICBuYW1lOiAnaWNlT3B0aW9ucycsXG4gICAgICByZWc6IC9eaWNlLW9wdGlvbnM6KFxcUyopLyxcbiAgICAgIGZvcm1hdDogXCJpY2Utb3B0aW9uczolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1zc3JjOjI1NjYxMDc1NjkgY25hbWU6dDlZVThNMVV4VEY4WTFBMVxuICAgICAgcHVzaDogXCJzc3Jjc1wiLFxuICAgICAgcmVnOiAvXnNzcmM6KFxcZCopIChbXFx3X10qKTooLiopLyxcbiAgICAgIG5hbWVzOiBbJ2lkJywgJ2F0dHJpYnV0ZScsICd2YWx1ZSddLFxuICAgICAgZm9ybWF0OiBcInNzcmM6JWQgJXM6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9c3NyYy1ncm91cDpGRUMgMSAyXG4gICAgICBwdXNoOiBcInNzcmNHcm91cHNcIixcbiAgICAgIHJlZzogL15zc3JjLWdyb3VwOihcXHcqKSAoLiopLyxcbiAgICAgIG5hbWVzOiBbJ3NlbWFudGljcycsICdzc3JjcyddLFxuICAgICAgZm9ybWF0OiBcInNzcmMtZ3JvdXA6JXMgJXNcIlxuICAgIH0sXG4gICAgeyAvL2E9bXNpZC1zZW1hbnRpYzogV01TIEp2bGFtNVgzU1gxT1A2cG4yMHpXb2d2YUtKejVIamY5T25sVlxuICAgICAgbmFtZTogXCJtc2lkU2VtYW50aWNcIixcbiAgICAgIHJlZzogL15tc2lkLXNlbWFudGljOlxccz8oXFx3KikgKFxcUyopLyxcbiAgICAgIG5hbWVzOiBbJ3NlbWFudGljJywgJ3Rva2VuJ10sXG4gICAgICBmb3JtYXQ6IFwibXNpZC1zZW1hbnRpYzogJXMgJXNcIiAvLyBzcGFjZSBhZnRlciBcIjpcIiBpcyBub3QgYWNjaWRlbnRhbFxuICAgIH0sXG4gICAgeyAvL2E9Z3JvdXA6QlVORExFIGF1ZGlvIHZpZGVvXG4gICAgICBwdXNoOiAnZ3JvdXBzJyxcbiAgICAgIHJlZzogL15ncm91cDooXFx3KikgKC4qKS8sXG4gICAgICBuYW1lczogWyd0eXBlJywgJ21pZHMnXSxcbiAgICAgIGZvcm1hdDogXCJncm91cDolcyAlc1wiXG4gICAgfSxcbiAgICB7IC8vYT1ydGNwLW11eFxuICAgICAgbmFtZTogJ3J0Y3BNdXgnLFxuICAgICAgcmVnOiAvXihydGNwLW11eCkvXG4gICAgfSxcbiAgICB7IC8vIGFueSBhPSB0aGF0IHdlIGRvbid0IHVuZGVyc3RhbmQgaXMga2VwdHMgdmVyYmF0aW0gb24gbWVkaWEuaW52YWxpZFxuICAgICAgcHVzaDogJ2ludmFsaWQnLFxuICAgICAgbmFtZXM6IFtcInZhbHVlXCJdXG4gICAgfVxuICBdXG59O1xuXG4vLyBzZXQgc2Vuc2libGUgZGVmYXVsdHMgdG8gYXZvaWQgcG9sbHV0aW5nIHRoZSBncmFtbWFyIHdpdGggYm9yaW5nIGRldGFpbHNcbk9iamVjdC5rZXlzKGdyYW1tYXIpLmZvckVhY2goZnVuY3Rpb24gKGtleSkge1xuICB2YXIgb2JqcyA9IGdyYW1tYXJba2V5XTtcbiAgb2Jqcy5mb3JFYWNoKGZ1bmN0aW9uIChvYmopIHtcbiAgICBpZiAoIW9iai5yZWcpIHtcbiAgICAgIG9iai5yZWcgPSAvKC4qKS87XG4gICAgfVxuICAgIGlmICghb2JqLmZvcm1hdCkge1xuICAgICAgb2JqLmZvcm1hdCA9IFwiJXNcIjtcbiAgICB9XG4gIH0pO1xufSk7XG4iLCJ2YXIgcGFyc2VyID0gcmVxdWlyZSgnLi9wYXJzZXInKTtcbnZhciB3cml0ZXIgPSByZXF1aXJlKCcuL3dyaXRlcicpO1xuXG5leHBvcnRzLndyaXRlID0gd3JpdGVyO1xuZXhwb3J0cy5wYXJzZSA9IHBhcnNlci5wYXJzZTtcbmV4cG9ydHMucGFyc2VGbXRwQ29uZmlnID0gcGFyc2VyLnBhcnNlRm10cENvbmZpZztcbmV4cG9ydHMucGFyc2VQYXlsb2FkcyA9IHBhcnNlci5wYXJzZVBheWxvYWRzO1xuZXhwb3J0cy5wYXJzZVJlbW90ZUNhbmRpZGF0ZXMgPSBwYXJzZXIucGFyc2VSZW1vdGVDYW5kaWRhdGVzO1xuIiwidmFyIHRvSW50SWZJbnQgPSBmdW5jdGlvbiAodikge1xuICByZXR1cm4gU3RyaW5nKE51bWJlcih2KSkgPT09IHYgPyBOdW1iZXIodikgOiB2O1xufTtcblxudmFyIGF0dGFjaFByb3BlcnRpZXMgPSBmdW5jdGlvbiAobWF0Y2gsIGxvY2F0aW9uLCBuYW1lcywgcmF3TmFtZSkge1xuICBpZiAocmF3TmFtZSAmJiAhbmFtZXMpIHtcbiAgICBsb2NhdGlvbltyYXdOYW1lXSA9IHRvSW50SWZJbnQobWF0Y2hbMV0pO1xuICB9XG4gIGVsc2Uge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbmFtZXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGlmIChtYXRjaFtpKzFdICE9IG51bGwpIHtcbiAgICAgICAgbG9jYXRpb25bbmFtZXNbaV1dID0gdG9JbnRJZkludChtYXRjaFtpKzFdKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn07XG5cbnZhciBwYXJzZVJlZyA9IGZ1bmN0aW9uIChvYmosIGxvY2F0aW9uLCBjb250ZW50KSB7XG4gIHZhciBuZWVkc0JsYW5rID0gb2JqLm5hbWUgJiYgb2JqLm5hbWVzO1xuICBpZiAob2JqLnB1c2ggJiYgIWxvY2F0aW9uW29iai5wdXNoXSkge1xuICAgIGxvY2F0aW9uW29iai5wdXNoXSA9IFtdO1xuICB9XG4gIGVsc2UgaWYgKG5lZWRzQmxhbmsgJiYgIWxvY2F0aW9uW29iai5uYW1lXSkge1xuICAgIGxvY2F0aW9uW29iai5uYW1lXSA9IHt9O1xuICB9XG4gIHZhciBrZXlMb2NhdGlvbiA9IG9iai5wdXNoID9cbiAgICB7fSA6ICAvLyBibGFuayBvYmplY3QgdGhhdCB3aWxsIGJlIHB1c2hlZFxuICAgIG5lZWRzQmxhbmsgPyBsb2NhdGlvbltvYmoubmFtZV0gOiBsb2NhdGlvbjsgLy8gb3RoZXJ3aXNlLCBuYW1lZCBsb2NhdGlvbiBvciByb290XG5cbiAgYXR0YWNoUHJvcGVydGllcyhjb250ZW50Lm1hdGNoKG9iai5yZWcpLCBrZXlMb2NhdGlvbiwgb2JqLm5hbWVzLCBvYmoubmFtZSk7XG5cbiAgaWYgKG9iai5wdXNoKSB7XG4gICAgbG9jYXRpb25bb2JqLnB1c2hdLnB1c2goa2V5TG9jYXRpb24pO1xuICB9XG59O1xuXG52YXIgZ3JhbW1hciA9IHJlcXVpcmUoJy4vZ3JhbW1hcicpO1xudmFyIHZhbGlkTGluZSA9IFJlZ0V4cC5wcm90b3R5cGUudGVzdC5iaW5kKC9eKFthLXpdKT0oLiopLyk7XG5cbmV4cG9ydHMucGFyc2UgPSBmdW5jdGlvbiAoc2RwKSB7XG4gIHZhciBzZXNzaW9uID0ge31cbiAgICAsIG1lZGlhID0gW11cbiAgICAsIGxvY2F0aW9uID0gc2Vzc2lvbjsgLy8gcG9pbnRzIGF0IHdoZXJlIHByb3BlcnRpZXMgZ28gdW5kZXIgKG9uZSBvZiB0aGUgYWJvdmUpXG5cbiAgLy8gcGFyc2UgbGluZXMgd2UgdW5kZXJzdGFuZFxuICBzZHAuc3BsaXQoLyhcXHJcXG58XFxyfFxcbikvKS5maWx0ZXIodmFsaWRMaW5lKS5mb3JFYWNoKGZ1bmN0aW9uIChsKSB7XG4gICAgdmFyIHR5cGUgPSBsWzBdO1xuICAgIHZhciBjb250ZW50ID0gbC5zbGljZSgyKTtcbiAgICBpZiAodHlwZSA9PT0gJ20nKSB7XG4gICAgICBtZWRpYS5wdXNoKHtydHA6IFtdLCBmbXRwOiBbXX0pO1xuICAgICAgbG9jYXRpb24gPSBtZWRpYVttZWRpYS5sZW5ndGgtMV07IC8vIHBvaW50IGF0IGxhdGVzdCBtZWRpYSBsaW5lXG4gICAgfVxuXG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCAoZ3JhbW1hclt0eXBlXSB8fCBbXSkubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgIHZhciBvYmogPSBncmFtbWFyW3R5cGVdW2pdO1xuICAgICAgaWYgKG9iai5yZWcudGVzdChjb250ZW50KSkge1xuICAgICAgICByZXR1cm4gcGFyc2VSZWcob2JqLCBsb2NhdGlvbiwgY29udGVudCk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICBzZXNzaW9uLm1lZGlhID0gbWVkaWE7IC8vIGxpbmsgaXQgdXBcbiAgcmV0dXJuIHNlc3Npb247XG59O1xuXG52YXIgZm10cFJlZHVjZXIgPSBmdW5jdGlvbiAoYWNjLCBleHByKSB7XG4gIHZhciBzID0gZXhwci5zcGxpdCgnPScpO1xuICBpZiAocy5sZW5ndGggPT09IDIpIHtcbiAgICBhY2Nbc1swXV0gPSB0b0ludElmSW50KHNbMV0pO1xuICB9XG4gIHJldHVybiBhY2M7XG59O1xuXG5leHBvcnRzLnBhcnNlRm10cENvbmZpZyA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgcmV0dXJuIHN0ci5zcGxpdCgnOycpLnJlZHVjZShmbXRwUmVkdWNlciwge30pO1xufTtcblxuZXhwb3J0cy5wYXJzZVBheWxvYWRzID0gZnVuY3Rpb24gKHN0cikge1xuICByZXR1cm4gc3RyLnNwbGl0KCcgJykubWFwKE51bWJlcik7XG59O1xuXG5leHBvcnRzLnBhcnNlUmVtb3RlQ2FuZGlkYXRlcyA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgdmFyIGNhbmRpZGF0ZXMgPSBbXTtcbiAgdmFyIHBhcnRzID0gc3RyLnNwbGl0KCcgJykubWFwKHRvSW50SWZJbnQpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgaSArPSAzKSB7XG4gICAgY2FuZGlkYXRlcy5wdXNoKHtcbiAgICAgIGNvbXBvbmVudDogcGFydHNbaV0sXG4gICAgICBpcDogcGFydHNbaSArIDFdLFxuICAgICAgcG9ydDogcGFydHNbaSArIDJdXG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZXM7XG59O1xuIiwidmFyIGdyYW1tYXIgPSByZXF1aXJlKCcuL2dyYW1tYXInKTtcblxuLy8gY3VzdG9taXplZCB1dGlsLmZvcm1hdCAtIGRpc2NhcmRzIGV4Y2VzcyBhcmd1bWVudHMgYW5kIGNhbiB2b2lkIG1pZGRsZSBvbmVzXG52YXIgZm9ybWF0UmVnRXhwID0gLyVbc2R2JV0vZztcbnZhciBmb3JtYXQgPSBmdW5jdGlvbiAoZm9ybWF0U3RyKSB7XG4gIHZhciBpID0gMTtcbiAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG4gIHZhciBsZW4gPSBhcmdzLmxlbmd0aDtcbiAgcmV0dXJuIGZvcm1hdFN0ci5yZXBsYWNlKGZvcm1hdFJlZ0V4cCwgZnVuY3Rpb24gKHgpIHtcbiAgICBpZiAoaSA+PSBsZW4pIHtcbiAgICAgIHJldHVybiB4OyAvLyBtaXNzaW5nIGFyZ3VtZW50XG4gICAgfVxuICAgIHZhciBhcmcgPSBhcmdzW2ldO1xuICAgIGkgKz0gMTtcbiAgICBzd2l0Y2ggKHgpIHtcbiAgICAgIGNhc2UgJyUlJzpcbiAgICAgICAgcmV0dXJuICclJztcbiAgICAgIGNhc2UgJyVzJzpcbiAgICAgICAgcmV0dXJuIFN0cmluZyhhcmcpO1xuICAgICAgY2FzZSAnJWQnOlxuICAgICAgICByZXR1cm4gTnVtYmVyKGFyZyk7XG4gICAgICBjYXNlICcldic6XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG4gIH0pO1xuICAvLyBOQjogd2UgZGlzY2FyZCBleGNlc3MgYXJndW1lbnRzIC0gdGhleSBhcmUgdHlwaWNhbGx5IHVuZGVmaW5lZCBmcm9tIG1ha2VMaW5lXG59O1xuXG52YXIgbWFrZUxpbmUgPSBmdW5jdGlvbiAodHlwZSwgb2JqLCBsb2NhdGlvbikge1xuICB2YXIgc3RyID0gb2JqLmZvcm1hdCBpbnN0YW5jZW9mIEZ1bmN0aW9uID9cbiAgICAob2JqLmZvcm1hdChvYmoucHVzaCA/IGxvY2F0aW9uIDogbG9jYXRpb25bb2JqLm5hbWVdKSkgOlxuICAgIG9iai5mb3JtYXQ7XG5cbiAgdmFyIGFyZ3MgPSBbdHlwZSArICc9JyArIHN0cl07XG4gIGlmIChvYmoubmFtZXMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG9iai5uYW1lcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgdmFyIG4gPSBvYmoubmFtZXNbaV07XG4gICAgICBpZiAob2JqLm5hbWUpIHtcbiAgICAgICAgYXJncy5wdXNoKGxvY2F0aW9uW29iai5uYW1lXVtuXSk7XG4gICAgICB9XG4gICAgICBlbHNlIHsgLy8gZm9yIG1MaW5lIGFuZCBwdXNoIGF0dHJpYnV0ZXNcbiAgICAgICAgYXJncy5wdXNoKGxvY2F0aW9uW29iai5uYW1lc1tpXV0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBlbHNlIHtcbiAgICBhcmdzLnB1c2gobG9jYXRpb25bb2JqLm5hbWVdKTtcbiAgfVxuICByZXR1cm4gZm9ybWF0LmFwcGx5KG51bGwsIGFyZ3MpO1xufTtcblxuLy8gUkZDIHNwZWNpZmllZCBvcmRlclxuLy8gVE9ETzogZXh0ZW5kIHRoaXMgd2l0aCBhbGwgdGhlIHJlc3RcbnZhciBkZWZhdWx0T3V0ZXJPcmRlciA9IFtcbiAgJ3YnLCAnbycsICdzJywgJ2knLFxuICAndScsICdlJywgJ3AnLCAnYycsXG4gICdiJywgJ3QnLCAncicsICd6JywgJ2EnXG5dO1xudmFyIGRlZmF1bHRJbm5lck9yZGVyID0gWydpJywgJ2MnLCAnYicsICdhJ107XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoc2Vzc2lvbiwgb3B0cykge1xuICBvcHRzID0gb3B0cyB8fCB7fTtcbiAgLy8gZW5zdXJlIGNlcnRhaW4gcHJvcGVydGllcyBleGlzdFxuICBpZiAoc2Vzc2lvbi52ZXJzaW9uID09IG51bGwpIHtcbiAgICBzZXNzaW9uLnZlcnNpb24gPSAwOyAvLyBcInY9MFwiIG11c3QgYmUgdGhlcmUgKG9ubHkgZGVmaW5lZCB2ZXJzaW9uIGF0bSlcbiAgfVxuICBpZiAoc2Vzc2lvbi5uYW1lID09IG51bGwpIHtcbiAgICBzZXNzaW9uLm5hbWUgPSBcIiBcIjsgLy8gXCJzPSBcIiBtdXN0IGJlIHRoZXJlIGlmIG5vIG1lYW5pbmdmdWwgbmFtZSBzZXRcbiAgfVxuICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG1MaW5lKSB7XG4gICAgaWYgKG1MaW5lLnBheWxvYWRzID09IG51bGwpIHtcbiAgICAgIG1MaW5lLnBheWxvYWRzID0gXCJcIjtcbiAgICB9XG4gIH0pO1xuXG4gIHZhciBvdXRlck9yZGVyID0gb3B0cy5vdXRlck9yZGVyIHx8IGRlZmF1bHRPdXRlck9yZGVyO1xuICB2YXIgaW5uZXJPcmRlciA9IG9wdHMuaW5uZXJPcmRlciB8fCBkZWZhdWx0SW5uZXJPcmRlcjtcbiAgdmFyIHNkcCA9IFtdO1xuXG4gIC8vIGxvb3AgdGhyb3VnaCBvdXRlck9yZGVyIGZvciBtYXRjaGluZyBwcm9wZXJ0aWVzIG9uIHNlc3Npb25cbiAgb3V0ZXJPcmRlci5mb3JFYWNoKGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgZ3JhbW1hclt0eXBlXS5mb3JFYWNoKGZ1bmN0aW9uIChvYmopIHtcbiAgICAgIGlmIChvYmoubmFtZSBpbiBzZXNzaW9uICYmIHNlc3Npb25bb2JqLm5hbWVdICE9IG51bGwpIHtcbiAgICAgICAgc2RwLnB1c2gobWFrZUxpbmUodHlwZSwgb2JqLCBzZXNzaW9uKSk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChvYmoucHVzaCBpbiBzZXNzaW9uICYmIHNlc3Npb25bb2JqLnB1c2hdICE9IG51bGwpIHtcbiAgICAgICAgc2Vzc2lvbltvYmoucHVzaF0uZm9yRWFjaChmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICBzZHAucHVzaChtYWtlTGluZSh0eXBlLCBvYmosIGVsKSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcblxuICAvLyB0aGVuIGZvciBlYWNoIG1lZGlhIGxpbmUsIGZvbGxvdyB0aGUgaW5uZXJPcmRlclxuICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG1MaW5lKSB7XG4gICAgc2RwLnB1c2gobWFrZUxpbmUoJ20nLCBncmFtbWFyLm1bMF0sIG1MaW5lKSk7XG5cbiAgICBpbm5lck9yZGVyLmZvckVhY2goZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgIGdyYW1tYXJbdHlwZV0uZm9yRWFjaChmdW5jdGlvbiAob2JqKSB7XG4gICAgICAgIGlmIChvYmoubmFtZSBpbiBtTGluZSAmJiBtTGluZVtvYmoubmFtZV0gIT0gbnVsbCkge1xuICAgICAgICAgIHNkcC5wdXNoKG1ha2VMaW5lKHR5cGUsIG9iaiwgbUxpbmUpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChvYmoucHVzaCBpbiBtTGluZSAmJiBtTGluZVtvYmoucHVzaF0gIT0gbnVsbCkge1xuICAgICAgICAgIG1MaW5lW29iai5wdXNoXS5mb3JFYWNoKGZ1bmN0aW9uIChlbCkge1xuICAgICAgICAgICAgc2RwLnB1c2gobWFrZUxpbmUodHlwZSwgb2JqLCBlbCkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgcmV0dXJuIHNkcC5qb2luKCdcXHJcXG4nKSArICdcXHJcXG4nO1xufTtcbiIsInZhciBNZWRpYVN0cmVhbVR5cGUgPSB7XG4gICAgVklERU9fVFlQRTogXCJWaWRlb1wiLFxuXG4gICAgQVVESU9fVFlQRTogXCJBdWRpb1wiXG59O1xubW9kdWxlLmV4cG9ydHMgPSBNZWRpYVN0cmVhbVR5cGU7IiwidmFyIFJUQ0Jyb3dzZXJUeXBlID0ge1xuICAgIFJUQ19CUk9XU0VSX0NIUk9NRTogXCJydGNfYnJvd3Nlci5jaHJvbWVcIixcblxuICAgIFJUQ19CUk9XU0VSX0ZJUkVGT1g6IFwicnRjX2Jyb3dzZXIuZmlyZWZveFwiXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJUQ0Jyb3dzZXJUeXBlOyIsInZhciBSVENFdmVudHMgPSB7XG4gICAgTEFTVE5fQ0hBTkdFRDogXCJydGMubGFzdG5fY2hhbmdlZFwiLFxuICAgIERPTUlOQU5UU1BFQUtFUl9DSEFOR0VEOiBcInJ0Yy5kb21pbmFudHNwZWFrZXJfY2hhbmdlZFwiLFxuICAgIExBU1ROX0VORFBPSU5UX0NIQU5HRUQ6IFwicnRjLmxhc3RuX2VuZHBvaW50X2NoYW5nZWRcIixcbiAgICBTSU1VTENBU1RfTEFZRVJfQ0hBTkdFRDogXCJydGMuc2ltdWxjYXN0X2xheWVyX2NoYW5nZWRcIixcbiAgICBTSU1VTENBU1RfTEFZRVJfQ0hBTkdJTkc6IFwicnRjLnNpbXVsY2FzdF9sYXllcl9jaGFuZ2luZ1wiLFxuICAgIFNJTVVMQ0FTVF9TVEFSVDogXCJydGMuc2ltbGNhc3Rfc3RhcnRcIixcbiAgICBTSU1VTENBU1RfU1RPUDogXCJydGMuc2ltbGNhc3Rfc3RvcFwiLFxuICAgIEFWQUlMQUJMRV9ERVZJQ0VTX0NIQU5HRUQ6IFwicnRjLmF2YWlsYWJsZV9kZXZpY2VzX2NoYW5nZWRcIlxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSVENFdmVudHM7IiwidmFyIFJlc29sdXRpb25zID0ge1xuICAgIFwiMTA4MFwiOiB7XG4gICAgICAgIHdpZHRoOiAxOTIwLFxuICAgICAgICBoZWlnaHQ6IDEwODAsXG4gICAgICAgIG9yZGVyOiA3XG4gICAgfSxcbiAgICBcImZ1bGxoZFwiOiB7XG4gICAgICAgIHdpZHRoOiAxOTIwLFxuICAgICAgICBoZWlnaHQ6IDEwODAsXG4gICAgICAgIG9yZGVyOiA3XG4gICAgfSxcbiAgICBcIjcyMFwiOiB7XG4gICAgICAgIHdpZHRoOiAxMjgwLFxuICAgICAgICBoZWlnaHQ6IDcyMCxcbiAgICAgICAgb3JkZXI6IDZcbiAgICB9LFxuICAgIFwiaGRcIjoge1xuICAgICAgICB3aWR0aDogMTI4MCxcbiAgICAgICAgaGVpZ2h0OiA3MjAsXG4gICAgICAgIG9yZGVyOiA2XG4gICAgfSxcbiAgICBcIjk2MFwiOiB7XG4gICAgICAgIHdpZHRoOiA5NjAsXG4gICAgICAgIGhlaWdodDogNzIwLFxuICAgICAgICBvcmRlcjogNVxuICAgIH0sXG4gICAgXCI2NDBcIjoge1xuICAgICAgICB3aWR0aDogNjQwLFxuICAgICAgICBoZWlnaHQ6IDQ4MCxcbiAgICAgICAgb3JkZXI6IDRcbiAgICB9LFxuICAgIFwidmdhXCI6IHtcbiAgICAgICAgd2lkdGg6IDY0MCxcbiAgICAgICAgaGVpZ2h0OiA0ODAsXG4gICAgICAgIG9yZGVyOiA0XG4gICAgfSxcbiAgICBcIjM2MFwiOiB7XG4gICAgICAgIHdpZHRoOiA2NDAsXG4gICAgICAgIGhlaWdodDogMzYwLFxuICAgICAgICBvcmRlcjogM1xuICAgIH0sXG4gICAgXCIzMjBcIjoge1xuICAgICAgICB3aWR0aDogMzIwLFxuICAgICAgICBoZWlnaHQ6IDI0MCxcbiAgICAgICAgb3JkZXI6IDJcbiAgICB9LFxuICAgIFwiMTgwXCI6IHtcbiAgICAgICAgd2lkdGg6IDMyMCxcbiAgICAgICAgaGVpZ2h0OiAxODAsXG4gICAgICAgIG9yZGVyOiAxXG4gICAgfVxufTtcbm1vZHVsZS5leHBvcnRzID0gUmVzb2x1dGlvbnM7IiwidmFyIFN0cmVhbUV2ZW50VHlwZXMgPSB7XG4gICAgRVZFTlRfVFlQRV9MT0NBTF9DUkVBVEVEOiBcInN0cmVhbS5sb2NhbF9jcmVhdGVkXCIsXG5cbiAgICBFVkVOVF9UWVBFX0xPQ0FMX0NIQU5HRUQ6IFwic3RyZWFtLmxvY2FsX2NoYW5nZWRcIixcblxuICAgIEVWRU5UX1RZUEVfTE9DQUxfRU5ERUQ6IFwic3RyZWFtLmxvY2FsX2VuZGVkXCIsXG5cbiAgICBFVkVOVF9UWVBFX1JFTU9URV9DUkVBVEVEOiBcInN0cmVhbS5yZW1vdGVfY3JlYXRlZFwiLFxuXG4gICAgRVZFTlRfVFlQRV9SRU1PVEVfRU5ERUQ6IFwic3RyZWFtLnJlbW90ZV9lbmRlZFwiLFxuXG4gICAgRVZFTlRfVFlQRV9SRU1PVEVfQ0hBTkdFRDogXCJzdHJlYW0uY2hhbmdlZFwiXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmVhbUV2ZW50VHlwZXM7IiwidmFyIFVJRXZlbnRzID0ge1xuICAgIE5JQ0tOQU1FX0NIQU5HRUQ6IFwiVUkubmlja25hbWVfY2hhbmdlZFwiLFxuICAgIFNFTEVDVEVEX0VORFBPSU5UOiBcIlVJLnNlbGVjdGVkX2VuZHBvaW50XCIsXG4gICAgUElOTkVEX0VORFBPSU5UOiBcIlVJLnBpbm5lZF9lbmRwb2ludFwiXG59O1xubW9kdWxlLmV4cG9ydHMgPSBVSUV2ZW50czsiLCJ2YXIgQXV0aGVudGljYXRpb25FdmVudHMgPSB7XG4gICAgLyoqXG4gICAgICogRXZlbnQgY2FsbGJhY2sgYXJndW1lbnRzOlxuICAgICAqIGZ1bmN0aW9uKGF1dGhlbnRpY2F0aW9uRW5hYmxlZCwgdXNlcklkZW50aXR5KVxuICAgICAqIGF1dGhlbnRpY2F0aW9uRW5hYmxlZCAtIGluZGljYXRlcyB3aGV0aGVyIGF1dGhlbnRpY2F0aW9uIGhhcyBiZWVuIGVuYWJsZWRcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICBpbiB0aGlzIHNlc3Npb25cbiAgICAgKiB1c2VySWRlbnRpdHkgLSBpZiB1c2VyIGhhcyBiZWVuIGxvZ2dlZCBpbiB0aGVuIGl0IGNvbnRhaW5zIHVzZXIgbmFtZS4gSWZcbiAgICAgKiAgICAgICAgICAgICAgICBjb250YWlucyAnbnVsbCcgb3IgJ3VuZGVmaW5lZCcgdGhlbiB1c2VyIGlzIG5vdCBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgSURFTlRJVFlfVVBEQVRFRDogXCJhdXRoZW50aWNhdGlvbi5pZGVudGl0eV91cGRhdGVkXCJcbn07XG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhlbnRpY2F0aW9uRXZlbnRzO1xuIiwidmFyIENRRXZlbnRzID0ge1xuICAgIExPQ0FMU1RBVFNfVVBEQVRFRDogXCJjcS5sb2NhbHN0YXRzX3VwZGF0ZWRcIixcbiAgICBSRU1PVEVTVEFUU19VUERBVEVEOiBcImNxLnJlbW90ZXN0YXRzX3VwZGF0ZWRcIixcbiAgICBTVE9QOiBcImNxLnN0b3BcIlxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDUUV2ZW50czsiLCJ2YXIgRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzID0ge1xuICAgIElOSVQ6IFwiZHMuaW5pdFwiLFxuXG4gICAgU1dJVENISU5HX0RPTkU6IFwiZHMuc3dpdGNoaW5nX2RvbmVcIixcblxuICAgIE5FV19TVFJFQU1fQ1JFQVRFRDogXCJkcy5uZXdfc3RyZWFtX2NyZWF0ZWRcIlxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBEZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXM7IiwibW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgZ2V0TGFuZ3VhZ2VzIDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgbGFuZ3VhZ2VzID0gW107XG4gICAgICAgIGZvcih2YXIgbGFuZyBpbiB0aGlzKVxuICAgICAgICB7XG4gICAgICAgICAgICBpZih0eXBlb2YgdGhpc1tsYW5nXSA9PT0gXCJzdHJpbmdcIilcbiAgICAgICAgICAgICAgICBsYW5ndWFnZXMucHVzaCh0aGlzW2xhbmddKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbGFuZ3VhZ2VzO1xuICAgIH0sXG4gICAgRU46IFwiZW5cIixcbiAgICBCRzogXCJiZ1wiLFxuICAgIERFOiBcImRlXCIsXG4gICAgVFI6IFwidHJcIlxufSIsInZhciBYTVBQRXZlbnRzID0ge1xuICAgIENPTkZFUkVOQ0VfQ0VSQVRFRDogXCJ4bXBwLmNvbmZlcmVuY2VDcmVhdGVkLmppbmdsZVwiLFxuICAgIENBTExfVEVSTUlOQVRFRDogXCJ4bXBwLmNhbGx0ZXJtaW5hdGVkLmppbmdsZVwiLFxuICAgIENBTExfSU5DT01JTkc6IFwieG1wcC5jYWxsaW5jb21pbmcuamluZ2xlXCIsXG4gICAgRElTUE9TRV9DT05GRVJFTkNFOiBcInhtcHAuZGlzcG9jZV9jb25mZXJuY2VcIixcbiAgICBHUkFDRUZVTF9TSFVURE9XTjogXCJ4bXBwLmdyYWNlZnVsX3NodXRkb3duXCIsXG4gICAgS0lDS0VEOiBcInhtcHAua2lja2VkXCIsXG4gICAgQlJJREdFX0RPV046IFwieG1wcC5icmlkZ2VfZG93blwiLFxuICAgIFVTRVJfSURfQ0hBTkdFRDogXCJ4bXBwLnVzZXJfaWRfY2hhbmdlZFwiLFxuICAgIENIQU5HRURfU1RSRUFNUzogXCJ4bXBwLmNoYW5nZWRfc3RyZWFtc1wiLFxuICAgIE1VQ19KT0lORUQ6IFwieG1wcC5tdWNfam9pbmVkXCIsXG4gICAgTVVDX0VOVEVSOiBcInhtcHAubXVjX2VudGVyXCIsXG4gICAgTVVDX1JPTEVfQ0hBTkdFRDogXCJ4bXBwLm11Y19yb2xlX2NoYW5nZWRcIixcbiAgICBNVUNfTEVGVDogXCJ4bXBwLm11Y19sZWZ0XCIsXG4gICAgTVVDX0RFU1RST1lFRDogXCJ4bXBwLm11Y19kZXN0cm95ZWRcIixcbiAgICBESVNQTEFZX05BTUVfQ0hBTkdFRDogXCJ4bXBwLmRpc3BsYXlfbmFtZV9jaGFuZ2VkXCIsXG4gICAgUkVNT1RFX1NUQVRTOiBcInhtcHAucmVtb3RlX3N0YXRzXCIsXG4gICAgTE9DQUxST0xFX0NIQU5HRUQ6IFwieG1wcC5sb2NhbHJvbGVfY2hhbmdlZFwiLFxuICAgIFBSRVNFTkNFX1NUQVRVUzogXCJ4bXBwLnByZXNlbmNlX3N0YXR1c1wiLFxuICAgIFJFU0VSVkFUSU9OX0VSUk9SOiBcInhtcHAucm9vbV9yZXNlcnZhdGlvbl9lcnJvclwiLFxuICAgIFNVQkpFQ1RfQ0hBTkdFRDogXCJ4bXBwLnN1YmplY3RfY2hhbmdlZFwiLFxuICAgIE1FU1NBR0VfUkVDRUlWRUQ6IFwieG1wcC5tZXNzYWdlX3JlY2VpdmVkXCIsXG4gICAgU0VORElOR19DSEFUX01FU1NBR0U6IFwieG1wcC5zZW5kaW5nX2NoYXRfbWVzc2FnZVwiLFxuICAgIFBBU1NXT1JEX1JFUVVJUkVEOiBcInhtcHAucGFzc3dvcmRfcmVxdWlyZWRcIixcbiAgICBBVVRIRU5USUNBVElPTl9SRVFVSVJFRDogXCJ4bXBwLmF1dGhlbnRpY2F0aW9uX3JlcXVpcmVkXCIsXG4gICAgQ0hBVF9FUlJPUl9SRUNFSVZFRDogXCJ4bXBwLmNoYXRfZXJyb3JfcmVjZWl2ZWRcIixcbiAgICBFVEhFUlBBRDogXCJ4bXBwLmV0aGVycGFkXCIsXG4gICAgREVWSUNFX0FWQUlMQUJMRTogXCJ4bXBwLmRldmljZV9hdmFpbGFibGVcIlxufTtcbm1vZHVsZS5leHBvcnRzID0gWE1QUEV2ZW50czsiLCIvLyBDb3B5cmlnaHQgSm95ZW50LCBJbmMuIGFuZCBvdGhlciBOb2RlIGNvbnRyaWJ1dG9ycy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYVxuLy8gY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZVxuLy8gXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nXG4vLyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsXG4vLyBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0XG4vLyBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGVcbi8vIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkXG4vLyBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTXG4vLyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GXG4vLyBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOXG4vLyBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSxcbi8vIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUlxuLy8gT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRVxuLy8gVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cblxuZnVuY3Rpb24gRXZlbnRFbWl0dGVyKCkge1xuICB0aGlzLl9ldmVudHMgPSB0aGlzLl9ldmVudHMgfHwge307XG4gIHRoaXMuX21heExpc3RlbmVycyA9IHRoaXMuX21heExpc3RlbmVycyB8fCB1bmRlZmluZWQ7XG59XG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50RW1pdHRlcjtcblxuLy8gQmFja3dhcmRzLWNvbXBhdCB3aXRoIG5vZGUgMC4xMC54XG5FdmVudEVtaXR0ZXIuRXZlbnRFbWl0dGVyID0gRXZlbnRFbWl0dGVyO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLl9ldmVudHMgPSB1bmRlZmluZWQ7XG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLl9tYXhMaXN0ZW5lcnMgPSB1bmRlZmluZWQ7XG5cbi8vIEJ5IGRlZmF1bHQgRXZlbnRFbWl0dGVycyB3aWxsIHByaW50IGEgd2FybmluZyBpZiBtb3JlIHRoYW4gMTAgbGlzdGVuZXJzIGFyZVxuLy8gYWRkZWQgdG8gaXQuIFRoaXMgaXMgYSB1c2VmdWwgZGVmYXVsdCB3aGljaCBoZWxwcyBmaW5kaW5nIG1lbW9yeSBsZWFrcy5cbkV2ZW50RW1pdHRlci5kZWZhdWx0TWF4TGlzdGVuZXJzID0gMTA7XG5cbi8vIE9idmlvdXNseSBub3QgYWxsIEVtaXR0ZXJzIHNob3VsZCBiZSBsaW1pdGVkIHRvIDEwLiBUaGlzIGZ1bmN0aW9uIGFsbG93c1xuLy8gdGhhdCB0byBiZSBpbmNyZWFzZWQuIFNldCB0byB6ZXJvIGZvciB1bmxpbWl0ZWQuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnNldE1heExpc3RlbmVycyA9IGZ1bmN0aW9uKG4pIHtcbiAgaWYgKCFpc051bWJlcihuKSB8fCBuIDwgMCB8fCBpc05hTihuKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ24gbXVzdCBiZSBhIHBvc2l0aXZlIG51bWJlcicpO1xuICB0aGlzLl9tYXhMaXN0ZW5lcnMgPSBuO1xuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZW1pdCA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgdmFyIGVyLCBoYW5kbGVyLCBsZW4sIGFyZ3MsIGksIGxpc3RlbmVycztcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcblxuICAvLyBJZiB0aGVyZSBpcyBubyAnZXJyb3InIGV2ZW50IGxpc3RlbmVyIHRoZW4gdGhyb3cuXG4gIGlmICh0eXBlID09PSAnZXJyb3InKSB7XG4gICAgaWYgKCF0aGlzLl9ldmVudHMuZXJyb3IgfHxcbiAgICAgICAgKGlzT2JqZWN0KHRoaXMuX2V2ZW50cy5lcnJvcikgJiYgIXRoaXMuX2V2ZW50cy5lcnJvci5sZW5ndGgpKSB7XG4gICAgICBlciA9IGFyZ3VtZW50c1sxXTtcbiAgICAgIGlmIChlciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgIHRocm93IGVyOyAvLyBVbmhhbmRsZWQgJ2Vycm9yJyBldmVudFxuICAgICAgfVxuICAgICAgdGhyb3cgVHlwZUVycm9yKCdVbmNhdWdodCwgdW5zcGVjaWZpZWQgXCJlcnJvclwiIGV2ZW50LicpO1xuICAgIH1cbiAgfVxuXG4gIGhhbmRsZXIgPSB0aGlzLl9ldmVudHNbdHlwZV07XG5cbiAgaWYgKGlzVW5kZWZpbmVkKGhhbmRsZXIpKVxuICAgIHJldHVybiBmYWxzZTtcblxuICBpZiAoaXNGdW5jdGlvbihoYW5kbGVyKSkge1xuICAgIHN3aXRjaCAoYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgLy8gZmFzdCBjYXNlc1xuICAgICAgY2FzZSAxOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcywgYXJndW1lbnRzWzFdKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDM6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzLCBhcmd1bWVudHNbMV0sIGFyZ3VtZW50c1syXSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgLy8gc2xvd2VyXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBsZW4gPSBhcmd1bWVudHMubGVuZ3RoO1xuICAgICAgICBhcmdzID0gbmV3IEFycmF5KGxlbiAtIDEpO1xuICAgICAgICBmb3IgKGkgPSAxOyBpIDwgbGVuOyBpKyspXG4gICAgICAgICAgYXJnc1tpIC0gMV0gPSBhcmd1bWVudHNbaV07XG4gICAgICAgIGhhbmRsZXIuYXBwbHkodGhpcywgYXJncyk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGlzT2JqZWN0KGhhbmRsZXIpKSB7XG4gICAgbGVuID0gYXJndW1lbnRzLmxlbmd0aDtcbiAgICBhcmdzID0gbmV3IEFycmF5KGxlbiAtIDEpO1xuICAgIGZvciAoaSA9IDE7IGkgPCBsZW47IGkrKylcbiAgICAgIGFyZ3NbaSAtIDFdID0gYXJndW1lbnRzW2ldO1xuXG4gICAgbGlzdGVuZXJzID0gaGFuZGxlci5zbGljZSgpO1xuICAgIGxlbiA9IGxpc3RlbmVycy5sZW5ndGg7XG4gICAgZm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKVxuICAgICAgbGlzdGVuZXJzW2ldLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICB9XG5cbiAgcmV0dXJuIHRydWU7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgdmFyIG07XG5cbiAgaWYgKCFpc0Z1bmN0aW9uKGxpc3RlbmVyKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ2xpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzKVxuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuXG4gIC8vIFRvIGF2b2lkIHJlY3Vyc2lvbiBpbiB0aGUgY2FzZSB0aGF0IHR5cGUgPT09IFwibmV3TGlzdGVuZXJcIiEgQmVmb3JlXG4gIC8vIGFkZGluZyBpdCB0byB0aGUgbGlzdGVuZXJzLCBmaXJzdCBlbWl0IFwibmV3TGlzdGVuZXJcIi5cbiAgaWYgKHRoaXMuX2V2ZW50cy5uZXdMaXN0ZW5lcilcbiAgICB0aGlzLmVtaXQoJ25ld0xpc3RlbmVyJywgdHlwZSxcbiAgICAgICAgICAgICAgaXNGdW5jdGlvbihsaXN0ZW5lci5saXN0ZW5lcikgP1xuICAgICAgICAgICAgICBsaXN0ZW5lci5saXN0ZW5lciA6IGxpc3RlbmVyKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50c1t0eXBlXSlcbiAgICAvLyBPcHRpbWl6ZSB0aGUgY2FzZSBvZiBvbmUgbGlzdGVuZXIuIERvbid0IG5lZWQgdGhlIGV4dHJhIGFycmF5IG9iamVjdC5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0gPSBsaXN0ZW5lcjtcbiAgZWxzZSBpZiAoaXNPYmplY3QodGhpcy5fZXZlbnRzW3R5cGVdKSlcbiAgICAvLyBJZiB3ZSd2ZSBhbHJlYWR5IGdvdCBhbiBhcnJheSwganVzdCBhcHBlbmQuXG4gICAgdGhpcy5fZXZlbnRzW3R5cGVdLnB1c2gobGlzdGVuZXIpO1xuICBlbHNlXG4gICAgLy8gQWRkaW5nIHRoZSBzZWNvbmQgZWxlbWVudCwgbmVlZCB0byBjaGFuZ2UgdG8gYXJyYXkuXG4gICAgdGhpcy5fZXZlbnRzW3R5cGVdID0gW3RoaXMuX2V2ZW50c1t0eXBlXSwgbGlzdGVuZXJdO1xuXG4gIC8vIENoZWNrIGZvciBsaXN0ZW5lciBsZWFrXG4gIGlmIChpc09iamVjdCh0aGlzLl9ldmVudHNbdHlwZV0pICYmICF0aGlzLl9ldmVudHNbdHlwZV0ud2FybmVkKSB7XG4gICAgdmFyIG07XG4gICAgaWYgKCFpc1VuZGVmaW5lZCh0aGlzLl9tYXhMaXN0ZW5lcnMpKSB7XG4gICAgICBtID0gdGhpcy5fbWF4TGlzdGVuZXJzO1xuICAgIH0gZWxzZSB7XG4gICAgICBtID0gRXZlbnRFbWl0dGVyLmRlZmF1bHRNYXhMaXN0ZW5lcnM7XG4gICAgfVxuXG4gICAgaWYgKG0gJiYgbSA+IDAgJiYgdGhpcy5fZXZlbnRzW3R5cGVdLmxlbmd0aCA+IG0pIHtcbiAgICAgIHRoaXMuX2V2ZW50c1t0eXBlXS53YXJuZWQgPSB0cnVlO1xuICAgICAgY29uc29sZS5lcnJvcignKG5vZGUpIHdhcm5pbmc6IHBvc3NpYmxlIEV2ZW50RW1pdHRlciBtZW1vcnkgJyArXG4gICAgICAgICAgICAgICAgICAgICdsZWFrIGRldGVjdGVkLiAlZCBsaXN0ZW5lcnMgYWRkZWQuICcgK1xuICAgICAgICAgICAgICAgICAgICAnVXNlIGVtaXR0ZXIuc2V0TWF4TGlzdGVuZXJzKCkgdG8gaW5jcmVhc2UgbGltaXQuJyxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fZXZlbnRzW3R5cGVdLmxlbmd0aCk7XG4gICAgICBpZiAodHlwZW9mIGNvbnNvbGUudHJhY2UgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgLy8gbm90IHN1cHBvcnRlZCBpbiBJRSAxMFxuICAgICAgICBjb25zb2xlLnRyYWNlKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uID0gRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5hZGRMaXN0ZW5lcjtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbmNlID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgaWYgKCFpc0Z1bmN0aW9uKGxpc3RlbmVyKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ2xpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuXG4gIHZhciBmaXJlZCA9IGZhbHNlO1xuXG4gIGZ1bmN0aW9uIGcoKSB7XG4gICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBnKTtcblxuICAgIGlmICghZmlyZWQpIHtcbiAgICAgIGZpcmVkID0gdHJ1ZTtcbiAgICAgIGxpc3RlbmVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgfVxuICB9XG5cbiAgZy5saXN0ZW5lciA9IGxpc3RlbmVyO1xuICB0aGlzLm9uKHR5cGUsIGcpO1xuXG4gIHJldHVybiB0aGlzO1xufTtcblxuLy8gZW1pdHMgYSAncmVtb3ZlTGlzdGVuZXInIGV2ZW50IGlmZiB0aGUgbGlzdGVuZXIgd2FzIHJlbW92ZWRcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlTGlzdGVuZXIgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICB2YXIgbGlzdCwgcG9zaXRpb24sIGxlbmd0aCwgaTtcblxuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMgfHwgIXRoaXMuX2V2ZW50c1t0eXBlXSlcbiAgICByZXR1cm4gdGhpcztcblxuICBsaXN0ID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuICBsZW5ndGggPSBsaXN0Lmxlbmd0aDtcbiAgcG9zaXRpb24gPSAtMTtcblxuICBpZiAobGlzdCA9PT0gbGlzdGVuZXIgfHxcbiAgICAgIChpc0Z1bmN0aW9uKGxpc3QubGlzdGVuZXIpICYmIGxpc3QubGlzdGVuZXIgPT09IGxpc3RlbmVyKSkge1xuICAgIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG4gICAgaWYgKHRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcilcbiAgICAgIHRoaXMuZW1pdCgncmVtb3ZlTGlzdGVuZXInLCB0eXBlLCBsaXN0ZW5lcik7XG5cbiAgfSBlbHNlIGlmIChpc09iamVjdChsaXN0KSkge1xuICAgIGZvciAoaSA9IGxlbmd0aDsgaS0tID4gMDspIHtcbiAgICAgIGlmIChsaXN0W2ldID09PSBsaXN0ZW5lciB8fFxuICAgICAgICAgIChsaXN0W2ldLmxpc3RlbmVyICYmIGxpc3RbaV0ubGlzdGVuZXIgPT09IGxpc3RlbmVyKSkge1xuICAgICAgICBwb3NpdGlvbiA9IGk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChwb3NpdGlvbiA8IDApXG4gICAgICByZXR1cm4gdGhpcztcblxuICAgIGlmIChsaXN0Lmxlbmd0aCA9PT0gMSkge1xuICAgICAgbGlzdC5sZW5ndGggPSAwO1xuICAgICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICB9IGVsc2Uge1xuICAgICAgbGlzdC5zcGxpY2UocG9zaXRpb24sIDEpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9ldmVudHMucmVtb3ZlTGlzdGVuZXIpXG4gICAgICB0aGlzLmVtaXQoJ3JlbW92ZUxpc3RlbmVyJywgdHlwZSwgbGlzdGVuZXIpO1xuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUFsbExpc3RlbmVycyA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgdmFyIGtleSwgbGlzdGVuZXJzO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzKVxuICAgIHJldHVybiB0aGlzO1xuXG4gIC8vIG5vdCBsaXN0ZW5pbmcgZm9yIHJlbW92ZUxpc3RlbmVyLCBubyBuZWVkIHRvIGVtaXRcbiAgaWYgKCF0aGlzLl9ldmVudHMucmVtb3ZlTGlzdGVuZXIpIHtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMClcbiAgICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuICAgIGVsc2UgaWYgKHRoaXMuX2V2ZW50c1t0eXBlXSlcbiAgICAgIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBlbWl0IHJlbW92ZUxpc3RlbmVyIGZvciBhbGwgbGlzdGVuZXJzIG9uIGFsbCBldmVudHNcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICBmb3IgKGtleSBpbiB0aGlzLl9ldmVudHMpIHtcbiAgICAgIGlmIChrZXkgPT09ICdyZW1vdmVMaXN0ZW5lcicpIGNvbnRpbnVlO1xuICAgICAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoa2V5KTtcbiAgICB9XG4gICAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoJ3JlbW92ZUxpc3RlbmVyJyk7XG4gICAgdGhpcy5fZXZlbnRzID0ge307XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbdHlwZV07XG5cbiAgaWYgKGlzRnVuY3Rpb24obGlzdGVuZXJzKSkge1xuICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgbGlzdGVuZXJzKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBMSUZPIG9yZGVyXG4gICAgd2hpbGUgKGxpc3RlbmVycy5sZW5ndGgpXG4gICAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVyc1tsaXN0ZW5lcnMubGVuZ3RoIC0gMV0pO1xuICB9XG4gIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmxpc3RlbmVycyA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgdmFyIHJldDtcbiAgaWYgKCF0aGlzLl9ldmVudHMgfHwgIXRoaXMuX2V2ZW50c1t0eXBlXSlcbiAgICByZXQgPSBbXTtcbiAgZWxzZSBpZiAoaXNGdW5jdGlvbih0aGlzLl9ldmVudHNbdHlwZV0pKVxuICAgIHJldCA9IFt0aGlzLl9ldmVudHNbdHlwZV1dO1xuICBlbHNlXG4gICAgcmV0ID0gdGhpcy5fZXZlbnRzW3R5cGVdLnNsaWNlKCk7XG4gIHJldHVybiByZXQ7XG59O1xuXG5FdmVudEVtaXR0ZXIubGlzdGVuZXJDb3VudCA9IGZ1bmN0aW9uKGVtaXR0ZXIsIHR5cGUpIHtcbiAgdmFyIHJldDtcbiAgaWYgKCFlbWl0dGVyLl9ldmVudHMgfHwgIWVtaXR0ZXIuX2V2ZW50c1t0eXBlXSlcbiAgICByZXQgPSAwO1xuICBlbHNlIGlmIChpc0Z1bmN0aW9uKGVtaXR0ZXIuX2V2ZW50c1t0eXBlXSkpXG4gICAgcmV0ID0gMTtcbiAgZWxzZVxuICAgIHJldCA9IGVtaXR0ZXIuX2V2ZW50c1t0eXBlXS5sZW5ndGg7XG4gIHJldHVybiByZXQ7XG59O1xuXG5mdW5jdGlvbiBpc0Z1bmN0aW9uKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuZnVuY3Rpb24gaXNOdW1iZXIoYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnbnVtYmVyJztcbn1cblxuZnVuY3Rpb24gaXNPYmplY3QoYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnb2JqZWN0JyAmJiBhcmcgIT09IG51bGw7XG59XG5cbmZ1bmN0aW9uIGlzVW5kZWZpbmVkKGFyZykge1xuICByZXR1cm4gYXJnID09PSB2b2lkIDA7XG59XG4iXX0=