您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

UI.bundle.js 542KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397
  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.UI=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. var UI = {};
  3. var VideoLayout = require("./videolayout/VideoLayout.js");
  4. var AudioLevels = require("./audio_levels/AudioLevels.js");
  5. var Prezi = require("./prezi/Prezi.js");
  6. var Etherpad = require("./etherpad/Etherpad.js");
  7. var Chat = require("./side_pannels/chat/Chat.js");
  8. var Toolbar = require("./toolbars/toolbar");
  9. var ToolbarToggler = require("./toolbars/toolbartoggler");
  10. var BottomToolbar = require("./toolbars/BottomToolbar");
  11. var ContactList = require("./side_pannels/contactlist/ContactList");
  12. var Avatar = require("./avatar/Avatar");
  13. //var EventEmitter = require("events");
  14. var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
  15. var Settings = require("./side_pannels/settings/Settings");
  16. var PanelToggler = require("./side_pannels/SidePanelToggler");
  17. var RoomNameGenerator = require("./welcome_page/RoomnameGenerator");
  18. UI.messageHandler = require("./util/MessageHandler");
  19. var messageHandler = UI.messageHandler;
  20. //var eventEmitter = new EventEmitter();
  21. function setupPrezi()
  22. {
  23. $("#reloadPresentationLink").click(function()
  24. {
  25. Prezi.reloadPresentation();
  26. });
  27. }
  28. function setupChat()
  29. {
  30. Chat.init();
  31. $("#toggle_smileys").click(function() {
  32. Chat.toggleSmileys();
  33. });
  34. }
  35. function setupToolbars() {
  36. Toolbar.init();
  37. Toolbar.setupButtonsFromConfig();
  38. BottomToolbar.init();
  39. }
  40. function registerListeners() {
  41. RTC.addStreamListener(function (stream) {
  42. switch (stream.type)
  43. {
  44. case "audio":
  45. VideoLayout.changeLocalAudio(stream.getOriginalStream());
  46. break;
  47. case "video":
  48. VideoLayout.changeLocalVideo(stream.getOriginalStream(), true);
  49. break;
  50. case "stream":
  51. VideoLayout.changeLocalStream(stream.getOriginalStream());
  52. break;
  53. case "desktop":
  54. VideoLayout.changeLocalVideo(stream, !isUsingScreenStream);
  55. break;
  56. }
  57. }, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  58. RTC.addStreamListener(function (stream) {
  59. VideoLayout.onRemoteStreamAdded(stream);
  60. }, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED);
  61. // Listen for large video size updates
  62. document.getElementById('largeVideo')
  63. .addEventListener('loadedmetadata', function (e) {
  64. currentVideoWidth = this.videoWidth;
  65. currentVideoHeight = this.videoHeight;
  66. VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
  67. });
  68. statistics.addAudioLevelListener(function(jid, audioLevel)
  69. {
  70. var resourceJid;
  71. if(jid === statistics.LOCAL_JID)
  72. {
  73. resourceJid = AudioLevels.LOCAL_LEVEL;
  74. if(isAudioMuted())
  75. {
  76. audioLevel = 0;
  77. }
  78. }
  79. else
  80. {
  81. resourceJid = Strophe.getResourceFromJid(jid);
  82. }
  83. AudioLevels.updateAudioLevel(resourceJid, audioLevel,
  84. UI.getLargeVideoState().userResourceJid);
  85. });
  86. }
  87. function bindEvents()
  88. {
  89. /**
  90. * Resizes and repositions videos in full screen mode.
  91. */
  92. $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
  93. function () {
  94. VideoLayout.resizeLargeVideoContainer();
  95. VideoLayout.positionLarge();
  96. isFullScreen = document.fullScreen ||
  97. document.mozFullScreen ||
  98. document.webkitIsFullScreen;
  99. }
  100. );
  101. $(window).resize(function () {
  102. VideoLayout.resizeLargeVideoContainer();
  103. VideoLayout.positionLarge();
  104. });
  105. }
  106. UI.start = function () {
  107. document.title = interfaceConfig.APP_NAME;
  108. if(config.enableWelcomePage && window.location.pathname == "/" &&
  109. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  110. {
  111. $("#videoconference_page").hide();
  112. var setupWelcomePage = require("./welcome_page/WelcomePage");
  113. setupWelcomePage();
  114. return;
  115. }
  116. if (interfaceConfig.SHOW_JITSI_WATERMARK) {
  117. var leftWatermarkDiv
  118. = $("#largeVideoContainer div[class='watermark leftwatermark']");
  119. leftWatermarkDiv.css({display: 'block'});
  120. leftWatermarkDiv.parent().get(0).href
  121. = interfaceConfig.JITSI_WATERMARK_LINK;
  122. }
  123. if (interfaceConfig.SHOW_BRAND_WATERMARK) {
  124. var rightWatermarkDiv
  125. = $("#largeVideoContainer div[class='watermark rightwatermark']");
  126. rightWatermarkDiv.css({display: 'block'});
  127. rightWatermarkDiv.parent().get(0).href
  128. = interfaceConfig.BRAND_WATERMARK_LINK;
  129. rightWatermarkDiv.get(0).style.backgroundImage
  130. = "url(images/rightwatermark.png)";
  131. }
  132. if (interfaceConfig.SHOW_POWERED_BY) {
  133. $("#largeVideoContainer>a[class='poweredby']").css({display: 'block'});
  134. }
  135. $("#welcome_page").hide();
  136. $('body').popover({ selector: '[data-toggle=popover]',
  137. trigger: 'click hover',
  138. content: function() {
  139. return this.getAttribute("content") +
  140. KeyboardShortcut.getShortcut(this.getAttribute("shortcut"));
  141. }
  142. });
  143. VideoLayout.resizeLargeVideoContainer();
  144. $("#videospace").mousemove(function () {
  145. return ToolbarToggler.showToolbar();
  146. });
  147. // Set the defaults for prompt dialogs.
  148. jQuery.prompt.setDefaults({persistent: false});
  149. // KeyboardShortcut.init();
  150. registerListeners();
  151. bindEvents();
  152. setupPrezi();
  153. setupToolbars();
  154. setupChat();
  155. document.title = interfaceConfig.APP_NAME;
  156. $("#downloadlog").click(function (event) {
  157. dump(event.target);
  158. });
  159. if(config.enableWelcomePage && window.location.pathname == "/" &&
  160. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  161. {
  162. $("#videoconference_page").hide();
  163. var setupWelcomePage = require("./welcome_page/WelcomePage");
  164. setupWelcomePage();
  165. return;
  166. }
  167. $("#welcome_page").hide();
  168. document.getElementById('largeVideo').volume = 0;
  169. if (!$('#settings').is(':visible')) {
  170. console.log('init');
  171. init();
  172. } else {
  173. loginInfo.onsubmit = function (e) {
  174. if (e.preventDefault) e.preventDefault();
  175. $('#settings').hide();
  176. init();
  177. };
  178. }
  179. toastr.options = {
  180. "closeButton": true,
  181. "debug": false,
  182. "positionClass": "notification-bottom-right",
  183. "onclick": null,
  184. "showDuration": "300",
  185. "hideDuration": "1000",
  186. "timeOut": "2000",
  187. "extendedTimeOut": "1000",
  188. "showEasing": "swing",
  189. "hideEasing": "linear",
  190. "showMethod": "fadeIn",
  191. "hideMethod": "fadeOut",
  192. "reposition": function() {
  193. if(PanelToggler.isVisible()) {
  194. $("#toast-container").addClass("notification-bottom-right-center");
  195. } else {
  196. $("#toast-container").removeClass("notification-bottom-right-center");
  197. }
  198. },
  199. "newestOnTop": false
  200. };
  201. $('#settingsmenu>input').keyup(function(event){
  202. if(event.keyCode === 13) {//enter
  203. SettingsMenu.update();
  204. }
  205. });
  206. $("#updateSettings").click(function () {
  207. SettingsMenu.update();
  208. });
  209. };
  210. UI.setUserAvatar = function (jid, id) {
  211. Avatar.setUserAvatar(jid, id);
  212. };
  213. UI.toggleSmileys = function () {
  214. Chat.toggleSmileys();
  215. };
  216. UI.chatAddError = function(errorMessage, originalText)
  217. {
  218. return Chat.chatAddError(errorMessage, originalText);
  219. };
  220. UI.chatSetSubject = function(text)
  221. {
  222. return Chat.chatSetSubject(text);
  223. };
  224. UI.updateChatConversation = function (from, displayName, message) {
  225. return Chat.updateChatConversation(from, displayName, message);
  226. };
  227. UI.onMucJoined = function (jid, info) {
  228. Toolbar.updateRoomUrl(window.location.href);
  229. document.getElementById('localNick').appendChild(
  230. document.createTextNode(Strophe.getResourceFromJid(jid) + ' (me)')
  231. );
  232. var settings = Settings.getSettings();
  233. // Add myself to the contact list.
  234. ContactList.addContact(jid, settings.email || settings.uid);
  235. // Once we've joined the muc show the toolbar
  236. ToolbarToggler.showToolbar();
  237. // Show authenticate button if needed
  238. Toolbar.showAuthenticateButton(
  239. Moderator.isExternalAuthEnabled() && !Moderator.isModerator());
  240. var displayName = !config.displayJids
  241. ? info.displayName : Strophe.getResourceFromJid(jid);
  242. if (displayName)
  243. $(document).trigger('displaynamechanged',
  244. ['localVideoContainer', displayName + ' (me)']);
  245. };
  246. UI.initEtherpad = function (name) {
  247. Etherpad.init(name);
  248. };
  249. UI.onMucLeft = function (jid) {
  250. console.log('left.muc', jid);
  251. var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
  252. '>.displayname').html();
  253. messageHandler.notify(displayName || 'Somebody',
  254. 'disconnected',
  255. 'disconnected');
  256. // Need to call this with a slight delay, otherwise the element couldn't be
  257. // found for some reason.
  258. // XXX(gp) it works fine without the timeout for me (with Chrome 38).
  259. window.setTimeout(function () {
  260. var container = document.getElementById(
  261. 'participant_' + Strophe.getResourceFromJid(jid));
  262. if (container) {
  263. ContactList.removeContact(jid);
  264. VideoLayout.removeConnectionIndicator(jid);
  265. // hide here, wait for video to close before removing
  266. $(container).hide();
  267. VideoLayout.resizeThumbnails();
  268. }
  269. }, 10);
  270. // Unlock large video
  271. if (focusedVideoInfo && focusedVideoInfo.jid === jid)
  272. {
  273. console.info("Focused video owner has left the conference");
  274. focusedVideoInfo = null;
  275. }
  276. };
  277. UI.getSettings = function () {
  278. return Settings.getSettings();
  279. };
  280. UI.toggleFilmStrip = function () {
  281. return BottomToolbar.toggleFilmStrip();
  282. };
  283. UI.toggleChat = function () {
  284. return BottomToolbar.toggleChat();
  285. };
  286. UI.toggleContactList = function () {
  287. return BottomToolbar.toggleContactList();
  288. };
  289. UI.onLocalRoleChange = function (jid, info, pres) {
  290. console.info("My role changed, new role: " + info.role);
  291. var isModerator = Moderator.isModerator();
  292. VideoLayout.showModeratorIndicator();
  293. Toolbar.showAuthenticateButton(
  294. Moderator.isExternalAuthEnabled() && !isModerator);
  295. if (isModerator) {
  296. Toolbar.closeAuthenticationWindow();
  297. messageHandler.notify(
  298. 'Me', 'connected', 'Moderator rights granted !');
  299. }
  300. };
  301. UI.onDisposeConference = function (unload) {
  302. Toolbar.showAuthenticateButton(false);
  303. };
  304. UI.onModeratorStatusChanged = function (isModerator) {
  305. Toolbar.showSipCallButton(isModerator);
  306. Toolbar.showRecordingButton(
  307. isModerator); //&&
  308. // FIXME:
  309. // Recording visible if
  310. // there are at least 2(+ 1 focus) participants
  311. //Object.keys(connection.emuc.members).length >= 3);
  312. if (isModerator && config.etherpad_base) {
  313. Etherpad.init();
  314. }
  315. };
  316. UI.onPasswordReqiured = function (callback) {
  317. // password is required
  318. Toolbar.lockLockButton();
  319. messageHandler.openTwoButtonDialog(null,
  320. '<h2>Password required</h2>' +
  321. '<input id="lockKey" type="text" placeholder="password" autofocus>',
  322. true,
  323. "Ok",
  324. function (e, v, m, f) {},
  325. function (event) {
  326. document.getElementById('lockKey').focus();
  327. },
  328. function (e, v, m, f) {
  329. if (v) {
  330. var lockKey = document.getElementById('lockKey');
  331. if (lockKey.value !== null) {
  332. Toolbar.setSharedKey(lockKey.value);
  333. callback(lockKey.value);
  334. }
  335. }
  336. }
  337. );
  338. };
  339. UI.onAuthenticationRequired = function () {
  340. // extract room name from 'room@muc.server.net'
  341. var room = roomName.substr(0, roomName.indexOf('@'));
  342. messageHandler.openDialog(
  343. 'Stop',
  344. 'Authentication is required to create room:<br/>' + room,
  345. true,
  346. {
  347. Authenticate: 'authNow',
  348. Close: 'close'
  349. },
  350. function (onSubmitEvent, submitValue) {
  351. console.info('On submit: ' + submitValue, submitValue);
  352. if (submitValue === 'authNow') {
  353. Toolbar.authenticateClicked();
  354. } else {
  355. Toolbar.showAuthenticateButton(true);
  356. }
  357. }
  358. );
  359. };
  360. UI.setRecordingButtonState = function (state) {
  361. Toolbar.setRecordingButtonState(state);
  362. };
  363. UI.changeDesktopSharingButtonState = function (isUsingScreenStream) {
  364. Toolbar.changeDesktopSharingButtonState(isUsingScreenStream);
  365. };
  366. UI.inputDisplayNameHandler = function (value) {
  367. VideoLayout.inputDisplayNameHandler(value);
  368. };
  369. UI.onMucEntered = function (jid, id, displayName) {
  370. messageHandler.notify(displayName || 'Somebody',
  371. 'connected',
  372. 'connected');
  373. // Add Peer's container
  374. VideoLayout.ensurePeerContainerExists(jid,id);
  375. if(APIConnector.isEnabled() &&
  376. APIConnector.isEventEnabled("participantJoined"))
  377. {
  378. APIConnector.triggerEvent("participantJoined",{jid: jid});
  379. }
  380. };
  381. UI.onMucPresenceStatus = function ( jid, info) {
  382. VideoLayout.setPresenceStatus(
  383. 'participant_' + Strophe.getResourceFromJid(jid), info.status);
  384. };
  385. UI.onMucRoleChanged = function (role, displayName) {
  386. VideoLayout.showModeratorIndicator();
  387. if (role === 'moderator') {
  388. var displayName = displayName;
  389. if (!displayName) {
  390. displayName = 'Somebody';
  391. }
  392. messageHandler.notify(
  393. displayName,
  394. 'connected',
  395. 'Moderator rights granted to ' + displayName + '!');
  396. }
  397. };
  398. UI.updateLocalConnectionStats = function(percent, stats)
  399. {
  400. VideoLayout.updateLocalConnectionStats(percent, stats);
  401. };
  402. UI.updateConnectionStats = function(jid, percent, stats)
  403. {
  404. VideoLayout.updateConnectionStats(jid, percent, stats);
  405. };
  406. UI.onStatsStop = function () {
  407. VideoLayout.onStatsStop();
  408. };
  409. UI.getLargeVideoState = function()
  410. {
  411. return VideoLayout.getLargeVideoState();
  412. };
  413. UI.showLocalAudioIndicator = function (mute) {
  414. VideoLayout.showLocalAudioIndicator(mute);
  415. };
  416. UI.changeLocalVideo = function (stream, flipx) {
  417. VideoLayout.changeLocalVideo(stream, flipx);
  418. };
  419. UI.generateRoomName = function() {
  420. var roomnode = null;
  421. var path = window.location.pathname;
  422. // determinde the room node from the url
  423. // TODO: just the roomnode or the whole bare jid?
  424. if (config.getroomnode && typeof config.getroomnode === 'function') {
  425. // custom function might be responsible for doing the pushstate
  426. roomnode = config.getroomnode(path);
  427. } else {
  428. /* fall back to default strategy
  429. * this is making assumptions about how the URL->room mapping happens.
  430. * It currently assumes deployment at root, with a rewrite like the
  431. * following one (for nginx):
  432. location ~ ^/([a-zA-Z0-9]+)$ {
  433. rewrite ^/(.*)$ / break;
  434. }
  435. */
  436. if (path.length > 1) {
  437. roomnode = path.substr(1).toLowerCase();
  438. } else {
  439. var word = RoomNameGenerator.generateRoomWithoutSeparator();
  440. roomnode = word.toLowerCase();
  441. window.history.pushState('VideoChat',
  442. 'Room: ' + word, window.location.pathname + word);
  443. }
  444. }
  445. roomName = roomnode + '@' + config.hosts.muc;
  446. };
  447. UI.connectionIndicatorShowMore = function(id)
  448. {
  449. return VideoLayout.connectionIndicators[id].showMore();
  450. }
  451. module.exports = UI;
  452. },{"./audio_levels/AudioLevels.js":2,"./avatar/Avatar":4,"./etherpad/Etherpad.js":5,"./prezi/Prezi.js":6,"./side_pannels/SidePanelToggler":7,"./side_pannels/chat/Chat.js":8,"./side_pannels/contactlist/ContactList":12,"./side_pannels/settings/Settings":13,"./side_pannels/settings/SettingsMenu":14,"./toolbars/BottomToolbar":15,"./toolbars/toolbar":17,"./toolbars/toolbartoggler":18,"./util/MessageHandler":20,"./videolayout/VideoLayout.js":23,"./welcome_page/RoomnameGenerator":24,"./welcome_page/WelcomePage":25}],2:[function(require,module,exports){
  453. var CanvasUtil = require("./CanvasUtils");
  454. /**
  455. * The audio Levels plugin.
  456. */
  457. var AudioLevels = (function(my) {
  458. var audioLevelCanvasCache = {};
  459. my.LOCAL_LEVEL = 'local';
  460. /**
  461. * Updates the audio level canvas for the given peerJid. If the canvas
  462. * didn't exist we create it.
  463. */
  464. my.updateAudioLevelCanvas = function (peerJid, VideoLayout) {
  465. var resourceJid = null;
  466. var videoSpanId = null;
  467. if (!peerJid)
  468. videoSpanId = 'localVideoContainer';
  469. else {
  470. resourceJid = Strophe.getResourceFromJid(peerJid);
  471. videoSpanId = 'participant_' + resourceJid;
  472. }
  473. var videoSpan = document.getElementById(videoSpanId);
  474. if (!videoSpan) {
  475. if (resourceJid)
  476. console.error("No video element for jid", resourceJid);
  477. else
  478. console.error("No video element for local video.");
  479. return;
  480. }
  481. var audioLevelCanvas = $('#' + videoSpanId + '>canvas');
  482. var videoSpaceWidth = $('#remoteVideos').width();
  483. var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
  484. var thumbnailWidth = thumbnailSize[0];
  485. var thumbnailHeight = thumbnailSize[1];
  486. if (!audioLevelCanvas || audioLevelCanvas.length === 0) {
  487. audioLevelCanvas = document.createElement('canvas');
  488. audioLevelCanvas.className = "audiolevel";
  489. audioLevelCanvas.style.bottom = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
  490. audioLevelCanvas.style.left = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
  491. resizeAudioLevelCanvas( audioLevelCanvas,
  492. thumbnailWidth,
  493. thumbnailHeight);
  494. videoSpan.appendChild(audioLevelCanvas);
  495. } else {
  496. audioLevelCanvas = audioLevelCanvas.get(0);
  497. resizeAudioLevelCanvas( audioLevelCanvas,
  498. thumbnailWidth,
  499. thumbnailHeight);
  500. }
  501. };
  502. /**
  503. * Updates the audio level UI for the given resourceJid.
  504. *
  505. * @param resourceJid the resource jid indicating the video element for
  506. * which we draw the audio level
  507. * @param audioLevel the newAudio level to render
  508. */
  509. my.updateAudioLevel = function (resourceJid, audioLevel, largeVideoResourceJid) {
  510. drawAudioLevelCanvas(resourceJid, audioLevel);
  511. var videoSpanId = getVideoSpanId(resourceJid);
  512. var audioLevelCanvas = $('#' + videoSpanId + '>canvas').get(0);
  513. if (!audioLevelCanvas)
  514. return;
  515. var drawContext = audioLevelCanvas.getContext('2d');
  516. var canvasCache = audioLevelCanvasCache[resourceJid];
  517. drawContext.clearRect (0, 0,
  518. audioLevelCanvas.width, audioLevelCanvas.height);
  519. drawContext.drawImage(canvasCache, 0, 0);
  520. if(resourceJid === AudioLevels.LOCAL_LEVEL) {
  521. if(!connection.emuc.myroomjid) {
  522. return;
  523. }
  524. resourceJid = Strophe.getResourceFromJid(connection.emuc.myroomjid);
  525. }
  526. if(resourceJid === largeVideoResourceJid) {
  527. AudioLevels.updateActiveSpeakerAudioLevel(audioLevel);
  528. }
  529. };
  530. my.updateActiveSpeakerAudioLevel = function(audioLevel) {
  531. var drawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
  532. var r = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2;
  533. var center = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + r) / 2;
  534. // Save the previous state of the context.
  535. drawContext.save();
  536. drawContext.clearRect(0, 0, 300, 300);
  537. // Draw a circle.
  538. drawContext.arc(center, center, r, 0, 2 * Math.PI);
  539. // Add a shadow around the circle
  540. drawContext.shadowColor = interfaceConfig.SHADOW_COLOR;
  541. drawContext.shadowBlur = getShadowLevel(audioLevel);
  542. drawContext.shadowOffsetX = 0;
  543. drawContext.shadowOffsetY = 0;
  544. // Fill the shape.
  545. drawContext.fill();
  546. drawContext.save();
  547. drawContext.restore();
  548. drawContext.arc(center, center, r, 0, 2 * Math.PI);
  549. drawContext.clip();
  550. drawContext.clearRect(0, 0, 277, 200);
  551. // Restore the previous context state.
  552. drawContext.restore();
  553. };
  554. /**
  555. * Resizes the given audio level canvas to match the given thumbnail size.
  556. */
  557. function resizeAudioLevelCanvas(audioLevelCanvas,
  558. thumbnailWidth,
  559. thumbnailHeight) {
  560. audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
  561. audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
  562. }
  563. /**
  564. * Draws the audio level canvas into the cached canvas object.
  565. *
  566. * @param resourceJid the resource jid indicating the video element for
  567. * which we draw the audio level
  568. * @param audioLevel the newAudio level to render
  569. */
  570. function drawAudioLevelCanvas(resourceJid, audioLevel) {
  571. if (!audioLevelCanvasCache[resourceJid]) {
  572. var videoSpanId = getVideoSpanId(resourceJid);
  573. var audioLevelCanvasOrig = $('#' + videoSpanId + '>canvas').get(0);
  574. /*
  575. * FIXME Testing has shown that audioLevelCanvasOrig may not exist.
  576. * In such a case, the method CanvasUtil.cloneCanvas may throw an
  577. * error. Since audio levels are frequently updated, the errors have
  578. * been observed to pile into the console, strain the CPU.
  579. */
  580. if (audioLevelCanvasOrig)
  581. {
  582. audioLevelCanvasCache[resourceJid]
  583. = CanvasUtil.cloneCanvas(audioLevelCanvasOrig);
  584. }
  585. }
  586. var canvas = audioLevelCanvasCache[resourceJid];
  587. if (!canvas)
  588. return;
  589. var drawContext = canvas.getContext('2d');
  590. drawContext.clearRect(0, 0, canvas.width, canvas.height);
  591. var shadowLevel = getShadowLevel(audioLevel);
  592. if (shadowLevel > 0)
  593. // drawContext, x, y, w, h, r, shadowColor, shadowLevel
  594. CanvasUtil.drawRoundRectGlow( drawContext,
  595. interfaceConfig.CANVAS_EXTRA/2, interfaceConfig.CANVAS_EXTRA/2,
  596. canvas.width - interfaceConfig.CANVAS_EXTRA,
  597. canvas.height - interfaceConfig.CANVAS_EXTRA,
  598. interfaceConfig.CANVAS_RADIUS,
  599. interfaceConfig.SHADOW_COLOR,
  600. shadowLevel);
  601. }
  602. /**
  603. * Returns the shadow/glow level for the given audio level.
  604. *
  605. * @param audioLevel the audio level from which we determine the shadow
  606. * level
  607. */
  608. function getShadowLevel (audioLevel) {
  609. var shadowLevel = 0;
  610. if (audioLevel <= 0.3) {
  611. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*(audioLevel/0.3));
  612. }
  613. else if (audioLevel <= 0.6) {
  614. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3));
  615. }
  616. else {
  617. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4));
  618. }
  619. return shadowLevel;
  620. }
  621. /**
  622. * Returns the video span id corresponding to the given resourceJid or local
  623. * user.
  624. */
  625. function getVideoSpanId(resourceJid) {
  626. var videoSpanId = null;
  627. if (resourceJid === AudioLevels.LOCAL_LEVEL
  628. || (connection.emuc.myroomjid && resourceJid
  629. === Strophe.getResourceFromJid(connection.emuc.myroomjid)))
  630. videoSpanId = 'localVideoContainer';
  631. else
  632. videoSpanId = 'participant_' + resourceJid;
  633. return videoSpanId;
  634. }
  635. /**
  636. * Indicates that the remote video has been resized.
  637. */
  638. $(document).bind('remotevideo.resized', function (event, width, height) {
  639. var resized = false;
  640. $('#remoteVideos>span>canvas').each(function() {
  641. var canvas = $(this).get(0);
  642. if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) {
  643. canvas.width = width + interfaceConfig.CANVAS_EXTRA;
  644. resized = true;
  645. }
  646. if (canvas.heigh !== height + interfaceConfig.CANVAS_EXTRA) {
  647. canvas.height = height + interfaceConfig.CANVAS_EXTRA;
  648. resized = true;
  649. }
  650. });
  651. if (resized)
  652. Object.keys(audioLevelCanvasCache).forEach(function (resourceJid) {
  653. audioLevelCanvasCache[resourceJid].width
  654. = width + interfaceConfig.CANVAS_EXTRA;
  655. audioLevelCanvasCache[resourceJid].height
  656. = height + interfaceConfig.CANVAS_EXTRA;
  657. });
  658. });
  659. return my;
  660. })(AudioLevels || {});
  661. module.exports = AudioLevels;
  662. },{"./CanvasUtils":3}],3:[function(require,module,exports){
  663. /**
  664. * Utility class for drawing canvas shapes.
  665. */
  666. var CanvasUtil = (function(my) {
  667. /**
  668. * Draws a round rectangle with a glow. The glowWidth indicates the depth
  669. * of the glow.
  670. *
  671. * @param drawContext the context of the canvas to draw to
  672. * @param x the x coordinate of the round rectangle
  673. * @param y the y coordinate of the round rectangle
  674. * @param w the width of the round rectangle
  675. * @param h the height of the round rectangle
  676. * @param glowColor the color of the glow
  677. * @param glowWidth the width of the glow
  678. */
  679. my.drawRoundRectGlow
  680. = function(drawContext, x, y, w, h, r, glowColor, glowWidth) {
  681. // Save the previous state of the context.
  682. drawContext.save();
  683. if (w < 2 * r) r = w / 2;
  684. if (h < 2 * r) r = h / 2;
  685. // Draw a round rectangle.
  686. drawContext.beginPath();
  687. drawContext.moveTo(x+r, y);
  688. drawContext.arcTo(x+w, y, x+w, y+h, r);
  689. drawContext.arcTo(x+w, y+h, x, y+h, r);
  690. drawContext.arcTo(x, y+h, x, y, r);
  691. drawContext.arcTo(x, y, x+w, y, r);
  692. drawContext.closePath();
  693. // Add a shadow around the rectangle
  694. drawContext.shadowColor = glowColor;
  695. drawContext.shadowBlur = glowWidth;
  696. drawContext.shadowOffsetX = 0;
  697. drawContext.shadowOffsetY = 0;
  698. // Fill the shape.
  699. drawContext.fill();
  700. drawContext.save();
  701. drawContext.restore();
  702. // 1) Uncomment this line to use Composite Operation, which is doing the
  703. // same as the clip function below and is also antialiasing the round
  704. // border, but is said to be less fast performance wise.
  705. // drawContext.globalCompositeOperation='destination-out';
  706. drawContext.beginPath();
  707. drawContext.moveTo(x+r, y);
  708. drawContext.arcTo(x+w, y, x+w, y+h, r);
  709. drawContext.arcTo(x+w, y+h, x, y+h, r);
  710. drawContext.arcTo(x, y+h, x, y, r);
  711. drawContext.arcTo(x, y, x+w, y, r);
  712. drawContext.closePath();
  713. // 2) Uncomment this line to use Composite Operation, which is doing the
  714. // same as the clip function below and is also antialiasing the round
  715. // border, but is said to be less fast performance wise.
  716. // drawContext.fill();
  717. // Comment these two lines if choosing to do the same with composite
  718. // operation above 1 and 2.
  719. drawContext.clip();
  720. drawContext.clearRect(0, 0, 277, 200);
  721. // Restore the previous context state.
  722. drawContext.restore();
  723. };
  724. /**
  725. * Clones the given canvas.
  726. *
  727. * @return the new cloned canvas.
  728. */
  729. my.cloneCanvas = function (oldCanvas) {
  730. /*
  731. * FIXME Testing has shown that oldCanvas may not exist. In such a case,
  732. * the method CanvasUtil.cloneCanvas may throw an error. Since audio
  733. * levels are frequently updated, the errors have been observed to pile
  734. * into the console, strain the CPU.
  735. */
  736. if (!oldCanvas)
  737. return oldCanvas;
  738. //create a new canvas
  739. var newCanvas = document.createElement('canvas');
  740. var context = newCanvas.getContext('2d');
  741. //set dimensions
  742. newCanvas.width = oldCanvas.width;
  743. newCanvas.height = oldCanvas.height;
  744. //apply the old canvas to the new one
  745. context.drawImage(oldCanvas, 0, 0);
  746. //return the new canvas
  747. return newCanvas;
  748. };
  749. return my;
  750. })(CanvasUtil || {});
  751. module.exports = CanvasUtil;
  752. },{}],4:[function(require,module,exports){
  753. var Settings = require("../side_pannels/settings/Settings");
  754. var users = {};
  755. var activeSpeakerJid;
  756. function setVisibility(selector, show) {
  757. if (selector && selector.length > 0) {
  758. selector.css("visibility", show ? "visible" : "hidden");
  759. }
  760. }
  761. function isUserMuted(jid) {
  762. // XXX(gp) we may want to rename this method to something like
  763. // isUserStreaming, for example.
  764. if (jid && jid != connection.emuc.myroomjid) {
  765. var resource = Strophe.getResourceFromJid(jid);
  766. if (!require("../videolayout/VideoLayout").isInLastN(resource)) {
  767. return true;
  768. }
  769. }
  770. if (!RTC.remoteStreams[jid] || !RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
  771. return null;
  772. }
  773. return RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted;
  774. }
  775. function getGravatarUrl(id, size) {
  776. if(id === connection.emuc.myroomjid || !id) {
  777. id = Settings.getSettings().uid;
  778. }
  779. return 'https://www.gravatar.com/avatar/' +
  780. MD5.hexdigest(id.trim().toLowerCase()) +
  781. "?d=wavatar&size=" + (size || "30");
  782. }
  783. var Avatar = {
  784. /**
  785. * Sets the user's avatar in the settings menu(if local user), contact list
  786. * and thumbnail
  787. * @param jid jid of the user
  788. * @param id email or userID to be used as a hash
  789. */
  790. setUserAvatar: function (jid, id) {
  791. if (id) {
  792. if (users[jid] === id) {
  793. return;
  794. }
  795. users[jid] = id;
  796. }
  797. var thumbUrl = getGravatarUrl(users[jid] || jid, 100);
  798. var contactListUrl = getGravatarUrl(users[jid] || jid);
  799. var resourceJid = Strophe.getResourceFromJid(jid);
  800. var thumbnail = $('#participant_' + resourceJid);
  801. var avatar = $('#avatar_' + resourceJid);
  802. // set the avatar in the settings menu if it is local user and get the
  803. // local video container
  804. if (jid === connection.emuc.myroomjid) {
  805. $('#avatar').get(0).src = thumbUrl;
  806. thumbnail = $('#localVideoContainer');
  807. }
  808. // set the avatar in the contact list
  809. var contact = $('#' + resourceJid + '>img');
  810. if (contact && contact.length > 0) {
  811. contact.get(0).src = contactListUrl;
  812. }
  813. // set the avatar in the thumbnail
  814. if (avatar && avatar.length > 0) {
  815. avatar[0].src = thumbUrl;
  816. } else {
  817. if (thumbnail && thumbnail.length > 0) {
  818. avatar = document.createElement('img');
  819. avatar.id = 'avatar_' + resourceJid;
  820. avatar.className = 'userAvatar';
  821. avatar.src = thumbUrl;
  822. thumbnail.append(avatar);
  823. }
  824. }
  825. //if the user is the current active speaker - update the active speaker
  826. // avatar
  827. if (jid === activeSpeakerJid) {
  828. this.updateActiveSpeakerAvatarSrc(jid);
  829. }
  830. },
  831. /**
  832. * Hides or shows the user's avatar
  833. * @param jid jid of the user
  834. * @param show whether we should show the avatar or not
  835. * video because there is no dominant speaker and no focused speaker
  836. */
  837. showUserAvatar: function (jid, show) {
  838. if (users[jid]) {
  839. var resourceJid = Strophe.getResourceFromJid(jid);
  840. var video = $('#participant_' + resourceJid + '>video');
  841. var avatar = $('#avatar_' + resourceJid);
  842. if (jid === connection.emuc.myroomjid) {
  843. video = $('#localVideoWrapper>video');
  844. }
  845. if (show === undefined || show === null) {
  846. show = isUserMuted(jid);
  847. }
  848. //if the user is the currently focused, the dominant speaker or if
  849. //there is no focused and no dominant speaker and the large video is
  850. //currently shown
  851. if (activeSpeakerJid === jid && require("../videolayout/VideoLayout").isLargeVideoOnTop()) {
  852. setVisibility($("#largeVideo"), !show);
  853. setVisibility($('#activeSpeaker'), show);
  854. setVisibility(avatar, false);
  855. setVisibility(video, false);
  856. } else {
  857. if (video && video.length > 0) {
  858. setVisibility(video, !show);
  859. setVisibility(avatar, show);
  860. }
  861. }
  862. }
  863. },
  864. /**
  865. * Updates the src of the active speaker avatar
  866. * @param jid of the current active speaker
  867. */
  868. updateActiveSpeakerAvatarSrc: function (jid) {
  869. if (!jid) {
  870. jid = connection.emuc.findJidFromResource(
  871. require("../videolayout/VideoLayout").getLargeVideoState().userResourceJid);
  872. }
  873. var avatar = $("#activeSpeakerAvatar")[0];
  874. var url = getGravatarUrl(users[jid],
  875. interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE);
  876. if (jid === activeSpeakerJid && avatar.src === url) {
  877. return;
  878. }
  879. activeSpeakerJid = jid;
  880. var isMuted = isUserMuted(jid);
  881. if (jid && isMuted !== null) {
  882. avatar.src = url;
  883. setVisibility($("#largeVideo"), !isMuted);
  884. Avatar.showUserAvatar(jid, isMuted);
  885. }
  886. }
  887. };
  888. module.exports = Avatar;
  889. },{"../side_pannels/settings/Settings":13,"../videolayout/VideoLayout":23}],5:[function(require,module,exports){
  890. /* global $, config, connection, dockToolbar, Moderator,
  891. setLargeVideoVisible, Util */
  892. var VideoLayout = require("../videolayout/VideoLayout");
  893. var Prezi = require("../prezi/Prezi");
  894. var UIUtil = require("../util/UIUtil");
  895. var etherpadName = null;
  896. var etherpadIFrame = null;
  897. var domain = null;
  898. var options = "?showControls=true&showChat=false&showLineNumbers=true&useMonospaceFont=false";
  899. /**
  900. * Resizes the etherpad.
  901. */
  902. function resize() {
  903. if ($('#etherpad>iframe').length) {
  904. var remoteVideos = $('#remoteVideos');
  905. var availableHeight
  906. = window.innerHeight - remoteVideos.outerHeight();
  907. var availableWidth = UIUtil.getAvailableVideoWidth();
  908. $('#etherpad>iframe').width(availableWidth);
  909. $('#etherpad>iframe').height(availableHeight);
  910. }
  911. }
  912. /**
  913. * Shares the Etherpad name with other participants.
  914. */
  915. function shareEtherpad() {
  916. connection.emuc.addEtherpadToPresence(etherpadName);
  917. connection.emuc.sendPresence();
  918. }
  919. /**
  920. * Creates the Etherpad button and adds it to the toolbar.
  921. */
  922. function enableEtherpadButton() {
  923. if (!$('#etherpadButton').is(":visible"))
  924. $('#etherpadButton').css({display: 'inline-block'});
  925. }
  926. /**
  927. * Creates the IFrame for the etherpad.
  928. */
  929. function createIFrame() {
  930. etherpadIFrame = document.createElement('iframe');
  931. etherpadIFrame.src = domain + etherpadName + options;
  932. etherpadIFrame.frameBorder = 0;
  933. etherpadIFrame.scrolling = "no";
  934. etherpadIFrame.width = $('#largeVideoContainer').width() || 640;
  935. etherpadIFrame.height = $('#largeVideoContainer').height() || 480;
  936. etherpadIFrame.setAttribute('style', 'visibility: hidden;');
  937. document.getElementById('etherpad').appendChild(etherpadIFrame);
  938. etherpadIFrame.onload = function() {
  939. document.domain = document.domain;
  940. bubbleIframeMouseMove(etherpadIFrame);
  941. setTimeout(function() {
  942. // the iframes inside of the etherpad are
  943. // not yet loaded when the etherpad iframe is loaded
  944. var outer = etherpadIFrame.
  945. contentDocument.getElementsByName("ace_outer")[0];
  946. bubbleIframeMouseMove(outer);
  947. var inner = outer.
  948. contentDocument.getElementsByName("ace_inner")[0];
  949. bubbleIframeMouseMove(inner);
  950. }, 2000);
  951. };
  952. }
  953. function bubbleIframeMouseMove(iframe){
  954. var existingOnMouseMove = iframe.contentWindow.onmousemove;
  955. iframe.contentWindow.onmousemove = function(e){
  956. if(existingOnMouseMove) existingOnMouseMove(e);
  957. var evt = document.createEvent("MouseEvents");
  958. var boundingClientRect = iframe.getBoundingClientRect();
  959. evt.initMouseEvent(
  960. "mousemove",
  961. true, // bubbles
  962. false, // not cancelable
  963. window,
  964. e.detail,
  965. e.screenX,
  966. e.screenY,
  967. e.clientX + boundingClientRect.left,
  968. e.clientY + boundingClientRect.top,
  969. e.ctrlKey,
  970. e.altKey,
  971. e.shiftKey,
  972. e.metaKey,
  973. e.button,
  974. null // no related element
  975. );
  976. iframe.dispatchEvent(evt);
  977. };
  978. }
  979. /**
  980. * On video selected event.
  981. */
  982. $(document).bind('video.selected', function (event, isPresentation) {
  983. if (config.etherpad_base && etherpadIFrame && etherpadIFrame.style.visibility !== 'hidden')
  984. Etherpad.toggleEtherpad(isPresentation);
  985. });
  986. var Etherpad = {
  987. /**
  988. * Initializes the etherpad.
  989. */
  990. init: function (name) {
  991. if (config.etherpad_base && !etherpadName) {
  992. domain = config.etherpad_base;
  993. if (!name) {
  994. // In case we're the focus we generate the name.
  995. etherpadName = Math.random().toString(36).substring(7) +
  996. '_' + (new Date().getTime()).toString();
  997. shareEtherpad();
  998. }
  999. else
  1000. etherpadName = name;
  1001. enableEtherpadButton();
  1002. /**
  1003. * Resizes the etherpad, when the window is resized.
  1004. */
  1005. $(window).resize(function () {
  1006. resize();
  1007. });
  1008. }
  1009. },
  1010. /**
  1011. * Opens/hides the Etherpad.
  1012. */
  1013. toggleEtherpad: function (isPresentation) {
  1014. if (!etherpadIFrame)
  1015. createIFrame();
  1016. var largeVideo = null;
  1017. if (Prezi.isPresentationVisible())
  1018. largeVideo = $('#presentation>iframe');
  1019. else
  1020. largeVideo = $('#largeVideo');
  1021. if ($('#etherpad>iframe').css('visibility') === 'hidden') {
  1022. $('#activeSpeaker').css('visibility', 'hidden');
  1023. largeVideo.fadeOut(300, function () {
  1024. if (Prezi.isPresentationVisible()) {
  1025. largeVideo.css({opacity: '0'});
  1026. } else {
  1027. VideoLayout.setLargeVideoVisible(false);
  1028. }
  1029. });
  1030. $('#etherpad>iframe').fadeIn(300, function () {
  1031. document.body.style.background = '#eeeeee';
  1032. $('#etherpad>iframe').css({visibility: 'visible'});
  1033. $('#etherpad').css({zIndex: 2});
  1034. });
  1035. }
  1036. else if ($('#etherpad>iframe')) {
  1037. $('#etherpad>iframe').fadeOut(300, function () {
  1038. $('#etherpad>iframe').css({visibility: 'hidden'});
  1039. $('#etherpad').css({zIndex: 0});
  1040. document.body.style.background = 'black';
  1041. });
  1042. if (!isPresentation) {
  1043. $('#largeVideo').fadeIn(300, function () {
  1044. VideoLayout.setLargeVideoVisible(true);
  1045. });
  1046. }
  1047. }
  1048. resize();
  1049. },
  1050. isVisible: function() {
  1051. var etherpadIframe = $('#etherpad>iframe');
  1052. return etherpadIframe && etherpadIframe.is(':visible');
  1053. }
  1054. };
  1055. module.exports = Etherpad;
  1056. },{"../prezi/Prezi":6,"../util/UIUtil":21,"../videolayout/VideoLayout":23}],6:[function(require,module,exports){
  1057. var ToolbarToggler = require("../toolbars/ToolbarToggler");
  1058. var UIUtil = require("../util/UIUtil");
  1059. var VideoLayout = require("../videolayout/VideoLayout");
  1060. var messageHandler = require("../util/MessageHandler");
  1061. var preziPlayer = null;
  1062. var Prezi = {
  1063. /**
  1064. * Reloads the current presentation.
  1065. */
  1066. reloadPresentation: function() {
  1067. var iframe = document.getElementById(preziPlayer.options.preziId);
  1068. iframe.src = iframe.src;
  1069. },
  1070. /**
  1071. * Returns <tt>true</tt> if the presentation is visible, <tt>false</tt> -
  1072. * otherwise.
  1073. */
  1074. isPresentationVisible: function () {
  1075. return ($('#presentation>iframe') != null
  1076. && $('#presentation>iframe').css('opacity') == 1);
  1077. },
  1078. /**
  1079. * Opens the Prezi dialog, from which the user could choose a presentation
  1080. * to load.
  1081. */
  1082. openPreziDialog: function() {
  1083. var myprezi = connection.emuc.getPrezi(connection.emuc.myroomjid);
  1084. if (myprezi) {
  1085. messageHandler.openTwoButtonDialog("Remove Prezi",
  1086. "Are you sure you would like to remove your Prezi?",
  1087. false,
  1088. "Remove",
  1089. function(e,v,m,f) {
  1090. if(v) {
  1091. connection.emuc.removePreziFromPresence();
  1092. connection.emuc.sendPresence();
  1093. }
  1094. }
  1095. );
  1096. }
  1097. else if (preziPlayer != null) {
  1098. messageHandler.openTwoButtonDialog("Share a Prezi",
  1099. "Another participant is already sharing a Prezi." +
  1100. "This conference allows only one Prezi at a time.",
  1101. false,
  1102. "Ok",
  1103. function(e,v,m,f) {
  1104. $.prompt.close();
  1105. }
  1106. );
  1107. }
  1108. else {
  1109. var openPreziState = {
  1110. state0: {
  1111. html: '<h2>Share a Prezi</h2>' +
  1112. '<input id="preziUrl" type="text" ' +
  1113. 'placeholder="e.g. ' +
  1114. 'http://prezi.com/wz7vhjycl7e6/my-prezi" autofocus>',
  1115. persistent: false,
  1116. buttons: { "Share": true , "Cancel": false},
  1117. defaultButton: 1,
  1118. submit: function(e,v,m,f){
  1119. e.preventDefault();
  1120. if(v)
  1121. {
  1122. var preziUrl = document.getElementById('preziUrl');
  1123. if (preziUrl.value)
  1124. {
  1125. var urlValue
  1126. = encodeURI(Util.escapeHtml(preziUrl.value));
  1127. if (urlValue.indexOf('http://prezi.com/') != 0
  1128. && urlValue.indexOf('https://prezi.com/') != 0)
  1129. {
  1130. $.prompt.goToState('state1');
  1131. return false;
  1132. }
  1133. else {
  1134. var presIdTmp = urlValue.substring(
  1135. urlValue.indexOf("prezi.com/") + 10);
  1136. if (!isAlphanumeric(presIdTmp)
  1137. || presIdTmp.indexOf('/') < 2) {
  1138. $.prompt.goToState('state1');
  1139. return false;
  1140. }
  1141. else {
  1142. connection.emuc
  1143. .addPreziToPresence(urlValue, 0);
  1144. connection.emuc.sendPresence();
  1145. $.prompt.close();
  1146. }
  1147. }
  1148. }
  1149. }
  1150. else
  1151. $.prompt.close();
  1152. }
  1153. },
  1154. state1: {
  1155. html: '<h2>Share a Prezi</h2>' +
  1156. 'Please provide a correct prezi link.',
  1157. persistent: false,
  1158. buttons: { "Back": true, "Cancel": false },
  1159. defaultButton: 1,
  1160. submit:function(e,v,m,f) {
  1161. e.preventDefault();
  1162. if(v==0)
  1163. $.prompt.close();
  1164. else
  1165. $.prompt.goToState('state0');
  1166. }
  1167. }
  1168. };
  1169. var focusPreziUrl = function(e) {
  1170. document.getElementById('preziUrl').focus();
  1171. };
  1172. messageHandler.openDialogWithStates(openPreziState, focusPreziUrl, focusPreziUrl);
  1173. }
  1174. }
  1175. };
  1176. /**
  1177. * A new presentation has been added.
  1178. *
  1179. * @param event the event indicating the add of a presentation
  1180. * @param jid the jid from which the presentation was added
  1181. * @param presUrl url of the presentation
  1182. * @param currentSlide the current slide to which we should move
  1183. */
  1184. function presentationAdded(event, jid, presUrl, currentSlide) {
  1185. console.log("presentation added", presUrl);
  1186. var presId = getPresentationId(presUrl);
  1187. var elementId = 'participant_'
  1188. + Strophe.getResourceFromJid(jid)
  1189. + '_' + presId;
  1190. // We explicitly don't specify the peer jid here, because we don't want
  1191. // this video to be dealt with as a peer related one (for example we
  1192. // don't want to show a mute/kick menu for this one, etc.).
  1193. VideoLayout.addRemoteVideoContainer(null, elementId);
  1194. VideoLayout.resizeThumbnails();
  1195. var controlsEnabled = false;
  1196. if (jid === connection.emuc.myroomjid)
  1197. controlsEnabled = true;
  1198. setPresentationVisible(true);
  1199. $('#largeVideoContainer').hover(
  1200. function (event) {
  1201. if (Prezi.isPresentationVisible()) {
  1202. var reloadButtonRight = window.innerWidth
  1203. - $('#presentation>iframe').offset().left
  1204. - $('#presentation>iframe').width();
  1205. $('#reloadPresentation').css({ right: reloadButtonRight,
  1206. display:'inline-block'});
  1207. }
  1208. },
  1209. function (event) {
  1210. if (!Prezi.isPresentationVisible())
  1211. $('#reloadPresentation').css({display:'none'});
  1212. else {
  1213. var e = event.toElement || event.relatedTarget;
  1214. if (e && e.id != 'reloadPresentation' && e.id != 'header')
  1215. $('#reloadPresentation').css({display:'none'});
  1216. }
  1217. });
  1218. preziPlayer = new PreziPlayer(
  1219. 'presentation',
  1220. {preziId: presId,
  1221. width: getPresentationWidth(),
  1222. height: getPresentationHeihgt(),
  1223. controls: controlsEnabled,
  1224. debug: true
  1225. });
  1226. $('#presentation>iframe').attr('id', preziPlayer.options.preziId);
  1227. preziPlayer.on(PreziPlayer.EVENT_STATUS, function(event) {
  1228. console.log("prezi status", event.value);
  1229. if (event.value == PreziPlayer.STATUS_CONTENT_READY) {
  1230. if (jid != connection.emuc.myroomjid)
  1231. preziPlayer.flyToStep(currentSlide);
  1232. }
  1233. });
  1234. preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function(event) {
  1235. console.log("event value", event.value);
  1236. connection.emuc.addCurrentSlideToPresence(event.value);
  1237. connection.emuc.sendPresence();
  1238. });
  1239. $("#" + elementId).css( 'background-image',
  1240. 'url(../images/avatarprezi.png)');
  1241. $("#" + elementId).click(
  1242. function () {
  1243. setPresentationVisible(true);
  1244. }
  1245. );
  1246. };
  1247. /**
  1248. * A presentation has been removed.
  1249. *
  1250. * @param event the event indicating the remove of a presentation
  1251. * @param jid the jid for which the presentation was removed
  1252. * @param the url of the presentation
  1253. */
  1254. function presentationRemoved(event, jid, presUrl) {
  1255. console.log('presentation removed', presUrl);
  1256. var presId = getPresentationId(presUrl);
  1257. setPresentationVisible(false);
  1258. $('#participant_'
  1259. + Strophe.getResourceFromJid(jid)
  1260. + '_' + presId).remove();
  1261. $('#presentation>iframe').remove();
  1262. if (preziPlayer != null) {
  1263. preziPlayer.destroy();
  1264. preziPlayer = null;
  1265. }
  1266. };
  1267. /**
  1268. * Indicates if the given string is an alphanumeric string.
  1269. * Note that some special characters are also allowed (-, _ , /, &, ?, =, ;) for the
  1270. * purpose of checking URIs.
  1271. */
  1272. function isAlphanumeric(unsafeText) {
  1273. var regex = /^[a-z0-9-_\/&\?=;]+$/i;
  1274. return regex.test(unsafeText);
  1275. }
  1276. /**
  1277. * Returns the presentation id from the given url.
  1278. */
  1279. function getPresentationId (presUrl) {
  1280. var presIdTmp = presUrl.substring(presUrl.indexOf("prezi.com/") + 10);
  1281. return presIdTmp.substring(0, presIdTmp.indexOf('/'));
  1282. }
  1283. /**
  1284. * Returns the presentation width.
  1285. */
  1286. function getPresentationWidth() {
  1287. var availableWidth = UIUtil.getAvailableVideoWidth();
  1288. var availableHeight = getPresentationHeihgt();
  1289. var aspectRatio = 16.0 / 9.0;
  1290. if (availableHeight < availableWidth / aspectRatio) {
  1291. availableWidth = Math.floor(availableHeight * aspectRatio);
  1292. }
  1293. return availableWidth;
  1294. }
  1295. /**
  1296. * Returns the presentation height.
  1297. */
  1298. function getPresentationHeihgt() {
  1299. var remoteVideos = $('#remoteVideos');
  1300. return window.innerHeight - remoteVideos.outerHeight();
  1301. }
  1302. /**
  1303. * Resizes the presentation iframe.
  1304. */
  1305. function resize() {
  1306. if ($('#presentation>iframe')) {
  1307. $('#presentation>iframe').width(getPresentationWidth());
  1308. $('#presentation>iframe').height(getPresentationHeihgt());
  1309. }
  1310. }
  1311. /**
  1312. * Shows/hides a presentation.
  1313. */
  1314. function setPresentationVisible(visible) {
  1315. var prezi = $('#presentation>iframe');
  1316. if (visible) {
  1317. // Trigger the video.selected event to indicate a change in the
  1318. // large video.
  1319. $(document).trigger("video.selected", [true]);
  1320. $('#largeVideo').fadeOut(300);
  1321. prezi.fadeIn(300, function() {
  1322. prezi.css({opacity:'1'});
  1323. ToolbarToggler.dockToolbar(true);
  1324. VideoLayout.setLargeVideoVisible(false);
  1325. });
  1326. $('#activeSpeaker').css('visibility', 'hidden');
  1327. }
  1328. else {
  1329. if (prezi.css('opacity') == '1') {
  1330. prezi.fadeOut(300, function () {
  1331. prezi.css({opacity:'0'});
  1332. $('#reloadPresentation').css({display:'none'});
  1333. $('#largeVideo').fadeIn(300, function() {
  1334. VideoLayout.setLargeVideoVisible(true);
  1335. ToolbarToggler.dockToolbar(false);
  1336. });
  1337. });
  1338. }
  1339. }
  1340. }
  1341. /**
  1342. * Presentation has been removed.
  1343. */
  1344. $(document).bind('presentationremoved.muc', presentationRemoved);
  1345. /**
  1346. * Presentation has been added.
  1347. */
  1348. $(document).bind('presentationadded.muc', presentationAdded);
  1349. /*
  1350. * Indicates presentation slide change.
  1351. */
  1352. $(document).bind('gotoslide.muc', function (event, jid, presUrl, current) {
  1353. if (preziPlayer && preziPlayer.getCurrentStep() != current) {
  1354. preziPlayer.flyToStep(current);
  1355. var animationStepsArray = preziPlayer.getAnimationCountOnSteps();
  1356. for (var i = 0; i < parseInt(animationStepsArray[current]); i++) {
  1357. preziPlayer.flyToStep(current, i);
  1358. }
  1359. }
  1360. });
  1361. /**
  1362. * On video selected event.
  1363. */
  1364. $(document).bind('video.selected', function (event, isPresentation) {
  1365. if (!isPresentation && $('#presentation>iframe')) {
  1366. setPresentationVisible(false);
  1367. }
  1368. });
  1369. $(window).resize(function () {
  1370. resize();
  1371. });
  1372. module.exports = Prezi;
  1373. },{"../toolbars/ToolbarToggler":16,"../util/MessageHandler":20,"../util/UIUtil":21,"../videolayout/VideoLayout":23}],7:[function(require,module,exports){
  1374. var Chat = require("./chat/Chat");
  1375. var ContactList = require("./contactlist/ContactList");
  1376. var Settings = require("./settings/Settings");
  1377. var SettingsMenu = require("./settings/SettingsMenu");
  1378. var VideoLayout = require("../videolayout/VideoLayout");
  1379. var ToolbarToggler = require("../toolbars/ToolbarToggler");
  1380. /**
  1381. * Toggler for the chat, contact list, settings menu, etc..
  1382. */
  1383. var PanelToggler = (function(my) {
  1384. var currentlyOpen = null;
  1385. var buttons = {
  1386. '#chatspace': '#chatBottomButton',
  1387. '#contactlist': '#contactListButton',
  1388. '#settingsmenu': '#settingsButton'
  1389. };
  1390. /**
  1391. * Resizes the video area
  1392. * @param isClosing whether the side panel is going to be closed or is going to open / remain opened
  1393. * @param completeFunction a function to be called when the video space is resized
  1394. */
  1395. var resizeVideoArea = function(isClosing, completeFunction) {
  1396. var videospace = $('#videospace');
  1397. var panelSize = isClosing ? [0, 0] : PanelToggler.getPanelSize();
  1398. var videospaceWidth = window.innerWidth - panelSize[0];
  1399. var videospaceHeight = window.innerHeight;
  1400. var videoSize
  1401. = getVideoSize(null, null, videospaceWidth, videospaceHeight);
  1402. var videoWidth = videoSize[0];
  1403. var videoHeight = videoSize[1];
  1404. var videoPosition = getVideoPosition(videoWidth,
  1405. videoHeight,
  1406. videospaceWidth,
  1407. videospaceHeight);
  1408. var horizontalIndent = videoPosition[0];
  1409. var verticalIndent = videoPosition[1];
  1410. var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
  1411. var thumbnailsWidth = thumbnailSize[0];
  1412. var thumbnailsHeight = thumbnailSize[1];
  1413. //for chat
  1414. videospace.animate({
  1415. right: panelSize[0],
  1416. width: videospaceWidth,
  1417. height: videospaceHeight
  1418. },
  1419. {
  1420. queue: false,
  1421. duration: 500,
  1422. complete: completeFunction
  1423. });
  1424. $('#remoteVideos').animate({
  1425. height: thumbnailsHeight
  1426. },
  1427. {
  1428. queue: false,
  1429. duration: 500
  1430. });
  1431. $('#remoteVideos>span').animate({
  1432. height: thumbnailsHeight,
  1433. width: thumbnailsWidth
  1434. },
  1435. {
  1436. queue: false,
  1437. duration: 500,
  1438. complete: function () {
  1439. $(document).trigger(
  1440. "remotevideo.resized",
  1441. [thumbnailsWidth,
  1442. thumbnailsHeight]);
  1443. }
  1444. });
  1445. $('#largeVideoContainer').animate({
  1446. width: videospaceWidth,
  1447. height: videospaceHeight
  1448. },
  1449. {
  1450. queue: false,
  1451. duration: 500
  1452. });
  1453. $('#largeVideo').animate({
  1454. width: videoWidth,
  1455. height: videoHeight,
  1456. top: verticalIndent,
  1457. bottom: verticalIndent,
  1458. left: horizontalIndent,
  1459. right: horizontalIndent
  1460. },
  1461. {
  1462. queue: false,
  1463. duration: 500
  1464. });
  1465. };
  1466. /**
  1467. * Toggles the windows in the side panel
  1468. * @param object the window that should be shown
  1469. * @param selector the selector for the element containing the panel
  1470. * @param onOpenComplete function to be called when the panel is opened
  1471. * @param onOpen function to be called if the window is going to be opened
  1472. * @param onClose function to be called if the window is going to be closed
  1473. */
  1474. var toggle = function(object, selector, onOpenComplete, onOpen, onClose) {
  1475. buttonClick(buttons[selector], "active");
  1476. if (object.isVisible()) {
  1477. $("#toast-container").animate({
  1478. right: '5px'
  1479. },
  1480. {
  1481. queue: false,
  1482. duration: 500
  1483. });
  1484. $(selector).hide("slide", {
  1485. direction: "right",
  1486. queue: false,
  1487. duration: 500
  1488. });
  1489. if(typeof onClose === "function") {
  1490. onClose();
  1491. }
  1492. currentlyOpen = null;
  1493. }
  1494. else {
  1495. // Undock the toolbar when the chat is shown and if we're in a
  1496. // video mode.
  1497. if (VideoLayout.isLargeVideoVisible()) {
  1498. ToolbarToggler.dockToolbar(false);
  1499. }
  1500. if(currentlyOpen) {
  1501. var current = $(currentlyOpen);
  1502. buttonClick(buttons[currentlyOpen], "active");
  1503. current.css('z-index', 4);
  1504. setTimeout(function () {
  1505. current.css('display', 'none');
  1506. current.css('z-index', 5);
  1507. }, 500);
  1508. }
  1509. $("#toast-container").animate({
  1510. right: (PanelToggler.getPanelSize()[0] + 5) + 'px'
  1511. },
  1512. {
  1513. queue: false,
  1514. duration: 500
  1515. });
  1516. $(selector).show("slide", {
  1517. direction: "right",
  1518. queue: false,
  1519. duration: 500,
  1520. complete: onOpenComplete
  1521. });
  1522. if(typeof onOpen === "function") {
  1523. onOpen();
  1524. }
  1525. currentlyOpen = selector;
  1526. }
  1527. };
  1528. /**
  1529. * Opens / closes the chat area.
  1530. */
  1531. my.toggleChat = function() {
  1532. var chatCompleteFunction = Chat.isVisible() ?
  1533. function() {} : function () {
  1534. Chat.scrollChatToBottom();
  1535. $('#chatspace').trigger('shown');
  1536. };
  1537. resizeVideoArea(Chat.isVisible(), chatCompleteFunction);
  1538. toggle(Chat,
  1539. '#chatspace',
  1540. function () {
  1541. // Request the focus in the nickname field or the chat input field.
  1542. if ($('#nickname').css('visibility') === 'visible') {
  1543. $('#nickinput').focus();
  1544. } else {
  1545. $('#usermsg').focus();
  1546. }
  1547. },
  1548. null,
  1549. Chat.resizeChat,
  1550. null);
  1551. };
  1552. /**
  1553. * Opens / closes the contact list area.
  1554. */
  1555. my.toggleContactList = function () {
  1556. var completeFunction = ContactList.isVisible() ?
  1557. function() {} : function () { $('#contactlist').trigger('shown');};
  1558. resizeVideoArea(ContactList.isVisible(), completeFunction);
  1559. toggle(ContactList,
  1560. '#contactlist',
  1561. null,
  1562. function() {
  1563. ContactList.setVisualNotification(false);
  1564. },
  1565. null);
  1566. };
  1567. /**
  1568. * Opens / closes the settings menu
  1569. */
  1570. my.toggleSettingsMenu = function() {
  1571. resizeVideoArea(SettingsMenu.isVisible(), function (){});
  1572. toggle(SettingsMenu,
  1573. '#settingsmenu',
  1574. null,
  1575. function() {
  1576. var settings = Settings.getSettings();
  1577. $('#setDisplayName').get(0).value = settings.displayName;
  1578. $('#setEmail').get(0).value = settings.email;
  1579. },
  1580. null);
  1581. };
  1582. /**
  1583. * Returns the size of the side panel.
  1584. */
  1585. my.getPanelSize = function () {
  1586. var availableHeight = window.innerHeight;
  1587. var availableWidth = window.innerWidth;
  1588. var panelWidth = 200;
  1589. if (availableWidth * 0.2 < 200) {
  1590. panelWidth = availableWidth * 0.2;
  1591. }
  1592. return [panelWidth, availableHeight];
  1593. };
  1594. my.isVisible = function() {
  1595. return (Chat.isVisible() || ContactList.isVisible() || SettingsMenu.isVisible());
  1596. };
  1597. return my;
  1598. }(PanelToggler || {}));
  1599. module.exports = PanelToggler;
  1600. },{"../toolbars/ToolbarToggler":16,"../videolayout/VideoLayout":23,"./chat/Chat":8,"./contactlist/ContactList":12,"./settings/Settings":13,"./settings/SettingsMenu":14}],8:[function(require,module,exports){
  1601. /* global $, Util, connection, nickname:true, getVideoSize,
  1602. getVideoPosition, showToolbar */
  1603. var Replacement = require("./Replacement");
  1604. var CommandsProcessor = require("./Commands");
  1605. var ToolbarToggler = require("../../toolbars/ToolbarToggler");
  1606. var smileys = require("./smileys.json").smileys;
  1607. var notificationInterval = false;
  1608. var unreadMessages = 0;
  1609. /**
  1610. * Shows/hides a visual notification, indicating that a message has arrived.
  1611. */
  1612. function setVisualNotification(show) {
  1613. var unreadMsgElement = document.getElementById('unreadMessages');
  1614. var unreadMsgBottomElement
  1615. = document.getElementById('bottomUnreadMessages');
  1616. var glower = $('#chatButton');
  1617. var bottomGlower = $('#chatBottomButton');
  1618. if (unreadMessages) {
  1619. unreadMsgElement.innerHTML = unreadMessages.toString();
  1620. unreadMsgBottomElement.innerHTML = unreadMessages.toString();
  1621. ToolbarToggler.dockToolbar(true);
  1622. var chatButtonElement
  1623. = document.getElementById('chatButton').parentNode;
  1624. var leftIndent = (Util.getTextWidth(chatButtonElement) -
  1625. Util.getTextWidth(unreadMsgElement)) / 2;
  1626. var topIndent = (Util.getTextHeight(chatButtonElement) -
  1627. Util.getTextHeight(unreadMsgElement)) / 2 - 3;
  1628. unreadMsgElement.setAttribute(
  1629. 'style',
  1630. 'top:' + topIndent +
  1631. '; left:' + leftIndent + ';');
  1632. var chatBottomButtonElement
  1633. = document.getElementById('chatBottomButton').parentNode;
  1634. var bottomLeftIndent = (Util.getTextWidth(chatBottomButtonElement) -
  1635. Util.getTextWidth(unreadMsgBottomElement)) / 2;
  1636. var bottomTopIndent = (Util.getTextHeight(chatBottomButtonElement) -
  1637. Util.getTextHeight(unreadMsgBottomElement)) / 2 - 2;
  1638. unreadMsgBottomElement.setAttribute(
  1639. 'style',
  1640. 'top:' + bottomTopIndent +
  1641. '; left:' + bottomLeftIndent + ';');
  1642. if (!glower.hasClass('icon-chat-simple')) {
  1643. glower.removeClass('icon-chat');
  1644. glower.addClass('icon-chat-simple');
  1645. }
  1646. }
  1647. else {
  1648. unreadMsgElement.innerHTML = '';
  1649. unreadMsgBottomElement.innerHTML = '';
  1650. glower.removeClass('icon-chat-simple');
  1651. glower.addClass('icon-chat');
  1652. }
  1653. if (show && !notificationInterval) {
  1654. notificationInterval = window.setInterval(function () {
  1655. glower.toggleClass('active');
  1656. bottomGlower.toggleClass('active glowing');
  1657. }, 800);
  1658. }
  1659. else if (!show && notificationInterval) {
  1660. window.clearInterval(notificationInterval);
  1661. notificationInterval = false;
  1662. glower.removeClass('active');
  1663. bottomGlower.removeClass('glowing');
  1664. bottomGlower.addClass('active');
  1665. }
  1666. }
  1667. /**
  1668. * Returns the current time in the format it is shown to the user
  1669. * @returns {string}
  1670. */
  1671. function getCurrentTime() {
  1672. var now = new Date();
  1673. var hour = now.getHours();
  1674. var minute = now.getMinutes();
  1675. var second = now.getSeconds();
  1676. if(hour.toString().length === 1) {
  1677. hour = '0'+hour;
  1678. }
  1679. if(minute.toString().length === 1) {
  1680. minute = '0'+minute;
  1681. }
  1682. if(second.toString().length === 1) {
  1683. second = '0'+second;
  1684. }
  1685. return hour+':'+minute+':'+second;
  1686. }
  1687. function toggleSmileys()
  1688. {
  1689. var smileys = $('#smileysContainer');
  1690. if(!smileys.is(':visible')) {
  1691. smileys.show("slide", { direction: "down", duration: 300});
  1692. } else {
  1693. smileys.hide("slide", { direction: "down", duration: 300});
  1694. }
  1695. $('#usermsg').focus();
  1696. }
  1697. function addClickFunction(smiley, number) {
  1698. smiley.onclick = function addSmileyToMessage() {
  1699. var usermsg = $('#usermsg');
  1700. var message = usermsg.val();
  1701. message += smileys['smiley' + number];
  1702. usermsg.val(message);
  1703. usermsg.get(0).setSelectionRange(message.length, message.length);
  1704. toggleSmileys();
  1705. usermsg.focus();
  1706. };
  1707. }
  1708. /**
  1709. * Adds the smileys container to the chat
  1710. */
  1711. function addSmileys() {
  1712. var smileysContainer = document.createElement('div');
  1713. smileysContainer.id = 'smileysContainer';
  1714. for(var i = 1; i <= 21; i++) {
  1715. var smileyContainer = document.createElement('div');
  1716. smileyContainer.id = 'smiley' + i;
  1717. smileyContainer.className = 'smileyContainer';
  1718. var smiley = document.createElement('img');
  1719. smiley.src = 'images/smileys/smiley' + i + '.svg';
  1720. smiley.className = 'smiley';
  1721. addClickFunction(smiley, i);
  1722. smileyContainer.appendChild(smiley);
  1723. smileysContainer.appendChild(smileyContainer);
  1724. }
  1725. $("#chatspace").append(smileysContainer);
  1726. }
  1727. /**
  1728. * Resizes the chat conversation.
  1729. */
  1730. function resizeChatConversation() {
  1731. var msgareaHeight = $('#usermsg').outerHeight();
  1732. var chatspace = $('#chatspace');
  1733. var width = chatspace.width();
  1734. var chat = $('#chatconversation');
  1735. var smileys = $('#smileysarea');
  1736. smileys.height(msgareaHeight);
  1737. $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
  1738. $('#smileysContainer').css('bottom', msgareaHeight);
  1739. chat.width(width - 10);
  1740. chat.height(window.innerHeight - 15 - msgareaHeight);
  1741. }
  1742. /**
  1743. * Chat related user interface.
  1744. */
  1745. var Chat = (function (my) {
  1746. /**
  1747. * Initializes chat related interface.
  1748. */
  1749. my.init = function () {
  1750. var storedDisplayName = window.localStorage.displayname;
  1751. if (storedDisplayName) {
  1752. nickname = storedDisplayName;
  1753. Chat.setChatConversationMode(true);
  1754. }
  1755. $('#nickinput').keydown(function (event) {
  1756. if (event.keyCode === 13) {
  1757. event.preventDefault();
  1758. var val = Util.escapeHtml(this.value);
  1759. this.value = '';
  1760. if (!nickname) {
  1761. nickname = val;
  1762. window.localStorage.displayname = nickname;
  1763. connection.emuc.addDisplayNameToPresence(nickname);
  1764. connection.emuc.sendPresence();
  1765. Chat.setChatConversationMode(true);
  1766. return;
  1767. }
  1768. }
  1769. });
  1770. $('#usermsg').keydown(function (event) {
  1771. if (event.keyCode === 13) {
  1772. event.preventDefault();
  1773. var value = this.value;
  1774. $('#usermsg').val('').trigger('autosize.resize');
  1775. this.focus();
  1776. var command = new CommandsProcessor(value);
  1777. if(command.isCommand())
  1778. {
  1779. command.processCommand();
  1780. }
  1781. else
  1782. {
  1783. var message = Util.escapeHtml(value);
  1784. connection.emuc.sendMessage(message, nickname);
  1785. }
  1786. }
  1787. });
  1788. var onTextAreaResize = function () {
  1789. resizeChatConversation();
  1790. Chat.scrollChatToBottom();
  1791. };
  1792. $('#usermsg').autosize({callback: onTextAreaResize});
  1793. $("#chatspace").bind("shown",
  1794. function () {
  1795. unreadMessages = 0;
  1796. setVisualNotification(false);
  1797. });
  1798. addSmileys();
  1799. };
  1800. /**
  1801. * Appends the given message to the chat conversation.
  1802. */
  1803. my.updateChatConversation = function (from, displayName, message) {
  1804. var divClassName = '';
  1805. if (connection.emuc.myroomjid === from) {
  1806. divClassName = "localuser";
  1807. }
  1808. else {
  1809. divClassName = "remoteuser";
  1810. if (!Chat.isVisible()) {
  1811. unreadMessages++;
  1812. Util.playSoundNotification('chatNotification');
  1813. setVisualNotification(true);
  1814. }
  1815. }
  1816. // replace links and smileys
  1817. // Strophe already escapes special symbols on sending,
  1818. // so we escape here only tags to avoid double &amp;
  1819. var escMessage = message.replace(/</g, '&lt;').
  1820. replace(/>/g, '&gt;').replace(/\n/g, '<br/>');
  1821. var escDisplayName = Util.escapeHtml(displayName);
  1822. message = Replacement.processReplacements(escMessage);
  1823. var messageContainer =
  1824. '<div class="chatmessage">'+
  1825. '<img src="../images/chatArrow.svg" class="chatArrow">' +
  1826. '<div class="username ' + divClassName +'">' + escDisplayName +
  1827. '</div>' + '<div class="timestamp">' + getCurrentTime() +
  1828. '</div>' + '<div class="usermessage">' + message + '</div>' +
  1829. '</div>';
  1830. $('#chatconversation').append(messageContainer);
  1831. $('#chatconversation').animate(
  1832. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  1833. };
  1834. /**
  1835. * Appends error message to the conversation
  1836. * @param errorMessage the received error message.
  1837. * @param originalText the original message.
  1838. */
  1839. my.chatAddError = function(errorMessage, originalText)
  1840. {
  1841. errorMessage = Util.escapeHtml(errorMessage);
  1842. originalText = Util.escapeHtml(originalText);
  1843. $('#chatconversation').append(
  1844. '<div class="errorMessage"><b>Error: </b>' + 'Your message' +
  1845. (originalText? (' \"'+ originalText + '\"') : "") +
  1846. ' was not sent.' +
  1847. (errorMessage? (' Reason: ' + errorMessage) : '') + '</div>');
  1848. $('#chatconversation').animate(
  1849. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  1850. };
  1851. /**
  1852. * Sets the subject to the UI
  1853. * @param subject the subject
  1854. */
  1855. my.chatSetSubject = function(subject)
  1856. {
  1857. if(subject)
  1858. subject = subject.trim();
  1859. $('#subject').html(Replacement.linkify(Util.escapeHtml(subject)));
  1860. if(subject === "")
  1861. {
  1862. $("#subject").css({display: "none"});
  1863. }
  1864. else
  1865. {
  1866. $("#subject").css({display: "block"});
  1867. }
  1868. };
  1869. /**
  1870. * Sets the chat conversation mode.
  1871. */
  1872. my.setChatConversationMode = function (isConversationMode) {
  1873. if (isConversationMode) {
  1874. $('#nickname').css({visibility: 'hidden'});
  1875. $('#chatconversation').css({visibility: 'visible'});
  1876. $('#usermsg').css({visibility: 'visible'});
  1877. $('#smileysarea').css({visibility: 'visible'});
  1878. $('#usermsg').focus();
  1879. }
  1880. };
  1881. /**
  1882. * Resizes the chat area.
  1883. */
  1884. my.resizeChat = function () {
  1885. var chatSize = require("../SidePanelToggler").getPanelSize();
  1886. $('#chatspace').width(chatSize[0]);
  1887. $('#chatspace').height(chatSize[1]);
  1888. resizeChatConversation();
  1889. };
  1890. /**
  1891. * Indicates if the chat is currently visible.
  1892. */
  1893. my.isVisible = function () {
  1894. return $('#chatspace').is(":visible");
  1895. };
  1896. /**
  1897. * Shows and hides the window with the smileys
  1898. */
  1899. my.toggleSmileys = toggleSmileys;
  1900. /**
  1901. * Scrolls chat to the bottom.
  1902. */
  1903. my.scrollChatToBottom = function() {
  1904. setTimeout(function () {
  1905. $('#chatconversation').scrollTop(
  1906. $('#chatconversation')[0].scrollHeight);
  1907. }, 5);
  1908. };
  1909. return my;
  1910. }(Chat || {}));
  1911. module.exports = Chat;
  1912. },{"../../toolbars/ToolbarToggler":16,"../SidePanelToggler":7,"./Commands":9,"./Replacement":10,"./smileys.json":11}],9:[function(require,module,exports){
  1913. /**
  1914. * List with supported commands. The keys are the names of the commands and
  1915. * the value is the function that processes the message.
  1916. * @type {{String: function}}
  1917. */
  1918. var commands = {
  1919. "topic" : processTopic
  1920. };
  1921. /**
  1922. * Extracts the command from the message.
  1923. * @param message the received message
  1924. * @returns {string} the command
  1925. */
  1926. function getCommand(message)
  1927. {
  1928. if(message)
  1929. {
  1930. for(var command in commands)
  1931. {
  1932. if(message.indexOf("/" + command) == 0)
  1933. return command;
  1934. }
  1935. }
  1936. return "";
  1937. };
  1938. /**
  1939. * Processes the data for topic command.
  1940. * @param commandArguments the arguments of the topic command.
  1941. */
  1942. function processTopic(commandArguments)
  1943. {
  1944. var topic = Util.escapeHtml(commandArguments);
  1945. connection.emuc.setSubject(topic);
  1946. }
  1947. /**
  1948. * Constructs new CommandProccessor instance from a message that
  1949. * handles commands received via chat messages.
  1950. * @param message the message
  1951. * @constructor
  1952. */
  1953. function CommandsProcessor(message)
  1954. {
  1955. var command = getCommand(message);
  1956. /**
  1957. * Returns the name of the command.
  1958. * @returns {String} the command
  1959. */
  1960. this.getCommand = function()
  1961. {
  1962. return command;
  1963. };
  1964. var messageArgument = message.substr(command.length + 2);
  1965. /**
  1966. * Returns the arguments of the command.
  1967. * @returns {string}
  1968. */
  1969. this.getArgument = function()
  1970. {
  1971. return messageArgument;
  1972. };
  1973. }
  1974. /**
  1975. * Checks whether this instance is valid command or not.
  1976. * @returns {boolean}
  1977. */
  1978. CommandsProcessor.prototype.isCommand = function()
  1979. {
  1980. if(this.getCommand())
  1981. return true;
  1982. return false;
  1983. };
  1984. /**
  1985. * Processes the command.
  1986. */
  1987. CommandsProcessor.prototype.processCommand = function()
  1988. {
  1989. if(!this.isCommand())
  1990. return;
  1991. commands[this.getCommand()](this.getArgument());
  1992. };
  1993. module.exports = CommandsProcessor;
  1994. },{}],10:[function(require,module,exports){
  1995. var Smileys = require("./smileys.json");
  1996. /**
  1997. * Processes links and smileys in "body"
  1998. */
  1999. function processReplacements(body)
  2000. {
  2001. //make links clickable
  2002. body = linkify(body);
  2003. //add smileys
  2004. body = smilify(body);
  2005. return body;
  2006. }
  2007. /**
  2008. * Finds and replaces all links in the links in "body"
  2009. * with their <a href=""></a>
  2010. */
  2011. function linkify(inputText)
  2012. {
  2013. var replacedText, replacePattern1, replacePattern2, replacePattern3;
  2014. //URLs starting with http://, https://, or ftp://
  2015. replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
  2016. replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');
  2017. //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
  2018. replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
  2019. replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');
  2020. //Change email addresses to mailto:: links.
  2021. replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
  2022. replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
  2023. return replacedText;
  2024. }
  2025. /**
  2026. * Replaces common smiley strings with images
  2027. */
  2028. function smilify(body)
  2029. {
  2030. if(!body) {
  2031. return body;
  2032. }
  2033. var regexs = Smileys["regexs"];
  2034. for(var smiley in regexs) {
  2035. if(regexs.hasOwnProperty(smiley)) {
  2036. body = body.replace(regexs[smiley],
  2037. '<img class="smiley" src="images/smileys/' + smiley + '.svg">');
  2038. }
  2039. }
  2040. return body;
  2041. }
  2042. module.exports = {
  2043. processReplacements: processReplacements,
  2044. linkify: linkify
  2045. };
  2046. },{"./smileys.json":11}],11:[function(require,module,exports){
  2047. module.exports={
  2048. "smileys": {
  2049. "smiley1": ":)",
  2050. "smiley2": ":(",
  2051. "smiley3": ":D",
  2052. "smiley4": "(y)",
  2053. "smiley5": " :P",
  2054. "smiley6": "(wave)",
  2055. "smiley7": "(blush)",
  2056. "smiley8": "(chuckle)",
  2057. "smiley9": "(shocked)",
  2058. "smiley10": ":*",
  2059. "smiley11": "(n)",
  2060. "smiley12": "(search)",
  2061. "smiley13": " <3",
  2062. "smiley14": "(oops)",
  2063. "smiley15": "(angry)",
  2064. "smiley16": "(angel)",
  2065. "smiley17": "(sick)",
  2066. "smiley18": ";(",
  2067. "smiley19": "(bomb)",
  2068. "smiley20": "(clap)",
  2069. "smiley21": " ;)"
  2070. },
  2071. "regexs": {
  2072. "smiley2": /(:-\(\(|:-\(|:\(\(|:\(|\(sad\))/gi,
  2073. "smiley3": /(:-\)\)|:\)\)|\(lol\)|:-D|:D)/gi,
  2074. "smiley1": /(:-\)|:\))/gi,
  2075. "smiley4": /(\(y\)|\(Y\)|\(ok\))/gi,
  2076. "smiley5": /(:-P|:P|:-p|:p)/gi,
  2077. "smiley6": /(\(wave\))/gi,
  2078. "smiley7": /(\(blush\))/gi,
  2079. "smiley8": /(\(chuckle\))/gi,
  2080. "smiley9": /(:-0|\(shocked\))/gi,
  2081. "smiley10": /(:-\*|:\*|\(kiss\))/gi,
  2082. "smiley11": /(\(n\))/gi,
  2083. "smiley12": /(\(search\))/g,
  2084. "smiley13": /(<3|&lt;3|&amp;lt;3|\(L\)|\(l\)|\(H\)|\(h\))/gi,
  2085. "smiley14": /(\(oops\))/gi,
  2086. "smiley15": /(\(angry\))/gi,
  2087. "smiley16": /(\(angel\))/gi,
  2088. "smiley17": /(\(sick\))/gi,
  2089. "smiley18": /(;-\(\(|;\(\(|;-\(|;\(|:"\(|:"-\(|:~-\(|:~\(|\(upset\))/gi,
  2090. "smiley19": /(\(bomb\))/gi,
  2091. "smiley20": /(\(clap\))/gi,
  2092. "smiley21": /(;-\)|;\)|;-\)\)|;\)\)|;-D|;D|\(wink\))/gi
  2093. }
  2094. }
  2095. },{}],12:[function(require,module,exports){
  2096. var numberOfContacts = 0;
  2097. var notificationInterval;
  2098. /**
  2099. * Updates the number of participants in the contact list button and sets
  2100. * the glow
  2101. * @param delta indicates whether a new user has joined (1) or someone has
  2102. * left(-1)
  2103. */
  2104. function updateNumberOfParticipants(delta) {
  2105. //when the user is alone we don't show the number of participants
  2106. if(numberOfContacts === 0) {
  2107. $("#numberOfParticipants").text('');
  2108. numberOfContacts += delta;
  2109. } else if(numberOfContacts !== 0 && !ContactList.isVisible()) {
  2110. ContactList.setVisualNotification(true);
  2111. numberOfContacts += delta;
  2112. $("#numberOfParticipants").text(numberOfContacts);
  2113. }
  2114. }
  2115. /**
  2116. * Creates the avatar element.
  2117. *
  2118. * @return the newly created avatar element
  2119. */
  2120. function createAvatar(id) {
  2121. var avatar = document.createElement('img');
  2122. avatar.className = "icon-avatar avatar";
  2123. avatar.src = "https://www.gravatar.com/avatar/" + id + "?d=wavatar&size=30";
  2124. return avatar;
  2125. }
  2126. /**
  2127. * Creates the display name paragraph.
  2128. *
  2129. * @param displayName the display name to set
  2130. */
  2131. function createDisplayNameParagraph(displayName) {
  2132. var p = document.createElement('p');
  2133. p.innerText = displayName;
  2134. return p;
  2135. }
  2136. /**
  2137. * Indicates that the display name has changed.
  2138. */
  2139. $(document).bind( 'displaynamechanged',
  2140. function (event, peerJid, displayName) {
  2141. if (peerJid === 'localVideoContainer')
  2142. peerJid = connection.emuc.myroomjid;
  2143. var resourceJid = Strophe.getResourceFromJid(peerJid);
  2144. var contactName = $('#contactlist #' + resourceJid + '>p');
  2145. if (contactName && displayName && displayName.length > 0)
  2146. contactName.html(displayName);
  2147. });
  2148. function stopGlowing(glower) {
  2149. window.clearInterval(notificationInterval);
  2150. notificationInterval = false;
  2151. glower.removeClass('glowing');
  2152. if (!ContactList.isVisible()) {
  2153. glower.removeClass('active');
  2154. }
  2155. }
  2156. /**
  2157. * Contact list.
  2158. */
  2159. var ContactList = {
  2160. /**
  2161. * Indicates if the chat is currently visible.
  2162. *
  2163. * @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
  2164. * otherwise
  2165. */
  2166. isVisible: function () {
  2167. return $('#contactlist').is(":visible");
  2168. },
  2169. /**
  2170. * Adds a contact for the given peerJid if such doesn't yet exist.
  2171. *
  2172. * @param peerJid the peerJid corresponding to the contact
  2173. * @param id the user's email or userId used to get the user's avatar
  2174. */
  2175. ensureAddContact: function (peerJid, id) {
  2176. var resourceJid = Strophe.getResourceFromJid(peerJid);
  2177. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  2178. if (!contact || contact.length <= 0)
  2179. ContactList.addContact(peerJid, id);
  2180. },
  2181. /**
  2182. * Adds a contact for the given peer jid.
  2183. *
  2184. * @param peerJid the jid of the contact to add
  2185. * @param id the email or userId of the user
  2186. */
  2187. addContact: function (peerJid, id) {
  2188. var resourceJid = Strophe.getResourceFromJid(peerJid);
  2189. var contactlist = $('#contactlist>ul');
  2190. var newContact = document.createElement('li');
  2191. newContact.id = resourceJid;
  2192. newContact.className = "clickable";
  2193. newContact.onclick = function (event) {
  2194. if (event.currentTarget.className === "clickable") {
  2195. $(ContactList).trigger('contactclicked', [peerJid]);
  2196. }
  2197. };
  2198. newContact.appendChild(createAvatar(id));
  2199. newContact.appendChild(createDisplayNameParagraph("Participant"));
  2200. var clElement = contactlist.get(0);
  2201. if (resourceJid === Strophe.getResourceFromJid(connection.emuc.myroomjid)
  2202. && $('#contactlist>ul .title')[0].nextSibling.nextSibling) {
  2203. clElement.insertBefore(newContact,
  2204. $('#contactlist>ul .title')[0].nextSibling.nextSibling);
  2205. }
  2206. else {
  2207. clElement.appendChild(newContact);
  2208. }
  2209. updateNumberOfParticipants(1);
  2210. },
  2211. /**
  2212. * Removes a contact for the given peer jid.
  2213. *
  2214. * @param peerJid the peerJid corresponding to the contact to remove
  2215. */
  2216. removeContact: function (peerJid) {
  2217. var resourceJid = Strophe.getResourceFromJid(peerJid);
  2218. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  2219. if (contact && contact.length > 0) {
  2220. var contactlist = $('#contactlist>ul');
  2221. contactlist.get(0).removeChild(contact.get(0));
  2222. updateNumberOfParticipants(-1);
  2223. }
  2224. },
  2225. setVisualNotification: function (show, stopGlowingIn) {
  2226. var glower = $('#contactListButton');
  2227. if (show && !notificationInterval) {
  2228. notificationInterval = window.setInterval(function () {
  2229. glower.toggleClass('active glowing');
  2230. }, 800);
  2231. }
  2232. else if (!show && notificationInterval) {
  2233. stopGlowing(glower);
  2234. }
  2235. if (stopGlowingIn) {
  2236. setTimeout(function () {
  2237. stopGlowing(glower);
  2238. }, stopGlowingIn);
  2239. }
  2240. },
  2241. setClickable: function (resourceJid, isClickable) {
  2242. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  2243. if (isClickable) {
  2244. contact.addClass('clickable');
  2245. } else {
  2246. contact.removeClass('clickable');
  2247. }
  2248. }
  2249. };
  2250. module.exports = ContactList;
  2251. },{}],13:[function(require,module,exports){
  2252. var email = '';
  2253. var displayName = '';
  2254. var userId;
  2255. function supportsLocalStorage() {
  2256. try {
  2257. return 'localStorage' in window && window.localStorage !== null;
  2258. } catch (e) {
  2259. console.log("localstorage is not supported");
  2260. return false;
  2261. }
  2262. }
  2263. function generateUniqueId() {
  2264. function _p8() {
  2265. return (Math.random().toString(16)+"000000000").substr(2,8);
  2266. }
  2267. return _p8() + _p8() + _p8() + _p8();
  2268. }
  2269. if(supportsLocalStorage()) {
  2270. if(!window.localStorage.jitsiMeetId) {
  2271. window.localStorage.jitsiMeetId = generateUniqueId();
  2272. console.log("generated id", window.localStorage.jitsiMeetId);
  2273. }
  2274. userId = window.localStorage.jitsiMeetId || '';
  2275. email = window.localStorage.email || '';
  2276. displayName = window.localStorage.displayname || '';
  2277. } else {
  2278. console.log("local storage is not supported");
  2279. userId = generateUniqueId();
  2280. }
  2281. var Settings =
  2282. {
  2283. setDisplayName: function (newDisplayName) {
  2284. displayName = newDisplayName;
  2285. window.localStorage.displayname = displayName;
  2286. return displayName;
  2287. },
  2288. setEmail: function(newEmail)
  2289. {
  2290. email = newEmail;
  2291. window.localStorage.email = newEmail;
  2292. return email;
  2293. },
  2294. getSettings: function () {
  2295. return {
  2296. email: email,
  2297. displayName: displayName,
  2298. uid: userId
  2299. };
  2300. }
  2301. };
  2302. module.exports = Settings;
  2303. },{}],14:[function(require,module,exports){
  2304. var Avatar = require("../../avatar/Avatar");
  2305. var Settings = require("./Settings");
  2306. var SettingsMenu = {
  2307. update: function() {
  2308. var newDisplayName = Util.escapeHtml($('#setDisplayName').get(0).value);
  2309. var newEmail = Util.escapeHtml($('#setEmail').get(0).value);
  2310. if(newDisplayName) {
  2311. var displayName = Settings.setDisplayName(newDisplayName);
  2312. connection.emuc.addDisplayNameToPresence(displayName);
  2313. }
  2314. connection.emuc.addEmailToPresence(newEmail);
  2315. var email = Settings.setEmail(newEmail);
  2316. connection.emuc.sendPresence();
  2317. Avatar.setUserAvatar(connection.emuc.myroomjid, email);
  2318. },
  2319. isVisible: function() {
  2320. return $('#settingsmenu').is(':visible');
  2321. },
  2322. setDisplayName: function(newDisplayName) {
  2323. var displayName = Settings.setDisplayName(newDisplayName);
  2324. $('#setDisplayName').get(0).value = displayName;
  2325. }
  2326. };
  2327. $(document).bind('displaynamechanged', function(event, peerJid, newDisplayName) {
  2328. if(peerJid === 'localVideoContainer' ||
  2329. peerJid === connection.emuc.myroomjid) {
  2330. SettingsMenu.setDisplayName(newDisplayName);
  2331. }
  2332. });
  2333. module.exports = SettingsMenu;
  2334. },{"../../avatar/Avatar":4,"./Settings":13}],15:[function(require,module,exports){
  2335. var PanelToggler = require("../side_pannels/SidePanelToggler");
  2336. var buttonHandlers = {
  2337. "bottom_toolbar_contact_list": function () {
  2338. BottomToolbar.toggleContactList();
  2339. },
  2340. "bottom_toolbar_film_strip": function () {
  2341. BottomToolbar.toggleFilmStrip();
  2342. },
  2343. "bottom_toolbar_chat": function () {
  2344. BottomToolbar.toggleChat();
  2345. }
  2346. };
  2347. var BottomToolbar = (function (my) {
  2348. my.init = function () {
  2349. for(var k in buttonHandlers)
  2350. $("#" + k).click(buttonHandlers[k]);
  2351. };
  2352. my.toggleChat = function() {
  2353. PanelToggler.toggleChat();
  2354. };
  2355. my.toggleContactList = function() {
  2356. PanelToggler.toggleContactList();
  2357. };
  2358. my.toggleFilmStrip = function() {
  2359. var filmstrip = $("#remoteVideos");
  2360. filmstrip.toggleClass("hidden");
  2361. };
  2362. $(document).bind("remotevideo.resized", function (event, width, height) {
  2363. var bottom = (height - $('#bottomToolbar').outerHeight())/2 + 18;
  2364. $('#bottomToolbar').css({bottom: bottom + 'px'});
  2365. });
  2366. return my;
  2367. }(BottomToolbar || {}));
  2368. module.exports = BottomToolbar;
  2369. },{"../side_pannels/SidePanelToggler":7}],16:[function(require,module,exports){
  2370. /* global $, interfaceConfig, Moderator, showDesktopSharingButton */
  2371. var toolbarTimeoutObject,
  2372. toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
  2373. /**
  2374. * Hides the toolbar.
  2375. */
  2376. function hideToolbar() {
  2377. var header = $("#header"),
  2378. bottomToolbar = $("#bottomToolbar");
  2379. var isToolbarHover = false;
  2380. header.find('*').each(function () {
  2381. var id = $(this).attr('id');
  2382. if ($("#" + id + ":hover").length > 0) {
  2383. isToolbarHover = true;
  2384. }
  2385. });
  2386. if ($("#bottomToolbar:hover").length > 0) {
  2387. isToolbarHover = true;
  2388. }
  2389. clearTimeout(toolbarTimeoutObject);
  2390. toolbarTimeoutObject = null;
  2391. if (!isToolbarHover) {
  2392. header.hide("slide", { direction: "up", duration: 300});
  2393. $('#subject').animate({top: "-=40"}, 300);
  2394. if ($("#remoteVideos").hasClass("hidden")) {
  2395. bottomToolbar.hide(
  2396. "slide", {direction: "right", duration: 300});
  2397. }
  2398. }
  2399. else {
  2400. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  2401. }
  2402. }
  2403. var ToolbarToggler = {
  2404. /**
  2405. * Shows the main toolbar.
  2406. */
  2407. showToolbar: function () {
  2408. var header = $("#header"),
  2409. bottomToolbar = $("#bottomToolbar");
  2410. if (!header.is(':visible') || !bottomToolbar.is(":visible")) {
  2411. header.show("slide", { direction: "up", duration: 300});
  2412. $('#subject').animate({top: "+=40"}, 300);
  2413. if (!bottomToolbar.is(":visible")) {
  2414. bottomToolbar.show(
  2415. "slide", {direction: "right", duration: 300});
  2416. }
  2417. if (toolbarTimeoutObject) {
  2418. clearTimeout(toolbarTimeoutObject);
  2419. toolbarTimeoutObject = null;
  2420. }
  2421. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  2422. toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
  2423. }
  2424. if (Moderator.isModerator())
  2425. {
  2426. // TODO: Enable settings functionality.
  2427. // Need to uncomment the settings button in index.html.
  2428. // $('#settingsButton').css({visibility:"visible"});
  2429. }
  2430. // Show/hide desktop sharing button
  2431. showDesktopSharingButton();
  2432. },
  2433. /**
  2434. * Docks/undocks the toolbar.
  2435. *
  2436. * @param isDock indicates what operation to perform
  2437. */
  2438. dockToolbar: function (isDock) {
  2439. if (isDock) {
  2440. // First make sure the toolbar is shown.
  2441. if (!$('#header').is(':visible')) {
  2442. this.showToolbar();
  2443. }
  2444. // Then clear the time out, to dock the toolbar.
  2445. if (toolbarTimeoutObject) {
  2446. clearTimeout(toolbarTimeoutObject);
  2447. toolbarTimeoutObject = null;
  2448. }
  2449. }
  2450. else {
  2451. if (!$('#header').is(':visible')) {
  2452. this.showToolbar();
  2453. }
  2454. else {
  2455. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  2456. }
  2457. }
  2458. }
  2459. };
  2460. module.exports = ToolbarToggler;
  2461. },{}],17:[function(require,module,exports){
  2462. /* global $, buttonClick, config, lockRoom, Moderator,
  2463. setSharedKey, sharedKey, Util */
  2464. var messageHandler = require("../util/MessageHandler");
  2465. var BottomToolbar = require("./BottomToolbar");
  2466. var Prezi = require("../prezi/Prezi");
  2467. var Etherpad = require("../etherpad/Etherpad");
  2468. var PanelToggler = require("../side_pannels/SidePanelToggler");
  2469. var roomUrl = null;
  2470. var sharedKey = '';
  2471. var authenticationWindow = null;
  2472. var buttonHandlers =
  2473. {
  2474. "toolbar_button_mute": function () {
  2475. return toggleAudio();
  2476. },
  2477. "toolbar_button_camera": function () {
  2478. return toggleVideo();
  2479. },
  2480. "toolbar_button_authentication": function () {
  2481. return Toolbar.authenticateClicked();
  2482. },
  2483. "toolbar_button_record": function () {
  2484. return toggleRecording();
  2485. },
  2486. "toolbar_button_security": function () {
  2487. return Toolbar.openLockDialog();
  2488. },
  2489. "toolbar_button_link": function () {
  2490. return Toolbar.openLinkDialog();
  2491. },
  2492. "toolbar_button_chat": function () {
  2493. return BottomToolbar.toggleChat();
  2494. },
  2495. "toolbar_button_prezi": function () {
  2496. return Prezi.openPreziDialog();
  2497. },
  2498. "toolbar_button_etherpad": function () {
  2499. return Etherpad.toggleEtherpad(0);
  2500. },
  2501. "toolbar_button_desktopsharing": function () {
  2502. return toggleScreenSharing();
  2503. },
  2504. "toolbar_button_fullScreen": function()
  2505. {
  2506. buttonClick("#fullScreen", "icon-full-screen icon-exit-full-screen");
  2507. return Toolbar.toggleFullScreen();
  2508. },
  2509. "toolbar_button_sip": function () {
  2510. return callSipButtonClicked();
  2511. },
  2512. "toolbar_button_settings": function () {
  2513. PanelToggler.toggleSettingsMenu();
  2514. },
  2515. "toolbar_button_hangup": function () {
  2516. return hangup();
  2517. }
  2518. };
  2519. /**
  2520. * Starts or stops the recording for the conference.
  2521. */
  2522. function toggleRecording() {
  2523. Recording.toggleRecording();
  2524. }
  2525. /**
  2526. * Locks / unlocks the room.
  2527. */
  2528. function lockRoom(lock) {
  2529. var currentSharedKey = '';
  2530. if (lock)
  2531. currentSharedKey = sharedKey;
  2532. connection.emuc.lockRoom(currentSharedKey, function (res) {
  2533. // password is required
  2534. if (sharedKey)
  2535. {
  2536. console.log('set room password');
  2537. Toolbar.lockLockButton();
  2538. }
  2539. else
  2540. {
  2541. console.log('removed room password');
  2542. Toolbar.unlockLockButton();
  2543. }
  2544. }, function (err) {
  2545. console.warn('setting password failed', err);
  2546. messageHandler.showError('Lock failed',
  2547. 'Failed to lock conference.',
  2548. err);
  2549. Toolbar.setSharedKey('');
  2550. }, function () {
  2551. console.warn('room passwords not supported');
  2552. messageHandler.showError('Warning',
  2553. 'Room passwords are currently not supported.');
  2554. Toolbar.setSharedKey('');
  2555. });
  2556. };
  2557. /**
  2558. * Invite participants to conference.
  2559. */
  2560. function inviteParticipants() {
  2561. if (roomUrl === null)
  2562. return;
  2563. var sharedKeyText = "";
  2564. if (sharedKey && sharedKey.length > 0) {
  2565. sharedKeyText =
  2566. "This conference is password protected. Please use the " +
  2567. "following pin when joining:%0D%0A%0D%0A" +
  2568. sharedKey + "%0D%0A%0D%0A";
  2569. }
  2570. var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
  2571. var subject = "Invitation to a " + interfaceConfig.APP_NAME + " (" + conferenceName + ")";
  2572. var body = "Hey there, I%27d like to invite you to a " + interfaceConfig.APP_NAME +
  2573. " conference I%27ve just set up.%0D%0A%0D%0A" +
  2574. "Please click on the following link in order" +
  2575. " to join the conference.%0D%0A%0D%0A" +
  2576. roomUrl +
  2577. "%0D%0A%0D%0A" +
  2578. sharedKeyText +
  2579. "Note that " + interfaceConfig.APP_NAME + " is currently" +
  2580. " only supported by Chromium," +
  2581. " Google Chrome and Opera, so you need" +
  2582. " to be using one of these browsers.%0D%0A%0D%0A" +
  2583. "Talk to you in a sec!";
  2584. if (window.localStorage.displayname) {
  2585. body += "%0D%0A%0D%0A" + window.localStorage.displayname;
  2586. }
  2587. if (interfaceConfig.INVITATION_POWERED_BY) {
  2588. body += "%0D%0A%0D%0A--%0D%0Apowered by jitsi.org";
  2589. }
  2590. window.open("mailto:?subject=" + subject + "&body=" + body, '_blank');
  2591. }
  2592. var Toolbar = (function (my) {
  2593. my.init = function () {
  2594. for(var k in buttonHandlers)
  2595. $("#" + k).click(buttonHandlers[k]);
  2596. }
  2597. /**
  2598. * Sets shared key
  2599. * @param sKey the shared key
  2600. */
  2601. my.setSharedKey = function (sKey) {
  2602. sharedKey = sKey;
  2603. };
  2604. my.closeAuthenticationWindow = function () {
  2605. if (authenticationWindow) {
  2606. authenticationWindow.close();
  2607. authenticationWindow = null;
  2608. }
  2609. }
  2610. my.authenticateClicked = function () {
  2611. // Get authentication URL
  2612. Moderator.getAuthUrl(function (url) {
  2613. // Open popup with authentication URL
  2614. authenticationWindow = messageHandler.openCenteredPopup(
  2615. url, 500, 400,
  2616. function () {
  2617. // On popup closed - retry room allocation
  2618. Moderator.allocateConferenceFocus(
  2619. roomName, doJoinAfterFocus);
  2620. authenticationWindow = null;
  2621. });
  2622. if (!authenticationWindow) {
  2623. Toolbar.showAuthenticateButton(true);
  2624. messageHandler.openMessageDialog(
  2625. null, "Your browser is blocking popup windows from this site." +
  2626. " Please enable popups in your browser security settings" +
  2627. " and try again.");
  2628. }
  2629. });
  2630. };
  2631. /**
  2632. * Updates the room invite url.
  2633. */
  2634. my.updateRoomUrl = function (newRoomUrl) {
  2635. roomUrl = newRoomUrl;
  2636. // If the invite dialog has been already opened we update the information.
  2637. var inviteLink = document.getElementById('inviteLinkRef');
  2638. if (inviteLink) {
  2639. inviteLink.value = roomUrl;
  2640. inviteLink.select();
  2641. document.getElementById('jqi_state0_buttonInvite').disabled = false;
  2642. }
  2643. }
  2644. /**
  2645. * Disables and enables some of the buttons.
  2646. */
  2647. my.setupButtonsFromConfig = function () {
  2648. if (config.disablePrezi)
  2649. {
  2650. $("#prezi_button").css({display: "none"});
  2651. }
  2652. };
  2653. /**
  2654. * Opens the lock room dialog.
  2655. */
  2656. my.openLockDialog = function () {
  2657. // Only the focus is able to set a shared key.
  2658. if (!Moderator.isModerator()) {
  2659. if (sharedKey) {
  2660. messageHandler.openMessageDialog(null,
  2661. "This conversation is currently protected by" +
  2662. " a password. Only the owner of the conference" +
  2663. " could set a password.",
  2664. false,
  2665. "Password");
  2666. } else {
  2667. messageHandler.openMessageDialog(null,
  2668. "This conversation isn't currently protected by" +
  2669. " a password. Only the owner of the conference" +
  2670. " could set a password.",
  2671. false,
  2672. "Password");
  2673. }
  2674. } else {
  2675. if (sharedKey) {
  2676. messageHandler.openTwoButtonDialog(null,
  2677. "Are you sure you would like to remove your password?",
  2678. false,
  2679. "Remove",
  2680. function (e, v) {
  2681. if (v) {
  2682. Toolbar.setSharedKey('');
  2683. lockRoom(false);
  2684. }
  2685. });
  2686. } else {
  2687. messageHandler.openTwoButtonDialog(null,
  2688. '<h2>Set a password to lock your room</h2>' +
  2689. '<input id="lockKey" type="text"' +
  2690. 'placeholder="your password" autofocus>',
  2691. false,
  2692. "Save",
  2693. function (e, v) {
  2694. if (v) {
  2695. var lockKey = document.getElementById('lockKey');
  2696. if (lockKey.value) {
  2697. Toolbar.setSharedKey(Util.escapeHtml(lockKey.value));
  2698. lockRoom(true);
  2699. }
  2700. }
  2701. },
  2702. function () {
  2703. document.getElementById('lockKey').focus();
  2704. }
  2705. );
  2706. }
  2707. }
  2708. };
  2709. /**
  2710. * Opens the invite link dialog.
  2711. */
  2712. my.openLinkDialog = function () {
  2713. var inviteLink;
  2714. if (roomUrl === null) {
  2715. inviteLink = "Your conference is currently being created...";
  2716. } else {
  2717. inviteLink = encodeURI(roomUrl);
  2718. }
  2719. messageHandler.openTwoButtonDialog(
  2720. "Share this link with everyone you want to invite",
  2721. '<input id="inviteLinkRef" type="text" value="' +
  2722. inviteLink + '" onclick="this.select();" readonly>',
  2723. false,
  2724. "Invite",
  2725. function (e, v) {
  2726. if (v) {
  2727. if (roomUrl) {
  2728. inviteParticipants();
  2729. }
  2730. }
  2731. },
  2732. function () {
  2733. if (roomUrl) {
  2734. document.getElementById('inviteLinkRef').select();
  2735. } else {
  2736. document.getElementById('jqi_state0_buttonInvite')
  2737. .disabled = true;
  2738. }
  2739. }
  2740. );
  2741. };
  2742. /**
  2743. * Opens the settings dialog.
  2744. */
  2745. my.openSettingsDialog = function () {
  2746. messageHandler.openTwoButtonDialog(
  2747. '<h2>Configure your conference</h2>' +
  2748. '<input type="checkbox" id="initMuted">' +
  2749. 'Participants join muted<br/>' +
  2750. '<input type="checkbox" id="requireNicknames">' +
  2751. 'Require nicknames<br/><br/>' +
  2752. 'Set a password to lock your room:' +
  2753. '<input id="lockKey" type="text" placeholder="your password"' +
  2754. 'autofocus>',
  2755. null,
  2756. false,
  2757. "Save",
  2758. function () {
  2759. document.getElementById('lockKey').focus();
  2760. },
  2761. function (e, v) {
  2762. if (v) {
  2763. if ($('#initMuted').is(":checked")) {
  2764. // it is checked
  2765. }
  2766. if ($('#requireNicknames').is(":checked")) {
  2767. // it is checked
  2768. }
  2769. /*
  2770. var lockKey = document.getElementById('lockKey');
  2771. if (lockKey.value) {
  2772. setSharedKey(lockKey.value);
  2773. lockRoom(true);
  2774. }
  2775. */
  2776. }
  2777. }
  2778. );
  2779. };
  2780. /**
  2781. * Toggles the application in and out of full screen mode
  2782. * (a.k.a. presentation mode in Chrome).
  2783. */
  2784. my.toggleFullScreen = function () {
  2785. var fsElement = document.documentElement;
  2786. if (!document.mozFullScreen && !document.webkitIsFullScreen) {
  2787. //Enter Full Screen
  2788. if (fsElement.mozRequestFullScreen) {
  2789. fsElement.mozRequestFullScreen();
  2790. }
  2791. else {
  2792. fsElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
  2793. }
  2794. } else {
  2795. //Exit Full Screen
  2796. if (document.mozCancelFullScreen) {
  2797. document.mozCancelFullScreen();
  2798. } else {
  2799. document.webkitCancelFullScreen();
  2800. }
  2801. }
  2802. };
  2803. /**
  2804. * Unlocks the lock button state.
  2805. */
  2806. my.unlockLockButton = function () {
  2807. if ($("#lockIcon").hasClass("icon-security-locked"))
  2808. buttonClick("#lockIcon", "icon-security icon-security-locked");
  2809. };
  2810. /**
  2811. * Updates the lock button state to locked.
  2812. */
  2813. my.lockLockButton = function () {
  2814. if ($("#lockIcon").hasClass("icon-security"))
  2815. buttonClick("#lockIcon", "icon-security icon-security-locked");
  2816. };
  2817. /**
  2818. * Shows or hides authentication button
  2819. * @param show <tt>true</tt> to show or <tt>false</tt> to hide
  2820. */
  2821. my.showAuthenticateButton = function (show) {
  2822. if (show) {
  2823. $('#authentication').css({display: "inline"});
  2824. }
  2825. else {
  2826. $('#authentication').css({display: "none"});
  2827. }
  2828. };
  2829. // Shows or hides the 'recording' button.
  2830. my.showRecordingButton = function (show) {
  2831. if (!config.enableRecording) {
  2832. return;
  2833. }
  2834. if (show) {
  2835. $('#recording').css({display: "inline"});
  2836. }
  2837. else {
  2838. $('#recording').css({display: "none"});
  2839. }
  2840. };
  2841. // Sets the state of the recording button
  2842. my.setRecordingButtonState = function (isRecording) {
  2843. if (isRecording) {
  2844. $('#recordButton').removeClass("icon-recEnable");
  2845. $('#recordButton').addClass("icon-recEnable active");
  2846. } else {
  2847. $('#recordButton').removeClass("icon-recEnable active");
  2848. $('#recordButton').addClass("icon-recEnable");
  2849. }
  2850. };
  2851. // Shows or hides SIP calls button
  2852. my.showSipCallButton = function (show) {
  2853. if (config.hosts.call_control && show) {
  2854. $('#sipCallButton').css({display: "inline"});
  2855. } else {
  2856. $('#sipCallButton').css({display: "none"});
  2857. }
  2858. };
  2859. /**
  2860. * Sets the state of the button. The button has blue glow if desktop
  2861. * streaming is active.
  2862. * @param active the state of the desktop streaming.
  2863. */
  2864. my.changeDesktopSharingButtonState = function (active) {
  2865. var button = $("#desktopsharing > a");
  2866. if (active)
  2867. {
  2868. button.addClass("glow");
  2869. }
  2870. else
  2871. {
  2872. button.removeClass("glow");
  2873. }
  2874. };
  2875. return my;
  2876. }(Toolbar || {}));
  2877. module.exports = Toolbar;
  2878. },{"../etherpad/Etherpad":5,"../prezi/Prezi":6,"../side_pannels/SidePanelToggler":7,"../util/MessageHandler":20,"./BottomToolbar":15}],18:[function(require,module,exports){
  2879. module.exports=require(16)
  2880. },{}],19:[function(require,module,exports){
  2881. var JitsiPopover = (function () {
  2882. /**
  2883. * Constructs new JitsiPopover and attaches it to the element
  2884. * @param element jquery selector
  2885. * @param options the options for the popover.
  2886. * @constructor
  2887. */
  2888. function JitsiPopover(element, options)
  2889. {
  2890. this.options = {
  2891. skin: "white",
  2892. content: ""
  2893. };
  2894. if(options)
  2895. {
  2896. if(options.skin)
  2897. this.options.skin = options.skin;
  2898. if(options.content)
  2899. this.options.content = options.content;
  2900. }
  2901. this.elementIsHovered = false;
  2902. this.popoverIsHovered = false;
  2903. this.popoverShown = false;
  2904. element.data("jitsi_popover", this);
  2905. this.element = element;
  2906. this.template = ' <div class="jitsipopover ' + this.options.skin +
  2907. '"><div class="arrow"></div><div class="jitsipopover-content"></div>' +
  2908. '<div class="jitsiPopupmenuPadding"></div></div>';
  2909. var self = this;
  2910. this.element.on("mouseenter", function () {
  2911. self.elementIsHovered = true;
  2912. self.show();
  2913. }).on("mouseleave", function () {
  2914. self.elementIsHovered = false;
  2915. setTimeout(function () {
  2916. self.hide();
  2917. }, 10);
  2918. });
  2919. }
  2920. /**
  2921. * Shows the popover
  2922. */
  2923. JitsiPopover.prototype.show = function () {
  2924. this.createPopover();
  2925. this.popoverShown = true;
  2926. };
  2927. /**
  2928. * Hides the popover
  2929. */
  2930. JitsiPopover.prototype.hide = function () {
  2931. if(!this.elementIsHovered && !this.popoverIsHovered && this.popoverShown)
  2932. {
  2933. this.forceHide();
  2934. }
  2935. };
  2936. /**
  2937. * Hides the popover
  2938. */
  2939. JitsiPopover.prototype.forceHide = function () {
  2940. $(".jitsipopover").remove();
  2941. this.popoverShown = false;
  2942. };
  2943. /**
  2944. * Creates the popover html
  2945. */
  2946. JitsiPopover.prototype.createPopover = function () {
  2947. $("body").append(this.template);
  2948. $(".jitsipopover > .jitsipopover-content").html(this.options.content);
  2949. var self = this;
  2950. $(".jitsipopover").on("mouseenter", function () {
  2951. self.popoverIsHovered = true;
  2952. }).on("mouseleave", function () {
  2953. self.popoverIsHovered = false;
  2954. self.hide();
  2955. });
  2956. this.refreshPosition();
  2957. };
  2958. /**
  2959. * Refreshes the position of the popover
  2960. */
  2961. JitsiPopover.prototype.refreshPosition = function () {
  2962. $(".jitsipopover").position({
  2963. my: "bottom",
  2964. at: "top",
  2965. collision: "fit",
  2966. of: this.element,
  2967. using: function (position, elements) {
  2968. var calcLeft = elements.target.left - elements.element.left + elements.target.width/2;
  2969. $(".jitsipopover").css({top: position.top, left: position.left, display: "table"});
  2970. $(".jitsipopover > .arrow").css({left: calcLeft});
  2971. $(".jitsipopover > .jitsiPopupmenuPadding").css({left: calcLeft - 50});
  2972. }
  2973. });
  2974. };
  2975. /**
  2976. * Updates the content of popover.
  2977. * @param content new content
  2978. */
  2979. JitsiPopover.prototype.updateContent = function (content) {
  2980. this.options.content = content;
  2981. if(!this.popoverShown)
  2982. return;
  2983. $(".jitsipopover").remove();
  2984. this.createPopover();
  2985. };
  2986. return JitsiPopover;
  2987. })();
  2988. module.exports = JitsiPopover;
  2989. },{}],20:[function(require,module,exports){
  2990. var messageHandler = (function(my) {
  2991. /**
  2992. * Shows a message to the user.
  2993. *
  2994. * @param titleString the title of the message
  2995. * @param messageString the text of the message
  2996. */
  2997. my.openMessageDialog = function(titleString, messageString) {
  2998. $.prompt(messageString,
  2999. {
  3000. title: titleString,
  3001. persistent: false
  3002. }
  3003. );
  3004. };
  3005. /**
  3006. * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel.
  3007. *
  3008. * @param titleString the title of the message
  3009. * @param msgString the text of the message
  3010. * @param persistent boolean value which determines whether the message is persistent or not
  3011. * @param leftButton the fist button's text
  3012. * @param submitFunction function to be called on submit
  3013. * @param loadedFunction function to be called after the prompt is fully loaded
  3014. * @param closeFunction function to be called after the prompt is closed
  3015. */
  3016. my.openTwoButtonDialog = function(titleString, msgString, persistent, leftButton,
  3017. submitFunction, loadedFunction, closeFunction) {
  3018. var buttons = {};
  3019. buttons[leftButton] = true;
  3020. buttons.Cancel = false;
  3021. $.prompt(msgString, {
  3022. title: titleString,
  3023. persistent: false,
  3024. buttons: buttons,
  3025. defaultButton: 1,
  3026. loaded: loadedFunction,
  3027. submit: submitFunction,
  3028. close: closeFunction
  3029. });
  3030. };
  3031. /**
  3032. * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel.
  3033. *
  3034. * @param titleString the title of the message
  3035. * @param msgString the text of the message
  3036. * @param persistent boolean value which determines whether the message is persistent or not
  3037. * @param buttons object with the buttons. The keys must be the name of the button and value is the value
  3038. * that will be passed to submitFunction
  3039. * @param submitFunction function to be called on submit
  3040. * @param loadedFunction function to be called after the prompt is fully loaded
  3041. */
  3042. my.openDialog = function(titleString, msgString, persistent, buttons, submitFunction, loadedFunction) {
  3043. $.prompt(msgString, {
  3044. title: titleString,
  3045. persistent: false,
  3046. buttons: buttons,
  3047. defaultButton: 1,
  3048. loaded: loadedFunction,
  3049. submit: submitFunction
  3050. });
  3051. };
  3052. /**
  3053. * Shows a dialog with different states to the user.
  3054. *
  3055. * @param statesObject object containing all the states of the dialog
  3056. * @param loadedFunction function to be called after the prompt is fully loaded
  3057. * @param stateChangedFunction function to be called when the state of the dialog is changed
  3058. */
  3059. my.openDialogWithStates = function(statesObject, loadedFunction, stateChangedFunction) {
  3060. var myPrompt = $.prompt(statesObject);
  3061. myPrompt.on('impromptu:loaded', loadedFunction);
  3062. myPrompt.on('impromptu:statechanged', stateChangedFunction);
  3063. };
  3064. /**
  3065. * Opens new popup window for given <tt>url</tt> centered over current
  3066. * window.
  3067. *
  3068. * @param url the URL to be displayed in the popup window
  3069. * @param w the width of the popup window
  3070. * @param h the height of the popup window
  3071. * @param onPopupClosed optional callback function called when popup window
  3072. * has been closed.
  3073. *
  3074. * @returns popup window object if opened successfully or undefined
  3075. * in case we failed to open it(popup blocked)
  3076. */
  3077. my.openCenteredPopup = function (url, w, h, onPopupClosed) {
  3078. var l = window.screenX + (window.innerWidth / 2) - (w / 2);
  3079. var t = window.screenY + (window.innerHeight / 2) - (h / 2);
  3080. var popup = window.open(
  3081. url, '_blank',
  3082. 'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + '');
  3083. if (popup && onPopupClosed) {
  3084. var pollTimer = window.setInterval(function () {
  3085. if (popup.closed !== false) {
  3086. window.clearInterval(pollTimer);
  3087. onPopupClosed();
  3088. }
  3089. }, 200);
  3090. }
  3091. return popup;
  3092. };
  3093. /**
  3094. * Shows a dialog prompting the user to send an error report.
  3095. *
  3096. * @param titleString the title of the message
  3097. * @param msgString the text of the message
  3098. * @param error the error that is being reported
  3099. */
  3100. my.openReportDialog = function(titleString, msgString, error) {
  3101. my.openMessageDialog(titleString, msgString);
  3102. console.log(error);
  3103. //FIXME send the error to the server
  3104. };
  3105. /**
  3106. * Shows an error dialog to the user.
  3107. * @param title the title of the message
  3108. * @param message the text of the messafe
  3109. */
  3110. my.showError = function(title, message) {
  3111. if(!(title || message)) {
  3112. title = title || "Oops!";
  3113. message = message || "There was some kind of error";
  3114. }
  3115. messageHandler.openMessageDialog(title, message);
  3116. };
  3117. my.notify = function(displayName, cls, message) {
  3118. toastr.info(
  3119. '<span class="nickname">' +
  3120. displayName +
  3121. '</span><br>' +
  3122. '<span class=' + cls + '>' +
  3123. message +
  3124. '</span>');
  3125. };
  3126. return my;
  3127. }(messageHandler || {}));
  3128. module.exports = messageHandler;
  3129. },{}],21:[function(require,module,exports){
  3130. /**
  3131. * Created by hristo on 12/22/14.
  3132. */
  3133. module.exports = {
  3134. /**
  3135. * Returns the available video width.
  3136. */
  3137. getAvailableVideoWidth: function () {
  3138. var PanelToggler = require("../side_pannels/SidePanelToggler");
  3139. var rightPanelWidth
  3140. = PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
  3141. return window.innerWidth - rightPanelWidth;
  3142. }
  3143. };
  3144. },{"../side_pannels/SidePanelToggler":7}],22:[function(require,module,exports){
  3145. var JitsiPopover = require("../util/JitsiPopover");
  3146. /**
  3147. * Constructs new connection indicator.
  3148. * @param videoContainer the video container associated with the indicator.
  3149. * @constructor
  3150. */
  3151. function ConnectionIndicator(videoContainer, jid, VideoLayout)
  3152. {
  3153. this.videoContainer = videoContainer;
  3154. this.bandwidth = null;
  3155. this.packetLoss = null;
  3156. this.bitrate = null;
  3157. this.showMoreValue = false;
  3158. this.resolution = null;
  3159. this.transport = [];
  3160. this.popover = null;
  3161. this.jid = jid;
  3162. this.create();
  3163. this.videoLayout = VideoLayout;
  3164. }
  3165. /**
  3166. * Values for the connection quality
  3167. * @type {{98: string,
  3168. * 81: string,
  3169. * 64: string,
  3170. * 47: string,
  3171. * 30: string,
  3172. * 0: string}}
  3173. */
  3174. ConnectionIndicator.connectionQualityValues = {
  3175. 98: "18px", //full
  3176. 81: "15px",//4 bars
  3177. 64: "11px",//3 bars
  3178. 47: "7px",//2 bars
  3179. 30: "3px",//1 bar
  3180. 0: "0px"//empty
  3181. };
  3182. ConnectionIndicator.getIP = function(value)
  3183. {
  3184. return value.substring(0, value.lastIndexOf(":"));
  3185. };
  3186. ConnectionIndicator.getPort = function(value)
  3187. {
  3188. return value.substring(value.lastIndexOf(":") + 1, value.length);
  3189. };
  3190. ConnectionIndicator.getStringFromArray = function (array) {
  3191. var res = "";
  3192. for(var i = 0; i < array.length; i++)
  3193. {
  3194. res += (i === 0? "" : ", ") + array[i];
  3195. }
  3196. return res;
  3197. };
  3198. /**
  3199. * Generates the html content.
  3200. * @returns {string} the html content.
  3201. */
  3202. ConnectionIndicator.prototype.generateText = function () {
  3203. var downloadBitrate, uploadBitrate, packetLoss, resolution, i;
  3204. if(this.bitrate === null)
  3205. {
  3206. downloadBitrate = "N/A";
  3207. uploadBitrate = "N/A";
  3208. }
  3209. else
  3210. {
  3211. downloadBitrate =
  3212. this.bitrate.download? this.bitrate.download + " Kbps" : "N/A";
  3213. uploadBitrate =
  3214. this.bitrate.upload? this.bitrate.upload + " Kbps" : "N/A";
  3215. }
  3216. if(this.packetLoss === null)
  3217. {
  3218. packetLoss = "N/A";
  3219. }
  3220. else
  3221. {
  3222. packetLoss = "<span class='jitsipopover_green'>&darr;</span>" +
  3223. (this.packetLoss.download !== null? this.packetLoss.download : "N/A") +
  3224. "% <span class='jitsipopover_orange'>&uarr;</span>" +
  3225. (this.packetLoss.upload !== null? this.packetLoss.upload : "N/A") + "%";
  3226. }
  3227. var resolutionValue = null;
  3228. if(this.resolution)
  3229. {
  3230. var keys = Object.keys(this.resolution);
  3231. if(keys.length == 1)
  3232. {
  3233. for(var ssrc in this.resolution)
  3234. {
  3235. resolutionValue = this.resolution[ssrc];
  3236. }
  3237. }
  3238. else if(keys.length > 1)
  3239. {
  3240. var displayedSsrc = simulcast.getReceivingSSRC(this.jid);
  3241. resolutionValue = this.resolution[displayedSsrc];
  3242. }
  3243. }
  3244. if(this.jid === null)
  3245. {
  3246. resolution = "";
  3247. if(this.resolution === null || !Object.keys(this.resolution) ||
  3248. Object.keys(this.resolution).length === 0)
  3249. {
  3250. resolution = "N/A";
  3251. }
  3252. else
  3253. for(i in this.resolution)
  3254. {
  3255. resolutionValue = this.resolution[i];
  3256. if(resolutionValue)
  3257. {
  3258. if(resolutionValue.height &&
  3259. resolutionValue.width)
  3260. {
  3261. resolution += (resolution === ""? "" : ", ") +
  3262. resolutionValue.width + "x" +
  3263. resolutionValue.height;
  3264. }
  3265. }
  3266. }
  3267. }
  3268. else if(!resolutionValue ||
  3269. !resolutionValue.height ||
  3270. !resolutionValue.width)
  3271. {
  3272. resolution = "N/A";
  3273. }
  3274. else
  3275. {
  3276. resolution = resolutionValue.width + "x" + resolutionValue.height;
  3277. }
  3278. var result = "<table style='width:100%'>" +
  3279. "<tr>" +
  3280. "<td><span class='jitsipopover_blue'>Bitrate:</span></td>" +
  3281. "<td><span class='jitsipopover_green'>&darr;</span>" +
  3282. downloadBitrate + " <span class='jitsipopover_orange'>&uarr;</span>" +
  3283. uploadBitrate + "</td>" +
  3284. "</tr><tr>" +
  3285. "<td><span class='jitsipopover_blue'>Packet loss: </span></td>" +
  3286. "<td>" + packetLoss + "</td>" +
  3287. "</tr><tr>" +
  3288. "<td><span class='jitsipopover_blue'>Resolution:</span></td>" +
  3289. "<td>" + resolution + "</td></tr></table>";
  3290. if(this.videoContainer.id == "localVideoContainer")
  3291. result += "<div class=\"jitsipopover_showmore\" " +
  3292. "onclick = \"UI.connectionIndicatorShowMore('" +
  3293. this.videoContainer.id + "')\">" +
  3294. (this.showMoreValue? "Show less" : "Show More") + "</div><br />";
  3295. if(this.showMoreValue)
  3296. {
  3297. var downloadBandwidth, uploadBandwidth, transport;
  3298. if(this.bandwidth === null)
  3299. {
  3300. downloadBandwidth = "N/A";
  3301. uploadBandwidth = "N/A";
  3302. }
  3303. else
  3304. {
  3305. downloadBandwidth = this.bandwidth.download?
  3306. this.bandwidth.download + " Kbps" :
  3307. "N/A";
  3308. uploadBandwidth = this.bandwidth.upload?
  3309. this.bandwidth.upload + " Kbps" :
  3310. "N/A";
  3311. }
  3312. if(!this.transport || this.transport.length === 0)
  3313. {
  3314. transport = "<tr>" +
  3315. "<td><span class='jitsipopover_blue'>Address:</span></td>" +
  3316. "<td> N/A</td></tr>";
  3317. }
  3318. else
  3319. {
  3320. var data = {remoteIP: [], localIP:[], remotePort:[], localPort:[]};
  3321. for(i = 0; i < this.transport.length; i++)
  3322. {
  3323. var ip = ConnectionIndicator.getIP(this.transport[i].ip);
  3324. var port = ConnectionIndicator.getPort(this.transport[i].ip);
  3325. var localIP =
  3326. ConnectionIndicator.getIP(this.transport[i].localip);
  3327. var localPort =
  3328. ConnectionIndicator.getPort(this.transport[i].localip);
  3329. if(data.remoteIP.indexOf(ip) == -1)
  3330. {
  3331. data.remoteIP.push(ip);
  3332. }
  3333. if(data.remotePort.indexOf(port) == -1)
  3334. {
  3335. data.remotePort.push(port);
  3336. }
  3337. if(data.localIP.indexOf(localIP) == -1)
  3338. {
  3339. data.localIP.push(localIP);
  3340. }
  3341. if(data.localPort.indexOf(localPort) == -1)
  3342. {
  3343. data.localPort.push(localPort);
  3344. }
  3345. }
  3346. var localTransport =
  3347. "<tr><td><span class='jitsipopover_blue'>Local address" +
  3348. (data.localIP.length > 1? "es" : "") + ": </span></td><td> " +
  3349. ConnectionIndicator.getStringFromArray(data.localIP) +
  3350. "</td></tr>";
  3351. transport =
  3352. "<tr><td><span class='jitsipopover_blue'>Remote address"+
  3353. (data.remoteIP.length > 1? "es" : "") + ":</span></td><td> " +
  3354. ConnectionIndicator.getStringFromArray(data.remoteIP) +
  3355. "</td></tr>";
  3356. if(this.transport.length > 1)
  3357. {
  3358. transport += "<tr>" +
  3359. "<td>" +
  3360. "<span class='jitsipopover_blue'>Remote ports:</span>" +
  3361. "</td><td>";
  3362. localTransport += "<tr>" +
  3363. "<td>" +
  3364. "<span class='jitsipopover_blue'>Local ports:</span>" +
  3365. "</td><td>";
  3366. }
  3367. else
  3368. {
  3369. transport +=
  3370. "<tr>" +
  3371. "<td>" +
  3372. "<span class='jitsipopover_blue'>Remote port:</span>" +
  3373. "</td><td>";
  3374. localTransport +=
  3375. "<tr>" +
  3376. "<td>" +
  3377. "<span class='jitsipopover_blue'>Local port:</span>" +
  3378. "</td><td>";
  3379. }
  3380. transport +=
  3381. ConnectionIndicator.getStringFromArray(data.remotePort);
  3382. localTransport +=
  3383. ConnectionIndicator.getStringFromArray(data.localPort);
  3384. transport += "</td></tr>";
  3385. transport += localTransport + "</td></tr>";
  3386. transport +="<tr>" +
  3387. "<td><span class='jitsipopover_blue'>Transport:</span></td>" +
  3388. "<td>" + this.transport[0].type + "</td></tr>";
  3389. }
  3390. result += "<table style='width:100%'>" +
  3391. "<tr>" +
  3392. "<td>" +
  3393. "<span class='jitsipopover_blue'>Estimated bandwidth:</span>" +
  3394. "</td><td>" +
  3395. "<span class='jitsipopover_green'>&darr;</span>" +
  3396. downloadBandwidth +
  3397. " <span class='jitsipopover_orange'>&uarr;</span>" +
  3398. uploadBandwidth + "</td></tr>";
  3399. result += transport + "</table>";
  3400. }
  3401. return result;
  3402. };
  3403. /**
  3404. * Shows or hide the additional information.
  3405. */
  3406. ConnectionIndicator.prototype.showMore = function () {
  3407. this.showMoreValue = !this.showMoreValue;
  3408. this.updatePopoverData();
  3409. };
  3410. function createIcon(classes)
  3411. {
  3412. var icon = document.createElement("span");
  3413. for(var i in classes)
  3414. {
  3415. icon.classList.add(classes[i]);
  3416. }
  3417. icon.appendChild(
  3418. document.createElement("i")).classList.add("icon-connection");
  3419. return icon;
  3420. }
  3421. /**
  3422. * Creates the indicator
  3423. */
  3424. ConnectionIndicator.prototype.create = function () {
  3425. this.connectionIndicatorContainer = document.createElement("div");
  3426. this.connectionIndicatorContainer.className = "connectionindicator";
  3427. this.connectionIndicatorContainer.style.display = "none";
  3428. this.videoContainer.appendChild(this.connectionIndicatorContainer);
  3429. this.popover = new JitsiPopover(
  3430. $("#" + this.videoContainer.id + " > .connectionindicator"),
  3431. {content: "<div class=\"connection_info\">Come back here for " +
  3432. "connection information once the conference starts</div>",
  3433. skin: "black"});
  3434. this.emptyIcon = this.connectionIndicatorContainer.appendChild(
  3435. createIcon(["connection", "connection_empty"]));
  3436. this.fullIcon = this.connectionIndicatorContainer.appendChild(
  3437. createIcon(["connection", "connection_full"]));
  3438. };
  3439. /**
  3440. * Removes the indicator
  3441. */
  3442. ConnectionIndicator.prototype.remove = function()
  3443. {
  3444. this.connectionIndicatorContainer.remove();
  3445. this.popover.forceHide();
  3446. };
  3447. /**
  3448. * Updates the data of the indicator
  3449. * @param percent the percent of connection quality
  3450. * @param object the statistics data.
  3451. */
  3452. ConnectionIndicator.prototype.updateConnectionQuality =
  3453. function (percent, object) {
  3454. if(percent === null)
  3455. {
  3456. this.connectionIndicatorContainer.style.display = "none";
  3457. this.popover.forceHide();
  3458. return;
  3459. }
  3460. else
  3461. {
  3462. if(this.connectionIndicatorContainer.style.display == "none") {
  3463. this.connectionIndicatorContainer.style.display = "block";
  3464. this.videoLayout.updateMutePosition(this.videoContainer.id);
  3465. }
  3466. }
  3467. this.bandwidth = object.bandwidth;
  3468. this.bitrate = object.bitrate;
  3469. this.packetLoss = object.packetLoss;
  3470. this.transport = object.transport;
  3471. if(object.resolution)
  3472. {
  3473. this.resolution = object.resolution;
  3474. }
  3475. for(var quality in ConnectionIndicator.connectionQualityValues)
  3476. {
  3477. if(percent >= quality)
  3478. {
  3479. this.fullIcon.style.width =
  3480. ConnectionIndicator.connectionQualityValues[quality];
  3481. }
  3482. }
  3483. this.updatePopoverData();
  3484. };
  3485. /**
  3486. * Updates the resolution
  3487. * @param resolution the new resolution
  3488. */
  3489. ConnectionIndicator.prototype.updateResolution = function (resolution) {
  3490. this.resolution = resolution;
  3491. this.updatePopoverData();
  3492. };
  3493. /**
  3494. * Updates the content of the popover
  3495. */
  3496. ConnectionIndicator.prototype.updatePopoverData = function () {
  3497. this.popover.updateContent(
  3498. "<div class=\"connection_info\">" + this.generateText() + "</div>");
  3499. };
  3500. /**
  3501. * Hides the popover
  3502. */
  3503. ConnectionIndicator.prototype.hide = function () {
  3504. this.popover.forceHide();
  3505. };
  3506. /**
  3507. * Hides the indicator
  3508. */
  3509. ConnectionIndicator.prototype.hideIndicator = function () {
  3510. this.connectionIndicatorContainer.style.display = "none";
  3511. if(this.popover)
  3512. this.popover.forceHide();
  3513. };
  3514. module.exports = ConnectionIndicator;
  3515. },{"../util/JitsiPopover":19}],23:[function(require,module,exports){
  3516. var AudioLevels = require("../audio_levels/AudioLevels");
  3517. var Avatar = require("../avatar/Avatar");
  3518. var Chat = require("../side_pannels/chat/Chat");
  3519. var ContactList = require("../side_pannels/contactlist/ContactList");
  3520. var UIUtil = require("../util/UIUtil");
  3521. var ConnectionIndicator = require("./ConnectionIndicator");
  3522. var currentDominantSpeaker = null;
  3523. var lastNCount = config.channelLastN;
  3524. var localLastNCount = config.channelLastN;
  3525. var localLastNSet = [];
  3526. var lastNEndpointsCache = [];
  3527. var lastNPickupJid = null;
  3528. var largeVideoState = {
  3529. updateInProgress: false,
  3530. newSrc: ''
  3531. };
  3532. var defaultLocalDisplayName = "Me";
  3533. /**
  3534. * Sets the display name for the given video span id.
  3535. */
  3536. function setDisplayName(videoSpanId, displayName) {
  3537. var nameSpan = $('#' + videoSpanId + '>span.displayname');
  3538. var defaultLocalDisplayName = interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME;
  3539. // If we already have a display name for this video.
  3540. if (nameSpan.length > 0) {
  3541. var nameSpanElement = nameSpan.get(0);
  3542. if (nameSpanElement.id === 'localDisplayName' &&
  3543. $('#localDisplayName').text() !== displayName) {
  3544. if (displayName && displayName.length > 0)
  3545. $('#localDisplayName').html(displayName + ' (me)');
  3546. else
  3547. $('#localDisplayName').text(defaultLocalDisplayName);
  3548. } else {
  3549. if (displayName && displayName.length > 0)
  3550. $('#' + videoSpanId + '_name').html(displayName);
  3551. else
  3552. $('#' + videoSpanId + '_name').text(interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
  3553. }
  3554. } else {
  3555. var editButton = null;
  3556. nameSpan = document.createElement('span');
  3557. nameSpan.className = 'displayname';
  3558. $('#' + videoSpanId)[0].appendChild(nameSpan);
  3559. if (videoSpanId === 'localVideoContainer') {
  3560. editButton = createEditDisplayNameButton();
  3561. nameSpan.innerText = defaultLocalDisplayName;
  3562. }
  3563. else {
  3564. nameSpan.innerText = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
  3565. }
  3566. if (displayName && displayName.length > 0) {
  3567. nameSpan.innerText = displayName;
  3568. }
  3569. if (!editButton) {
  3570. nameSpan.id = videoSpanId + '_name';
  3571. } else {
  3572. nameSpan.id = 'localDisplayName';
  3573. $('#' + videoSpanId)[0].appendChild(editButton);
  3574. var editableText = document.createElement('input');
  3575. editableText.className = 'displayname';
  3576. editableText.type = 'text';
  3577. editableText.id = 'editDisplayName';
  3578. if (displayName && displayName.length) {
  3579. editableText.value
  3580. = displayName.substring(0, displayName.indexOf(' (me)'));
  3581. }
  3582. editableText.setAttribute('style', 'display:none;');
  3583. editableText.setAttribute('placeholder', 'ex. Jane Pink');
  3584. $('#' + videoSpanId)[0].appendChild(editableText);
  3585. $('#localVideoContainer .displayname')
  3586. .bind("click", function (e) {
  3587. e.preventDefault();
  3588. e.stopPropagation();
  3589. $('#localDisplayName').hide();
  3590. $('#editDisplayName').show();
  3591. $('#editDisplayName').focus();
  3592. $('#editDisplayName').select();
  3593. $('#editDisplayName').one("focusout", function (e) {
  3594. VideoLayout.inputDisplayNameHandler(this.value);
  3595. });
  3596. $('#editDisplayName').on('keydown', function (e) {
  3597. if (e.keyCode === 13) {
  3598. e.preventDefault();
  3599. VideoLayout.inputDisplayNameHandler(this.value);
  3600. }
  3601. });
  3602. });
  3603. }
  3604. }
  3605. }
  3606. /**
  3607. * Gets the selector of video thumbnail container for the user identified by
  3608. * given <tt>userJid</tt>
  3609. * @param resourceJid user's Jid for whom we want to get the video container.
  3610. */
  3611. function getParticipantContainer(resourceJid)
  3612. {
  3613. if (!resourceJid)
  3614. return null;
  3615. if (resourceJid === Strophe.getResourceFromJid(connection.emuc.myroomjid))
  3616. return $("#localVideoContainer");
  3617. else
  3618. return $("#participant_" + resourceJid);
  3619. }
  3620. /**
  3621. * Sets the size and position of the given video element.
  3622. *
  3623. * @param video the video element to position
  3624. * @param width the desired video width
  3625. * @param height the desired video height
  3626. * @param horizontalIndent the left and right indent
  3627. * @param verticalIndent the top and bottom indent
  3628. */
  3629. function positionVideo(video,
  3630. width,
  3631. height,
  3632. horizontalIndent,
  3633. verticalIndent) {
  3634. video.width(width);
  3635. video.height(height);
  3636. video.css({ top: verticalIndent + 'px',
  3637. bottom: verticalIndent + 'px',
  3638. left: horizontalIndent + 'px',
  3639. right: horizontalIndent + 'px'});
  3640. }
  3641. /**
  3642. * Adds the remote video menu element for the given <tt>jid</tt> in the
  3643. * given <tt>parentElement</tt>.
  3644. *
  3645. * @param jid the jid indicating the video for which we're adding a menu.
  3646. * @param parentElement the parent element where this menu will be added
  3647. */
  3648. function addRemoteVideoMenu(jid, parentElement) {
  3649. var spanElement = document.createElement('span');
  3650. spanElement.className = 'remotevideomenu';
  3651. parentElement.appendChild(spanElement);
  3652. var menuElement = document.createElement('i');
  3653. menuElement.className = 'fa fa-angle-down';
  3654. menuElement.title = 'Remote user controls';
  3655. spanElement.appendChild(menuElement);
  3656. // <ul class="popupmenu">
  3657. // <li><a href="#">Mute</a></li>
  3658. // <li><a href="#">Eject</a></li>
  3659. // </ul>
  3660. var popupmenuElement = document.createElement('ul');
  3661. popupmenuElement.className = 'popupmenu';
  3662. popupmenuElement.id
  3663. = 'remote_popupmenu_' + Strophe.getResourceFromJid(jid);
  3664. spanElement.appendChild(popupmenuElement);
  3665. var muteMenuItem = document.createElement('li');
  3666. var muteLinkItem = document.createElement('a');
  3667. var mutedIndicator = "<i class='icon-mic-disabled'></i>";
  3668. if (!mutedAudios[jid]) {
  3669. muteLinkItem.innerHTML = mutedIndicator + 'Mute';
  3670. muteLinkItem.className = 'mutelink';
  3671. }
  3672. else {
  3673. muteLinkItem.innerHTML = mutedIndicator + ' Muted';
  3674. muteLinkItem.className = 'mutelink disabled';
  3675. }
  3676. muteLinkItem.onclick = function(){
  3677. if ($(this).attr('disabled') != undefined) {
  3678. event.preventDefault();
  3679. }
  3680. var isMute = mutedAudios[jid] == true;
  3681. connection.moderate.setMute(jid, !isMute);
  3682. popupmenuElement.setAttribute('style', 'display:none;');
  3683. if (isMute) {
  3684. this.innerHTML = mutedIndicator + ' Muted';
  3685. this.className = 'mutelink disabled';
  3686. }
  3687. else {
  3688. this.innerHTML = mutedIndicator + ' Mute';
  3689. this.className = 'mutelink';
  3690. }
  3691. };
  3692. muteMenuItem.appendChild(muteLinkItem);
  3693. popupmenuElement.appendChild(muteMenuItem);
  3694. var ejectIndicator = "<i class='fa fa-eject'></i>";
  3695. var ejectMenuItem = document.createElement('li');
  3696. var ejectLinkItem = document.createElement('a');
  3697. ejectLinkItem.innerHTML = ejectIndicator + ' Kick out';
  3698. ejectLinkItem.onclick = function(){
  3699. connection.moderate.eject(jid);
  3700. popupmenuElement.setAttribute('style', 'display:none;');
  3701. };
  3702. ejectMenuItem.appendChild(ejectLinkItem);
  3703. popupmenuElement.appendChild(ejectMenuItem);
  3704. var paddingSpan = document.createElement('span');
  3705. paddingSpan.className = 'popupmenuPadding';
  3706. popupmenuElement.appendChild(paddingSpan);
  3707. }
  3708. /**
  3709. * Removes remote video menu element from video element identified by
  3710. * given <tt>videoElementId</tt>.
  3711. *
  3712. * @param videoElementId the id of local or remote video element.
  3713. */
  3714. function removeRemoteVideoMenu(videoElementId) {
  3715. var menuSpan = $('#' + videoElementId + '>span.remotevideomenu');
  3716. if (menuSpan.length) {
  3717. menuSpan.remove();
  3718. }
  3719. }
  3720. /**
  3721. * Updates the data for the indicator
  3722. * @param id the id of the indicator
  3723. * @param percent the percent for connection quality
  3724. * @param object the data
  3725. */
  3726. function updateStatsIndicator(id, percent, object) {
  3727. if(VideoLayout.connectionIndicators[id])
  3728. VideoLayout.connectionIndicators[id].updateConnectionQuality(percent, object);
  3729. }
  3730. /**
  3731. * Returns an array of the video dimensions, so that it keeps it's aspect
  3732. * ratio and fits available area with it's larger dimension. This method
  3733. * ensures that whole video will be visible and can leave empty areas.
  3734. *
  3735. * @return an array with 2 elements, the video width and the video height
  3736. */
  3737. function getDesktopVideoSize(videoWidth,
  3738. videoHeight,
  3739. videoSpaceWidth,
  3740. videoSpaceHeight) {
  3741. if (!videoWidth)
  3742. videoWidth = currentVideoWidth;
  3743. if (!videoHeight)
  3744. videoHeight = currentVideoHeight;
  3745. var aspectRatio = videoWidth / videoHeight;
  3746. var availableWidth = Math.max(videoWidth, videoSpaceWidth);
  3747. var availableHeight = Math.max(videoHeight, videoSpaceHeight);
  3748. videoSpaceHeight -= $('#remoteVideos').outerHeight();
  3749. if (availableWidth / aspectRatio >= videoSpaceHeight)
  3750. {
  3751. availableHeight = videoSpaceHeight;
  3752. availableWidth = availableHeight * aspectRatio;
  3753. }
  3754. if (availableHeight * aspectRatio >= videoSpaceWidth)
  3755. {
  3756. availableWidth = videoSpaceWidth;
  3757. availableHeight = availableWidth / aspectRatio;
  3758. }
  3759. return [availableWidth, availableHeight];
  3760. }
  3761. /**
  3762. * Creates the edit display name button.
  3763. *
  3764. * @returns the edit button
  3765. */
  3766. function createEditDisplayNameButton() {
  3767. var editButton = document.createElement('a');
  3768. editButton.className = 'displayname';
  3769. Util.setTooltip(editButton,
  3770. 'Click to edit your<br/>display name',
  3771. "top");
  3772. editButton.innerHTML = '<i class="fa fa-pencil"></i>';
  3773. return editButton;
  3774. }
  3775. /**
  3776. * Creates the element indicating the moderator(owner) of the conference.
  3777. *
  3778. * @param parentElement the parent element where the owner indicator will
  3779. * be added
  3780. */
  3781. function createModeratorIndicatorElement(parentElement) {
  3782. var moderatorIndicator = document.createElement('i');
  3783. moderatorIndicator.className = 'fa fa-star';
  3784. parentElement.appendChild(moderatorIndicator);
  3785. Util.setTooltip(parentElement,
  3786. "The owner of<br/>this conference",
  3787. "top");
  3788. }
  3789. var VideoLayout = (function (my) {
  3790. my.connectionIndicators = {};
  3791. my.isInLastN = function(resource) {
  3792. return lastNCount < 0 // lastN is disabled, return true
  3793. || (lastNCount > 0 && lastNEndpointsCache.length == 0) // lastNEndpoints cache not built yet, return true
  3794. || (lastNEndpointsCache && lastNEndpointsCache.indexOf(resource) !== -1);
  3795. };
  3796. my.changeLocalStream = function (stream) {
  3797. connection.jingle.localAudio = stream;
  3798. VideoLayout.changeLocalVideo(stream, true);
  3799. };
  3800. my.changeLocalAudio = function(stream) {
  3801. connection.jingle.localAudio = stream;
  3802. RTC.attachMediaStream($('#localAudio'), stream);
  3803. document.getElementById('localAudio').autoplay = true;
  3804. document.getElementById('localAudio').volume = 0;
  3805. if (preMuted) {
  3806. setAudioMuted(true);
  3807. preMuted = false;
  3808. }
  3809. };
  3810. my.changeLocalVideo = function(stream, flipX) {
  3811. connection.jingle.localVideo = stream;
  3812. var localVideo = document.createElement('video');
  3813. localVideo.id = 'localVideo_' + RTC.getStreamID(stream);
  3814. localVideo.autoplay = true;
  3815. localVideo.volume = 0; // is it required if audio is separated ?
  3816. localVideo.oncontextmenu = function () { return false; };
  3817. var localVideoContainer = document.getElementById('localVideoWrapper');
  3818. localVideoContainer.appendChild(localVideo);
  3819. // Set default display name.
  3820. setDisplayName('localVideoContainer');
  3821. if(!VideoLayout.connectionIndicators["localVideoContainer"]) {
  3822. VideoLayout.connectionIndicators["localVideoContainer"]
  3823. = new ConnectionIndicator($("#localVideoContainer")[0], null, VideoLayout);
  3824. }
  3825. AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
  3826. var localVideoSelector = $('#' + localVideo.id);
  3827. // Add click handler to both video and video wrapper elements in case
  3828. // there's no video.
  3829. localVideoSelector.click(function (event) {
  3830. event.stopPropagation();
  3831. VideoLayout.handleVideoThumbClicked(
  3832. RTC.getVideoSrc(localVideo),
  3833. false,
  3834. Strophe.getResourceFromJid(connection.emuc.myroomjid));
  3835. });
  3836. $('#localVideoContainer').click(function (event) {
  3837. event.stopPropagation();
  3838. VideoLayout.handleVideoThumbClicked(
  3839. RTC.getVideoSrc(localVideo),
  3840. false,
  3841. Strophe.getResourceFromJid(connection.emuc.myroomjid));
  3842. });
  3843. // Add hover handler
  3844. $('#localVideoContainer').hover(
  3845. function() {
  3846. VideoLayout.showDisplayName('localVideoContainer', true);
  3847. },
  3848. function() {
  3849. if (!VideoLayout.isLargeVideoVisible()
  3850. || RTC.getVideoSrc(localVideo) !== RTC.getVideoSrc($('#largeVideo')[0]))
  3851. VideoLayout.showDisplayName('localVideoContainer', false);
  3852. }
  3853. );
  3854. // Add stream ended handler
  3855. stream.onended = function () {
  3856. localVideoContainer.removeChild(localVideo);
  3857. VideoLayout.updateRemovedVideo(RTC.getVideoSrc(localVideo));
  3858. };
  3859. // Flip video x axis if needed
  3860. flipXLocalVideo = flipX;
  3861. if (flipX) {
  3862. localVideoSelector.addClass("flipVideoX");
  3863. }
  3864. // Attach WebRTC stream
  3865. var videoStream = simulcast.getLocalVideoStream();
  3866. RTC.attachMediaStream(localVideoSelector, videoStream);
  3867. localVideoSrc = RTC.getVideoSrc(localVideo);
  3868. var myResourceJid = null;
  3869. if(connection.emuc.myroomjid)
  3870. {
  3871. myResourceJid = Strophe.getResourceFromJid(connection.emuc.myroomjid);
  3872. }
  3873. VideoLayout.updateLargeVideo(localVideoSrc, 0,
  3874. myResourceJid);
  3875. };
  3876. /**
  3877. * Checks if removed video is currently displayed and tries to display
  3878. * another one instead.
  3879. * @param removedVideoSrc src stream identifier of the video.
  3880. */
  3881. my.updateRemovedVideo = function(removedVideoSrc) {
  3882. if (removedVideoSrc === RTC.getVideoSrc($('#largeVideo')[0])) {
  3883. // this is currently displayed as large
  3884. // pick the last visible video in the row
  3885. // if nobody else is left, this picks the local video
  3886. var pick
  3887. = $('#remoteVideos>span[id!="mixedstream"]:visible:last>video')
  3888. .get(0);
  3889. if (!pick) {
  3890. console.info("Last visible video no longer exists");
  3891. pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0);
  3892. if (!pick || !RTC.getVideoSrc(pick)) {
  3893. // Try local video
  3894. console.info("Fallback to local video...");
  3895. pick = $('#remoteVideos>span>span>video').get(0);
  3896. }
  3897. }
  3898. // mute if localvideo
  3899. if (pick) {
  3900. var container = pick.parentNode;
  3901. var jid = null;
  3902. if(container)
  3903. {
  3904. if(container.id == "localVideoWrapper")
  3905. {
  3906. jid = Strophe.getResourceFromJid(connection.emuc.myroomjid);
  3907. }
  3908. else
  3909. {
  3910. jid = VideoLayout.getPeerContainerResourceJid(container);
  3911. }
  3912. }
  3913. VideoLayout.updateLargeVideo(RTC.getVideoSrc(pick), pick.volume, jid);
  3914. } else {
  3915. console.warn("Failed to elect large video");
  3916. }
  3917. }
  3918. };
  3919. my.onRemoteStreamAdded = function (stream) {
  3920. var container;
  3921. var remotes = document.getElementById('remoteVideos');
  3922. if (stream.peerjid) {
  3923. VideoLayout.ensurePeerContainerExists(stream.peerjid);
  3924. container = document.getElementById(
  3925. 'participant_' + Strophe.getResourceFromJid(stream.peerjid));
  3926. } else {
  3927. var id = stream.getOriginalStream().id;
  3928. if (id !== 'mixedmslabel'
  3929. // FIXME: default stream is added always with new focus
  3930. // (to be investigated)
  3931. && id !== 'default') {
  3932. console.error('can not associate stream',
  3933. id,
  3934. 'with a participant');
  3935. // We don't want to add it here since it will cause troubles
  3936. return;
  3937. }
  3938. // FIXME: for the mixed ms we dont need a video -- currently
  3939. container = document.createElement('span');
  3940. container.id = 'mixedstream';
  3941. container.className = 'videocontainer';
  3942. remotes.appendChild(container);
  3943. Util.playSoundNotification('userJoined');
  3944. }
  3945. if (container) {
  3946. VideoLayout.addRemoteStreamElement( container,
  3947. stream.sid,
  3948. stream.getOriginalStream(),
  3949. stream.peerjid,
  3950. stream.ssrc);
  3951. }
  3952. }
  3953. my.getLargeVideoState = function () {
  3954. return largeVideoState;
  3955. };
  3956. /**
  3957. * Updates the large video with the given new video source.
  3958. */
  3959. my.updateLargeVideo = function(newSrc, vol, resourceJid) {
  3960. console.log('hover in', newSrc);
  3961. if (RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc) {
  3962. $('#activeSpeaker').css('visibility', 'hidden');
  3963. // Due to the simulcast the localVideoSrc may have changed when the
  3964. // fadeOut event triggers. In that case the getJidFromVideoSrc and
  3965. // isVideoSrcDesktop methods will not function correctly.
  3966. //
  3967. // Also, again due to the simulcast, the updateLargeVideo method can
  3968. // be called multiple times almost simultaneously. Therefore, we
  3969. // store the state here and update only once.
  3970. largeVideoState.newSrc = newSrc;
  3971. largeVideoState.isVisible = $('#largeVideo').is(':visible');
  3972. largeVideoState.isDesktop = isVideoSrcDesktop(resourceJid);
  3973. if(jid2Ssrc[largeVideoState.userResourceJid] ||
  3974. (connection && connection.emuc.myroomjid &&
  3975. largeVideoState.userResourceJid ===
  3976. Strophe.getResourceFromJid(connection.emuc.myroomjid))) {
  3977. largeVideoState.oldResourceJid = largeVideoState.userResourceJid;
  3978. } else {
  3979. largeVideoState.oldResourceJid = null;
  3980. }
  3981. largeVideoState.userResourceJid = resourceJid;
  3982. // Screen stream is already rotated
  3983. largeVideoState.flipX = (newSrc === localVideoSrc) && flipXLocalVideo;
  3984. var userChanged = false;
  3985. if (largeVideoState.oldResourceJid !== largeVideoState.userResourceJid) {
  3986. userChanged = true;
  3987. // we want the notification to trigger even if userJid is undefined,
  3988. // or null.
  3989. $(document).trigger("selectedendpointchanged", [largeVideoState.userResourceJid]);
  3990. }
  3991. if (!largeVideoState.updateInProgress) {
  3992. largeVideoState.updateInProgress = true;
  3993. var doUpdate = function () {
  3994. Avatar.updateActiveSpeakerAvatarSrc(
  3995. connection.emuc.findJidFromResource(
  3996. largeVideoState.userResourceJid));
  3997. if (!userChanged && largeVideoState.preload &&
  3998. largeVideoState.preload !== null &&
  3999. RTC.getVideoSrc($(largeVideoState.preload)[0]) === newSrc)
  4000. {
  4001. console.info('Switching to preloaded video');
  4002. var attributes = $('#largeVideo').prop("attributes");
  4003. // loop through largeVideo attributes and apply them on
  4004. // preload.
  4005. $.each(attributes, function () {
  4006. if (this.name !== 'id' && this.name !== 'src') {
  4007. largeVideoState.preload.attr(this.name, this.value);
  4008. }
  4009. });
  4010. largeVideoState.preload.appendTo($('#largeVideoContainer'));
  4011. $('#largeVideo').attr('id', 'previousLargeVideo');
  4012. largeVideoState.preload.attr('id', 'largeVideo');
  4013. $('#previousLargeVideo').remove();
  4014. largeVideoState.preload.on('loadedmetadata', function (e) {
  4015. currentVideoWidth = this.videoWidth;
  4016. currentVideoHeight = this.videoHeight;
  4017. VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
  4018. });
  4019. largeVideoState.preload = null;
  4020. largeVideoState.preload_ssrc = 0;
  4021. } else {
  4022. RTC.setVideoSrc($('#largeVideo')[0], largeVideoState.newSrc);
  4023. }
  4024. var videoTransform = document.getElementById('largeVideo')
  4025. .style.webkitTransform;
  4026. if (largeVideoState.flipX && videoTransform !== 'scaleX(-1)') {
  4027. document.getElementById('largeVideo').style.webkitTransform
  4028. = "scaleX(-1)";
  4029. }
  4030. else if (!largeVideoState.flipX && videoTransform === 'scaleX(-1)') {
  4031. document.getElementById('largeVideo').style.webkitTransform
  4032. = "none";
  4033. }
  4034. // Change the way we'll be measuring and positioning large video
  4035. getVideoSize = largeVideoState.isDesktop
  4036. ? getDesktopVideoSize
  4037. : getCameraVideoSize;
  4038. getVideoPosition = largeVideoState.isDesktop
  4039. ? getDesktopVideoPosition
  4040. : getCameraVideoPosition;
  4041. // Only if the large video is currently visible.
  4042. // Disable previous dominant speaker video.
  4043. if (largeVideoState.oldResourceJid) {
  4044. VideoLayout.enableDominantSpeaker(
  4045. largeVideoState.oldResourceJid,
  4046. false);
  4047. }
  4048. // Enable new dominant speaker in the remote videos section.
  4049. if (largeVideoState.userResourceJid) {
  4050. VideoLayout.enableDominantSpeaker(
  4051. largeVideoState.userResourceJid,
  4052. true);
  4053. }
  4054. if (userChanged && largeVideoState.isVisible) {
  4055. // using "this" should be ok because we're called
  4056. // from within the fadeOut event.
  4057. $(this).fadeIn(300);
  4058. }
  4059. if(userChanged) {
  4060. Avatar.showUserAvatar(
  4061. connection.emuc.findJidFromResource(
  4062. largeVideoState.oldResourceJid));
  4063. }
  4064. largeVideoState.updateInProgress = false;
  4065. };
  4066. if (userChanged) {
  4067. $('#largeVideo').fadeOut(300, doUpdate);
  4068. } else {
  4069. doUpdate();
  4070. }
  4071. }
  4072. } else {
  4073. Avatar.showUserAvatar(
  4074. connection.emuc.findJidFromResource(
  4075. largeVideoState.userResourceJid));
  4076. }
  4077. };
  4078. my.handleVideoThumbClicked = function(videoSrc,
  4079. noPinnedEndpointChangedEvent,
  4080. resourceJid) {
  4081. // Restore style for previously focused video
  4082. var oldContainer = null;
  4083. if(focusedVideoInfo) {
  4084. var focusResourceJid = focusedVideoInfo.resourceJid;
  4085. oldContainer = getParticipantContainer(focusResourceJid);
  4086. }
  4087. if (oldContainer) {
  4088. oldContainer.removeClass("videoContainerFocused");
  4089. }
  4090. // Unlock current focused.
  4091. if (focusedVideoInfo && focusedVideoInfo.src === videoSrc)
  4092. {
  4093. focusedVideoInfo = null;
  4094. var dominantSpeakerVideo = null;
  4095. // Enable the currently set dominant speaker.
  4096. if (currentDominantSpeaker) {
  4097. dominantSpeakerVideo
  4098. = $('#participant_' + currentDominantSpeaker + '>video')
  4099. .get(0);
  4100. if (dominantSpeakerVideo) {
  4101. VideoLayout.updateLargeVideo(
  4102. RTC.getVideoSrc(dominantSpeakerVideo),
  4103. 1,
  4104. currentDominantSpeaker);
  4105. }
  4106. }
  4107. if (!noPinnedEndpointChangedEvent) {
  4108. $(document).trigger("pinnedendpointchanged");
  4109. }
  4110. return;
  4111. }
  4112. // Lock new video
  4113. focusedVideoInfo = {
  4114. src: videoSrc,
  4115. resourceJid: resourceJid
  4116. };
  4117. // Update focused/pinned interface.
  4118. if (resourceJid)
  4119. {
  4120. var container = getParticipantContainer(resourceJid);
  4121. container.addClass("videoContainerFocused");
  4122. if (!noPinnedEndpointChangedEvent) {
  4123. $(document).trigger("pinnedendpointchanged", [resourceJid]);
  4124. }
  4125. }
  4126. if ($('#largeVideo').attr('src') === videoSrc &&
  4127. VideoLayout.isLargeVideoOnTop()) {
  4128. return;
  4129. }
  4130. // Triggers a "video.selected" event. The "false" parameter indicates
  4131. // this isn't a prezi.
  4132. $(document).trigger("video.selected", [false]);
  4133. VideoLayout.updateLargeVideo(videoSrc, 1, resourceJid);
  4134. $('audio').each(function (idx, el) {
  4135. if (el.id.indexOf('mixedmslabel') !== -1) {
  4136. el.volume = 0;
  4137. el.volume = 1;
  4138. }
  4139. });
  4140. };
  4141. /**
  4142. * Positions the large video.
  4143. *
  4144. * @param videoWidth the stream video width
  4145. * @param videoHeight the stream video height
  4146. */
  4147. my.positionLarge = function (videoWidth, videoHeight) {
  4148. var videoSpaceWidth = $('#videospace').width();
  4149. var videoSpaceHeight = window.innerHeight;
  4150. var videoSize = getVideoSize(videoWidth,
  4151. videoHeight,
  4152. videoSpaceWidth,
  4153. videoSpaceHeight);
  4154. var largeVideoWidth = videoSize[0];
  4155. var largeVideoHeight = videoSize[1];
  4156. var videoPosition = getVideoPosition(largeVideoWidth,
  4157. largeVideoHeight,
  4158. videoSpaceWidth,
  4159. videoSpaceHeight);
  4160. var horizontalIndent = videoPosition[0];
  4161. var verticalIndent = videoPosition[1];
  4162. positionVideo($('#largeVideo'),
  4163. largeVideoWidth,
  4164. largeVideoHeight,
  4165. horizontalIndent, verticalIndent);
  4166. };
  4167. /**
  4168. * Shows/hides the large video.
  4169. */
  4170. my.setLargeVideoVisible = function(isVisible) {
  4171. var resourceJid = largeVideoState.userResourceJid;
  4172. if (isVisible) {
  4173. $('#largeVideo').css({visibility: 'visible'});
  4174. $('.watermark').css({visibility: 'visible'});
  4175. VideoLayout.enableDominantSpeaker(resourceJid, true);
  4176. }
  4177. else {
  4178. $('#largeVideo').css({visibility: 'hidden'});
  4179. $('#activeSpeaker').css('visibility', 'hidden');
  4180. $('.watermark').css({visibility: 'hidden'});
  4181. VideoLayout.enableDominantSpeaker(resourceJid, false);
  4182. if(focusedVideoInfo) {
  4183. var focusResourceJid = focusedVideoInfo.resourceJid;
  4184. var oldContainer = getParticipantContainer(focusResourceJid);
  4185. if (oldContainer && oldContainer.length > 0) {
  4186. oldContainer.removeClass("videoContainerFocused");
  4187. }
  4188. focusedVideoInfo = null;
  4189. if(focusResourceJid) {
  4190. Avatar.showUserAvatar(
  4191. connection.emuc.findJidFromResource(focusResourceJid));
  4192. }
  4193. }
  4194. }
  4195. };
  4196. /**
  4197. * Indicates if the large video is currently visible.
  4198. *
  4199. * @return <tt>true</tt> if visible, <tt>false</tt> - otherwise
  4200. */
  4201. my.isLargeVideoVisible = function() {
  4202. return $('#largeVideo').is(':visible');
  4203. };
  4204. my.isLargeVideoOnTop = function () {
  4205. var Etherpad = require("../etherpad/Etherpad");
  4206. var Prezi = require("../prezi/Prezi");
  4207. return !Prezi.isPresentationVisible() && !Etherpad.isVisible();
  4208. };
  4209. /**
  4210. * Checks if container for participant identified by given peerJid exists
  4211. * in the document and creates it eventually.
  4212. *
  4213. * @param peerJid peer Jid to check.
  4214. * @param userId user email or id for setting the avatar
  4215. *
  4216. * @return Returns <tt>true</tt> if the peer container exists,
  4217. * <tt>false</tt> - otherwise
  4218. */
  4219. my.ensurePeerContainerExists = function(peerJid, userId) {
  4220. ContactList.ensureAddContact(peerJid, userId);
  4221. var resourceJid = Strophe.getResourceFromJid(peerJid);
  4222. var videoSpanId = 'participant_' + resourceJid;
  4223. if ($('#' + videoSpanId).length > 0) {
  4224. // If there's been a focus change, make sure we add focus related
  4225. // interface!!
  4226. if (Moderator.isModerator() && !Moderator.isPeerModerator(peerJid)
  4227. && $('#remote_popupmenu_' + resourceJid).length <= 0) {
  4228. addRemoteVideoMenu(peerJid,
  4229. document.getElementById(videoSpanId));
  4230. }
  4231. }
  4232. else {
  4233. var container =
  4234. VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId, userId);
  4235. Avatar.setUserAvatar(peerJid, userId);
  4236. // Set default display name.
  4237. setDisplayName(videoSpanId);
  4238. VideoLayout.connectionIndicators[videoSpanId] =
  4239. new ConnectionIndicator(container, peerJid, VideoLayout);
  4240. var nickfield = document.createElement('span');
  4241. nickfield.className = "nick";
  4242. nickfield.appendChild(document.createTextNode(resourceJid));
  4243. container.appendChild(nickfield);
  4244. // In case this is not currently in the last n we don't show it.
  4245. if (localLastNCount
  4246. && localLastNCount > 0
  4247. && $('#remoteVideos>span').length >= localLastNCount + 2) {
  4248. showPeerContainer(resourceJid, 'hide');
  4249. }
  4250. else
  4251. VideoLayout.resizeThumbnails();
  4252. }
  4253. };
  4254. my.addRemoteVideoContainer = function(peerJid, spanId) {
  4255. var container = document.createElement('span');
  4256. container.id = spanId;
  4257. container.className = 'videocontainer';
  4258. var remotes = document.getElementById('remoteVideos');
  4259. // If the peerJid is null then this video span couldn't be directly
  4260. // associated with a participant (this could happen in the case of prezi).
  4261. if (Moderator.isModerator() && peerJid !== null)
  4262. addRemoteVideoMenu(peerJid, container);
  4263. remotes.appendChild(container);
  4264. AudioLevels.updateAudioLevelCanvas(peerJid, VideoLayout);
  4265. return container;
  4266. };
  4267. /**
  4268. * Creates an audio or video stream element.
  4269. */
  4270. my.createStreamElement = function (sid, stream) {
  4271. var isVideo = stream.getVideoTracks().length > 0;
  4272. var element = isVideo
  4273. ? document.createElement('video')
  4274. : document.createElement('audio');
  4275. var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_')
  4276. + sid + '_' + RTC.getStreamID(stream);
  4277. element.id = id;
  4278. element.autoplay = true;
  4279. element.oncontextmenu = function () { return false; };
  4280. return element;
  4281. };
  4282. my.addRemoteStreamElement
  4283. = function (container, sid, stream, peerJid, thessrc) {
  4284. var newElementId = null;
  4285. var isVideo = stream.getVideoTracks().length > 0;
  4286. if (container) {
  4287. var streamElement = VideoLayout.createStreamElement(sid, stream);
  4288. newElementId = streamElement.id;
  4289. container.appendChild(streamElement);
  4290. var sel = $('#' + newElementId);
  4291. sel.hide();
  4292. // If the container is currently visible we attach the stream.
  4293. if (!isVideo
  4294. || (container.offsetParent !== null && isVideo)) {
  4295. var videoStream = simulcast.getReceivingVideoStream(stream);
  4296. RTC.attachMediaStream(sel, videoStream);
  4297. if (isVideo)
  4298. waitForRemoteVideo(sel, thessrc, stream, peerJid);
  4299. }
  4300. stream.onended = function () {
  4301. console.log('stream ended', this);
  4302. VideoLayout.removeRemoteStreamElement(
  4303. stream, isVideo, container);
  4304. // NOTE(gp) it seems that under certain circumstances, the
  4305. // onended event is not fired and thus the contact list is not
  4306. // updated.
  4307. //
  4308. // The onended event of a stream should be fired when the SSRCs
  4309. // corresponding to that stream are removed from the SDP; but
  4310. // this doesn't seem to always be the case, resulting in ghost
  4311. // contacts.
  4312. //
  4313. // In an attempt to fix the ghost contacts problem, I'm moving
  4314. // the removeContact() method call in app.js, inside the
  4315. // 'muc.left' event handler.
  4316. //if (peerJid)
  4317. // ContactList.removeContact(peerJid);
  4318. };
  4319. // Add click handler.
  4320. container.onclick = function (event) {
  4321. /*
  4322. * FIXME It turns out that videoThumb may not exist (if there is
  4323. * no actual video).
  4324. */
  4325. var videoThumb = $('#' + container.id + '>video').get(0);
  4326. if (videoThumb) {
  4327. VideoLayout.handleVideoThumbClicked(
  4328. RTC.getVideoSrc(videoThumb),
  4329. false,
  4330. Strophe.getResourceFromJid(peerJid));
  4331. }
  4332. event.stopPropagation();
  4333. event.preventDefault();
  4334. return false;
  4335. };
  4336. // Add hover handler
  4337. $(container).hover(
  4338. function() {
  4339. VideoLayout.showDisplayName(container.id, true);
  4340. },
  4341. function() {
  4342. var videoSrc = null;
  4343. if ($('#' + container.id + '>video')
  4344. && $('#' + container.id + '>video').length > 0) {
  4345. videoSrc = RTC.getVideoSrc($('#' + container.id + '>video').get(0));
  4346. }
  4347. // If the video has been "pinned" by the user we want to
  4348. // keep the display name on place.
  4349. if (!VideoLayout.isLargeVideoVisible()
  4350. || videoSrc !== RTC.getVideoSrc($('#largeVideo')[0]))
  4351. VideoLayout.showDisplayName(container.id, false);
  4352. }
  4353. );
  4354. }
  4355. return newElementId;
  4356. };
  4357. /**
  4358. * Removes the remote stream element corresponding to the given stream and
  4359. * parent container.
  4360. *
  4361. * @param stream the stream
  4362. * @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
  4363. * @param container
  4364. */
  4365. my.removeRemoteStreamElement = function (stream, isVideo, container) {
  4366. if (!container)
  4367. return;
  4368. var select = null;
  4369. var removedVideoSrc = null;
  4370. if (isVideo) {
  4371. select = $('#' + container.id + '>video');
  4372. removedVideoSrc = RTC.getVideoSrc(select.get(0));
  4373. }
  4374. else
  4375. select = $('#' + container.id + '>audio');
  4376. // Mark video as removed to cancel waiting loop(if video is removed
  4377. // before has started)
  4378. select.removed = true;
  4379. select.remove();
  4380. var audioCount = $('#' + container.id + '>audio').length;
  4381. var videoCount = $('#' + container.id + '>video').length;
  4382. if (!audioCount && !videoCount) {
  4383. console.log("Remove whole user", container.id);
  4384. if(VideoLayout.connectionIndicators[container.id])
  4385. VideoLayout.connectionIndicators[container.id].remove();
  4386. // Remove whole container
  4387. container.remove();
  4388. Util.playSoundNotification('userLeft');
  4389. VideoLayout.resizeThumbnails();
  4390. }
  4391. if (removedVideoSrc)
  4392. VideoLayout.updateRemovedVideo(removedVideoSrc);
  4393. };
  4394. /**
  4395. * Show/hide peer container for the given resourceJid.
  4396. */
  4397. function showPeerContainer(resourceJid, state) {
  4398. var peerContainer = $('#participant_' + resourceJid);
  4399. if (!peerContainer)
  4400. return;
  4401. var isHide = state === 'hide';
  4402. var resizeThumbnails = false;
  4403. if (!isHide) {
  4404. if (!peerContainer.is(':visible')) {
  4405. resizeThumbnails = true;
  4406. peerContainer.show();
  4407. }
  4408. if (state == 'show')
  4409. {
  4410. // peerContainer.css('-webkit-filter', '');
  4411. var jid = connection.emuc.findJidFromResource(resourceJid);
  4412. Avatar.showUserAvatar(jid, false);
  4413. }
  4414. else // if (state == 'avatar')
  4415. {
  4416. // peerContainer.css('-webkit-filter', 'grayscale(100%)');
  4417. var jid = connection.emuc.findJidFromResource(resourceJid);
  4418. Avatar.showUserAvatar(jid, true);
  4419. }
  4420. }
  4421. else if (peerContainer.is(':visible') && isHide)
  4422. {
  4423. resizeThumbnails = true;
  4424. peerContainer.hide();
  4425. if(VideoLayout.connectionIndicators['participant_' + resourceJid])
  4426. VideoLayout.connectionIndicators['participant_' + resourceJid].hide();
  4427. }
  4428. if (resizeThumbnails) {
  4429. VideoLayout.resizeThumbnails();
  4430. }
  4431. // We want to be able to pin a participant from the contact list, even
  4432. // if he's not in the lastN set!
  4433. // ContactList.setClickable(resourceJid, !isHide);
  4434. };
  4435. my.inputDisplayNameHandler = function (name) {
  4436. if (name && nickname !== name) {
  4437. nickname = name;
  4438. window.localStorage.displayname = nickname;
  4439. connection.emuc.addDisplayNameToPresence(nickname);
  4440. connection.emuc.sendPresence();
  4441. Chat.setChatConversationMode(true);
  4442. }
  4443. if (!$('#localDisplayName').is(":visible")) {
  4444. if (nickname)
  4445. $('#localDisplayName').text(nickname + " (me)");
  4446. else
  4447. $('#localDisplayName')
  4448. .text(interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
  4449. $('#localDisplayName').show();
  4450. }
  4451. $('#editDisplayName').hide();
  4452. };
  4453. /**
  4454. * Shows/hides the display name on the remote video.
  4455. * @param videoSpanId the identifier of the video span element
  4456. * @param isShow indicates if the display name should be shown or hidden
  4457. */
  4458. my.showDisplayName = function(videoSpanId, isShow) {
  4459. var nameSpan = $('#' + videoSpanId + '>span.displayname').get(0);
  4460. if (isShow) {
  4461. if (nameSpan && nameSpan.innerHTML && nameSpan.innerHTML.length)
  4462. nameSpan.setAttribute("style", "display:inline-block;");
  4463. }
  4464. else {
  4465. if (nameSpan)
  4466. nameSpan.setAttribute("style", "display:none;");
  4467. }
  4468. };
  4469. /**
  4470. * Shows the presence status message for the given video.
  4471. */
  4472. my.setPresenceStatus = function (videoSpanId, statusMsg) {
  4473. if (!$('#' + videoSpanId).length) {
  4474. // No container
  4475. return;
  4476. }
  4477. var statusSpan = $('#' + videoSpanId + '>span.status');
  4478. if (!statusSpan.length) {
  4479. //Add status span
  4480. statusSpan = document.createElement('span');
  4481. statusSpan.className = 'status';
  4482. statusSpan.id = videoSpanId + '_status';
  4483. $('#' + videoSpanId)[0].appendChild(statusSpan);
  4484. statusSpan = $('#' + videoSpanId + '>span.status');
  4485. }
  4486. // Display status
  4487. if (statusMsg && statusMsg.length) {
  4488. $('#' + videoSpanId + '_status').text(statusMsg);
  4489. statusSpan.get(0).setAttribute("style", "display:inline-block;");
  4490. }
  4491. else {
  4492. // Hide
  4493. statusSpan.get(0).setAttribute("style", "display:none;");
  4494. }
  4495. };
  4496. /**
  4497. * Shows a visual indicator for the moderator of the conference.
  4498. */
  4499. my.showModeratorIndicator = function () {
  4500. if (Moderator.isModerator()) {
  4501. var indicatorSpan = $('#localVideoContainer .focusindicator');
  4502. if (indicatorSpan.children().length === 0)
  4503. {
  4504. createModeratorIndicatorElement(indicatorSpan[0]);
  4505. }
  4506. }
  4507. Object.keys(connection.emuc.members).forEach(function (jid) {
  4508. var member = connection.emuc.members[jid];
  4509. if (member.role === 'moderator') {
  4510. var moderatorId
  4511. = 'participant_' + Strophe.getResourceFromJid(jid);
  4512. var moderatorContainer
  4513. = document.getElementById(moderatorId);
  4514. if (Strophe.getResourceFromJid(jid) === 'focus') {
  4515. // Skip server side focus
  4516. return;
  4517. }
  4518. if (!moderatorContainer) {
  4519. console.error("No moderator container for " + jid);
  4520. return;
  4521. }
  4522. var menuSpan = $('#' + moderatorId + '>span.remotevideomenu');
  4523. if (menuSpan.length) {
  4524. removeRemoteVideoMenu(moderatorId);
  4525. }
  4526. var indicatorSpan
  4527. = $('#' + moderatorId + ' .focusindicator');
  4528. if (!indicatorSpan || indicatorSpan.length === 0) {
  4529. indicatorSpan = document.createElement('span');
  4530. indicatorSpan.className = 'focusindicator';
  4531. moderatorContainer.appendChild(indicatorSpan);
  4532. createModeratorIndicatorElement(indicatorSpan);
  4533. }
  4534. }
  4535. });
  4536. };
  4537. /**
  4538. * Shows video muted indicator over small videos.
  4539. */
  4540. my.showVideoIndicator = function(videoSpanId, isMuted) {
  4541. var videoMutedSpan = $('#' + videoSpanId + '>span.videoMuted');
  4542. if (isMuted === 'false') {
  4543. if (videoMutedSpan.length > 0) {
  4544. videoMutedSpan.remove();
  4545. }
  4546. }
  4547. else {
  4548. if(videoMutedSpan.length == 0) {
  4549. videoMutedSpan = document.createElement('span');
  4550. videoMutedSpan.className = 'videoMuted';
  4551. $('#' + videoSpanId)[0].appendChild(videoMutedSpan);
  4552. var mutedIndicator = document.createElement('i');
  4553. mutedIndicator.className = 'icon-camera-disabled';
  4554. Util.setTooltip(mutedIndicator,
  4555. "Participant has<br/>stopped the camera.",
  4556. "top");
  4557. videoMutedSpan.appendChild(mutedIndicator);
  4558. }
  4559. VideoLayout.updateMutePosition(videoSpanId);
  4560. }
  4561. };
  4562. my.updateMutePosition = function (videoSpanId) {
  4563. var audioMutedSpan = $('#' + videoSpanId + '>span.audioMuted');
  4564. var connectionIndicator = $('#' + videoSpanId + '>div.connectionindicator');
  4565. var videoMutedSpan = $('#' + videoSpanId + '>span.videoMuted');
  4566. if(connectionIndicator.length > 0
  4567. && connectionIndicator[0].style.display != "none") {
  4568. audioMutedSpan.css({right: "23px"});
  4569. videoMutedSpan.css({right: ((audioMutedSpan.length > 0? 23 : 0) + 30) + "px"});
  4570. }
  4571. else
  4572. {
  4573. audioMutedSpan.css({right: "0px"});
  4574. videoMutedSpan.css({right: (audioMutedSpan.length > 0? 30 : 0) + "px"});
  4575. }
  4576. }
  4577. /**
  4578. * Shows audio muted indicator over small videos.
  4579. * @param {string} isMuted
  4580. */
  4581. my.showAudioIndicator = function(videoSpanId, isMuted) {
  4582. var audioMutedSpan = $('#' + videoSpanId + '>span.audioMuted');
  4583. if (isMuted === 'false') {
  4584. if (audioMutedSpan.length > 0) {
  4585. audioMutedSpan.popover('hide');
  4586. audioMutedSpan.remove();
  4587. }
  4588. }
  4589. else {
  4590. if(audioMutedSpan.length == 0 ) {
  4591. audioMutedSpan = document.createElement('span');
  4592. audioMutedSpan.className = 'audioMuted';
  4593. Util.setTooltip(audioMutedSpan,
  4594. "Participant is muted",
  4595. "top");
  4596. $('#' + videoSpanId)[0].appendChild(audioMutedSpan);
  4597. var mutedIndicator = document.createElement('i');
  4598. mutedIndicator.className = 'icon-mic-disabled';
  4599. audioMutedSpan.appendChild(mutedIndicator);
  4600. }
  4601. VideoLayout.updateMutePosition(videoSpanId);
  4602. }
  4603. };
  4604. /*
  4605. * Shows or hides the audio muted indicator over the local thumbnail video.
  4606. * @param {boolean} isMuted
  4607. */
  4608. my.showLocalAudioIndicator = function(isMuted) {
  4609. VideoLayout.showAudioIndicator('localVideoContainer', isMuted.toString());
  4610. };
  4611. /**
  4612. * Resizes the large video container.
  4613. */
  4614. my.resizeLargeVideoContainer = function () {
  4615. Chat.resizeChat();
  4616. var availableHeight = window.innerHeight;
  4617. var availableWidth = UIUtil.getAvailableVideoWidth();
  4618. if (availableWidth < 0 || availableHeight < 0) return;
  4619. $('#videospace').width(availableWidth);
  4620. $('#videospace').height(availableHeight);
  4621. $('#largeVideoContainer').width(availableWidth);
  4622. $('#largeVideoContainer').height(availableHeight);
  4623. var avatarSize = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE;
  4624. var top = availableHeight / 2 - avatarSize / 4 * 3;
  4625. $('#activeSpeaker').css('top', top);
  4626. VideoLayout.resizeThumbnails();
  4627. };
  4628. /**
  4629. * Resizes thumbnails.
  4630. */
  4631. my.resizeThumbnails = function() {
  4632. var videoSpaceWidth = $('#remoteVideos').width();
  4633. var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
  4634. var width = thumbnailSize[0];
  4635. var height = thumbnailSize[1];
  4636. // size videos so that while keeping AR and max height, we have a
  4637. // nice fit
  4638. $('#remoteVideos').height(height);
  4639. $('#remoteVideos>span').width(width);
  4640. $('#remoteVideos>span').height(height);
  4641. $('.userAvatar').css('left', (width - height) / 2);
  4642. $(document).trigger("remotevideo.resized", [width, height]);
  4643. };
  4644. /**
  4645. * Enables the dominant speaker UI.
  4646. *
  4647. * @param resourceJid the jid indicating the video element to
  4648. * activate/deactivate
  4649. * @param isEnable indicates if the dominant speaker should be enabled or
  4650. * disabled
  4651. */
  4652. my.enableDominantSpeaker = function(resourceJid, isEnable) {
  4653. var videoSpanId = null;
  4654. var videoContainerId = null;
  4655. if (resourceJid
  4656. === Strophe.getResourceFromJid(connection.emuc.myroomjid)) {
  4657. videoSpanId = 'localVideoWrapper';
  4658. videoContainerId = 'localVideoContainer';
  4659. }
  4660. else {
  4661. videoSpanId = 'participant_' + resourceJid;
  4662. videoContainerId = videoSpanId;
  4663. }
  4664. var displayName = resourceJid;
  4665. var nameSpan = $('#' + videoContainerId + '>span.displayname');
  4666. if (nameSpan.length > 0)
  4667. displayName = nameSpan.html();
  4668. console.log("UI enable dominant speaker",
  4669. displayName,
  4670. resourceJid,
  4671. isEnable);
  4672. videoSpan = document.getElementById(videoContainerId);
  4673. if (!videoSpan) {
  4674. return;
  4675. }
  4676. var video = $('#' + videoSpanId + '>video');
  4677. if (video && video.length > 0) {
  4678. if (isEnable) {
  4679. var isLargeVideoVisible = VideoLayout.isLargeVideoOnTop();
  4680. VideoLayout.showDisplayName(videoContainerId, isLargeVideoVisible);
  4681. if (!videoSpan.classList.contains("dominantspeaker"))
  4682. videoSpan.classList.add("dominantspeaker");
  4683. }
  4684. else {
  4685. VideoLayout.showDisplayName(videoContainerId, false);
  4686. if (videoSpan.classList.contains("dominantspeaker"))
  4687. videoSpan.classList.remove("dominantspeaker");
  4688. }
  4689. Avatar.showUserAvatar(
  4690. connection.emuc.findJidFromResource(resourceJid));
  4691. }
  4692. };
  4693. /**
  4694. * Calculates the thumbnail size.
  4695. *
  4696. * @param videoSpaceWidth the width of the video space
  4697. */
  4698. my.calculateThumbnailSize = function (videoSpaceWidth) {
  4699. // Calculate the available height, which is the inner window height minus
  4700. // 39px for the header minus 2px for the delimiter lines on the top and
  4701. // bottom of the large video, minus the 36px space inside the remoteVideos
  4702. // container used for highlighting shadow.
  4703. var availableHeight = 100;
  4704. var numvids = $('#remoteVideos>span:visible').length;
  4705. if (localLastNCount && localLastNCount > 0) {
  4706. numvids = Math.min(localLastNCount + 1, numvids);
  4707. }
  4708. // Remove the 3px borders arround videos and border around the remote
  4709. // videos area and the 4 pixels between the local video and the others
  4710. //TODO: Find out where the 4 pixels come from and remove them
  4711. var availableWinWidth = videoSpaceWidth - 2 * 3 * numvids - 70 - 4;
  4712. var availableWidth = availableWinWidth / numvids;
  4713. var aspectRatio = 16.0 / 9.0;
  4714. var maxHeight = Math.min(160, availableHeight);
  4715. availableHeight = Math.min(maxHeight, availableWidth / aspectRatio);
  4716. if (availableHeight < availableWidth / aspectRatio) {
  4717. availableWidth = Math.floor(availableHeight * aspectRatio);
  4718. }
  4719. return [availableWidth, availableHeight];
  4720. };
  4721. /**
  4722. * Updates the remote video menu.
  4723. *
  4724. * @param jid the jid indicating the video for which we're adding a menu.
  4725. * @param isMuted indicates the current mute state
  4726. */
  4727. my.updateRemoteVideoMenu = function(jid, isMuted) {
  4728. var muteMenuItem
  4729. = $('#remote_popupmenu_'
  4730. + Strophe.getResourceFromJid(jid)
  4731. + '>li>a.mutelink');
  4732. var mutedIndicator = "<i class='icon-mic-disabled'></i>";
  4733. if (muteMenuItem.length) {
  4734. var muteLink = muteMenuItem.get(0);
  4735. if (isMuted === 'true') {
  4736. muteLink.innerHTML = mutedIndicator + ' Muted';
  4737. muteLink.className = 'mutelink disabled';
  4738. }
  4739. else {
  4740. muteLink.innerHTML = mutedIndicator + ' Mute';
  4741. muteLink.className = 'mutelink';
  4742. }
  4743. }
  4744. };
  4745. /**
  4746. * Returns the current dominant speaker resource jid.
  4747. */
  4748. my.getDominantSpeakerResourceJid = function () {
  4749. return currentDominantSpeaker;
  4750. };
  4751. /**
  4752. * Returns the corresponding resource jid to the given peer container
  4753. * DOM element.
  4754. *
  4755. * @return the corresponding resource jid to the given peer container
  4756. * DOM element
  4757. */
  4758. my.getPeerContainerResourceJid = function (containerElement) {
  4759. var i = containerElement.id.indexOf('participant_');
  4760. if (i >= 0)
  4761. return containerElement.id.substring(i + 12);
  4762. };
  4763. /**
  4764. * On contact list item clicked.
  4765. */
  4766. $(ContactList).bind('contactclicked', function(event, jid) {
  4767. if (!jid) {
  4768. return;
  4769. }
  4770. var resource = Strophe.getResourceFromJid(jid);
  4771. var videoContainer = $("#participant_" + resource);
  4772. if (videoContainer.length > 0) {
  4773. var videoThumb = $('video', videoContainer).get(0);
  4774. // It is not always the case that a videoThumb exists (if there is
  4775. // no actual video).
  4776. if (videoThumb) {
  4777. if (videoThumb.src && videoThumb.src != '') {
  4778. // We have a video src, great! Let's update the large video
  4779. // now.
  4780. VideoLayout.handleVideoThumbClicked(
  4781. videoThumb.src,
  4782. false,
  4783. Strophe.getResourceFromJid(jid));
  4784. } else {
  4785. // If we don't have a video src for jid, there's absolutely
  4786. // no point in calling handleVideoThumbClicked; Quite
  4787. // simply, it won't work because it needs an src to attach
  4788. // to the large video.
  4789. //
  4790. // Instead, we trigger the pinned endpoint changed event to
  4791. // let the bridge adjust its lastN set for myjid and store
  4792. // the pinned user in the lastNPickupJid variable to be
  4793. // picked up later by the lastN changed event handler.
  4794. lastNPickupJid = jid;
  4795. $(document).trigger("pinnedendpointchanged", [jid]);
  4796. }
  4797. } else if (jid == connection.emuc.myroomjid) {
  4798. $("#localVideoContainer").click();
  4799. }
  4800. }
  4801. });
  4802. /**
  4803. * On audio muted event.
  4804. */
  4805. $(document).bind('audiomuted.muc', function (event, jid, isMuted) {
  4806. /*
  4807. // FIXME: but focus can not mute in this case ? - check
  4808. if (jid === connection.emuc.myroomjid) {
  4809. // The local mute indicator is controlled locally
  4810. return;
  4811. }*/
  4812. var videoSpanId = null;
  4813. if (jid === connection.emuc.myroomjid) {
  4814. videoSpanId = 'localVideoContainer';
  4815. } else {
  4816. VideoLayout.ensurePeerContainerExists(jid);
  4817. videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
  4818. }
  4819. mutedAudios[jid] = isMuted;
  4820. if (Moderator.isModerator()) {
  4821. VideoLayout.updateRemoteVideoMenu(jid, isMuted);
  4822. }
  4823. if (videoSpanId)
  4824. VideoLayout.showAudioIndicator(videoSpanId, isMuted);
  4825. });
  4826. /**
  4827. * On video muted event.
  4828. */
  4829. $(document).bind('videomuted.muc', function (event, jid, isMuted) {
  4830. if(!RTC.muteRemoteVideoStream(jid, isMuted))
  4831. return;
  4832. Avatar.showUserAvatar(jid, isMuted);
  4833. var videoSpanId = null;
  4834. if (jid === connection.emuc.myroomjid) {
  4835. videoSpanId = 'localVideoContainer';
  4836. } else {
  4837. VideoLayout.ensurePeerContainerExists(jid);
  4838. videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
  4839. }
  4840. if (videoSpanId)
  4841. VideoLayout.showVideoIndicator(videoSpanId, isMuted);
  4842. });
  4843. /**
  4844. * Display name changed.
  4845. */
  4846. $(document).bind('displaynamechanged',
  4847. function (event, jid, displayName, status) {
  4848. var name = null;
  4849. if (jid === 'localVideoContainer'
  4850. || jid === connection.emuc.myroomjid) {
  4851. name = nickname;
  4852. setDisplayName('localVideoContainer',
  4853. displayName);
  4854. } else {
  4855. VideoLayout.ensurePeerContainerExists(jid);
  4856. name = $('#participant_' + Strophe.getResourceFromJid(jid) + "_name").text();
  4857. setDisplayName(
  4858. 'participant_' + Strophe.getResourceFromJid(jid),
  4859. displayName,
  4860. status);
  4861. }
  4862. if(APIConnector.isEnabled() && APIConnector.isEventEnabled("displayNameChange"))
  4863. {
  4864. if(jid === 'localVideoContainer')
  4865. jid = connection.emuc.myroomjid;
  4866. if(!name || name != displayName)
  4867. APIConnector.triggerEvent("displayNameChange",{jid: jid, displayname: displayName});
  4868. }
  4869. });
  4870. /**
  4871. * On dominant speaker changed event.
  4872. */
  4873. $(document).bind('dominantspeakerchanged', function (event, resourceJid) {
  4874. // We ignore local user events.
  4875. if (resourceJid
  4876. === Strophe.getResourceFromJid(connection.emuc.myroomjid))
  4877. return;
  4878. // Update the current dominant speaker.
  4879. if (resourceJid !== currentDominantSpeaker) {
  4880. var oldSpeakerVideoSpanId = "participant_" + currentDominantSpeaker,
  4881. newSpeakerVideoSpanId = "participant_" + resourceJid;
  4882. if($("#" + oldSpeakerVideoSpanId + ">span.displayname").text() ===
  4883. interfaceConfig.DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME) {
  4884. setDisplayName(oldSpeakerVideoSpanId, null);
  4885. }
  4886. if($("#" + newSpeakerVideoSpanId + ">span.displayname").text() ===
  4887. interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME) {
  4888. setDisplayName(newSpeakerVideoSpanId,
  4889. interfaceConfig.DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME);
  4890. }
  4891. currentDominantSpeaker = resourceJid;
  4892. } else {
  4893. return;
  4894. }
  4895. // Obtain container for new dominant speaker.
  4896. var container = document.getElementById(
  4897. 'participant_' + resourceJid);
  4898. // Local video will not have container found, but that's ok
  4899. // since we don't want to switch to local video.
  4900. if (container && !focusedVideoInfo)
  4901. {
  4902. var video = container.getElementsByTagName("video");
  4903. // Update the large video if the video source is already available,
  4904. // otherwise wait for the "videoactive.jingle" event.
  4905. if (video.length && video[0].currentTime > 0)
  4906. VideoLayout.updateLargeVideo(RTC.getVideoSrc(video[0]), resourceJid);
  4907. }
  4908. });
  4909. /**
  4910. * On last N change event.
  4911. *
  4912. * @param event the event that notified us
  4913. * @param lastNEndpoints the list of last N endpoints
  4914. * @param endpointsEnteringLastN the list currently entering last N
  4915. * endpoints
  4916. */
  4917. $(document).bind('lastnchanged', function ( event,
  4918. lastNEndpoints,
  4919. endpointsEnteringLastN,
  4920. stream) {
  4921. if (lastNCount !== lastNEndpoints.length)
  4922. lastNCount = lastNEndpoints.length;
  4923. lastNEndpointsCache = lastNEndpoints;
  4924. // Say A, B, C, D, E, and F are in a conference and LastN = 3.
  4925. //
  4926. // If LastN drops to, say, 2, because of adaptivity, then E should see
  4927. // thumbnails for A, B and C. A and B are in E's server side LastN set,
  4928. // so E sees them. C is only in E's local LastN set.
  4929. //
  4930. // If F starts talking and LastN = 3, then E should see thumbnails for
  4931. // F, A, B. B gets "ejected" from E's server side LastN set, but it
  4932. // enters E's local LastN ejecting C.
  4933. // Increase the local LastN set size, if necessary.
  4934. if (lastNCount > localLastNCount) {
  4935. localLastNCount = lastNCount;
  4936. }
  4937. // Update the local LastN set preserving the order in which the
  4938. // endpoints appeared in the LastN/local LastN set.
  4939. var nextLocalLastNSet = lastNEndpoints.slice(0);
  4940. for (var i = 0; i < localLastNSet.length; i++) {
  4941. if (nextLocalLastNSet.length >= localLastNCount) {
  4942. break;
  4943. }
  4944. var resourceJid = localLastNSet[i];
  4945. if (nextLocalLastNSet.indexOf(resourceJid) === -1) {
  4946. nextLocalLastNSet.push(resourceJid);
  4947. }
  4948. }
  4949. localLastNSet = nextLocalLastNSet;
  4950. var updateLargeVideo = false;
  4951. // Handle LastN/local LastN changes.
  4952. $('#remoteVideos>span').each(function( index, element ) {
  4953. var resourceJid = VideoLayout.getPeerContainerResourceJid(element);
  4954. var isReceived = true;
  4955. if (resourceJid
  4956. && lastNEndpoints.indexOf(resourceJid) < 0
  4957. && localLastNSet.indexOf(resourceJid) < 0) {
  4958. console.log("Remove from last N", resourceJid);
  4959. showPeerContainer(resourceJid, 'hide');
  4960. isReceived = false;
  4961. } else if (resourceJid
  4962. && $('#participant_' + resourceJid).is(':visible')
  4963. && lastNEndpoints.indexOf(resourceJid) < 0
  4964. && localLastNSet.indexOf(resourceJid) >= 0) {
  4965. showPeerContainer(resourceJid, 'avatar');
  4966. isReceived = false;
  4967. }
  4968. if (!isReceived) {
  4969. // resourceJid has dropped out of the server side lastN set, so
  4970. // it is no longer being received. If resourceJid was being
  4971. // displayed in the large video we have to switch to another
  4972. // user.
  4973. var largeVideoResource = largeVideoState.userResourceJid;
  4974. if (!updateLargeVideo && resourceJid === largeVideoResource) {
  4975. updateLargeVideo = true;
  4976. }
  4977. }
  4978. });
  4979. if (!endpointsEnteringLastN || endpointsEnteringLastN.length < 0)
  4980. endpointsEnteringLastN = lastNEndpoints;
  4981. if (endpointsEnteringLastN && endpointsEnteringLastN.length > 0) {
  4982. endpointsEnteringLastN.forEach(function (resourceJid) {
  4983. var isVisible = $('#participant_' + resourceJid).is(':visible');
  4984. showPeerContainer(resourceJid, 'show');
  4985. if (!isVisible) {
  4986. console.log("Add to last N", resourceJid);
  4987. var jid = connection.emuc.findJidFromResource(resourceJid);
  4988. var mediaStream = RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  4989. var sel = $('#participant_' + resourceJid + '>video');
  4990. var videoStream = simulcast.getReceivingVideoStream(
  4991. mediaStream.stream);
  4992. RTC.attachMediaStream(sel, videoStream);
  4993. if (lastNPickupJid == mediaStream.peerjid) {
  4994. // Clean up the lastN pickup jid.
  4995. lastNPickupJid = null;
  4996. // Don't fire the events again, they've already
  4997. // been fired in the contact list click handler.
  4998. VideoLayout.handleVideoThumbClicked(
  4999. $(sel).attr('src'),
  5000. false,
  5001. Strophe.getResourceFromJid(mediaStream.peerjid));
  5002. updateLargeVideo = false;
  5003. }
  5004. waitForRemoteVideo(sel, mediaStream.ssrc, mediaStream.stream, resourceJid);
  5005. }
  5006. })
  5007. }
  5008. // The endpoint that was being shown in the large video has dropped out
  5009. // of the lastN set and there was no lastN pickup jid. We need to update
  5010. // the large video now.
  5011. if (updateLargeVideo) {
  5012. var resource, container, src;
  5013. var myResource
  5014. = Strophe.getResourceFromJid(connection.emuc.myroomjid);
  5015. // Find out which endpoint to show in the large video.
  5016. for (var i = 0; i < lastNEndpoints.length; i++) {
  5017. resource = lastNEndpoints[i];
  5018. if (!resource || resource === myResource)
  5019. continue;
  5020. container = $("#participant_" + resource);
  5021. if (container.length == 0)
  5022. continue;
  5023. src = $('video', container).attr('src');
  5024. if (!src)
  5025. continue;
  5026. // videoSrcToSsrc needs to be update for this call to succeed.
  5027. VideoLayout.updateLargeVideo(src);
  5028. break;
  5029. }
  5030. }
  5031. });
  5032. $(document).bind('videoactive.jingle', function (event, videoelem) {
  5033. if (videoelem.attr('id').indexOf('mixedmslabel') === -1) {
  5034. // ignore mixedmslabela0 and v0
  5035. videoelem.show();
  5036. VideoLayout.resizeThumbnails();
  5037. var videoParent = videoelem.parent();
  5038. var parentResourceJid = null;
  5039. if (videoParent)
  5040. parentResourceJid
  5041. = VideoLayout.getPeerContainerResourceJid(videoParent[0]);
  5042. // Update the large video to the last added video only if there's no
  5043. // current dominant, focused speaker or prezi playing or update it to
  5044. // the current dominant speaker.
  5045. if ((!focusedVideoInfo &&
  5046. !VideoLayout.getDominantSpeakerResourceJid() &&
  5047. !require("../prezi/Prezi").isPresentationVisible()) ||
  5048. (parentResourceJid &&
  5049. VideoLayout.getDominantSpeakerResourceJid() === parentResourceJid)) {
  5050. VideoLayout.updateLargeVideo(
  5051. RTC.getVideoSrc(videoelem[0]),
  5052. 1,
  5053. parentResourceJid);
  5054. }
  5055. VideoLayout.showModeratorIndicator();
  5056. }
  5057. });
  5058. $(document).bind('simulcastlayerschanging', function (event, endpointSimulcastLayers) {
  5059. endpointSimulcastLayers.forEach(function (esl) {
  5060. var resource = esl.endpoint;
  5061. // if lastN is enabled *and* the endpoint is *not* in the lastN set,
  5062. // then ignore the event (= do not preload anything).
  5063. //
  5064. // The bridge could probably stop sending this message if it's for
  5065. // an endpoint that's not in lastN.
  5066. if (lastNCount != -1
  5067. && (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) {
  5068. return;
  5069. }
  5070. var primarySSRC = esl.simulcastLayer.primarySSRC;
  5071. // Get session and stream from primary ssrc.
  5072. var res = simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
  5073. var session = res.session;
  5074. var electedStream = res.stream;
  5075. if (session && electedStream) {
  5076. var msid = simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
  5077. console.info([esl, primarySSRC, msid, session, electedStream]);
  5078. var msidParts = msid.split(' ');
  5079. var preload = (Strophe.getResourceFromJid(ssrc2jid[primarySSRC]) == largeVideoState.userResourceJid);
  5080. if (preload) {
  5081. if (largeVideoState.preload)
  5082. {
  5083. $(largeVideoState.preload).remove();
  5084. }
  5085. console.info('Preloading remote video');
  5086. largeVideoState.preload = $('<video autoplay></video>');
  5087. // ssrcs are unique in an rtp session
  5088. largeVideoState.preload_ssrc = primarySSRC;
  5089. RTC.attachMediaStream(largeVideoState.preload, electedStream)
  5090. }
  5091. } else {
  5092. console.error('Could not find a stream or a session.', session, electedStream);
  5093. }
  5094. });
  5095. });
  5096. /**
  5097. * On simulcast layers changed event.
  5098. */
  5099. $(document).bind('simulcastlayerschanged', function (event, endpointSimulcastLayers) {
  5100. endpointSimulcastLayers.forEach(function (esl) {
  5101. var resource = esl.endpoint;
  5102. // if lastN is enabled *and* the endpoint is *not* in the lastN set,
  5103. // then ignore the event (= do not change large video/thumbnail
  5104. // SRCs).
  5105. //
  5106. // Note that even if we ignore the "changed" event in this event
  5107. // handler, the bridge must continue sending these events because
  5108. // the simulcast code in simulcast.js uses it to know what's going
  5109. // to be streamed by the bridge when/if the endpoint gets back into
  5110. // the lastN set.
  5111. if (lastNCount != -1
  5112. && (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) {
  5113. return;
  5114. }
  5115. var primarySSRC = esl.simulcastLayer.primarySSRC;
  5116. // Get session and stream from primary ssrc.
  5117. var res = simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
  5118. var session = res.session;
  5119. var electedStream = res.stream;
  5120. if (session && electedStream) {
  5121. var msid = simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
  5122. console.info('Switching simulcast substream.');
  5123. console.info([esl, primarySSRC, msid, session, electedStream]);
  5124. var msidParts = msid.split(' ');
  5125. var selRemoteVideo = $(['#', 'remoteVideo_', session.sid, '_', msidParts[0]].join(''));
  5126. var updateLargeVideo = (Strophe.getResourceFromJid(ssrc2jid[primarySSRC])
  5127. == largeVideoState.userResourceJid);
  5128. var updateFocusedVideoSrc = (focusedVideoInfo && focusedVideoInfo.src && focusedVideoInfo.src != '' &&
  5129. (RTC.getVideoSrc(selRemoteVideo[0]) == focusedVideoInfo.src));
  5130. var electedStreamUrl;
  5131. if (largeVideoState.preload_ssrc == primarySSRC)
  5132. {
  5133. RTC.setVideoSrc(selRemoteVideo[0], RTC.getVideoSrc(largeVideoState.preload[0]));
  5134. }
  5135. else
  5136. {
  5137. if (largeVideoState.preload
  5138. && largeVideoState.preload != null) {
  5139. $(largeVideoState.preload).remove();
  5140. }
  5141. largeVideoState.preload_ssrc = 0;
  5142. RTC.attachMediaStream(selRemoteVideo, electedStream);
  5143. }
  5144. var jid = ssrc2jid[primarySSRC];
  5145. jid2Ssrc[jid] = primarySSRC;
  5146. if (updateLargeVideo) {
  5147. VideoLayout.updateLargeVideo(RTC.getVideoSrc(selRemoteVideo[0]), null,
  5148. Strophe.getResourceFromJid(jid));
  5149. }
  5150. if (updateFocusedVideoSrc) {
  5151. focusedVideoInfo.src = RTC.getVideoSrc(selRemoteVideo[0]);
  5152. }
  5153. var videoId;
  5154. if(resource == Strophe.getResourceFromJid(connection.emuc.myroomjid))
  5155. {
  5156. videoId = "localVideoContainer";
  5157. }
  5158. else
  5159. {
  5160. videoId = "participant_" + resource;
  5161. }
  5162. var connectionIndicator = VideoLayout.connectionIndicators[videoId];
  5163. if(connectionIndicator)
  5164. connectionIndicator.updatePopoverData();
  5165. } else {
  5166. console.error('Could not find a stream or a session.', session, electedStream);
  5167. }
  5168. });
  5169. });
  5170. /**
  5171. * Updates local stats
  5172. * @param percent
  5173. * @param object
  5174. */
  5175. my.updateLocalConnectionStats = function (percent, object) {
  5176. var resolution = null;
  5177. if(object.resolution !== null)
  5178. {
  5179. resolution = object.resolution;
  5180. object.resolution = resolution[connection.emuc.myroomjid];
  5181. delete resolution[connection.emuc.myroomjid];
  5182. }
  5183. updateStatsIndicator("localVideoContainer", percent, object);
  5184. for(var jid in resolution)
  5185. {
  5186. if(resolution[jid] === null)
  5187. continue;
  5188. var id = 'participant_' + Strophe.getResourceFromJid(jid);
  5189. if(VideoLayout.connectionIndicators[id])
  5190. {
  5191. VideoLayout.connectionIndicators[id].updateResolution(resolution[jid]);
  5192. }
  5193. }
  5194. };
  5195. /**
  5196. * Updates remote stats.
  5197. * @param jid the jid associated with the stats
  5198. * @param percent the connection quality percent
  5199. * @param object the stats data
  5200. */
  5201. my.updateConnectionStats = function (jid, percent, object) {
  5202. var resourceJid = Strophe.getResourceFromJid(jid);
  5203. var videoSpanId = 'participant_' + resourceJid;
  5204. updateStatsIndicator(videoSpanId, percent, object);
  5205. };
  5206. /**
  5207. * Removes the connection
  5208. * @param jid
  5209. */
  5210. my.removeConnectionIndicator = function (jid) {
  5211. if(VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)])
  5212. VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)].remove();
  5213. };
  5214. /**
  5215. * Hides the connection indicator
  5216. * @param jid
  5217. */
  5218. my.hideConnectionIndicator = function (jid) {
  5219. if(VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)])
  5220. VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)].hide();
  5221. };
  5222. /**
  5223. * Hides all the indicators
  5224. */
  5225. my.onStatsStop = function () {
  5226. for(var indicator in VideoLayout.connectionIndicators)
  5227. {
  5228. VideoLayout.connectionIndicators[indicator].hideIndicator();
  5229. }
  5230. };
  5231. return my;
  5232. }(VideoLayout || {}));
  5233. module.exports = VideoLayout;
  5234. },{"../audio_levels/AudioLevels":2,"../avatar/Avatar":4,"../etherpad/Etherpad":5,"../prezi/Prezi":6,"../side_pannels/chat/Chat":8,"../side_pannels/contactlist/ContactList":12,"../util/UIUtil":21,"./ConnectionIndicator":22}],24:[function(require,module,exports){
  5235. //var nouns = [
  5236. //];
  5237. var pluralNouns = [
  5238. "Aliens", "Animals", "Antelopes", "Ants", "Apes", "Apples", "Baboons", "Bacteria", "Badgers", "Bananas", "Bats",
  5239. "Bears", "Birds", "Bonobos", "Brides", "Bugs", "Bulls", "Butterflies", "Cheetahs",
  5240. "Cherries", "Chicken", "Children", "Chimps", "Clowns", "Cows", "Creatures", "Dinosaurs", "Dogs", "Dolphins",
  5241. "Donkeys", "Dragons", "Ducks", "Dwarfs", "Eagles", "Elephants", "Elves", "FAIL", "Fathers",
  5242. "Fish", "Flowers", "Frogs", "Fruit", "Fungi", "Galaxies", "Geese", "Goats",
  5243. "Gorillas", "Hedgehogs", "Hippos", "Horses", "Hunters", "Insects", "Kids", "Knights",
  5244. "Lemons", "Lemurs", "Leopards", "LifeForms", "Lions", "Lizards", "Mice", "Monkeys", "Monsters",
  5245. "Mushrooms", "Octopodes", "Oranges", "Orangutans", "Organisms", "Pants", "Parrots", "Penguins",
  5246. "People", "Pigeons", "Pigs", "Pineapples", "Plants", "Potatoes", "Priests", "Rats", "Reptiles", "Reptilians",
  5247. "Rhinos", "Seagulls", "Sheep", "Siblings", "Snakes", "Spaghetti", "Spiders", "Squid", "Squirrels",
  5248. "Stars", "Students", "Teachers", "Tigers", "Tomatoes", "Trees", "Vampires", "Vegetables", "Viruses", "Vulcans",
  5249. "Warewolves", "Weasels", "Whales", "Witches", "Wizards", "Wolves", "Workers", "Worms", "Zebras"
  5250. ];
  5251. //var places = [
  5252. //"Pub", "University", "Airport", "Library", "Mall", "Theater", "Stadium", "Office", "Show", "Gallows", "Beach",
  5253. // "Cemetery", "Hospital", "Reception", "Restaurant", "Bar", "Church", "House", "School", "Square", "Village",
  5254. // "Cinema", "Movies", "Party", "Restroom", "End", "Jail", "PostOffice", "Station", "Circus", "Gates", "Entrance",
  5255. // "Bridge"
  5256. //];
  5257. var verbs = [
  5258. "Abandon", "Adapt", "Advertise", "Answer", "Anticipate", "Appreciate",
  5259. "Approach", "Argue", "Ask", "Bite", "Blossom", "Blush", "Breathe", "Breed", "Bribe", "Burn", "Calculate",
  5260. "Clean", "Code", "Communicate", "Compute", "Confess", "Confiscate", "Conjugate", "Conjure", "Consume",
  5261. "Contemplate", "Crawl", "Dance", "Delegate", "Devour", "Develop", "Differ", "Discuss",
  5262. "Dissolve", "Drink", "Eat", "Elaborate", "Emancipate", "Estimate", "Expire", "Extinguish",
  5263. "Extract", "FAIL", "Facilitate", "Fall", "Feed", "Finish", "Floss", "Fly", "Follow", "Fragment", "Freeze",
  5264. "Gather", "Glow", "Grow", "Hex", "Hide", "Hug", "Hurry", "Improve", "Intersect", "Investigate", "Jinx",
  5265. "Joke", "Jubilate", "Kiss", "Laugh", "Manage", "Meet", "Merge", "Move", "Object", "Observe", "Offer",
  5266. "Paint", "Participate", "Party", "Perform", "Plan", "Pursue", "Pierce", "Play", "Postpone", "Pray", "Proclaim",
  5267. "Question", "Read", "Reckon", "Rejoice", "Represent", "Resize", "Rhyme", "Scream", "Search", "Select", "Share", "Shoot",
  5268. "Shout", "Signal", "Sing", "Skate", "Sleep", "Smile", "Smoke", "Solve", "Spell", "Steer", "Stink",
  5269. "Substitute", "Swim", "Taste", "Teach", "Terminate", "Think", "Type", "Unite", "Vanish", "Worship"
  5270. ];
  5271. var adverbs = [
  5272. "Absently", "Accurately", "Accusingly", "Adorably", "AllTheTime", "Alone", "Always", "Amazingly", "Angrily",
  5273. "Anxiously", "Anywhere", "Appallingly", "Apparently", "Articulately", "Astonishingly", "Badly", "Barely",
  5274. "Beautifully", "Blindly", "Bravely", "Brightly", "Briskly", "Brutally", "Calmly", "Carefully", "Casually",
  5275. "Cautiously", "Cleverly", "Constantly", "Correctly", "Crazily", "Curiously", "Cynically", "Daily",
  5276. "Dangerously", "Deliberately", "Delicately", "Desperately", "Discreetly", "Eagerly", "Easily", "Euphoricly",
  5277. "Evenly", "Everywhere", "Exactly", "Expectantly", "Extensively", "FAIL", "Ferociously", "Fiercely", "Finely",
  5278. "Flatly", "Frequently", "Frighteningly", "Gently", "Gloriously", "Grimly", "Guiltily", "Happily",
  5279. "Hard", "Hastily", "Heroically", "High", "Highly", "Hourly", "Humbly", "Hysterically", "Immensely",
  5280. "Impartially", "Impolitely", "Indifferently", "Intensely", "Jealously", "Jovially", "Kindly", "Lazily",
  5281. "Lightly", "Loudly", "Lovingly", "Loyally", "Magnificently", "Malevolently", "Merrily", "Mightily", "Miserably",
  5282. "Mysteriously", "NOT", "Nervously", "Nicely", "Nowhere", "Objectively", "Obnoxiously", "Obsessively",
  5283. "Obviously", "Often", "Painfully", "Patiently", "Playfully", "Politely", "Poorly", "Precisely", "Promptly",
  5284. "Quickly", "Quietly", "Randomly", "Rapidly", "Rarely", "Recklessly", "Regularly", "Remorsefully", "Responsibly",
  5285. "Rudely", "Ruthlessly", "Sadly", "Scornfully", "Seamlessly", "Seldom", "Selfishly", "Seriously", "Shakily",
  5286. "Sharply", "Sideways", "Silently", "Sleepily", "Slightly", "Slowly", "Slyly", "Smoothly", "Softly", "Solemnly", "Steadily", "Sternly", "Strangely", "Strongly", "Stunningly", "Surely", "Tenderly", "Thoughtfully",
  5287. "Tightly", "Uneasily", "Vanishingly", "Violently", "Warmly", "Weakly", "Wearily", "Weekly", "Weirdly", "Well",
  5288. "Well", "Wickedly", "Wildly", "Wisely", "Wonderfully", "Yearly"
  5289. ];
  5290. var adjectives = [
  5291. "Abominable", "Accurate", "Adorable", "All", "Alleged", "Ancient", "Angry", "Angry", "Anxious", "Appalling",
  5292. "Apparent", "Astonishing", "Attractive", "Awesome", "Baby", "Bad", "Beautiful", "Benign", "Big", "Bitter",
  5293. "Blind", "Blue", "Bold", "Brave", "Bright", "Brisk", "Calm", "Camouflaged", "Casual", "Cautious",
  5294. "Choppy", "Chosen", "Clever", "Cold", "Cool", "Crawly", "Crazy", "Creepy", "Cruel", "Curious", "Cynical",
  5295. "Dangerous", "Dark", "Delicate", "Desperate", "Difficult", "Discreet", "Disguised", "Dizzy",
  5296. "Dumb", "Eager", "Easy", "Edgy", "Electric", "Elegant", "Emancipated", "Enormous", "Euphoric", "Evil",
  5297. "FAIL", "Fast", "Ferocious", "Fierce", "Fine", "Flawed", "Flying", "Foolish", "Foxy",
  5298. "Freezing", "Funny", "Furious", "Gentle", "Glorious", "Golden", "Good", "Green", "Green", "Guilty",
  5299. "Hairy", "Happy", "Hard", "Hasty", "Hazy", "Heroic", "Hostile", "Hot", "Humble", "Humongous",
  5300. "Humorous", "Hysterical", "Idealistic", "Ignorant", "Immense", "Impartial", "Impolite", "Indifferent",
  5301. "Infuriated", "Insightful", "Intense", "Interesting", "Intimidated", "Intriguing", "Jealous", "Jolly", "Jovial",
  5302. "Jumpy", "Kind", "Laughing", "Lazy", "Liquid", "Lonely", "Longing", "Loud", "Loving", "Loyal", "Macabre", "Mad",
  5303. "Magical", "Magnificent", "Malevolent", "Medieval", "Memorable", "Mere", "Merry", "Mighty",
  5304. "Mischievous", "Miserable", "Modified", "Moody", "Most", "Mysterious", "Mystical", "Needy",
  5305. "Nervous", "Nice", "Objective", "Obnoxious", "Obsessive", "Obvious", "Opinionated", "Orange",
  5306. "Painful", "Passionate", "Perfect", "Pink", "Playful", "Poisonous", "Polite", "Poor", "Popular", "Powerful",
  5307. "Precise", "Preserved", "Pretty", "Purple", "Quick", "Quiet", "Random", "Rapid", "Rare", "Real",
  5308. "Reassuring", "Reckless", "Red", "Regular", "Remorseful", "Responsible", "Rich", "Rude", "Ruthless",
  5309. "Sad", "Scared", "Scary", "Scornful", "Screaming", "Selfish", "Serious", "Shady", "Shaky", "Sharp",
  5310. "Shiny", "Shy", "Simple", "Sleepy", "Slow", "Sly", "Small", "Smart", "Smelly", "Smiling", "Smooth",
  5311. "Smug", "Sober", "Soft", "Solemn", "Square", "Square", "Steady", "Strange", "Strong",
  5312. "Stunning", "Subjective", "Successful", "Surly", "Sweet", "Tactful", "Tense",
  5313. "Thoughtful", "Tight", "Tiny", "Tolerant", "Uneasy", "Unique", "Unseen", "Warm", "Weak",
  5314. "Weird", "WellCooked", "Wild", "Wise", "Witty", "Wonderful", "Worried", "Yellow", "Young",
  5315. "Zealous"
  5316. ];
  5317. //var pronouns = [
  5318. //];
  5319. //var conjunctions = [
  5320. //"And", "Or", "For", "Above", "Before", "Against", "Between"
  5321. //];
  5322. /*
  5323. * Maps a string (category name) to the array of words from that category.
  5324. */
  5325. var CATEGORIES =
  5326. {
  5327. //"_NOUN_": nouns,
  5328. "_PLURALNOUN_": pluralNouns,
  5329. //"_PLACE_": places,
  5330. "_VERB_": verbs,
  5331. "_ADVERB_": adverbs,
  5332. "_ADJECTIVE_": adjectives
  5333. //"_PRONOUN_": pronouns,
  5334. //"_CONJUNCTION_": conjunctions,
  5335. };
  5336. var PATTERNS = [
  5337. "_ADJECTIVE__PLURALNOUN__VERB__ADVERB_"
  5338. // BeautifulFungiOrSpaghetti
  5339. //"_ADJECTIVE__PLURALNOUN__CONJUNCTION__PLURALNOUN_",
  5340. // AmazinglyScaryToy
  5341. //"_ADVERB__ADJECTIVE__NOUN_",
  5342. // NeitherTrashNorRifle
  5343. //"Neither_NOUN_Nor_NOUN_",
  5344. //"Either_NOUN_Or_NOUN_",
  5345. // EitherCopulateOrInvestigate
  5346. //"Either_VERB_Or_VERB_",
  5347. //"Neither_VERB_Nor_VERB_",
  5348. //"The_ADJECTIVE__ADJECTIVE__NOUN_",
  5349. //"The_ADVERB__ADJECTIVE__NOUN_",
  5350. //"The_ADVERB__ADJECTIVE__NOUN_s",
  5351. //"The_ADVERB__ADJECTIVE__PLURALNOUN__VERB_",
  5352. // WolvesComputeBadly
  5353. //"_PLURALNOUN__VERB__ADVERB_",
  5354. // UniteFacilitateAndMerge
  5355. //"_VERB__VERB_And_VERB_",
  5356. //NastyWitchesAtThePub
  5357. //"_ADJECTIVE__PLURALNOUN_AtThe_PLACE_",
  5358. ];
  5359. /*
  5360. * Returns a random element from the array 'arr'
  5361. */
  5362. function randomElement(arr)
  5363. {
  5364. return arr[Math.floor(Math.random() * arr.length)];
  5365. }
  5366. /*
  5367. * Returns true if the string 's' contains one of the
  5368. * template strings.
  5369. */
  5370. function hasTemplate(s)
  5371. {
  5372. for (var template in CATEGORIES){
  5373. if (s.indexOf(template) >= 0){
  5374. return true;
  5375. }
  5376. }
  5377. }
  5378. /**
  5379. * Generates new room name.
  5380. */
  5381. var RoomNameGenerator = {
  5382. generateRoomWithoutSeparator: function()
  5383. {
  5384. // Note that if more than one pattern is available, the choice of 'name' won't be random (names from patterns
  5385. // with fewer options will have higher probability of being chosen that names from patterns with more options).
  5386. var name = randomElement(PATTERNS);
  5387. var word;
  5388. while (hasTemplate(name)){
  5389. for (var template in CATEGORIES){
  5390. word = randomElement(CATEGORIES[template]);
  5391. name = name.replace(template, word);
  5392. }
  5393. }
  5394. return name;
  5395. }
  5396. }
  5397. module.exports = RoomNameGenerator;
  5398. },{}],25:[function(require,module,exports){
  5399. var animateTimeout, updateTimeout;
  5400. var RoomNameGenerator = require("./RoomnameGenerator");
  5401. function enter_room()
  5402. {
  5403. var val = $("#enter_room_field").val();
  5404. if(!val) {
  5405. val = $("#enter_room_field").attr("room_name");
  5406. }
  5407. if (val) {
  5408. window.location.pathname = "/" + val;
  5409. }
  5410. }
  5411. function animate(word) {
  5412. var currentVal = $("#enter_room_field").attr("placeholder");
  5413. $("#enter_room_field").attr("placeholder", currentVal + word.substr(0, 1));
  5414. animateTimeout = setTimeout(function() {
  5415. animate(word.substring(1, word.length))
  5416. }, 70);
  5417. }
  5418. function update_roomname()
  5419. {
  5420. var word = RoomNameGenerator.generateRoomWithoutSeparator();
  5421. $("#enter_room_field").attr("room_name", word);
  5422. $("#enter_room_field").attr("placeholder", "");
  5423. clearTimeout(animateTimeout);
  5424. animate(word);
  5425. updateTimeout = setTimeout(update_roomname, 10000);
  5426. }
  5427. function setupWelcomePage()
  5428. {
  5429. $("#videoconference_page").hide();
  5430. $("#domain_name").text(
  5431. window.location.protocol + "//" + window.location.host + "/");
  5432. $("span[name='appName']").text(interfaceConfig.APP_NAME);
  5433. if (interfaceConfig.SHOW_JITSI_WATERMARK) {
  5434. var leftWatermarkDiv
  5435. = $("#welcome_page_header div[class='watermark leftwatermark']");
  5436. if(leftWatermarkDiv && leftWatermarkDiv.length > 0)
  5437. {
  5438. leftWatermarkDiv.css({display: 'block'});
  5439. leftWatermarkDiv.parent().get(0).href
  5440. = interfaceConfig.JITSI_WATERMARK_LINK;
  5441. }
  5442. }
  5443. if (interfaceConfig.SHOW_BRAND_WATERMARK) {
  5444. var rightWatermarkDiv
  5445. = $("#welcome_page_header div[class='watermark rightwatermark']");
  5446. if(rightWatermarkDiv && rightWatermarkDiv.length > 0) {
  5447. rightWatermarkDiv.css({display: 'block'});
  5448. rightWatermarkDiv.parent().get(0).href
  5449. = interfaceConfig.BRAND_WATERMARK_LINK;
  5450. rightWatermarkDiv.get(0).style.backgroundImage
  5451. = "url(images/rightwatermark.png)";
  5452. }
  5453. }
  5454. if (interfaceConfig.SHOW_POWERED_BY) {
  5455. $("#welcome_page_header>a[class='poweredby']")
  5456. .css({display: 'block'});
  5457. }
  5458. $("#enter_room_button").click(function()
  5459. {
  5460. enter_room();
  5461. });
  5462. $("#enter_room_field").keydown(function (event) {
  5463. if (event.keyCode === 13 /* enter */) {
  5464. enter_room();
  5465. }
  5466. });
  5467. if (!(interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE === false)){
  5468. var updateTimeout;
  5469. var animateTimeout;
  5470. $("#reload_roomname").click(function () {
  5471. clearTimeout(updateTimeout);
  5472. clearTimeout(animateTimeout);
  5473. update_roomname();
  5474. });
  5475. $("#reload_roomname").show();
  5476. update_roomname();
  5477. }
  5478. $("#disable_welcome").click(function () {
  5479. window.localStorage.welcomePageDisabled
  5480. = $("#disable_welcome").is(":checked");
  5481. });
  5482. }
  5483. module.exports = setupWelcomePage;
  5484. },{"./RoomnameGenerator":24}]},{},[1])(1)
  5485. });
  5486. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvVXNlcnMvaHJpc3RvL0RvY3VtZW50cy93b3Jrc3BhY2Uvaml0c2ktbWVldC9tb2R1bGVzL1VJL1VJLmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS9hdWRpb19sZXZlbHMvQXVkaW9MZXZlbHMuanMiLCIvVXNlcnMvaHJpc3RvL0RvY3VtZW50cy93b3Jrc3BhY2Uvaml0c2ktbWVldC9tb2R1bGVzL1VJL2F1ZGlvX2xldmVscy9DYW52YXNVdGlscy5qcyIsIi9Vc2Vycy9ocmlzdG8vRG9jdW1lbnRzL3dvcmtzcGFjZS9qaXRzaS1tZWV0L21vZHVsZXMvVUkvYXZhdGFyL0F2YXRhci5qcyIsIi9Vc2Vycy9ocmlzdG8vRG9jdW1lbnRzL3dvcmtzcGFjZS9qaXRzaS1tZWV0L21vZHVsZXMvVUkvZXRoZXJwYWQvRXRoZXJwYWQuanMiLCIvVXNlcnMvaHJpc3RvL0RvY3VtZW50cy93b3Jrc3BhY2Uvaml0c2ktbWVldC9tb2R1bGVzL1VJL3ByZXppL1ByZXppLmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS9zaWRlX3Bhbm5lbHMvU2lkZVBhbmVsVG9nZ2xlci5qcyIsIi9Vc2Vycy9ocmlzdG8vRG9jdW1lbnRzL3dvcmtzcGFjZS9qaXRzaS1tZWV0L21vZHVsZXMvVUkvc2lkZV9wYW5uZWxzL2NoYXQvQ2hhdC5qcyIsIi9Vc2Vycy9ocmlzdG8vRG9jdW1lbnRzL3dvcmtzcGFjZS9qaXRzaS1tZWV0L21vZHVsZXMvVUkvc2lkZV9wYW5uZWxzL2NoYXQvQ29tbWFuZHMuanMiLCIvVXNlcnMvaHJpc3RvL0RvY3VtZW50cy93b3Jrc3BhY2Uvaml0c2ktbWVldC9tb2R1bGVzL1VJL3NpZGVfcGFubmVscy9jaGF0L1JlcGxhY2VtZW50LmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS9zaWRlX3Bhbm5lbHMvY2hhdC9zbWlsZXlzLmpzb24iLCIvVXNlcnMvaHJpc3RvL0RvY3VtZW50cy93b3Jrc3BhY2Uvaml0c2ktbWVldC9tb2R1bGVzL1VJL3NpZGVfcGFubmVscy9jb250YWN0bGlzdC9Db250YWN0TGlzdC5qcyIsIi9Vc2Vycy9ocmlzdG8vRG9jdW1lbnRzL3dvcmtzcGFjZS9qaXRzaS1tZWV0L21vZHVsZXMvVUkvc2lkZV9wYW5uZWxzL3NldHRpbmdzL1NldHRpbmdzLmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS9zaWRlX3Bhbm5lbHMvc2V0dGluZ3MvU2V0dGluZ3NNZW51LmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS90b29sYmFycy9Cb3R0b21Ub29sYmFyLmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS90b29sYmFycy9Ub29sYmFyVG9nZ2xlci5qcyIsIi9Vc2Vycy9ocmlzdG8vRG9jdW1lbnRzL3dvcmtzcGFjZS9qaXRzaS1tZWV0L21vZHVsZXMvVUkvdG9vbGJhcnMvdG9vbGJhci5qcyIsIi9Vc2Vycy9ocmlzdG8vRG9jdW1lbnRzL3dvcmtzcGFjZS9qaXRzaS1tZWV0L21vZHVsZXMvVUkvdXRpbC9KaXRzaVBvcG92ZXIuanMiLCIvVXNlcnMvaHJpc3RvL0RvY3VtZW50cy93b3Jrc3BhY2Uvaml0c2ktbWVldC9tb2R1bGVzL1VJL3V0aWwvTWVzc2FnZUhhbmRsZXIuanMiLCIvVXNlcnMvaHJpc3RvL0RvY3VtZW50cy93b3Jrc3BhY2Uvaml0c2ktbWVldC9tb2R1bGVzL1VJL3V0aWwvVUlVdGlsLmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS92aWRlb2xheW91dC9Db25uZWN0aW9uSW5kaWNhdG9yLmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS92aWRlb2xheW91dC9WaWRlb0xheW91dC5qcyIsIi9Vc2Vycy9ocmlzdG8vRG9jdW1lbnRzL3dvcmtzcGFjZS9qaXRzaS1tZWV0L21vZHVsZXMvVUkvd2VsY29tZV9wYWdlL1Jvb21uYW1lR2VuZXJhdG9yLmpzIiwiL1VzZXJzL2hyaXN0by9Eb2N1bWVudHMvd29ya3NwYWNlL2ppdHNpLW1lZXQvbW9kdWxlcy9VSS93ZWxjb21lX3BhZ2UvV2VsY29tZVBhZ2UuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDamlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdlFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4V0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDbmNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6WkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzEvREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25MQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJ2YXIgVUkgPSB7fTtcblxudmFyIFZpZGVvTGF5b3V0ID0gcmVxdWlyZShcIi4vdmlkZW9sYXlvdXQvVmlkZW9MYXlvdXQuanNcIik7XG52YXIgQXVkaW9MZXZlbHMgPSByZXF1aXJlKFwiLi9hdWRpb19sZXZlbHMvQXVkaW9MZXZlbHMuanNcIik7XG52YXIgUHJlemkgPSByZXF1aXJlKFwiLi9wcmV6aS9QcmV6aS5qc1wiKTtcbnZhciBFdGhlcnBhZCA9IHJlcXVpcmUoXCIuL2V0aGVycGFkL0V0aGVycGFkLmpzXCIpO1xudmFyIENoYXQgPSByZXF1aXJlKFwiLi9zaWRlX3Bhbm5lbHMvY2hhdC9DaGF0LmpzXCIpO1xudmFyIFRvb2xiYXIgPSByZXF1aXJlKFwiLi90b29sYmFycy90b29sYmFyXCIpO1xudmFyIFRvb2xiYXJUb2dnbGVyID0gcmVxdWlyZShcIi4vdG9vbGJhcnMvdG9vbGJhcnRvZ2dsZXJcIik7XG52YXIgQm90dG9tVG9vbGJhciA9IHJlcXVpcmUoXCIuL3Rvb2xiYXJzL0JvdHRvbVRvb2xiYXJcIik7XG52YXIgQ29udGFjdExpc3QgPSByZXF1aXJlKFwiLi9zaWRlX3Bhbm5lbHMvY29udGFjdGxpc3QvQ29udGFjdExpc3RcIik7XG52YXIgQXZhdGFyID0gcmVxdWlyZShcIi4vYXZhdGFyL0F2YXRhclwiKTtcbi8vdmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoXCJldmVudHNcIik7XG52YXIgU2V0dGluZ3NNZW51ID0gcmVxdWlyZShcIi4vc2lkZV9wYW5uZWxzL3NldHRpbmdzL1NldHRpbmdzTWVudVwiKTtcbnZhciBTZXR0aW5ncyA9IHJlcXVpcmUoXCIuL3NpZGVfcGFubmVscy9zZXR0aW5ncy9TZXR0aW5nc1wiKTtcbnZhciBQYW5lbFRvZ2dsZXIgPSByZXF1aXJlKFwiLi9zaWRlX3Bhbm5lbHMvU2lkZVBhbmVsVG9nZ2xlclwiKTtcbnZhciBSb29tTmFtZUdlbmVyYXRvciA9IHJlcXVpcmUoXCIuL3dlbGNvbWVfcGFnZS9Sb29tbmFtZUdlbmVyYXRvclwiKTtcblVJLm1lc3NhZ2VIYW5kbGVyID0gcmVxdWlyZShcIi4vdXRpbC9NZXNzYWdlSGFuZGxlclwiKTtcbnZhciBtZXNzYWdlSGFuZGxlciA9IFVJLm1lc3NhZ2VIYW5kbGVyO1xuXG4vL3ZhciBldmVudEVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cblxuXG5mdW5jdGlvbiBzZXR1cFByZXppKClcbntcbiAgICAkKFwiI3JlbG9hZFByZXNlbnRhdGlvbkxpbmtcIikuY2xpY2soZnVuY3Rpb24oKVxuICAgIHtcbiAgICAgICAgUHJlemkucmVsb2FkUHJlc2VudGF0aW9uKCk7XG4gICAgfSk7XG59XG5cbmZ1bmN0aW9uIHNldHVwQ2hhdCgpXG57XG4gICAgQ2hhdC5pbml0KCk7XG4gICAgJChcIiN0b2dnbGVfc21pbGV5c1wiKS5jbGljayhmdW5jdGlvbigpIHtcbiAgICAgICAgQ2hhdC50b2dnbGVTbWlsZXlzKCk7XG4gICAgfSk7XG59XG5cbmZ1bmN0aW9uIHNldHVwVG9vbGJhcnMoKSB7XG4gICAgVG9vbGJhci5pbml0KCk7XG4gICAgVG9vbGJhci5zZXR1cEJ1dHRvbnNGcm9tQ29uZmlnKCk7XG4gICAgQm90dG9tVG9vbGJhci5pbml0KCk7XG59XG5cblxuZnVuY3Rpb24gcmVnaXN0ZXJMaXN0ZW5lcnMoKSB7XG4gICAgUlRDLmFkZFN0cmVhbUxpc3RlbmVyKGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgc3dpdGNoIChzdHJlYW0udHlwZSlcbiAgICAgICAge1xuICAgICAgICAgICAgY2FzZSBcImF1ZGlvXCI6XG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuY2hhbmdlTG9jYWxBdWRpbyhzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwidmlkZW9cIjpcbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5jaGFuZ2VMb2NhbFZpZGVvKHN0cmVhbS5nZXRPcmlnaW5hbFN0cmVhbSgpLCB0cnVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJzdHJlYW1cIjpcbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5jaGFuZ2VMb2NhbFN0cmVhbShzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiZGVza3RvcFwiOlxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNoYW5nZUxvY2FsVmlkZW8oc3RyZWFtLCAhaXNVc2luZ1NjcmVlblN0cmVhbSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9LCBTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfTE9DQUxfQ1JFQVRFRCk7XG5cbiAgICBSVEMuYWRkU3RyZWFtTGlzdGVuZXIoZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICBWaWRlb0xheW91dC5vblJlbW90ZVN0cmVhbUFkZGVkKHN0cmVhbSk7XG4gICAgfSwgU3RyZWFtRXZlbnRUeXBlcy5FVkVOVF9UWVBFX1JFTU9URV9DUkVBVEVEKTtcblxuICAgIC8vIExpc3RlbiBmb3IgbGFyZ2UgdmlkZW8gc2l6ZSB1cGRhdGVzXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xhcmdlVmlkZW8nKVxuICAgICAgICAuYWRkRXZlbnRMaXN0ZW5lcignbG9hZGVkbWV0YWRhdGEnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgY3VycmVudFZpZGVvV2lkdGggPSB0aGlzLnZpZGVvV2lkdGg7XG4gICAgICAgICAgICBjdXJyZW50VmlkZW9IZWlnaHQgPSB0aGlzLnZpZGVvSGVpZ2h0O1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucG9zaXRpb25MYXJnZShjdXJyZW50VmlkZW9XaWR0aCwgY3VycmVudFZpZGVvSGVpZ2h0KTtcbiAgICAgICAgfSk7XG5cblxuICAgIHN0YXRpc3RpY3MuYWRkQXVkaW9MZXZlbExpc3RlbmVyKGZ1bmN0aW9uKGppZCwgYXVkaW9MZXZlbClcbiAgICB7XG4gICAgICAgIHZhciByZXNvdXJjZUppZDtcbiAgICAgICAgaWYoamlkID09PSBzdGF0aXN0aWNzLkxPQ0FMX0pJRClcbiAgICAgICAge1xuICAgICAgICAgICAgcmVzb3VyY2VKaWQgPSBBdWRpb0xldmVscy5MT0NBTF9MRVZFTDtcbiAgICAgICAgICAgIGlmKGlzQXVkaW9NdXRlZCgpKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGF1ZGlvTGV2ZWwgPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgQXVkaW9MZXZlbHMudXBkYXRlQXVkaW9MZXZlbChyZXNvdXJjZUppZCwgYXVkaW9MZXZlbCxcbiAgICAgICAgICAgIFVJLmdldExhcmdlVmlkZW9TdGF0ZSgpLnVzZXJSZXNvdXJjZUppZCk7XG4gICAgfSk7XG5cbn1cblxuZnVuY3Rpb24gYmluZEV2ZW50cygpXG57XG4gICAgLyoqXG4gICAgICogUmVzaXplcyBhbmQgcmVwb3NpdGlvbnMgdmlkZW9zIGluIGZ1bGwgc2NyZWVuIG1vZGUuXG4gICAgICovXG4gICAgJChkb2N1bWVudCkub24oJ3dlYmtpdGZ1bGxzY3JlZW5jaGFuZ2UgbW96ZnVsbHNjcmVlbmNoYW5nZSBmdWxsc2NyZWVuY2hhbmdlJyxcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplTGFyZ2VWaWRlb0NvbnRhaW5lcigpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucG9zaXRpb25MYXJnZSgpO1xuICAgICAgICAgICAgaXNGdWxsU2NyZWVuID0gZG9jdW1lbnQuZnVsbFNjcmVlbiB8fFxuICAgICAgICAgICAgICAgIGRvY3VtZW50Lm1vekZ1bGxTY3JlZW4gfHxcbiAgICAgICAgICAgICAgICBkb2N1bWVudC53ZWJraXRJc0Z1bGxTY3JlZW47XG5cbiAgICAgICAgfVxuICAgICk7XG5cbiAgICAkKHdpbmRvdykucmVzaXplKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplTGFyZ2VWaWRlb0NvbnRhaW5lcigpO1xuICAgICAgICBWaWRlb0xheW91dC5wb3NpdGlvbkxhcmdlKCk7XG4gICAgfSk7XG59XG5cblVJLnN0YXJ0ID0gZnVuY3Rpb24gKCkge1xuICAgIGRvY3VtZW50LnRpdGxlID0gaW50ZXJmYWNlQ29uZmlnLkFQUF9OQU1FO1xuICAgIGlmKGNvbmZpZy5lbmFibGVXZWxjb21lUGFnZSAmJiB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUgPT0gXCIvXCIgJiZcbiAgICAgICAgKCF3aW5kb3cubG9jYWxTdG9yYWdlLndlbGNvbWVQYWdlRGlzYWJsZWQgfHwgd2luZG93LmxvY2FsU3RvcmFnZS53ZWxjb21lUGFnZURpc2FibGVkID09IFwiZmFsc2VcIikpXG4gICAge1xuICAgICAgICAkKFwiI3ZpZGVvY29uZmVyZW5jZV9wYWdlXCIpLmhpZGUoKTtcbiAgICAgICAgdmFyIHNldHVwV2VsY29tZVBhZ2UgPSByZXF1aXJlKFwiLi93ZWxjb21lX3BhZ2UvV2VsY29tZVBhZ2VcIik7XG4gICAgICAgIHNldHVwV2VsY29tZVBhZ2UoKTtcblxuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGludGVyZmFjZUNvbmZpZy5TSE9XX0pJVFNJX1dBVEVSTUFSSykge1xuICAgICAgICB2YXIgbGVmdFdhdGVybWFya0RpdlxuICAgICAgICAgICAgPSAkKFwiI2xhcmdlVmlkZW9Db250YWluZXIgZGl2W2NsYXNzPSd3YXRlcm1hcmsgbGVmdHdhdGVybWFyayddXCIpO1xuXG4gICAgICAgIGxlZnRXYXRlcm1hcmtEaXYuY3NzKHtkaXNwbGF5OiAnYmxvY2snfSk7XG4gICAgICAgIGxlZnRXYXRlcm1hcmtEaXYucGFyZW50KCkuZ2V0KDApLmhyZWZcbiAgICAgICAgICAgID0gaW50ZXJmYWNlQ29uZmlnLkpJVFNJX1dBVEVSTUFSS19MSU5LO1xuICAgIH1cblxuICAgIGlmIChpbnRlcmZhY2VDb25maWcuU0hPV19CUkFORF9XQVRFUk1BUkspIHtcbiAgICAgICAgdmFyIHJpZ2h0V2F0ZXJtYXJrRGl2XG4gICAgICAgICAgICA9ICQoXCIjbGFyZ2VWaWRlb0NvbnRhaW5lciBkaXZbY2xhc3M9J3dhdGVybWFyayByaWdodHdhdGVybWFyayddXCIpO1xuXG4gICAgICAgIHJpZ2h0V2F0ZXJtYXJrRGl2LmNzcyh7ZGlzcGxheTogJ2Jsb2NrJ30pO1xuICAgICAgICByaWdodFdhdGVybWFya0Rpdi5wYXJlbnQoKS5nZXQoMCkuaHJlZlxuICAgICAgICAgICAgPSBpbnRlcmZhY2VDb25maWcuQlJBTkRfV0FURVJNQVJLX0xJTks7XG4gICAgICAgIHJpZ2h0V2F0ZXJtYXJrRGl2LmdldCgwKS5zdHlsZS5iYWNrZ3JvdW5kSW1hZ2VcbiAgICAgICAgICAgID0gXCJ1cmwoaW1hZ2VzL3JpZ2h0d2F0ZXJtYXJrLnBuZylcIjtcbiAgICB9XG5cbiAgICBpZiAoaW50ZXJmYWNlQ29uZmlnLlNIT1dfUE9XRVJFRF9CWSkge1xuICAgICAgICAkKFwiI2xhcmdlVmlkZW9Db250YWluZXI+YVtjbGFzcz0ncG93ZXJlZGJ5J11cIikuY3NzKHtkaXNwbGF5OiAnYmxvY2snfSk7XG4gICAgfVxuXG4gICAgJChcIiN3ZWxjb21lX3BhZ2VcIikuaGlkZSgpO1xuXG4gICAgJCgnYm9keScpLnBvcG92ZXIoeyBzZWxlY3RvcjogJ1tkYXRhLXRvZ2dsZT1wb3BvdmVyXScsXG4gICAgICAgIHRyaWdnZXI6ICdjbGljayBob3ZlcicsXG4gICAgICAgIGNvbnRlbnQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QXR0cmlidXRlKFwiY29udGVudFwiKSArXG4gICAgICAgICAgICAgICAgS2V5Ym9hcmRTaG9ydGN1dC5nZXRTaG9ydGN1dCh0aGlzLmdldEF0dHJpYnV0ZShcInNob3J0Y3V0XCIpKTtcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIFZpZGVvTGF5b3V0LnJlc2l6ZUxhcmdlVmlkZW9Db250YWluZXIoKTtcbiAgICAkKFwiI3ZpZGVvc3BhY2VcIikubW91c2Vtb3ZlKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFRvb2xiYXJUb2dnbGVyLnNob3dUb29sYmFyKCk7XG4gICAgfSk7XG4gICAgLy8gU2V0IHRoZSBkZWZhdWx0cyBmb3IgcHJvbXB0IGRpYWxvZ3MuXG4gICAgalF1ZXJ5LnByb21wdC5zZXREZWZhdWx0cyh7cGVyc2lzdGVudDogZmFsc2V9KTtcblxuLy8gICAgS2V5Ym9hcmRTaG9ydGN1dC5pbml0KCk7XG4gICAgcmVnaXN0ZXJMaXN0ZW5lcnMoKTtcbiAgICBiaW5kRXZlbnRzKCk7XG4gICAgc2V0dXBQcmV6aSgpO1xuICAgIHNldHVwVG9vbGJhcnMoKTtcbiAgICBzZXR1cENoYXQoKTtcblxuICAgIGRvY3VtZW50LnRpdGxlID0gaW50ZXJmYWNlQ29uZmlnLkFQUF9OQU1FO1xuXG4gICAgJChcIiNkb3dubG9hZGxvZ1wiKS5jbGljayhmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgZHVtcChldmVudC50YXJnZXQpO1xuICAgIH0pO1xuXG4gICAgaWYoY29uZmlnLmVuYWJsZVdlbGNvbWVQYWdlICYmIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSA9PSBcIi9cIiAmJlxuICAgICAgICAoIXdpbmRvdy5sb2NhbFN0b3JhZ2Uud2VsY29tZVBhZ2VEaXNhYmxlZCB8fCB3aW5kb3cubG9jYWxTdG9yYWdlLndlbGNvbWVQYWdlRGlzYWJsZWQgPT0gXCJmYWxzZVwiKSlcbiAgICB7XG4gICAgICAgICQoXCIjdmlkZW9jb25mZXJlbmNlX3BhZ2VcIikuaGlkZSgpO1xuICAgICAgICB2YXIgc2V0dXBXZWxjb21lUGFnZSA9IHJlcXVpcmUoXCIuL3dlbGNvbWVfcGFnZS9XZWxjb21lUGFnZVwiKTtcbiAgICAgICAgc2V0dXBXZWxjb21lUGFnZSgpO1xuXG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAkKFwiI3dlbGNvbWVfcGFnZVwiKS5oaWRlKCk7XG5cbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbGFyZ2VWaWRlbycpLnZvbHVtZSA9IDA7XG5cbiAgICBpZiAoISQoJyNzZXR0aW5ncycpLmlzKCc6dmlzaWJsZScpKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdpbml0Jyk7XG4gICAgICAgIGluaXQoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsb2dpbkluZm8ub25zdWJtaXQgPSBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgaWYgKGUucHJldmVudERlZmF1bHQpIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICQoJyNzZXR0aW5ncycpLmhpZGUoKTtcbiAgICAgICAgICAgIGluaXQoKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB0b2FzdHIub3B0aW9ucyA9IHtcbiAgICAgICAgXCJjbG9zZUJ1dHRvblwiOiB0cnVlLFxuICAgICAgICBcImRlYnVnXCI6IGZhbHNlLFxuICAgICAgICBcInBvc2l0aW9uQ2xhc3NcIjogXCJub3RpZmljYXRpb24tYm90dG9tLXJpZ2h0XCIsXG4gICAgICAgIFwib25jbGlja1wiOiBudWxsLFxuICAgICAgICBcInNob3dEdXJhdGlvblwiOiBcIjMwMFwiLFxuICAgICAgICBcImhpZGVEdXJhdGlvblwiOiBcIjEwMDBcIixcbiAgICAgICAgXCJ0aW1lT3V0XCI6IFwiMjAwMFwiLFxuICAgICAgICBcImV4dGVuZGVkVGltZU91dFwiOiBcIjEwMDBcIixcbiAgICAgICAgXCJzaG93RWFzaW5nXCI6IFwic3dpbmdcIixcbiAgICAgICAgXCJoaWRlRWFzaW5nXCI6IFwibGluZWFyXCIsXG4gICAgICAgIFwic2hvd01ldGhvZFwiOiBcImZhZGVJblwiLFxuICAgICAgICBcImhpZGVNZXRob2RcIjogXCJmYWRlT3V0XCIsXG4gICAgICAgIFwicmVwb3NpdGlvblwiOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGlmKFBhbmVsVG9nZ2xlci5pc1Zpc2libGUoKSkge1xuICAgICAgICAgICAgICAgICQoXCIjdG9hc3QtY29udGFpbmVyXCIpLmFkZENsYXNzKFwibm90aWZpY2F0aW9uLWJvdHRvbS1yaWdodC1jZW50ZXJcIik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICQoXCIjdG9hc3QtY29udGFpbmVyXCIpLnJlbW92ZUNsYXNzKFwibm90aWZpY2F0aW9uLWJvdHRvbS1yaWdodC1jZW50ZXJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwibmV3ZXN0T25Ub3BcIjogZmFsc2VcbiAgICB9O1xuXG4gICAgJCgnI3NldHRpbmdzbWVudT5pbnB1dCcpLmtleXVwKGZ1bmN0aW9uKGV2ZW50KXtcbiAgICAgICAgaWYoZXZlbnQua2V5Q29kZSA9PT0gMTMpIHsvL2VudGVyXG4gICAgICAgICAgICBTZXR0aW5nc01lbnUudXBkYXRlKCk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgICQoXCIjdXBkYXRlU2V0dGluZ3NcIikuY2xpY2soZnVuY3Rpb24gKCkge1xuICAgICAgICBTZXR0aW5nc01lbnUudXBkYXRlKCk7XG4gICAgfSk7XG5cbn07XG5cblxuVUkuc2V0VXNlckF2YXRhciA9IGZ1bmN0aW9uIChqaWQsIGlkKSB7XG4gICAgQXZhdGFyLnNldFVzZXJBdmF0YXIoamlkLCBpZCk7XG59O1xuXG5VSS50b2dnbGVTbWlsZXlzID0gZnVuY3Rpb24gKCkge1xuICAgIENoYXQudG9nZ2xlU21pbGV5cygpO1xufTtcblxuVUkuY2hhdEFkZEVycm9yID0gZnVuY3Rpb24oZXJyb3JNZXNzYWdlLCBvcmlnaW5hbFRleHQpXG57XG4gICAgcmV0dXJuIENoYXQuY2hhdEFkZEVycm9yKGVycm9yTWVzc2FnZSwgb3JpZ2luYWxUZXh0KTtcbn07XG5cblVJLmNoYXRTZXRTdWJqZWN0ID0gZnVuY3Rpb24odGV4dClcbntcbiAgICByZXR1cm4gQ2hhdC5jaGF0U2V0U3ViamVjdCh0ZXh0KTtcbn07XG5cblVJLnVwZGF0ZUNoYXRDb252ZXJzYXRpb24gPSBmdW5jdGlvbiAoZnJvbSwgZGlzcGxheU5hbWUsIG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gQ2hhdC51cGRhdGVDaGF0Q29udmVyc2F0aW9uKGZyb20sIGRpc3BsYXlOYW1lLCBtZXNzYWdlKTtcbn07XG5cblVJLm9uTXVjSm9pbmVkID0gZnVuY3Rpb24gKGppZCwgaW5mbykge1xuICAgIFRvb2xiYXIudXBkYXRlUm9vbVVybCh3aW5kb3cubG9jYXRpb24uaHJlZik7XG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xvY2FsTmljaycpLmFwcGVuZENoaWxkKFxuICAgICAgICBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpICsgJyAobWUpJylcbiAgICApO1xuXG4gICAgdmFyIHNldHRpbmdzID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbiAgICAvLyBBZGQgbXlzZWxmIHRvIHRoZSBjb250YWN0IGxpc3QuXG4gICAgQ29udGFjdExpc3QuYWRkQ29udGFjdChqaWQsIHNldHRpbmdzLmVtYWlsIHx8IHNldHRpbmdzLnVpZCk7XG5cbiAgICAvLyBPbmNlIHdlJ3ZlIGpvaW5lZCB0aGUgbXVjIHNob3cgdGhlIHRvb2xiYXJcbiAgICBUb29sYmFyVG9nZ2xlci5zaG93VG9vbGJhcigpO1xuXG4gICAgLy8gU2hvdyBhdXRoZW50aWNhdGUgYnV0dG9uIGlmIG5lZWRlZFxuICAgIFRvb2xiYXIuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbihcbiAgICAgICAgICAgIE1vZGVyYXRvci5pc0V4dGVybmFsQXV0aEVuYWJsZWQoKSAmJiAhTW9kZXJhdG9yLmlzTW9kZXJhdG9yKCkpO1xuXG4gICAgdmFyIGRpc3BsYXlOYW1lID0gIWNvbmZpZy5kaXNwbGF5Smlkc1xuICAgICAgICA/IGluZm8uZGlzcGxheU5hbWUgOiBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuXG4gICAgaWYgKGRpc3BsYXlOYW1lKVxuICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdkaXNwbGF5bmFtZWNoYW5nZWQnLFxuICAgICAgICAgICAgWydsb2NhbFZpZGVvQ29udGFpbmVyJywgZGlzcGxheU5hbWUgKyAnIChtZSknXSk7XG59O1xuXG5VSS5pbml0RXRoZXJwYWQgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgIEV0aGVycGFkLmluaXQobmFtZSk7XG59O1xuXG5VSS5vbk11Y0xlZnQgPSBmdW5jdGlvbiAoamlkKSB7XG4gICAgY29uc29sZS5sb2coJ2xlZnQubXVjJywgamlkKTtcbiAgICB2YXIgZGlzcGxheU5hbWUgPSAkKCcjcGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCkgK1xuICAgICAgICAnPi5kaXNwbGF5bmFtZScpLmh0bWwoKTtcbiAgICBtZXNzYWdlSGFuZGxlci5ub3RpZnkoZGlzcGxheU5hbWUgfHwgJ1NvbWVib2R5JyxcbiAgICAgICAgJ2Rpc2Nvbm5lY3RlZCcsXG4gICAgICAgICdkaXNjb25uZWN0ZWQnKTtcbiAgICAvLyBOZWVkIHRvIGNhbGwgdGhpcyB3aXRoIGEgc2xpZ2h0IGRlbGF5LCBvdGhlcndpc2UgdGhlIGVsZW1lbnQgY291bGRuJ3QgYmVcbiAgICAvLyBmb3VuZCBmb3Igc29tZSByZWFzb24uXG4gICAgLy8gWFhYKGdwKSBpdCB3b3JrcyBmaW5lIHdpdGhvdXQgdGhlIHRpbWVvdXQgZm9yIG1lICh3aXRoIENocm9tZSAzOCkuXG4gICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgY29udGFpbmVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXG4gICAgICAgICAgICAgICAgJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpKTtcbiAgICAgICAgaWYgKGNvbnRhaW5lcikge1xuICAgICAgICAgICAgQ29udGFjdExpc3QucmVtb3ZlQ29udGFjdChqaWQpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVtb3ZlQ29ubmVjdGlvbkluZGljYXRvcihqaWQpO1xuICAgICAgICAgICAgLy8gaGlkZSBoZXJlLCB3YWl0IGZvciB2aWRlbyB0byBjbG9zZSBiZWZvcmUgcmVtb3ZpbmdcbiAgICAgICAgICAgICQoY29udGFpbmVyKS5oaWRlKCk7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5yZXNpemVUaHVtYm5haWxzKCk7XG4gICAgICAgIH1cbiAgICB9LCAxMCk7XG5cbiAgICAvLyBVbmxvY2sgbGFyZ2UgdmlkZW9cbiAgICBpZiAoZm9jdXNlZFZpZGVvSW5mbyAmJiBmb2N1c2VkVmlkZW9JbmZvLmppZCA9PT0gamlkKVxuICAgIHtcbiAgICAgICAgY29uc29sZS5pbmZvKFwiRm9jdXNlZCB2aWRlbyBvd25lciBoYXMgbGVmdCB0aGUgY29uZmVyZW5jZVwiKTtcbiAgICAgICAgZm9jdXNlZFZpZGVvSW5mbyA9IG51bGw7XG4gICAgfVxuXG59O1xuXG5VSS5nZXRTZXR0aW5ncyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbn07XG5cblVJLnRvZ2dsZUZpbG1TdHJpcCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gQm90dG9tVG9vbGJhci50b2dnbGVGaWxtU3RyaXAoKTtcbn07XG5cblVJLnRvZ2dsZUNoYXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIEJvdHRvbVRvb2xiYXIudG9nZ2xlQ2hhdCgpO1xufTtcblxuVUkudG9nZ2xlQ29udGFjdExpc3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIEJvdHRvbVRvb2xiYXIudG9nZ2xlQ29udGFjdExpc3QoKTtcbn07XG5cblVJLm9uTG9jYWxSb2xlQ2hhbmdlID0gZnVuY3Rpb24gKGppZCwgaW5mbywgcHJlcykge1xuXG4gICAgY29uc29sZS5pbmZvKFwiTXkgcm9sZSBjaGFuZ2VkLCBuZXcgcm9sZTogXCIgKyBpbmZvLnJvbGUpO1xuICAgIHZhciBpc01vZGVyYXRvciA9IE1vZGVyYXRvci5pc01vZGVyYXRvcigpO1xuXG4gICAgVmlkZW9MYXlvdXQuc2hvd01vZGVyYXRvckluZGljYXRvcigpO1xuICAgIFRvb2xiYXIuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbihcbiAgICAgICAgICAgIE1vZGVyYXRvci5pc0V4dGVybmFsQXV0aEVuYWJsZWQoKSAmJiAhaXNNb2RlcmF0b3IpO1xuXG4gICAgaWYgKGlzTW9kZXJhdG9yKSB7XG4gICAgICAgIFRvb2xiYXIuY2xvc2VBdXRoZW50aWNhdGlvbldpbmRvdygpO1xuICAgICAgICBtZXNzYWdlSGFuZGxlci5ub3RpZnkoXG4gICAgICAgICAgICAnTWUnLCAnY29ubmVjdGVkJywgJ01vZGVyYXRvciByaWdodHMgZ3JhbnRlZCAhJyk7XG4gICAgfVxufTtcblxuVUkub25EaXNwb3NlQ29uZmVyZW5jZSA9IGZ1bmN0aW9uICh1bmxvYWQpIHtcbiAgICBUb29sYmFyLnNob3dBdXRoZW50aWNhdGVCdXR0b24oZmFsc2UpO1xufTtcblxuVUkub25Nb2RlcmF0b3JTdGF0dXNDaGFuZ2VkID0gZnVuY3Rpb24gKGlzTW9kZXJhdG9yKSB7XG5cbiAgICBUb29sYmFyLnNob3dTaXBDYWxsQnV0dG9uKGlzTW9kZXJhdG9yKTtcbiAgICBUb29sYmFyLnNob3dSZWNvcmRpbmdCdXR0b24oXG4gICAgICAgIGlzTW9kZXJhdG9yKTsgLy8mJlxuICAgIC8vIEZJWE1FOlxuICAgIC8vIFJlY29yZGluZyB2aXNpYmxlIGlmXG4gICAgLy8gdGhlcmUgYXJlIGF0IGxlYXN0IDIoKyAxIGZvY3VzKSBwYXJ0aWNpcGFudHNcbiAgICAvL09iamVjdC5rZXlzKGNvbm5lY3Rpb24uZW11Yy5tZW1iZXJzKS5sZW5ndGggPj0gMyk7XG5cbiAgICBpZiAoaXNNb2RlcmF0b3IgJiYgY29uZmlnLmV0aGVycGFkX2Jhc2UpIHtcbiAgICAgICAgRXRoZXJwYWQuaW5pdCgpO1xuICAgIH1cbn07XG5cblVJLm9uUGFzc3dvcmRSZXFpdXJlZCA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgIC8vIHBhc3N3b3JkIGlzIHJlcXVpcmVkXG4gICAgVG9vbGJhci5sb2NrTG9ja0J1dHRvbigpO1xuXG4gICAgbWVzc2FnZUhhbmRsZXIub3BlblR3b0J1dHRvbkRpYWxvZyhudWxsLFxuICAgICAgICAgICAgJzxoMj5QYXNzd29yZCByZXF1aXJlZDwvaDI+JyArXG4gICAgICAgICAgICAnPGlucHV0IGlkPVwibG9ja0tleVwiIHR5cGU9XCJ0ZXh0XCIgcGxhY2Vob2xkZXI9XCJwYXNzd29yZFwiIGF1dG9mb2N1cz4nLFxuICAgICAgICB0cnVlLFxuICAgICAgICBcIk9rXCIsXG4gICAgICAgIGZ1bmN0aW9uIChlLCB2LCBtLCBmKSB7fSxcbiAgICAgICAgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9ja0tleScpLmZvY3VzKCk7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uIChlLCB2LCBtLCBmKSB7XG4gICAgICAgICAgICBpZiAodikge1xuICAgICAgICAgICAgICAgIHZhciBsb2NrS2V5ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xvY2tLZXknKTtcbiAgICAgICAgICAgICAgICBpZiAobG9ja0tleS52YWx1ZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBUb29sYmFyLnNldFNoYXJlZEtleShsb2NrS2V5LnZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sobG9ja0tleS52YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgKTtcbn07XG5cblVJLm9uQXV0aGVudGljYXRpb25SZXF1aXJlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBleHRyYWN0IHJvb20gbmFtZSBmcm9tICdyb29tQG11Yy5zZXJ2ZXIubmV0J1xuICAgIHZhciByb29tID0gcm9vbU5hbWUuc3Vic3RyKDAsIHJvb21OYW1lLmluZGV4T2YoJ0AnKSk7XG5cbiAgICBtZXNzYWdlSGFuZGxlci5vcGVuRGlhbG9nKFxuICAgICAgICAnU3RvcCcsXG4gICAgICAgICAgICAnQXV0aGVudGljYXRpb24gaXMgcmVxdWlyZWQgdG8gY3JlYXRlIHJvb206PGJyLz4nICsgcm9vbSxcbiAgICAgICAgdHJ1ZSxcbiAgICAgICAge1xuICAgICAgICAgICAgQXV0aGVudGljYXRlOiAnYXV0aE5vdycsXG4gICAgICAgICAgICBDbG9zZTogJ2Nsb3NlJ1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAob25TdWJtaXRFdmVudCwgc3VibWl0VmFsdWUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbygnT24gc3VibWl0OiAnICsgc3VibWl0VmFsdWUsIHN1Ym1pdFZhbHVlKTtcbiAgICAgICAgICAgIGlmIChzdWJtaXRWYWx1ZSA9PT0gJ2F1dGhOb3cnKSB7XG4gICAgICAgICAgICAgICAgVG9vbGJhci5hdXRoZW50aWNhdGVDbGlja2VkKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIFRvb2xiYXIuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbih0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICk7XG59O1xuXG5VSS5zZXRSZWNvcmRpbmdCdXR0b25TdGF0ZSA9IGZ1bmN0aW9uIChzdGF0ZSkge1xuICAgIFRvb2xiYXIuc2V0UmVjb3JkaW5nQnV0dG9uU3RhdGUoc3RhdGUpO1xufTtcblxuVUkuY2hhbmdlRGVza3RvcFNoYXJpbmdCdXR0b25TdGF0ZSA9IGZ1bmN0aW9uIChpc1VzaW5nU2NyZWVuU3RyZWFtKSB7XG4gICAgVG9vbGJhci5jaGFuZ2VEZXNrdG9wU2hhcmluZ0J1dHRvblN0YXRlKGlzVXNpbmdTY3JlZW5TdHJlYW0pO1xufTtcblxuVUkuaW5wdXREaXNwbGF5TmFtZUhhbmRsZXIgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICBWaWRlb0xheW91dC5pbnB1dERpc3BsYXlOYW1lSGFuZGxlcih2YWx1ZSk7XG59O1xuXG5VSS5vbk11Y0VudGVyZWQgPSBmdW5jdGlvbiAoamlkLCBpZCwgZGlzcGxheU5hbWUpIHtcbiAgICBtZXNzYWdlSGFuZGxlci5ub3RpZnkoZGlzcGxheU5hbWUgfHwgJ1NvbWVib2R5JyxcbiAgICAgICAgJ2Nvbm5lY3RlZCcsXG4gICAgICAgICdjb25uZWN0ZWQnKTtcblxuICAgIC8vIEFkZCBQZWVyJ3MgY29udGFpbmVyXG4gICAgVmlkZW9MYXlvdXQuZW5zdXJlUGVlckNvbnRhaW5lckV4aXN0cyhqaWQsaWQpO1xuXG4gICAgaWYoQVBJQ29ubmVjdG9yLmlzRW5hYmxlZCgpICYmXG4gICAgICAgIEFQSUNvbm5lY3Rvci5pc0V2ZW50RW5hYmxlZChcInBhcnRpY2lwYW50Sm9pbmVkXCIpKVxuICAgIHtcbiAgICAgICAgQVBJQ29ubmVjdG9yLnRyaWdnZXJFdmVudChcInBhcnRpY2lwYW50Sm9pbmVkXCIse2ppZDogamlkfSk7XG4gICAgfVxufTtcblxuVUkub25NdWNQcmVzZW5jZVN0YXR1cyA9IGZ1bmN0aW9uICggamlkLCBpbmZvKSB7XG4gICAgVmlkZW9MYXlvdXQuc2V0UHJlc2VuY2VTdGF0dXMoXG4gICAgICAgICAgICAncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCksIGluZm8uc3RhdHVzKTtcbn07XG5cblVJLm9uTXVjUm9sZUNoYW5nZWQgPSBmdW5jdGlvbiAocm9sZSwgZGlzcGxheU5hbWUpIHtcbiAgICBWaWRlb0xheW91dC5zaG93TW9kZXJhdG9ySW5kaWNhdG9yKCk7XG5cbiAgICBpZiAocm9sZSA9PT0gJ21vZGVyYXRvcicpIHtcbiAgICAgICAgdmFyIGRpc3BsYXlOYW1lID0gZGlzcGxheU5hbWU7XG4gICAgICAgIGlmICghZGlzcGxheU5hbWUpIHtcbiAgICAgICAgICAgIGRpc3BsYXlOYW1lID0gJ1NvbWVib2R5JztcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdlSGFuZGxlci5ub3RpZnkoXG4gICAgICAgICAgICBkaXNwbGF5TmFtZSxcbiAgICAgICAgICAgICdjb25uZWN0ZWQnLFxuICAgICAgICAgICAgICAgICdNb2RlcmF0b3IgcmlnaHRzIGdyYW50ZWQgdG8gJyArIGRpc3BsYXlOYW1lICsgJyEnKTtcbiAgICB9XG59O1xuXG5VSS51cGRhdGVMb2NhbENvbm5lY3Rpb25TdGF0cyA9IGZ1bmN0aW9uKHBlcmNlbnQsIHN0YXRzKVxue1xuICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxvY2FsQ29ubmVjdGlvblN0YXRzKHBlcmNlbnQsIHN0YXRzKTtcbn07XG5cblVJLnVwZGF0ZUNvbm5lY3Rpb25TdGF0cyA9IGZ1bmN0aW9uKGppZCwgcGVyY2VudCwgc3RhdHMpXG57XG4gICAgVmlkZW9MYXlvdXQudXBkYXRlQ29ubmVjdGlvblN0YXRzKGppZCwgcGVyY2VudCwgc3RhdHMpO1xufTtcblxuVUkub25TdGF0c1N0b3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgVmlkZW9MYXlvdXQub25TdGF0c1N0b3AoKTtcbn07XG5cblVJLmdldExhcmdlVmlkZW9TdGF0ZSA9IGZ1bmN0aW9uKClcbntcbiAgICByZXR1cm4gVmlkZW9MYXlvdXQuZ2V0TGFyZ2VWaWRlb1N0YXRlKCk7XG59O1xuXG5VSS5zaG93TG9jYWxBdWRpb0luZGljYXRvciA9IGZ1bmN0aW9uIChtdXRlKSB7XG4gICAgVmlkZW9MYXlvdXQuc2hvd0xvY2FsQXVkaW9JbmRpY2F0b3IobXV0ZSk7XG59O1xuXG5VSS5jaGFuZ2VMb2NhbFZpZGVvID0gZnVuY3Rpb24gKHN0cmVhbSwgZmxpcHgpIHtcbiAgICBWaWRlb0xheW91dC5jaGFuZ2VMb2NhbFZpZGVvKHN0cmVhbSwgZmxpcHgpO1xufTtcblxuVUkuZ2VuZXJhdGVSb29tTmFtZSA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciByb29tbm9kZSA9IG51bGw7XG4gICAgdmFyIHBhdGggPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWU7XG5cbiAgICAvLyBkZXRlcm1pbmRlIHRoZSByb29tIG5vZGUgZnJvbSB0aGUgdXJsXG4gICAgLy8gVE9ETzoganVzdCB0aGUgcm9vbW5vZGUgb3IgdGhlIHdob2xlIGJhcmUgamlkP1xuICAgIGlmIChjb25maWcuZ2V0cm9vbW5vZGUgJiYgdHlwZW9mIGNvbmZpZy5nZXRyb29tbm9kZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAvLyBjdXN0b20gZnVuY3Rpb24gbWlnaHQgYmUgcmVzcG9uc2libGUgZm9yIGRvaW5nIHRoZSBwdXNoc3RhdGVcbiAgICAgICAgcm9vbW5vZGUgPSBjb25maWcuZ2V0cm9vbW5vZGUocGF0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLyogZmFsbCBiYWNrIHRvIGRlZmF1bHQgc3RyYXRlZ3lcbiAgICAgICAgICogdGhpcyBpcyBtYWtpbmcgYXNzdW1wdGlvbnMgYWJvdXQgaG93IHRoZSBVUkwtPnJvb20gbWFwcGluZyBoYXBwZW5zLlxuICAgICAgICAgKiBJdCBjdXJyZW50bHkgYXNzdW1lcyBkZXBsb3ltZW50IGF0IHJvb3QsIHdpdGggYSByZXdyaXRlIGxpa2UgdGhlXG4gICAgICAgICAqIGZvbGxvd2luZyBvbmUgKGZvciBuZ2lueCk6XG4gICAgICAgICBsb2NhdGlvbiB+IF4vKFthLXpBLVowLTldKykkIHtcbiAgICAgICAgIHJld3JpdGUgXi8oLiopJCAvIGJyZWFrO1xuICAgICAgICAgfVxuICAgICAgICAgKi9cbiAgICAgICAgaWYgKHBhdGgubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgcm9vbW5vZGUgPSBwYXRoLnN1YnN0cigxKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdmFyIHdvcmQgPSBSb29tTmFtZUdlbmVyYXRvci5nZW5lcmF0ZVJvb21XaXRob3V0U2VwYXJhdG9yKCk7XG4gICAgICAgICAgICByb29tbm9kZSA9IHdvcmQudG9Mb3dlckNhc2UoKTtcblxuICAgICAgICAgICAgd2luZG93Lmhpc3RvcnkucHVzaFN0YXRlKCdWaWRlb0NoYXQnLFxuICAgICAgICAgICAgICAgICAgICAnUm9vbTogJyArIHdvcmQsIHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSArIHdvcmQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcm9vbU5hbWUgPSByb29tbm9kZSArICdAJyArIGNvbmZpZy5ob3N0cy5tdWM7XG59O1xuXG5cblVJLmNvbm5lY3Rpb25JbmRpY2F0b3JTaG93TW9yZSA9IGZ1bmN0aW9uKGlkKVxue1xuICAgIHJldHVybiBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tpZF0uc2hvd01vcmUoKTtcbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IFVJO1xuXG4iLCJ2YXIgQ2FudmFzVXRpbCA9IHJlcXVpcmUoXCIuL0NhbnZhc1V0aWxzXCIpO1xuXG4vKipcbiAqIFRoZSBhdWRpbyBMZXZlbHMgcGx1Z2luLlxuICovXG52YXIgQXVkaW9MZXZlbHMgPSAoZnVuY3Rpb24obXkpIHtcbiAgICB2YXIgYXVkaW9MZXZlbENhbnZhc0NhY2hlID0ge307XG5cbiAgICBteS5MT0NBTF9MRVZFTCA9ICdsb2NhbCc7XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBhdWRpbyBsZXZlbCBjYW52YXMgZm9yIHRoZSBnaXZlbiBwZWVySmlkLiBJZiB0aGUgY2FudmFzXG4gICAgICogZGlkbid0IGV4aXN0IHdlIGNyZWF0ZSBpdC5cbiAgICAgKi9cbiAgICBteS51cGRhdGVBdWRpb0xldmVsQ2FudmFzID0gZnVuY3Rpb24gKHBlZXJKaWQsIFZpZGVvTGF5b3V0KSB7XG4gICAgICAgIHZhciByZXNvdXJjZUppZCA9IG51bGw7XG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9IG51bGw7XG4gICAgICAgIGlmICghcGVlckppZClcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ2xvY2FsVmlkZW9Db250YWluZXInO1xuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQocGVlckppZCk7XG5cbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB2aWRlb1NwYW4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh2aWRlb1NwYW5JZCk7XG5cbiAgICAgICAgaWYgKCF2aWRlb1NwYW4pIHtcbiAgICAgICAgICAgIGlmIChyZXNvdXJjZUppZClcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiTm8gdmlkZW8gZWxlbWVudCBmb3IgamlkXCIsIHJlc291cmNlSmlkKTtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiTm8gdmlkZW8gZWxlbWVudCBmb3IgbG9jYWwgdmlkZW8uXCIpO1xuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXVkaW9MZXZlbENhbnZhcyA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPmNhbnZhcycpO1xuXG4gICAgICAgIHZhciB2aWRlb1NwYWNlV2lkdGggPSAkKCcjcmVtb3RlVmlkZW9zJykud2lkdGgoKTtcbiAgICAgICAgdmFyIHRodW1ibmFpbFNpemUgPSBWaWRlb0xheW91dC5jYWxjdWxhdGVUaHVtYm5haWxTaXplKHZpZGVvU3BhY2VXaWR0aCk7XG4gICAgICAgIHZhciB0aHVtYm5haWxXaWR0aCA9IHRodW1ibmFpbFNpemVbMF07XG4gICAgICAgIHZhciB0aHVtYm5haWxIZWlnaHQgPSB0aHVtYm5haWxTaXplWzFdO1xuXG4gICAgICAgIGlmICghYXVkaW9MZXZlbENhbnZhcyB8fCBhdWRpb0xldmVsQ2FudmFzLmxlbmd0aCA9PT0gMCkge1xuXG4gICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzLmNsYXNzTmFtZSA9IFwiYXVkaW9sZXZlbFwiO1xuICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhcy5zdHlsZS5ib3R0b20gPSBcIi1cIiArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEvMiArIFwicHhcIjtcbiAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXMuc3R5bGUubGVmdCA9IFwiLVwiICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQS8yICsgXCJweFwiO1xuICAgICAgICAgICAgcmVzaXplQXVkaW9MZXZlbENhbnZhcyggYXVkaW9MZXZlbENhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgdGh1bWJuYWlsV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgIHRodW1ibmFpbEhlaWdodCk7XG5cbiAgICAgICAgICAgIHZpZGVvU3Bhbi5hcHBlbmRDaGlsZChhdWRpb0xldmVsQ2FudmFzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXMgPSBhdWRpb0xldmVsQ2FudmFzLmdldCgwKTtcblxuICAgICAgICAgICAgcmVzaXplQXVkaW9MZXZlbENhbnZhcyggYXVkaW9MZXZlbENhbnZhcyxcbiAgICAgICAgICAgICAgICAgICAgdGh1bWJuYWlsV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgIHRodW1ibmFpbEhlaWdodCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgYXVkaW8gbGV2ZWwgVUkgZm9yIHRoZSBnaXZlbiByZXNvdXJjZUppZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSByZXNvdXJjZUppZCB0aGUgcmVzb3VyY2UgamlkIGluZGljYXRpbmcgdGhlIHZpZGVvIGVsZW1lbnQgZm9yXG4gICAgICogd2hpY2ggd2UgZHJhdyB0aGUgYXVkaW8gbGV2ZWxcbiAgICAgKiBAcGFyYW0gYXVkaW9MZXZlbCB0aGUgbmV3QXVkaW8gbGV2ZWwgdG8gcmVuZGVyXG4gICAgICovXG4gICAgbXkudXBkYXRlQXVkaW9MZXZlbCA9IGZ1bmN0aW9uIChyZXNvdXJjZUppZCwgYXVkaW9MZXZlbCwgbGFyZ2VWaWRlb1Jlc291cmNlSmlkKSB7XG4gICAgICAgIGRyYXdBdWRpb0xldmVsQ2FudmFzKHJlc291cmNlSmlkLCBhdWRpb0xldmVsKTtcblxuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBnZXRWaWRlb1NwYW5JZChyZXNvdXJjZUppZCk7XG5cbiAgICAgICAgdmFyIGF1ZGlvTGV2ZWxDYW52YXMgPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5jYW52YXMnKS5nZXQoMCk7XG5cbiAgICAgICAgaWYgKCFhdWRpb0xldmVsQ2FudmFzKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHZhciBkcmF3Q29udGV4dCA9IGF1ZGlvTGV2ZWxDYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcblxuICAgICAgICB2YXIgY2FudmFzQ2FjaGUgPSBhdWRpb0xldmVsQ2FudmFzQ2FjaGVbcmVzb3VyY2VKaWRdO1xuXG4gICAgICAgIGRyYXdDb250ZXh0LmNsZWFyUmVjdCAoMCwgMCxcbiAgICAgICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzLndpZHRoLCBhdWRpb0xldmVsQ2FudmFzLmhlaWdodCk7XG4gICAgICAgIGRyYXdDb250ZXh0LmRyYXdJbWFnZShjYW52YXNDYWNoZSwgMCwgMCk7XG5cbiAgICAgICAgaWYocmVzb3VyY2VKaWQgPT09IEF1ZGlvTGV2ZWxzLkxPQ0FMX0xFVkVMKSB7XG4gICAgICAgICAgICBpZighY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZihyZXNvdXJjZUppZCAgPT09IGxhcmdlVmlkZW9SZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgQXVkaW9MZXZlbHMudXBkYXRlQWN0aXZlU3BlYWtlckF1ZGlvTGV2ZWwoYXVkaW9MZXZlbCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbXkudXBkYXRlQWN0aXZlU3BlYWtlckF1ZGlvTGV2ZWwgPSBmdW5jdGlvbihhdWRpb0xldmVsKSB7XG4gICAgICAgIHZhciBkcmF3Q29udGV4dCA9ICQoJyNhY3RpdmVTcGVha2VyQXVkaW9MZXZlbCcpWzBdLmdldENvbnRleHQoJzJkJyk7XG4gICAgICAgIHZhciByID0gaW50ZXJmYWNlQ29uZmlnLkFDVElWRV9TUEVBS0VSX0FWQVRBUl9TSVpFIC8gMjtcbiAgICAgICAgdmFyIGNlbnRlciA9IChpbnRlcmZhY2VDb25maWcuQUNUSVZFX1NQRUFLRVJfQVZBVEFSX1NJWkUgKyByKSAvIDI7XG5cbiAgICAgICAgLy8gU2F2ZSB0aGUgcHJldmlvdXMgc3RhdGUgb2YgdGhlIGNvbnRleHQuXG4gICAgICAgIGRyYXdDb250ZXh0LnNhdmUoKTtcblxuICAgICAgICBkcmF3Q29udGV4dC5jbGVhclJlY3QoMCwgMCwgMzAwLCAzMDApO1xuXG4gICAgICAgIC8vIERyYXcgYSBjaXJjbGUuXG4gICAgICAgIGRyYXdDb250ZXh0LmFyYyhjZW50ZXIsIGNlbnRlciwgciwgMCwgMiAqIE1hdGguUEkpO1xuXG4gICAgICAgIC8vIEFkZCBhIHNoYWRvdyBhcm91bmQgdGhlIGNpcmNsZVxuICAgICAgICBkcmF3Q29udGV4dC5zaGFkb3dDb2xvciA9IGludGVyZmFjZUNvbmZpZy5TSEFET1dfQ09MT1I7XG4gICAgICAgIGRyYXdDb250ZXh0LnNoYWRvd0JsdXIgPSBnZXRTaGFkb3dMZXZlbChhdWRpb0xldmVsKTtcbiAgICAgICAgZHJhd0NvbnRleHQuc2hhZG93T2Zmc2V0WCA9IDA7XG4gICAgICAgIGRyYXdDb250ZXh0LnNoYWRvd09mZnNldFkgPSAwO1xuXG4gICAgICAgIC8vIEZpbGwgdGhlIHNoYXBlLlxuICAgICAgICBkcmF3Q29udGV4dC5maWxsKCk7XG5cbiAgICAgICAgZHJhd0NvbnRleHQuc2F2ZSgpO1xuXG4gICAgICAgIGRyYXdDb250ZXh0LnJlc3RvcmUoKTtcblxuXG4gICAgICAgIGRyYXdDb250ZXh0LmFyYyhjZW50ZXIsIGNlbnRlciwgciwgMCwgMiAqIE1hdGguUEkpO1xuXG4gICAgICAgIGRyYXdDb250ZXh0LmNsaXAoKTtcbiAgICAgICAgZHJhd0NvbnRleHQuY2xlYXJSZWN0KDAsIDAsIDI3NywgMjAwKTtcblxuICAgICAgICAvLyBSZXN0b3JlIHRoZSBwcmV2aW91cyBjb250ZXh0IHN0YXRlLlxuICAgICAgICBkcmF3Q29udGV4dC5yZXN0b3JlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGhlIGdpdmVuIGF1ZGlvIGxldmVsIGNhbnZhcyB0byBtYXRjaCB0aGUgZ2l2ZW4gdGh1bWJuYWlsIHNpemUuXG4gICAgICovXG4gICAgZnVuY3Rpb24gcmVzaXplQXVkaW9MZXZlbENhbnZhcyhhdWRpb0xldmVsQ2FudmFzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGh1bWJuYWlsV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHVtYm5haWxIZWlnaHQpIHtcbiAgICAgICAgYXVkaW9MZXZlbENhbnZhcy53aWR0aCA9IHRodW1ibmFpbFdpZHRoICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQTtcbiAgICAgICAgYXVkaW9MZXZlbENhbnZhcy5oZWlnaHQgPSB0aHVtYm5haWxIZWlnaHQgKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERyYXdzIHRoZSBhdWRpbyBsZXZlbCBjYW52YXMgaW50byB0aGUgY2FjaGVkIGNhbnZhcyBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcmVzb3VyY2VKaWQgdGhlIHJlc291cmNlIGppZCBpbmRpY2F0aW5nIHRoZSB2aWRlbyBlbGVtZW50IGZvclxuICAgICAqIHdoaWNoIHdlIGRyYXcgdGhlIGF1ZGlvIGxldmVsXG4gICAgICogQHBhcmFtIGF1ZGlvTGV2ZWwgdGhlIG5ld0F1ZGlvIGxldmVsIHRvIHJlbmRlclxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGRyYXdBdWRpb0xldmVsQ2FudmFzKHJlc291cmNlSmlkLCBhdWRpb0xldmVsKSB7XG4gICAgICAgIGlmICghYXVkaW9MZXZlbENhbnZhc0NhY2hlW3Jlc291cmNlSmlkXSkge1xuXG4gICAgICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBnZXRWaWRlb1NwYW5JZChyZXNvdXJjZUppZCk7XG5cbiAgICAgICAgICAgIHZhciBhdWRpb0xldmVsQ2FudmFzT3JpZyA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPmNhbnZhcycpLmdldCgwKTtcblxuICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAqIEZJWE1FIFRlc3RpbmcgaGFzIHNob3duIHRoYXQgYXVkaW9MZXZlbENhbnZhc09yaWcgbWF5IG5vdCBleGlzdC5cbiAgICAgICAgICAgICAqIEluIHN1Y2ggYSBjYXNlLCB0aGUgbWV0aG9kIENhbnZhc1V0aWwuY2xvbmVDYW52YXMgbWF5IHRocm93IGFuXG4gICAgICAgICAgICAgKiBlcnJvci4gU2luY2UgYXVkaW8gbGV2ZWxzIGFyZSBmcmVxdWVudGx5IHVwZGF0ZWQsIHRoZSBlcnJvcnMgaGF2ZVxuICAgICAgICAgICAgICogYmVlbiBvYnNlcnZlZCB0byBwaWxlIGludG8gdGhlIGNvbnNvbGUsIHN0cmFpbiB0aGUgQ1BVLlxuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBpZiAoYXVkaW9MZXZlbENhbnZhc09yaWcpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhc0NhY2hlW3Jlc291cmNlSmlkXVxuICAgICAgICAgICAgICAgICAgICA9IENhbnZhc1V0aWwuY2xvbmVDYW52YXMoYXVkaW9MZXZlbENhbnZhc09yaWcpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNhbnZhcyA9IGF1ZGlvTGV2ZWxDYW52YXNDYWNoZVtyZXNvdXJjZUppZF07XG5cbiAgICAgICAgaWYgKCFjYW52YXMpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdmFyIGRyYXdDb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG5cbiAgICAgICAgZHJhd0NvbnRleHQuY2xlYXJSZWN0KDAsIDAsIGNhbnZhcy53aWR0aCwgY2FudmFzLmhlaWdodCk7XG5cbiAgICAgICAgdmFyIHNoYWRvd0xldmVsID0gZ2V0U2hhZG93TGV2ZWwoYXVkaW9MZXZlbCk7XG5cbiAgICAgICAgaWYgKHNoYWRvd0xldmVsID4gMClcbiAgICAgICAgICAgIC8vIGRyYXdDb250ZXh0LCB4LCB5LCB3LCBoLCByLCBzaGFkb3dDb2xvciwgc2hhZG93TGV2ZWxcbiAgICAgICAgICAgIENhbnZhc1V0aWwuZHJhd1JvdW5kUmVjdEdsb3coICAgZHJhd0NvbnRleHQsXG4gICAgICAgICAgICAgICAgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQS8yLCBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLzIsXG4gICAgICAgICAgICAgICAgY2FudmFzLndpZHRoIC0gaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQSxcbiAgICAgICAgICAgICAgICBjYW52YXMuaGVpZ2h0IC0gaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQSxcbiAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX1JBRElVUyxcbiAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuU0hBRE9XX0NPTE9SLFxuICAgICAgICAgICAgICAgIHNoYWRvd0xldmVsKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBzaGFkb3cvZ2xvdyBsZXZlbCBmb3IgdGhlIGdpdmVuIGF1ZGlvIGxldmVsLlxuICAgICAqXG4gICAgICogQHBhcmFtIGF1ZGlvTGV2ZWwgdGhlIGF1ZGlvIGxldmVsIGZyb20gd2hpY2ggd2UgZGV0ZXJtaW5lIHRoZSBzaGFkb3dcbiAgICAgKiBsZXZlbFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGdldFNoYWRvd0xldmVsIChhdWRpb0xldmVsKSB7XG4gICAgICAgIHZhciBzaGFkb3dMZXZlbCA9IDA7XG5cbiAgICAgICAgaWYgKGF1ZGlvTGV2ZWwgPD0gMC4zKSB7XG4gICAgICAgICAgICBzaGFkb3dMZXZlbCA9IE1hdGgucm91bmQoaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQS8yKihhdWRpb0xldmVsLzAuMykpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGF1ZGlvTGV2ZWwgPD0gMC42KSB7XG4gICAgICAgICAgICBzaGFkb3dMZXZlbCA9IE1hdGgucm91bmQoaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQS8yKigoYXVkaW9MZXZlbCAtIDAuMykgLyAwLjMpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHNoYWRvd0xldmVsID0gTWF0aC5yb3VuZChpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLzIqKChhdWRpb0xldmVsIC0gMC42KSAvIDAuNCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzaGFkb3dMZXZlbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSB2aWRlbyBzcGFuIGlkIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGdpdmVuIHJlc291cmNlSmlkIG9yIGxvY2FsXG4gICAgICogdXNlci5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRWaWRlb1NwYW5JZChyZXNvdXJjZUppZCkge1xuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBudWxsO1xuICAgICAgICBpZiAocmVzb3VyY2VKaWQgPT09IEF1ZGlvTGV2ZWxzLkxPQ0FMX0xFVkVMXG4gICAgICAgICAgICAgICAgfHwgKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQgJiYgcmVzb3VyY2VKaWRcbiAgICAgICAgICAgICAgICAgICAgPT09IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpKSlcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ2xvY2FsVmlkZW9Db250YWluZXInO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICB2aWRlb1NwYW5JZCA9ICdwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQ7XG5cbiAgICAgICAgcmV0dXJuIHZpZGVvU3BhbklkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEluZGljYXRlcyB0aGF0IHRoZSByZW1vdGUgdmlkZW8gaGFzIGJlZW4gcmVzaXplZC5cbiAgICAgKi9cbiAgICAkKGRvY3VtZW50KS5iaW5kKCdyZW1vdGV2aWRlby5yZXNpemVkJywgZnVuY3Rpb24gKGV2ZW50LCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgICAgIHZhciByZXNpemVkID0gZmFsc2U7XG4gICAgICAgICQoJyNyZW1vdGVWaWRlb3M+c3Bhbj5jYW52YXMnKS5lYWNoKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGNhbnZhcyA9ICQodGhpcykuZ2V0KDApO1xuICAgICAgICAgICAgaWYgKGNhbnZhcy53aWR0aCAhPT0gd2lkdGggKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBKSB7XG4gICAgICAgICAgICAgICAgY2FudmFzLndpZHRoID0gd2lkdGggKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBO1xuICAgICAgICAgICAgICAgIHJlc2l6ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoY2FudmFzLmhlaWdoICE9PSBoZWlnaHQgKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBKSB7XG4gICAgICAgICAgICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodCArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkE7XG4gICAgICAgICAgICAgICAgcmVzaXplZCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChyZXNpemVkKVxuICAgICAgICAgICAgT2JqZWN0LmtleXMoYXVkaW9MZXZlbENhbnZhc0NhY2hlKS5mb3JFYWNoKGZ1bmN0aW9uIChyZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXNDYWNoZVtyZXNvdXJjZUppZF0ud2lkdGhcbiAgICAgICAgICAgICAgICAgICAgPSB3aWR0aCArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkE7XG4gICAgICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhc0NhY2hlW3Jlc291cmNlSmlkXS5oZWlnaHRcbiAgICAgICAgICAgICAgICAgICAgPSBoZWlnaHQgKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBO1xuICAgICAgICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gbXk7XG5cbn0pKEF1ZGlvTGV2ZWxzIHx8IHt9KTtcblxubW9kdWxlLmV4cG9ydHMgPSBBdWRpb0xldmVsczsiLCIvKipcbiAqIFV0aWxpdHkgY2xhc3MgZm9yIGRyYXdpbmcgY2FudmFzIHNoYXBlcy5cbiAqL1xudmFyIENhbnZhc1V0aWwgPSAoZnVuY3Rpb24obXkpIHtcblxuICAgIC8qKlxuICAgICAqIERyYXdzIGEgcm91bmQgcmVjdGFuZ2xlIHdpdGggYSBnbG93LiBUaGUgZ2xvd1dpZHRoIGluZGljYXRlcyB0aGUgZGVwdGhcbiAgICAgKiBvZiB0aGUgZ2xvdy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBkcmF3Q29udGV4dCB0aGUgY29udGV4dCBvZiB0aGUgY2FudmFzIHRvIGRyYXcgdG9cbiAgICAgKiBAcGFyYW0geCB0aGUgeCBjb29yZGluYXRlIG9mIHRoZSByb3VuZCByZWN0YW5nbGVcbiAgICAgKiBAcGFyYW0geSB0aGUgeSBjb29yZGluYXRlIG9mIHRoZSByb3VuZCByZWN0YW5nbGVcbiAgICAgKiBAcGFyYW0gdyB0aGUgd2lkdGggb2YgdGhlIHJvdW5kIHJlY3RhbmdsZVxuICAgICAqIEBwYXJhbSBoIHRoZSBoZWlnaHQgb2YgdGhlIHJvdW5kIHJlY3RhbmdsZVxuICAgICAqIEBwYXJhbSBnbG93Q29sb3IgdGhlIGNvbG9yIG9mIHRoZSBnbG93XG4gICAgICogQHBhcmFtIGdsb3dXaWR0aCB0aGUgd2lkdGggb2YgdGhlIGdsb3dcbiAgICAgKi9cbiAgICBteS5kcmF3Um91bmRSZWN0R2xvd1xuICAgICAgICA9IGZ1bmN0aW9uKGRyYXdDb250ZXh0LCB4LCB5LCB3LCBoLCByLCBnbG93Q29sb3IsIGdsb3dXaWR0aCkge1xuXG4gICAgICAgIC8vIFNhdmUgdGhlIHByZXZpb3VzIHN0YXRlIG9mIHRoZSBjb250ZXh0LlxuICAgICAgICBkcmF3Q29udGV4dC5zYXZlKCk7XG5cbiAgICAgICAgaWYgKHcgPCAyICogcikgciA9IHcgLyAyO1xuICAgICAgICBpZiAoaCA8IDIgKiByKSByID0gaCAvIDI7XG5cbiAgICAgICAgLy8gRHJhdyBhIHJvdW5kIHJlY3RhbmdsZS5cbiAgICAgICAgZHJhd0NvbnRleHQuYmVnaW5QYXRoKCk7XG4gICAgICAgIGRyYXdDb250ZXh0Lm1vdmVUbyh4K3IsIHkpO1xuICAgICAgICBkcmF3Q29udGV4dC5hcmNUbyh4K3csIHksICAgeCt3LCB5K2gsIHIpO1xuICAgICAgICBkcmF3Q29udGV4dC5hcmNUbyh4K3csIHkraCwgeCwgICB5K2gsIHIpO1xuICAgICAgICBkcmF3Q29udGV4dC5hcmNUbyh4LCAgIHkraCwgeCwgICB5LCAgIHIpO1xuICAgICAgICBkcmF3Q29udGV4dC5hcmNUbyh4LCAgIHksICAgeCt3LCB5LCAgIHIpO1xuICAgICAgICBkcmF3Q29udGV4dC5jbG9zZVBhdGgoKTtcblxuICAgICAgICAvLyBBZGQgYSBzaGFkb3cgYXJvdW5kIHRoZSByZWN0YW5nbGVcbiAgICAgICAgZHJhd0NvbnRleHQuc2hhZG93Q29sb3IgPSBnbG93Q29sb3I7XG4gICAgICAgIGRyYXdDb250ZXh0LnNoYWRvd0JsdXIgPSBnbG93V2lkdGg7XG4gICAgICAgIGRyYXdDb250ZXh0LnNoYWRvd09mZnNldFggPSAwO1xuICAgICAgICBkcmF3Q29udGV4dC5zaGFkb3dPZmZzZXRZID0gMDtcblxuICAgICAgICAvLyBGaWxsIHRoZSBzaGFwZS5cbiAgICAgICAgZHJhd0NvbnRleHQuZmlsbCgpO1xuXG4gICAgICAgIGRyYXdDb250ZXh0LnNhdmUoKTtcblxuICAgICAgICBkcmF3Q29udGV4dC5yZXN0b3JlKCk7XG5cbi8vICAgICAgMSkgVW5jb21tZW50IHRoaXMgbGluZSB0byB1c2UgQ29tcG9zaXRlIE9wZXJhdGlvbiwgd2hpY2ggaXMgZG9pbmcgdGhlXG4vLyAgICAgIHNhbWUgYXMgdGhlIGNsaXAgZnVuY3Rpb24gYmVsb3cgYW5kIGlzIGFsc28gYW50aWFsaWFzaW5nIHRoZSByb3VuZFxuLy8gICAgICBib3JkZXIsIGJ1dCBpcyBzYWlkIHRvIGJlIGxlc3MgZmFzdCBwZXJmb3JtYW5jZSB3aXNlLlxuXG4vLyAgICAgIGRyYXdDb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbj0nZGVzdGluYXRpb24tb3V0JztcblxuICAgICAgICBkcmF3Q29udGV4dC5iZWdpblBhdGgoKTtcbiAgICAgICAgZHJhd0NvbnRleHQubW92ZVRvKHgrciwgeSk7XG4gICAgICAgIGRyYXdDb250ZXh0LmFyY1RvKHgrdywgeSwgICB4K3csIHkraCwgcik7XG4gICAgICAgIGRyYXdDb250ZXh0LmFyY1RvKHgrdywgeStoLCB4LCAgIHkraCwgcik7XG4gICAgICAgIGRyYXdDb250ZXh0LmFyY1RvKHgsICAgeStoLCB4LCAgIHksICAgcik7XG4gICAgICAgIGRyYXdDb250ZXh0LmFyY1RvKHgsICAgeSwgICB4K3csIHksICAgcik7XG4gICAgICAgIGRyYXdDb250ZXh0LmNsb3NlUGF0aCgpO1xuXG4vLyAgICAgIDIpIFVuY29tbWVudCB0aGlzIGxpbmUgdG8gdXNlIENvbXBvc2l0ZSBPcGVyYXRpb24sIHdoaWNoIGlzIGRvaW5nIHRoZVxuLy8gICAgICBzYW1lIGFzIHRoZSBjbGlwIGZ1bmN0aW9uIGJlbG93IGFuZCBpcyBhbHNvIGFudGlhbGlhc2luZyB0aGUgcm91bmRcbi8vICAgICAgYm9yZGVyLCBidXQgaXMgc2FpZCB0byBiZSBsZXNzIGZhc3QgcGVyZm9ybWFuY2Ugd2lzZS5cblxuLy8gICAgICBkcmF3Q29udGV4dC5maWxsKCk7XG5cbiAgICAgICAgLy8gQ29tbWVudCB0aGVzZSB0d28gbGluZXMgaWYgY2hvb3NpbmcgdG8gZG8gdGhlIHNhbWUgd2l0aCBjb21wb3NpdGVcbiAgICAgICAgLy8gb3BlcmF0aW9uIGFib3ZlIDEgYW5kIDIuXG4gICAgICAgIGRyYXdDb250ZXh0LmNsaXAoKTtcbiAgICAgICAgZHJhd0NvbnRleHQuY2xlYXJSZWN0KDAsIDAsIDI3NywgMjAwKTtcblxuICAgICAgICAvLyBSZXN0b3JlIHRoZSBwcmV2aW91cyBjb250ZXh0IHN0YXRlLlxuICAgICAgICBkcmF3Q29udGV4dC5yZXN0b3JlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENsb25lcyB0aGUgZ2l2ZW4gY2FudmFzLlxuICAgICAqXG4gICAgICogQHJldHVybiB0aGUgbmV3IGNsb25lZCBjYW52YXMuXG4gICAgICovXG4gICAgbXkuY2xvbmVDYW52YXMgPSBmdW5jdGlvbiAob2xkQ2FudmFzKSB7XG4gICAgICAgIC8qXG4gICAgICAgICAqIEZJWE1FIFRlc3RpbmcgaGFzIHNob3duIHRoYXQgb2xkQ2FudmFzIG1heSBub3QgZXhpc3QuIEluIHN1Y2ggYSBjYXNlLFxuICAgICAgICAgKiB0aGUgbWV0aG9kIENhbnZhc1V0aWwuY2xvbmVDYW52YXMgbWF5IHRocm93IGFuIGVycm9yLiBTaW5jZSBhdWRpb1xuICAgICAgICAgKiBsZXZlbHMgYXJlIGZyZXF1ZW50bHkgdXBkYXRlZCwgdGhlIGVycm9ycyBoYXZlIGJlZW4gb2JzZXJ2ZWQgdG8gcGlsZVxuICAgICAgICAgKiBpbnRvIHRoZSBjb25zb2xlLCBzdHJhaW4gdGhlIENQVS5cbiAgICAgICAgICovXG4gICAgICAgIGlmICghb2xkQ2FudmFzKVxuICAgICAgICAgICAgcmV0dXJuIG9sZENhbnZhcztcblxuICAgICAgICAvL2NyZWF0ZSBhIG5ldyBjYW52YXNcbiAgICAgICAgdmFyIG5ld0NhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgICAgICB2YXIgY29udGV4dCA9IG5ld0NhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuXG4gICAgICAgIC8vc2V0IGRpbWVuc2lvbnNcbiAgICAgICAgbmV3Q2FudmFzLndpZHRoID0gb2xkQ2FudmFzLndpZHRoO1xuICAgICAgICBuZXdDYW52YXMuaGVpZ2h0ID0gb2xkQ2FudmFzLmhlaWdodDtcblxuICAgICAgICAvL2FwcGx5IHRoZSBvbGQgY2FudmFzIHRvIHRoZSBuZXcgb25lXG4gICAgICAgIGNvbnRleHQuZHJhd0ltYWdlKG9sZENhbnZhcywgMCwgMCk7XG5cbiAgICAgICAgLy9yZXR1cm4gdGhlIG5ldyBjYW52YXNcbiAgICAgICAgcmV0dXJuIG5ld0NhbnZhcztcbiAgICB9O1xuXG4gICAgcmV0dXJuIG15O1xufSkoQ2FudmFzVXRpbCB8fCB7fSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2FudmFzVXRpbDsiLCJ2YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi4vc2lkZV9wYW5uZWxzL3NldHRpbmdzL1NldHRpbmdzXCIpO1xuXG52YXIgdXNlcnMgPSB7fTtcbnZhciBhY3RpdmVTcGVha2VySmlkO1xuXG5mdW5jdGlvbiBzZXRWaXNpYmlsaXR5KHNlbGVjdG9yLCBzaG93KSB7XG4gICAgaWYgKHNlbGVjdG9yICYmIHNlbGVjdG9yLmxlbmd0aCA+IDApIHtcbiAgICAgICAgc2VsZWN0b3IuY3NzKFwidmlzaWJpbGl0eVwiLCBzaG93ID8gXCJ2aXNpYmxlXCIgOiBcImhpZGRlblwiKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGlzVXNlck11dGVkKGppZCkge1xuICAgIC8vIFhYWChncCkgd2UgbWF5IHdhbnQgdG8gcmVuYW1lIHRoaXMgbWV0aG9kIHRvIHNvbWV0aGluZyBsaWtlXG4gICAgLy8gaXNVc2VyU3RyZWFtaW5nLCBmb3IgZXhhbXBsZS5cbiAgICBpZiAoamlkICYmIGppZCAhPSBjb25uZWN0aW9uLmVtdWMubXlyb29tamlkKSB7XG4gICAgICAgIHZhciByZXNvdXJjZSA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIGlmICghcmVxdWlyZShcIi4uL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0XCIpLmlzSW5MYXN0TihyZXNvdXJjZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFSVEMucmVtb3RlU3RyZWFtc1tqaWRdIHx8ICFSVEMucmVtb3RlU3RyZWFtc1tqaWRdW01lZGlhU3RyZWFtVHlwZS5WSURFT19UWVBFXSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgcmV0dXJuIFJUQy5yZW1vdGVTdHJlYW1zW2ppZF1bTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdLm11dGVkO1xufVxuXG5mdW5jdGlvbiBnZXRHcmF2YXRhclVybChpZCwgc2l6ZSkge1xuICAgIGlmKGlkID09PSBjb25uZWN0aW9uLmVtdWMubXlyb29tamlkIHx8ICFpZCkge1xuICAgICAgICBpZCA9IFNldHRpbmdzLmdldFNldHRpbmdzKCkudWlkO1xuICAgIH1cbiAgICByZXR1cm4gJ2h0dHBzOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvJyArXG4gICAgICAgIE1ENS5oZXhkaWdlc3QoaWQudHJpbSgpLnRvTG93ZXJDYXNlKCkpICtcbiAgICAgICAgXCI/ZD13YXZhdGFyJnNpemU9XCIgKyAoc2l6ZSB8fCBcIjMwXCIpO1xufVxuXG52YXIgQXZhdGFyID0ge1xuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgdXNlcidzIGF2YXRhciBpbiB0aGUgc2V0dGluZ3MgbWVudShpZiBsb2NhbCB1c2VyKSwgY29udGFjdCBsaXN0XG4gICAgICogYW5kIHRodW1ibmFpbFxuICAgICAqIEBwYXJhbSBqaWQgamlkIG9mIHRoZSB1c2VyXG4gICAgICogQHBhcmFtIGlkIGVtYWlsIG9yIHVzZXJJRCB0byBiZSB1c2VkIGFzIGEgaGFzaFxuICAgICAqL1xuICAgIHNldFVzZXJBdmF0YXI6IGZ1bmN0aW9uIChqaWQsIGlkKSB7XG4gICAgICAgIGlmIChpZCkge1xuICAgICAgICAgICAgaWYgKHVzZXJzW2ppZF0gPT09IGlkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdXNlcnNbamlkXSA9IGlkO1xuICAgICAgICB9XG4gICAgICAgIHZhciB0aHVtYlVybCA9IGdldEdyYXZhdGFyVXJsKHVzZXJzW2ppZF0gfHwgamlkLCAxMDApO1xuICAgICAgICB2YXIgY29udGFjdExpc3RVcmwgPSBnZXRHcmF2YXRhclVybCh1c2Vyc1tqaWRdIHx8IGppZCk7XG4gICAgICAgIHZhciByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIHZhciB0aHVtYm5haWwgPSAkKCcjcGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkKTtcbiAgICAgICAgdmFyIGF2YXRhciA9ICQoJyNhdmF0YXJfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICAvLyBzZXQgdGhlIGF2YXRhciBpbiB0aGUgc2V0dGluZ3MgbWVudSBpZiBpdCBpcyBsb2NhbCB1c2VyIGFuZCBnZXQgdGhlXG4gICAgICAgIC8vIGxvY2FsIHZpZGVvIGNvbnRhaW5lclxuICAgICAgICBpZiAoamlkID09PSBjb25uZWN0aW9uLmVtdWMubXlyb29tamlkKSB7XG4gICAgICAgICAgICAkKCcjYXZhdGFyJykuZ2V0KDApLnNyYyA9IHRodW1iVXJsO1xuICAgICAgICAgICAgdGh1bWJuYWlsID0gJCgnI2xvY2FsVmlkZW9Db250YWluZXInKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNldCB0aGUgYXZhdGFyIGluIHRoZSBjb250YWN0IGxpc3RcbiAgICAgICAgdmFyIGNvbnRhY3QgPSAkKCcjJyArIHJlc291cmNlSmlkICsgJz5pbWcnKTtcbiAgICAgICAgaWYgKGNvbnRhY3QgJiYgY29udGFjdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb250YWN0LmdldCgwKS5zcmMgPSBjb250YWN0TGlzdFVybDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNldCB0aGUgYXZhdGFyIGluIHRoZSB0aHVtYm5haWxcbiAgICAgICAgaWYgKGF2YXRhciAmJiBhdmF0YXIubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgYXZhdGFyWzBdLnNyYyA9IHRodW1iVXJsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKHRodW1ibmFpbCAmJiB0aHVtYm5haWwubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGF2YXRhciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2ltZycpO1xuICAgICAgICAgICAgICAgIGF2YXRhci5pZCA9ICdhdmF0YXJfJyArIHJlc291cmNlSmlkO1xuICAgICAgICAgICAgICAgIGF2YXRhci5jbGFzc05hbWUgPSAndXNlckF2YXRhcic7XG4gICAgICAgICAgICAgICAgYXZhdGFyLnNyYyA9IHRodW1iVXJsO1xuICAgICAgICAgICAgICAgIHRodW1ibmFpbC5hcHBlbmQoYXZhdGFyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vaWYgdGhlIHVzZXIgaXMgdGhlIGN1cnJlbnQgYWN0aXZlIHNwZWFrZXIgLSB1cGRhdGUgdGhlIGFjdGl2ZSBzcGVha2VyXG4gICAgICAgIC8vIGF2YXRhclxuICAgICAgICBpZiAoamlkID09PSBhY3RpdmVTcGVha2VySmlkKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUFjdGl2ZVNwZWFrZXJBdmF0YXJTcmMoamlkKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBIaWRlcyBvciBzaG93cyB0aGUgdXNlcidzIGF2YXRhclxuICAgICAqIEBwYXJhbSBqaWQgamlkIG9mIHRoZSB1c2VyXG4gICAgICogQHBhcmFtIHNob3cgd2hldGhlciB3ZSBzaG91bGQgc2hvdyB0aGUgYXZhdGFyIG9yIG5vdFxuICAgICAqIHZpZGVvIGJlY2F1c2UgdGhlcmUgaXMgbm8gZG9taW5hbnQgc3BlYWtlciBhbmQgbm8gZm9jdXNlZCBzcGVha2VyXG4gICAgICovXG4gICAgc2hvd1VzZXJBdmF0YXI6IGZ1bmN0aW9uIChqaWQsIHNob3cpIHtcbiAgICAgICAgaWYgKHVzZXJzW2ppZF0pIHtcbiAgICAgICAgICAgIHZhciByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgICAgICB2YXIgdmlkZW8gPSAkKCcjcGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkICsgJz52aWRlbycpO1xuICAgICAgICAgICAgdmFyIGF2YXRhciA9ICQoJyNhdmF0YXJfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICAgICAgaWYgKGppZCA9PT0gY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCkge1xuICAgICAgICAgICAgICAgIHZpZGVvID0gJCgnI2xvY2FsVmlkZW9XcmFwcGVyPnZpZGVvJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoc2hvdyA9PT0gdW5kZWZpbmVkIHx8IHNob3cgPT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBzaG93ID0gaXNVc2VyTXV0ZWQoamlkKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy9pZiB0aGUgdXNlciBpcyB0aGUgY3VycmVudGx5IGZvY3VzZWQsIHRoZSBkb21pbmFudCBzcGVha2VyIG9yIGlmXG4gICAgICAgICAgICAvL3RoZXJlIGlzIG5vIGZvY3VzZWQgYW5kIG5vIGRvbWluYW50IHNwZWFrZXIgYW5kIHRoZSBsYXJnZSB2aWRlbyBpc1xuICAgICAgICAgICAgLy9jdXJyZW50bHkgc2hvd25cbiAgICAgICAgICAgIGlmIChhY3RpdmVTcGVha2VySmlkID09PSBqaWQgJiYgcmVxdWlyZShcIi4uL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0XCIpLmlzTGFyZ2VWaWRlb09uVG9wKCkpIHtcbiAgICAgICAgICAgICAgICBzZXRWaXNpYmlsaXR5KCQoXCIjbGFyZ2VWaWRlb1wiKSwgIXNob3cpO1xuICAgICAgICAgICAgICAgIHNldFZpc2liaWxpdHkoJCgnI2FjdGl2ZVNwZWFrZXInKSwgc2hvdyk7XG4gICAgICAgICAgICAgICAgc2V0VmlzaWJpbGl0eShhdmF0YXIsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICBzZXRWaXNpYmlsaXR5KHZpZGVvLCBmYWxzZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICh2aWRlbyAmJiB2aWRlby5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHNldFZpc2liaWxpdHkodmlkZW8sICFzaG93KTtcbiAgICAgICAgICAgICAgICAgICAgc2V0VmlzaWJpbGl0eShhdmF0YXIsIHNob3cpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBzcmMgb2YgdGhlIGFjdGl2ZSBzcGVha2VyIGF2YXRhclxuICAgICAqIEBwYXJhbSBqaWQgb2YgdGhlIGN1cnJlbnQgYWN0aXZlIHNwZWFrZXJcbiAgICAgKi9cbiAgICB1cGRhdGVBY3RpdmVTcGVha2VyQXZhdGFyU3JjOiBmdW5jdGlvbiAoamlkKSB7XG4gICAgICAgIGlmICghamlkKSB7XG4gICAgICAgICAgICBqaWQgPSBjb25uZWN0aW9uLmVtdWMuZmluZEppZEZyb21SZXNvdXJjZShcbiAgICAgICAgICAgICAgICByZXF1aXJlKFwiLi4vdmlkZW9sYXlvdXQvVmlkZW9MYXlvdXRcIikuZ2V0TGFyZ2VWaWRlb1N0YXRlKCkudXNlclJlc291cmNlSmlkKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgYXZhdGFyID0gJChcIiNhY3RpdmVTcGVha2VyQXZhdGFyXCIpWzBdO1xuICAgICAgICB2YXIgdXJsID0gZ2V0R3JhdmF0YXJVcmwodXNlcnNbamlkXSxcbiAgICAgICAgICAgIGludGVyZmFjZUNvbmZpZy5BQ1RJVkVfU1BFQUtFUl9BVkFUQVJfU0laRSk7XG4gICAgICAgIGlmIChqaWQgPT09IGFjdGl2ZVNwZWFrZXJKaWQgJiYgYXZhdGFyLnNyYyA9PT0gdXJsKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYWN0aXZlU3BlYWtlckppZCA9IGppZDtcbiAgICAgICAgdmFyIGlzTXV0ZWQgPSBpc1VzZXJNdXRlZChqaWQpO1xuICAgICAgICBpZiAoamlkICYmIGlzTXV0ZWQgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGF2YXRhci5zcmMgPSB1cmw7XG4gICAgICAgICAgICBzZXRWaXNpYmlsaXR5KCQoXCIjbGFyZ2VWaWRlb1wiKSwgIWlzTXV0ZWQpO1xuICAgICAgICAgICAgQXZhdGFyLnNob3dVc2VyQXZhdGFyKGppZCwgaXNNdXRlZCk7XG4gICAgICAgIH1cbiAgICB9XG5cbn07XG5cblxubW9kdWxlLmV4cG9ydHMgPSBBdmF0YXI7IiwiLyogZ2xvYmFsICQsIGNvbmZpZywgY29ubmVjdGlvbiwgZG9ja1Rvb2xiYXIsIE1vZGVyYXRvcixcbiAgIHNldExhcmdlVmlkZW9WaXNpYmxlLCBVdGlsICovXG5cbnZhciBWaWRlb0xheW91dCA9IHJlcXVpcmUoXCIuLi92aWRlb2xheW91dC9WaWRlb0xheW91dFwiKTtcbnZhciBQcmV6aSA9IHJlcXVpcmUoXCIuLi9wcmV6aS9QcmV6aVwiKTtcbnZhciBVSVV0aWwgPSByZXF1aXJlKFwiLi4vdXRpbC9VSVV0aWxcIik7XG5cbnZhciBldGhlcnBhZE5hbWUgPSBudWxsO1xudmFyIGV0aGVycGFkSUZyYW1lID0gbnVsbDtcbnZhciBkb21haW4gPSBudWxsO1xudmFyIG9wdGlvbnMgPSBcIj9zaG93Q29udHJvbHM9dHJ1ZSZzaG93Q2hhdD1mYWxzZSZzaG93TGluZU51bWJlcnM9dHJ1ZSZ1c2VNb25vc3BhY2VGb250PWZhbHNlXCI7XG5cblxuLyoqXG4gKiBSZXNpemVzIHRoZSBldGhlcnBhZC5cbiAqL1xuZnVuY3Rpb24gcmVzaXplKCkge1xuICAgIGlmICgkKCcjZXRoZXJwYWQ+aWZyYW1lJykubGVuZ3RoKSB7XG4gICAgICAgIHZhciByZW1vdGVWaWRlb3MgPSAkKCcjcmVtb3RlVmlkZW9zJyk7XG4gICAgICAgIHZhciBhdmFpbGFibGVIZWlnaHRcbiAgICAgICAgICAgID0gd2luZG93LmlubmVySGVpZ2h0IC0gcmVtb3RlVmlkZW9zLm91dGVySGVpZ2h0KCk7XG4gICAgICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IFVJVXRpbC5nZXRBdmFpbGFibGVWaWRlb1dpZHRoKCk7XG5cbiAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLndpZHRoKGF2YWlsYWJsZVdpZHRoKTtcbiAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmhlaWdodChhdmFpbGFibGVIZWlnaHQpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBTaGFyZXMgdGhlIEV0aGVycGFkIG5hbWUgd2l0aCBvdGhlciBwYXJ0aWNpcGFudHMuXG4gKi9cbmZ1bmN0aW9uIHNoYXJlRXRoZXJwYWQoKSB7XG4gICAgY29ubmVjdGlvbi5lbXVjLmFkZEV0aGVycGFkVG9QcmVzZW5jZShldGhlcnBhZE5hbWUpO1xuICAgIGNvbm5lY3Rpb24uZW11Yy5zZW5kUHJlc2VuY2UoKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBFdGhlcnBhZCBidXR0b24gYW5kIGFkZHMgaXQgdG8gdGhlIHRvb2xiYXIuXG4gKi9cbmZ1bmN0aW9uIGVuYWJsZUV0aGVycGFkQnV0dG9uKCkge1xuICAgIGlmICghJCgnI2V0aGVycGFkQnV0dG9uJykuaXMoXCI6dmlzaWJsZVwiKSlcbiAgICAgICAgJCgnI2V0aGVycGFkQnV0dG9uJykuY3NzKHtkaXNwbGF5OiAnaW5saW5lLWJsb2NrJ30pO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIElGcmFtZSBmb3IgdGhlIGV0aGVycGFkLlxuICovXG5mdW5jdGlvbiBjcmVhdGVJRnJhbWUoKSB7XG4gICAgZXRoZXJwYWRJRnJhbWUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpZnJhbWUnKTtcbiAgICBldGhlcnBhZElGcmFtZS5zcmMgPSBkb21haW4gKyBldGhlcnBhZE5hbWUgKyBvcHRpb25zO1xuICAgIGV0aGVycGFkSUZyYW1lLmZyYW1lQm9yZGVyID0gMDtcbiAgICBldGhlcnBhZElGcmFtZS5zY3JvbGxpbmcgPSBcIm5vXCI7XG4gICAgZXRoZXJwYWRJRnJhbWUud2lkdGggPSAkKCcjbGFyZ2VWaWRlb0NvbnRhaW5lcicpLndpZHRoKCkgfHwgNjQwO1xuICAgIGV0aGVycGFkSUZyYW1lLmhlaWdodCA9ICQoJyNsYXJnZVZpZGVvQ29udGFpbmVyJykuaGVpZ2h0KCkgfHwgNDgwO1xuICAgIGV0aGVycGFkSUZyYW1lLnNldEF0dHJpYnV0ZSgnc3R5bGUnLCAndmlzaWJpbGl0eTogaGlkZGVuOycpO1xuXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2V0aGVycGFkJykuYXBwZW5kQ2hpbGQoZXRoZXJwYWRJRnJhbWUpO1xuXG4gICAgZXRoZXJwYWRJRnJhbWUub25sb2FkID0gZnVuY3Rpb24oKSB7XG5cbiAgICAgICAgZG9jdW1lbnQuZG9tYWluID0gZG9jdW1lbnQuZG9tYWluO1xuICAgICAgICBidWJibGVJZnJhbWVNb3VzZU1vdmUoZXRoZXJwYWRJRnJhbWUpO1xuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgLy8gdGhlIGlmcmFtZXMgaW5zaWRlIG9mIHRoZSBldGhlcnBhZCBhcmVcbiAgICAgICAgICAgIC8vIG5vdCB5ZXQgbG9hZGVkIHdoZW4gdGhlIGV0aGVycGFkIGlmcmFtZSBpcyBsb2FkZWRcbiAgICAgICAgICAgIHZhciBvdXRlciA9IGV0aGVycGFkSUZyYW1lLlxuICAgICAgICAgICAgICAgIGNvbnRlbnREb2N1bWVudC5nZXRFbGVtZW50c0J5TmFtZShcImFjZV9vdXRlclwiKVswXTtcbiAgICAgICAgICAgIGJ1YmJsZUlmcmFtZU1vdXNlTW92ZShvdXRlcik7XG4gICAgICAgICAgICB2YXIgaW5uZXIgPSBvdXRlci5cbiAgICAgICAgICAgICAgICBjb250ZW50RG9jdW1lbnQuZ2V0RWxlbWVudHNCeU5hbWUoXCJhY2VfaW5uZXJcIilbMF07XG4gICAgICAgICAgICBidWJibGVJZnJhbWVNb3VzZU1vdmUoaW5uZXIpO1xuICAgICAgICB9LCAyMDAwKTtcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBidWJibGVJZnJhbWVNb3VzZU1vdmUoaWZyYW1lKXtcbiAgICB2YXIgZXhpc3RpbmdPbk1vdXNlTW92ZSA9IGlmcmFtZS5jb250ZW50V2luZG93Lm9ubW91c2Vtb3ZlO1xuICAgIGlmcmFtZS5jb250ZW50V2luZG93Lm9ubW91c2Vtb3ZlID0gZnVuY3Rpb24oZSl7XG4gICAgICAgIGlmKGV4aXN0aW5nT25Nb3VzZU1vdmUpIGV4aXN0aW5nT25Nb3VzZU1vdmUoZSk7XG4gICAgICAgIHZhciBldnQgPSBkb2N1bWVudC5jcmVhdGVFdmVudChcIk1vdXNlRXZlbnRzXCIpO1xuICAgICAgICB2YXIgYm91bmRpbmdDbGllbnRSZWN0ID0gaWZyYW1lLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBldnQuaW5pdE1vdXNlRXZlbnQoXG4gICAgICAgICAgICBcIm1vdXNlbW92ZVwiLFxuICAgICAgICAgICAgdHJ1ZSwgLy8gYnViYmxlc1xuICAgICAgICAgICAgZmFsc2UsIC8vIG5vdCBjYW5jZWxhYmxlXG4gICAgICAgICAgICB3aW5kb3csXG4gICAgICAgICAgICBlLmRldGFpbCxcbiAgICAgICAgICAgIGUuc2NyZWVuWCxcbiAgICAgICAgICAgIGUuc2NyZWVuWSxcbiAgICAgICAgICAgICAgICBlLmNsaWVudFggKyBib3VuZGluZ0NsaWVudFJlY3QubGVmdCxcbiAgICAgICAgICAgICAgICBlLmNsaWVudFkgKyBib3VuZGluZ0NsaWVudFJlY3QudG9wLFxuICAgICAgICAgICAgZS5jdHJsS2V5LFxuICAgICAgICAgICAgZS5hbHRLZXksXG4gICAgICAgICAgICBlLnNoaWZ0S2V5LFxuICAgICAgICAgICAgZS5tZXRhS2V5LFxuICAgICAgICAgICAgZS5idXR0b24sXG4gICAgICAgICAgICBudWxsIC8vIG5vIHJlbGF0ZWQgZWxlbWVudFxuICAgICAgICApO1xuICAgICAgICBpZnJhbWUuZGlzcGF0Y2hFdmVudChldnQpO1xuICAgIH07XG59XG5cblxuLyoqXG4gKiBPbiB2aWRlbyBzZWxlY3RlZCBldmVudC5cbiAqL1xuJChkb2N1bWVudCkuYmluZCgndmlkZW8uc2VsZWN0ZWQnLCBmdW5jdGlvbiAoZXZlbnQsIGlzUHJlc2VudGF0aW9uKSB7XG4gICAgaWYgKGNvbmZpZy5ldGhlcnBhZF9iYXNlICYmIGV0aGVycGFkSUZyYW1lICYmIGV0aGVycGFkSUZyYW1lLnN0eWxlLnZpc2liaWxpdHkgIT09ICdoaWRkZW4nKVxuICAgICAgICBFdGhlcnBhZC50b2dnbGVFdGhlcnBhZChpc1ByZXNlbnRhdGlvbik7XG59KTtcblxuXG52YXIgRXRoZXJwYWQgPSB7XG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZXMgdGhlIGV0aGVycGFkLlxuICAgICAqL1xuICAgIGluaXQ6IGZ1bmN0aW9uIChuYW1lKSB7XG5cbiAgICAgICAgaWYgKGNvbmZpZy5ldGhlcnBhZF9iYXNlICYmICFldGhlcnBhZE5hbWUpIHtcblxuICAgICAgICAgICAgZG9tYWluID0gY29uZmlnLmV0aGVycGFkX2Jhc2U7XG5cbiAgICAgICAgICAgIGlmICghbmFtZSkge1xuICAgICAgICAgICAgICAgIC8vIEluIGNhc2Ugd2UncmUgdGhlIGZvY3VzIHdlIGdlbmVyYXRlIHRoZSBuYW1lLlxuICAgICAgICAgICAgICAgIGV0aGVycGFkTmFtZSA9IE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZyg3KSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdfJyArIChuZXcgRGF0ZSgpLmdldFRpbWUoKSkudG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgICBzaGFyZUV0aGVycGFkKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgZXRoZXJwYWROYW1lID0gbmFtZTtcblxuICAgICAgICAgICAgZW5hYmxlRXRoZXJwYWRCdXR0b24oKTtcblxuICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgKiBSZXNpemVzIHRoZSBldGhlcnBhZCwgd2hlbiB0aGUgd2luZG93IGlzIHJlc2l6ZWQuXG4gICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICQod2luZG93KS5yZXNpemUoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJlc2l6ZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogT3BlbnMvaGlkZXMgdGhlIEV0aGVycGFkLlxuICAgICAqL1xuICAgIHRvZ2dsZUV0aGVycGFkOiBmdW5jdGlvbiAoaXNQcmVzZW50YXRpb24pIHtcbiAgICAgICAgaWYgKCFldGhlcnBhZElGcmFtZSlcbiAgICAgICAgICAgIGNyZWF0ZUlGcmFtZSgpO1xuXG4gICAgICAgIHZhciBsYXJnZVZpZGVvID0gbnVsbDtcbiAgICAgICAgaWYgKFByZXppLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpKVxuICAgICAgICAgICAgbGFyZ2VWaWRlbyA9ICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJyk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGxhcmdlVmlkZW8gPSAkKCcjbGFyZ2VWaWRlbycpO1xuXG4gICAgICAgIGlmICgkKCcjZXRoZXJwYWQ+aWZyYW1lJykuY3NzKCd2aXNpYmlsaXR5JykgPT09ICdoaWRkZW4nKSB7XG4gICAgICAgICAgICAkKCcjYWN0aXZlU3BlYWtlcicpLmNzcygndmlzaWJpbGl0eScsICdoaWRkZW4nKTtcbiAgICAgICAgICAgIGxhcmdlVmlkZW8uZmFkZU91dCgzMDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAoUHJlemkuaXNQcmVzZW50YXRpb25WaXNpYmxlKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlby5jc3Moe29wYWNpdHk6ICcwJ30pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNldExhcmdlVmlkZW9WaXNpYmxlKGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmZhZGVJbigzMDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLmJhY2tncm91bmQgPSAnI2VlZWVlZSc7XG4gICAgICAgICAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmNzcyh7dmlzaWJpbGl0eTogJ3Zpc2libGUnfSk7XG4gICAgICAgICAgICAgICAgJCgnI2V0aGVycGFkJykuY3NzKHt6SW5kZXg6IDJ9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCQoJyNldGhlcnBhZD5pZnJhbWUnKSkge1xuICAgICAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmZhZGVPdXQoMzAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmNzcyh7dmlzaWJpbGl0eTogJ2hpZGRlbid9KTtcbiAgICAgICAgICAgICAgICAkKCcjZXRoZXJwYWQnKS5jc3Moe3pJbmRleDogMH0pO1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuYmFja2dyb3VuZCA9ICdibGFjayc7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKCFpc1ByZXNlbnRhdGlvbikge1xuICAgICAgICAgICAgICAgICQoJyNsYXJnZVZpZGVvJykuZmFkZUluKDMwMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5zZXRMYXJnZVZpZGVvVmlzaWJsZSh0cnVlKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXNpemUoKTtcbiAgICB9LFxuXG4gICAgaXNWaXNpYmxlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGV0aGVycGFkSWZyYW1lID0gJCgnI2V0aGVycGFkPmlmcmFtZScpO1xuICAgICAgICByZXR1cm4gZXRoZXJwYWRJZnJhbWUgJiYgZXRoZXJwYWRJZnJhbWUuaXMoJzp2aXNpYmxlJyk7XG4gICAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV0aGVycGFkO1xuIiwidmFyIFRvb2xiYXJUb2dnbGVyID0gcmVxdWlyZShcIi4uL3Rvb2xiYXJzL1Rvb2xiYXJUb2dnbGVyXCIpO1xudmFyIFVJVXRpbCA9IHJlcXVpcmUoXCIuLi91dGlsL1VJVXRpbFwiKTtcbnZhciBWaWRlb0xheW91dCA9IHJlcXVpcmUoXCIuLi92aWRlb2xheW91dC9WaWRlb0xheW91dFwiKTtcbnZhciBtZXNzYWdlSGFuZGxlciA9IHJlcXVpcmUoXCIuLi91dGlsL01lc3NhZ2VIYW5kbGVyXCIpO1xuXG52YXIgcHJlemlQbGF5ZXIgPSBudWxsO1xuXG52YXIgUHJlemkgPSB7XG5cblxuICAgIC8qKlxuICAgICAqIFJlbG9hZHMgdGhlIGN1cnJlbnQgcHJlc2VudGF0aW9uLlxuICAgICAqL1xuICAgIHJlbG9hZFByZXNlbnRhdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpZnJhbWUgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwcmV6aVBsYXllci5vcHRpb25zLnByZXppSWQpO1xuICAgICAgICBpZnJhbWUuc3JjID0gaWZyYW1lLnNyYztcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyA8dHQ+dHJ1ZTwvdHQ+IGlmIHRoZSBwcmVzZW50YXRpb24gaXMgdmlzaWJsZSwgPHR0PmZhbHNlPC90dD4gLVxuICAgICAqIG90aGVyd2lzZS5cbiAgICAgKi9cbiAgICBpc1ByZXNlbnRhdGlvblZpc2libGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuICgkKCcjcHJlc2VudGF0aW9uPmlmcmFtZScpICE9IG51bGxcbiAgICAgICAgICAgICAgICAmJiAkKCcjcHJlc2VudGF0aW9uPmlmcmFtZScpLmNzcygnb3BhY2l0eScpID09IDEpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBPcGVucyB0aGUgUHJlemkgZGlhbG9nLCBmcm9tIHdoaWNoIHRoZSB1c2VyIGNvdWxkIGNob29zZSBhIHByZXNlbnRhdGlvblxuICAgICAqIHRvIGxvYWQuXG4gICAgICovXG4gICAgb3BlblByZXppRGlhbG9nOiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIG15cHJlemkgPSBjb25uZWN0aW9uLmVtdWMuZ2V0UHJlemkoY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCk7XG4gICAgICAgIGlmIChteXByZXppKSB7XG4gICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKFwiUmVtb3ZlIFByZXppXCIsXG4gICAgICAgICAgICAgICAgXCJBcmUgeW91IHN1cmUgeW91IHdvdWxkIGxpa2UgdG8gcmVtb3ZlIHlvdXIgUHJlemk/XCIsXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgXCJSZW1vdmVcIixcbiAgICAgICAgICAgICAgICBmdW5jdGlvbihlLHYsbSxmKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmKHYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uZW11Yy5yZW1vdmVQcmV6aUZyb21QcmVzZW5jZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLnNlbmRQcmVzZW5jZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChwcmV6aVBsYXllciAhPSBudWxsKSB7XG4gICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKFwiU2hhcmUgYSBQcmV6aVwiLFxuICAgICAgICAgICAgICAgIFwiQW5vdGhlciBwYXJ0aWNpcGFudCBpcyBhbHJlYWR5IHNoYXJpbmcgYSBQcmV6aS5cIiArXG4gICAgICAgICAgICAgICAgICAgIFwiVGhpcyBjb25mZXJlbmNlIGFsbG93cyBvbmx5IG9uZSBQcmV6aSBhdCBhIHRpbWUuXCIsXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgXCJPa1wiLFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGUsdixtLGYpIHtcbiAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIG9wZW5QcmV6aVN0YXRlID0ge1xuICAgICAgICAgICAgICAgIHN0YXRlMDoge1xuICAgICAgICAgICAgICAgICAgICBodG1sOiAgICc8aDI+U2hhcmUgYSBQcmV6aTwvaDI+JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxpbnB1dCBpZD1cInByZXppVXJsXCIgdHlwZT1cInRleHRcIiAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAncGxhY2Vob2xkZXI9XCJlLmcuICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdodHRwOi8vcHJlemkuY29tL3d6N3ZoanljbDdlNi9teS1wcmV6aVwiIGF1dG9mb2N1cz4nLFxuICAgICAgICAgICAgICAgICAgICBwZXJzaXN0ZW50OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgYnV0dG9uczogeyBcIlNoYXJlXCI6IHRydWUgLCBcIkNhbmNlbFwiOiBmYWxzZX0sXG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHRCdXR0b246IDEsXG4gICAgICAgICAgICAgICAgICAgIHN1Ym1pdDogZnVuY3Rpb24oZSx2LG0sZil7XG4gICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZih2KVxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBwcmV6aVVybCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwcmV6aVVybCcpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHByZXppVXJsLnZhbHVlKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHVybFZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IGVuY29kZVVSSShVdGlsLmVzY2FwZUh0bWwocHJlemlVcmwudmFsdWUpKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodXJsVmFsdWUuaW5kZXhPZignaHR0cDovL3ByZXppLmNvbS8nKSAhPSAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiB1cmxWYWx1ZS5pbmRleE9mKCdodHRwczovL3ByZXppLmNvbS8nKSAhPSAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5nb1RvU3RhdGUoJ3N0YXRlMScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHByZXNJZFRtcCA9IHVybFZhbHVlLnN1YnN0cmluZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXJsVmFsdWUuaW5kZXhPZihcInByZXppLmNvbS9cIikgKyAxMCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzQWxwaGFudW1lcmljKHByZXNJZFRtcClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfHwgcHJlc0lkVG1wLmluZGV4T2YoJy8nKSA8IDIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5nb1RvU3RhdGUoJ3N0YXRlMScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uZW11Y1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuYWRkUHJlemlUb1ByZXNlbmNlKHVybFZhbHVlLCAwKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuc2VuZFByZXNlbmNlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBzdGF0ZTE6IHtcbiAgICAgICAgICAgICAgICAgICAgaHRtbDogICAnPGgyPlNoYXJlIGEgUHJlemk8L2gyPicgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdQbGVhc2UgcHJvdmlkZSBhIGNvcnJlY3QgcHJlemkgbGluay4nLFxuICAgICAgICAgICAgICAgICAgICBwZXJzaXN0ZW50OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgYnV0dG9uczogeyBcIkJhY2tcIjogdHJ1ZSwgXCJDYW5jZWxcIjogZmFsc2UgfSxcbiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdEJ1dHRvbjogMSxcbiAgICAgICAgICAgICAgICAgICAgc3VibWl0OmZ1bmN0aW9uKGUsdixtLGYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmKHY9PTApXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5nb1RvU3RhdGUoJ3N0YXRlMCcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHZhciBmb2N1c1ByZXppVXJsID0gIGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ByZXppVXJsJykuZm9jdXMoKTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgbWVzc2FnZUhhbmRsZXIub3BlbkRpYWxvZ1dpdGhTdGF0ZXMob3BlblByZXppU3RhdGUsIGZvY3VzUHJlemlVcmwsIGZvY3VzUHJlemlVcmwpO1xuICAgICAgICB9XG4gICAgfVxuXG59O1xuXG4vKipcbiAqIEEgbmV3IHByZXNlbnRhdGlvbiBoYXMgYmVlbiBhZGRlZC5cbiAqXG4gKiBAcGFyYW0gZXZlbnQgdGhlIGV2ZW50IGluZGljYXRpbmcgdGhlIGFkZCBvZiBhIHByZXNlbnRhdGlvblxuICogQHBhcmFtIGppZCB0aGUgamlkIGZyb20gd2hpY2ggdGhlIHByZXNlbnRhdGlvbiB3YXMgYWRkZWRcbiAqIEBwYXJhbSBwcmVzVXJsIHVybCBvZiB0aGUgcHJlc2VudGF0aW9uXG4gKiBAcGFyYW0gY3VycmVudFNsaWRlIHRoZSBjdXJyZW50IHNsaWRlIHRvIHdoaWNoIHdlIHNob3VsZCBtb3ZlXG4gKi9cbmZ1bmN0aW9uIHByZXNlbnRhdGlvbkFkZGVkKGV2ZW50LCBqaWQsIHByZXNVcmwsIGN1cnJlbnRTbGlkZSkge1xuICAgIGNvbnNvbGUubG9nKFwicHJlc2VudGF0aW9uIGFkZGVkXCIsIHByZXNVcmwpO1xuXG4gICAgdmFyIHByZXNJZCA9IGdldFByZXNlbnRhdGlvbklkKHByZXNVcmwpO1xuXG4gICAgdmFyIGVsZW1lbnRJZCA9ICdwYXJ0aWNpcGFudF8nXG4gICAgICAgICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKVxuICAgICAgICArICdfJyArIHByZXNJZDtcblxuICAgIC8vIFdlIGV4cGxpY2l0bHkgZG9uJ3Qgc3BlY2lmeSB0aGUgcGVlciBqaWQgaGVyZSwgYmVjYXVzZSB3ZSBkb24ndCB3YW50XG4gICAgLy8gdGhpcyB2aWRlbyB0byBiZSBkZWFsdCB3aXRoIGFzIGEgcGVlciByZWxhdGVkIG9uZSAoZm9yIGV4YW1wbGUgd2VcbiAgICAvLyBkb24ndCB3YW50IHRvIHNob3cgYSBtdXRlL2tpY2sgbWVudSBmb3IgdGhpcyBvbmUsIGV0Yy4pLlxuICAgIFZpZGVvTGF5b3V0LmFkZFJlbW90ZVZpZGVvQ29udGFpbmVyKG51bGwsIGVsZW1lbnRJZCk7XG4gICAgVmlkZW9MYXlvdXQucmVzaXplVGh1bWJuYWlscygpO1xuXG4gICAgdmFyIGNvbnRyb2xzRW5hYmxlZCA9IGZhbHNlO1xuICAgIGlmIChqaWQgPT09IGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpXG4gICAgICAgIGNvbnRyb2xzRW5hYmxlZCA9IHRydWU7XG5cbiAgICBzZXRQcmVzZW50YXRpb25WaXNpYmxlKHRydWUpO1xuICAgICQoJyNsYXJnZVZpZGVvQ29udGFpbmVyJykuaG92ZXIoXG4gICAgICAgIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgICAgaWYgKFByZXppLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlbG9hZEJ1dHRvblJpZ2h0ID0gd2luZG93LmlubmVyV2lkdGhcbiAgICAgICAgICAgICAgICAgICAgLSAkKCcjcHJlc2VudGF0aW9uPmlmcmFtZScpLm9mZnNldCgpLmxlZnRcbiAgICAgICAgICAgICAgICAgICAgLSAkKCcjcHJlc2VudGF0aW9uPmlmcmFtZScpLndpZHRoKCk7XG5cbiAgICAgICAgICAgICAgICAkKCcjcmVsb2FkUHJlc2VudGF0aW9uJykuY3NzKHsgIHJpZ2h0OiByZWxvYWRCdXR0b25SaWdodCxcbiAgICAgICAgICAgICAgICAgICAgZGlzcGxheTonaW5saW5lLWJsb2NrJ30pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmICghUHJlemkuaXNQcmVzZW50YXRpb25WaXNpYmxlKCkpXG4gICAgICAgICAgICAgICAgJCgnI3JlbG9hZFByZXNlbnRhdGlvbicpLmNzcyh7ZGlzcGxheTonbm9uZSd9KTtcbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHZhciBlID0gZXZlbnQudG9FbGVtZW50IHx8IGV2ZW50LnJlbGF0ZWRUYXJnZXQ7XG5cbiAgICAgICAgICAgICAgICBpZiAoZSAmJiBlLmlkICE9ICdyZWxvYWRQcmVzZW50YXRpb24nICYmIGUuaWQgIT0gJ2hlYWRlcicpXG4gICAgICAgICAgICAgICAgICAgICQoJyNyZWxvYWRQcmVzZW50YXRpb24nKS5jc3Moe2Rpc3BsYXk6J25vbmUnfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgcHJlemlQbGF5ZXIgPSBuZXcgUHJlemlQbGF5ZXIoXG4gICAgICAgICdwcmVzZW50YXRpb24nLFxuICAgICAgICB7cHJlemlJZDogcHJlc0lkLFxuICAgICAgICAgICAgd2lkdGg6IGdldFByZXNlbnRhdGlvbldpZHRoKCksXG4gICAgICAgICAgICBoZWlnaHQ6IGdldFByZXNlbnRhdGlvbkhlaWhndCgpLFxuICAgICAgICAgICAgY29udHJvbHM6IGNvbnRyb2xzRW5hYmxlZCxcbiAgICAgICAgICAgIGRlYnVnOiB0cnVlXG4gICAgICAgIH0pO1xuXG4gICAgJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS5hdHRyKCdpZCcsIHByZXppUGxheWVyLm9wdGlvbnMucHJlemlJZCk7XG5cbiAgICBwcmV6aVBsYXllci5vbihQcmV6aVBsYXllci5FVkVOVF9TVEFUVVMsIGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwicHJlemkgc3RhdHVzXCIsIGV2ZW50LnZhbHVlKTtcbiAgICAgICAgaWYgKGV2ZW50LnZhbHVlID09IFByZXppUGxheWVyLlNUQVRVU19DT05URU5UX1JFQURZKSB7XG4gICAgICAgICAgICBpZiAoamlkICE9IGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpXG4gICAgICAgICAgICAgICAgcHJlemlQbGF5ZXIuZmx5VG9TdGVwKGN1cnJlbnRTbGlkZSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIHByZXppUGxheWVyLm9uKFByZXppUGxheWVyLkVWRU5UX0NVUlJFTlRfU1RFUCwgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJldmVudCB2YWx1ZVwiLCBldmVudC52YWx1ZSk7XG4gICAgICAgIGNvbm5lY3Rpb24uZW11Yy5hZGRDdXJyZW50U2xpZGVUb1ByZXNlbmNlKGV2ZW50LnZhbHVlKTtcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLnNlbmRQcmVzZW5jZSgpO1xuICAgIH0pO1xuXG4gICAgJChcIiNcIiArIGVsZW1lbnRJZCkuY3NzKCAnYmFja2dyb3VuZC1pbWFnZScsXG4gICAgICAgICd1cmwoLi4vaW1hZ2VzL2F2YXRhcnByZXppLnBuZyknKTtcbiAgICAkKFwiI1wiICsgZWxlbWVudElkKS5jbGljayhcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2V0UHJlc2VudGF0aW9uVmlzaWJsZSh0cnVlKTtcbiAgICAgICAgfVxuICAgICk7XG59O1xuXG4vKipcbiAqIEEgcHJlc2VudGF0aW9uIGhhcyBiZWVuIHJlbW92ZWQuXG4gKlxuICogQHBhcmFtIGV2ZW50IHRoZSBldmVudCBpbmRpY2F0aW5nIHRoZSByZW1vdmUgb2YgYSBwcmVzZW50YXRpb25cbiAqIEBwYXJhbSBqaWQgdGhlIGppZCBmb3Igd2hpY2ggdGhlIHByZXNlbnRhdGlvbiB3YXMgcmVtb3ZlZFxuICogQHBhcmFtIHRoZSB1cmwgb2YgdGhlIHByZXNlbnRhdGlvblxuICovXG5mdW5jdGlvbiBwcmVzZW50YXRpb25SZW1vdmVkKGV2ZW50LCBqaWQsIHByZXNVcmwpIHtcbiAgICBjb25zb2xlLmxvZygncHJlc2VudGF0aW9uIHJlbW92ZWQnLCBwcmVzVXJsKTtcbiAgICB2YXIgcHJlc0lkID0gZ2V0UHJlc2VudGF0aW9uSWQocHJlc1VybCk7XG4gICAgc2V0UHJlc2VudGF0aW9uVmlzaWJsZShmYWxzZSk7XG4gICAgJCgnI3BhcnRpY2lwYW50XydcbiAgICAgICAgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpXG4gICAgICAgICsgJ18nICsgcHJlc0lkKS5yZW1vdmUoKTtcbiAgICAkKCcjcHJlc2VudGF0aW9uPmlmcmFtZScpLnJlbW92ZSgpO1xuICAgIGlmIChwcmV6aVBsYXllciAhPSBudWxsKSB7XG4gICAgICAgIHByZXppUGxheWVyLmRlc3Ryb3koKTtcbiAgICAgICAgcHJlemlQbGF5ZXIgPSBudWxsO1xuICAgIH1cbn07XG5cbi8qKlxuICogSW5kaWNhdGVzIGlmIHRoZSBnaXZlbiBzdHJpbmcgaXMgYW4gYWxwaGFudW1lcmljIHN0cmluZy5cbiAqIE5vdGUgdGhhdCBzb21lIHNwZWNpYWwgY2hhcmFjdGVycyBhcmUgYWxzbyBhbGxvd2VkICgtLCBfICwgLywgJiwgPywgPSwgOykgZm9yIHRoZVxuICogcHVycG9zZSBvZiBjaGVja2luZyBVUklzLlxuICovXG5mdW5jdGlvbiBpc0FscGhhbnVtZXJpYyh1bnNhZmVUZXh0KSB7XG4gICAgdmFyIHJlZ2V4ID0gL15bYS16MC05LV9cXC8mXFw/PTtdKyQvaTtcbiAgICByZXR1cm4gcmVnZXgudGVzdCh1bnNhZmVUZXh0KTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBwcmVzZW50YXRpb24gaWQgZnJvbSB0aGUgZ2l2ZW4gdXJsLlxuICovXG5mdW5jdGlvbiBnZXRQcmVzZW50YXRpb25JZCAocHJlc1VybCkge1xuICAgIHZhciBwcmVzSWRUbXAgPSBwcmVzVXJsLnN1YnN0cmluZyhwcmVzVXJsLmluZGV4T2YoXCJwcmV6aS5jb20vXCIpICsgMTApO1xuICAgIHJldHVybiBwcmVzSWRUbXAuc3Vic3RyaW5nKDAsIHByZXNJZFRtcC5pbmRleE9mKCcvJykpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHByZXNlbnRhdGlvbiB3aWR0aC5cbiAqL1xuZnVuY3Rpb24gZ2V0UHJlc2VudGF0aW9uV2lkdGgoKSB7XG4gICAgdmFyIGF2YWlsYWJsZVdpZHRoID0gVUlVdGlsLmdldEF2YWlsYWJsZVZpZGVvV2lkdGgoKTtcbiAgICB2YXIgYXZhaWxhYmxlSGVpZ2h0ID0gZ2V0UHJlc2VudGF0aW9uSGVpaGd0KCk7XG5cbiAgICB2YXIgYXNwZWN0UmF0aW8gPSAxNi4wIC8gOS4wO1xuICAgIGlmIChhdmFpbGFibGVIZWlnaHQgPCBhdmFpbGFibGVXaWR0aCAvIGFzcGVjdFJhdGlvKSB7XG4gICAgICAgIGF2YWlsYWJsZVdpZHRoID0gTWF0aC5mbG9vcihhdmFpbGFibGVIZWlnaHQgKiBhc3BlY3RSYXRpbyk7XG4gICAgfVxuICAgIHJldHVybiBhdmFpbGFibGVXaWR0aDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBwcmVzZW50YXRpb24gaGVpZ2h0LlxuICovXG5mdW5jdGlvbiBnZXRQcmVzZW50YXRpb25IZWloZ3QoKSB7XG4gICAgdmFyIHJlbW90ZVZpZGVvcyA9ICQoJyNyZW1vdGVWaWRlb3MnKTtcbiAgICByZXR1cm4gd2luZG93LmlubmVySGVpZ2h0IC0gcmVtb3RlVmlkZW9zLm91dGVySGVpZ2h0KCk7XG59XG5cbi8qKlxuICogUmVzaXplcyB0aGUgcHJlc2VudGF0aW9uIGlmcmFtZS5cbiAqL1xuZnVuY3Rpb24gcmVzaXplKCkge1xuICAgIGlmICgkKCcjcHJlc2VudGF0aW9uPmlmcmFtZScpKSB7XG4gICAgICAgICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykud2lkdGgoZ2V0UHJlc2VudGF0aW9uV2lkdGgoKSk7XG4gICAgICAgICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykuaGVpZ2h0KGdldFByZXNlbnRhdGlvbkhlaWhndCgpKTtcbiAgICB9XG59XG5cbi8qKlxuICogU2hvd3MvaGlkZXMgYSBwcmVzZW50YXRpb24uXG4gKi9cbmZ1bmN0aW9uIHNldFByZXNlbnRhdGlvblZpc2libGUodmlzaWJsZSkge1xuICAgIHZhciBwcmV6aSA9ICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJyk7XG4gICAgaWYgKHZpc2libGUpIHtcbiAgICAgICAgLy8gVHJpZ2dlciB0aGUgdmlkZW8uc2VsZWN0ZWQgZXZlbnQgdG8gaW5kaWNhdGUgYSBjaGFuZ2UgaW4gdGhlXG4gICAgICAgIC8vIGxhcmdlIHZpZGVvLlxuICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKFwidmlkZW8uc2VsZWN0ZWRcIiwgW3RydWVdKTtcblxuICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmZhZGVPdXQoMzAwKTtcbiAgICAgICAgcHJlemkuZmFkZUluKDMwMCwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBwcmV6aS5jc3Moe29wYWNpdHk6JzEnfSk7XG4gICAgICAgICAgICBUb29sYmFyVG9nZ2xlci5kb2NrVG9vbGJhcih0cnVlKTtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNldExhcmdlVmlkZW9WaXNpYmxlKGZhbHNlKTtcbiAgICAgICAgfSk7XG4gICAgICAgICQoJyNhY3RpdmVTcGVha2VyJykuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgaWYgKHByZXppLmNzcygnb3BhY2l0eScpID09ICcxJykge1xuICAgICAgICAgICAgcHJlemkuZmFkZU91dCgzMDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBwcmV6aS5jc3Moe29wYWNpdHk6JzAnfSk7XG4gICAgICAgICAgICAgICAgJCgnI3JlbG9hZFByZXNlbnRhdGlvbicpLmNzcyh7ZGlzcGxheTonbm9uZSd9KTtcbiAgICAgICAgICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmZhZGVJbigzMDAsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5zZXRMYXJnZVZpZGVvVmlzaWJsZSh0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgVG9vbGJhclRvZ2dsZXIuZG9ja1Rvb2xiYXIoZmFsc2UpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogUHJlc2VudGF0aW9uIGhhcyBiZWVuIHJlbW92ZWQuXG4gKi9cbiQoZG9jdW1lbnQpLmJpbmQoJ3ByZXNlbnRhdGlvbnJlbW92ZWQubXVjJywgcHJlc2VudGF0aW9uUmVtb3ZlZCk7XG5cbi8qKlxuICogUHJlc2VudGF0aW9uIGhhcyBiZWVuIGFkZGVkLlxuICovXG4kKGRvY3VtZW50KS5iaW5kKCdwcmVzZW50YXRpb25hZGRlZC5tdWMnLCBwcmVzZW50YXRpb25BZGRlZCk7XG5cbi8qXG4gKiBJbmRpY2F0ZXMgcHJlc2VudGF0aW9uIHNsaWRlIGNoYW5nZS5cbiAqL1xuJChkb2N1bWVudCkuYmluZCgnZ290b3NsaWRlLm11YycsIGZ1bmN0aW9uIChldmVudCwgamlkLCBwcmVzVXJsLCBjdXJyZW50KSB7XG4gICAgaWYgKHByZXppUGxheWVyICYmIHByZXppUGxheWVyLmdldEN1cnJlbnRTdGVwKCkgIT0gY3VycmVudCkge1xuICAgICAgICBwcmV6aVBsYXllci5mbHlUb1N0ZXAoY3VycmVudCk7XG5cbiAgICAgICAgdmFyIGFuaW1hdGlvblN0ZXBzQXJyYXkgPSBwcmV6aVBsYXllci5nZXRBbmltYXRpb25Db3VudE9uU3RlcHMoKTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwYXJzZUludChhbmltYXRpb25TdGVwc0FycmF5W2N1cnJlbnRdKTsgaSsrKSB7XG4gICAgICAgICAgICBwcmV6aVBsYXllci5mbHlUb1N0ZXAoY3VycmVudCwgaSk7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBPbiB2aWRlbyBzZWxlY3RlZCBldmVudC5cbiAqL1xuJChkb2N1bWVudCkuYmluZCgndmlkZW8uc2VsZWN0ZWQnLCBmdW5jdGlvbiAoZXZlbnQsIGlzUHJlc2VudGF0aW9uKSB7XG4gICAgaWYgKCFpc1ByZXNlbnRhdGlvbiAmJiAkKCcjcHJlc2VudGF0aW9uPmlmcmFtZScpKSB7XG4gICAgICAgIHNldFByZXNlbnRhdGlvblZpc2libGUoZmFsc2UpO1xuICAgIH1cbn0pO1xuXG4kKHdpbmRvdykucmVzaXplKGZ1bmN0aW9uICgpIHtcbiAgICByZXNpemUoKTtcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFByZXppO1xuIiwidmFyIENoYXQgPSByZXF1aXJlKFwiLi9jaGF0L0NoYXRcIik7XG52YXIgQ29udGFjdExpc3QgPSByZXF1aXJlKFwiLi9jb250YWN0bGlzdC9Db250YWN0TGlzdFwiKTtcbnZhciBTZXR0aW5ncyA9IHJlcXVpcmUoXCIuL3NldHRpbmdzL1NldHRpbmdzXCIpO1xudmFyIFNldHRpbmdzTWVudSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzL1NldHRpbmdzTWVudVwiKTtcbnZhciBWaWRlb0xheW91dCA9IHJlcXVpcmUoXCIuLi92aWRlb2xheW91dC9WaWRlb0xheW91dFwiKTtcbnZhciBUb29sYmFyVG9nZ2xlciA9IHJlcXVpcmUoXCIuLi90b29sYmFycy9Ub29sYmFyVG9nZ2xlclwiKTtcblxuLyoqXG4gKiBUb2dnbGVyIGZvciB0aGUgY2hhdCwgY29udGFjdCBsaXN0LCBzZXR0aW5ncyBtZW51LCBldGMuLlxuICovXG52YXIgUGFuZWxUb2dnbGVyID0gKGZ1bmN0aW9uKG15KSB7XG5cbiAgICB2YXIgY3VycmVudGx5T3BlbiA9IG51bGw7XG4gICAgdmFyIGJ1dHRvbnMgPSB7XG4gICAgICAgICcjY2hhdHNwYWNlJzogJyNjaGF0Qm90dG9tQnV0dG9uJyxcbiAgICAgICAgJyNjb250YWN0bGlzdCc6ICcjY29udGFjdExpc3RCdXR0b24nLFxuICAgICAgICAnI3NldHRpbmdzbWVudSc6ICcjc2V0dGluZ3NCdXR0b24nXG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGhlIHZpZGVvIGFyZWFcbiAgICAgKiBAcGFyYW0gaXNDbG9zaW5nIHdoZXRoZXIgdGhlIHNpZGUgcGFuZWwgaXMgZ29pbmcgdG8gYmUgY2xvc2VkIG9yIGlzIGdvaW5nIHRvIG9wZW4gLyByZW1haW4gb3BlbmVkXG4gICAgICogQHBhcmFtIGNvbXBsZXRlRnVuY3Rpb24gYSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbiB0aGUgdmlkZW8gc3BhY2UgaXMgcmVzaXplZFxuICAgICAqL1xuICAgIHZhciByZXNpemVWaWRlb0FyZWEgPSBmdW5jdGlvbihpc0Nsb3NpbmcsIGNvbXBsZXRlRnVuY3Rpb24pIHtcbiAgICAgICAgdmFyIHZpZGVvc3BhY2UgPSAkKCcjdmlkZW9zcGFjZScpO1xuXG4gICAgICAgIHZhciBwYW5lbFNpemUgPSBpc0Nsb3NpbmcgPyBbMCwgMF0gOiBQYW5lbFRvZ2dsZXIuZ2V0UGFuZWxTaXplKCk7XG4gICAgICAgIHZhciB2aWRlb3NwYWNlV2lkdGggPSB3aW5kb3cuaW5uZXJXaWR0aCAtIHBhbmVsU2l6ZVswXTtcbiAgICAgICAgdmFyIHZpZGVvc3BhY2VIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICAgIHZhciB2aWRlb1NpemVcbiAgICAgICAgICAgID0gZ2V0VmlkZW9TaXplKG51bGwsIG51bGwsIHZpZGVvc3BhY2VXaWR0aCwgdmlkZW9zcGFjZUhlaWdodCk7XG4gICAgICAgIHZhciB2aWRlb1dpZHRoID0gdmlkZW9TaXplWzBdO1xuICAgICAgICB2YXIgdmlkZW9IZWlnaHQgPSB2aWRlb1NpemVbMV07XG4gICAgICAgIHZhciB2aWRlb1Bvc2l0aW9uID0gZ2V0VmlkZW9Qb3NpdGlvbih2aWRlb1dpZHRoLFxuICAgICAgICAgICAgdmlkZW9IZWlnaHQsXG4gICAgICAgICAgICB2aWRlb3NwYWNlV2lkdGgsXG4gICAgICAgICAgICB2aWRlb3NwYWNlSGVpZ2h0KTtcbiAgICAgICAgdmFyIGhvcml6b250YWxJbmRlbnQgPSB2aWRlb1Bvc2l0aW9uWzBdO1xuICAgICAgICB2YXIgdmVydGljYWxJbmRlbnQgPSB2aWRlb1Bvc2l0aW9uWzFdO1xuXG4gICAgICAgIHZhciB0aHVtYm5haWxTaXplID0gVmlkZW9MYXlvdXQuY2FsY3VsYXRlVGh1bWJuYWlsU2l6ZSh2aWRlb3NwYWNlV2lkdGgpO1xuICAgICAgICB2YXIgdGh1bWJuYWlsc1dpZHRoID0gdGh1bWJuYWlsU2l6ZVswXTtcbiAgICAgICAgdmFyIHRodW1ibmFpbHNIZWlnaHQgPSB0aHVtYm5haWxTaXplWzFdO1xuICAgICAgICAvL2ZvciBjaGF0XG5cbiAgICAgICAgdmlkZW9zcGFjZS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICByaWdodDogcGFuZWxTaXplWzBdLFxuICAgICAgICAgICAgICAgIHdpZHRoOiB2aWRlb3NwYWNlV2lkdGgsXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiB2aWRlb3NwYWNlSGVpZ2h0XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBjb21wbGV0ZUZ1bmN0aW9uXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zJykuYW5pbWF0ZSh7XG4gICAgICAgICAgICAgICAgaGVpZ2h0OiB0aHVtYm5haWxzSGVpZ2h0XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zPnNwYW4nKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IHRodW1ibmFpbHNIZWlnaHQsXG4gICAgICAgICAgICAgICAgd2lkdGg6IHRodW1ibmFpbHNXaWR0aFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDUwMCxcbiAgICAgICAgICAgICAgICBjb21wbGV0ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJyZW1vdGV2aWRlby5yZXNpemVkXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBbdGh1bWJuYWlsc1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRodW1ibmFpbHNIZWlnaHRdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAkKCcjbGFyZ2VWaWRlb0NvbnRhaW5lcicpLmFuaW1hdGUoe1xuICAgICAgICAgICAgICAgIHdpZHRoOiB2aWRlb3NwYWNlV2lkdGgsXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiB2aWRlb3NwYWNlSGVpZ2h0XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmFuaW1hdGUoe1xuICAgICAgICAgICAgICAgIHdpZHRoOiB2aWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgIGhlaWdodDogdmlkZW9IZWlnaHQsXG4gICAgICAgICAgICAgICAgdG9wOiB2ZXJ0aWNhbEluZGVudCxcbiAgICAgICAgICAgICAgICBib3R0b206IHZlcnRpY2FsSW5kZW50LFxuICAgICAgICAgICAgICAgIGxlZnQ6IGhvcml6b250YWxJbmRlbnQsXG4gICAgICAgICAgICAgICAgcmlnaHQ6IGhvcml6b250YWxJbmRlbnRcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiA1MDBcbiAgICAgICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBUb2dnbGVzIHRoZSB3aW5kb3dzIGluIHRoZSBzaWRlIHBhbmVsXG4gICAgICogQHBhcmFtIG9iamVjdCB0aGUgd2luZG93IHRoYXQgc2hvdWxkIGJlIHNob3duXG4gICAgICogQHBhcmFtIHNlbGVjdG9yIHRoZSBzZWxlY3RvciBmb3IgdGhlIGVsZW1lbnQgY29udGFpbmluZyB0aGUgcGFuZWxcbiAgICAgKiBAcGFyYW0gb25PcGVuQ29tcGxldGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIHBhbmVsIGlzIG9wZW5lZFxuICAgICAqIEBwYXJhbSBvbk9wZW4gZnVuY3Rpb24gdG8gYmUgY2FsbGVkIGlmIHRoZSB3aW5kb3cgaXMgZ29pbmcgdG8gYmUgb3BlbmVkXG4gICAgICogQHBhcmFtIG9uQ2xvc2UgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIGlmIHRoZSB3aW5kb3cgaXMgZ29pbmcgdG8gYmUgY2xvc2VkXG4gICAgICovXG4gICAgdmFyIHRvZ2dsZSA9IGZ1bmN0aW9uKG9iamVjdCwgc2VsZWN0b3IsIG9uT3BlbkNvbXBsZXRlLCBvbk9wZW4sIG9uQ2xvc2UpIHtcbiAgICAgICAgYnV0dG9uQ2xpY2soYnV0dG9uc1tzZWxlY3Rvcl0sIFwiYWN0aXZlXCIpO1xuXG4gICAgICAgIGlmIChvYmplY3QuaXNWaXNpYmxlKCkpIHtcbiAgICAgICAgICAgICQoXCIjdG9hc3QtY29udGFpbmVyXCIpLmFuaW1hdGUoe1xuICAgICAgICAgICAgICAgICAgICByaWdodDogJzVweCdcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAkKHNlbGVjdG9yKS5oaWRlKFwic2xpZGVcIiwge1xuICAgICAgICAgICAgICAgIGRpcmVjdGlvbjogXCJyaWdodFwiLFxuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmKHR5cGVvZiBvbkNsb3NlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICBvbkNsb3NlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGN1cnJlbnRseU9wZW4gPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gVW5kb2NrIHRoZSB0b29sYmFyIHdoZW4gdGhlIGNoYXQgaXMgc2hvd24gYW5kIGlmIHdlJ3JlIGluIGFcbiAgICAgICAgICAgIC8vIHZpZGVvIG1vZGUuXG4gICAgICAgICAgICBpZiAoVmlkZW9MYXlvdXQuaXNMYXJnZVZpZGVvVmlzaWJsZSgpKSB7XG4gICAgICAgICAgICAgICAgVG9vbGJhclRvZ2dsZXIuZG9ja1Rvb2xiYXIoZmFsc2UpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZihjdXJyZW50bHlPcGVuKSB7XG4gICAgICAgICAgICAgICAgdmFyIGN1cnJlbnQgPSAkKGN1cnJlbnRseU9wZW4pO1xuICAgICAgICAgICAgICAgIGJ1dHRvbkNsaWNrKGJ1dHRvbnNbY3VycmVudGx5T3Blbl0sIFwiYWN0aXZlXCIpO1xuICAgICAgICAgICAgICAgIGN1cnJlbnQuY3NzKCd6LWluZGV4JywgNCk7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY3NzKCdkaXNwbGF5JywgJ25vbmUnKTtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudC5jc3MoJ3otaW5kZXgnLCA1KTtcbiAgICAgICAgICAgICAgICB9LCA1MDApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAkKFwiI3RvYXN0LWNvbnRhaW5lclwiKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICAgICAgcmlnaHQ6IChQYW5lbFRvZ2dsZXIuZ2V0UGFuZWxTaXplKClbMF0gKyA1KSArICdweCdcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAkKHNlbGVjdG9yKS5zaG93KFwic2xpZGVcIiwge1xuICAgICAgICAgICAgICAgIGRpcmVjdGlvbjogXCJyaWdodFwiLFxuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBvbk9wZW5Db21wbGV0ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZih0eXBlb2Ygb25PcGVuID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICBvbk9wZW4oKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY3VycmVudGx5T3BlbiA9IHNlbGVjdG9yO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIE9wZW5zIC8gY2xvc2VzIHRoZSBjaGF0IGFyZWEuXG4gICAgICovXG4gICAgbXkudG9nZ2xlQ2hhdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgY2hhdENvbXBsZXRlRnVuY3Rpb24gPSBDaGF0LmlzVmlzaWJsZSgpID9cbiAgICAgICAgICAgIGZ1bmN0aW9uKCkge30gOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBDaGF0LnNjcm9sbENoYXRUb0JvdHRvbSgpO1xuICAgICAgICAgICAgJCgnI2NoYXRzcGFjZScpLnRyaWdnZXIoJ3Nob3duJyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmVzaXplVmlkZW9BcmVhKENoYXQuaXNWaXNpYmxlKCksIGNoYXRDb21wbGV0ZUZ1bmN0aW9uKTtcblxuICAgICAgICB0b2dnbGUoQ2hhdCxcbiAgICAgICAgICAgICcjY2hhdHNwYWNlJyxcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBSZXF1ZXN0IHRoZSBmb2N1cyBpbiB0aGUgbmlja25hbWUgZmllbGQgb3IgdGhlIGNoYXQgaW5wdXQgZmllbGQuXG4gICAgICAgICAgICAgICAgaWYgKCQoJyNuaWNrbmFtZScpLmNzcygndmlzaWJpbGl0eScpID09PSAndmlzaWJsZScpIHtcbiAgICAgICAgICAgICAgICAgICAgJCgnI25pY2tpbnB1dCcpLmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgJCgnI3VzZXJtc2cnKS5mb2N1cygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgQ2hhdC5yZXNpemVDaGF0LFxuICAgICAgICAgICAgbnVsbCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIE9wZW5zIC8gY2xvc2VzIHRoZSBjb250YWN0IGxpc3QgYXJlYS5cbiAgICAgKi9cbiAgICBteS50b2dnbGVDb250YWN0TGlzdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNvbXBsZXRlRnVuY3Rpb24gPSBDb250YWN0TGlzdC5pc1Zpc2libGUoKSA/XG4gICAgICAgICAgICBmdW5jdGlvbigpIHt9IDogZnVuY3Rpb24gKCkgeyAkKCcjY29udGFjdGxpc3QnKS50cmlnZ2VyKCdzaG93bicpO307XG4gICAgICAgIHJlc2l6ZVZpZGVvQXJlYShDb250YWN0TGlzdC5pc1Zpc2libGUoKSwgY29tcGxldGVGdW5jdGlvbik7XG5cbiAgICAgICAgdG9nZ2xlKENvbnRhY3RMaXN0LFxuICAgICAgICAgICAgJyNjb250YWN0bGlzdCcsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgQ29udGFjdExpc3Quc2V0VmlzdWFsTm90aWZpY2F0aW9uKGZhbHNlKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogT3BlbnMgLyBjbG9zZXMgdGhlIHNldHRpbmdzIG1lbnVcbiAgICAgKi9cbiAgICBteS50b2dnbGVTZXR0aW5nc01lbnUgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmVzaXplVmlkZW9BcmVhKFNldHRpbmdzTWVudS5pc1Zpc2libGUoKSwgZnVuY3Rpb24gKCl7fSk7XG4gICAgICAgIHRvZ2dsZShTZXR0aW5nc01lbnUsXG4gICAgICAgICAgICAnI3NldHRpbmdzbWVudScsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNldHRpbmdzID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbiAgICAgICAgICAgICAgICAkKCcjc2V0RGlzcGxheU5hbWUnKS5nZXQoMCkudmFsdWUgPSBzZXR0aW5ncy5kaXNwbGF5TmFtZTtcbiAgICAgICAgICAgICAgICAkKCcjc2V0RW1haWwnKS5nZXQoMCkudmFsdWUgPSBzZXR0aW5ncy5lbWFpbDtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgc2l6ZSBvZiB0aGUgc2lkZSBwYW5lbC5cbiAgICAgKi9cbiAgICBteS5nZXRQYW5lbFNpemUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhdmFpbGFibGVIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoO1xuXG4gICAgICAgIHZhciBwYW5lbFdpZHRoID0gMjAwO1xuICAgICAgICBpZiAoYXZhaWxhYmxlV2lkdGggKiAwLjIgPCAyMDApIHtcbiAgICAgICAgICAgIHBhbmVsV2lkdGggPSBhdmFpbGFibGVXaWR0aCAqIDAuMjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbcGFuZWxXaWR0aCwgYXZhaWxhYmxlSGVpZ2h0XTtcbiAgICB9O1xuXG4gICAgbXkuaXNWaXNpYmxlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiAoQ2hhdC5pc1Zpc2libGUoKSB8fCBDb250YWN0TGlzdC5pc1Zpc2libGUoKSB8fCBTZXR0aW5nc01lbnUuaXNWaXNpYmxlKCkpO1xuICAgIH07XG5cbiAgICByZXR1cm4gbXk7XG5cbn0oUGFuZWxUb2dnbGVyIHx8IHt9KSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUGFuZWxUb2dnbGVyOyIsIi8qIGdsb2JhbCAkLCBVdGlsLCBjb25uZWN0aW9uLCBuaWNrbmFtZTp0cnVlLCBnZXRWaWRlb1NpemUsXG5nZXRWaWRlb1Bvc2l0aW9uLCBzaG93VG9vbGJhciAqL1xudmFyIFJlcGxhY2VtZW50ID0gcmVxdWlyZShcIi4vUmVwbGFjZW1lbnRcIik7XG52YXIgQ29tbWFuZHNQcm9jZXNzb3IgPSByZXF1aXJlKFwiLi9Db21tYW5kc1wiKTtcbnZhciBUb29sYmFyVG9nZ2xlciA9IHJlcXVpcmUoXCIuLi8uLi90b29sYmFycy9Ub29sYmFyVG9nZ2xlclwiKTtcbnZhciBzbWlsZXlzID0gcmVxdWlyZShcIi4vc21pbGV5cy5qc29uXCIpLnNtaWxleXM7XG5cbnZhciBub3RpZmljYXRpb25JbnRlcnZhbCA9IGZhbHNlO1xudmFyIHVucmVhZE1lc3NhZ2VzID0gMDtcblxuXG4vKipcbiAqIFNob3dzL2hpZGVzIGEgdmlzdWFsIG5vdGlmaWNhdGlvbiwgaW5kaWNhdGluZyB0aGF0IGEgbWVzc2FnZSBoYXMgYXJyaXZlZC5cbiAqL1xuZnVuY3Rpb24gc2V0VmlzdWFsTm90aWZpY2F0aW9uKHNob3cpIHtcbiAgICB2YXIgdW5yZWFkTXNnRWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd1bnJlYWRNZXNzYWdlcycpO1xuICAgIHZhciB1bnJlYWRNc2dCb3R0b21FbGVtZW50XG4gICAgICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JvdHRvbVVucmVhZE1lc3NhZ2VzJyk7XG5cbiAgICB2YXIgZ2xvd2VyID0gJCgnI2NoYXRCdXR0b24nKTtcbiAgICB2YXIgYm90dG9tR2xvd2VyID0gJCgnI2NoYXRCb3R0b21CdXR0b24nKTtcblxuICAgIGlmICh1bnJlYWRNZXNzYWdlcykge1xuICAgICAgICB1bnJlYWRNc2dFbGVtZW50LmlubmVySFRNTCA9IHVucmVhZE1lc3NhZ2VzLnRvU3RyaW5nKCk7XG4gICAgICAgIHVucmVhZE1zZ0JvdHRvbUVsZW1lbnQuaW5uZXJIVE1MID0gdW5yZWFkTWVzc2FnZXMudG9TdHJpbmcoKTtcblxuICAgICAgICBUb29sYmFyVG9nZ2xlci5kb2NrVG9vbGJhcih0cnVlKTtcblxuICAgICAgICB2YXIgY2hhdEJ1dHRvbkVsZW1lbnRcbiAgICAgICAgICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXRCdXR0b24nKS5wYXJlbnROb2RlO1xuICAgICAgICB2YXIgbGVmdEluZGVudCA9IChVdGlsLmdldFRleHRXaWR0aChjaGF0QnV0dG9uRWxlbWVudCkgLVxuICAgICAgICAgICAgVXRpbC5nZXRUZXh0V2lkdGgodW5yZWFkTXNnRWxlbWVudCkpIC8gMjtcbiAgICAgICAgdmFyIHRvcEluZGVudCA9IChVdGlsLmdldFRleHRIZWlnaHQoY2hhdEJ1dHRvbkVsZW1lbnQpIC1cbiAgICAgICAgICAgIFV0aWwuZ2V0VGV4dEhlaWdodCh1bnJlYWRNc2dFbGVtZW50KSkgLyAyIC0gMztcblxuICAgICAgICB1bnJlYWRNc2dFbGVtZW50LnNldEF0dHJpYnV0ZShcbiAgICAgICAgICAgICdzdHlsZScsXG4gICAgICAgICAgICAgICAgJ3RvcDonICsgdG9wSW5kZW50ICtcbiAgICAgICAgICAgICAgICAnOyBsZWZ0OicgKyBsZWZ0SW5kZW50ICsgJzsnKTtcblxuICAgICAgICB2YXIgY2hhdEJvdHRvbUJ1dHRvbkVsZW1lbnRcbiAgICAgICAgICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXRCb3R0b21CdXR0b24nKS5wYXJlbnROb2RlO1xuICAgICAgICB2YXIgYm90dG9tTGVmdEluZGVudCA9IChVdGlsLmdldFRleHRXaWR0aChjaGF0Qm90dG9tQnV0dG9uRWxlbWVudCkgLVxuICAgICAgICAgICAgVXRpbC5nZXRUZXh0V2lkdGgodW5yZWFkTXNnQm90dG9tRWxlbWVudCkpIC8gMjtcbiAgICAgICAgdmFyIGJvdHRvbVRvcEluZGVudCA9IChVdGlsLmdldFRleHRIZWlnaHQoY2hhdEJvdHRvbUJ1dHRvbkVsZW1lbnQpIC1cbiAgICAgICAgICAgIFV0aWwuZ2V0VGV4dEhlaWdodCh1bnJlYWRNc2dCb3R0b21FbGVtZW50KSkgLyAyIC0gMjtcblxuICAgICAgICB1bnJlYWRNc2dCb3R0b21FbGVtZW50LnNldEF0dHJpYnV0ZShcbiAgICAgICAgICAgICdzdHlsZScsXG4gICAgICAgICAgICAgICAgJ3RvcDonICsgYm90dG9tVG9wSW5kZW50ICtcbiAgICAgICAgICAgICAgICAnOyBsZWZ0OicgKyBib3R0b21MZWZ0SW5kZW50ICsgJzsnKTtcblxuXG4gICAgICAgIGlmICghZ2xvd2VyLmhhc0NsYXNzKCdpY29uLWNoYXQtc2ltcGxlJykpIHtcbiAgICAgICAgICAgIGdsb3dlci5yZW1vdmVDbGFzcygnaWNvbi1jaGF0Jyk7XG4gICAgICAgICAgICBnbG93ZXIuYWRkQ2xhc3MoJ2ljb24tY2hhdC1zaW1wbGUnKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdW5yZWFkTXNnRWxlbWVudC5pbm5lckhUTUwgPSAnJztcbiAgICAgICAgdW5yZWFkTXNnQm90dG9tRWxlbWVudC5pbm5lckhUTUwgPSAnJztcbiAgICAgICAgZ2xvd2VyLnJlbW92ZUNsYXNzKCdpY29uLWNoYXQtc2ltcGxlJyk7XG4gICAgICAgIGdsb3dlci5hZGRDbGFzcygnaWNvbi1jaGF0Jyk7XG4gICAgfVxuXG4gICAgaWYgKHNob3cgJiYgIW5vdGlmaWNhdGlvbkludGVydmFsKSB7XG4gICAgICAgIG5vdGlmaWNhdGlvbkludGVydmFsID0gd2luZG93LnNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGdsb3dlci50b2dnbGVDbGFzcygnYWN0aXZlJyk7XG4gICAgICAgICAgICBib3R0b21HbG93ZXIudG9nZ2xlQ2xhc3MoJ2FjdGl2ZSBnbG93aW5nJyk7XG4gICAgICAgIH0sIDgwMCk7XG4gICAgfVxuICAgIGVsc2UgaWYgKCFzaG93ICYmIG5vdGlmaWNhdGlvbkludGVydmFsKSB7XG4gICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKG5vdGlmaWNhdGlvbkludGVydmFsKTtcbiAgICAgICAgbm90aWZpY2F0aW9uSW50ZXJ2YWwgPSBmYWxzZTtcbiAgICAgICAgZ2xvd2VyLnJlbW92ZUNsYXNzKCdhY3RpdmUnKTtcbiAgICAgICAgYm90dG9tR2xvd2VyLnJlbW92ZUNsYXNzKCdnbG93aW5nJyk7XG4gICAgICAgIGJvdHRvbUdsb3dlci5hZGRDbGFzcygnYWN0aXZlJyk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogUmV0dXJucyB0aGUgY3VycmVudCB0aW1lIGluIHRoZSBmb3JtYXQgaXQgaXMgc2hvd24gdG8gdGhlIHVzZXJcbiAqIEByZXR1cm5zIHtzdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGdldEN1cnJlbnRUaW1lKCkge1xuICAgIHZhciBub3cgICAgID0gbmV3IERhdGUoKTtcbiAgICB2YXIgaG91ciAgICA9IG5vdy5nZXRIb3VycygpO1xuICAgIHZhciBtaW51dGUgID0gbm93LmdldE1pbnV0ZXMoKTtcbiAgICB2YXIgc2Vjb25kICA9IG5vdy5nZXRTZWNvbmRzKCk7XG4gICAgaWYoaG91ci50b1N0cmluZygpLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBob3VyID0gJzAnK2hvdXI7XG4gICAgfVxuICAgIGlmKG1pbnV0ZS50b1N0cmluZygpLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICBtaW51dGUgPSAnMCcrbWludXRlO1xuICAgIH1cbiAgICBpZihzZWNvbmQudG9TdHJpbmcoKS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgc2Vjb25kID0gJzAnK3NlY29uZDtcbiAgICB9XG4gICAgcmV0dXJuIGhvdXIrJzonK21pbnV0ZSsnOicrc2Vjb25kO1xufVxuXG5mdW5jdGlvbiB0b2dnbGVTbWlsZXlzKClcbntcbiAgICB2YXIgc21pbGV5cyA9ICQoJyNzbWlsZXlzQ29udGFpbmVyJyk7XG4gICAgaWYoIXNtaWxleXMuaXMoJzp2aXNpYmxlJykpIHtcbiAgICAgICAgc21pbGV5cy5zaG93KFwic2xpZGVcIiwgeyBkaXJlY3Rpb246IFwiZG93blwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgc21pbGV5cy5oaWRlKFwic2xpZGVcIiwgeyBkaXJlY3Rpb246IFwiZG93blwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgfVxuICAgICQoJyN1c2VybXNnJykuZm9jdXMoKTtcbn1cblxuZnVuY3Rpb24gYWRkQ2xpY2tGdW5jdGlvbihzbWlsZXksIG51bWJlcikge1xuICAgIHNtaWxleS5vbmNsaWNrID0gZnVuY3Rpb24gYWRkU21pbGV5VG9NZXNzYWdlKCkge1xuICAgICAgICB2YXIgdXNlcm1zZyA9ICQoJyN1c2VybXNnJyk7XG4gICAgICAgIHZhciBtZXNzYWdlID0gdXNlcm1zZy52YWwoKTtcbiAgICAgICAgbWVzc2FnZSArPSBzbWlsZXlzWydzbWlsZXknICsgbnVtYmVyXTtcbiAgICAgICAgdXNlcm1zZy52YWwobWVzc2FnZSk7XG4gICAgICAgIHVzZXJtc2cuZ2V0KDApLnNldFNlbGVjdGlvblJhbmdlKG1lc3NhZ2UubGVuZ3RoLCBtZXNzYWdlLmxlbmd0aCk7XG4gICAgICAgIHRvZ2dsZVNtaWxleXMoKTtcbiAgICAgICAgdXNlcm1zZy5mb2N1cygpO1xuICAgIH07XG59XG5cbi8qKlxuICogQWRkcyB0aGUgc21pbGV5cyBjb250YWluZXIgdG8gdGhlIGNoYXRcbiAqL1xuZnVuY3Rpb24gYWRkU21pbGV5cygpIHtcbiAgICB2YXIgc21pbGV5c0NvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIHNtaWxleXNDb250YWluZXIuaWQgPSAnc21pbGV5c0NvbnRhaW5lcic7XG4gICAgZm9yKHZhciBpID0gMTsgaSA8PSAyMTsgaSsrKSB7XG4gICAgICAgIHZhciBzbWlsZXlDb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgc21pbGV5Q29udGFpbmVyLmlkID0gJ3NtaWxleScgKyBpO1xuICAgICAgICBzbWlsZXlDb250YWluZXIuY2xhc3NOYW1lID0gJ3NtaWxleUNvbnRhaW5lcic7XG4gICAgICAgIHZhciBzbWlsZXkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcbiAgICAgICAgc21pbGV5LnNyYyA9ICdpbWFnZXMvc21pbGV5cy9zbWlsZXknICsgaSArICcuc3ZnJztcbiAgICAgICAgc21pbGV5LmNsYXNzTmFtZSA9ICAnc21pbGV5JztcbiAgICAgICAgYWRkQ2xpY2tGdW5jdGlvbihzbWlsZXksIGkpO1xuICAgICAgICBzbWlsZXlDb250YWluZXIuYXBwZW5kQ2hpbGQoc21pbGV5KTtcbiAgICAgICAgc21pbGV5c0NvbnRhaW5lci5hcHBlbmRDaGlsZChzbWlsZXlDb250YWluZXIpO1xuICAgIH1cblxuICAgICQoXCIjY2hhdHNwYWNlXCIpLmFwcGVuZChzbWlsZXlzQ29udGFpbmVyKTtcbn1cblxuLyoqXG4gKiBSZXNpemVzIHRoZSBjaGF0IGNvbnZlcnNhdGlvbi5cbiAqL1xuZnVuY3Rpb24gcmVzaXplQ2hhdENvbnZlcnNhdGlvbigpIHtcbiAgICB2YXIgbXNnYXJlYUhlaWdodCA9ICQoJyN1c2VybXNnJykub3V0ZXJIZWlnaHQoKTtcbiAgICB2YXIgY2hhdHNwYWNlID0gJCgnI2NoYXRzcGFjZScpO1xuICAgIHZhciB3aWR0aCA9IGNoYXRzcGFjZS53aWR0aCgpO1xuICAgIHZhciBjaGF0ID0gJCgnI2NoYXRjb252ZXJzYXRpb24nKTtcbiAgICB2YXIgc21pbGV5cyA9ICQoJyNzbWlsZXlzYXJlYScpO1xuXG4gICAgc21pbGV5cy5oZWlnaHQobXNnYXJlYUhlaWdodCk7XG4gICAgJChcIiNzbWlsZXlzXCIpLmNzcygnYm90dG9tJywgKG1zZ2FyZWFIZWlnaHQgLSAyNikgLyAyKTtcbiAgICAkKCcjc21pbGV5c0NvbnRhaW5lcicpLmNzcygnYm90dG9tJywgbXNnYXJlYUhlaWdodCk7XG4gICAgY2hhdC53aWR0aCh3aWR0aCAtIDEwKTtcbiAgICBjaGF0LmhlaWdodCh3aW5kb3cuaW5uZXJIZWlnaHQgLSAxNSAtIG1zZ2FyZWFIZWlnaHQpO1xufVxuXG4vKipcbiAqIENoYXQgcmVsYXRlZCB1c2VyIGludGVyZmFjZS5cbiAqL1xudmFyIENoYXQgPSAoZnVuY3Rpb24gKG15KSB7XG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZXMgY2hhdCByZWxhdGVkIGludGVyZmFjZS5cbiAgICAgKi9cbiAgICBteS5pbml0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc3RvcmVkRGlzcGxheU5hbWUgPSB3aW5kb3cubG9jYWxTdG9yYWdlLmRpc3BsYXluYW1lO1xuICAgICAgICBpZiAoc3RvcmVkRGlzcGxheU5hbWUpIHtcbiAgICAgICAgICAgIG5pY2tuYW1lID0gc3RvcmVkRGlzcGxheU5hbWU7XG5cbiAgICAgICAgICAgIENoYXQuc2V0Q2hhdENvbnZlcnNhdGlvbk1vZGUodHJ1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICAkKCcjbmlja2lucHV0Jykua2V5ZG93bihmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5rZXlDb2RlID09PSAxMykge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdmFyIHZhbCA9IFV0aWwuZXNjYXBlSHRtbCh0aGlzLnZhbHVlKTtcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlID0gJyc7XG4gICAgICAgICAgICAgICAgaWYgKCFuaWNrbmFtZSkge1xuICAgICAgICAgICAgICAgICAgICBuaWNrbmFtZSA9IHZhbDtcbiAgICAgICAgICAgICAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZSA9IG5pY2tuYW1lO1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uZW11Yy5hZGREaXNwbGF5TmFtZVRvUHJlc2VuY2Uobmlja25hbWUpO1xuICAgICAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuc2VuZFByZXNlbmNlKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgQ2hhdC5zZXRDaGF0Q29udmVyc2F0aW9uTW9kZSh0cnVlKTtcblxuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAkKCcjdXNlcm1zZycpLmtleWRvd24oZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICBpZiAoZXZlbnQua2V5Q29kZSA9PT0gMTMpIHtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIHZhciB2YWx1ZSA9IHRoaXMudmFsdWU7XG4gICAgICAgICAgICAgICAgJCgnI3VzZXJtc2cnKS52YWwoJycpLnRyaWdnZXIoJ2F1dG9zaXplLnJlc2l6ZScpO1xuICAgICAgICAgICAgICAgIHRoaXMuZm9jdXMoKTtcbiAgICAgICAgICAgICAgICB2YXIgY29tbWFuZCA9IG5ldyBDb21tYW5kc1Byb2Nlc3Nvcih2YWx1ZSk7XG4gICAgICAgICAgICAgICAgaWYoY29tbWFuZC5pc0NvbW1hbmQoKSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGNvbW1hbmQucHJvY2Vzc0NvbW1hbmQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG1lc3NhZ2UgPSBVdGlsLmVzY2FwZUh0bWwodmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuc2VuZE1lc3NhZ2UobWVzc2FnZSwgbmlja25hbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgdmFyIG9uVGV4dEFyZWFSZXNpemUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXNpemVDaGF0Q29udmVyc2F0aW9uKCk7XG4gICAgICAgICAgICBDaGF0LnNjcm9sbENoYXRUb0JvdHRvbSgpO1xuICAgICAgICB9O1xuICAgICAgICAkKCcjdXNlcm1zZycpLmF1dG9zaXplKHtjYWxsYmFjazogb25UZXh0QXJlYVJlc2l6ZX0pO1xuXG4gICAgICAgICQoXCIjY2hhdHNwYWNlXCIpLmJpbmQoXCJzaG93blwiLFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHVucmVhZE1lc3NhZ2VzID0gMDtcbiAgICAgICAgICAgICAgICBzZXRWaXN1YWxOb3RpZmljYXRpb24oZmFsc2UpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgYWRkU21pbGV5cygpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBcHBlbmRzIHRoZSBnaXZlbiBtZXNzYWdlIHRvIHRoZSBjaGF0IGNvbnZlcnNhdGlvbi5cbiAgICAgKi9cbiAgICBteS51cGRhdGVDaGF0Q29udmVyc2F0aW9uID0gZnVuY3Rpb24gKGZyb20sIGRpc3BsYXlOYW1lLCBtZXNzYWdlKSB7XG4gICAgICAgIHZhciBkaXZDbGFzc05hbWUgPSAnJztcblxuICAgICAgICBpZiAoY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCA9PT0gZnJvbSkge1xuICAgICAgICAgICAgZGl2Q2xhc3NOYW1lID0gXCJsb2NhbHVzZXJcIjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGRpdkNsYXNzTmFtZSA9IFwicmVtb3RldXNlclwiO1xuXG4gICAgICAgICAgICBpZiAoIUNoYXQuaXNWaXNpYmxlKCkpIHtcbiAgICAgICAgICAgICAgICB1bnJlYWRNZXNzYWdlcysrO1xuICAgICAgICAgICAgICAgIFV0aWwucGxheVNvdW5kTm90aWZpY2F0aW9uKCdjaGF0Tm90aWZpY2F0aW9uJyk7XG4gICAgICAgICAgICAgICAgc2V0VmlzdWFsTm90aWZpY2F0aW9uKHRydWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gcmVwbGFjZSBsaW5rcyBhbmQgc21pbGV5c1xuICAgICAgICAvLyBTdHJvcGhlIGFscmVhZHkgZXNjYXBlcyBzcGVjaWFsIHN5bWJvbHMgb24gc2VuZGluZyxcbiAgICAgICAgLy8gc28gd2UgZXNjYXBlIGhlcmUgb25seSB0YWdzIHRvIGF2b2lkIGRvdWJsZSAmYW1wO1xuICAgICAgICB2YXIgZXNjTWVzc2FnZSA9IG1lc3NhZ2UucmVwbGFjZSgvPC9nLCAnJmx0OycpLlxuICAgICAgICAgICAgcmVwbGFjZSgvPi9nLCAnJmd0OycpLnJlcGxhY2UoL1xcbi9nLCAnPGJyLz4nKTtcbiAgICAgICAgdmFyIGVzY0Rpc3BsYXlOYW1lID0gVXRpbC5lc2NhcGVIdG1sKGRpc3BsYXlOYW1lKTtcbiAgICAgICAgbWVzc2FnZSA9IFJlcGxhY2VtZW50LnByb2Nlc3NSZXBsYWNlbWVudHMoZXNjTWVzc2FnZSk7XG5cbiAgICAgICAgdmFyIG1lc3NhZ2VDb250YWluZXIgPVxuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJjaGF0bWVzc2FnZVwiPicrXG4gICAgICAgICAgICAgICAgJzxpbWcgc3JjPVwiLi4vaW1hZ2VzL2NoYXRBcnJvdy5zdmdcIiBjbGFzcz1cImNoYXRBcnJvd1wiPicgK1xuICAgICAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwidXNlcm5hbWUgJyArIGRpdkNsYXNzTmFtZSArJ1wiPicgKyBlc2NEaXNwbGF5TmFtZSArXG4gICAgICAgICAgICAgICAgJzwvZGl2PicgKyAnPGRpdiBjbGFzcz1cInRpbWVzdGFtcFwiPicgKyBnZXRDdXJyZW50VGltZSgpICtcbiAgICAgICAgICAgICAgICAnPC9kaXY+JyArICc8ZGl2IGNsYXNzPVwidXNlcm1lc3NhZ2VcIj4nICsgbWVzc2FnZSArICc8L2Rpdj4nICtcbiAgICAgICAgICAgICc8L2Rpdj4nO1xuXG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYXBwZW5kKG1lc3NhZ2VDb250YWluZXIpO1xuICAgICAgICAkKCcjY2hhdGNvbnZlcnNhdGlvbicpLmFuaW1hdGUoXG4gICAgICAgICAgICAgICAgeyBzY3JvbGxUb3A6ICQoJyNjaGF0Y29udmVyc2F0aW9uJylbMF0uc2Nyb2xsSGVpZ2h0fSwgMTAwMCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEFwcGVuZHMgZXJyb3IgbWVzc2FnZSB0byB0aGUgY29udmVyc2F0aW9uXG4gICAgICogQHBhcmFtIGVycm9yTWVzc2FnZSB0aGUgcmVjZWl2ZWQgZXJyb3IgbWVzc2FnZS5cbiAgICAgKiBAcGFyYW0gb3JpZ2luYWxUZXh0IHRoZSBvcmlnaW5hbCBtZXNzYWdlLlxuICAgICAqL1xuICAgIG15LmNoYXRBZGRFcnJvciA9IGZ1bmN0aW9uKGVycm9yTWVzc2FnZSwgb3JpZ2luYWxUZXh0KVxuICAgIHtcbiAgICAgICAgZXJyb3JNZXNzYWdlID0gVXRpbC5lc2NhcGVIdG1sKGVycm9yTWVzc2FnZSk7XG4gICAgICAgIG9yaWdpbmFsVGV4dCA9IFV0aWwuZXNjYXBlSHRtbChvcmlnaW5hbFRleHQpO1xuXG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYXBwZW5kKFxuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJlcnJvck1lc3NhZ2VcIj48Yj5FcnJvcjogPC9iPicgKyAnWW91ciBtZXNzYWdlJyArXG4gICAgICAgICAgICAob3JpZ2luYWxUZXh0PyAoJyBcXFwiJysgb3JpZ2luYWxUZXh0ICsgJ1xcXCInKSA6IFwiXCIpICtcbiAgICAgICAgICAgICcgd2FzIG5vdCBzZW50LicgK1xuICAgICAgICAgICAgKGVycm9yTWVzc2FnZT8gKCcgUmVhc29uOiAnICsgZXJyb3JNZXNzYWdlKSA6ICcnKSArICAnPC9kaXY+Jyk7XG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYW5pbWF0ZShcbiAgICAgICAgICAgIHsgc2Nyb2xsVG9wOiAkKCcjY2hhdGNvbnZlcnNhdGlvbicpWzBdLnNjcm9sbEhlaWdodH0sIDEwMDApO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdWJqZWN0IHRvIHRoZSBVSVxuICAgICAqIEBwYXJhbSBzdWJqZWN0IHRoZSBzdWJqZWN0XG4gICAgICovXG4gICAgbXkuY2hhdFNldFN1YmplY3QgPSBmdW5jdGlvbihzdWJqZWN0KVxuICAgIHtcbiAgICAgICAgaWYoc3ViamVjdClcbiAgICAgICAgICAgIHN1YmplY3QgPSBzdWJqZWN0LnRyaW0oKTtcbiAgICAgICAgJCgnI3N1YmplY3QnKS5odG1sKFJlcGxhY2VtZW50LmxpbmtpZnkoVXRpbC5lc2NhcGVIdG1sKHN1YmplY3QpKSk7XG4gICAgICAgIGlmKHN1YmplY3QgPT09IFwiXCIpXG4gICAgICAgIHtcbiAgICAgICAgICAgICQoXCIjc3ViamVjdFwiKS5jc3Moe2Rpc3BsYXk6IFwibm9uZVwifSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICAkKFwiI3N1YmplY3RcIikuY3NzKHtkaXNwbGF5OiBcImJsb2NrXCJ9KTtcbiAgICAgICAgfVxuICAgIH07XG5cblxuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgY2hhdCBjb252ZXJzYXRpb24gbW9kZS5cbiAgICAgKi9cbiAgICBteS5zZXRDaGF0Q29udmVyc2F0aW9uTW9kZSA9IGZ1bmN0aW9uIChpc0NvbnZlcnNhdGlvbk1vZGUpIHtcbiAgICAgICAgaWYgKGlzQ29udmVyc2F0aW9uTW9kZSkge1xuICAgICAgICAgICAgJCgnI25pY2tuYW1lJykuY3NzKHt2aXNpYmlsaXR5OiAnaGlkZGVuJ30pO1xuICAgICAgICAgICAgJCgnI2NoYXRjb252ZXJzYXRpb24nKS5jc3Moe3Zpc2liaWxpdHk6ICd2aXNpYmxlJ30pO1xuICAgICAgICAgICAgJCgnI3VzZXJtc2cnKS5jc3Moe3Zpc2liaWxpdHk6ICd2aXNpYmxlJ30pO1xuICAgICAgICAgICAgJCgnI3NtaWxleXNhcmVhJykuY3NzKHt2aXNpYmlsaXR5OiAndmlzaWJsZSd9KTtcbiAgICAgICAgICAgICQoJyN1c2VybXNnJykuZm9jdXMoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXNpemVzIHRoZSBjaGF0IGFyZWEuXG4gICAgICovXG4gICAgbXkucmVzaXplQ2hhdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNoYXRTaXplID0gcmVxdWlyZShcIi4uL1NpZGVQYW5lbFRvZ2dsZXJcIikuZ2V0UGFuZWxTaXplKCk7XG5cbiAgICAgICAgJCgnI2NoYXRzcGFjZScpLndpZHRoKGNoYXRTaXplWzBdKTtcbiAgICAgICAgJCgnI2NoYXRzcGFjZScpLmhlaWdodChjaGF0U2l6ZVsxXSk7XG5cbiAgICAgICAgcmVzaXplQ2hhdENvbnZlcnNhdGlvbigpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGNoYXQgaXMgY3VycmVudGx5IHZpc2libGUuXG4gICAgICovXG4gICAgbXkuaXNWaXNpYmxlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gJCgnI2NoYXRzcGFjZScpLmlzKFwiOnZpc2libGVcIik7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBTaG93cyBhbmQgaGlkZXMgdGhlIHdpbmRvdyB3aXRoIHRoZSBzbWlsZXlzXG4gICAgICovXG4gICAgbXkudG9nZ2xlU21pbGV5cyA9IHRvZ2dsZVNtaWxleXM7XG5cbiAgICAvKipcbiAgICAgKiBTY3JvbGxzIGNoYXQgdG8gdGhlIGJvdHRvbS5cbiAgICAgKi9cbiAgICBteS5zY3JvbGxDaGF0VG9Cb3R0b20gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkKCcjY2hhdGNvbnZlcnNhdGlvbicpLnNjcm9sbFRvcChcbiAgICAgICAgICAgICAgICAkKCcjY2hhdGNvbnZlcnNhdGlvbicpWzBdLnNjcm9sbEhlaWdodCk7XG4gICAgICAgIH0sIDUpO1xuICAgIH07XG5cblxuICAgIHJldHVybiBteTtcbn0oQ2hhdCB8fCB7fSkpO1xubW9kdWxlLmV4cG9ydHMgPSBDaGF0OyIsIi8qKlxuICogTGlzdCB3aXRoIHN1cHBvcnRlZCBjb21tYW5kcy4gVGhlIGtleXMgYXJlIHRoZSBuYW1lcyBvZiB0aGUgY29tbWFuZHMgYW5kXG4gKiB0aGUgdmFsdWUgaXMgdGhlIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIHRoZSBtZXNzYWdlLlxuICogQHR5cGUge3tTdHJpbmc6IGZ1bmN0aW9ufX1cbiAqL1xudmFyIGNvbW1hbmRzID0ge1xuICAgIFwidG9waWNcIiA6IHByb2Nlc3NUb3BpY1xufTtcblxuLyoqXG4gKiBFeHRyYWN0cyB0aGUgY29tbWFuZCBmcm9tIHRoZSBtZXNzYWdlLlxuICogQHBhcmFtIG1lc3NhZ2UgdGhlIHJlY2VpdmVkIG1lc3NhZ2VcbiAqIEByZXR1cm5zIHtzdHJpbmd9IHRoZSBjb21tYW5kXG4gKi9cbmZ1bmN0aW9uIGdldENvbW1hbmQobWVzc2FnZSlcbntcbiAgICBpZihtZXNzYWdlKVxuICAgIHtcbiAgICAgICAgZm9yKHZhciBjb21tYW5kIGluIGNvbW1hbmRzKVxuICAgICAgICB7XG4gICAgICAgICAgICBpZihtZXNzYWdlLmluZGV4T2YoXCIvXCIgKyBjb21tYW5kKSA9PSAwKVxuICAgICAgICAgICAgICAgIHJldHVybiBjb21tYW5kO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBcIlwiO1xufTtcblxuLyoqXG4gKiBQcm9jZXNzZXMgdGhlIGRhdGEgZm9yIHRvcGljIGNvbW1hbmQuXG4gKiBAcGFyYW0gY29tbWFuZEFyZ3VtZW50cyB0aGUgYXJndW1lbnRzIG9mIHRoZSB0b3BpYyBjb21tYW5kLlxuICovXG5mdW5jdGlvbiBwcm9jZXNzVG9waWMoY29tbWFuZEFyZ3VtZW50cylcbntcbiAgICB2YXIgdG9waWMgPSBVdGlsLmVzY2FwZUh0bWwoY29tbWFuZEFyZ3VtZW50cyk7XG4gICAgY29ubmVjdGlvbi5lbXVjLnNldFN1YmplY3QodG9waWMpO1xufVxuXG4vKipcbiAqIENvbnN0cnVjdHMgbmV3IENvbW1hbmRQcm9jY2Vzc29yIGluc3RhbmNlIGZyb20gYSBtZXNzYWdlIHRoYXRcbiAqIGhhbmRsZXMgY29tbWFuZHMgcmVjZWl2ZWQgdmlhIGNoYXQgbWVzc2FnZXMuXG4gKiBAcGFyYW0gbWVzc2FnZSB0aGUgbWVzc2FnZVxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIENvbW1hbmRzUHJvY2Vzc29yKG1lc3NhZ2UpXG57XG5cblxuICAgIHZhciBjb21tYW5kID0gZ2V0Q29tbWFuZChtZXNzYWdlKTtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhlIGNvbW1hbmQuXG4gICAgICogQHJldHVybnMge1N0cmluZ30gdGhlIGNvbW1hbmRcbiAgICAgKi9cbiAgICB0aGlzLmdldENvbW1hbmQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICByZXR1cm4gY29tbWFuZDtcbiAgICB9O1xuXG5cbiAgICB2YXIgbWVzc2FnZUFyZ3VtZW50ID0gbWVzc2FnZS5zdWJzdHIoY29tbWFuZC5sZW5ndGggKyAyKTtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGFyZ3VtZW50cyBvZiB0aGUgY29tbWFuZC5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgICAqL1xuICAgIHRoaXMuZ2V0QXJndW1lbnQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICByZXR1cm4gbWVzc2FnZUFyZ3VtZW50O1xuICAgIH07XG59XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhpcyBpbnN0YW5jZSBpcyB2YWxpZCBjb21tYW5kIG9yIG5vdC5cbiAqIEByZXR1cm5zIHtib29sZWFufVxuICovXG5Db21tYW5kc1Byb2Nlc3Nvci5wcm90b3R5cGUuaXNDb21tYW5kID0gZnVuY3Rpb24oKVxue1xuICAgIGlmKHRoaXMuZ2V0Q29tbWFuZCgpKVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gZmFsc2U7XG59O1xuXG4vKipcbiAqIFByb2Nlc3NlcyB0aGUgY29tbWFuZC5cbiAqL1xuQ29tbWFuZHNQcm9jZXNzb3IucHJvdG90eXBlLnByb2Nlc3NDb21tYW5kID0gZnVuY3Rpb24oKVxue1xuICAgIGlmKCF0aGlzLmlzQ29tbWFuZCgpKVxuICAgICAgICByZXR1cm47XG5cbiAgICBjb21tYW5kc1t0aGlzLmdldENvbW1hbmQoKV0odGhpcy5nZXRBcmd1bWVudCgpKTtcblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb21tYW5kc1Byb2Nlc3NvcjsiLCJ2YXIgU21pbGV5cyA9IHJlcXVpcmUoXCIuL3NtaWxleXMuanNvblwiKTtcbi8qKlxuICogUHJvY2Vzc2VzIGxpbmtzIGFuZCBzbWlsZXlzIGluIFwiYm9keVwiXG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NSZXBsYWNlbWVudHMoYm9keSlcbntcbiAgICAvL21ha2UgbGlua3MgY2xpY2thYmxlXG4gICAgYm9keSA9IGxpbmtpZnkoYm9keSk7XG5cbiAgICAvL2FkZCBzbWlsZXlzXG4gICAgYm9keSA9IHNtaWxpZnkoYm9keSk7XG5cbiAgICByZXR1cm4gYm9keTtcbn1cblxuLyoqXG4gKiBGaW5kcyBhbmQgcmVwbGFjZXMgYWxsIGxpbmtzIGluIHRoZSBsaW5rcyBpbiBcImJvZHlcIlxuICogd2l0aCB0aGVpciA8YSBocmVmPVwiXCI+PC9hPlxuICovXG5mdW5jdGlvbiBsaW5raWZ5KGlucHV0VGV4dClcbntcbiAgICB2YXIgcmVwbGFjZWRUZXh0LCByZXBsYWNlUGF0dGVybjEsIHJlcGxhY2VQYXR0ZXJuMiwgcmVwbGFjZVBhdHRlcm4zO1xuXG4gICAgLy9VUkxzIHN0YXJ0aW5nIHdpdGggaHR0cDovLywgaHR0cHM6Ly8sIG9yIGZ0cDovL1xuICAgIHJlcGxhY2VQYXR0ZXJuMSA9IC8oXFxiKGh0dHBzP3xmdHApOlxcL1xcL1stQS1aMC05KyZAI1xcLyU/PX5ffCE6LC47XSpbLUEtWjAtOSsmQCNcXC8lPX5ffF0pL2dpbTtcbiAgICByZXBsYWNlZFRleHQgPSBpbnB1dFRleHQucmVwbGFjZShyZXBsYWNlUGF0dGVybjEsICc8YSBocmVmPVwiJDFcIiB0YXJnZXQ9XCJfYmxhbmtcIj4kMTwvYT4nKTtcblxuICAgIC8vVVJMcyBzdGFydGluZyB3aXRoIFwid3d3LlwiICh3aXRob3V0IC8vIGJlZm9yZSBpdCwgb3IgaXQnZCByZS1saW5rIHRoZSBvbmVzIGRvbmUgYWJvdmUpLlxuICAgIHJlcGxhY2VQYXR0ZXJuMiA9IC8oXnxbXlxcL10pKHd3d1xcLltcXFNdKyhcXGJ8JCkpL2dpbTtcbiAgICByZXBsYWNlZFRleHQgPSByZXBsYWNlZFRleHQucmVwbGFjZShyZXBsYWNlUGF0dGVybjIsICckMTxhIGhyZWY9XCJodHRwOi8vJDJcIiB0YXJnZXQ9XCJfYmxhbmtcIj4kMjwvYT4nKTtcblxuICAgIC8vQ2hhbmdlIGVtYWlsIGFkZHJlc3NlcyB0byBtYWlsdG86OiBsaW5rcy5cbiAgICByZXBsYWNlUGF0dGVybjMgPSAvKChbYS16QS1aMC05XFwtXFxfXFwuXSkrQFthLXpBLVpcXF9dKz8oXFwuW2EtekEtWl17Miw2fSkrKS9naW07XG4gICAgcmVwbGFjZWRUZXh0ID0gcmVwbGFjZWRUZXh0LnJlcGxhY2UocmVwbGFjZVBhdHRlcm4zLCAnPGEgaHJlZj1cIm1haWx0bzokMVwiPiQxPC9hPicpO1xuXG4gICAgcmV0dXJuIHJlcGxhY2VkVGV4dDtcbn1cblxuLyoqXG4gKiBSZXBsYWNlcyBjb21tb24gc21pbGV5IHN0cmluZ3Mgd2l0aCBpbWFnZXNcbiAqL1xuZnVuY3Rpb24gc21pbGlmeShib2R5KVxue1xuICAgIGlmKCFib2R5KSB7XG4gICAgICAgIHJldHVybiBib2R5O1xuICAgIH1cblxuICAgIHZhciByZWdleHMgPSBTbWlsZXlzW1wicmVnZXhzXCJdO1xuICAgIGZvcih2YXIgc21pbGV5IGluIHJlZ2V4cykge1xuICAgICAgICBpZihyZWdleHMuaGFzT3duUHJvcGVydHkoc21pbGV5KSkge1xuICAgICAgICAgICAgYm9keSA9IGJvZHkucmVwbGFjZShyZWdleHNbc21pbGV5XSxcbiAgICAgICAgICAgICAgICAgICAgJzxpbWcgY2xhc3M9XCJzbWlsZXlcIiBzcmM9XCJpbWFnZXMvc21pbGV5cy8nICsgc21pbGV5ICsgJy5zdmdcIj4nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBib2R5O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBwcm9jZXNzUmVwbGFjZW1lbnRzOiBwcm9jZXNzUmVwbGFjZW1lbnRzLFxuICAgIGxpbmtpZnk6IGxpbmtpZnlcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJzbWlsZXlzXCI6IHtcbiAgICAgICAgXCJzbWlsZXkxXCI6IFwiOilcIixcbiAgICAgICAgXCJzbWlsZXkyXCI6IFwiOihcIixcbiAgICAgICAgXCJzbWlsZXkzXCI6IFwiOkRcIixcbiAgICAgICAgXCJzbWlsZXk0XCI6IFwiKHkpXCIsXG4gICAgICAgIFwic21pbGV5NVwiOiBcIiA6UFwiLFxuICAgICAgICBcInNtaWxleTZcIjogXCIod2F2ZSlcIixcbiAgICAgICAgXCJzbWlsZXk3XCI6IFwiKGJsdXNoKVwiLFxuICAgICAgICBcInNtaWxleThcIjogXCIoY2h1Y2tsZSlcIixcbiAgICAgICAgXCJzbWlsZXk5XCI6IFwiKHNob2NrZWQpXCIsXG4gICAgICAgIFwic21pbGV5MTBcIjogXCI6KlwiLFxuICAgICAgICBcInNtaWxleTExXCI6IFwiKG4pXCIsXG4gICAgICAgIFwic21pbGV5MTJcIjogXCIoc2VhcmNoKVwiLFxuICAgICAgICBcInNtaWxleTEzXCI6IFwiIDwzXCIsXG4gICAgICAgIFwic21pbGV5MTRcIjogXCIob29wcylcIixcbiAgICAgICAgXCJzbWlsZXkxNVwiOiBcIihhbmdyeSlcIixcbiAgICAgICAgXCJzbWlsZXkxNlwiOiBcIihhbmdlbClcIixcbiAgICAgICAgXCJzbWlsZXkxN1wiOiBcIihzaWNrKVwiLFxuICAgICAgICBcInNtaWxleTE4XCI6IFwiOyhcIixcbiAgICAgICAgXCJzbWlsZXkxOVwiOiBcIihib21iKVwiLFxuICAgICAgICBcInNtaWxleTIwXCI6IFwiKGNsYXApXCIsXG4gICAgICAgIFwic21pbGV5MjFcIjogXCIgOylcIlxuICAgIH0sXG4gICAgXCJyZWdleHNcIjoge1xuICAgICAgICBcInNtaWxleTJcIjogLyg6LVxcKFxcKHw6LVxcKHw6XFwoXFwofDpcXCh8XFwoc2FkXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkzXCI6IC8oOi1cXClcXCl8OlxcKVxcKXxcXChsb2xcXCl8Oi1EfDpEKS9naSxcbiAgICAgICAgXCJzbWlsZXkxXCI6IC8oOi1cXCl8OlxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5NFwiOiAvKFxcKHlcXCl8XFwoWVxcKXxcXChva1xcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5NVwiOiAvKDotUHw6UHw6LXB8OnApL2dpLFxuICAgICAgICBcInNtaWxleTZcIjogLyhcXCh3YXZlXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXk3XCI6IC8oXFwoYmx1c2hcXCkpL2dpLFxuICAgICAgICBcInNtaWxleThcIjogLyhcXChjaHVja2xlXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXk5XCI6IC8oOi0wfFxcKHNob2NrZWRcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTEwXCI6IC8oOi1cXCp8OlxcKnxcXChraXNzXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkxMVwiOiAvKFxcKG5cXCkpL2dpLFxuICAgICAgICBcInNtaWxleTEyXCI6IC8oXFwoc2VhcmNoXFwpKS9nLFxuICAgICAgICBcInNtaWxleTEzXCI6IC8oPDN8Jmx0OzN8JmFtcDtsdDszfFxcKExcXCl8XFwobFxcKXxcXChIXFwpfFxcKGhcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTE0XCI6IC8oXFwob29wc1xcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTVcIjogLyhcXChhbmdyeVxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTZcIjogLyhcXChhbmdlbFxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTdcIjogLyhcXChzaWNrXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkxOFwiOiAvKDstXFwoXFwofDtcXChcXCh8Oy1cXCh8O1xcKHw6XCJcXCh8OlwiLVxcKHw6fi1cXCh8On5cXCh8XFwodXBzZXRcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTE5XCI6IC8oXFwoYm9tYlxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MjBcIjogLyhcXChjbGFwXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkyMVwiOiAvKDstXFwpfDtcXCl8Oy1cXClcXCl8O1xcKVxcKXw7LUR8O0R8XFwod2lua1xcKSkvZ2lcbiAgICB9XG59XG4iLCJcbnZhciBudW1iZXJPZkNvbnRhY3RzID0gMDtcbnZhciBub3RpZmljYXRpb25JbnRlcnZhbDtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBudW1iZXIgb2YgcGFydGljaXBhbnRzIGluIHRoZSBjb250YWN0IGxpc3QgYnV0dG9uIGFuZCBzZXRzXG4gKiB0aGUgZ2xvd1xuICogQHBhcmFtIGRlbHRhIGluZGljYXRlcyB3aGV0aGVyIGEgbmV3IHVzZXIgaGFzIGpvaW5lZCAoMSkgb3Igc29tZW9uZSBoYXNcbiAqIGxlZnQoLTEpXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZU51bWJlck9mUGFydGljaXBhbnRzKGRlbHRhKSB7XG4gICAgLy93aGVuIHRoZSB1c2VyIGlzIGFsb25lIHdlIGRvbid0IHNob3cgdGhlIG51bWJlciBvZiBwYXJ0aWNpcGFudHNcbiAgICBpZihudW1iZXJPZkNvbnRhY3RzID09PSAwKSB7XG4gICAgICAgICQoXCIjbnVtYmVyT2ZQYXJ0aWNpcGFudHNcIikudGV4dCgnJyk7XG4gICAgICAgIG51bWJlck9mQ29udGFjdHMgKz0gZGVsdGE7XG4gICAgfSBlbHNlIGlmKG51bWJlck9mQ29udGFjdHMgIT09IDAgJiYgIUNvbnRhY3RMaXN0LmlzVmlzaWJsZSgpKSB7XG4gICAgICAgIENvbnRhY3RMaXN0LnNldFZpc3VhbE5vdGlmaWNhdGlvbih0cnVlKTtcbiAgICAgICAgbnVtYmVyT2ZDb250YWN0cyArPSBkZWx0YTtcbiAgICAgICAgJChcIiNudW1iZXJPZlBhcnRpY2lwYW50c1wiKS50ZXh0KG51bWJlck9mQ29udGFjdHMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBhdmF0YXIgZWxlbWVudC5cbiAqXG4gKiBAcmV0dXJuIHRoZSBuZXdseSBjcmVhdGVkIGF2YXRhciBlbGVtZW50XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUF2YXRhcihpZCkge1xuICAgIHZhciBhdmF0YXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcbiAgICBhdmF0YXIuY2xhc3NOYW1lID0gXCJpY29uLWF2YXRhciBhdmF0YXJcIjtcbiAgICBhdmF0YXIuc3JjID0gXCJodHRwczovL3d3dy5ncmF2YXRhci5jb20vYXZhdGFyL1wiICsgaWQgKyBcIj9kPXdhdmF0YXImc2l6ZT0zMFwiO1xuXG4gICAgcmV0dXJuIGF2YXRhcjtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBkaXNwbGF5IG5hbWUgcGFyYWdyYXBoLlxuICpcbiAqIEBwYXJhbSBkaXNwbGF5TmFtZSB0aGUgZGlzcGxheSBuYW1lIHRvIHNldFxuICovXG5mdW5jdGlvbiBjcmVhdGVEaXNwbGF5TmFtZVBhcmFncmFwaChkaXNwbGF5TmFtZSkge1xuICAgIHZhciBwID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgncCcpO1xuICAgIHAuaW5uZXJUZXh0ID0gZGlzcGxheU5hbWU7XG5cbiAgICByZXR1cm4gcDtcbn1cblxuXG4vKipcbiAqIEluZGljYXRlcyB0aGF0IHRoZSBkaXNwbGF5IG5hbWUgaGFzIGNoYW5nZWQuXG4gKi9cbiQoZG9jdW1lbnQpLmJpbmQoICAgJ2Rpc3BsYXluYW1lY2hhbmdlZCcsXG4gICAgZnVuY3Rpb24gKGV2ZW50LCBwZWVySmlkLCBkaXNwbGF5TmFtZSkge1xuICAgICAgICBpZiAocGVlckppZCA9PT0gJ2xvY2FsVmlkZW9Db250YWluZXInKVxuICAgICAgICAgICAgcGVlckppZCA9IGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQ7XG5cbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQocGVlckppZCk7XG5cbiAgICAgICAgdmFyIGNvbnRhY3ROYW1lID0gJCgnI2NvbnRhY3RsaXN0ICMnICsgcmVzb3VyY2VKaWQgKyAnPnAnKTtcblxuICAgICAgICBpZiAoY29udGFjdE5hbWUgJiYgZGlzcGxheU5hbWUgJiYgZGlzcGxheU5hbWUubGVuZ3RoID4gMClcbiAgICAgICAgICAgIGNvbnRhY3ROYW1lLmh0bWwoZGlzcGxheU5hbWUpO1xuICAgIH0pO1xuXG5cbmZ1bmN0aW9uIHN0b3BHbG93aW5nKGdsb3dlcikge1xuICAgIHdpbmRvdy5jbGVhckludGVydmFsKG5vdGlmaWNhdGlvbkludGVydmFsKTtcbiAgICBub3RpZmljYXRpb25JbnRlcnZhbCA9IGZhbHNlO1xuICAgIGdsb3dlci5yZW1vdmVDbGFzcygnZ2xvd2luZycpO1xuICAgIGlmICghQ29udGFjdExpc3QuaXNWaXNpYmxlKCkpIHtcbiAgICAgICAgZ2xvd2VyLnJlbW92ZUNsYXNzKCdhY3RpdmUnKTtcbiAgICB9XG59XG5cblxuLyoqXG4gKiBDb250YWN0IGxpc3QuXG4gKi9cbnZhciBDb250YWN0TGlzdCA9IHtcbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGNoYXQgaXMgY3VycmVudGx5IHZpc2libGUuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIDx0dD50cnVlPC90dD4gaWYgdGhlIGNoYXQgaXMgY3VycmVudGx5IHZpc2libGUsIDx0dD5mYWxzZTwvdHQ+IC1cbiAgICAgKiBvdGhlcndpc2VcbiAgICAgKi9cbiAgICBpc1Zpc2libGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuICQoJyNjb250YWN0bGlzdCcpLmlzKFwiOnZpc2libGVcIik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEFkZHMgYSBjb250YWN0IGZvciB0aGUgZ2l2ZW4gcGVlckppZCBpZiBzdWNoIGRvZXNuJ3QgeWV0IGV4aXN0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHBlZXJKaWQgdGhlIHBlZXJKaWQgY29ycmVzcG9uZGluZyB0byB0aGUgY29udGFjdFxuICAgICAqIEBwYXJhbSBpZCB0aGUgdXNlcidzIGVtYWlsIG9yIHVzZXJJZCB1c2VkIHRvIGdldCB0aGUgdXNlcidzIGF2YXRhclxuICAgICAqL1xuICAgIGVuc3VyZUFkZENvbnRhY3Q6IGZ1bmN0aW9uIChwZWVySmlkLCBpZCkge1xuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChwZWVySmlkKTtcblxuICAgICAgICB2YXIgY29udGFjdCA9ICQoJyNjb250YWN0bGlzdD51bD5saVtpZD1cIicgKyByZXNvdXJjZUppZCArICdcIl0nKTtcblxuICAgICAgICBpZiAoIWNvbnRhY3QgfHwgY29udGFjdC5sZW5ndGggPD0gMClcbiAgICAgICAgICAgIENvbnRhY3RMaXN0LmFkZENvbnRhY3QocGVlckppZCwgaWQpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBZGRzIGEgY29udGFjdCBmb3IgdGhlIGdpdmVuIHBlZXIgamlkLlxuICAgICAqXG4gICAgICogQHBhcmFtIHBlZXJKaWQgdGhlIGppZCBvZiB0aGUgY29udGFjdCB0byBhZGRcbiAgICAgKiBAcGFyYW0gaWQgdGhlIGVtYWlsIG9yIHVzZXJJZCBvZiB0aGUgdXNlclxuICAgICAqL1xuICAgIGFkZENvbnRhY3Q6IGZ1bmN0aW9uIChwZWVySmlkLCBpZCkge1xuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChwZWVySmlkKTtcblxuICAgICAgICB2YXIgY29udGFjdGxpc3QgPSAkKCcjY29udGFjdGxpc3Q+dWwnKTtcblxuICAgICAgICB2YXIgbmV3Q29udGFjdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpJyk7XG4gICAgICAgIG5ld0NvbnRhY3QuaWQgPSByZXNvdXJjZUppZDtcbiAgICAgICAgbmV3Q29udGFjdC5jbGFzc05hbWUgPSBcImNsaWNrYWJsZVwiO1xuICAgICAgICBuZXdDb250YWN0Lm9uY2xpY2sgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5jdXJyZW50VGFyZ2V0LmNsYXNzTmFtZSA9PT0gXCJjbGlja2FibGVcIikge1xuICAgICAgICAgICAgICAgICQoQ29udGFjdExpc3QpLnRyaWdnZXIoJ2NvbnRhY3RjbGlja2VkJywgW3BlZXJKaWRdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBuZXdDb250YWN0LmFwcGVuZENoaWxkKGNyZWF0ZUF2YXRhcihpZCkpO1xuICAgICAgICBuZXdDb250YWN0LmFwcGVuZENoaWxkKGNyZWF0ZURpc3BsYXlOYW1lUGFyYWdyYXBoKFwiUGFydGljaXBhbnRcIikpO1xuXG4gICAgICAgIHZhciBjbEVsZW1lbnQgPSBjb250YWN0bGlzdC5nZXQoMCk7XG5cbiAgICAgICAgaWYgKHJlc291cmNlSmlkID09PSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChjb25uZWN0aW9uLmVtdWMubXlyb29tamlkKVxuICAgICAgICAgICAgJiYgJCgnI2NvbnRhY3RsaXN0PnVsIC50aXRsZScpWzBdLm5leHRTaWJsaW5nLm5leHRTaWJsaW5nKSB7XG4gICAgICAgICAgICBjbEVsZW1lbnQuaW5zZXJ0QmVmb3JlKG5ld0NvbnRhY3QsXG4gICAgICAgICAgICAgICAgJCgnI2NvbnRhY3RsaXN0PnVsIC50aXRsZScpWzBdLm5leHRTaWJsaW5nLm5leHRTaWJsaW5nKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNsRWxlbWVudC5hcHBlbmRDaGlsZChuZXdDb250YWN0KTtcbiAgICAgICAgfVxuICAgICAgICB1cGRhdGVOdW1iZXJPZlBhcnRpY2lwYW50cygxKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyBhIGNvbnRhY3QgZm9yIHRoZSBnaXZlbiBwZWVyIGppZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBwZWVySmlkIHRoZSBwZWVySmlkIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGNvbnRhY3QgdG8gcmVtb3ZlXG4gICAgICovXG4gICAgcmVtb3ZlQ29udGFjdDogZnVuY3Rpb24gKHBlZXJKaWQpIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQocGVlckppZCk7XG5cbiAgICAgICAgdmFyIGNvbnRhY3QgPSAkKCcjY29udGFjdGxpc3Q+dWw+bGlbaWQ9XCInICsgcmVzb3VyY2VKaWQgKyAnXCJdJyk7XG5cbiAgICAgICAgaWYgKGNvbnRhY3QgJiYgY29udGFjdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICB2YXIgY29udGFjdGxpc3QgPSAkKCcjY29udGFjdGxpc3Q+dWwnKTtcblxuICAgICAgICAgICAgY29udGFjdGxpc3QuZ2V0KDApLnJlbW92ZUNoaWxkKGNvbnRhY3QuZ2V0KDApKTtcblxuICAgICAgICAgICAgdXBkYXRlTnVtYmVyT2ZQYXJ0aWNpcGFudHMoLTEpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIHNldFZpc3VhbE5vdGlmaWNhdGlvbjogZnVuY3Rpb24gKHNob3csIHN0b3BHbG93aW5nSW4pIHtcbiAgICAgICAgdmFyIGdsb3dlciA9ICQoJyNjb250YWN0TGlzdEJ1dHRvbicpO1xuXG4gICAgICAgIGlmIChzaG93ICYmICFub3RpZmljYXRpb25JbnRlcnZhbCkge1xuICAgICAgICAgICAgbm90aWZpY2F0aW9uSW50ZXJ2YWwgPSB3aW5kb3cuc2V0SW50ZXJ2YWwoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGdsb3dlci50b2dnbGVDbGFzcygnYWN0aXZlIGdsb3dpbmcnKTtcbiAgICAgICAgICAgIH0sIDgwMCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoIXNob3cgJiYgbm90aWZpY2F0aW9uSW50ZXJ2YWwpIHtcbiAgICAgICAgICAgIHN0b3BHbG93aW5nKGdsb3dlcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHN0b3BHbG93aW5nSW4pIHtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHN0b3BHbG93aW5nKGdsb3dlcik7XG4gICAgICAgICAgICB9LCBzdG9wR2xvd2luZ0luKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBzZXRDbGlja2FibGU6IGZ1bmN0aW9uIChyZXNvdXJjZUppZCwgaXNDbGlja2FibGUpIHtcbiAgICAgICAgdmFyIGNvbnRhY3QgPSAkKCcjY29udGFjdGxpc3Q+dWw+bGlbaWQ9XCInICsgcmVzb3VyY2VKaWQgKyAnXCJdJyk7XG4gICAgICAgIGlmIChpc0NsaWNrYWJsZSkge1xuICAgICAgICAgICAgY29udGFjdC5hZGRDbGFzcygnY2xpY2thYmxlJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb250YWN0LnJlbW92ZUNsYXNzKCdjbGlja2FibGUnKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ29udGFjdExpc3Q7IiwidmFyIGVtYWlsID0gJyc7XG52YXIgZGlzcGxheU5hbWUgPSAnJztcbnZhciB1c2VySWQ7XG5cblxuZnVuY3Rpb24gc3VwcG9ydHNMb2NhbFN0b3JhZ2UoKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuICdsb2NhbFN0b3JhZ2UnIGluIHdpbmRvdyAmJiB3aW5kb3cubG9jYWxTdG9yYWdlICE9PSBudWxsO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJsb2NhbHN0b3JhZ2UgaXMgbm90IHN1cHBvcnRlZFwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBnZW5lcmF0ZVVuaXF1ZUlkKCkge1xuICAgIGZ1bmN0aW9uIF9wOCgpIHtcbiAgICAgICAgcmV0dXJuIChNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDE2KStcIjAwMDAwMDAwMFwiKS5zdWJzdHIoMiw4KTtcbiAgICB9XG4gICAgcmV0dXJuIF9wOCgpICsgX3A4KCkgKyBfcDgoKSArIF9wOCgpO1xufVxuXG5pZihzdXBwb3J0c0xvY2FsU3RvcmFnZSgpKSB7XG4gICAgaWYoIXdpbmRvdy5sb2NhbFN0b3JhZ2Uuaml0c2lNZWV0SWQpIHtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5qaXRzaU1lZXRJZCA9IGdlbmVyYXRlVW5pcXVlSWQoKTtcbiAgICAgICAgY29uc29sZS5sb2coXCJnZW5lcmF0ZWQgaWRcIiwgd2luZG93LmxvY2FsU3RvcmFnZS5qaXRzaU1lZXRJZCk7XG4gICAgfVxuICAgIHVzZXJJZCA9IHdpbmRvdy5sb2NhbFN0b3JhZ2Uuaml0c2lNZWV0SWQgfHwgJyc7XG4gICAgZW1haWwgPSB3aW5kb3cubG9jYWxTdG9yYWdlLmVtYWlsIHx8ICcnO1xuICAgIGRpc3BsYXlOYW1lID0gd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZSB8fCAnJztcbn0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coXCJsb2NhbCBzdG9yYWdlIGlzIG5vdCBzdXBwb3J0ZWRcIik7XG4gICAgdXNlcklkID0gZ2VuZXJhdGVVbmlxdWVJZCgpO1xufVxuXG52YXIgU2V0dGluZ3MgPVxue1xuICAgIHNldERpc3BsYXlOYW1lOiBmdW5jdGlvbiAobmV3RGlzcGxheU5hbWUpIHtcbiAgICAgICAgZGlzcGxheU5hbWUgPSBuZXdEaXNwbGF5TmFtZTtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZSA9IGRpc3BsYXlOYW1lO1xuICAgICAgICByZXR1cm4gZGlzcGxheU5hbWU7XG4gICAgfSxcbiAgICBzZXRFbWFpbDogZnVuY3Rpb24obmV3RW1haWwpXG4gICAge1xuICAgICAgICBlbWFpbCA9IG5ld0VtYWlsO1xuICAgICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLmVtYWlsID0gbmV3RW1haWw7XG4gICAgICAgIHJldHVybiBlbWFpbDtcbiAgICB9LFxuICAgIGdldFNldHRpbmdzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBlbWFpbDogZW1haWwsXG4gICAgICAgICAgICBkaXNwbGF5TmFtZTogZGlzcGxheU5hbWUsXG4gICAgICAgICAgICB1aWQ6IHVzZXJJZFxuICAgICAgICB9O1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2V0dGluZ3M7XG4iLCJ2YXIgQXZhdGFyID0gcmVxdWlyZShcIi4uLy4uL2F2YXRhci9BdmF0YXJcIik7XG52YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi9TZXR0aW5nc1wiKTtcblxuXG52YXIgU2V0dGluZ3NNZW51ID0ge1xuXG4gICAgdXBkYXRlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIG5ld0Rpc3BsYXlOYW1lID0gVXRpbC5lc2NhcGVIdG1sKCQoJyNzZXREaXNwbGF5TmFtZScpLmdldCgwKS52YWx1ZSk7XG4gICAgICAgIHZhciBuZXdFbWFpbCA9IFV0aWwuZXNjYXBlSHRtbCgkKCcjc2V0RW1haWwnKS5nZXQoMCkudmFsdWUpO1xuXG4gICAgICAgIGlmKG5ld0Rpc3BsYXlOYW1lKSB7XG4gICAgICAgICAgICB2YXIgZGlzcGxheU5hbWUgPSBTZXR0aW5ncy5zZXREaXNwbGF5TmFtZShuZXdEaXNwbGF5TmFtZSk7XG4gICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuYWRkRGlzcGxheU5hbWVUb1ByZXNlbmNlKGRpc3BsYXlOYW1lKTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZEVtYWlsVG9QcmVzZW5jZShuZXdFbWFpbCk7XG4gICAgICAgIHZhciBlbWFpbCA9IFNldHRpbmdzLnNldEVtYWlsKG5ld0VtYWlsKTtcblxuXG4gICAgICAgIGNvbm5lY3Rpb24uZW11Yy5zZW5kUHJlc2VuY2UoKTtcbiAgICAgICAgQXZhdGFyLnNldFVzZXJBdmF0YXIoY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCwgZW1haWwpO1xuICAgIH0sXG5cbiAgICBpc1Zpc2libGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gJCgnI3NldHRpbmdzbWVudScpLmlzKCc6dmlzaWJsZScpO1xuICAgIH0sXG5cbiAgICBzZXREaXNwbGF5TmFtZTogZnVuY3Rpb24obmV3RGlzcGxheU5hbWUpIHtcbiAgICAgICAgdmFyIGRpc3BsYXlOYW1lID0gU2V0dGluZ3Muc2V0RGlzcGxheU5hbWUobmV3RGlzcGxheU5hbWUpO1xuICAgICAgICAkKCcjc2V0RGlzcGxheU5hbWUnKS5nZXQoMCkudmFsdWUgPSBkaXNwbGF5TmFtZTtcbiAgICB9XG59O1xuXG4kKGRvY3VtZW50KS5iaW5kKCdkaXNwbGF5bmFtZWNoYW5nZWQnLCBmdW5jdGlvbihldmVudCwgcGVlckppZCwgbmV3RGlzcGxheU5hbWUpIHtcbiAgICBpZihwZWVySmlkID09PSAnbG9jYWxWaWRlb0NvbnRhaW5lcicgfHxcbiAgICAgICAgcGVlckppZCA9PT0gY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCkge1xuICAgICAgICBTZXR0aW5nc01lbnUuc2V0RGlzcGxheU5hbWUobmV3RGlzcGxheU5hbWUpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNldHRpbmdzTWVudTsiLCJ2YXIgUGFuZWxUb2dnbGVyID0gcmVxdWlyZShcIi4uL3NpZGVfcGFubmVscy9TaWRlUGFuZWxUb2dnbGVyXCIpO1xuXG52YXIgYnV0dG9uSGFuZGxlcnMgPSB7XG4gICAgXCJib3R0b21fdG9vbGJhcl9jb250YWN0X2xpc3RcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICBCb3R0b21Ub29sYmFyLnRvZ2dsZUNvbnRhY3RMaXN0KCk7XG4gICAgfSxcbiAgICBcImJvdHRvbV90b29sYmFyX2ZpbG1fc3RyaXBcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICBCb3R0b21Ub29sYmFyLnRvZ2dsZUZpbG1TdHJpcCgpO1xuICAgIH0sXG4gICAgXCJib3R0b21fdG9vbGJhcl9jaGF0XCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQm90dG9tVG9vbGJhci50b2dnbGVDaGF0KCk7XG4gICAgfVxufTtcblxudmFyIEJvdHRvbVRvb2xiYXIgPSAoZnVuY3Rpb24gKG15KSB7XG4gICAgbXkuaW5pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZm9yKHZhciBrIGluIGJ1dHRvbkhhbmRsZXJzKVxuICAgICAgICAgICAgJChcIiNcIiArIGspLmNsaWNrKGJ1dHRvbkhhbmRsZXJzW2tdKTtcbiAgICB9O1xuXG4gICAgbXkudG9nZ2xlQ2hhdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBQYW5lbFRvZ2dsZXIudG9nZ2xlQ2hhdCgpO1xuICAgIH07XG5cbiAgICBteS50b2dnbGVDb250YWN0TGlzdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBQYW5lbFRvZ2dsZXIudG9nZ2xlQ29udGFjdExpc3QoKTtcbiAgICB9O1xuXG4gICAgbXkudG9nZ2xlRmlsbVN0cmlwID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBmaWxtc3RyaXAgPSAkKFwiI3JlbW90ZVZpZGVvc1wiKTtcbiAgICAgICAgZmlsbXN0cmlwLnRvZ2dsZUNsYXNzKFwiaGlkZGVuXCIpO1xuICAgIH07XG5cbiAgICAkKGRvY3VtZW50KS5iaW5kKFwicmVtb3RldmlkZW8ucmVzaXplZFwiLCBmdW5jdGlvbiAoZXZlbnQsIHdpZHRoLCBoZWlnaHQpIHtcbiAgICAgICAgdmFyIGJvdHRvbSA9IChoZWlnaHQgLSAkKCcjYm90dG9tVG9vbGJhcicpLm91dGVySGVpZ2h0KCkpLzIgKyAxODtcblxuICAgICAgICAkKCcjYm90dG9tVG9vbGJhcicpLmNzcyh7Ym90dG9tOiBib3R0b20gKyAncHgnfSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gbXk7XG59KEJvdHRvbVRvb2xiYXIgfHwge30pKTtcblxubW9kdWxlLmV4cG9ydHMgPSBCb3R0b21Ub29sYmFyO1xuIiwiLyogZ2xvYmFsICQsIGludGVyZmFjZUNvbmZpZywgTW9kZXJhdG9yLCBzaG93RGVza3RvcFNoYXJpbmdCdXR0b24gKi9cblxudmFyIHRvb2xiYXJUaW1lb3V0T2JqZWN0LFxuICAgIHRvb2xiYXJUaW1lb3V0ID0gaW50ZXJmYWNlQ29uZmlnLklOSVRJQUxfVE9PTEJBUl9USU1FT1VUO1xuXG4vKipcbiAqIEhpZGVzIHRoZSB0b29sYmFyLlxuICovXG5mdW5jdGlvbiBoaWRlVG9vbGJhcigpIHtcbiAgICB2YXIgaGVhZGVyID0gJChcIiNoZWFkZXJcIiksXG4gICAgICAgIGJvdHRvbVRvb2xiYXIgPSAkKFwiI2JvdHRvbVRvb2xiYXJcIik7XG4gICAgdmFyIGlzVG9vbGJhckhvdmVyID0gZmFsc2U7XG4gICAgaGVhZGVyLmZpbmQoJyonKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGlkID0gJCh0aGlzKS5hdHRyKCdpZCcpO1xuICAgICAgICBpZiAoJChcIiNcIiArIGlkICsgXCI6aG92ZXJcIikubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgaXNUb29sYmFySG92ZXIgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfSk7XG4gICAgaWYgKCQoXCIjYm90dG9tVG9vbGJhcjpob3ZlclwiKS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGlzVG9vbGJhckhvdmVyID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBjbGVhclRpbWVvdXQodG9vbGJhclRpbWVvdXRPYmplY3QpO1xuICAgIHRvb2xiYXJUaW1lb3V0T2JqZWN0ID0gbnVsbDtcblxuICAgIGlmICghaXNUb29sYmFySG92ZXIpIHtcbiAgICAgICAgaGVhZGVyLmhpZGUoXCJzbGlkZVwiLCB7IGRpcmVjdGlvbjogXCJ1cFwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgICAgICQoJyNzdWJqZWN0JykuYW5pbWF0ZSh7dG9wOiBcIi09NDBcIn0sIDMwMCk7XG4gICAgICAgIGlmICgkKFwiI3JlbW90ZVZpZGVvc1wiKS5oYXNDbGFzcyhcImhpZGRlblwiKSkge1xuICAgICAgICAgICAgYm90dG9tVG9vbGJhci5oaWRlKFxuICAgICAgICAgICAgICAgIFwic2xpZGVcIiwge2RpcmVjdGlvbjogXCJyaWdodFwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRvb2xiYXJUaW1lb3V0T2JqZWN0ID0gc2V0VGltZW91dChoaWRlVG9vbGJhciwgdG9vbGJhclRpbWVvdXQpO1xuICAgIH1cbn1cblxudmFyIFRvb2xiYXJUb2dnbGVyID0ge1xuICAgIC8qKlxuICAgICAqIFNob3dzIHRoZSBtYWluIHRvb2xiYXIuXG4gICAgICovXG4gICAgc2hvd1Rvb2xiYXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGhlYWRlciA9ICQoXCIjaGVhZGVyXCIpLFxuICAgICAgICAgICAgYm90dG9tVG9vbGJhciA9ICQoXCIjYm90dG9tVG9vbGJhclwiKTtcbiAgICAgICAgaWYgKCFoZWFkZXIuaXMoJzp2aXNpYmxlJykgfHwgIWJvdHRvbVRvb2xiYXIuaXMoXCI6dmlzaWJsZVwiKSkge1xuICAgICAgICAgICAgaGVhZGVyLnNob3coXCJzbGlkZVwiLCB7IGRpcmVjdGlvbjogXCJ1cFwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgICAgICAgICAkKCcjc3ViamVjdCcpLmFuaW1hdGUoe3RvcDogXCIrPTQwXCJ9LCAzMDApO1xuICAgICAgICAgICAgaWYgKCFib3R0b21Ub29sYmFyLmlzKFwiOnZpc2libGVcIikpIHtcbiAgICAgICAgICAgICAgICBib3R0b21Ub29sYmFyLnNob3coXG4gICAgICAgICAgICAgICAgICAgIFwic2xpZGVcIiwge2RpcmVjdGlvbjogXCJyaWdodFwiLCBkdXJhdGlvbjogMzAwfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0b29sYmFyVGltZW91dE9iamVjdCkge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0b29sYmFyVGltZW91dE9iamVjdCk7XG4gICAgICAgICAgICAgICAgdG9vbGJhclRpbWVvdXRPYmplY3QgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdG9vbGJhclRpbWVvdXRPYmplY3QgPSBzZXRUaW1lb3V0KGhpZGVUb29sYmFyLCB0b29sYmFyVGltZW91dCk7XG4gICAgICAgICAgICB0b29sYmFyVGltZW91dCA9IGludGVyZmFjZUNvbmZpZy5UT09MQkFSX1RJTUVPVVQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoTW9kZXJhdG9yLmlzTW9kZXJhdG9yKCkpXG4gICAgICAgIHtcbi8vICAgICAgICAgICAgVE9ETzogRW5hYmxlIHNldHRpbmdzIGZ1bmN0aW9uYWxpdHkuXG4vLyAgICAgICAgICAgICAgICAgIE5lZWQgdG8gdW5jb21tZW50IHRoZSBzZXR0aW5ncyBidXR0b24gaW4gaW5kZXguaHRtbC5cbi8vICAgICAgICAgICAgJCgnI3NldHRpbmdzQnV0dG9uJykuY3NzKHt2aXNpYmlsaXR5OlwidmlzaWJsZVwifSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTaG93L2hpZGUgZGVza3RvcCBzaGFyaW5nIGJ1dHRvblxuICAgICAgICBzaG93RGVza3RvcFNoYXJpbmdCdXR0b24oKTtcbiAgICB9LFxuXG5cbiAgICAvKipcbiAgICAgKiBEb2Nrcy91bmRvY2tzIHRoZSB0b29sYmFyLlxuICAgICAqXG4gICAgICogQHBhcmFtIGlzRG9jayBpbmRpY2F0ZXMgd2hhdCBvcGVyYXRpb24gdG8gcGVyZm9ybVxuICAgICAqL1xuICAgIGRvY2tUb29sYmFyOiBmdW5jdGlvbiAoaXNEb2NrKSB7XG4gICAgICAgIGlmIChpc0RvY2spIHtcbiAgICAgICAgICAgIC8vIEZpcnN0IG1ha2Ugc3VyZSB0aGUgdG9vbGJhciBpcyBzaG93bi5cbiAgICAgICAgICAgIGlmICghJCgnI2hlYWRlcicpLmlzKCc6dmlzaWJsZScpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zaG93VG9vbGJhcigpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBUaGVuIGNsZWFyIHRoZSB0aW1lIG91dCwgdG8gZG9jayB0aGUgdG9vbGJhci5cbiAgICAgICAgICAgIGlmICh0b29sYmFyVGltZW91dE9iamVjdCkge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0b29sYmFyVGltZW91dE9iamVjdCk7XG4gICAgICAgICAgICAgICAgdG9vbGJhclRpbWVvdXRPYmplY3QgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKCEkKCcjaGVhZGVyJykuaXMoJzp2aXNpYmxlJykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNob3dUb29sYmFyKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0b29sYmFyVGltZW91dE9iamVjdCA9IHNldFRpbWVvdXQoaGlkZVRvb2xiYXIsIHRvb2xiYXJUaW1lb3V0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBUb29sYmFyVG9nZ2xlcjsiLCIvKiBnbG9iYWwgJCwgYnV0dG9uQ2xpY2ssIGNvbmZpZywgbG9ja1Jvb20sICBNb2RlcmF0b3IsXG4gICBzZXRTaGFyZWRLZXksIHNoYXJlZEtleSwgVXRpbCAqL1xudmFyIG1lc3NhZ2VIYW5kbGVyID0gcmVxdWlyZShcIi4uL3V0aWwvTWVzc2FnZUhhbmRsZXJcIik7XG52YXIgQm90dG9tVG9vbGJhciA9IHJlcXVpcmUoXCIuL0JvdHRvbVRvb2xiYXJcIik7XG52YXIgUHJlemkgPSByZXF1aXJlKFwiLi4vcHJlemkvUHJlemlcIik7XG52YXIgRXRoZXJwYWQgPSByZXF1aXJlKFwiLi4vZXRoZXJwYWQvRXRoZXJwYWRcIik7XG52YXIgUGFuZWxUb2dnbGVyID0gcmVxdWlyZShcIi4uL3NpZGVfcGFubmVscy9TaWRlUGFuZWxUb2dnbGVyXCIpO1xuXG52YXIgcm9vbVVybCA9IG51bGw7XG52YXIgc2hhcmVkS2V5ID0gJyc7XG52YXIgYXV0aGVudGljYXRpb25XaW5kb3cgPSBudWxsO1xuXG52YXIgYnV0dG9uSGFuZGxlcnMgPVxue1xuICAgIFwidG9vbGJhcl9idXR0b25fbXV0ZVwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0b2dnbGVBdWRpbygpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9jYW1lcmFcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdG9nZ2xlVmlkZW8oKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fYXV0aGVudGljYXRpb25cIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gVG9vbGJhci5hdXRoZW50aWNhdGVDbGlja2VkKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX3JlY29yZFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0b2dnbGVSZWNvcmRpbmcoKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fc2VjdXJpdHlcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gVG9vbGJhci5vcGVuTG9ja0RpYWxvZygpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9saW5rXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFRvb2xiYXIub3BlbkxpbmtEaWFsb2coKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fY2hhdFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBCb3R0b21Ub29sYmFyLnRvZ2dsZUNoYXQoKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fcHJlemlcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUHJlemkub3BlblByZXppRGlhbG9nKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX2V0aGVycGFkXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIEV0aGVycGFkLnRvZ2dsZUV0aGVycGFkKDApO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9kZXNrdG9wc2hhcmluZ1wiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0b2dnbGVTY3JlZW5TaGFyaW5nKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX2Z1bGxTY3JlZW5cIjogZnVuY3Rpb24oKVxuICAgIHtcbiAgICAgICAgYnV0dG9uQ2xpY2soXCIjZnVsbFNjcmVlblwiLCBcImljb24tZnVsbC1zY3JlZW4gaWNvbi1leGl0LWZ1bGwtc2NyZWVuXCIpO1xuICAgICAgICByZXR1cm4gVG9vbGJhci50b2dnbGVGdWxsU2NyZWVuKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX3NpcFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBjYWxsU2lwQnV0dG9uQ2xpY2tlZCgpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9zZXR0aW5nc1wiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIFBhbmVsVG9nZ2xlci50b2dnbGVTZXR0aW5nc01lbnUoKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25faGFuZ3VwXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGhhbmd1cCgpO1xuICAgIH1cbn07XG5cbi8qKlxuICogU3RhcnRzIG9yIHN0b3BzIHRoZSByZWNvcmRpbmcgZm9yIHRoZSBjb25mZXJlbmNlLlxuICovXG5cbmZ1bmN0aW9uIHRvZ2dsZVJlY29yZGluZygpIHtcbiAgICBSZWNvcmRpbmcudG9nZ2xlUmVjb3JkaW5nKCk7XG59XG5cbi8qKlxuICogTG9ja3MgLyB1bmxvY2tzIHRoZSByb29tLlxuICovXG5mdW5jdGlvbiBsb2NrUm9vbShsb2NrKSB7XG4gICAgdmFyIGN1cnJlbnRTaGFyZWRLZXkgPSAnJztcbiAgICBpZiAobG9jaylcbiAgICAgICAgY3VycmVudFNoYXJlZEtleSA9IHNoYXJlZEtleTtcblxuICAgIGNvbm5lY3Rpb24uZW11Yy5sb2NrUm9vbShjdXJyZW50U2hhcmVkS2V5LCBmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgIC8vIHBhc3N3b3JkIGlzIHJlcXVpcmVkXG4gICAgICAgIGlmIChzaGFyZWRLZXkpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzZXQgcm9vbSBwYXNzd29yZCcpO1xuICAgICAgICAgICAgVG9vbGJhci5sb2NrTG9ja0J1dHRvbigpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ3JlbW92ZWQgcm9vbSBwYXNzd29yZCcpO1xuICAgICAgICAgICAgVG9vbGJhci51bmxvY2tMb2NrQnV0dG9uKCk7XG4gICAgICAgIH1cbiAgICB9LCBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUud2Fybignc2V0dGluZyBwYXNzd29yZCBmYWlsZWQnLCBlcnIpO1xuICAgICAgICBtZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoJ0xvY2sgZmFpbGVkJyxcbiAgICAgICAgICAgICdGYWlsZWQgdG8gbG9jayBjb25mZXJlbmNlLicsXG4gICAgICAgICAgICBlcnIpO1xuICAgICAgICBUb29sYmFyLnNldFNoYXJlZEtleSgnJyk7XG4gICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zb2xlLndhcm4oJ3Jvb20gcGFzc3dvcmRzIG5vdCBzdXBwb3J0ZWQnKTtcbiAgICAgICAgbWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKCdXYXJuaW5nJyxcbiAgICAgICAgICAgICdSb29tIHBhc3N3b3JkcyBhcmUgY3VycmVudGx5IG5vdCBzdXBwb3J0ZWQuJyk7XG4gICAgICAgIFRvb2xiYXIuc2V0U2hhcmVkS2V5KCcnKTtcbiAgICB9KTtcbn07XG5cbi8qKlxuICogSW52aXRlIHBhcnRpY2lwYW50cyB0byBjb25mZXJlbmNlLlxuICovXG5mdW5jdGlvbiBpbnZpdGVQYXJ0aWNpcGFudHMoKSB7XG4gICAgaWYgKHJvb21VcmwgPT09IG51bGwpXG4gICAgICAgIHJldHVybjtcblxuICAgIHZhciBzaGFyZWRLZXlUZXh0ID0gXCJcIjtcbiAgICBpZiAoc2hhcmVkS2V5ICYmIHNoYXJlZEtleS5sZW5ndGggPiAwKSB7XG4gICAgICAgIHNoYXJlZEtleVRleHQgPVxuICAgICAgICAgICAgXCJUaGlzIGNvbmZlcmVuY2UgaXMgcGFzc3dvcmQgcHJvdGVjdGVkLiBQbGVhc2UgdXNlIHRoZSBcIiArXG4gICAgICAgICAgICBcImZvbGxvd2luZyBwaW4gd2hlbiBqb2luaW5nOiUwRCUwQSUwRCUwQVwiICtcbiAgICAgICAgICAgIHNoYXJlZEtleSArIFwiJTBEJTBBJTBEJTBBXCI7XG4gICAgfVxuXG4gICAgdmFyIGNvbmZlcmVuY2VOYW1lID0gcm9vbVVybC5zdWJzdHJpbmcocm9vbVVybC5sYXN0SW5kZXhPZignLycpICsgMSk7XG4gICAgdmFyIHN1YmplY3QgPSBcIkludml0YXRpb24gdG8gYSBcIiArIGludGVyZmFjZUNvbmZpZy5BUFBfTkFNRSArIFwiIChcIiArIGNvbmZlcmVuY2VOYW1lICsgXCIpXCI7XG4gICAgdmFyIGJvZHkgPSBcIkhleSB0aGVyZSwgSSUyN2QgbGlrZSB0byBpbnZpdGUgeW91IHRvIGEgXCIgKyBpbnRlcmZhY2VDb25maWcuQVBQX05BTUUgK1xuICAgICAgICBcIiBjb25mZXJlbmNlIEklMjd2ZSBqdXN0IHNldCB1cC4lMEQlMEElMEQlMEFcIiArXG4gICAgICAgIFwiUGxlYXNlIGNsaWNrIG9uIHRoZSBmb2xsb3dpbmcgbGluayBpbiBvcmRlclwiICtcbiAgICAgICAgXCIgdG8gam9pbiB0aGUgY29uZmVyZW5jZS4lMEQlMEElMEQlMEFcIiArXG4gICAgICAgIHJvb21VcmwgK1xuICAgICAgICBcIiUwRCUwQSUwRCUwQVwiICtcbiAgICAgICAgc2hhcmVkS2V5VGV4dCArXG4gICAgICAgIFwiTm90ZSB0aGF0IFwiICsgaW50ZXJmYWNlQ29uZmlnLkFQUF9OQU1FICsgXCIgaXMgY3VycmVudGx5XCIgK1xuICAgICAgICBcIiBvbmx5IHN1cHBvcnRlZCBieSBDaHJvbWl1bSxcIiArXG4gICAgICAgIFwiIEdvb2dsZSBDaHJvbWUgYW5kIE9wZXJhLCBzbyB5b3UgbmVlZFwiICtcbiAgICAgICAgXCIgdG8gYmUgdXNpbmcgb25lIG9mIHRoZXNlIGJyb3dzZXJzLiUwRCUwQSUwRCUwQVwiICtcbiAgICAgICAgXCJUYWxrIHRvIHlvdSBpbiBhIHNlYyFcIjtcblxuICAgIGlmICh3aW5kb3cubG9jYWxTdG9yYWdlLmRpc3BsYXluYW1lKSB7XG4gICAgICAgIGJvZHkgKz0gXCIlMEQlMEElMEQlMEFcIiArIHdpbmRvdy5sb2NhbFN0b3JhZ2UuZGlzcGxheW5hbWU7XG4gICAgfVxuXG4gICAgaWYgKGludGVyZmFjZUNvbmZpZy5JTlZJVEFUSU9OX1BPV0VSRURfQlkpIHtcbiAgICAgICAgYm9keSArPSBcIiUwRCUwQSUwRCUwQS0tJTBEJTBBcG93ZXJlZCBieSBqaXRzaS5vcmdcIjtcbiAgICB9XG5cbiAgICB3aW5kb3cub3BlbihcIm1haWx0bzo/c3ViamVjdD1cIiArIHN1YmplY3QgKyBcIiZib2R5PVwiICsgYm9keSwgJ19ibGFuaycpO1xufVxuXG52YXIgVG9vbGJhciA9IChmdW5jdGlvbiAobXkpIHtcblxuICAgIG15LmluaXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGZvcih2YXIgayBpbiBidXR0b25IYW5kbGVycylcbiAgICAgICAgICAgICQoXCIjXCIgKyBrKS5jbGljayhidXR0b25IYW5kbGVyc1trXSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0cyBzaGFyZWQga2V5XG4gICAgICogQHBhcmFtIHNLZXkgdGhlIHNoYXJlZCBrZXlcbiAgICAgKi9cbiAgICBteS5zZXRTaGFyZWRLZXkgPSBmdW5jdGlvbiAoc0tleSkge1xuICAgICAgICBzaGFyZWRLZXkgPSBzS2V5O1xuICAgIH07XG5cbiAgICBteS5jbG9zZUF1dGhlbnRpY2F0aW9uV2luZG93ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoYXV0aGVudGljYXRpb25XaW5kb3cpIHtcbiAgICAgICAgICAgIGF1dGhlbnRpY2F0aW9uV2luZG93LmNsb3NlKCk7XG4gICAgICAgICAgICBhdXRoZW50aWNhdGlvbldpbmRvdyA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBteS5hdXRoZW50aWNhdGVDbGlja2VkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBHZXQgYXV0aGVudGljYXRpb24gVVJMXG4gICAgICAgIE1vZGVyYXRvci5nZXRBdXRoVXJsKGZ1bmN0aW9uICh1cmwpIHtcbiAgICAgICAgICAgIC8vIE9wZW4gcG9wdXAgd2l0aCBhdXRoZW50aWNhdGlvbiBVUkxcbiAgICAgICAgICAgIGF1dGhlbnRpY2F0aW9uV2luZG93ID0gbWVzc2FnZUhhbmRsZXIub3BlbkNlbnRlcmVkUG9wdXAoXG4gICAgICAgICAgICAgICAgdXJsLCA1MDAsIDQwMCxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIE9uIHBvcHVwIGNsb3NlZCAtIHJldHJ5IHJvb20gYWxsb2NhdGlvblxuICAgICAgICAgICAgICAgICAgICBNb2RlcmF0b3IuYWxsb2NhdGVDb25mZXJlbmNlRm9jdXMoXG4gICAgICAgICAgICAgICAgICAgICAgICByb29tTmFtZSwgZG9Kb2luQWZ0ZXJGb2N1cyk7XG4gICAgICAgICAgICAgICAgICAgIGF1dGhlbnRpY2F0aW9uV2luZG93ID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmICghYXV0aGVudGljYXRpb25XaW5kb3cpIHtcbiAgICAgICAgICAgICAgICBUb29sYmFyLnNob3dBdXRoZW50aWNhdGVCdXR0b24odHJ1ZSk7XG4gICAgICAgICAgICAgICAgbWVzc2FnZUhhbmRsZXIub3Blbk1lc3NhZ2VEaWFsb2coXG4gICAgICAgICAgICAgICAgICAgIG51bGwsIFwiWW91ciBicm93c2VyIGlzIGJsb2NraW5nIHBvcHVwIHdpbmRvd3MgZnJvbSB0aGlzIHNpdGUuXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCIgUGxlYXNlIGVuYWJsZSBwb3B1cHMgaW4geW91ciBicm93c2VyIHNlY3VyaXR5IHNldHRpbmdzXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCIgYW5kIHRyeSBhZ2Fpbi5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSByb29tIGludml0ZSB1cmwuXG4gICAgICovXG4gICAgbXkudXBkYXRlUm9vbVVybCA9IGZ1bmN0aW9uIChuZXdSb29tVXJsKSB7XG4gICAgICAgIHJvb21VcmwgPSBuZXdSb29tVXJsO1xuXG4gICAgICAgIC8vIElmIHRoZSBpbnZpdGUgZGlhbG9nIGhhcyBiZWVuIGFscmVhZHkgb3BlbmVkIHdlIHVwZGF0ZSB0aGUgaW5mb3JtYXRpb24uXG4gICAgICAgIHZhciBpbnZpdGVMaW5rID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2ludml0ZUxpbmtSZWYnKTtcbiAgICAgICAgaWYgKGludml0ZUxpbmspIHtcbiAgICAgICAgICAgIGludml0ZUxpbmsudmFsdWUgPSByb29tVXJsO1xuICAgICAgICAgICAgaW52aXRlTGluay5zZWxlY3QoKTtcbiAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdqcWlfc3RhdGUwX2J1dHRvbkludml0ZScpLmRpc2FibGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEaXNhYmxlcyBhbmQgZW5hYmxlcyBzb21lIG9mIHRoZSBidXR0b25zLlxuICAgICAqL1xuICAgIG15LnNldHVwQnV0dG9uc0Zyb21Db25maWcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmIChjb25maWcuZGlzYWJsZVByZXppKVxuICAgICAgICB7XG4gICAgICAgICAgICAkKFwiI3ByZXppX2J1dHRvblwiKS5jc3Moe2Rpc3BsYXk6IFwibm9uZVwifSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogT3BlbnMgdGhlIGxvY2sgcm9vbSBkaWFsb2cuXG4gICAgICovXG4gICAgbXkub3BlbkxvY2tEaWFsb2cgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIE9ubHkgdGhlIGZvY3VzIGlzIGFibGUgdG8gc2V0IGEgc2hhcmVkIGtleS5cbiAgICAgICAgaWYgKCFNb2RlcmF0b3IuaXNNb2RlcmF0b3IoKSkge1xuICAgICAgICAgICAgaWYgKHNoYXJlZEtleSkge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5NZXNzYWdlRGlhbG9nKG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICBcIlRoaXMgY29udmVyc2F0aW9uIGlzIGN1cnJlbnRseSBwcm90ZWN0ZWQgYnlcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiBhIHBhc3N3b3JkLiBPbmx5IHRoZSBvd25lciBvZiB0aGUgY29uZmVyZW5jZVwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiIGNvdWxkIHNldCBhIHBhc3N3b3JkLlwiLFxuICAgICAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgXCJQYXNzd29yZFwiKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZUhhbmRsZXIub3Blbk1lc3NhZ2VEaWFsb2cobnVsbCxcbiAgICAgICAgICAgICAgICAgICAgXCJUaGlzIGNvbnZlcnNhdGlvbiBpc24ndCBjdXJyZW50bHkgcHJvdGVjdGVkIGJ5XCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCIgYSBwYXNzd29yZC4gT25seSB0aGUgb3duZXIgb2YgdGhlIGNvbmZlcmVuY2VcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiBjb3VsZCBzZXQgYSBwYXNzd29yZC5cIixcbiAgICAgICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIFwiUGFzc3dvcmRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoc2hhcmVkS2V5KSB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZUhhbmRsZXIub3BlblR3b0J1dHRvbkRpYWxvZyhudWxsLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB5b3Ugc3VyZSB5b3Ugd291bGQgbGlrZSB0byByZW1vdmUgeW91ciBwYXNzd29yZD9cIixcbiAgICAgICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIFwiUmVtb3ZlXCIsXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChlLCB2KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRvb2xiYXIuc2V0U2hhcmVkS2V5KCcnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NrUm9vbShmYWxzZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKG51bGwsXG4gICAgICAgICAgICAgICAgICAgICc8aDI+U2V0IGEgcGFzc3dvcmQgdG8gbG9jayB5b3VyIHJvb208L2gyPicgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJzxpbnB1dCBpZD1cImxvY2tLZXlcIiB0eXBlPVwidGV4dFwiJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAncGxhY2Vob2xkZXI9XCJ5b3VyIHBhc3N3b3JkXCIgYXV0b2ZvY3VzPicsXG4gICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBcIlNhdmVcIixcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGUsIHYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxvY2tLZXkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9ja0tleScpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGxvY2tLZXkudmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVG9vbGJhci5zZXRTaGFyZWRLZXkoVXRpbC5lc2NhcGVIdG1sKGxvY2tLZXkudmFsdWUpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9ja1Jvb20odHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9ja0tleScpLmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIE9wZW5zIHRoZSBpbnZpdGUgbGluayBkaWFsb2cuXG4gICAgICovXG4gICAgbXkub3BlbkxpbmtEaWFsb2cgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpbnZpdGVMaW5rO1xuICAgICAgICBpZiAocm9vbVVybCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgaW52aXRlTGluayA9IFwiWW91ciBjb25mZXJlbmNlIGlzIGN1cnJlbnRseSBiZWluZyBjcmVhdGVkLi4uXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpbnZpdGVMaW5rID0gZW5jb2RlVVJJKHJvb21VcmwpO1xuICAgICAgICB9XG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2coXG4gICAgICAgICAgICBcIlNoYXJlIHRoaXMgbGluayB3aXRoIGV2ZXJ5b25lIHlvdSB3YW50IHRvIGludml0ZVwiLFxuICAgICAgICAgICAgJzxpbnB1dCBpZD1cImludml0ZUxpbmtSZWZcIiB0eXBlPVwidGV4dFwiIHZhbHVlPVwiJyArXG4gICAgICAgICAgICAgICAgaW52aXRlTGluayArICdcIiBvbmNsaWNrPVwidGhpcy5zZWxlY3QoKTtcIiByZWFkb25seT4nLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBcIkludml0ZVwiLFxuICAgICAgICAgICAgZnVuY3Rpb24gKGUsIHYpIHtcbiAgICAgICAgICAgICAgICBpZiAodikge1xuICAgICAgICAgICAgICAgICAgICBpZiAocm9vbVVybCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW52aXRlUGFydGljaXBhbnRzKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGlmIChyb29tVXJsKSB7XG4gICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdpbnZpdGVMaW5rUmVmJykuc2VsZWN0KCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2pxaV9zdGF0ZTBfYnV0dG9uSW52aXRlJylcbiAgICAgICAgICAgICAgICAgICAgICAgIC5kaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPcGVucyB0aGUgc2V0dGluZ3MgZGlhbG9nLlxuICAgICAqL1xuICAgIG15Lm9wZW5TZXR0aW5nc0RpYWxvZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbWVzc2FnZUhhbmRsZXIub3BlblR3b0J1dHRvbkRpYWxvZyhcbiAgICAgICAgICAgICc8aDI+Q29uZmlndXJlIHlvdXIgY29uZmVyZW5jZTwvaDI+JyArXG4gICAgICAgICAgICAgICAgJzxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBpZD1cImluaXRNdXRlZFwiPicgK1xuICAgICAgICAgICAgICAgICdQYXJ0aWNpcGFudHMgam9pbiBtdXRlZDxici8+JyArXG4gICAgICAgICAgICAgICAgJzxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBpZD1cInJlcXVpcmVOaWNrbmFtZXNcIj4nICtcbiAgICAgICAgICAgICAgICAnUmVxdWlyZSBuaWNrbmFtZXM8YnIvPjxici8+JyArXG4gICAgICAgICAgICAgICAgJ1NldCBhIHBhc3N3b3JkIHRvIGxvY2sgeW91ciByb29tOicgK1xuICAgICAgICAgICAgICAgICc8aW5wdXQgaWQ9XCJsb2NrS2V5XCIgdHlwZT1cInRleHRcIiBwbGFjZWhvbGRlcj1cInlvdXIgcGFzc3dvcmRcIicgK1xuICAgICAgICAgICAgICAgICdhdXRvZm9jdXM+JyxcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgIFwiU2F2ZVwiLFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NrS2V5JykuZm9jdXMoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoZSwgdikge1xuICAgICAgICAgICAgICAgIGlmICh2KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICgkKCcjaW5pdE11dGVkJykuaXMoXCI6Y2hlY2tlZFwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXQgaXMgY2hlY2tlZFxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCQoJyNyZXF1aXJlTmlja25hbWVzJykuaXMoXCI6Y2hlY2tlZFwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXQgaXMgY2hlY2tlZFxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8qXG4gICAgICAgICAgICAgICAgICAgIHZhciBsb2NrS2V5ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xvY2tLZXknKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobG9ja0tleS52YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2V0U2hhcmVkS2V5KGxvY2tLZXkudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbG9ja1Jvb20odHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFRvZ2dsZXMgdGhlIGFwcGxpY2F0aW9uIGluIGFuZCBvdXQgb2YgZnVsbCBzY3JlZW4gbW9kZVxuICAgICAqIChhLmsuYS4gcHJlc2VudGF0aW9uIG1vZGUgaW4gQ2hyb21lKS5cbiAgICAgKi9cbiAgICBteS50b2dnbGVGdWxsU2NyZWVuID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZnNFbGVtZW50ID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50O1xuXG4gICAgICAgIGlmICghZG9jdW1lbnQubW96RnVsbFNjcmVlbiAmJiAhZG9jdW1lbnQud2Via2l0SXNGdWxsU2NyZWVuKSB7XG4gICAgICAgICAgICAvL0VudGVyIEZ1bGwgU2NyZWVuXG4gICAgICAgICAgICBpZiAoZnNFbGVtZW50Lm1velJlcXVlc3RGdWxsU2NyZWVuKSB7XG4gICAgICAgICAgICAgICAgZnNFbGVtZW50Lm1velJlcXVlc3RGdWxsU2NyZWVuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBmc0VsZW1lbnQud2Via2l0UmVxdWVzdEZ1bGxTY3JlZW4oRWxlbWVudC5BTExPV19LRVlCT0FSRF9JTlBVVCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvL0V4aXQgRnVsbCBTY3JlZW5cbiAgICAgICAgICAgIGlmIChkb2N1bWVudC5tb3pDYW5jZWxGdWxsU2NyZWVuKSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQubW96Q2FuY2VsRnVsbFNjcmVlbigpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC53ZWJraXRDYW5jZWxGdWxsU2NyZWVuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFVubG9ja3MgdGhlIGxvY2sgYnV0dG9uIHN0YXRlLlxuICAgICAqL1xuICAgIG15LnVubG9ja0xvY2tCdXR0b24gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICgkKFwiI2xvY2tJY29uXCIpLmhhc0NsYXNzKFwiaWNvbi1zZWN1cml0eS1sb2NrZWRcIikpXG4gICAgICAgICAgICBidXR0b25DbGljayhcIiNsb2NrSWNvblwiLCBcImljb24tc2VjdXJpdHkgaWNvbi1zZWN1cml0eS1sb2NrZWRcIik7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBsb2NrIGJ1dHRvbiBzdGF0ZSB0byBsb2NrZWQuXG4gICAgICovXG4gICAgbXkubG9ja0xvY2tCdXR0b24gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICgkKFwiI2xvY2tJY29uXCIpLmhhc0NsYXNzKFwiaWNvbi1zZWN1cml0eVwiKSlcbiAgICAgICAgICAgIGJ1dHRvbkNsaWNrKFwiI2xvY2tJY29uXCIsIFwiaWNvbi1zZWN1cml0eSBpY29uLXNlY3VyaXR5LWxvY2tlZFwiKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2hvd3Mgb3IgaGlkZXMgYXV0aGVudGljYXRpb24gYnV0dG9uXG4gICAgICogQHBhcmFtIHNob3cgPHR0PnRydWU8L3R0PiB0byBzaG93IG9yIDx0dD5mYWxzZTwvdHQ+IHRvIGhpZGVcbiAgICAgKi9cbiAgICBteS5zaG93QXV0aGVudGljYXRlQnV0dG9uID0gZnVuY3Rpb24gKHNob3cpIHtcbiAgICAgICAgaWYgKHNob3cpIHtcbiAgICAgICAgICAgICQoJyNhdXRoZW50aWNhdGlvbicpLmNzcyh7ZGlzcGxheTogXCJpbmxpbmVcIn0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgJCgnI2F1dGhlbnRpY2F0aW9uJykuY3NzKHtkaXNwbGF5OiBcIm5vbmVcIn0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8vIFNob3dzIG9yIGhpZGVzIHRoZSAncmVjb3JkaW5nJyBidXR0b24uXG4gICAgbXkuc2hvd1JlY29yZGluZ0J1dHRvbiA9IGZ1bmN0aW9uIChzaG93KSB7XG4gICAgICAgIGlmICghY29uZmlnLmVuYWJsZVJlY29yZGluZykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHNob3cpIHtcbiAgICAgICAgICAgICQoJyNyZWNvcmRpbmcnKS5jc3Moe2Rpc3BsYXk6IFwiaW5saW5lXCJ9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICQoJyNyZWNvcmRpbmcnKS5jc3Moe2Rpc3BsYXk6IFwibm9uZVwifSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gU2V0cyB0aGUgc3RhdGUgb2YgdGhlIHJlY29yZGluZyBidXR0b25cbiAgICBteS5zZXRSZWNvcmRpbmdCdXR0b25TdGF0ZSA9IGZ1bmN0aW9uIChpc1JlY29yZGluZykge1xuICAgICAgICBpZiAoaXNSZWNvcmRpbmcpIHtcbiAgICAgICAgICAgICQoJyNyZWNvcmRCdXR0b24nKS5yZW1vdmVDbGFzcyhcImljb24tcmVjRW5hYmxlXCIpO1xuICAgICAgICAgICAgJCgnI3JlY29yZEJ1dHRvbicpLmFkZENsYXNzKFwiaWNvbi1yZWNFbmFibGUgYWN0aXZlXCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgJCgnI3JlY29yZEJ1dHRvbicpLnJlbW92ZUNsYXNzKFwiaWNvbi1yZWNFbmFibGUgYWN0aXZlXCIpO1xuICAgICAgICAgICAgJCgnI3JlY29yZEJ1dHRvbicpLmFkZENsYXNzKFwiaWNvbi1yZWNFbmFibGVcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gU2hvd3Mgb3IgaGlkZXMgU0lQIGNhbGxzIGJ1dHRvblxuICAgIG15LnNob3dTaXBDYWxsQnV0dG9uID0gZnVuY3Rpb24gKHNob3cpIHtcbiAgICAgICAgaWYgKGNvbmZpZy5ob3N0cy5jYWxsX2NvbnRyb2wgJiYgc2hvdykge1xuICAgICAgICAgICAgJCgnI3NpcENhbGxCdXR0b24nKS5jc3Moe2Rpc3BsYXk6IFwiaW5saW5lXCJ9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICQoJyNzaXBDYWxsQnV0dG9uJykuY3NzKHtkaXNwbGF5OiBcIm5vbmVcIn0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIHN0YXRlIG9mIHRoZSBidXR0b24uIFRoZSBidXR0b24gaGFzIGJsdWUgZ2xvdyBpZiBkZXNrdG9wXG4gICAgICogc3RyZWFtaW5nIGlzIGFjdGl2ZS5cbiAgICAgKiBAcGFyYW0gYWN0aXZlIHRoZSBzdGF0ZSBvZiB0aGUgZGVza3RvcCBzdHJlYW1pbmcuXG4gICAgICovXG4gICAgbXkuY2hhbmdlRGVza3RvcFNoYXJpbmdCdXR0b25TdGF0ZSA9IGZ1bmN0aW9uIChhY3RpdmUpIHtcbiAgICAgICAgdmFyIGJ1dHRvbiA9ICQoXCIjZGVza3RvcHNoYXJpbmcgPiBhXCIpO1xuICAgICAgICBpZiAoYWN0aXZlKVxuICAgICAgICB7XG4gICAgICAgICAgICBidXR0b24uYWRkQ2xhc3MoXCJnbG93XCIpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgYnV0dG9uLnJlbW92ZUNsYXNzKFwiZ2xvd1wiKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICByZXR1cm4gbXk7XG59KFRvb2xiYXIgfHwge30pKTtcblxubW9kdWxlLmV4cG9ydHMgPSBUb29sYmFyOyIsInZhciBKaXRzaVBvcG92ZXIgPSAoZnVuY3Rpb24gKCkge1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdHMgbmV3IEppdHNpUG9wb3ZlciBhbmQgYXR0YWNoZXMgaXQgdG8gdGhlIGVsZW1lbnRcbiAgICAgKiBAcGFyYW0gZWxlbWVudCBqcXVlcnkgc2VsZWN0b3JcbiAgICAgKiBAcGFyYW0gb3B0aW9ucyB0aGUgb3B0aW9ucyBmb3IgdGhlIHBvcG92ZXIuXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICovXG4gICAgZnVuY3Rpb24gSml0c2lQb3BvdmVyKGVsZW1lbnQsIG9wdGlvbnMpXG4gICAge1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICAgICAgICBza2luOiBcIndoaXRlXCIsXG4gICAgICAgICAgICBjb250ZW50OiBcIlwiXG4gICAgICAgIH07XG4gICAgICAgIGlmKG9wdGlvbnMpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGlmKG9wdGlvbnMuc2tpbilcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMuc2tpbiA9IG9wdGlvbnMuc2tpbjtcblxuICAgICAgICAgICAgaWYob3B0aW9ucy5jb250ZW50KVxuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5jb250ZW50ID0gb3B0aW9ucy5jb250ZW50O1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lbGVtZW50SXNIb3ZlcmVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMucG9wb3ZlcklzSG92ZXJlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLnBvcG92ZXJTaG93biA9IGZhbHNlO1xuXG4gICAgICAgIGVsZW1lbnQuZGF0YShcImppdHNpX3BvcG92ZXJcIiwgdGhpcyk7XG4gICAgICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgIHRoaXMudGVtcGxhdGUgPSAnIDxkaXYgY2xhc3M9XCJqaXRzaXBvcG92ZXIgJyArIHRoaXMub3B0aW9ucy5za2luICtcbiAgICAgICAgICAgICdcIj48ZGl2IGNsYXNzPVwiYXJyb3dcIj48L2Rpdj48ZGl2IGNsYXNzPVwiaml0c2lwb3BvdmVyLWNvbnRlbnRcIj48L2Rpdj4nICtcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiaml0c2lQb3B1cG1lbnVQYWRkaW5nXCI+PC9kaXY+PC9kaXY+JztcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB0aGlzLmVsZW1lbnQub24oXCJtb3VzZWVudGVyXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbGYuZWxlbWVudElzSG92ZXJlZCA9IHRydWU7XG4gICAgICAgICAgICBzZWxmLnNob3coKTtcbiAgICAgICAgfSkub24oXCJtb3VzZWxlYXZlXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbGYuZWxlbWVudElzSG92ZXJlZCA9IGZhbHNlO1xuICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgc2VsZi5oaWRlKCk7XG4gICAgICAgICAgICB9LCAxMCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3dzIHRoZSBwb3BvdmVyXG4gICAgICovXG4gICAgSml0c2lQb3BvdmVyLnByb3RvdHlwZS5zaG93ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmNyZWF0ZVBvcG92ZXIoKTtcbiAgICAgICAgdGhpcy5wb3BvdmVyU2hvd24gPSB0cnVlO1xuXG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEhpZGVzIHRoZSBwb3BvdmVyXG4gICAgICovXG4gICAgSml0c2lQb3BvdmVyLnByb3RvdHlwZS5oaWRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZighdGhpcy5lbGVtZW50SXNIb3ZlcmVkICYmICF0aGlzLnBvcG92ZXJJc0hvdmVyZWQgJiYgdGhpcy5wb3BvdmVyU2hvd24pXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMuZm9yY2VIaWRlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSGlkZXMgdGhlIHBvcG92ZXJcbiAgICAgKi9cbiAgICBKaXRzaVBvcG92ZXIucHJvdG90eXBlLmZvcmNlSGlkZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJChcIi5qaXRzaXBvcG92ZXJcIikucmVtb3ZlKCk7XG4gICAgICAgIHRoaXMucG9wb3ZlclNob3duID0gZmFsc2U7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgdGhlIHBvcG92ZXIgaHRtbFxuICAgICAqL1xuICAgIEppdHNpUG9wb3Zlci5wcm90b3R5cGUuY3JlYXRlUG9wb3ZlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJChcImJvZHlcIikuYXBwZW5kKHRoaXMudGVtcGxhdGUpO1xuICAgICAgICAkKFwiLmppdHNpcG9wb3ZlciA+IC5qaXRzaXBvcG92ZXItY29udGVudFwiKS5odG1sKHRoaXMub3B0aW9ucy5jb250ZW50KTtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAkKFwiLmppdHNpcG9wb3ZlclwiKS5vbihcIm1vdXNlZW50ZXJcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi5wb3BvdmVySXNIb3ZlcmVkID0gdHJ1ZTtcbiAgICAgICAgfSkub24oXCJtb3VzZWxlYXZlXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbGYucG9wb3ZlcklzSG92ZXJlZCA9IGZhbHNlO1xuICAgICAgICAgICAgc2VsZi5oaWRlKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMucmVmcmVzaFBvc2l0aW9uKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlZnJlc2hlcyB0aGUgcG9zaXRpb24gb2YgdGhlIHBvcG92ZXJcbiAgICAgKi9cbiAgICBKaXRzaVBvcG92ZXIucHJvdG90eXBlLnJlZnJlc2hQb3NpdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJChcIi5qaXRzaXBvcG92ZXJcIikucG9zaXRpb24oe1xuICAgICAgICAgICAgbXk6IFwiYm90dG9tXCIsXG4gICAgICAgICAgICBhdDogXCJ0b3BcIixcbiAgICAgICAgICAgIGNvbGxpc2lvbjogXCJmaXRcIixcbiAgICAgICAgICAgIG9mOiB0aGlzLmVsZW1lbnQsXG4gICAgICAgICAgICB1c2luZzogZnVuY3Rpb24gKHBvc2l0aW9uLCBlbGVtZW50cykge1xuICAgICAgICAgICAgICAgIHZhciBjYWxjTGVmdCA9IGVsZW1lbnRzLnRhcmdldC5sZWZ0IC0gZWxlbWVudHMuZWxlbWVudC5sZWZ0ICsgZWxlbWVudHMudGFyZ2V0LndpZHRoLzI7XG4gICAgICAgICAgICAgICAgJChcIi5qaXRzaXBvcG92ZXJcIikuY3NzKHt0b3A6IHBvc2l0aW9uLnRvcCwgbGVmdDogcG9zaXRpb24ubGVmdCwgZGlzcGxheTogXCJ0YWJsZVwifSk7XG4gICAgICAgICAgICAgICAgJChcIi5qaXRzaXBvcG92ZXIgPiAuYXJyb3dcIikuY3NzKHtsZWZ0OiBjYWxjTGVmdH0pO1xuICAgICAgICAgICAgICAgICQoXCIuaml0c2lwb3BvdmVyID4gLmppdHNpUG9wdXBtZW51UGFkZGluZ1wiKS5jc3Moe2xlZnQ6IGNhbGNMZWZ0IC0gNTB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIGNvbnRlbnQgb2YgcG9wb3Zlci5cbiAgICAgKiBAcGFyYW0gY29udGVudCBuZXcgY29udGVudFxuICAgICAqL1xuICAgIEppdHNpUG9wb3Zlci5wcm90b3R5cGUudXBkYXRlQ29udGVudCA9IGZ1bmN0aW9uIChjb250ZW50KSB7XG4gICAgICAgIHRoaXMub3B0aW9ucy5jb250ZW50ID0gY29udGVudDtcbiAgICAgICAgaWYoIXRoaXMucG9wb3ZlclNob3duKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAkKFwiLmppdHNpcG9wb3ZlclwiKS5yZW1vdmUoKTtcbiAgICAgICAgdGhpcy5jcmVhdGVQb3BvdmVyKCk7XG4gICAgfTtcblxuICAgIHJldHVybiBKaXRzaVBvcG92ZXI7XG5cblxufSkoKTtcblxubW9kdWxlLmV4cG9ydHMgPSBKaXRzaVBvcG92ZXI7IiwidmFyIG1lc3NhZ2VIYW5kbGVyID0gKGZ1bmN0aW9uKG15KSB7XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyBhIG1lc3NhZ2UgdG8gdGhlIHVzZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdGl0bGVTdHJpbmcgdGhlIHRpdGxlIG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIG1lc3NhZ2VTdHJpbmcgdGhlIHRleHQgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKi9cbiAgICBteS5vcGVuTWVzc2FnZURpYWxvZyA9IGZ1bmN0aW9uKHRpdGxlU3RyaW5nLCBtZXNzYWdlU3RyaW5nKSB7XG4gICAgICAgICQucHJvbXB0KG1lc3NhZ2VTdHJpbmcsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdGl0bGU6IHRpdGxlU3RyaW5nLFxuICAgICAgICAgICAgICAgIHBlcnNpc3RlbnQ6IGZhbHNlXG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgbWVzc2FnZSB0byB0aGUgdXNlciB3aXRoIHR3byBidXR0b25zOiBmaXJzdCBpcyBnaXZlbiBhcyBhIHBhcmFtZXRlciBhbmQgdGhlIHNlY29uZCBpcyBDYW5jZWwuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdGl0bGVTdHJpbmcgdGhlIHRpdGxlIG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIG1zZ1N0cmluZyB0aGUgdGV4dCBvZiB0aGUgbWVzc2FnZVxuICAgICAqIEBwYXJhbSBwZXJzaXN0ZW50IGJvb2xlYW4gdmFsdWUgd2hpY2ggZGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBtZXNzYWdlIGlzIHBlcnNpc3RlbnQgb3Igbm90XG4gICAgICogQHBhcmFtIGxlZnRCdXR0b24gdGhlIGZpc3QgYnV0dG9uJ3MgdGV4dFxuICAgICAqIEBwYXJhbSBzdWJtaXRGdW5jdGlvbiBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb24gc3VibWl0XG4gICAgICogQHBhcmFtIGxvYWRlZEZ1bmN0aW9uIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgcHJvbXB0IGlzIGZ1bGx5IGxvYWRlZFxuICAgICAqIEBwYXJhbSBjbG9zZUZ1bmN0aW9uIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgcHJvbXB0IGlzIGNsb3NlZFxuICAgICAqL1xuICAgIG15Lm9wZW5Ud29CdXR0b25EaWFsb2cgPSBmdW5jdGlvbih0aXRsZVN0cmluZywgbXNnU3RyaW5nLCBwZXJzaXN0ZW50LCBsZWZ0QnV0dG9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJtaXRGdW5jdGlvbiwgbG9hZGVkRnVuY3Rpb24sIGNsb3NlRnVuY3Rpb24pIHtcbiAgICAgICAgdmFyIGJ1dHRvbnMgPSB7fTtcbiAgICAgICAgYnV0dG9uc1tsZWZ0QnV0dG9uXSA9IHRydWU7XG4gICAgICAgIGJ1dHRvbnMuQ2FuY2VsID0gZmFsc2U7XG4gICAgICAgICQucHJvbXB0KG1zZ1N0cmluZywge1xuICAgICAgICAgICAgdGl0bGU6IHRpdGxlU3RyaW5nLFxuICAgICAgICAgICAgcGVyc2lzdGVudDogZmFsc2UsXG4gICAgICAgICAgICBidXR0b25zOiBidXR0b25zLFxuICAgICAgICAgICAgZGVmYXVsdEJ1dHRvbjogMSxcbiAgICAgICAgICAgIGxvYWRlZDogbG9hZGVkRnVuY3Rpb24sXG4gICAgICAgICAgICBzdWJtaXQ6IHN1Ym1pdEZ1bmN0aW9uLFxuICAgICAgICAgICAgY2xvc2U6IGNsb3NlRnVuY3Rpb25cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgbWVzc2FnZSB0byB0aGUgdXNlciB3aXRoIHR3byBidXR0b25zOiBmaXJzdCBpcyBnaXZlbiBhcyBhIHBhcmFtZXRlciBhbmQgdGhlIHNlY29uZCBpcyBDYW5jZWwuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdGl0bGVTdHJpbmcgdGhlIHRpdGxlIG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIG1zZ1N0cmluZyB0aGUgdGV4dCBvZiB0aGUgbWVzc2FnZVxuICAgICAqIEBwYXJhbSBwZXJzaXN0ZW50IGJvb2xlYW4gdmFsdWUgd2hpY2ggZGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBtZXNzYWdlIGlzIHBlcnNpc3RlbnQgb3Igbm90XG4gICAgICogQHBhcmFtIGJ1dHRvbnMgb2JqZWN0IHdpdGggdGhlIGJ1dHRvbnMuIFRoZSBrZXlzIG11c3QgYmUgdGhlIG5hbWUgb2YgdGhlIGJ1dHRvbiBhbmQgdmFsdWUgaXMgdGhlIHZhbHVlXG4gICAgICogdGhhdCB3aWxsIGJlIHBhc3NlZCB0byBzdWJtaXRGdW5jdGlvblxuICAgICAqIEBwYXJhbSBzdWJtaXRGdW5jdGlvbiBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb24gc3VibWl0XG4gICAgICogQHBhcmFtIGxvYWRlZEZ1bmN0aW9uIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgcHJvbXB0IGlzIGZ1bGx5IGxvYWRlZFxuICAgICAqL1xuICAgIG15Lm9wZW5EaWFsb2cgPSBmdW5jdGlvbih0aXRsZVN0cmluZywgbXNnU3RyaW5nLCBwZXJzaXN0ZW50LCBidXR0b25zLCBzdWJtaXRGdW5jdGlvbiwgbG9hZGVkRnVuY3Rpb24pIHtcbiAgICAgICAgJC5wcm9tcHQobXNnU3RyaW5nLCB7XG4gICAgICAgICAgICB0aXRsZTogdGl0bGVTdHJpbmcsXG4gICAgICAgICAgICBwZXJzaXN0ZW50OiBmYWxzZSxcbiAgICAgICAgICAgIGJ1dHRvbnM6IGJ1dHRvbnMsXG4gICAgICAgICAgICBkZWZhdWx0QnV0dG9uOiAxLFxuICAgICAgICAgICAgbG9hZGVkOiBsb2FkZWRGdW5jdGlvbixcbiAgICAgICAgICAgIHN1Ym1pdDogc3VibWl0RnVuY3Rpb25cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgZGlhbG9nIHdpdGggZGlmZmVyZW50IHN0YXRlcyB0byB0aGUgdXNlci5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBzdGF0ZXNPYmplY3Qgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBzdGF0ZXMgb2YgdGhlIGRpYWxvZ1xuICAgICAqIEBwYXJhbSBsb2FkZWRGdW5jdGlvbiBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYWZ0ZXIgdGhlIHByb21wdCBpcyBmdWxseSBsb2FkZWRcbiAgICAgKiBAcGFyYW0gc3RhdGVDaGFuZ2VkRnVuY3Rpb24gZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIHN0YXRlIG9mIHRoZSBkaWFsb2cgaXMgY2hhbmdlZFxuICAgICAqL1xuICAgIG15Lm9wZW5EaWFsb2dXaXRoU3RhdGVzID0gZnVuY3Rpb24oc3RhdGVzT2JqZWN0LCBsb2FkZWRGdW5jdGlvbiwgc3RhdGVDaGFuZ2VkRnVuY3Rpb24pIHtcblxuXG4gICAgICAgIHZhciBteVByb21wdCA9ICQucHJvbXB0KHN0YXRlc09iamVjdCk7XG5cbiAgICAgICAgbXlQcm9tcHQub24oJ2ltcHJvbXB0dTpsb2FkZWQnLCBsb2FkZWRGdW5jdGlvbik7XG4gICAgICAgIG15UHJvbXB0Lm9uKCdpbXByb21wdHU6c3RhdGVjaGFuZ2VkJywgc3RhdGVDaGFuZ2VkRnVuY3Rpb24pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPcGVucyBuZXcgcG9wdXAgd2luZG93IGZvciBnaXZlbiA8dHQ+dXJsPC90dD4gY2VudGVyZWQgb3ZlciBjdXJyZW50XG4gICAgICogd2luZG93LlxuICAgICAqXG4gICAgICogQHBhcmFtIHVybCB0aGUgVVJMIHRvIGJlIGRpc3BsYXllZCBpbiB0aGUgcG9wdXAgd2luZG93XG4gICAgICogQHBhcmFtIHcgdGhlIHdpZHRoIG9mIHRoZSBwb3B1cCB3aW5kb3dcbiAgICAgKiBAcGFyYW0gaCB0aGUgaGVpZ2h0IG9mIHRoZSBwb3B1cCB3aW5kb3dcbiAgICAgKiBAcGFyYW0gb25Qb3B1cENsb3NlZCBvcHRpb25hbCBjYWxsYmFjayBmdW5jdGlvbiBjYWxsZWQgd2hlbiBwb3B1cCB3aW5kb3dcbiAgICAgKiAgICAgICAgaGFzIGJlZW4gY2xvc2VkLlxuICAgICAqXG4gICAgICogQHJldHVybnMgcG9wdXAgd2luZG93IG9iamVjdCBpZiBvcGVuZWQgc3VjY2Vzc2Z1bGx5IG9yIHVuZGVmaW5lZFxuICAgICAqICAgICAgICAgIGluIGNhc2Ugd2UgZmFpbGVkIHRvIG9wZW4gaXQocG9wdXAgYmxvY2tlZClcbiAgICAgKi9cbiAgICBteS5vcGVuQ2VudGVyZWRQb3B1cCA9IGZ1bmN0aW9uICh1cmwsIHcsIGgsIG9uUG9wdXBDbG9zZWQpIHtcbiAgICAgICAgdmFyIGwgPSB3aW5kb3cuc2NyZWVuWCArICh3aW5kb3cuaW5uZXJXaWR0aCAvIDIpIC0gKHcgLyAyKTtcbiAgICAgICAgdmFyIHQgPSB3aW5kb3cuc2NyZWVuWSArICh3aW5kb3cuaW5uZXJIZWlnaHQgLyAyKSAtIChoIC8gMik7XG4gICAgICAgIHZhciBwb3B1cCA9IHdpbmRvdy5vcGVuKFxuICAgICAgICAgICAgdXJsLCAnX2JsYW5rJyxcbiAgICAgICAgICAgICd0b3A9JyArIHQgKyAnLCBsZWZ0PScgKyBsICsgJywgd2lkdGg9JyArIHcgKyAnLCBoZWlnaHQ9JyArIGggKyAnJyk7XG4gICAgICAgIGlmIChwb3B1cCAmJiBvblBvcHVwQ2xvc2VkKSB7XG4gICAgICAgICAgICB2YXIgcG9sbFRpbWVyID0gd2luZG93LnNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAocG9wdXAuY2xvc2VkICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbChwb2xsVGltZXIpO1xuICAgICAgICAgICAgICAgICAgICBvblBvcHVwQ2xvc2VkKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgMjAwKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcG9wdXA7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgZGlhbG9nIHByb21wdGluZyB0aGUgdXNlciB0byBzZW5kIGFuIGVycm9yIHJlcG9ydC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB0aXRsZVN0cmluZyB0aGUgdGl0bGUgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gbXNnU3RyaW5nIHRoZSB0ZXh0IG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIGVycm9yIHRoZSBlcnJvciB0aGF0IGlzIGJlaW5nIHJlcG9ydGVkXG4gICAgICovXG4gICAgbXkub3BlblJlcG9ydERpYWxvZyA9IGZ1bmN0aW9uKHRpdGxlU3RyaW5nLCBtc2dTdHJpbmcsIGVycm9yKSB7XG4gICAgICAgIG15Lm9wZW5NZXNzYWdlRGlhbG9nKHRpdGxlU3RyaW5nLCBtc2dTdHJpbmcpO1xuICAgICAgICBjb25zb2xlLmxvZyhlcnJvcik7XG4gICAgICAgIC8vRklYTUUgc2VuZCB0aGUgZXJyb3IgdG8gdGhlIHNlcnZlclxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiAgU2hvd3MgYW4gZXJyb3IgZGlhbG9nIHRvIHRoZSB1c2VyLlxuICAgICAqIEBwYXJhbSB0aXRsZSB0aGUgdGl0bGUgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSB0aGUgdGV4dCBvZiB0aGUgbWVzc2FmZVxuICAgICAqL1xuICAgIG15LnNob3dFcnJvciA9IGZ1bmN0aW9uKHRpdGxlLCBtZXNzYWdlKSB7XG4gICAgICAgIGlmKCEodGl0bGUgfHwgbWVzc2FnZSkpIHtcbiAgICAgICAgICAgIHRpdGxlID0gdGl0bGUgfHwgXCJPb3BzIVwiO1xuICAgICAgICAgICAgbWVzc2FnZSA9IG1lc3NhZ2UgfHwgXCJUaGVyZSB3YXMgc29tZSBraW5kIG9mIGVycm9yXCI7XG4gICAgICAgIH1cbiAgICAgICAgbWVzc2FnZUhhbmRsZXIub3Blbk1lc3NhZ2VEaWFsb2codGl0bGUsIG1lc3NhZ2UpO1xuICAgIH07XG5cbiAgICBteS5ub3RpZnkgPSBmdW5jdGlvbihkaXNwbGF5TmFtZSwgY2xzLCBtZXNzYWdlKSB7XG4gICAgICAgIHRvYXN0ci5pbmZvKFxuICAgICAgICAgICAgJzxzcGFuIGNsYXNzPVwibmlja25hbWVcIj4nICtcbiAgICAgICAgICAgICAgICBkaXNwbGF5TmFtZSArXG4gICAgICAgICAgICAnPC9zcGFuPjxicj4nICtcbiAgICAgICAgICAgICc8c3BhbiBjbGFzcz0nICsgY2xzICsgJz4nICtcbiAgICAgICAgICAgICAgICBtZXNzYWdlICtcbiAgICAgICAgICAgICc8L3NwYW4+Jyk7XG4gICAgfTtcblxuICAgIHJldHVybiBteTtcbn0obWVzc2FnZUhhbmRsZXIgfHwge30pKTtcblxubW9kdWxlLmV4cG9ydHMgPSBtZXNzYWdlSGFuZGxlcjtcblxuXG4iLCIvKipcbiAqIENyZWF0ZWQgYnkgaHJpc3RvIG9uIDEyLzIyLzE0LlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBhdmFpbGFibGUgdmlkZW8gd2lkdGguXG4gICAgICovXG4gICAgZ2V0QXZhaWxhYmxlVmlkZW9XaWR0aDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgUGFuZWxUb2dnbGVyID0gcmVxdWlyZShcIi4uL3NpZGVfcGFubmVscy9TaWRlUGFuZWxUb2dnbGVyXCIpO1xuICAgICAgICB2YXIgcmlnaHRQYW5lbFdpZHRoXG4gICAgICAgICAgICA9IFBhbmVsVG9nZ2xlci5pc1Zpc2libGUoKSA/IFBhbmVsVG9nZ2xlci5nZXRQYW5lbFNpemUoKVswXSA6IDA7XG5cbiAgICAgICAgcmV0dXJuIHdpbmRvdy5pbm5lcldpZHRoIC0gcmlnaHRQYW5lbFdpZHRoO1xuICAgIH1cblxufTsiLCJ2YXIgSml0c2lQb3BvdmVyID0gcmVxdWlyZShcIi4uL3V0aWwvSml0c2lQb3BvdmVyXCIpO1xuXG4vKipcbiAqIENvbnN0cnVjdHMgbmV3IGNvbm5lY3Rpb24gaW5kaWNhdG9yLlxuICogQHBhcmFtIHZpZGVvQ29udGFpbmVyIHRoZSB2aWRlbyBjb250YWluZXIgYXNzb2NpYXRlZCB3aXRoIHRoZSBpbmRpY2F0b3IuXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZnVuY3Rpb24gQ29ubmVjdGlvbkluZGljYXRvcih2aWRlb0NvbnRhaW5lciwgamlkLCBWaWRlb0xheW91dClcbntcbiAgICB0aGlzLnZpZGVvQ29udGFpbmVyID0gdmlkZW9Db250YWluZXI7XG4gICAgdGhpcy5iYW5kd2lkdGggPSBudWxsO1xuICAgIHRoaXMucGFja2V0TG9zcyA9IG51bGw7XG4gICAgdGhpcy5iaXRyYXRlID0gbnVsbDtcbiAgICB0aGlzLnNob3dNb3JlVmFsdWUgPSBmYWxzZTtcbiAgICB0aGlzLnJlc29sdXRpb24gPSBudWxsO1xuICAgIHRoaXMudHJhbnNwb3J0ID0gW107XG4gICAgdGhpcy5wb3BvdmVyID0gbnVsbDtcbiAgICB0aGlzLmppZCA9IGppZDtcbiAgICB0aGlzLmNyZWF0ZSgpO1xuICAgIHRoaXMudmlkZW9MYXlvdXQgPSBWaWRlb0xheW91dDtcbn1cblxuLyoqXG4gKiBWYWx1ZXMgZm9yIHRoZSBjb25uZWN0aW9uIHF1YWxpdHlcbiAqIEB0eXBlIHt7OTg6IHN0cmluZyxcbiAqICAgICAgICAgODE6IHN0cmluZyxcbiAqICAgICAgICAgNjQ6IHN0cmluZyxcbiAqICAgICAgICAgNDc6IHN0cmluZyxcbiAqICAgICAgICAgMzA6IHN0cmluZyxcbiAqICAgICAgICAgMDogc3RyaW5nfX1cbiAqL1xuQ29ubmVjdGlvbkluZGljYXRvci5jb25uZWN0aW9uUXVhbGl0eVZhbHVlcyA9IHtcbiAgICA5ODogXCIxOHB4XCIsIC8vZnVsbFxuICAgIDgxOiBcIjE1cHhcIiwvLzQgYmFyc1xuICAgIDY0OiBcIjExcHhcIiwvLzMgYmFyc1xuICAgIDQ3OiBcIjdweFwiLC8vMiBiYXJzXG4gICAgMzA6IFwiM3B4XCIsLy8xIGJhclxuICAgIDA6IFwiMHB4XCIvL2VtcHR5XG59O1xuXG5Db25uZWN0aW9uSW5kaWNhdG9yLmdldElQID0gZnVuY3Rpb24odmFsdWUpXG57XG4gICAgcmV0dXJuIHZhbHVlLnN1YnN0cmluZygwLCB2YWx1ZS5sYXN0SW5kZXhPZihcIjpcIikpO1xufTtcblxuQ29ubmVjdGlvbkluZGljYXRvci5nZXRQb3J0ID0gZnVuY3Rpb24odmFsdWUpXG57XG4gICAgcmV0dXJuIHZhbHVlLnN1YnN0cmluZyh2YWx1ZS5sYXN0SW5kZXhPZihcIjpcIikgKyAxLCB2YWx1ZS5sZW5ndGgpO1xufTtcblxuQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkgPSBmdW5jdGlvbiAoYXJyYXkpIHtcbiAgICB2YXIgcmVzID0gXCJcIjtcbiAgICBmb3IodmFyIGkgPSAwOyBpIDwgYXJyYXkubGVuZ3RoOyBpKyspXG4gICAge1xuICAgICAgICByZXMgKz0gKGkgPT09IDA/IFwiXCIgOiBcIiwgXCIpICsgYXJyYXlbaV07XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59O1xuXG4vKipcbiAqIEdlbmVyYXRlcyB0aGUgaHRtbCBjb250ZW50LlxuICogQHJldHVybnMge3N0cmluZ30gdGhlIGh0bWwgY29udGVudC5cbiAqL1xuQ29ubmVjdGlvbkluZGljYXRvci5wcm90b3R5cGUuZ2VuZXJhdGVUZXh0ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBkb3dubG9hZEJpdHJhdGUsIHVwbG9hZEJpdHJhdGUsIHBhY2tldExvc3MsIHJlc29sdXRpb24sIGk7XG5cbiAgICBpZih0aGlzLmJpdHJhdGUgPT09IG51bGwpXG4gICAge1xuICAgICAgICBkb3dubG9hZEJpdHJhdGUgPSBcIk4vQVwiO1xuICAgICAgICB1cGxvYWRCaXRyYXRlID0gXCJOL0FcIjtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgZG93bmxvYWRCaXRyYXRlID1cbiAgICAgICAgICAgIHRoaXMuYml0cmF0ZS5kb3dubG9hZD8gdGhpcy5iaXRyYXRlLmRvd25sb2FkICsgXCIgS2Jwc1wiIDogXCJOL0FcIjtcbiAgICAgICAgdXBsb2FkQml0cmF0ZSA9XG4gICAgICAgICAgICB0aGlzLmJpdHJhdGUudXBsb2FkPyB0aGlzLmJpdHJhdGUudXBsb2FkICsgXCIgS2Jwc1wiIDogXCJOL0FcIjtcbiAgICB9XG5cbiAgICBpZih0aGlzLnBhY2tldExvc3MgPT09IG51bGwpXG4gICAge1xuICAgICAgICBwYWNrZXRMb3NzID0gXCJOL0FcIjtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcblxuICAgICAgICBwYWNrZXRMb3NzID0gXCI8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2dyZWVuJz4mZGFycjs8L3NwYW4+XCIgK1xuICAgICAgICAgICAgKHRoaXMucGFja2V0TG9zcy5kb3dubG9hZCAhPT0gbnVsbD8gdGhpcy5wYWNrZXRMb3NzLmRvd25sb2FkIDogXCJOL0FcIikgK1xuICAgICAgICAgICAgXCIlIDxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfb3JhbmdlJz4mdWFycjs8L3NwYW4+XCIgK1xuICAgICAgICAgICAgKHRoaXMucGFja2V0TG9zcy51cGxvYWQgIT09IG51bGw/IHRoaXMucGFja2V0TG9zcy51cGxvYWQgOiBcIk4vQVwiKSArIFwiJVwiO1xuICAgIH1cblxuICAgIHZhciByZXNvbHV0aW9uVmFsdWUgPSBudWxsO1xuICAgIGlmKHRoaXMucmVzb2x1dGlvbilcbiAgICB7XG4gICAgICAgIHZhciBrZXlzID0gT2JqZWN0LmtleXModGhpcy5yZXNvbHV0aW9uKTtcbiAgICAgICAgaWYoa2V5cy5sZW5ndGggPT0gMSlcbiAgICAgICAge1xuICAgICAgICAgICAgZm9yKHZhciBzc3JjIGluIHRoaXMucmVzb2x1dGlvbilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSB0aGlzLnJlc29sdXRpb25bc3NyY107XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZihrZXlzLmxlbmd0aCA+IDEpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBkaXNwbGF5ZWRTc3JjID0gc2ltdWxjYXN0LmdldFJlY2VpdmluZ1NTUkModGhpcy5qaWQpO1xuICAgICAgICAgICAgcmVzb2x1dGlvblZhbHVlID0gdGhpcy5yZXNvbHV0aW9uW2Rpc3BsYXllZFNzcmNdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYodGhpcy5qaWQgPT09IG51bGwpXG4gICAge1xuICAgICAgICByZXNvbHV0aW9uID0gXCJcIjtcbiAgICAgICAgaWYodGhpcy5yZXNvbHV0aW9uID09PSBudWxsIHx8ICFPYmplY3Qua2V5cyh0aGlzLnJlc29sdXRpb24pIHx8XG4gICAgICAgICAgICBPYmplY3Qua2V5cyh0aGlzLnJlc29sdXRpb24pLmxlbmd0aCA9PT0gMClcbiAgICAgICAge1xuICAgICAgICAgICAgcmVzb2x1dGlvbiA9IFwiTi9BXCI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgZm9yKGkgaW4gdGhpcy5yZXNvbHV0aW9uKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHJlc29sdXRpb25WYWx1ZSA9IHRoaXMucmVzb2x1dGlvbltpXTtcbiAgICAgICAgICAgICAgICBpZihyZXNvbHV0aW9uVmFsdWUpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBpZihyZXNvbHV0aW9uVmFsdWUuaGVpZ2h0ICYmXG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHV0aW9uVmFsdWUud2lkdGgpXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24gKz0gKHJlc29sdXRpb24gPT09IFwiXCI/IFwiXCIgOiBcIiwgXCIpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNvbHV0aW9uVmFsdWUud2lkdGggKyBcInhcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvblZhbHVlLmhlaWdodDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSBpZighcmVzb2x1dGlvblZhbHVlIHx8XG4gICAgICAgICFyZXNvbHV0aW9uVmFsdWUuaGVpZ2h0IHx8XG4gICAgICAgICFyZXNvbHV0aW9uVmFsdWUud2lkdGgpXG4gICAge1xuICAgICAgICByZXNvbHV0aW9uID0gXCJOL0FcIjtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgcmVzb2x1dGlvbiA9IHJlc29sdXRpb25WYWx1ZS53aWR0aCArIFwieFwiICsgcmVzb2x1dGlvblZhbHVlLmhlaWdodDtcbiAgICB9XG5cbiAgICB2YXIgcmVzdWx0ID0gXCI8dGFibGUgc3R5bGU9J3dpZHRoOjEwMCUnPlwiICtcbiAgICAgICAgXCI8dHI+XCIgK1xuICAgICAgICBcIjx0ZD48c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnPkJpdHJhdGU6PC9zcGFuPjwvdGQ+XCIgK1xuICAgICAgICBcIjx0ZD48c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2dyZWVuJz4mZGFycjs8L3NwYW4+XCIgK1xuICAgICAgICBkb3dubG9hZEJpdHJhdGUgKyBcIiA8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX29yYW5nZSc+JnVhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgdXBsb2FkQml0cmF0ZSArIFwiPC90ZD5cIiArXG4gICAgICAgIFwiPC90cj48dHI+XCIgK1xuICAgICAgICBcIjx0ZD48c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnPlBhY2tldCBsb3NzOiA8L3NwYW4+PC90ZD5cIiArXG4gICAgICAgIFwiPHRkPlwiICsgcGFja2V0TG9zcyAgKyBcIjwvdGQ+XCIgK1xuICAgICAgICBcIjwvdHI+PHRyPlwiICtcbiAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJz5SZXNvbHV0aW9uOjwvc3Bhbj48L3RkPlwiICtcbiAgICAgICAgXCI8dGQ+XCIgKyByZXNvbHV0aW9uICsgXCI8L3RkPjwvdHI+PC90YWJsZT5cIjtcblxuICAgIGlmKHRoaXMudmlkZW9Db250YWluZXIuaWQgPT0gXCJsb2NhbFZpZGVvQ29udGFpbmVyXCIpXG4gICAgICAgIHJlc3VsdCArPSBcIjxkaXYgY2xhc3M9XFxcImppdHNpcG9wb3Zlcl9zaG93bW9yZVxcXCIgXCIgK1xuICAgICAgICAgICAgXCJvbmNsaWNrID0gXFxcIlVJLmNvbm5lY3Rpb25JbmRpY2F0b3JTaG93TW9yZSgnXCIgK1xuICAgICAgICAgICAgdGhpcy52aWRlb0NvbnRhaW5lci5pZCArIFwiJylcXFwiPlwiICtcbiAgICAgICAgICAgICh0aGlzLnNob3dNb3JlVmFsdWU/IFwiU2hvdyBsZXNzXCIgOiBcIlNob3cgTW9yZVwiKSArIFwiPC9kaXY+PGJyIC8+XCI7XG5cbiAgICBpZih0aGlzLnNob3dNb3JlVmFsdWUpXG4gICAge1xuICAgICAgICB2YXIgZG93bmxvYWRCYW5kd2lkdGgsIHVwbG9hZEJhbmR3aWR0aCwgdHJhbnNwb3J0O1xuICAgICAgICBpZih0aGlzLmJhbmR3aWR0aCA9PT0gbnVsbClcbiAgICAgICAge1xuICAgICAgICAgICAgZG93bmxvYWRCYW5kd2lkdGggPSBcIk4vQVwiO1xuICAgICAgICAgICAgdXBsb2FkQmFuZHdpZHRoID0gXCJOL0FcIjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIGRvd25sb2FkQmFuZHdpZHRoID0gdGhpcy5iYW5kd2lkdGguZG93bmxvYWQ/XG4gICAgICAgICAgICAgICAgdGhpcy5iYW5kd2lkdGguZG93bmxvYWQgKyBcIiBLYnBzXCIgOlxuICAgICAgICAgICAgICAgIFwiTi9BXCI7XG4gICAgICAgICAgICB1cGxvYWRCYW5kd2lkdGggPSB0aGlzLmJhbmR3aWR0aC51cGxvYWQ/XG4gICAgICAgICAgICAgICAgdGhpcy5iYW5kd2lkdGgudXBsb2FkICsgXCIgS2Jwc1wiIDpcbiAgICAgICAgICAgICAgICBcIk4vQVwiO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYoIXRoaXMudHJhbnNwb3J0IHx8IHRoaXMudHJhbnNwb3J0Lmxlbmd0aCA9PT0gMClcbiAgICAgICAge1xuICAgICAgICAgICAgdHJhbnNwb3J0ID0gXCI8dHI+XCIgK1xuICAgICAgICAgICAgICAgIFwiPHRkPjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfYmx1ZSc+QWRkcmVzczo8L3NwYW4+PC90ZD5cIiArXG4gICAgICAgICAgICAgICAgXCI8dGQ+IE4vQTwvdGQ+PC90cj5cIjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBkYXRhID0ge3JlbW90ZUlQOiBbXSwgbG9jYWxJUDpbXSwgcmVtb3RlUG9ydDpbXSwgbG9jYWxQb3J0OltdfTtcbiAgICAgICAgICAgIGZvcihpID0gMDsgaSA8IHRoaXMudHJhbnNwb3J0Lmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHZhciBpcCA9ICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldElQKHRoaXMudHJhbnNwb3J0W2ldLmlwKTtcbiAgICAgICAgICAgICAgICB2YXIgcG9ydCA9IENvbm5lY3Rpb25JbmRpY2F0b3IuZ2V0UG9ydCh0aGlzLnRyYW5zcG9ydFtpXS5pcCk7XG4gICAgICAgICAgICAgICAgdmFyIGxvY2FsSVAgPVxuICAgICAgICAgICAgICAgICAgICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldElQKHRoaXMudHJhbnNwb3J0W2ldLmxvY2FsaXApO1xuICAgICAgICAgICAgICAgIHZhciBsb2NhbFBvcnQgPVxuICAgICAgICAgICAgICAgICAgICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldFBvcnQodGhpcy50cmFuc3BvcnRbaV0ubG9jYWxpcCk7XG4gICAgICAgICAgICAgICAgaWYoZGF0YS5yZW1vdGVJUC5pbmRleE9mKGlwKSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEucmVtb3RlSVAucHVzaChpcCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYoZGF0YS5yZW1vdGVQb3J0LmluZGV4T2YocG9ydCkgPT0gLTEpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBkYXRhLnJlbW90ZVBvcnQucHVzaChwb3J0KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZihkYXRhLmxvY2FsSVAuaW5kZXhPZihsb2NhbElQKSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEubG9jYWxJUC5wdXNoKGxvY2FsSVApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmKGRhdGEubG9jYWxQb3J0LmluZGV4T2YobG9jYWxQb3J0KSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEubG9jYWxQb3J0LnB1c2gobG9jYWxQb3J0KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBsb2NhbFRyYW5zcG9ydCA9XG4gICAgICAgICAgICAgICAgXCI8dHI+PHRkPjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfYmx1ZSc+TG9jYWwgYWRkcmVzc1wiICtcbiAgICAgICAgICAgICAgICAoZGF0YS5sb2NhbElQLmxlbmd0aCA+IDE/IFwiZXNcIiA6IFwiXCIpICsgXCI6IDwvc3Bhbj48L3RkPjx0ZD4gXCIgK1xuICAgICAgICAgICAgICAgIENvbm5lY3Rpb25JbmRpY2F0b3IuZ2V0U3RyaW5nRnJvbUFycmF5KGRhdGEubG9jYWxJUCkgK1xuICAgICAgICAgICAgICAgIFwiPC90ZD48L3RyPlwiO1xuICAgICAgICAgICAgdHJhbnNwb3J0ID1cbiAgICAgICAgICAgICAgICBcIjx0cj48dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJz5SZW1vdGUgYWRkcmVzc1wiK1xuICAgICAgICAgICAgICAgIChkYXRhLnJlbW90ZUlQLmxlbmd0aCA+IDE/IFwiZXNcIiA6IFwiXCIpICsgXCI6PC9zcGFuPjwvdGQ+PHRkPiBcIiArXG4gICAgICAgICAgICAgICAgQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkoZGF0YS5yZW1vdGVJUCkgK1xuICAgICAgICAgICAgICAgIFwiPC90ZD48L3RyPlwiO1xuICAgICAgICAgICAgaWYodGhpcy50cmFuc3BvcnQubGVuZ3RoID4gMSlcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0cmFuc3BvcnQgKz0gXCI8dHI+XCIgK1xuICAgICAgICAgICAgICAgICAgICBcIjx0ZD5cIiArXG4gICAgICAgICAgICAgICAgICAgIFwiPHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJz5SZW1vdGUgcG9ydHM6PC9zcGFuPlwiICtcbiAgICAgICAgICAgICAgICAgICAgXCI8L3RkPjx0ZD5cIjtcbiAgICAgICAgICAgICAgICBsb2NhbFRyYW5zcG9ydCArPSBcIjx0cj5cIiArXG4gICAgICAgICAgICAgICAgICAgIFwiPHRkPlwiICtcbiAgICAgICAgICAgICAgICAgICAgXCI8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnPkxvY2FsIHBvcnRzOjwvc3Bhbj5cIiArXG4gICAgICAgICAgICAgICAgICAgIFwiPC90ZD48dGQ+XCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdHJhbnNwb3J0ICs9XG4gICAgICAgICAgICAgICAgICAgIFwiPHRyPlwiICtcbiAgICAgICAgICAgICAgICAgICAgXCI8dGQ+XCIgK1xuICAgICAgICAgICAgICAgICAgICBcIjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfYmx1ZSc+UmVtb3RlIHBvcnQ6PC9zcGFuPlwiICtcbiAgICAgICAgICAgICAgICAgICAgXCI8L3RkPjx0ZD5cIjtcbiAgICAgICAgICAgICAgICBsb2NhbFRyYW5zcG9ydCArPVxuICAgICAgICAgICAgICAgICAgICBcIjx0cj5cIiArXG4gICAgICAgICAgICAgICAgICAgIFwiPHRkPlwiICtcbiAgICAgICAgICAgICAgICAgICAgXCI8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnPkxvY2FsIHBvcnQ6PC9zcGFuPlwiICtcbiAgICAgICAgICAgICAgICAgICAgXCI8L3RkPjx0ZD5cIjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdHJhbnNwb3J0ICs9XG4gICAgICAgICAgICAgICAgQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkoZGF0YS5yZW1vdGVQb3J0KTtcbiAgICAgICAgICAgIGxvY2FsVHJhbnNwb3J0ICs9XG4gICAgICAgICAgICAgICAgQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkoZGF0YS5sb2NhbFBvcnQpO1xuICAgICAgICAgICAgdHJhbnNwb3J0ICs9IFwiPC90ZD48L3RyPlwiO1xuICAgICAgICAgICAgdHJhbnNwb3J0ICs9IGxvY2FsVHJhbnNwb3J0ICsgXCI8L3RkPjwvdHI+XCI7XG4gICAgICAgICAgICB0cmFuc3BvcnQgKz1cIjx0cj5cIiArXG4gICAgICAgICAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJz5UcmFuc3BvcnQ6PC9zcGFuPjwvdGQ+XCIgK1xuICAgICAgICAgICAgICAgIFwiPHRkPlwiICsgdGhpcy50cmFuc3BvcnRbMF0udHlwZSArIFwiPC90ZD48L3RyPlwiO1xuXG4gICAgICAgIH1cblxuICAgICAgICByZXN1bHQgKz0gXCI8dGFibGUgIHN0eWxlPSd3aWR0aDoxMDAlJz5cIiArXG4gICAgICAgICAgICBcIjx0cj5cIiArXG4gICAgICAgICAgICBcIjx0ZD5cIiArXG4gICAgICAgICAgICBcIjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfYmx1ZSc+RXN0aW1hdGVkIGJhbmR3aWR0aDo8L3NwYW4+XCIgK1xuICAgICAgICAgICAgXCI8L3RkPjx0ZD5cIiArXG4gICAgICAgICAgICBcIjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfZ3JlZW4nPiZkYXJyOzwvc3Bhbj5cIiArXG4gICAgICAgICAgICBkb3dubG9hZEJhbmR3aWR0aCArXG4gICAgICAgICAgICBcIiA8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX29yYW5nZSc+JnVhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgICAgIHVwbG9hZEJhbmR3aWR0aCArIFwiPC90ZD48L3RyPlwiO1xuXG4gICAgICAgIHJlc3VsdCArPSB0cmFuc3BvcnQgKyBcIjwvdGFibGU+XCI7XG5cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBTaG93cyBvciBoaWRlIHRoZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLlxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5zaG93TW9yZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnNob3dNb3JlVmFsdWUgPSAhdGhpcy5zaG93TW9yZVZhbHVlO1xuICAgIHRoaXMudXBkYXRlUG9wb3ZlckRhdGEoKTtcbn07XG5cblxuZnVuY3Rpb24gY3JlYXRlSWNvbihjbGFzc2VzKVxue1xuICAgIHZhciBpY29uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNwYW5cIik7XG4gICAgZm9yKHZhciBpIGluIGNsYXNzZXMpXG4gICAge1xuICAgICAgICBpY29uLmNsYXNzTGlzdC5hZGQoY2xhc3Nlc1tpXSk7XG4gICAgfVxuICAgIGljb24uYXBwZW5kQ2hpbGQoXG4gICAgICAgIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpXCIpKS5jbGFzc0xpc3QuYWRkKFwiaWNvbi1jb25uZWN0aW9uXCIpO1xuICAgIHJldHVybiBpY29uO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIGluZGljYXRvclxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5jcmVhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICB0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuY2xhc3NOYW1lID0gXCJjb25uZWN0aW9uaW5kaWNhdG9yXCI7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICB0aGlzLnZpZGVvQ29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lcik7XG4gICAgdGhpcy5wb3BvdmVyID0gbmV3IEppdHNpUG9wb3ZlcihcbiAgICAgICAgJChcIiNcIiArIHRoaXMudmlkZW9Db250YWluZXIuaWQgKyBcIiA+IC5jb25uZWN0aW9uaW5kaWNhdG9yXCIpLFxuICAgICAgICB7Y29udGVudDogXCI8ZGl2IGNsYXNzPVxcXCJjb25uZWN0aW9uX2luZm9cXFwiPkNvbWUgYmFjayBoZXJlIGZvciBcIiArXG4gICAgICAgICAgICBcImNvbm5lY3Rpb24gaW5mb3JtYXRpb24gb25jZSB0aGUgY29uZmVyZW5jZSBzdGFydHM8L2Rpdj5cIixcbiAgICAgICAgICAgIHNraW46IFwiYmxhY2tcIn0pO1xuXG4gICAgdGhpcy5lbXB0eUljb24gPSB0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuYXBwZW5kQ2hpbGQoXG4gICAgICAgIGNyZWF0ZUljb24oW1wiY29ubmVjdGlvblwiLCBcImNvbm5lY3Rpb25fZW1wdHlcIl0pKTtcbiAgICB0aGlzLmZ1bGxJY29uID0gdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLmFwcGVuZENoaWxkKFxuICAgICAgICBjcmVhdGVJY29uKFtcImNvbm5lY3Rpb25cIiwgXCJjb25uZWN0aW9uX2Z1bGxcIl0pKTtcblxufTtcblxuLyoqXG4gKiBSZW1vdmVzIHRoZSBpbmRpY2F0b3JcbiAqL1xuQ29ubmVjdGlvbkluZGljYXRvci5wcm90b3R5cGUucmVtb3ZlID0gZnVuY3Rpb24oKVxue1xuICAgIHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lci5yZW1vdmUoKTtcbiAgICB0aGlzLnBvcG92ZXIuZm9yY2VIaWRlKCk7XG5cbn07XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZGF0YSBvZiB0aGUgaW5kaWNhdG9yXG4gKiBAcGFyYW0gcGVyY2VudCB0aGUgcGVyY2VudCBvZiBjb25uZWN0aW9uIHF1YWxpdHlcbiAqIEBwYXJhbSBvYmplY3QgdGhlIHN0YXRpc3RpY3MgZGF0YS5cbiAqL1xuQ29ubmVjdGlvbkluZGljYXRvci5wcm90b3R5cGUudXBkYXRlQ29ubmVjdGlvblF1YWxpdHkgPVxuZnVuY3Rpb24gKHBlcmNlbnQsIG9iamVjdCkge1xuXG4gICAgaWYocGVyY2VudCA9PT0gbnVsbClcbiAgICB7XG4gICAgICAgIHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lci5zdHlsZS5kaXNwbGF5ID0gXCJub25lXCI7XG4gICAgICAgIHRoaXMucG9wb3Zlci5mb3JjZUhpZGUoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgICBpZih0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuc3R5bGUuZGlzcGxheSA9PSBcIm5vbmVcIikge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSBcImJsb2NrXCI7XG4gICAgICAgICAgICB0aGlzLnZpZGVvTGF5b3V0LnVwZGF0ZU11dGVQb3NpdGlvbih0aGlzLnZpZGVvQ29udGFpbmVyLmlkKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmJhbmR3aWR0aCA9IG9iamVjdC5iYW5kd2lkdGg7XG4gICAgdGhpcy5iaXRyYXRlID0gb2JqZWN0LmJpdHJhdGU7XG4gICAgdGhpcy5wYWNrZXRMb3NzID0gb2JqZWN0LnBhY2tldExvc3M7XG4gICAgdGhpcy50cmFuc3BvcnQgPSBvYmplY3QudHJhbnNwb3J0O1xuICAgIGlmKG9iamVjdC5yZXNvbHV0aW9uKVxuICAgIHtcbiAgICAgICAgdGhpcy5yZXNvbHV0aW9uID0gb2JqZWN0LnJlc29sdXRpb247XG4gICAgfVxuICAgIGZvcih2YXIgcXVhbGl0eSBpbiBDb25uZWN0aW9uSW5kaWNhdG9yLmNvbm5lY3Rpb25RdWFsaXR5VmFsdWVzKVxuICAgIHtcbiAgICAgICAgaWYocGVyY2VudCA+PSBxdWFsaXR5KVxuICAgICAgICB7XG4gICAgICAgICAgICB0aGlzLmZ1bGxJY29uLnN0eWxlLndpZHRoID1cbiAgICAgICAgICAgICAgICBDb25uZWN0aW9uSW5kaWNhdG9yLmNvbm5lY3Rpb25RdWFsaXR5VmFsdWVzW3F1YWxpdHldO1xuICAgICAgICB9XG4gICAgfVxuICAgIHRoaXMudXBkYXRlUG9wb3ZlckRhdGEoKTtcbn07XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgcmVzb2x1dGlvblxuICogQHBhcmFtIHJlc29sdXRpb24gdGhlIG5ldyByZXNvbHV0aW9uXG4gKi9cbkNvbm5lY3Rpb25JbmRpY2F0b3IucHJvdG90eXBlLnVwZGF0ZVJlc29sdXRpb24gPSBmdW5jdGlvbiAocmVzb2x1dGlvbikge1xuICAgIHRoaXMucmVzb2x1dGlvbiA9IHJlc29sdXRpb247XG4gICAgdGhpcy51cGRhdGVQb3BvdmVyRGF0YSgpO1xufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBjb250ZW50IG9mIHRoZSBwb3BvdmVyXG4gKi9cbkNvbm5lY3Rpb25JbmRpY2F0b3IucHJvdG90eXBlLnVwZGF0ZVBvcG92ZXJEYXRhID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMucG9wb3Zlci51cGRhdGVDb250ZW50KFxuICAgICAgICAgICAgXCI8ZGl2IGNsYXNzPVxcXCJjb25uZWN0aW9uX2luZm9cXFwiPlwiICsgdGhpcy5nZW5lcmF0ZVRleHQoKSArIFwiPC9kaXY+XCIpO1xufTtcblxuLyoqXG4gKiBIaWRlcyB0aGUgcG9wb3ZlclxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5oaWRlID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMucG9wb3Zlci5mb3JjZUhpZGUoKTtcbn07XG5cbi8qKlxuICogSGlkZXMgdGhlIGluZGljYXRvclxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5oaWRlSW5kaWNhdG9yID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lci5zdHlsZS5kaXNwbGF5ID0gXCJub25lXCI7XG4gICAgaWYodGhpcy5wb3BvdmVyKVxuICAgICAgICB0aGlzLnBvcG92ZXIuZm9yY2VIaWRlKCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvbm5lY3Rpb25JbmRpY2F0b3I7IiwidmFyIEF1ZGlvTGV2ZWxzID0gcmVxdWlyZShcIi4uL2F1ZGlvX2xldmVscy9BdWRpb0xldmVsc1wiKTtcbnZhciBBdmF0YXIgPSByZXF1aXJlKFwiLi4vYXZhdGFyL0F2YXRhclwiKTtcbnZhciBDaGF0ID0gcmVxdWlyZShcIi4uL3NpZGVfcGFubmVscy9jaGF0L0NoYXRcIik7XG52YXIgQ29udGFjdExpc3QgPSByZXF1aXJlKFwiLi4vc2lkZV9wYW5uZWxzL2NvbnRhY3RsaXN0L0NvbnRhY3RMaXN0XCIpO1xudmFyIFVJVXRpbCA9IHJlcXVpcmUoXCIuLi91dGlsL1VJVXRpbFwiKTtcbnZhciBDb25uZWN0aW9uSW5kaWNhdG9yID0gcmVxdWlyZShcIi4vQ29ubmVjdGlvbkluZGljYXRvclwiKTtcblxudmFyIGN1cnJlbnREb21pbmFudFNwZWFrZXIgPSBudWxsO1xudmFyIGxhc3ROQ291bnQgPSBjb25maWcuY2hhbm5lbExhc3ROO1xudmFyIGxvY2FsTGFzdE5Db3VudCA9IGNvbmZpZy5jaGFubmVsTGFzdE47XG52YXIgbG9jYWxMYXN0TlNldCA9IFtdO1xudmFyIGxhc3RORW5kcG9pbnRzQ2FjaGUgPSBbXTtcbnZhciBsYXN0TlBpY2t1cEppZCA9IG51bGw7XG52YXIgbGFyZ2VWaWRlb1N0YXRlID0ge1xuICAgIHVwZGF0ZUluUHJvZ3Jlc3M6IGZhbHNlLFxuICAgIG5ld1NyYzogJydcbn07XG5cbnZhciBkZWZhdWx0TG9jYWxEaXNwbGF5TmFtZSA9IFwiTWVcIjtcblxuLyoqXG4gKiBTZXRzIHRoZSBkaXNwbGF5IG5hbWUgZm9yIHRoZSBnaXZlbiB2aWRlbyBzcGFuIGlkLlxuICovXG5mdW5jdGlvbiBzZXREaXNwbGF5TmFtZSh2aWRlb1NwYW5JZCwgZGlzcGxheU5hbWUpIHtcbiAgICB2YXIgbmFtZVNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLmRpc3BsYXluYW1lJyk7XG4gICAgdmFyIGRlZmF1bHRMb2NhbERpc3BsYXlOYW1lID0gaW50ZXJmYWNlQ29uZmlnLkRFRkFVTFRfTE9DQUxfRElTUExBWV9OQU1FO1xuXG4gICAgLy8gSWYgd2UgYWxyZWFkeSBoYXZlIGEgZGlzcGxheSBuYW1lIGZvciB0aGlzIHZpZGVvLlxuICAgIGlmIChuYW1lU3Bhbi5sZW5ndGggPiAwKSB7XG4gICAgICAgIHZhciBuYW1lU3BhbkVsZW1lbnQgPSBuYW1lU3Bhbi5nZXQoMCk7XG5cbiAgICAgICAgaWYgKG5hbWVTcGFuRWxlbWVudC5pZCA9PT0gJ2xvY2FsRGlzcGxheU5hbWUnICYmXG4gICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLnRleHQoKSAhPT0gZGlzcGxheU5hbWUpIHtcbiAgICAgICAgICAgIGlmIChkaXNwbGF5TmFtZSAmJiBkaXNwbGF5TmFtZS5sZW5ndGggPiAwKVxuICAgICAgICAgICAgICAgICQoJyNsb2NhbERpc3BsYXlOYW1lJykuaHRtbChkaXNwbGF5TmFtZSArICcgKG1lKScpO1xuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICQoJyNsb2NhbERpc3BsYXlOYW1lJykudGV4dChkZWZhdWx0TG9jYWxEaXNwbGF5TmFtZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoZGlzcGxheU5hbWUgJiYgZGlzcGxheU5hbWUubGVuZ3RoID4gMClcbiAgICAgICAgICAgICAgICAkKCcjJyArIHZpZGVvU3BhbklkICsgJ19uYW1lJykuaHRtbChkaXNwbGF5TmFtZSk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZCArICdfbmFtZScpLnRleHQoaW50ZXJmYWNlQ29uZmlnLkRFRkFVTFRfUkVNT1RFX0RJU1BMQVlfTkFNRSk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgZWRpdEJ1dHRvbiA9IG51bGw7XG5cbiAgICAgICAgbmFtZVNwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgIG5hbWVTcGFuLmNsYXNzTmFtZSA9ICdkaXNwbGF5bmFtZSc7XG4gICAgICAgICQoJyMnICsgdmlkZW9TcGFuSWQpWzBdLmFwcGVuZENoaWxkKG5hbWVTcGFuKTtcblxuICAgICAgICBpZiAodmlkZW9TcGFuSWQgPT09ICdsb2NhbFZpZGVvQ29udGFpbmVyJykge1xuICAgICAgICAgICAgZWRpdEJ1dHRvbiA9IGNyZWF0ZUVkaXREaXNwbGF5TmFtZUJ1dHRvbigpO1xuICAgICAgICAgICAgbmFtZVNwYW4uaW5uZXJUZXh0ID0gZGVmYXVsdExvY2FsRGlzcGxheU5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBuYW1lU3Bhbi5pbm5lclRleHQgPSBpbnRlcmZhY2VDb25maWcuREVGQVVMVF9SRU1PVEVfRElTUExBWV9OQU1FO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRpc3BsYXlOYW1lICYmIGRpc3BsYXlOYW1lLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIG5hbWVTcGFuLmlubmVyVGV4dCA9IGRpc3BsYXlOYW1lO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFlZGl0QnV0dG9uKSB7XG4gICAgICAgICAgICBuYW1lU3Bhbi5pZCA9IHZpZGVvU3BhbklkICsgJ19uYW1lJztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG5hbWVTcGFuLmlkID0gJ2xvY2FsRGlzcGxheU5hbWUnO1xuICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQoZWRpdEJ1dHRvbik7XG5cbiAgICAgICAgICAgIHZhciBlZGl0YWJsZVRleHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbnB1dCcpO1xuICAgICAgICAgICAgZWRpdGFibGVUZXh0LmNsYXNzTmFtZSA9ICdkaXNwbGF5bmFtZSc7XG4gICAgICAgICAgICBlZGl0YWJsZVRleHQudHlwZSA9ICd0ZXh0JztcbiAgICAgICAgICAgIGVkaXRhYmxlVGV4dC5pZCA9ICdlZGl0RGlzcGxheU5hbWUnO1xuXG4gICAgICAgICAgICBpZiAoZGlzcGxheU5hbWUgJiYgZGlzcGxheU5hbWUubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgZWRpdGFibGVUZXh0LnZhbHVlXG4gICAgICAgICAgICAgICAgICAgID0gZGlzcGxheU5hbWUuc3Vic3RyaW5nKDAsIGRpc3BsYXlOYW1lLmluZGV4T2YoJyAobWUpJykpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBlZGl0YWJsZVRleHQuc2V0QXR0cmlidXRlKCdzdHlsZScsICdkaXNwbGF5Om5vbmU7Jyk7XG4gICAgICAgICAgICBlZGl0YWJsZVRleHQuc2V0QXR0cmlidXRlKCdwbGFjZWhvbGRlcicsICdleC4gSmFuZSBQaW5rJyk7XG4gICAgICAgICAgICAkKCcjJyArIHZpZGVvU3BhbklkKVswXS5hcHBlbmRDaGlsZChlZGl0YWJsZVRleHQpO1xuXG4gICAgICAgICAgICAkKCcjbG9jYWxWaWRlb0NvbnRhaW5lciAuZGlzcGxheW5hbWUnKVxuICAgICAgICAgICAgICAgIC5iaW5kKFwiY2xpY2tcIiwgZnVuY3Rpb24gKGUpIHtcblxuICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICAgICAgICAgICQoJyNsb2NhbERpc3BsYXlOYW1lJykuaGlkZSgpO1xuICAgICAgICAgICAgICAgICAgICAkKCcjZWRpdERpc3BsYXlOYW1lJykuc2hvdygpO1xuICAgICAgICAgICAgICAgICAgICAkKCcjZWRpdERpc3BsYXlOYW1lJykuZm9jdXMoKTtcbiAgICAgICAgICAgICAgICAgICAgJCgnI2VkaXREaXNwbGF5TmFtZScpLnNlbGVjdCgpO1xuXG4gICAgICAgICAgICAgICAgICAgICQoJyNlZGl0RGlzcGxheU5hbWUnKS5vbmUoXCJmb2N1c291dFwiLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuaW5wdXREaXNwbGF5TmFtZUhhbmRsZXIodGhpcy52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgICQoJyNlZGl0RGlzcGxheU5hbWUnKS5vbigna2V5ZG93bicsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZS5rZXlDb2RlID09PSAxMykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5pbnB1dERpc3BsYXlOYW1lSGFuZGxlcih0aGlzLnZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogR2V0cyB0aGUgc2VsZWN0b3Igb2YgdmlkZW8gdGh1bWJuYWlsIGNvbnRhaW5lciBmb3IgdGhlIHVzZXIgaWRlbnRpZmllZCBieVxuICogZ2l2ZW4gPHR0PnVzZXJKaWQ8L3R0PlxuICogQHBhcmFtIHJlc291cmNlSmlkIHVzZXIncyBKaWQgZm9yIHdob20gd2Ugd2FudCB0byBnZXQgdGhlIHZpZGVvIGNvbnRhaW5lci5cbiAqL1xuZnVuY3Rpb24gZ2V0UGFydGljaXBhbnRDb250YWluZXIocmVzb3VyY2VKaWQpXG57XG4gICAgaWYgKCFyZXNvdXJjZUppZClcbiAgICAgICAgcmV0dXJuIG51bGw7XG5cbiAgICBpZiAocmVzb3VyY2VKaWQgPT09IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpKVxuICAgICAgICByZXR1cm4gJChcIiNsb2NhbFZpZGVvQ29udGFpbmVyXCIpO1xuICAgIGVsc2VcbiAgICAgICAgcmV0dXJuICQoXCIjcGFydGljaXBhbnRfXCIgKyByZXNvdXJjZUppZCk7XG59XG5cbi8qKlxuICogU2V0cyB0aGUgc2l6ZSBhbmQgcG9zaXRpb24gb2YgdGhlIGdpdmVuIHZpZGVvIGVsZW1lbnQuXG4gKlxuICogQHBhcmFtIHZpZGVvIHRoZSB2aWRlbyBlbGVtZW50IHRvIHBvc2l0aW9uXG4gKiBAcGFyYW0gd2lkdGggdGhlIGRlc2lyZWQgdmlkZW8gd2lkdGhcbiAqIEBwYXJhbSBoZWlnaHQgdGhlIGRlc2lyZWQgdmlkZW8gaGVpZ2h0XG4gKiBAcGFyYW0gaG9yaXpvbnRhbEluZGVudCB0aGUgbGVmdCBhbmQgcmlnaHQgaW5kZW50XG4gKiBAcGFyYW0gdmVydGljYWxJbmRlbnQgdGhlIHRvcCBhbmQgYm90dG9tIGluZGVudFxuICovXG5mdW5jdGlvbiBwb3NpdGlvblZpZGVvKHZpZGVvLFxuICAgICAgICAgICAgICAgICAgICAgICB3aWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICBob3Jpem9udGFsSW5kZW50LFxuICAgICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNhbEluZGVudCkge1xuICAgIHZpZGVvLndpZHRoKHdpZHRoKTtcbiAgICB2aWRlby5oZWlnaHQoaGVpZ2h0KTtcbiAgICB2aWRlby5jc3MoeyAgdG9wOiB2ZXJ0aWNhbEluZGVudCArICdweCcsXG4gICAgICAgIGJvdHRvbTogdmVydGljYWxJbmRlbnQgKyAncHgnLFxuICAgICAgICBsZWZ0OiBob3Jpem9udGFsSW5kZW50ICsgJ3B4JyxcbiAgICAgICAgcmlnaHQ6IGhvcml6b250YWxJbmRlbnQgKyAncHgnfSk7XG59XG5cbi8qKlxuICogQWRkcyB0aGUgcmVtb3RlIHZpZGVvIG1lbnUgZWxlbWVudCBmb3IgdGhlIGdpdmVuIDx0dD5qaWQ8L3R0PiBpbiB0aGVcbiAqIGdpdmVuIDx0dD5wYXJlbnRFbGVtZW50PC90dD4uXG4gKlxuICogQHBhcmFtIGppZCB0aGUgamlkIGluZGljYXRpbmcgdGhlIHZpZGVvIGZvciB3aGljaCB3ZSdyZSBhZGRpbmcgYSBtZW51LlxuICogQHBhcmFtIHBhcmVudEVsZW1lbnQgdGhlIHBhcmVudCBlbGVtZW50IHdoZXJlIHRoaXMgbWVudSB3aWxsIGJlIGFkZGVkXG4gKi9cbmZ1bmN0aW9uIGFkZFJlbW90ZVZpZGVvTWVudShqaWQsIHBhcmVudEVsZW1lbnQpIHtcbiAgICB2YXIgc3BhbkVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgc3BhbkVsZW1lbnQuY2xhc3NOYW1lID0gJ3JlbW90ZXZpZGVvbWVudSc7XG5cbiAgICBwYXJlbnRFbGVtZW50LmFwcGVuZENoaWxkKHNwYW5FbGVtZW50KTtcblxuICAgIHZhciBtZW51RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2knKTtcbiAgICBtZW51RWxlbWVudC5jbGFzc05hbWUgPSAnZmEgZmEtYW5nbGUtZG93bic7XG4gICAgbWVudUVsZW1lbnQudGl0bGUgPSAnUmVtb3RlIHVzZXIgY29udHJvbHMnO1xuICAgIHNwYW5FbGVtZW50LmFwcGVuZENoaWxkKG1lbnVFbGVtZW50KTtcblxuLy8gICAgICAgIDx1bCBjbGFzcz1cInBvcHVwbWVudVwiPlxuLy8gICAgICAgIDxsaT48YSBocmVmPVwiI1wiPk11dGU8L2E+PC9saT5cbi8vICAgICAgICA8bGk+PGEgaHJlZj1cIiNcIj5FamVjdDwvYT48L2xpPlxuLy8gICAgICAgIDwvdWw+XG5cbiAgICB2YXIgcG9wdXBtZW51RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3VsJyk7XG4gICAgcG9wdXBtZW51RWxlbWVudC5jbGFzc05hbWUgPSAncG9wdXBtZW51JztcbiAgICBwb3B1cG1lbnVFbGVtZW50LmlkXG4gICAgICAgID0gJ3JlbW90ZV9wb3B1cG1lbnVfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgc3BhbkVsZW1lbnQuYXBwZW5kQ2hpbGQocG9wdXBtZW51RWxlbWVudCk7XG5cbiAgICB2YXIgbXV0ZU1lbnVJdGVtID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnbGknKTtcbiAgICB2YXIgbXV0ZUxpbmtJdGVtID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuXG4gICAgdmFyIG11dGVkSW5kaWNhdG9yID0gXCI8aSBjbGFzcz0naWNvbi1taWMtZGlzYWJsZWQnPjwvaT5cIjtcblxuICAgIGlmICghbXV0ZWRBdWRpb3NbamlkXSkge1xuICAgICAgICBtdXRlTGlua0l0ZW0uaW5uZXJIVE1MID0gbXV0ZWRJbmRpY2F0b3IgKyAnTXV0ZSc7XG4gICAgICAgIG11dGVMaW5rSXRlbS5jbGFzc05hbWUgPSAnbXV0ZWxpbmsnO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgbXV0ZUxpbmtJdGVtLmlubmVySFRNTCA9IG11dGVkSW5kaWNhdG9yICsgJyBNdXRlZCc7XG4gICAgICAgIG11dGVMaW5rSXRlbS5jbGFzc05hbWUgPSAnbXV0ZWxpbmsgZGlzYWJsZWQnO1xuICAgIH1cblxuICAgIG11dGVMaW5rSXRlbS5vbmNsaWNrID0gZnVuY3Rpb24oKXtcbiAgICAgICAgaWYgKCQodGhpcykuYXR0cignZGlzYWJsZWQnKSAhPSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGlzTXV0ZSA9IG11dGVkQXVkaW9zW2ppZF0gPT0gdHJ1ZTtcbiAgICAgICAgY29ubmVjdGlvbi5tb2RlcmF0ZS5zZXRNdXRlKGppZCwgIWlzTXV0ZSk7XG4gICAgICAgIHBvcHVwbWVudUVsZW1lbnQuc2V0QXR0cmlidXRlKCdzdHlsZScsICdkaXNwbGF5Om5vbmU7Jyk7XG5cbiAgICAgICAgaWYgKGlzTXV0ZSkge1xuICAgICAgICAgICAgdGhpcy5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArICcgTXV0ZWQnO1xuICAgICAgICAgICAgdGhpcy5jbGFzc05hbWUgPSAnbXV0ZWxpbmsgZGlzYWJsZWQnO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArICcgTXV0ZSc7XG4gICAgICAgICAgICB0aGlzLmNsYXNzTmFtZSA9ICdtdXRlbGluayc7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbXV0ZU1lbnVJdGVtLmFwcGVuZENoaWxkKG11dGVMaW5rSXRlbSk7XG4gICAgcG9wdXBtZW51RWxlbWVudC5hcHBlbmRDaGlsZChtdXRlTWVudUl0ZW0pO1xuXG4gICAgdmFyIGVqZWN0SW5kaWNhdG9yID0gXCI8aSBjbGFzcz0nZmEgZmEtZWplY3QnPjwvaT5cIjtcblxuICAgIHZhciBlamVjdE1lbnVJdGVtID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnbGknKTtcbiAgICB2YXIgZWplY3RMaW5rSXRlbSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2EnKTtcbiAgICBlamVjdExpbmtJdGVtLmlubmVySFRNTCA9IGVqZWN0SW5kaWNhdG9yICsgJyBLaWNrIG91dCc7XG4gICAgZWplY3RMaW5rSXRlbS5vbmNsaWNrID0gZnVuY3Rpb24oKXtcbiAgICAgICAgY29ubmVjdGlvbi5tb2RlcmF0ZS5lamVjdChqaWQpO1xuICAgICAgICBwb3B1cG1lbnVFbGVtZW50LnNldEF0dHJpYnV0ZSgnc3R5bGUnLCAnZGlzcGxheTpub25lOycpO1xuICAgIH07XG5cbiAgICBlamVjdE1lbnVJdGVtLmFwcGVuZENoaWxkKGVqZWN0TGlua0l0ZW0pO1xuICAgIHBvcHVwbWVudUVsZW1lbnQuYXBwZW5kQ2hpbGQoZWplY3RNZW51SXRlbSk7XG5cbiAgICB2YXIgcGFkZGluZ1NwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgcGFkZGluZ1NwYW4uY2xhc3NOYW1lID0gJ3BvcHVwbWVudVBhZGRpbmcnO1xuICAgIHBvcHVwbWVudUVsZW1lbnQuYXBwZW5kQ2hpbGQocGFkZGluZ1NwYW4pO1xufVxuXG4vKipcbiAqIFJlbW92ZXMgcmVtb3RlIHZpZGVvIG1lbnUgZWxlbWVudCBmcm9tIHZpZGVvIGVsZW1lbnQgaWRlbnRpZmllZCBieVxuICogZ2l2ZW4gPHR0PnZpZGVvRWxlbWVudElkPC90dD4uXG4gKlxuICogQHBhcmFtIHZpZGVvRWxlbWVudElkIHRoZSBpZCBvZiBsb2NhbCBvciByZW1vdGUgdmlkZW8gZWxlbWVudC5cbiAqL1xuZnVuY3Rpb24gcmVtb3ZlUmVtb3RlVmlkZW9NZW51KHZpZGVvRWxlbWVudElkKSB7XG4gICAgdmFyIG1lbnVTcGFuID0gJCgnIycgKyB2aWRlb0VsZW1lbnRJZCArICc+c3Bhbi5yZW1vdGV2aWRlb21lbnUnKTtcbiAgICBpZiAobWVudVNwYW4ubGVuZ3RoKSB7XG4gICAgICAgIG1lbnVTcGFuLnJlbW92ZSgpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBkYXRhIGZvciB0aGUgaW5kaWNhdG9yXG4gKiBAcGFyYW0gaWQgdGhlIGlkIG9mIHRoZSBpbmRpY2F0b3JcbiAqIEBwYXJhbSBwZXJjZW50IHRoZSBwZXJjZW50IGZvciBjb25uZWN0aW9uIHF1YWxpdHlcbiAqIEBwYXJhbSBvYmplY3QgdGhlIGRhdGFcbiAqL1xuZnVuY3Rpb24gdXBkYXRlU3RhdHNJbmRpY2F0b3IoaWQsIHBlcmNlbnQsIG9iamVjdCkge1xuICAgIGlmKFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW2lkXSlcbiAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbaWRdLnVwZGF0ZUNvbm5lY3Rpb25RdWFsaXR5KHBlcmNlbnQsIG9iamVjdCk7XG59XG5cblxuLyoqXG4gKiBSZXR1cm5zIGFuIGFycmF5IG9mIHRoZSB2aWRlbyBkaW1lbnNpb25zLCBzbyB0aGF0IGl0IGtlZXBzIGl0J3MgYXNwZWN0XG4gKiByYXRpbyBhbmQgZml0cyBhdmFpbGFibGUgYXJlYSB3aXRoIGl0J3MgbGFyZ2VyIGRpbWVuc2lvbi4gVGhpcyBtZXRob2RcbiAqIGVuc3VyZXMgdGhhdCB3aG9sZSB2aWRlbyB3aWxsIGJlIHZpc2libGUgYW5kIGNhbiBsZWF2ZSBlbXB0eSBhcmVhcy5cbiAqXG4gKiBAcmV0dXJuIGFuIGFycmF5IHdpdGggMiBlbGVtZW50cywgdGhlIHZpZGVvIHdpZHRoIGFuZCB0aGUgdmlkZW8gaGVpZ2h0XG4gKi9cbmZ1bmN0aW9uIGdldERlc2t0b3BWaWRlb1NpemUodmlkZW9XaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9IZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFjZUhlaWdodCkge1xuICAgIGlmICghdmlkZW9XaWR0aClcbiAgICAgICAgdmlkZW9XaWR0aCA9IGN1cnJlbnRWaWRlb1dpZHRoO1xuICAgIGlmICghdmlkZW9IZWlnaHQpXG4gICAgICAgIHZpZGVvSGVpZ2h0ID0gY3VycmVudFZpZGVvSGVpZ2h0O1xuXG4gICAgdmFyIGFzcGVjdFJhdGlvID0gdmlkZW9XaWR0aCAvIHZpZGVvSGVpZ2h0O1xuXG4gICAgdmFyIGF2YWlsYWJsZVdpZHRoID0gTWF0aC5tYXgodmlkZW9XaWR0aCwgdmlkZW9TcGFjZVdpZHRoKTtcbiAgICB2YXIgYXZhaWxhYmxlSGVpZ2h0ID0gTWF0aC5tYXgodmlkZW9IZWlnaHQsIHZpZGVvU3BhY2VIZWlnaHQpO1xuXG4gICAgdmlkZW9TcGFjZUhlaWdodCAtPSAkKCcjcmVtb3RlVmlkZW9zJykub3V0ZXJIZWlnaHQoKTtcblxuICAgIGlmIChhdmFpbGFibGVXaWR0aCAvIGFzcGVjdFJhdGlvID49IHZpZGVvU3BhY2VIZWlnaHQpXG4gICAge1xuICAgICAgICBhdmFpbGFibGVIZWlnaHQgPSB2aWRlb1NwYWNlSGVpZ2h0O1xuICAgICAgICBhdmFpbGFibGVXaWR0aCA9IGF2YWlsYWJsZUhlaWdodCAqIGFzcGVjdFJhdGlvO1xuICAgIH1cblxuICAgIGlmIChhdmFpbGFibGVIZWlnaHQgKiBhc3BlY3RSYXRpbyA+PSB2aWRlb1NwYWNlV2lkdGgpXG4gICAge1xuICAgICAgICBhdmFpbGFibGVXaWR0aCA9IHZpZGVvU3BhY2VXaWR0aDtcbiAgICAgICAgYXZhaWxhYmxlSGVpZ2h0ID0gYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbztcbiAgICB9XG5cbiAgICByZXR1cm4gW2F2YWlsYWJsZVdpZHRoLCBhdmFpbGFibGVIZWlnaHRdO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIGVkaXQgZGlzcGxheSBuYW1lIGJ1dHRvbi5cbiAqXG4gKiBAcmV0dXJucyB0aGUgZWRpdCBidXR0b25cbiAqL1xuZnVuY3Rpb24gY3JlYXRlRWRpdERpc3BsYXlOYW1lQnV0dG9uKCkge1xuICAgIHZhciBlZGl0QnV0dG9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuICAgIGVkaXRCdXR0b24uY2xhc3NOYW1lID0gJ2Rpc3BsYXluYW1lJztcbiAgICBVdGlsLnNldFRvb2x0aXAoZWRpdEJ1dHRvbixcbiAgICAgICAgJ0NsaWNrIHRvIGVkaXQgeW91cjxici8+ZGlzcGxheSBuYW1lJyxcbiAgICAgICAgXCJ0b3BcIik7XG4gICAgZWRpdEJ1dHRvbi5pbm5lckhUTUwgPSAnPGkgY2xhc3M9XCJmYSBmYS1wZW5jaWxcIj48L2k+JztcblxuICAgIHJldHVybiBlZGl0QnV0dG9uO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIGVsZW1lbnQgaW5kaWNhdGluZyB0aGUgbW9kZXJhdG9yKG93bmVyKSBvZiB0aGUgY29uZmVyZW5jZS5cbiAqXG4gKiBAcGFyYW0gcGFyZW50RWxlbWVudCB0aGUgcGFyZW50IGVsZW1lbnQgd2hlcmUgdGhlIG93bmVyIGluZGljYXRvciB3aWxsXG4gKiBiZSBhZGRlZFxuICovXG5mdW5jdGlvbiBjcmVhdGVNb2RlcmF0b3JJbmRpY2F0b3JFbGVtZW50KHBhcmVudEVsZW1lbnQpIHtcbiAgICB2YXIgbW9kZXJhdG9ySW5kaWNhdG9yID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaScpO1xuICAgIG1vZGVyYXRvckluZGljYXRvci5jbGFzc05hbWUgPSAnZmEgZmEtc3Rhcic7XG4gICAgcGFyZW50RWxlbWVudC5hcHBlbmRDaGlsZChtb2RlcmF0b3JJbmRpY2F0b3IpO1xuXG4gICAgVXRpbC5zZXRUb29sdGlwKHBhcmVudEVsZW1lbnQsXG4gICAgICAgIFwiVGhlIG93bmVyIG9mPGJyLz50aGlzIGNvbmZlcmVuY2VcIixcbiAgICAgICAgXCJ0b3BcIik7XG59XG5cblxudmFyIFZpZGVvTGF5b3V0ID0gKGZ1bmN0aW9uIChteSkge1xuICAgIG15LmNvbm5lY3Rpb25JbmRpY2F0b3JzID0ge307XG5cbiAgICBteS5pc0luTGFzdE4gPSBmdW5jdGlvbihyZXNvdXJjZSkge1xuICAgICAgICByZXR1cm4gbGFzdE5Db3VudCA8IDAgLy8gbGFzdE4gaXMgZGlzYWJsZWQsIHJldHVybiB0cnVlXG4gICAgICAgICAgICB8fCAobGFzdE5Db3VudCA+IDAgJiYgbGFzdE5FbmRwb2ludHNDYWNoZS5sZW5ndGggPT0gMCkgLy8gbGFzdE5FbmRwb2ludHMgY2FjaGUgbm90IGJ1aWx0IHlldCwgcmV0dXJuIHRydWVcbiAgICAgICAgICAgIHx8IChsYXN0TkVuZHBvaW50c0NhY2hlICYmIGxhc3RORW5kcG9pbnRzQ2FjaGUuaW5kZXhPZihyZXNvdXJjZSkgIT09IC0xKTtcbiAgICB9O1xuXG4gICAgbXkuY2hhbmdlTG9jYWxTdHJlYW0gPSBmdW5jdGlvbiAoc3RyZWFtKSB7XG4gICAgICAgIGNvbm5lY3Rpb24uamluZ2xlLmxvY2FsQXVkaW8gPSBzdHJlYW07XG4gICAgICAgIFZpZGVvTGF5b3V0LmNoYW5nZUxvY2FsVmlkZW8oc3RyZWFtLCB0cnVlKTtcbiAgICB9O1xuXG4gICAgbXkuY2hhbmdlTG9jYWxBdWRpbyA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICBjb25uZWN0aW9uLmppbmdsZS5sb2NhbEF1ZGlvID0gc3RyZWFtO1xuICAgICAgICBSVEMuYXR0YWNoTWVkaWFTdHJlYW0oJCgnI2xvY2FsQXVkaW8nKSwgc3RyZWFtKTtcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xvY2FsQXVkaW8nKS5hdXRvcGxheSA9IHRydWU7XG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NhbEF1ZGlvJykudm9sdW1lID0gMDtcbiAgICAgICAgaWYgKHByZU11dGVkKSB7XG4gICAgICAgICAgICBzZXRBdWRpb011dGVkKHRydWUpO1xuICAgICAgICAgICAgcHJlTXV0ZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBteS5jaGFuZ2VMb2NhbFZpZGVvID0gZnVuY3Rpb24oc3RyZWFtLCBmbGlwWCkge1xuICAgICAgICBjb25uZWN0aW9uLmppbmdsZS5sb2NhbFZpZGVvID0gc3RyZWFtO1xuXG4gICAgICAgIHZhciBsb2NhbFZpZGVvID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndmlkZW8nKTtcbiAgICAgICAgbG9jYWxWaWRlby5pZCA9ICdsb2NhbFZpZGVvXycgKyBSVEMuZ2V0U3RyZWFtSUQoc3RyZWFtKTtcbiAgICAgICAgbG9jYWxWaWRlby5hdXRvcGxheSA9IHRydWU7XG4gICAgICAgIGxvY2FsVmlkZW8udm9sdW1lID0gMDsgLy8gaXMgaXQgcmVxdWlyZWQgaWYgYXVkaW8gaXMgc2VwYXJhdGVkID9cbiAgICAgICAgbG9jYWxWaWRlby5vbmNvbnRleHRtZW51ID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gZmFsc2U7IH07XG5cbiAgICAgICAgdmFyIGxvY2FsVmlkZW9Db250YWluZXIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9jYWxWaWRlb1dyYXBwZXInKTtcbiAgICAgICAgbG9jYWxWaWRlb0NvbnRhaW5lci5hcHBlbmRDaGlsZChsb2NhbFZpZGVvKTtcblxuICAgICAgICAvLyBTZXQgZGVmYXVsdCBkaXNwbGF5IG5hbWUuXG4gICAgICAgIHNldERpc3BsYXlOYW1lKCdsb2NhbFZpZGVvQ29udGFpbmVyJyk7XG5cbiAgICAgICAgaWYoIVZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW1wibG9jYWxWaWRlb0NvbnRhaW5lclwiXSkge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbXCJsb2NhbFZpZGVvQ29udGFpbmVyXCJdXG4gICAgICAgICAgICAgICAgPSBuZXcgQ29ubmVjdGlvbkluZGljYXRvcigkKFwiI2xvY2FsVmlkZW9Db250YWluZXJcIilbMF0sIG51bGwsIFZpZGVvTGF5b3V0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIEF1ZGlvTGV2ZWxzLnVwZGF0ZUF1ZGlvTGV2ZWxDYW52YXMobnVsbCwgVmlkZW9MYXlvdXQpO1xuXG4gICAgICAgIHZhciBsb2NhbFZpZGVvU2VsZWN0b3IgPSAkKCcjJyArIGxvY2FsVmlkZW8uaWQpO1xuICAgICAgICAvLyBBZGQgY2xpY2sgaGFuZGxlciB0byBib3RoIHZpZGVvIGFuZCB2aWRlbyB3cmFwcGVyIGVsZW1lbnRzIGluIGNhc2VcbiAgICAgICAgLy8gdGhlcmUncyBubyB2aWRlby5cbiAgICAgICAgbG9jYWxWaWRlb1NlbGVjdG9yLmNsaWNrKGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5oYW5kbGVWaWRlb1RodW1iQ2xpY2tlZChcbiAgICAgICAgICAgICAgICBSVEMuZ2V0VmlkZW9TcmMobG9jYWxWaWRlbyksXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCkpO1xuICAgICAgICB9KTtcbiAgICAgICAgJCgnI2xvY2FsVmlkZW9Db250YWluZXInKS5jbGljayhmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuaGFuZGxlVmlkZW9UaHVtYkNsaWNrZWQoXG4gICAgICAgICAgICAgICAgUlRDLmdldFZpZGVvU3JjKGxvY2FsVmlkZW8pLFxuICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQWRkIGhvdmVyIGhhbmRsZXJcbiAgICAgICAgJCgnI2xvY2FsVmlkZW9Db250YWluZXInKS5ob3ZlcihcbiAgICAgICAgICAgIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dEaXNwbGF5TmFtZSgnbG9jYWxWaWRlb0NvbnRhaW5lcicsIHRydWUpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIGlmICghVmlkZW9MYXlvdXQuaXNMYXJnZVZpZGVvVmlzaWJsZSgpXG4gICAgICAgICAgICAgICAgICAgICAgICB8fCBSVEMuZ2V0VmlkZW9TcmMobG9jYWxWaWRlbykgIT09IFJUQy5nZXRWaWRlb1NyYygkKCcjbGFyZ2VWaWRlbycpWzBdKSlcbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2hvd0Rpc3BsYXlOYW1lKCdsb2NhbFZpZGVvQ29udGFpbmVyJywgZmFsc2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgICAvLyBBZGQgc3RyZWFtIGVuZGVkIGhhbmRsZXJcbiAgICAgICAgc3RyZWFtLm9uZW5kZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBsb2NhbFZpZGVvQ29udGFpbmVyLnJlbW92ZUNoaWxkKGxvY2FsVmlkZW8pO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlUmVtb3ZlZFZpZGVvKFJUQy5nZXRWaWRlb1NyYyhsb2NhbFZpZGVvKSk7XG4gICAgICAgIH07XG4gICAgICAgIC8vIEZsaXAgdmlkZW8geCBheGlzIGlmIG5lZWRlZFxuICAgICAgICBmbGlwWExvY2FsVmlkZW8gPSBmbGlwWDtcbiAgICAgICAgaWYgKGZsaXBYKSB7XG4gICAgICAgICAgICBsb2NhbFZpZGVvU2VsZWN0b3IuYWRkQ2xhc3MoXCJmbGlwVmlkZW9YXCIpO1xuICAgICAgICB9XG4gICAgICAgIC8vIEF0dGFjaCBXZWJSVEMgc3RyZWFtXG4gICAgICAgIHZhciB2aWRlb1N0cmVhbSA9IHNpbXVsY2FzdC5nZXRMb2NhbFZpZGVvU3RyZWFtKCk7XG4gICAgICAgIFJUQy5hdHRhY2hNZWRpYVN0cmVhbShsb2NhbFZpZGVvU2VsZWN0b3IsIHZpZGVvU3RyZWFtKTtcblxuICAgICAgICBsb2NhbFZpZGVvU3JjID0gUlRDLmdldFZpZGVvU3JjKGxvY2FsVmlkZW8pO1xuXG4gICAgICAgIHZhciBteVJlc291cmNlSmlkID0gbnVsbDtcbiAgICAgICAgaWYoY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZClcbiAgICAgICAge1xuICAgICAgICAgICBteVJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCk7XG4gICAgICAgIH1cbiAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlTGFyZ2VWaWRlbyhsb2NhbFZpZGVvU3JjLCAwLFxuICAgICAgICAgICAgbXlSZXNvdXJjZUppZCk7XG5cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIHJlbW92ZWQgdmlkZW8gaXMgY3VycmVudGx5IGRpc3BsYXllZCBhbmQgdHJpZXMgdG8gZGlzcGxheVxuICAgICAqIGFub3RoZXIgb25lIGluc3RlYWQuXG4gICAgICogQHBhcmFtIHJlbW92ZWRWaWRlb1NyYyBzcmMgc3RyZWFtIGlkZW50aWZpZXIgb2YgdGhlIHZpZGVvLlxuICAgICAqL1xuICAgIG15LnVwZGF0ZVJlbW92ZWRWaWRlbyA9IGZ1bmN0aW9uKHJlbW92ZWRWaWRlb1NyYykge1xuICAgICAgICBpZiAocmVtb3ZlZFZpZGVvU3JjID09PSBSVEMuZ2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSkpIHtcbiAgICAgICAgICAgIC8vIHRoaXMgaXMgY3VycmVudGx5IGRpc3BsYXllZCBhcyBsYXJnZVxuICAgICAgICAgICAgLy8gcGljayB0aGUgbGFzdCB2aXNpYmxlIHZpZGVvIGluIHRoZSByb3dcbiAgICAgICAgICAgIC8vIGlmIG5vYm9keSBlbHNlIGlzIGxlZnQsIHRoaXMgcGlja3MgdGhlIGxvY2FsIHZpZGVvXG4gICAgICAgICAgICB2YXIgcGlja1xuICAgICAgICAgICAgICAgID0gJCgnI3JlbW90ZVZpZGVvcz5zcGFuW2lkIT1cIm1peGVkc3RyZWFtXCJdOnZpc2libGU6bGFzdD52aWRlbycpXG4gICAgICAgICAgICAgICAgICAgIC5nZXQoMCk7XG5cbiAgICAgICAgICAgIGlmICghcGljaykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkxhc3QgdmlzaWJsZSB2aWRlbyBubyBsb25nZXIgZXhpc3RzXCIpO1xuICAgICAgICAgICAgICAgIHBpY2sgPSAkKCcjcmVtb3RlVmlkZW9zPnNwYW5baWQhPVwibWl4ZWRzdHJlYW1cIl0+dmlkZW8nKS5nZXQoMCk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIXBpY2sgfHwgIVJUQy5nZXRWaWRlb1NyYyhwaWNrKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBUcnkgbG9jYWwgdmlkZW9cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiRmFsbGJhY2sgdG8gbG9jYWwgdmlkZW8uLi5cIik7XG4gICAgICAgICAgICAgICAgICAgIHBpY2sgPSAkKCcjcmVtb3RlVmlkZW9zPnNwYW4+c3Bhbj52aWRlbycpLmdldCgwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG11dGUgaWYgbG9jYWx2aWRlb1xuICAgICAgICAgICAgaWYgKHBpY2spIHtcbiAgICAgICAgICAgICAgICB2YXIgY29udGFpbmVyID0gcGljay5wYXJlbnROb2RlO1xuICAgICAgICAgICAgICAgIHZhciBqaWQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGlmKGNvbnRhaW5lcilcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGlmKGNvbnRhaW5lci5pZCA9PSBcImxvY2FsVmlkZW9XcmFwcGVyXCIpXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgamlkID0gVmlkZW9MYXlvdXQuZ2V0UGVlckNvbnRhaW5lclJlc291cmNlSmlkKGNvbnRhaW5lcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKFJUQy5nZXRWaWRlb1NyYyhwaWNrKSwgcGljay52b2x1bWUsIGppZCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIkZhaWxlZCB0byBlbGVjdCBsYXJnZSB2aWRlb1wiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgXG4gICAgbXkub25SZW1vdGVTdHJlYW1BZGRlZCA9IGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgdmFyIGNvbnRhaW5lcjtcbiAgICAgICAgdmFyIHJlbW90ZXMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmVtb3RlVmlkZW9zJyk7XG5cbiAgICAgICAgaWYgKHN0cmVhbS5wZWVyamlkKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5lbnN1cmVQZWVyQ29udGFpbmVyRXhpc3RzKHN0cmVhbS5wZWVyamlkKTtcblxuICAgICAgICAgICAgY29udGFpbmVyICA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFxuICAgICAgICAgICAgICAgICAgICAncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKHN0cmVhbS5wZWVyamlkKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgaWQgPSBzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKS5pZDtcbiAgICAgICAgICAgIGlmIChpZCAhPT0gJ21peGVkbXNsYWJlbCdcbiAgICAgICAgICAgICAgICAvLyBGSVhNRTogZGVmYXVsdCBzdHJlYW0gaXMgYWRkZWQgYWx3YXlzIHdpdGggbmV3IGZvY3VzXG4gICAgICAgICAgICAgICAgLy8gKHRvIGJlIGludmVzdGlnYXRlZClcbiAgICAgICAgICAgICAgICAmJiBpZCAhPT0gJ2RlZmF1bHQnKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignY2FuIG5vdCBhc3NvY2lhdGUgc3RyZWFtJyxcbiAgICAgICAgICAgICAgICAgICAgaWQsXG4gICAgICAgICAgICAgICAgICAgICd3aXRoIGEgcGFydGljaXBhbnQnKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBkb24ndCB3YW50IHRvIGFkZCBpdCBoZXJlIHNpbmNlIGl0IHdpbGwgY2F1c2UgdHJvdWJsZXNcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBGSVhNRTogZm9yIHRoZSBtaXhlZCBtcyB3ZSBkb250IG5lZWQgYSB2aWRlbyAtLSBjdXJyZW50bHlcbiAgICAgICAgICAgIGNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICAgICAgICAgIGNvbnRhaW5lci5pZCA9ICdtaXhlZHN0cmVhbSc7XG4gICAgICAgICAgICBjb250YWluZXIuY2xhc3NOYW1lID0gJ3ZpZGVvY29udGFpbmVyJztcbiAgICAgICAgICAgIHJlbW90ZXMuYXBwZW5kQ2hpbGQoY29udGFpbmVyKTtcbiAgICAgICAgICAgIFV0aWwucGxheVNvdW5kTm90aWZpY2F0aW9uKCd1c2VySm9pbmVkJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5hZGRSZW1vdGVTdHJlYW1FbGVtZW50KCBjb250YWluZXIsXG4gICAgICAgICAgICAgICAgc3RyZWFtLnNpZCxcbiAgICAgICAgICAgICAgICBzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKSxcbiAgICAgICAgICAgICAgICBzdHJlYW0ucGVlcmppZCxcbiAgICAgICAgICAgICAgICBzdHJlYW0uc3NyYyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBteS5nZXRMYXJnZVZpZGVvU3RhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBsYXJnZVZpZGVvU3RhdGU7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIGxhcmdlIHZpZGVvIHdpdGggdGhlIGdpdmVuIG5ldyB2aWRlbyBzb3VyY2UuXG4gICAgICovXG4gICAgbXkudXBkYXRlTGFyZ2VWaWRlbyA9IGZ1bmN0aW9uKG5ld1NyYywgdm9sLCByZXNvdXJjZUppZCkge1xuICAgICAgICBjb25zb2xlLmxvZygnaG92ZXIgaW4nLCBuZXdTcmMpO1xuXG4gICAgICAgIGlmIChSVEMuZ2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSkgIT09IG5ld1NyYykge1xuXG4gICAgICAgICAgICAkKCcjYWN0aXZlU3BlYWtlcicpLmNzcygndmlzaWJpbGl0eScsICdoaWRkZW4nKTtcbiAgICAgICAgICAgIC8vIER1ZSB0byB0aGUgc2ltdWxjYXN0IHRoZSBsb2NhbFZpZGVvU3JjIG1heSBoYXZlIGNoYW5nZWQgd2hlbiB0aGVcbiAgICAgICAgICAgIC8vIGZhZGVPdXQgZXZlbnQgdHJpZ2dlcnMuIEluIHRoYXQgY2FzZSB0aGUgZ2V0SmlkRnJvbVZpZGVvU3JjIGFuZFxuICAgICAgICAgICAgLy8gaXNWaWRlb1NyY0Rlc2t0b3AgbWV0aG9kcyB3aWxsIG5vdCBmdW5jdGlvbiBjb3JyZWN0bHkuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gQWxzbywgYWdhaW4gZHVlIHRvIHRoZSBzaW11bGNhc3QsIHRoZSB1cGRhdGVMYXJnZVZpZGVvIG1ldGhvZCBjYW5cbiAgICAgICAgICAgIC8vIGJlIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyBhbG1vc3Qgc2ltdWx0YW5lb3VzbHkuIFRoZXJlZm9yZSwgd2VcbiAgICAgICAgICAgIC8vIHN0b3JlIHRoZSBzdGF0ZSBoZXJlIGFuZCB1cGRhdGUgb25seSBvbmNlLlxuXG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUubmV3U3JjID0gbmV3U3JjO1xuICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLmlzVmlzaWJsZSA9ICQoJyNsYXJnZVZpZGVvJykuaXMoJzp2aXNpYmxlJyk7XG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUuaXNEZXNrdG9wID0gaXNWaWRlb1NyY0Rlc2t0b3AocmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgaWYoamlkMlNzcmNbbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZF0gfHxcbiAgICAgICAgICAgICAgICAoY29ubmVjdGlvbiAmJiBjb25uZWN0aW9uLmVtdWMubXlyb29tamlkICYmXG4gICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQgPT09XG4gICAgICAgICAgICAgICAgICAgIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpKSkge1xuICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5vbGRSZXNvdXJjZUppZCA9IGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5vbGRSZXNvdXJjZUppZCA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkID0gcmVzb3VyY2VKaWQ7XG5cbiAgICAgICAgICAgIC8vIFNjcmVlbiBzdHJlYW0gaXMgYWxyZWFkeSByb3RhdGVkXG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUuZmxpcFggPSAobmV3U3JjID09PSBsb2NhbFZpZGVvU3JjKSAmJiBmbGlwWExvY2FsVmlkZW87XG5cbiAgICAgICAgICAgIHZhciB1c2VyQ2hhbmdlZCA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKGxhcmdlVmlkZW9TdGF0ZS5vbGRSZXNvdXJjZUppZCAhPT0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgICAgIHVzZXJDaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAvLyB3ZSB3YW50IHRoZSBub3RpZmljYXRpb24gdG8gdHJpZ2dlciBldmVuIGlmIHVzZXJKaWQgaXMgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIC8vIG9yIG51bGwuXG4gICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcihcInNlbGVjdGVkZW5kcG9pbnRjaGFuZ2VkXCIsIFtsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghbGFyZ2VWaWRlb1N0YXRlLnVwZGF0ZUluUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUudXBkYXRlSW5Qcm9ncmVzcyA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICB2YXIgZG9VcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgQXZhdGFyLnVwZGF0ZUFjdGl2ZVNwZWFrZXJBdmF0YXJTcmMoXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuZmluZEppZEZyb21SZXNvdXJjZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCF1c2VyQ2hhbmdlZCAmJiBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQgIT09IG51bGwgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIFJUQy5nZXRWaWRlb1NyYygkKGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkKVswXSkgPT09IG5ld1NyYylcbiAgICAgICAgICAgICAgICAgICAge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oJ1N3aXRjaGluZyB0byBwcmVsb2FkZWQgdmlkZW8nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhdHRyaWJ1dGVzID0gJCgnI2xhcmdlVmlkZW8nKS5wcm9wKFwiYXR0cmlidXRlc1wiKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbG9vcCB0aHJvdWdoIGxhcmdlVmlkZW8gYXR0cmlidXRlcyBhbmQgYXBwbHkgdGhlbSBvblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJlbG9hZC5cbiAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhdHRyaWJ1dGVzLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubmFtZSAhPT0gJ2lkJyAmJiB0aGlzLm5hbWUgIT09ICdzcmMnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkLmF0dHIodGhpcy5uYW1lLCB0aGlzLnZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQuYXBwZW5kVG8oJCgnI2xhcmdlVmlkZW9Db250YWluZXInKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmF0dHIoJ2lkJywgJ3ByZXZpb3VzTGFyZ2VWaWRlbycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQuYXR0cignaWQnLCAnbGFyZ2VWaWRlbycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgJCgnI3ByZXZpb3VzTGFyZ2VWaWRlbycpLnJlbW92ZSgpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZC5vbignbG9hZGVkbWV0YWRhdGEnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRWaWRlb1dpZHRoID0gdGhpcy52aWRlb1dpZHRoO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRWaWRlb0hlaWdodCA9IHRoaXMudmlkZW9IZWlnaHQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQucG9zaXRpb25MYXJnZShjdXJyZW50VmlkZW9XaWR0aCwgY3VycmVudFZpZGVvSGVpZ2h0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWRfc3NyYyA9IDA7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBSVEMuc2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSwgbGFyZ2VWaWRlb1N0YXRlLm5ld1NyYyk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICB2YXIgdmlkZW9UcmFuc2Zvcm0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbGFyZ2VWaWRlbycpXG4gICAgICAgICAgICAgICAgICAgICAgICAuc3R5bGUud2Via2l0VHJhbnNmb3JtO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChsYXJnZVZpZGVvU3RhdGUuZmxpcFggJiYgdmlkZW9UcmFuc2Zvcm0gIT09ICdzY2FsZVgoLTEpJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xhcmdlVmlkZW8nKS5zdHlsZS53ZWJraXRUcmFuc2Zvcm1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IFwic2NhbGVYKC0xKVwiO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKCFsYXJnZVZpZGVvU3RhdGUuZmxpcFggJiYgdmlkZW9UcmFuc2Zvcm0gPT09ICdzY2FsZVgoLTEpJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xhcmdlVmlkZW8nKS5zdHlsZS53ZWJraXRUcmFuc2Zvcm1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IFwibm9uZVwiO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQ2hhbmdlIHRoZSB3YXkgd2UnbGwgYmUgbWVhc3VyaW5nIGFuZCBwb3NpdGlvbmluZyBsYXJnZSB2aWRlb1xuXG4gICAgICAgICAgICAgICAgICAgIGdldFZpZGVvU2l6ZSA9IGxhcmdlVmlkZW9TdGF0ZS5pc0Rlc2t0b3BcbiAgICAgICAgICAgICAgICAgICAgICAgID8gZ2V0RGVza3RvcFZpZGVvU2l6ZVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBnZXRDYW1lcmFWaWRlb1NpemU7XG4gICAgICAgICAgICAgICAgICAgIGdldFZpZGVvUG9zaXRpb24gPSBsYXJnZVZpZGVvU3RhdGUuaXNEZXNrdG9wXG4gICAgICAgICAgICAgICAgICAgICAgICA/IGdldERlc2t0b3BWaWRlb1Bvc2l0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGdldENhbWVyYVZpZGVvUG9zaXRpb247XG5cblxuICAgICAgICAgICAgICAgICAgICAvLyBPbmx5IGlmIHRoZSBsYXJnZSB2aWRlbyBpcyBjdXJyZW50bHkgdmlzaWJsZS5cbiAgICAgICAgICAgICAgICAgICAgLy8gRGlzYWJsZSBwcmV2aW91cyBkb21pbmFudCBzcGVha2VyIHZpZGVvLlxuICAgICAgICAgICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLm9sZFJlc291cmNlSmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5lbmFibGVEb21pbmFudFNwZWFrZXIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLm9sZFJlc291cmNlSmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIEVuYWJsZSBuZXcgZG9taW5hbnQgc3BlYWtlciBpbiB0aGUgcmVtb3RlIHZpZGVvcyBzZWN0aW9uLlxuICAgICAgICAgICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5hYmxlRG9taW5hbnRTcGVha2VyKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpZiAodXNlckNoYW5nZWQgJiYgbGFyZ2VWaWRlb1N0YXRlLmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdXNpbmcgXCJ0aGlzXCIgc2hvdWxkIGJlIG9rIGJlY2F1c2Ugd2UncmUgY2FsbGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmcm9tIHdpdGhpbiB0aGUgZmFkZU91dCBldmVudC5cbiAgICAgICAgICAgICAgICAgICAgICAgICQodGhpcykuZmFkZUluKDMwMCk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpZih1c2VyQ2hhbmdlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgQXZhdGFyLnNob3dVc2VyQXZhdGFyKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uZW11Yy5maW5kSmlkRnJvbVJlc291cmNlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUub2xkUmVzb3VyY2VKaWQpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51cGRhdGVJblByb2dyZXNzID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIGlmICh1c2VyQ2hhbmdlZCkge1xuICAgICAgICAgICAgICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmZhZGVPdXQoMzAwLCBkb1VwZGF0ZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZG9VcGRhdGUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBBdmF0YXIuc2hvd1VzZXJBdmF0YXIoXG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmZpbmRKaWRGcm9tUmVzb3VyY2UoXG4gICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQpKTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgIG15LmhhbmRsZVZpZGVvVGh1bWJDbGlja2VkID0gZnVuY3Rpb24odmlkZW9TcmMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub1Bpbm5lZEVuZHBvaW50Q2hhbmdlZEV2ZW50LCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc291cmNlSmlkKSB7XG4gICAgICAgIC8vIFJlc3RvcmUgc3R5bGUgZm9yIHByZXZpb3VzbHkgZm9jdXNlZCB2aWRlb1xuICAgICAgICB2YXIgb2xkQ29udGFpbmVyID0gbnVsbDtcbiAgICAgICAgaWYoZm9jdXNlZFZpZGVvSW5mbykge1xuICAgICAgICAgICAgdmFyIGZvY3VzUmVzb3VyY2VKaWQgPSBmb2N1c2VkVmlkZW9JbmZvLnJlc291cmNlSmlkO1xuICAgICAgICAgICAgb2xkQ29udGFpbmVyID0gZ2V0UGFydGljaXBhbnRDb250YWluZXIoZm9jdXNSZXNvdXJjZUppZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob2xkQ29udGFpbmVyKSB7XG4gICAgICAgICAgICBvbGRDb250YWluZXIucmVtb3ZlQ2xhc3MoXCJ2aWRlb0NvbnRhaW5lckZvY3VzZWRcIik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVbmxvY2sgY3VycmVudCBmb2N1c2VkLlxuICAgICAgICBpZiAoZm9jdXNlZFZpZGVvSW5mbyAmJiBmb2N1c2VkVmlkZW9JbmZvLnNyYyA9PT0gdmlkZW9TcmMpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGZvY3VzZWRWaWRlb0luZm8gPSBudWxsO1xuICAgICAgICAgICAgdmFyIGRvbWluYW50U3BlYWtlclZpZGVvID0gbnVsbDtcbiAgICAgICAgICAgIC8vIEVuYWJsZSB0aGUgY3VycmVudGx5IHNldCBkb21pbmFudCBzcGVha2VyLlxuICAgICAgICAgICAgaWYgKGN1cnJlbnREb21pbmFudFNwZWFrZXIpIHtcbiAgICAgICAgICAgICAgICBkb21pbmFudFNwZWFrZXJWaWRlb1xuICAgICAgICAgICAgICAgICAgICA9ICQoJyNwYXJ0aWNpcGFudF8nICsgY3VycmVudERvbWluYW50U3BlYWtlciArICc+dmlkZW8nKVxuICAgICAgICAgICAgICAgICAgICAgICAgLmdldCgwKTtcblxuICAgICAgICAgICAgICAgIGlmIChkb21pbmFudFNwZWFrZXJWaWRlbykge1xuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKFxuICAgICAgICAgICAgICAgICAgICAgICAgUlRDLmdldFZpZGVvU3JjKGRvbWluYW50U3BlYWtlclZpZGVvKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RG9taW5hbnRTcGVha2VyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghbm9QaW5uZWRFbmRwb2ludENoYW5nZWRFdmVudCkge1xuICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoXCJwaW5uZWRlbmRwb2ludGNoYW5nZWRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBMb2NrIG5ldyB2aWRlb1xuICAgICAgICBmb2N1c2VkVmlkZW9JbmZvID0ge1xuICAgICAgICAgICAgc3JjOiB2aWRlb1NyYyxcbiAgICAgICAgICAgIHJlc291cmNlSmlkOiByZXNvdXJjZUppZFxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFVwZGF0ZSBmb2N1c2VkL3Bpbm5lZCBpbnRlcmZhY2UuXG4gICAgICAgIGlmIChyZXNvdXJjZUppZClcbiAgICAgICAge1xuICAgICAgICAgICAgdmFyIGNvbnRhaW5lciA9IGdldFBhcnRpY2lwYW50Q29udGFpbmVyKHJlc291cmNlSmlkKTtcbiAgICAgICAgICAgIGNvbnRhaW5lci5hZGRDbGFzcyhcInZpZGVvQ29udGFpbmVyRm9jdXNlZFwiKTtcblxuICAgICAgICAgICAgaWYgKCFub1Bpbm5lZEVuZHBvaW50Q2hhbmdlZEV2ZW50KSB7XG4gICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcihcInBpbm5lZGVuZHBvaW50Y2hhbmdlZFwiLCBbcmVzb3VyY2VKaWRdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgkKCcjbGFyZ2VWaWRlbycpLmF0dHIoJ3NyYycpID09PSB2aWRlb1NyYyAmJlxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuaXNMYXJnZVZpZGVvT25Ub3AoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVHJpZ2dlcnMgYSBcInZpZGVvLnNlbGVjdGVkXCIgZXZlbnQuIFRoZSBcImZhbHNlXCIgcGFyYW1ldGVyIGluZGljYXRlc1xuICAgICAgICAvLyB0aGlzIGlzbid0IGEgcHJlemkuXG4gICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoXCJ2aWRlby5zZWxlY3RlZFwiLCBbZmFsc2VdKTtcblxuICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKHZpZGVvU3JjLCAxLCByZXNvdXJjZUppZCk7XG5cbiAgICAgICAgJCgnYXVkaW8nKS5lYWNoKGZ1bmN0aW9uIChpZHgsIGVsKSB7XG4gICAgICAgICAgICBpZiAoZWwuaWQuaW5kZXhPZignbWl4ZWRtc2xhYmVsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgZWwudm9sdW1lID0gMDtcbiAgICAgICAgICAgICAgICBlbC52b2x1bWUgPSAxO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUG9zaXRpb25zIHRoZSBsYXJnZSB2aWRlby5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB2aWRlb1dpZHRoIHRoZSBzdHJlYW0gdmlkZW8gd2lkdGhcbiAgICAgKiBAcGFyYW0gdmlkZW9IZWlnaHQgdGhlIHN0cmVhbSB2aWRlbyBoZWlnaHRcbiAgICAgKi9cbiAgICBteS5wb3NpdGlvbkxhcmdlID0gZnVuY3Rpb24gKHZpZGVvV2lkdGgsIHZpZGVvSGVpZ2h0KSB7XG4gICAgICAgIHZhciB2aWRlb1NwYWNlV2lkdGggPSAkKCcjdmlkZW9zcGFjZScpLndpZHRoKCk7XG4gICAgICAgIHZhciB2aWRlb1NwYWNlSGVpZ2h0ID0gd2luZG93LmlubmVySGVpZ2h0O1xuXG4gICAgICAgIHZhciB2aWRlb1NpemUgPSBnZXRWaWRlb1NpemUodmlkZW9XaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb0hlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFjZUhlaWdodCk7XG5cbiAgICAgICAgdmFyIGxhcmdlVmlkZW9XaWR0aCA9IHZpZGVvU2l6ZVswXTtcbiAgICAgICAgdmFyIGxhcmdlVmlkZW9IZWlnaHQgPSB2aWRlb1NpemVbMV07XG5cbiAgICAgICAgdmFyIHZpZGVvUG9zaXRpb24gPSBnZXRWaWRlb1Bvc2l0aW9uKGxhcmdlVmlkZW9XaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9IZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlSGVpZ2h0KTtcblxuICAgICAgICB2YXIgaG9yaXpvbnRhbEluZGVudCA9IHZpZGVvUG9zaXRpb25bMF07XG4gICAgICAgIHZhciB2ZXJ0aWNhbEluZGVudCA9IHZpZGVvUG9zaXRpb25bMV07XG5cbiAgICAgICAgcG9zaXRpb25WaWRlbygkKCcjbGFyZ2VWaWRlbycpLFxuICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9XaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgIGhvcml6b250YWxJbmRlbnQsIHZlcnRpY2FsSW5kZW50KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2hvd3MvaGlkZXMgdGhlIGxhcmdlIHZpZGVvLlxuICAgICAqL1xuICAgIG15LnNldExhcmdlVmlkZW9WaXNpYmxlID0gZnVuY3Rpb24oaXNWaXNpYmxlKSB7XG4gICAgICAgIHZhciByZXNvdXJjZUppZCA9IGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQ7XG5cbiAgICAgICAgaWYgKGlzVmlzaWJsZSkge1xuICAgICAgICAgICAgJCgnI2xhcmdlVmlkZW8nKS5jc3Moe3Zpc2liaWxpdHk6ICd2aXNpYmxlJ30pO1xuICAgICAgICAgICAgJCgnLndhdGVybWFyaycpLmNzcyh7dmlzaWJpbGl0eTogJ3Zpc2libGUnfSk7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5lbmFibGVEb21pbmFudFNwZWFrZXIocmVzb3VyY2VKaWQsIHRydWUpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgJCgnI2xhcmdlVmlkZW8nKS5jc3Moe3Zpc2liaWxpdHk6ICdoaWRkZW4nfSk7XG4gICAgICAgICAgICAkKCcjYWN0aXZlU3BlYWtlcicpLmNzcygndmlzaWJpbGl0eScsICdoaWRkZW4nKTtcbiAgICAgICAgICAgICQoJy53YXRlcm1hcmsnKS5jc3Moe3Zpc2liaWxpdHk6ICdoaWRkZW4nfSk7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5lbmFibGVEb21pbmFudFNwZWFrZXIocmVzb3VyY2VKaWQsIGZhbHNlKTtcbiAgICAgICAgICAgIGlmKGZvY3VzZWRWaWRlb0luZm8pIHtcbiAgICAgICAgICAgICAgICB2YXIgZm9jdXNSZXNvdXJjZUppZCA9IGZvY3VzZWRWaWRlb0luZm8ucmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICAgICAgdmFyIG9sZENvbnRhaW5lciA9IGdldFBhcnRpY2lwYW50Q29udGFpbmVyKGZvY3VzUmVzb3VyY2VKaWQpO1xuXG4gICAgICAgICAgICAgICAgaWYgKG9sZENvbnRhaW5lciAmJiBvbGRDb250YWluZXIubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBvbGRDb250YWluZXIucmVtb3ZlQ2xhc3MoXCJ2aWRlb0NvbnRhaW5lckZvY3VzZWRcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGZvY3VzZWRWaWRlb0luZm8gPSBudWxsO1xuICAgICAgICAgICAgICAgIGlmKGZvY3VzUmVzb3VyY2VKaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgQXZhdGFyLnNob3dVc2VyQXZhdGFyKFxuICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmZpbmRKaWRGcm9tUmVzb3VyY2UoZm9jdXNSZXNvdXJjZUppZCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGxhcmdlIHZpZGVvIGlzIGN1cnJlbnRseSB2aXNpYmxlLlxuICAgICAqXG4gICAgICogQHJldHVybiA8dHQ+dHJ1ZTwvdHQ+IGlmIHZpc2libGUsIDx0dD5mYWxzZTwvdHQ+IC0gb3RoZXJ3aXNlXG4gICAgICovXG4gICAgbXkuaXNMYXJnZVZpZGVvVmlzaWJsZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gJCgnI2xhcmdlVmlkZW8nKS5pcygnOnZpc2libGUnKTtcbiAgICB9O1xuXG4gICAgbXkuaXNMYXJnZVZpZGVvT25Ub3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBFdGhlcnBhZCA9IHJlcXVpcmUoXCIuLi9ldGhlcnBhZC9FdGhlcnBhZFwiKTtcbiAgICAgICAgdmFyIFByZXppID0gcmVxdWlyZShcIi4uL3ByZXppL1ByZXppXCIpO1xuICAgICAgICByZXR1cm4gIVByZXppLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpICYmICFFdGhlcnBhZC5pc1Zpc2libGUoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGNvbnRhaW5lciBmb3IgcGFydGljaXBhbnQgaWRlbnRpZmllZCBieSBnaXZlbiBwZWVySmlkIGV4aXN0c1xuICAgICAqIGluIHRoZSBkb2N1bWVudCBhbmQgY3JlYXRlcyBpdCBldmVudHVhbGx5LlxuICAgICAqIFxuICAgICAqIEBwYXJhbSBwZWVySmlkIHBlZXIgSmlkIHRvIGNoZWNrLlxuICAgICAqIEBwYXJhbSB1c2VySWQgdXNlciBlbWFpbCBvciBpZCBmb3Igc2V0dGluZyB0aGUgYXZhdGFyXG4gICAgICogXG4gICAgICogQHJldHVybiBSZXR1cm5zIDx0dD50cnVlPC90dD4gaWYgdGhlIHBlZXIgY29udGFpbmVyIGV4aXN0cyxcbiAgICAgKiA8dHQ+ZmFsc2U8L3R0PiAtIG90aGVyd2lzZVxuICAgICAqL1xuICAgIG15LmVuc3VyZVBlZXJDb250YWluZXJFeGlzdHMgPSBmdW5jdGlvbihwZWVySmlkLCB1c2VySWQpIHtcbiAgICAgICAgQ29udGFjdExpc3QuZW5zdXJlQWRkQ29udGFjdChwZWVySmlkLCB1c2VySWQpO1xuXG4gICAgICAgIHZhciByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKHBlZXJKaWQpO1xuXG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9ICdwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQ7XG5cbiAgICAgICAgaWYgKCQoJyMnICsgdmlkZW9TcGFuSWQpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIC8vIElmIHRoZXJlJ3MgYmVlbiBhIGZvY3VzIGNoYW5nZSwgbWFrZSBzdXJlIHdlIGFkZCBmb2N1cyByZWxhdGVkXG4gICAgICAgICAgICAvLyBpbnRlcmZhY2UhIVxuICAgICAgICAgICAgaWYgKE1vZGVyYXRvci5pc01vZGVyYXRvcigpICYmICFNb2RlcmF0b3IuaXNQZWVyTW9kZXJhdG9yKHBlZXJKaWQpXG4gICAgICAgICAgICAgICAgJiYgJCgnI3JlbW90ZV9wb3B1cG1lbnVfJyArIHJlc291cmNlSmlkKS5sZW5ndGggPD0gMCkge1xuICAgICAgICAgICAgICAgIGFkZFJlbW90ZVZpZGVvTWVudShwZWVySmlkLFxuICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh2aWRlb1NwYW5JZCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIGNvbnRhaW5lciA9XG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuYWRkUmVtb3RlVmlkZW9Db250YWluZXIocGVlckppZCwgdmlkZW9TcGFuSWQsIHVzZXJJZCk7XG4gICAgICAgICAgICBBdmF0YXIuc2V0VXNlckF2YXRhcihwZWVySmlkLCB1c2VySWQpO1xuICAgICAgICAgICAgLy8gU2V0IGRlZmF1bHQgZGlzcGxheSBuYW1lLlxuICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUodmlkZW9TcGFuSWQpO1xuXG4gICAgICAgICAgICBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1t2aWRlb1NwYW5JZF0gPVxuICAgICAgICAgICAgICAgIG5ldyBDb25uZWN0aW9uSW5kaWNhdG9yKGNvbnRhaW5lciwgcGVlckppZCwgVmlkZW9MYXlvdXQpO1xuXG4gICAgICAgICAgICB2YXIgbmlja2ZpZWxkID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgICAgICAgICAgbmlja2ZpZWxkLmNsYXNzTmFtZSA9IFwibmlja1wiO1xuICAgICAgICAgICAgbmlja2ZpZWxkLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHJlc291cmNlSmlkKSk7XG4gICAgICAgICAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQobmlja2ZpZWxkKTtcblxuICAgICAgICAgICAgLy8gSW4gY2FzZSB0aGlzIGlzIG5vdCBjdXJyZW50bHkgaW4gdGhlIGxhc3QgbiB3ZSBkb24ndCBzaG93IGl0LlxuICAgICAgICAgICAgaWYgKGxvY2FsTGFzdE5Db3VudFxuICAgICAgICAgICAgICAgICYmIGxvY2FsTGFzdE5Db3VudCA+IDBcbiAgICAgICAgICAgICAgICAmJiAkKCcjcmVtb3RlVmlkZW9zPnNwYW4nKS5sZW5ndGggPj0gbG9jYWxMYXN0TkNvdW50ICsgMikge1xuICAgICAgICAgICAgICAgIHNob3dQZWVyQ29udGFpbmVyKHJlc291cmNlSmlkLCAnaGlkZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnJlc2l6ZVRodW1ibmFpbHMoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBteS5hZGRSZW1vdGVWaWRlb0NvbnRhaW5lciA9IGZ1bmN0aW9uKHBlZXJKaWQsIHNwYW5JZCkge1xuICAgICAgICB2YXIgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgICAgICBjb250YWluZXIuaWQgPSBzcGFuSWQ7XG4gICAgICAgIGNvbnRhaW5lci5jbGFzc05hbWUgPSAndmlkZW9jb250YWluZXInO1xuICAgICAgICB2YXIgcmVtb3RlcyA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyZW1vdGVWaWRlb3MnKTtcblxuICAgICAgICAvLyBJZiB0aGUgcGVlckppZCBpcyBudWxsIHRoZW4gdGhpcyB2aWRlbyBzcGFuIGNvdWxkbid0IGJlIGRpcmVjdGx5XG4gICAgICAgIC8vIGFzc29jaWF0ZWQgd2l0aCBhIHBhcnRpY2lwYW50ICh0aGlzIGNvdWxkIGhhcHBlbiBpbiB0aGUgY2FzZSBvZiBwcmV6aSkuXG4gICAgICAgIGlmIChNb2RlcmF0b3IuaXNNb2RlcmF0b3IoKSAmJiBwZWVySmlkICE9PSBudWxsKVxuICAgICAgICAgICAgYWRkUmVtb3RlVmlkZW9NZW51KHBlZXJKaWQsIGNvbnRhaW5lcik7XG5cbiAgICAgICAgcmVtb3Rlcy5hcHBlbmRDaGlsZChjb250YWluZXIpO1xuICAgICAgICBBdWRpb0xldmVscy51cGRhdGVBdWRpb0xldmVsQ2FudmFzKHBlZXJKaWQsIFZpZGVvTGF5b3V0KTtcblxuICAgICAgICByZXR1cm4gY29udGFpbmVyO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGF1ZGlvIG9yIHZpZGVvIHN0cmVhbSBlbGVtZW50LlxuICAgICAqL1xuICAgIG15LmNyZWF0ZVN0cmVhbUVsZW1lbnQgPSBmdW5jdGlvbiAoc2lkLCBzdHJlYW0pIHtcbiAgICAgICAgdmFyIGlzVmlkZW8gPSBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGggPiAwO1xuXG4gICAgICAgIHZhciBlbGVtZW50ID0gaXNWaWRlb1xuICAgICAgICAgICAgICAgICAgICAgICAgPyBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd2aWRlbycpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2F1ZGlvJyk7XG4gICAgICAgIHZhciBpZCA9IChpc1ZpZGVvID8gJ3JlbW90ZVZpZGVvXycgOiAncmVtb3RlQXVkaW9fJylcbiAgICAgICAgICAgICAgICAgICAgKyBzaWQgKyAnXycgKyBSVEMuZ2V0U3RyZWFtSUQoc3RyZWFtKTtcblxuICAgICAgICBlbGVtZW50LmlkID0gaWQ7XG4gICAgICAgIGVsZW1lbnQuYXV0b3BsYXkgPSB0cnVlO1xuICAgICAgICBlbGVtZW50Lm9uY29udGV4dG1lbnUgPSBmdW5jdGlvbiAoKSB7IHJldHVybiBmYWxzZTsgfTtcblxuICAgICAgICByZXR1cm4gZWxlbWVudDtcbiAgICB9O1xuXG4gICAgbXkuYWRkUmVtb3RlU3RyZWFtRWxlbWVudFxuICAgICAgICA9IGZ1bmN0aW9uIChjb250YWluZXIsIHNpZCwgc3RyZWFtLCBwZWVySmlkLCB0aGVzc3JjKSB7XG4gICAgICAgIHZhciBuZXdFbGVtZW50SWQgPSBudWxsO1xuXG4gICAgICAgIHZhciBpc1ZpZGVvID0gc3RyZWFtLmdldFZpZGVvVHJhY2tzKCkubGVuZ3RoID4gMDtcblxuICAgICAgICBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgICB2YXIgc3RyZWFtRWxlbWVudCA9IFZpZGVvTGF5b3V0LmNyZWF0ZVN0cmVhbUVsZW1lbnQoc2lkLCBzdHJlYW0pO1xuICAgICAgICAgICAgbmV3RWxlbWVudElkID0gc3RyZWFtRWxlbWVudC5pZDtcblxuICAgICAgICAgICAgY29udGFpbmVyLmFwcGVuZENoaWxkKHN0cmVhbUVsZW1lbnQpO1xuXG4gICAgICAgICAgICB2YXIgc2VsID0gJCgnIycgKyBuZXdFbGVtZW50SWQpO1xuICAgICAgICAgICAgc2VsLmhpZGUoKTtcblxuICAgICAgICAgICAgLy8gSWYgdGhlIGNvbnRhaW5lciBpcyBjdXJyZW50bHkgdmlzaWJsZSB3ZSBhdHRhY2ggdGhlIHN0cmVhbS5cbiAgICAgICAgICAgIGlmICghaXNWaWRlb1xuICAgICAgICAgICAgICAgIHx8IChjb250YWluZXIub2Zmc2V0UGFyZW50ICE9PSBudWxsICYmIGlzVmlkZW8pKSB7XG4gICAgICAgICAgICAgICAgdmFyIHZpZGVvU3RyZWFtID0gc2ltdWxjYXN0LmdldFJlY2VpdmluZ1ZpZGVvU3RyZWFtKHN0cmVhbSk7XG4gICAgICAgICAgICAgICAgUlRDLmF0dGFjaE1lZGlhU3RyZWFtKHNlbCwgdmlkZW9TdHJlYW0pO1xuXG4gICAgICAgICAgICAgICAgaWYgKGlzVmlkZW8pXG4gICAgICAgICAgICAgICAgICAgIHdhaXRGb3JSZW1vdGVWaWRlbyhzZWwsIHRoZXNzcmMsIHN0cmVhbSwgcGVlckppZCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHN0cmVhbS5vbmVuZGVkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzdHJlYW0gZW5kZWQnLCB0aGlzKTtcblxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnJlbW92ZVJlbW90ZVN0cmVhbUVsZW1lbnQoXG4gICAgICAgICAgICAgICAgICAgIHN0cmVhbSwgaXNWaWRlbywgY29udGFpbmVyKTtcblxuICAgICAgICAgICAgICAgIC8vIE5PVEUoZ3ApIGl0IHNlZW1zIHRoYXQgdW5kZXIgY2VydGFpbiBjaXJjdW1zdGFuY2VzLCB0aGVcbiAgICAgICAgICAgICAgICAvLyBvbmVuZGVkIGV2ZW50IGlzIG5vdCBmaXJlZCBhbmQgdGh1cyB0aGUgY29udGFjdCBsaXN0IGlzIG5vdFxuICAgICAgICAgICAgICAgIC8vIHVwZGF0ZWQuXG4gICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAvLyBUaGUgb25lbmRlZCBldmVudCBvZiBhIHN0cmVhbSBzaG91bGQgYmUgZmlyZWQgd2hlbiB0aGUgU1NSQ3NcbiAgICAgICAgICAgICAgICAvLyBjb3JyZXNwb25kaW5nIHRvIHRoYXQgc3RyZWFtIGFyZSByZW1vdmVkIGZyb20gdGhlIFNEUDsgYnV0XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBkb2Vzbid0IHNlZW0gdG8gYWx3YXlzIGJlIHRoZSBjYXNlLCByZXN1bHRpbmcgaW4gZ2hvc3RcbiAgICAgICAgICAgICAgICAvLyBjb250YWN0cy5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIC8vIEluIGFuIGF0dGVtcHQgdG8gZml4IHRoZSBnaG9zdCBjb250YWN0cyBwcm9ibGVtLCBJJ20gbW92aW5nXG4gICAgICAgICAgICAgICAgLy8gdGhlIHJlbW92ZUNvbnRhY3QoKSBtZXRob2QgY2FsbCBpbiBhcHAuanMsIGluc2lkZSB0aGVcbiAgICAgICAgICAgICAgICAvLyAnbXVjLmxlZnQnIGV2ZW50IGhhbmRsZXIuXG5cbiAgICAgICAgICAgICAgICAvL2lmIChwZWVySmlkKVxuICAgICAgICAgICAgICAgIC8vICAgIENvbnRhY3RMaXN0LnJlbW92ZUNvbnRhY3QocGVlckppZCk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvLyBBZGQgY2xpY2sgaGFuZGxlci5cbiAgICAgICAgICAgIGNvbnRhaW5lci5vbmNsaWNrID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAgICAgKiBGSVhNRSBJdCB0dXJucyBvdXQgdGhhdCB2aWRlb1RodW1iIG1heSBub3QgZXhpc3QgKGlmIHRoZXJlIGlzXG4gICAgICAgICAgICAgICAgICogbm8gYWN0dWFsIHZpZGVvKS5cbiAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICB2YXIgdmlkZW9UaHVtYiA9ICQoJyMnICsgY29udGFpbmVyLmlkICsgJz52aWRlbycpLmdldCgwKTtcbiAgICAgICAgICAgICAgICBpZiAodmlkZW9UaHVtYikge1xuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5oYW5kbGVWaWRlb1RodW1iQ2xpY2tlZChcbiAgICAgICAgICAgICAgICAgICAgICAgIFJUQy5nZXRWaWRlb1NyYyh2aWRlb1RodW1iKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQocGVlckppZCkpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy8gQWRkIGhvdmVyIGhhbmRsZXJcbiAgICAgICAgICAgICQoY29udGFpbmVyKS5ob3ZlcihcbiAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2hvd0Rpc3BsYXlOYW1lKGNvbnRhaW5lci5pZCwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZpZGVvU3JjID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQoJyMnICsgY29udGFpbmVyLmlkICsgJz52aWRlbycpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgJCgnIycgKyBjb250YWluZXIuaWQgKyAnPnZpZGVvJykubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcmMgPSBSVEMuZ2V0VmlkZW9TcmMoJCgnIycgKyBjb250YWluZXIuaWQgKyAnPnZpZGVvJykuZ2V0KDApKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZSB2aWRlbyBoYXMgYmVlbiBcInBpbm5lZFwiIGJ5IHRoZSB1c2VyIHdlIHdhbnQgdG9cbiAgICAgICAgICAgICAgICAgICAgLy8ga2VlcCB0aGUgZGlzcGxheSBuYW1lIG9uIHBsYWNlLlxuICAgICAgICAgICAgICAgICAgICBpZiAoIVZpZGVvTGF5b3V0LmlzTGFyZ2VWaWRlb1Zpc2libGUoKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8IHZpZGVvU3JjICE9PSBSVEMuZ2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSkpXG4gICAgICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5zaG93RGlzcGxheU5hbWUoY29udGFpbmVyLmlkLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBuZXdFbGVtZW50SWQ7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgdGhlIHJlbW90ZSBzdHJlYW0gZWxlbWVudCBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiBzdHJlYW0gYW5kXG4gICAgICogcGFyZW50IGNvbnRhaW5lci5cbiAgICAgKiBcbiAgICAgKiBAcGFyYW0gc3RyZWFtIHRoZSBzdHJlYW1cbiAgICAgKiBAcGFyYW0gaXNWaWRlbyA8dHQ+dHJ1ZTwvdHQ+IGlmIGdpdmVuIDx0dD5zdHJlYW08L3R0PiBpcyBhIHZpZGVvIG9uZS5cbiAgICAgKiBAcGFyYW0gY29udGFpbmVyXG4gICAgICovXG4gICAgbXkucmVtb3ZlUmVtb3RlU3RyZWFtRWxlbWVudCA9IGZ1bmN0aW9uIChzdHJlYW0sIGlzVmlkZW8sIGNvbnRhaW5lcikge1xuICAgICAgICBpZiAoIWNvbnRhaW5lcilcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB2YXIgc2VsZWN0ID0gbnVsbDtcbiAgICAgICAgdmFyIHJlbW92ZWRWaWRlb1NyYyA9IG51bGw7XG4gICAgICAgIGlmIChpc1ZpZGVvKSB7XG4gICAgICAgICAgICBzZWxlY3QgPSAkKCcjJyArIGNvbnRhaW5lci5pZCArICc+dmlkZW8nKTtcbiAgICAgICAgICAgIHJlbW92ZWRWaWRlb1NyYyA9IFJUQy5nZXRWaWRlb1NyYyhzZWxlY3QuZ2V0KDApKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgICAgICBzZWxlY3QgPSAkKCcjJyArIGNvbnRhaW5lci5pZCArICc+YXVkaW8nKTtcblxuXG4gICAgICAgIC8vIE1hcmsgdmlkZW8gYXMgcmVtb3ZlZCB0byBjYW5jZWwgd2FpdGluZyBsb29wKGlmIHZpZGVvIGlzIHJlbW92ZWRcbiAgICAgICAgLy8gYmVmb3JlIGhhcyBzdGFydGVkKVxuICAgICAgICBzZWxlY3QucmVtb3ZlZCA9IHRydWU7XG4gICAgICAgIHNlbGVjdC5yZW1vdmUoKTtcblxuICAgICAgICB2YXIgYXVkaW9Db3VudCA9ICQoJyMnICsgY29udGFpbmVyLmlkICsgJz5hdWRpbycpLmxlbmd0aDtcbiAgICAgICAgdmFyIHZpZGVvQ291bnQgPSAkKCcjJyArIGNvbnRhaW5lci5pZCArICc+dmlkZW8nKS5sZW5ndGg7XG5cbiAgICAgICAgaWYgKCFhdWRpb0NvdW50ICYmICF2aWRlb0NvdW50KSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlJlbW92ZSB3aG9sZSB1c2VyXCIsIGNvbnRhaW5lci5pZCk7XG4gICAgICAgICAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tjb250YWluZXIuaWRdKVxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW2NvbnRhaW5lci5pZF0ucmVtb3ZlKCk7XG4gICAgICAgICAgICAvLyBSZW1vdmUgd2hvbGUgY29udGFpbmVyXG4gICAgICAgICAgICBjb250YWluZXIucmVtb3ZlKCk7XG5cbiAgICAgICAgICAgIFV0aWwucGxheVNvdW5kTm90aWZpY2F0aW9uKCd1c2VyTGVmdCcpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplVGh1bWJuYWlscygpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJlbW92ZWRWaWRlb1NyYylcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZVJlbW92ZWRWaWRlbyhyZW1vdmVkVmlkZW9TcmMpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93L2hpZGUgcGVlciBjb250YWluZXIgZm9yIHRoZSBnaXZlbiByZXNvdXJjZUppZC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBzaG93UGVlckNvbnRhaW5lcihyZXNvdXJjZUppZCwgc3RhdGUpIHtcbiAgICAgICAgdmFyIHBlZXJDb250YWluZXIgPSAkKCcjcGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICBpZiAoIXBlZXJDb250YWluZXIpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdmFyIGlzSGlkZSA9IHN0YXRlID09PSAnaGlkZSc7XG4gICAgICAgIHZhciByZXNpemVUaHVtYm5haWxzID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKCFpc0hpZGUpIHtcbiAgICAgICAgICAgIGlmICghcGVlckNvbnRhaW5lci5pcygnOnZpc2libGUnKSkge1xuICAgICAgICAgICAgICAgIHJlc2l6ZVRodW1ibmFpbHMgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHBlZXJDb250YWluZXIuc2hvdygpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoc3RhdGUgPT0gJ3Nob3cnKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIC8vIHBlZXJDb250YWluZXIuY3NzKCctd2Via2l0LWZpbHRlcicsICcnKTtcbiAgICAgICAgICAgICAgICB2YXIgamlkID0gY29ubmVjdGlvbi5lbXVjLmZpbmRKaWRGcm9tUmVzb3VyY2UocmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihqaWQsIGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgLy8gaWYgKHN0YXRlID09ICdhdmF0YXInKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIC8vIHBlZXJDb250YWluZXIuY3NzKCctd2Via2l0LWZpbHRlcicsICdncmF5c2NhbGUoMTAwJSknKTtcbiAgICAgICAgICAgICAgICB2YXIgamlkID0gY29ubmVjdGlvbi5lbXVjLmZpbmRKaWRGcm9tUmVzb3VyY2UocmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihqaWQsIHRydWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHBlZXJDb250YWluZXIuaXMoJzp2aXNpYmxlJykgJiYgaXNIaWRlKVxuICAgICAgICB7XG4gICAgICAgICAgICByZXNpemVUaHVtYm5haWxzID0gdHJ1ZTtcbiAgICAgICAgICAgIHBlZXJDb250YWluZXIuaGlkZSgpO1xuICAgICAgICAgICAgaWYoVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZF0pXG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZF0uaGlkZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJlc2l6ZVRodW1ibmFpbHMpIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnJlc2l6ZVRodW1ibmFpbHMoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFdlIHdhbnQgdG8gYmUgYWJsZSB0byBwaW4gYSBwYXJ0aWNpcGFudCBmcm9tIHRoZSBjb250YWN0IGxpc3QsIGV2ZW5cbiAgICAgICAgLy8gaWYgaGUncyBub3QgaW4gdGhlIGxhc3ROIHNldCFcbiAgICAgICAgLy8gQ29udGFjdExpc3Quc2V0Q2xpY2thYmxlKHJlc291cmNlSmlkLCAhaXNIaWRlKTtcblxuICAgIH07XG5cbiAgICBteS5pbnB1dERpc3BsYXlOYW1lSGFuZGxlciA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIGlmIChuYW1lICYmIG5pY2tuYW1lICE9PSBuYW1lKSB7XG4gICAgICAgICAgICBuaWNrbmFtZSA9IG5hbWU7XG4gICAgICAgICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLmRpc3BsYXluYW1lID0gbmlja25hbWU7XG4gICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuYWRkRGlzcGxheU5hbWVUb1ByZXNlbmNlKG5pY2tuYW1lKTtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24uZW11Yy5zZW5kUHJlc2VuY2UoKTtcblxuICAgICAgICAgICAgQ2hhdC5zZXRDaGF0Q29udmVyc2F0aW9uTW9kZSh0cnVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghJCgnI2xvY2FsRGlzcGxheU5hbWUnKS5pcyhcIjp2aXNpYmxlXCIpKSB7XG4gICAgICAgICAgICBpZiAobmlja25hbWUpXG4gICAgICAgICAgICAgICAgJCgnI2xvY2FsRGlzcGxheU5hbWUnKS50ZXh0KG5pY2tuYW1lICsgXCIgKG1lKVwiKTtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpXG4gICAgICAgICAgICAgICAgICAgIC50ZXh0KGludGVyZmFjZUNvbmZpZy5ERUZBVUxUX0xPQ0FMX0RJU1BMQVlfTkFNRSk7XG4gICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLnNob3coKTtcbiAgICAgICAgfVxuXG4gICAgICAgICQoJyNlZGl0RGlzcGxheU5hbWUnKS5oaWRlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzL2hpZGVzIHRoZSBkaXNwbGF5IG5hbWUgb24gdGhlIHJlbW90ZSB2aWRlby5cbiAgICAgKiBAcGFyYW0gdmlkZW9TcGFuSWQgdGhlIGlkZW50aWZpZXIgb2YgdGhlIHZpZGVvIHNwYW4gZWxlbWVudFxuICAgICAqIEBwYXJhbSBpc1Nob3cgaW5kaWNhdGVzIGlmIHRoZSBkaXNwbGF5IG5hbWUgc2hvdWxkIGJlIHNob3duIG9yIGhpZGRlblxuICAgICAqL1xuICAgIG15LnNob3dEaXNwbGF5TmFtZSA9IGZ1bmN0aW9uKHZpZGVvU3BhbklkLCBpc1Nob3cpIHtcbiAgICAgICAgdmFyIG5hbWVTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi5kaXNwbGF5bmFtZScpLmdldCgwKTtcbiAgICAgICAgaWYgKGlzU2hvdykge1xuICAgICAgICAgICAgaWYgKG5hbWVTcGFuICYmIG5hbWVTcGFuLmlubmVySFRNTCAmJiBuYW1lU3Bhbi5pbm5lckhUTUwubGVuZ3RoKSBcbiAgICAgICAgICAgICAgICBuYW1lU3Bhbi5zZXRBdHRyaWJ1dGUoXCJzdHlsZVwiLCBcImRpc3BsYXk6aW5saW5lLWJsb2NrO1wiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGlmIChuYW1lU3BhbilcbiAgICAgICAgICAgICAgICBuYW1lU3Bhbi5zZXRBdHRyaWJ1dGUoXCJzdHlsZVwiLCBcImRpc3BsYXk6bm9uZTtcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2hvd3MgdGhlIHByZXNlbmNlIHN0YXR1cyBtZXNzYWdlIGZvciB0aGUgZ2l2ZW4gdmlkZW8uXG4gICAgICovXG4gICAgbXkuc2V0UHJlc2VuY2VTdGF0dXMgPSBmdW5jdGlvbiAodmlkZW9TcGFuSWQsIHN0YXR1c01zZykge1xuXG4gICAgICAgIGlmICghJCgnIycgKyB2aWRlb1NwYW5JZCkubGVuZ3RoKSB7XG4gICAgICAgICAgICAvLyBObyBjb250YWluZXJcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBzdGF0dXNTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi5zdGF0dXMnKTtcbiAgICAgICAgaWYgKCFzdGF0dXNTcGFuLmxlbmd0aCkge1xuICAgICAgICAgICAgLy9BZGQgc3RhdHVzIHNwYW5cbiAgICAgICAgICAgIHN0YXR1c1NwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgICAgICBzdGF0dXNTcGFuLmNsYXNzTmFtZSA9ICdzdGF0dXMnO1xuICAgICAgICAgICAgc3RhdHVzU3Bhbi5pZCA9IHZpZGVvU3BhbklkICsgJ19zdGF0dXMnO1xuICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQoc3RhdHVzU3Bhbik7XG5cbiAgICAgICAgICAgIHN0YXR1c1NwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLnN0YXR1cycpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRGlzcGxheSBzdGF0dXNcbiAgICAgICAgaWYgKHN0YXR1c01zZyAmJiBzdGF0dXNNc2cubGVuZ3RoKSB7XG4gICAgICAgICAgICAkKCcjJyArIHZpZGVvU3BhbklkICsgJ19zdGF0dXMnKS50ZXh0KHN0YXR1c01zZyk7XG4gICAgICAgICAgICBzdGF0dXNTcGFuLmdldCgwKS5zZXRBdHRyaWJ1dGUoXCJzdHlsZVwiLCBcImRpc3BsYXk6aW5saW5lLWJsb2NrO1wiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIEhpZGVcbiAgICAgICAgICAgIHN0YXR1c1NwYW4uZ2V0KDApLnNldEF0dHJpYnV0ZShcInN0eWxlXCIsIFwiZGlzcGxheTpub25lO1wiKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyBhIHZpc3VhbCBpbmRpY2F0b3IgZm9yIHRoZSBtb2RlcmF0b3Igb2YgdGhlIGNvbmZlcmVuY2UuXG4gICAgICovXG4gICAgbXkuc2hvd01vZGVyYXRvckluZGljYXRvciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKE1vZGVyYXRvci5pc01vZGVyYXRvcigpKSB7XG4gICAgICAgICAgICB2YXIgaW5kaWNhdG9yU3BhbiA9ICQoJyNsb2NhbFZpZGVvQ29udGFpbmVyIC5mb2N1c2luZGljYXRvcicpO1xuXG4gICAgICAgICAgICBpZiAoaW5kaWNhdG9yU3Bhbi5jaGlsZHJlbigpLmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBjcmVhdGVNb2RlcmF0b3JJbmRpY2F0b3JFbGVtZW50KGluZGljYXRvclNwYW5bMF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIE9iamVjdC5rZXlzKGNvbm5lY3Rpb24uZW11Yy5tZW1iZXJzKS5mb3JFYWNoKGZ1bmN0aW9uIChqaWQpIHtcbiAgICAgICAgICAgIHZhciBtZW1iZXIgPSBjb25uZWN0aW9uLmVtdWMubWVtYmVyc1tqaWRdO1xuICAgICAgICAgICAgaWYgKG1lbWJlci5yb2xlID09PSAnbW9kZXJhdG9yJykge1xuICAgICAgICAgICAgICAgIHZhciBtb2RlcmF0b3JJZFxuICAgICAgICAgICAgICAgICAgICA9ICdwYXJ0aWNpcGFudF8nICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcblxuICAgICAgICAgICAgICAgIHZhciBtb2RlcmF0b3JDb250YWluZXJcbiAgICAgICAgICAgICAgICAgICAgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChtb2RlcmF0b3JJZCk7XG5cbiAgICAgICAgICAgICAgICBpZiAoU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSA9PT0gJ2ZvY3VzJykge1xuICAgICAgICAgICAgICAgICAgICAvLyBTa2lwIHNlcnZlciBzaWRlIGZvY3VzXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCFtb2RlcmF0b3JDb250YWluZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIk5vIG1vZGVyYXRvciBjb250YWluZXIgZm9yIFwiICsgamlkKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgbWVudVNwYW4gPSAkKCcjJyArIG1vZGVyYXRvcklkICsgJz5zcGFuLnJlbW90ZXZpZGVvbWVudScpO1xuICAgICAgICAgICAgICAgIGlmIChtZW51U3Bhbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlUmVtb3RlVmlkZW9NZW51KG1vZGVyYXRvcklkKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgaW5kaWNhdG9yU3BhblxuICAgICAgICAgICAgICAgICAgICA9ICQoJyMnICsgbW9kZXJhdG9ySWQgKyAnIC5mb2N1c2luZGljYXRvcicpO1xuXG4gICAgICAgICAgICAgICAgaWYgKCFpbmRpY2F0b3JTcGFuIHx8IGluZGljYXRvclNwYW4ubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGluZGljYXRvclNwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgICAgICAgICAgICAgIGluZGljYXRvclNwYW4uY2xhc3NOYW1lID0gJ2ZvY3VzaW5kaWNhdG9yJztcblxuICAgICAgICAgICAgICAgICAgICBtb2RlcmF0b3JDb250YWluZXIuYXBwZW5kQ2hpbGQoaW5kaWNhdG9yU3Bhbik7XG5cbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlTW9kZXJhdG9ySW5kaWNhdG9yRWxlbWVudChpbmRpY2F0b3JTcGFuKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyB2aWRlbyBtdXRlZCBpbmRpY2F0b3Igb3ZlciBzbWFsbCB2aWRlb3MuXG4gICAgICovXG4gICAgbXkuc2hvd1ZpZGVvSW5kaWNhdG9yID0gZnVuY3Rpb24odmlkZW9TcGFuSWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgdmFyIHZpZGVvTXV0ZWRTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi52aWRlb011dGVkJyk7XG5cbiAgICAgICAgaWYgKGlzTXV0ZWQgPT09ICdmYWxzZScpIHtcbiAgICAgICAgICAgIGlmICh2aWRlb011dGVkU3Bhbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdmlkZW9NdXRlZFNwYW4ucmVtb3ZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBpZih2aWRlb011dGVkU3Bhbi5sZW5ndGggPT0gMCkge1xuICAgICAgICAgICAgICAgIHZpZGVvTXV0ZWRTcGFuID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgICAgICAgICAgICAgIHZpZGVvTXV0ZWRTcGFuLmNsYXNzTmFtZSA9ICd2aWRlb011dGVkJztcblxuICAgICAgICAgICAgICAgICQoJyMnICsgdmlkZW9TcGFuSWQpWzBdLmFwcGVuZENoaWxkKHZpZGVvTXV0ZWRTcGFuKTtcblxuICAgICAgICAgICAgICAgIHZhciBtdXRlZEluZGljYXRvciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2knKTtcbiAgICAgICAgICAgICAgICBtdXRlZEluZGljYXRvci5jbGFzc05hbWUgPSAnaWNvbi1jYW1lcmEtZGlzYWJsZWQnO1xuICAgICAgICAgICAgICAgIFV0aWwuc2V0VG9vbHRpcChtdXRlZEluZGljYXRvcixcbiAgICAgICAgICAgICAgICAgICAgXCJQYXJ0aWNpcGFudCBoYXM8YnIvPnN0b3BwZWQgdGhlIGNhbWVyYS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJ0b3BcIik7XG4gICAgICAgICAgICAgICAgdmlkZW9NdXRlZFNwYW4uYXBwZW5kQ2hpbGQobXV0ZWRJbmRpY2F0b3IpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVNdXRlUG9zaXRpb24odmlkZW9TcGFuSWQpO1xuXG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbXkudXBkYXRlTXV0ZVBvc2l0aW9uID0gZnVuY3Rpb24gKHZpZGVvU3BhbklkKSB7XG4gICAgICAgIHZhciBhdWRpb011dGVkU3BhbiA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPnNwYW4uYXVkaW9NdXRlZCcpO1xuICAgICAgICB2YXIgY29ubmVjdGlvbkluZGljYXRvciA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPmRpdi5jb25uZWN0aW9uaW5kaWNhdG9yJyk7XG4gICAgICAgIHZhciB2aWRlb011dGVkU3BhbiA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPnNwYW4udmlkZW9NdXRlZCcpO1xuICAgICAgICBpZihjb25uZWN0aW9uSW5kaWNhdG9yLmxlbmd0aCA+IDBcbiAgICAgICAgICAgICYmIGNvbm5lY3Rpb25JbmRpY2F0b3JbMF0uc3R5bGUuZGlzcGxheSAhPSBcIm5vbmVcIikge1xuICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4uY3NzKHtyaWdodDogXCIyM3B4XCJ9KTtcbiAgICAgICAgICAgIHZpZGVvTXV0ZWRTcGFuLmNzcyh7cmlnaHQ6ICgoYXVkaW9NdXRlZFNwYW4ubGVuZ3RoID4gMD8gMjMgOiAwKSArIDMwKSArIFwicHhcIn0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4uY3NzKHtyaWdodDogXCIwcHhcIn0pO1xuICAgICAgICAgICAgdmlkZW9NdXRlZFNwYW4uY3NzKHtyaWdodDogKGF1ZGlvTXV0ZWRTcGFuLmxlbmd0aCA+IDA/IDMwIDogMCkgKyBcInB4XCJ9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiBTaG93cyBhdWRpbyBtdXRlZCBpbmRpY2F0b3Igb3ZlciBzbWFsbCB2aWRlb3MuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGlzTXV0ZWRcbiAgICAgKi9cbiAgICBteS5zaG93QXVkaW9JbmRpY2F0b3IgPSBmdW5jdGlvbih2aWRlb1NwYW5JZCwgaXNNdXRlZCkge1xuICAgICAgICB2YXIgYXVkaW9NdXRlZFNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLmF1ZGlvTXV0ZWQnKTtcblxuICAgICAgICBpZiAoaXNNdXRlZCA9PT0gJ2ZhbHNlJykge1xuICAgICAgICAgICAgaWYgKGF1ZGlvTXV0ZWRTcGFuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBhdWRpb011dGVkU3Bhbi5wb3BvdmVyKCdoaWRlJyk7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4ucmVtb3ZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBpZihhdWRpb011dGVkU3Bhbi5sZW5ndGggPT0gMCApIHtcbiAgICAgICAgICAgICAgICBhdWRpb011dGVkU3BhbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICAgICAgICAgICAgICBhdWRpb011dGVkU3Bhbi5jbGFzc05hbWUgPSAnYXVkaW9NdXRlZCc7XG4gICAgICAgICAgICAgICAgVXRpbC5zZXRUb29sdGlwKGF1ZGlvTXV0ZWRTcGFuLFxuICAgICAgICAgICAgICAgICAgICBcIlBhcnRpY2lwYW50IGlzIG11dGVkXCIsXG4gICAgICAgICAgICAgICAgICAgIFwidG9wXCIpO1xuXG4gICAgICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQoYXVkaW9NdXRlZFNwYW4pO1xuICAgICAgICAgICAgICAgIHZhciBtdXRlZEluZGljYXRvciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2knKTtcbiAgICAgICAgICAgICAgICBtdXRlZEluZGljYXRvci5jbGFzc05hbWUgPSAnaWNvbi1taWMtZGlzYWJsZWQnO1xuICAgICAgICAgICAgICAgIGF1ZGlvTXV0ZWRTcGFuLmFwcGVuZENoaWxkKG11dGVkSW5kaWNhdG9yKTtcblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlTXV0ZVBvc2l0aW9uKHZpZGVvU3BhbklkKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKlxuICAgICAqIFNob3dzIG9yIGhpZGVzIHRoZSBhdWRpbyBtdXRlZCBpbmRpY2F0b3Igb3ZlciB0aGUgbG9jYWwgdGh1bWJuYWlsIHZpZGVvLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNNdXRlZFxuICAgICAqL1xuICAgIG15LnNob3dMb2NhbEF1ZGlvSW5kaWNhdG9yID0gZnVuY3Rpb24oaXNNdXRlZCkge1xuICAgICAgICBWaWRlb0xheW91dC5zaG93QXVkaW9JbmRpY2F0b3IoJ2xvY2FsVmlkZW9Db250YWluZXInLCBpc011dGVkLnRvU3RyaW5nKCkpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXNpemVzIHRoZSBsYXJnZSB2aWRlbyBjb250YWluZXIuXG4gICAgICovXG4gICAgbXkucmVzaXplTGFyZ2VWaWRlb0NvbnRhaW5lciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQ2hhdC5yZXNpemVDaGF0KCk7XG4gICAgICAgIHZhciBhdmFpbGFibGVIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IFVJVXRpbC5nZXRBdmFpbGFibGVWaWRlb1dpZHRoKCk7XG5cbiAgICAgICAgaWYgKGF2YWlsYWJsZVdpZHRoIDwgMCB8fCBhdmFpbGFibGVIZWlnaHQgPCAwKSByZXR1cm47XG5cbiAgICAgICAgJCgnI3ZpZGVvc3BhY2UnKS53aWR0aChhdmFpbGFibGVXaWR0aCk7XG4gICAgICAgICQoJyN2aWRlb3NwYWNlJykuaGVpZ2h0KGF2YWlsYWJsZUhlaWdodCk7XG4gICAgICAgICQoJyNsYXJnZVZpZGVvQ29udGFpbmVyJykud2lkdGgoYXZhaWxhYmxlV2lkdGgpO1xuICAgICAgICAkKCcjbGFyZ2VWaWRlb0NvbnRhaW5lcicpLmhlaWdodChhdmFpbGFibGVIZWlnaHQpO1xuXG4gICAgICAgIHZhciBhdmF0YXJTaXplID0gaW50ZXJmYWNlQ29uZmlnLkFDVElWRV9TUEVBS0VSX0FWQVRBUl9TSVpFO1xuICAgICAgICB2YXIgdG9wID0gYXZhaWxhYmxlSGVpZ2h0IC8gMiAtIGF2YXRhclNpemUgLyA0ICogMztcbiAgICAgICAgJCgnI2FjdGl2ZVNwZWFrZXInKS5jc3MoJ3RvcCcsIHRvcCk7XG5cbiAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplVGh1bWJuYWlscygpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXNpemVzIHRodW1ibmFpbHMuXG4gICAgICovXG4gICAgbXkucmVzaXplVGh1bWJuYWlscyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgdmlkZW9TcGFjZVdpZHRoID0gJCgnI3JlbW90ZVZpZGVvcycpLndpZHRoKCk7XG5cbiAgICAgICAgdmFyIHRodW1ibmFpbFNpemUgPSBWaWRlb0xheW91dC5jYWxjdWxhdGVUaHVtYm5haWxTaXplKHZpZGVvU3BhY2VXaWR0aCk7XG4gICAgICAgIHZhciB3aWR0aCA9IHRodW1ibmFpbFNpemVbMF07XG4gICAgICAgIHZhciBoZWlnaHQgPSB0aHVtYm5haWxTaXplWzFdO1xuXG4gICAgICAgIC8vIHNpemUgdmlkZW9zIHNvIHRoYXQgd2hpbGUga2VlcGluZyBBUiBhbmQgbWF4IGhlaWdodCwgd2UgaGF2ZSBhXG4gICAgICAgIC8vIG5pY2UgZml0XG4gICAgICAgICQoJyNyZW1vdGVWaWRlb3MnKS5oZWlnaHQoaGVpZ2h0KTtcbiAgICAgICAgJCgnI3JlbW90ZVZpZGVvcz5zcGFuJykud2lkdGgod2lkdGgpO1xuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zPnNwYW4nKS5oZWlnaHQoaGVpZ2h0KTtcblxuICAgICAgICAkKCcudXNlckF2YXRhcicpLmNzcygnbGVmdCcsICh3aWR0aCAtIGhlaWdodCkgLyAyKTtcblxuICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKFwicmVtb3RldmlkZW8ucmVzaXplZFwiLCBbd2lkdGgsIGhlaWdodF0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBFbmFibGVzIHRoZSBkb21pbmFudCBzcGVha2VyIFVJLlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc291cmNlSmlkIHRoZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZWxlbWVudCB0b1xuICAgICAqIGFjdGl2YXRlL2RlYWN0aXZhdGVcbiAgICAgKiBAcGFyYW0gaXNFbmFibGUgaW5kaWNhdGVzIGlmIHRoZSBkb21pbmFudCBzcGVha2VyIHNob3VsZCBiZSBlbmFibGVkIG9yXG4gICAgICogZGlzYWJsZWRcbiAgICAgKi9cbiAgICBteS5lbmFibGVEb21pbmFudFNwZWFrZXIgPSBmdW5jdGlvbihyZXNvdXJjZUppZCwgaXNFbmFibGUpIHtcblxuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBudWxsO1xuICAgICAgICB2YXIgdmlkZW9Db250YWluZXJJZCA9IG51bGw7XG4gICAgICAgIGlmIChyZXNvdXJjZUppZFxuICAgICAgICAgICAgICAgID09PSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChjb25uZWN0aW9uLmVtdWMubXlyb29tamlkKSkge1xuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAnbG9jYWxWaWRlb1dyYXBwZXInO1xuICAgICAgICAgICAgdmlkZW9Db250YWluZXJJZCA9ICdsb2NhbFZpZGVvQ29udGFpbmVyJztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZDtcbiAgICAgICAgICAgIHZpZGVvQ29udGFpbmVySWQgPSB2aWRlb1NwYW5JZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBkaXNwbGF5TmFtZSA9IHJlc291cmNlSmlkO1xuICAgICAgICB2YXIgbmFtZVNwYW4gPSAkKCcjJyArIHZpZGVvQ29udGFpbmVySWQgKyAnPnNwYW4uZGlzcGxheW5hbWUnKTtcbiAgICAgICAgaWYgKG5hbWVTcGFuLmxlbmd0aCA+IDApXG4gICAgICAgICAgICBkaXNwbGF5TmFtZSA9IG5hbWVTcGFuLmh0bWwoKTtcblxuICAgICAgICBjb25zb2xlLmxvZyhcIlVJIGVuYWJsZSBkb21pbmFudCBzcGVha2VyXCIsXG4gICAgICAgICAgICBkaXNwbGF5TmFtZSxcbiAgICAgICAgICAgIHJlc291cmNlSmlkLFxuICAgICAgICAgICAgaXNFbmFibGUpO1xuXG4gICAgICAgIHZpZGVvU3BhbiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHZpZGVvQ29udGFpbmVySWQpO1xuXG4gICAgICAgIGlmICghdmlkZW9TcGFuKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgdmlkZW8gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz52aWRlbycpO1xuXG4gICAgICAgIGlmICh2aWRlbyAmJiB2aWRlby5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBpZiAoaXNFbmFibGUpIHtcbiAgICAgICAgICAgICAgICB2YXIgaXNMYXJnZVZpZGVvVmlzaWJsZSA9IFZpZGVvTGF5b3V0LmlzTGFyZ2VWaWRlb09uVG9wKCk7XG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2hvd0Rpc3BsYXlOYW1lKHZpZGVvQ29udGFpbmVySWQsIGlzTGFyZ2VWaWRlb1Zpc2libGUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKCF2aWRlb1NwYW4uY2xhc3NMaXN0LmNvbnRhaW5zKFwiZG9taW5hbnRzcGVha2VyXCIpKVxuICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYW4uY2xhc3NMaXN0LmFkZChcImRvbWluYW50c3BlYWtlclwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dEaXNwbGF5TmFtZSh2aWRlb0NvbnRhaW5lcklkLCBmYWxzZSk7XG5cbiAgICAgICAgICAgICAgICBpZiAodmlkZW9TcGFuLmNsYXNzTGlzdC5jb250YWlucyhcImRvbWluYW50c3BlYWtlclwiKSlcbiAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFuLmNsYXNzTGlzdC5yZW1vdmUoXCJkb21pbmFudHNwZWFrZXJcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuZmluZEppZEZyb21SZXNvdXJjZShyZXNvdXJjZUppZCkpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZXMgdGhlIHRodW1ibmFpbCBzaXplLlxuICAgICAqXG4gICAgICogQHBhcmFtIHZpZGVvU3BhY2VXaWR0aCB0aGUgd2lkdGggb2YgdGhlIHZpZGVvIHNwYWNlXG4gICAgICovXG4gICAgbXkuY2FsY3VsYXRlVGh1bWJuYWlsU2l6ZSA9IGZ1bmN0aW9uICh2aWRlb1NwYWNlV2lkdGgpIHtcbiAgICAgICAgLy8gQ2FsY3VsYXRlIHRoZSBhdmFpbGFibGUgaGVpZ2h0LCB3aGljaCBpcyB0aGUgaW5uZXIgd2luZG93IGhlaWdodCBtaW51c1xuICAgICAgIC8vIDM5cHggZm9yIHRoZSBoZWFkZXIgbWludXMgMnB4IGZvciB0aGUgZGVsaW1pdGVyIGxpbmVzIG9uIHRoZSB0b3AgYW5kXG4gICAgICAgLy8gYm90dG9tIG9mIHRoZSBsYXJnZSB2aWRlbywgbWludXMgdGhlIDM2cHggc3BhY2UgaW5zaWRlIHRoZSByZW1vdGVWaWRlb3NcbiAgICAgICAvLyBjb250YWluZXIgdXNlZCBmb3IgaGlnaGxpZ2h0aW5nIHNoYWRvdy5cbiAgICAgICB2YXIgYXZhaWxhYmxlSGVpZ2h0ID0gMTAwO1xuXG4gICAgICAgIHZhciBudW12aWRzID0gJCgnI3JlbW90ZVZpZGVvcz5zcGFuOnZpc2libGUnKS5sZW5ndGg7XG4gICAgICAgIGlmIChsb2NhbExhc3ROQ291bnQgJiYgbG9jYWxMYXN0TkNvdW50ID4gMCkge1xuICAgICAgICAgICAgbnVtdmlkcyA9IE1hdGgubWluKGxvY2FsTGFzdE5Db3VudCArIDEsIG51bXZpZHMpO1xuICAgICAgICB9XG5cbiAgICAgICAvLyBSZW1vdmUgdGhlIDNweCBib3JkZXJzIGFycm91bmQgdmlkZW9zIGFuZCBib3JkZXIgYXJvdW5kIHRoZSByZW1vdGVcbiAgICAgICAvLyB2aWRlb3MgYXJlYSBhbmQgdGhlIDQgcGl4ZWxzIGJldHdlZW4gdGhlIGxvY2FsIHZpZGVvIGFuZCB0aGUgb3RoZXJzXG4gICAgICAgLy9UT0RPOiBGaW5kIG91dCB3aGVyZSB0aGUgNCBwaXhlbHMgY29tZSBmcm9tIGFuZCByZW1vdmUgdGhlbVxuICAgICAgIHZhciBhdmFpbGFibGVXaW5XaWR0aCA9IHZpZGVvU3BhY2VXaWR0aCAtIDIgKiAzICogbnVtdmlkcyAtIDcwIC0gNDtcblxuICAgICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IGF2YWlsYWJsZVdpbldpZHRoIC8gbnVtdmlkcztcbiAgICAgICB2YXIgYXNwZWN0UmF0aW8gPSAxNi4wIC8gOS4wO1xuICAgICAgIHZhciBtYXhIZWlnaHQgPSBNYXRoLm1pbigxNjAsIGF2YWlsYWJsZUhlaWdodCk7XG4gICAgICAgYXZhaWxhYmxlSGVpZ2h0ID0gTWF0aC5taW4obWF4SGVpZ2h0LCBhdmFpbGFibGVXaWR0aCAvIGFzcGVjdFJhdGlvKTtcbiAgICAgICBpZiAoYXZhaWxhYmxlSGVpZ2h0IDwgYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbykge1xuICAgICAgICAgICBhdmFpbGFibGVXaWR0aCA9IE1hdGguZmxvb3IoYXZhaWxhYmxlSGVpZ2h0ICogYXNwZWN0UmF0aW8pO1xuICAgICAgIH1cblxuICAgICAgIHJldHVybiBbYXZhaWxhYmxlV2lkdGgsIGF2YWlsYWJsZUhlaWdodF07XG4gICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgcmVtb3RlIHZpZGVvIG1lbnUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gamlkIHRoZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZm9yIHdoaWNoIHdlJ3JlIGFkZGluZyBhIG1lbnUuXG4gICAgICogQHBhcmFtIGlzTXV0ZWQgaW5kaWNhdGVzIHRoZSBjdXJyZW50IG11dGUgc3RhdGVcbiAgICAgKi9cbiAgICBteS51cGRhdGVSZW1vdGVWaWRlb01lbnUgPSBmdW5jdGlvbihqaWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgdmFyIG11dGVNZW51SXRlbVxuICAgICAgICAgICAgPSAkKCcjcmVtb3RlX3BvcHVwbWVudV8nXG4gICAgICAgICAgICAgICAgICAgICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKVxuICAgICAgICAgICAgICAgICAgICArICc+bGk+YS5tdXRlbGluaycpO1xuXG4gICAgICAgIHZhciBtdXRlZEluZGljYXRvciA9IFwiPGkgY2xhc3M9J2ljb24tbWljLWRpc2FibGVkJz48L2k+XCI7XG5cbiAgICAgICAgaWYgKG11dGVNZW51SXRlbS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHZhciBtdXRlTGluayA9IG11dGVNZW51SXRlbS5nZXQoMCk7XG5cbiAgICAgICAgICAgIGlmIChpc011dGVkID09PSAndHJ1ZScpIHtcbiAgICAgICAgICAgICAgICBtdXRlTGluay5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArICcgTXV0ZWQnO1xuICAgICAgICAgICAgICAgIG11dGVMaW5rLmNsYXNzTmFtZSA9ICdtdXRlbGluayBkaXNhYmxlZCc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBtdXRlTGluay5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArICcgTXV0ZSc7XG4gICAgICAgICAgICAgICAgbXV0ZUxpbmsuY2xhc3NOYW1lID0gJ211dGVsaW5rJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IGRvbWluYW50IHNwZWFrZXIgcmVzb3VyY2UgamlkLlxuICAgICAqL1xuICAgIG15LmdldERvbWluYW50U3BlYWtlclJlc291cmNlSmlkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY3VycmVudERvbWluYW50U3BlYWtlcjtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgY29ycmVzcG9uZGluZyByZXNvdXJjZSBqaWQgdG8gdGhlIGdpdmVuIHBlZXIgY29udGFpbmVyXG4gICAgICogRE9NIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHRoZSBjb3JyZXNwb25kaW5nIHJlc291cmNlIGppZCB0byB0aGUgZ2l2ZW4gcGVlciBjb250YWluZXJcbiAgICAgKiBET00gZWxlbWVudFxuICAgICAqL1xuICAgIG15LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZCA9IGZ1bmN0aW9uIChjb250YWluZXJFbGVtZW50KSB7XG4gICAgICAgIHZhciBpID0gY29udGFpbmVyRWxlbWVudC5pZC5pbmRleE9mKCdwYXJ0aWNpcGFudF8nKTtcblxuICAgICAgICBpZiAoaSA+PSAwKVxuICAgICAgICAgICAgcmV0dXJuIGNvbnRhaW5lckVsZW1lbnQuaWQuc3Vic3RyaW5nKGkgKyAxMik7IFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPbiBjb250YWN0IGxpc3QgaXRlbSBjbGlja2VkLlxuICAgICAqL1xuICAgICQoQ29udGFjdExpc3QpLmJpbmQoJ2NvbnRhY3RjbGlja2VkJywgZnVuY3Rpb24oZXZlbnQsIGppZCkge1xuICAgICAgICBpZiAoIWppZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHJlc291cmNlID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgdmFyIHZpZGVvQ29udGFpbmVyID0gJChcIiNwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlKTtcbiAgICAgICAgaWYgKHZpZGVvQ29udGFpbmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHZhciB2aWRlb1RodW1iID0gJCgndmlkZW8nLCB2aWRlb0NvbnRhaW5lcikuZ2V0KDApO1xuICAgICAgICAgICAgLy8gSXQgaXMgbm90IGFsd2F5cyB0aGUgY2FzZSB0aGF0IGEgdmlkZW9UaHVtYiBleGlzdHMgKGlmIHRoZXJlIGlzXG4gICAgICAgICAgICAvLyBubyBhY3R1YWwgdmlkZW8pLlxuICAgICAgICAgICAgaWYgKHZpZGVvVGh1bWIpIHtcbiAgICAgICAgICAgICAgICBpZiAodmlkZW9UaHVtYi5zcmMgJiYgdmlkZW9UaHVtYi5zcmMgIT0gJycpIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBXZSBoYXZlIGEgdmlkZW8gc3JjLCBncmVhdCEgTGV0J3MgdXBkYXRlIHRoZSBsYXJnZSB2aWRlb1xuICAgICAgICAgICAgICAgICAgICAvLyBub3cuXG5cbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuaGFuZGxlVmlkZW9UaHVtYkNsaWNrZWQoXG4gICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1RodW1iLnNyYyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB3ZSBkb24ndCBoYXZlIGEgdmlkZW8gc3JjIGZvciBqaWQsIHRoZXJlJ3MgYWJzb2x1dGVseVxuICAgICAgICAgICAgICAgICAgICAvLyBubyBwb2ludCBpbiBjYWxsaW5nIGhhbmRsZVZpZGVvVGh1bWJDbGlja2VkOyBRdWl0ZVxuICAgICAgICAgICAgICAgICAgICAvLyBzaW1wbHksIGl0IHdvbid0IHdvcmsgYmVjYXVzZSBpdCBuZWVkcyBhbiBzcmMgdG8gYXR0YWNoXG4gICAgICAgICAgICAgICAgICAgIC8vIHRvIHRoZSBsYXJnZSB2aWRlby5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gSW5zdGVhZCwgd2UgdHJpZ2dlciB0aGUgcGlubmVkIGVuZHBvaW50IGNoYW5nZWQgZXZlbnQgdG9cbiAgICAgICAgICAgICAgICAgICAgLy8gbGV0IHRoZSBicmlkZ2UgYWRqdXN0IGl0cyBsYXN0TiBzZXQgZm9yIG15amlkIGFuZCBzdG9yZVxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgcGlubmVkIHVzZXIgaW4gdGhlIGxhc3ROUGlja3VwSmlkIHZhcmlhYmxlIHRvIGJlXG4gICAgICAgICAgICAgICAgICAgIC8vIHBpY2tlZCB1cCBsYXRlciBieSB0aGUgbGFzdE4gY2hhbmdlZCBldmVudCBoYW5kbGVyLlxuXG4gICAgICAgICAgICAgICAgICAgIGxhc3ROUGlja3VwSmlkID0gamlkO1xuICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKFwicGlubmVkZW5kcG9pbnRjaGFuZ2VkXCIsIFtqaWRdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGppZCA9PSBjb25uZWN0aW9uLmVtdWMubXlyb29tamlkKSB7XG4gICAgICAgICAgICAgICAgJChcIiNsb2NhbFZpZGVvQ29udGFpbmVyXCIpLmNsaWNrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIE9uIGF1ZGlvIG11dGVkIGV2ZW50LlxuICAgICAqL1xuICAgICQoZG9jdW1lbnQpLmJpbmQoJ2F1ZGlvbXV0ZWQubXVjJywgZnVuY3Rpb24gKGV2ZW50LCBqaWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgLypcbiAgICAgICAgIC8vIEZJWE1FOiBidXQgZm9jdXMgY2FuIG5vdCBtdXRlIGluIHRoaXMgY2FzZSA/IC0gY2hlY2tcbiAgICAgICAgaWYgKGppZCA9PT0gY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCkge1xuXG4gICAgICAgICAgICAvLyBUaGUgbG9jYWwgbXV0ZSBpbmRpY2F0b3IgaXMgY29udHJvbGxlZCBsb2NhbGx5XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0qL1xuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBudWxsO1xuICAgICAgICBpZiAoamlkID09PSBjb25uZWN0aW9uLmVtdWMubXlyb29tamlkKSB7XG4gICAgICAgICAgICB2aWRlb1NwYW5JZCA9ICdsb2NhbFZpZGVvQ29udGFpbmVyJztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmVuc3VyZVBlZXJDb250YWluZXJFeGlzdHMoamlkKTtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuICAgICAgICB9XG5cbiAgICAgICAgbXV0ZWRBdWRpb3NbamlkXSA9IGlzTXV0ZWQ7XG5cbiAgICAgICAgaWYgKE1vZGVyYXRvci5pc01vZGVyYXRvcigpKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVSZW1vdGVWaWRlb01lbnUoamlkLCBpc011dGVkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh2aWRlb1NwYW5JZClcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dBdWRpb0luZGljYXRvcih2aWRlb1NwYW5JZCwgaXNNdXRlZCk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBPbiB2aWRlbyBtdXRlZCBldmVudC5cbiAgICAgKi9cbiAgICAkKGRvY3VtZW50KS5iaW5kKCd2aWRlb211dGVkLm11YycsIGZ1bmN0aW9uIChldmVudCwgamlkLCBpc011dGVkKSB7XG4gICAgICAgIGlmKCFSVEMubXV0ZVJlbW90ZVZpZGVvU3RyZWFtKGppZCwgaXNNdXRlZCkpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgQXZhdGFyLnNob3dVc2VyQXZhdGFyKGppZCwgaXNNdXRlZCk7XG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9IG51bGw7XG4gICAgICAgIGlmIChqaWQgPT09IGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpIHtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ2xvY2FsVmlkZW9Db250YWluZXInO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5zdXJlUGVlckNvbnRhaW5lckV4aXN0cyhqaWQpO1xuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodmlkZW9TcGFuSWQpXG4gICAgICAgICAgICBWaWRlb0xheW91dC5zaG93VmlkZW9JbmRpY2F0b3IodmlkZW9TcGFuSWQsIGlzTXV0ZWQpO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogRGlzcGxheSBuYW1lIGNoYW5nZWQuXG4gICAgICovXG4gICAgJChkb2N1bWVudCkuYmluZCgnZGlzcGxheW5hbWVjaGFuZ2VkJyxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGV2ZW50LCBqaWQsIGRpc3BsYXlOYW1lLCBzdGF0dXMpIHtcbiAgICAgICAgdmFyIG5hbWUgPSBudWxsO1xuICAgICAgICBpZiAoamlkID09PSAnbG9jYWxWaWRlb0NvbnRhaW5lcidcbiAgICAgICAgICAgIHx8IGppZCA9PT0gY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCkge1xuICAgICAgICAgICAgbmFtZSA9IG5pY2tuYW1lO1xuICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUoJ2xvY2FsVmlkZW9Db250YWluZXInLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheU5hbWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5zdXJlUGVlckNvbnRhaW5lckV4aXN0cyhqaWQpO1xuICAgICAgICAgICAgbmFtZSA9ICQoJyNwYXJ0aWNpcGFudF8nICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSArIFwiX25hbWVcIikudGV4dCgpO1xuICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUoXG4gICAgICAgICAgICAgICAgJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpLFxuICAgICAgICAgICAgICAgIGRpc3BsYXlOYW1lLFxuICAgICAgICAgICAgICAgIHN0YXR1cyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZihBUElDb25uZWN0b3IuaXNFbmFibGVkKCkgJiYgQVBJQ29ubmVjdG9yLmlzRXZlbnRFbmFibGVkKFwiZGlzcGxheU5hbWVDaGFuZ2VcIikpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGlmKGppZCA9PT0gJ2xvY2FsVmlkZW9Db250YWluZXInKVxuICAgICAgICAgICAgICAgIGppZCA9IGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQ7XG4gICAgICAgICAgICBpZighbmFtZSB8fCBuYW1lICE9IGRpc3BsYXlOYW1lKVxuICAgICAgICAgICAgICAgIEFQSUNvbm5lY3Rvci50cmlnZ2VyRXZlbnQoXCJkaXNwbGF5TmFtZUNoYW5nZVwiLHtqaWQ6IGppZCwgZGlzcGxheW5hbWU6IGRpc3BsYXlOYW1lfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIE9uIGRvbWluYW50IHNwZWFrZXIgY2hhbmdlZCBldmVudC5cbiAgICAgKi9cbiAgICAkKGRvY3VtZW50KS5iaW5kKCdkb21pbmFudHNwZWFrZXJjaGFuZ2VkJywgZnVuY3Rpb24gKGV2ZW50LCByZXNvdXJjZUppZCkge1xuICAgICAgICAvLyBXZSBpZ25vcmUgbG9jYWwgdXNlciBldmVudHMuXG4gICAgICAgIGlmIChyZXNvdXJjZUppZFxuICAgICAgICAgICAgICAgID09PSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChjb25uZWN0aW9uLmVtdWMubXlyb29tamlkKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICAvLyBVcGRhdGUgdGhlIGN1cnJlbnQgZG9taW5hbnQgc3BlYWtlci5cbiAgICAgICAgaWYgKHJlc291cmNlSmlkICE9PSBjdXJyZW50RG9taW5hbnRTcGVha2VyKSB7XG4gICAgICAgICAgICB2YXIgb2xkU3BlYWtlclZpZGVvU3BhbklkID0gXCJwYXJ0aWNpcGFudF9cIiArIGN1cnJlbnREb21pbmFudFNwZWFrZXIsXG4gICAgICAgICAgICAgICAgbmV3U3BlYWtlclZpZGVvU3BhbklkID0gXCJwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlSmlkO1xuICAgICAgICAgICAgaWYoJChcIiNcIiArIG9sZFNwZWFrZXJWaWRlb1NwYW5JZCArIFwiPnNwYW4uZGlzcGxheW5hbWVcIikudGV4dCgpID09PVxuICAgICAgICAgICAgICAgIGludGVyZmFjZUNvbmZpZy5ERUZBVUxUX0RPTUlOQU5UX1NQRUFLRVJfRElTUExBWV9OQU1FKSB7XG4gICAgICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUob2xkU3BlYWtlclZpZGVvU3BhbklkLCBudWxsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmKCQoXCIjXCIgKyBuZXdTcGVha2VyVmlkZW9TcGFuSWQgKyBcIj5zcGFuLmRpc3BsYXluYW1lXCIpLnRleHQoKSA9PT1cbiAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuREVGQVVMVF9SRU1PVEVfRElTUExBWV9OQU1FKSB7XG4gICAgICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUobmV3U3BlYWtlclZpZGVvU3BhbklkLFxuICAgICAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuREVGQVVMVF9ET01JTkFOVF9TUEVBS0VSX0RJU1BMQVlfTkFNRSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjdXJyZW50RG9taW5hbnRTcGVha2VyID0gcmVzb3VyY2VKaWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBPYnRhaW4gY29udGFpbmVyIGZvciBuZXcgZG9taW5hbnQgc3BlYWtlci5cbiAgICAgICAgdmFyIGNvbnRhaW5lciAgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcbiAgICAgICAgICAgICAgICAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICAvLyBMb2NhbCB2aWRlbyB3aWxsIG5vdCBoYXZlIGNvbnRhaW5lciBmb3VuZCwgYnV0IHRoYXQncyBva1xuICAgICAgICAvLyBzaW5jZSB3ZSBkb24ndCB3YW50IHRvIHN3aXRjaCB0byBsb2NhbCB2aWRlby5cbiAgICAgICAgaWYgKGNvbnRhaW5lciAmJiAhZm9jdXNlZFZpZGVvSW5mbylcbiAgICAgICAge1xuICAgICAgICAgICAgdmFyIHZpZGVvID0gY29udGFpbmVyLmdldEVsZW1lbnRzQnlUYWdOYW1lKFwidmlkZW9cIik7XG5cbiAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgbGFyZ2UgdmlkZW8gaWYgdGhlIHZpZGVvIHNvdXJjZSBpcyBhbHJlYWR5IGF2YWlsYWJsZSxcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSB3YWl0IGZvciB0aGUgXCJ2aWRlb2FjdGl2ZS5qaW5nbGVcIiBldmVudC5cbiAgICAgICAgICAgIGlmICh2aWRlby5sZW5ndGggJiYgdmlkZW9bMF0uY3VycmVudFRpbWUgPiAwKVxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oUlRDLmdldFZpZGVvU3JjKHZpZGVvWzBdKSwgcmVzb3VyY2VKaWQpO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBPbiBsYXN0IE4gY2hhbmdlIGV2ZW50LlxuICAgICAqXG4gICAgICogQHBhcmFtIGV2ZW50IHRoZSBldmVudCB0aGF0IG5vdGlmaWVkIHVzXG4gICAgICogQHBhcmFtIGxhc3RORW5kcG9pbnRzIHRoZSBsaXN0IG9mIGxhc3QgTiBlbmRwb2ludHNcbiAgICAgKiBAcGFyYW0gZW5kcG9pbnRzRW50ZXJpbmdMYXN0TiB0aGUgbGlzdCBjdXJyZW50bHkgZW50ZXJpbmcgbGFzdCBOXG4gICAgICogZW5kcG9pbnRzXG4gICAgICovXG4gICAgJChkb2N1bWVudCkuYmluZCgnbGFzdG5jaGFuZ2VkJywgZnVuY3Rpb24gKCBldmVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RORW5kcG9pbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kcG9pbnRzRW50ZXJpbmdMYXN0TixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmVhbSkge1xuICAgICAgICBpZiAobGFzdE5Db3VudCAhPT0gbGFzdE5FbmRwb2ludHMubGVuZ3RoKVxuICAgICAgICAgICAgbGFzdE5Db3VudCA9IGxhc3RORW5kcG9pbnRzLmxlbmd0aDtcblxuICAgICAgICBsYXN0TkVuZHBvaW50c0NhY2hlID0gbGFzdE5FbmRwb2ludHM7XG5cbiAgICAgICAgLy8gU2F5IEEsIEIsIEMsIEQsIEUsIGFuZCBGIGFyZSBpbiBhIGNvbmZlcmVuY2UgYW5kIExhc3ROID0gMy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gSWYgTGFzdE4gZHJvcHMgdG8sIHNheSwgMiwgYmVjYXVzZSBvZiBhZGFwdGl2aXR5LCB0aGVuIEUgc2hvdWxkIHNlZVxuICAgICAgICAvLyB0aHVtYm5haWxzIGZvciBBLCBCIGFuZCBDLiBBIGFuZCBCIGFyZSBpbiBFJ3Mgc2VydmVyIHNpZGUgTGFzdE4gc2V0LFxuICAgICAgICAvLyBzbyBFIHNlZXMgdGhlbS4gQyBpcyBvbmx5IGluIEUncyBsb2NhbCBMYXN0TiBzZXQuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIElmIEYgc3RhcnRzIHRhbGtpbmcgYW5kIExhc3ROID0gMywgdGhlbiBFIHNob3VsZCBzZWUgdGh1bWJuYWlscyBmb3JcbiAgICAgICAgLy8gRiwgQSwgQi4gQiBnZXRzIFwiZWplY3RlZFwiIGZyb20gRSdzIHNlcnZlciBzaWRlIExhc3ROIHNldCwgYnV0IGl0XG4gICAgICAgIC8vIGVudGVycyBFJ3MgbG9jYWwgTGFzdE4gZWplY3RpbmcgQy5cblxuICAgICAgICAvLyBJbmNyZWFzZSB0aGUgbG9jYWwgTGFzdE4gc2V0IHNpemUsIGlmIG5lY2Vzc2FyeS5cbiAgICAgICAgaWYgKGxhc3ROQ291bnQgPiBsb2NhbExhc3ROQ291bnQpIHtcbiAgICAgICAgICAgIGxvY2FsTGFzdE5Db3VudCA9IGxhc3ROQ291bnQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVcGRhdGUgdGhlIGxvY2FsIExhc3ROIHNldCBwcmVzZXJ2aW5nIHRoZSBvcmRlciBpbiB3aGljaCB0aGVcbiAgICAgICAgLy8gZW5kcG9pbnRzIGFwcGVhcmVkIGluIHRoZSBMYXN0Ti9sb2NhbCBMYXN0TiBzZXQuXG5cbiAgICAgICAgdmFyIG5leHRMb2NhbExhc3ROU2V0ID0gbGFzdE5FbmRwb2ludHMuc2xpY2UoMCk7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbG9jYWxMYXN0TlNldC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKG5leHRMb2NhbExhc3ROU2V0Lmxlbmd0aCA+PSBsb2NhbExhc3ROQ291bnQpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJlc291cmNlSmlkID0gbG9jYWxMYXN0TlNldFtpXTtcbiAgICAgICAgICAgIGlmIChuZXh0TG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICBuZXh0TG9jYWxMYXN0TlNldC5wdXNoKHJlc291cmNlSmlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxvY2FsTGFzdE5TZXQgPSBuZXh0TG9jYWxMYXN0TlNldDtcblxuICAgICAgICB2YXIgdXBkYXRlTGFyZ2VWaWRlbyA9IGZhbHNlO1xuXG4gICAgICAgIC8vIEhhbmRsZSBMYXN0Ti9sb2NhbCBMYXN0TiBjaGFuZ2VzLlxuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zPnNwYW4nKS5lYWNoKGZ1bmN0aW9uKCBpbmRleCwgZWxlbWVudCApIHtcbiAgICAgICAgICAgIHZhciByZXNvdXJjZUppZCA9IFZpZGVvTGF5b3V0LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZChlbGVtZW50KTtcblxuICAgICAgICAgICAgdmFyIGlzUmVjZWl2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgaWYgKHJlc291cmNlSmlkXG4gICAgICAgICAgICAgICAgJiYgbGFzdE5FbmRwb2ludHMuaW5kZXhPZihyZXNvdXJjZUppZCkgPCAwXG4gICAgICAgICAgICAgICAgJiYgbG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA8IDApIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIlJlbW92ZSBmcm9tIGxhc3QgTlwiLCByZXNvdXJjZUppZCk7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdoaWRlJyk7XG4gICAgICAgICAgICAgICAgaXNSZWNlaXZlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChyZXNvdXJjZUppZFxuICAgICAgICAgICAgICAgICYmICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQpLmlzKCc6dmlzaWJsZScpXG4gICAgICAgICAgICAgICAgJiYgbGFzdE5FbmRwb2ludHMuaW5kZXhPZihyZXNvdXJjZUppZCkgPCAwXG4gICAgICAgICAgICAgICAgJiYgbG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA+PSAwKSB7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdhdmF0YXInKTtcbiAgICAgICAgICAgICAgICBpc1JlY2VpdmVkID0gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghaXNSZWNlaXZlZCkge1xuICAgICAgICAgICAgICAgIC8vIHJlc291cmNlSmlkIGhhcyBkcm9wcGVkIG91dCBvZiB0aGUgc2VydmVyIHNpZGUgbGFzdE4gc2V0LCBzb1xuICAgICAgICAgICAgICAgIC8vIGl0IGlzIG5vIGxvbmdlciBiZWluZyByZWNlaXZlZC4gSWYgcmVzb3VyY2VKaWQgd2FzIGJlaW5nXG4gICAgICAgICAgICAgICAgLy8gZGlzcGxheWVkIGluIHRoZSBsYXJnZSB2aWRlbyB3ZSBoYXZlIHRvIHN3aXRjaCB0byBhbm90aGVyXG4gICAgICAgICAgICAgICAgLy8gdXNlci5cbiAgICAgICAgICAgICAgICB2YXIgbGFyZ2VWaWRlb1Jlc291cmNlID0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZDtcbiAgICAgICAgICAgICAgICBpZiAoIXVwZGF0ZUxhcmdlVmlkZW8gJiYgcmVzb3VyY2VKaWQgPT09IGxhcmdlVmlkZW9SZXNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICB1cGRhdGVMYXJnZVZpZGVvID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghZW5kcG9pbnRzRW50ZXJpbmdMYXN0TiB8fCBlbmRwb2ludHNFbnRlcmluZ0xhc3ROLmxlbmd0aCA8IDApXG4gICAgICAgICAgICBlbmRwb2ludHNFbnRlcmluZ0xhc3ROID0gbGFzdE5FbmRwb2ludHM7XG5cbiAgICAgICAgaWYgKGVuZHBvaW50c0VudGVyaW5nTGFzdE4gJiYgZW5kcG9pbnRzRW50ZXJpbmdMYXN0Ti5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBlbmRwb2ludHNFbnRlcmluZ0xhc3ROLmZvckVhY2goZnVuY3Rpb24gKHJlc291cmNlSmlkKSB7XG5cbiAgICAgICAgICAgICAgICB2YXIgaXNWaXNpYmxlID0gJCgnI3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZCkuaXMoJzp2aXNpYmxlJyk7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdzaG93Jyk7XG4gICAgICAgICAgICAgICAgaWYgKCFpc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJBZGQgdG8gbGFzdCBOXCIsIHJlc291cmNlSmlkKTtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgamlkID0gY29ubmVjdGlvbi5lbXVjLmZpbmRKaWRGcm9tUmVzb3VyY2UocmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgbWVkaWFTdHJlYW0gPSBSVEMucmVtb3RlU3RyZWFtc1tqaWRdW01lZGlhU3RyZWFtVHlwZS5WSURFT19UWVBFXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlbCA9ICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQgKyAnPnZpZGVvJyk7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIHZpZGVvU3RyZWFtID0gc2ltdWxjYXN0LmdldFJlY2VpdmluZ1ZpZGVvU3RyZWFtKFxuICAgICAgICAgICAgICAgICAgICAgICAgbWVkaWFTdHJlYW0uc3RyZWFtKTtcbiAgICAgICAgICAgICAgICAgICAgUlRDLmF0dGFjaE1lZGlhU3RyZWFtKHNlbCwgdmlkZW9TdHJlYW0pO1xuICAgICAgICAgICAgICAgICAgICBpZiAobGFzdE5QaWNrdXBKaWQgPT0gbWVkaWFTdHJlYW0ucGVlcmppZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2xlYW4gdXAgdGhlIGxhc3ROIHBpY2t1cCBqaWQuXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXN0TlBpY2t1cEppZCA9IG51bGw7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIERvbid0IGZpcmUgdGhlIGV2ZW50cyBhZ2FpbiwgdGhleSd2ZSBhbHJlYWR5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBiZWVuIGZpcmVkIGluIHRoZSBjb250YWN0IGxpc3QgY2xpY2sgaGFuZGxlci5cbiAgICAgICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmhhbmRsZVZpZGVvVGh1bWJDbGlja2VkKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoc2VsKS5hdHRyKCdzcmMnKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChtZWRpYVN0cmVhbS5wZWVyamlkKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZUxhcmdlVmlkZW8gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB3YWl0Rm9yUmVtb3RlVmlkZW8oc2VsLCBtZWRpYVN0cmVhbS5zc3JjLCBtZWRpYVN0cmVhbS5zdHJlYW0sIHJlc291cmNlSmlkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gVGhlIGVuZHBvaW50IHRoYXQgd2FzIGJlaW5nIHNob3duIGluIHRoZSBsYXJnZSB2aWRlbyBoYXMgZHJvcHBlZCBvdXRcbiAgICAgICAgLy8gb2YgdGhlIGxhc3ROIHNldCBhbmQgdGhlcmUgd2FzIG5vIGxhc3ROIHBpY2t1cCBqaWQuIFdlIG5lZWQgdG8gdXBkYXRlXG4gICAgICAgIC8vIHRoZSBsYXJnZSB2aWRlbyBub3cuXG5cbiAgICAgICAgaWYgKHVwZGF0ZUxhcmdlVmlkZW8pIHtcblxuICAgICAgICAgICAgdmFyIHJlc291cmNlLCBjb250YWluZXIsIHNyYztcbiAgICAgICAgICAgIHZhciBteVJlc291cmNlXG4gICAgICAgICAgICAgICAgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChjb25uZWN0aW9uLmVtdWMubXlyb29tamlkKTtcblxuICAgICAgICAgICAgLy8gRmluZCBvdXQgd2hpY2ggZW5kcG9pbnQgdG8gc2hvdyBpbiB0aGUgbGFyZ2UgdmlkZW8uXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxhc3RORW5kcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcmVzb3VyY2UgPSBsYXN0TkVuZHBvaW50c1tpXTtcbiAgICAgICAgICAgICAgICBpZiAoIXJlc291cmNlIHx8IHJlc291cmNlID09PSBteVJlc291cmNlKVxuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcblxuICAgICAgICAgICAgICAgIGNvbnRhaW5lciA9ICQoXCIjcGFydGljaXBhbnRfXCIgKyByZXNvdXJjZSk7XG4gICAgICAgICAgICAgICAgaWYgKGNvbnRhaW5lci5sZW5ndGggPT0gMClcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG5cbiAgICAgICAgICAgICAgICBzcmMgPSAkKCd2aWRlbycsIGNvbnRhaW5lcikuYXR0cignc3JjJyk7XG4gICAgICAgICAgICAgICAgaWYgKCFzcmMpXG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICAgICAgLy8gdmlkZW9TcmNUb1NzcmMgbmVlZHMgdG8gYmUgdXBkYXRlIGZvciB0aGlzIGNhbGwgdG8gc3VjY2VlZC5cbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKHNyYyk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgJChkb2N1bWVudCkuYmluZCgndmlkZW9hY3RpdmUuamluZ2xlJywgZnVuY3Rpb24gKGV2ZW50LCB2aWRlb2VsZW0pIHtcbiAgICAgICAgaWYgKHZpZGVvZWxlbS5hdHRyKCdpZCcpLmluZGV4T2YoJ21peGVkbXNsYWJlbCcpID09PSAtMSkge1xuICAgICAgICAgICAgLy8gaWdub3JlIG1peGVkbXNsYWJlbGEwIGFuZCB2MFxuXG4gICAgICAgICAgICB2aWRlb2VsZW0uc2hvdygpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplVGh1bWJuYWlscygpO1xuXG4gICAgICAgICAgICB2YXIgdmlkZW9QYXJlbnQgPSB2aWRlb2VsZW0ucGFyZW50KCk7XG4gICAgICAgICAgICB2YXIgcGFyZW50UmVzb3VyY2VKaWQgPSBudWxsO1xuICAgICAgICAgICAgaWYgKHZpZGVvUGFyZW50KVxuICAgICAgICAgICAgICAgIHBhcmVudFJlc291cmNlSmlkXG4gICAgICAgICAgICAgICAgICAgID0gVmlkZW9MYXlvdXQuZ2V0UGVlckNvbnRhaW5lclJlc291cmNlSmlkKHZpZGVvUGFyZW50WzBdKTtcblxuICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSBsYXJnZSB2aWRlbyB0byB0aGUgbGFzdCBhZGRlZCB2aWRlbyBvbmx5IGlmIHRoZXJlJ3Mgbm9cbiAgICAgICAgICAgIC8vIGN1cnJlbnQgZG9taW5hbnQsIGZvY3VzZWQgc3BlYWtlciBvciBwcmV6aSBwbGF5aW5nIG9yIHVwZGF0ZSBpdCB0b1xuICAgICAgICAgICAgLy8gdGhlIGN1cnJlbnQgZG9taW5hbnQgc3BlYWtlci5cbiAgICAgICAgICAgIGlmICgoIWZvY3VzZWRWaWRlb0luZm8gJiZcbiAgICAgICAgICAgICAgICAhVmlkZW9MYXlvdXQuZ2V0RG9taW5hbnRTcGVha2VyUmVzb3VyY2VKaWQoKSAmJlxuICAgICAgICAgICAgICAgICFyZXF1aXJlKFwiLi4vcHJlemkvUHJlemlcIikuaXNQcmVzZW50YXRpb25WaXNpYmxlKCkpIHx8XG4gICAgICAgICAgICAgICAgKHBhcmVudFJlc291cmNlSmlkICYmXG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuZ2V0RG9taW5hbnRTcGVha2VyUmVzb3VyY2VKaWQoKSA9PT0gcGFyZW50UmVzb3VyY2VKaWQpKSB7XG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlTGFyZ2VWaWRlbyhcbiAgICAgICAgICAgICAgICAgICAgUlRDLmdldFZpZGVvU3JjKHZpZGVvZWxlbVswXSksXG4gICAgICAgICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgICAgICAgIHBhcmVudFJlc291cmNlSmlkKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2hvd01vZGVyYXRvckluZGljYXRvcigpO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICAkKGRvY3VtZW50KS5iaW5kKCdzaW11bGNhc3RsYXllcnNjaGFuZ2luZycsIGZ1bmN0aW9uIChldmVudCwgZW5kcG9pbnRTaW11bGNhc3RMYXllcnMpIHtcbiAgICAgICAgZW5kcG9pbnRTaW11bGNhc3RMYXllcnMuZm9yRWFjaChmdW5jdGlvbiAoZXNsKSB7XG5cbiAgICAgICAgICAgIHZhciByZXNvdXJjZSA9IGVzbC5lbmRwb2ludDtcblxuICAgICAgICAgICAgLy8gaWYgbGFzdE4gaXMgZW5hYmxlZCAqYW5kKiB0aGUgZW5kcG9pbnQgaXMgKm5vdCogaW4gdGhlIGxhc3ROIHNldCxcbiAgICAgICAgICAgIC8vIHRoZW4gaWdub3JlIHRoZSBldmVudCAoPSBkbyBub3QgcHJlbG9hZCBhbnl0aGluZykuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gVGhlIGJyaWRnZSBjb3VsZCBwcm9iYWJseSBzdG9wIHNlbmRpbmcgdGhpcyBtZXNzYWdlIGlmIGl0J3MgZm9yXG4gICAgICAgICAgICAvLyBhbiBlbmRwb2ludCB0aGF0J3Mgbm90IGluIGxhc3ROLlxuXG4gICAgICAgICAgICBpZiAobGFzdE5Db3VudCAhPSAtMVxuICAgICAgICAgICAgICAgICYmIChsYXN0TkNvdW50IDwgMSB8fCBsYXN0TkVuZHBvaW50c0NhY2hlLmluZGV4T2YocmVzb3VyY2UpID09PSAtMSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwcmltYXJ5U1NSQyA9IGVzbC5zaW11bGNhc3RMYXllci5wcmltYXJ5U1NSQztcblxuICAgICAgICAgICAgLy8gR2V0IHNlc3Npb24gYW5kIHN0cmVhbSBmcm9tIHByaW1hcnkgc3NyYy5cbiAgICAgICAgICAgIHZhciByZXMgPSBzaW11bGNhc3QuZ2V0UmVjZWl2aW5nVmlkZW9TdHJlYW1CeVNTUkMocHJpbWFyeVNTUkMpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSByZXMuc2Vzc2lvbjtcbiAgICAgICAgICAgIHZhciBlbGVjdGVkU3RyZWFtID0gcmVzLnN0cmVhbTtcblxuICAgICAgICAgICAgaWYgKHNlc3Npb24gJiYgZWxlY3RlZFN0cmVhbSkge1xuICAgICAgICAgICAgICAgIHZhciBtc2lkID0gc2ltdWxjYXN0LmdldFJlbW90ZVZpZGVvU3RyZWFtSWRCeVNTUkMocHJpbWFyeVNTUkMpO1xuXG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFtlc2wsIHByaW1hcnlTU1JDLCBtc2lkLCBzZXNzaW9uLCBlbGVjdGVkU3RyZWFtXSk7XG5cbiAgICAgICAgICAgICAgICB2YXIgbXNpZFBhcnRzID0gbXNpZC5zcGxpdCgnICcpO1xuXG4gICAgICAgICAgICAgICAgdmFyIHByZWxvYWQgPSAoU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoc3NyYzJqaWRbcHJpbWFyeVNTUkNdKSA9PSBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkKTtcblxuICAgICAgICAgICAgICAgIGlmIChwcmVsb2FkKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChsYXJnZVZpZGVvU3RhdGUucHJlbG9hZClcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgJChsYXJnZVZpZGVvU3RhdGUucHJlbG9hZCkucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdQcmVsb2FkaW5nIHJlbW90ZSB2aWRlbycpO1xuICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZCA9ICQoJzx2aWRlbyBhdXRvcGxheT48L3ZpZGVvPicpO1xuICAgICAgICAgICAgICAgICAgICAvLyBzc3JjcyBhcmUgdW5pcXVlIGluIGFuIHJ0cCBzZXNzaW9uXG4gICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkX3NzcmMgPSBwcmltYXJ5U1NSQztcblxuICAgICAgICAgICAgICAgICAgICBSVEMuYXR0YWNoTWVkaWFTdHJlYW0obGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQsIGVsZWN0ZWRTdHJlYW0pXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0NvdWxkIG5vdCBmaW5kIGEgc3RyZWFtIG9yIGEgc2Vzc2lvbi4nLCBzZXNzaW9uLCBlbGVjdGVkU3RyZWFtKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBPbiBzaW11bGNhc3QgbGF5ZXJzIGNoYW5nZWQgZXZlbnQuXG4gICAgICovXG4gICAgJChkb2N1bWVudCkuYmluZCgnc2ltdWxjYXN0bGF5ZXJzY2hhbmdlZCcsIGZ1bmN0aW9uIChldmVudCwgZW5kcG9pbnRTaW11bGNhc3RMYXllcnMpIHtcbiAgICAgICAgZW5kcG9pbnRTaW11bGNhc3RMYXllcnMuZm9yRWFjaChmdW5jdGlvbiAoZXNsKSB7XG5cbiAgICAgICAgICAgIHZhciByZXNvdXJjZSA9IGVzbC5lbmRwb2ludDtcblxuICAgICAgICAgICAgLy8gaWYgbGFzdE4gaXMgZW5hYmxlZCAqYW5kKiB0aGUgZW5kcG9pbnQgaXMgKm5vdCogaW4gdGhlIGxhc3ROIHNldCxcbiAgICAgICAgICAgIC8vIHRoZW4gaWdub3JlIHRoZSBldmVudCAoPSBkbyBub3QgY2hhbmdlIGxhcmdlIHZpZGVvL3RodW1ibmFpbFxuICAgICAgICAgICAgLy8gU1JDcykuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gTm90ZSB0aGF0IGV2ZW4gaWYgd2UgaWdub3JlIHRoZSBcImNoYW5nZWRcIiBldmVudCBpbiB0aGlzIGV2ZW50XG4gICAgICAgICAgICAvLyBoYW5kbGVyLCB0aGUgYnJpZGdlIG11c3QgY29udGludWUgc2VuZGluZyB0aGVzZSBldmVudHMgYmVjYXVzZVxuICAgICAgICAgICAgLy8gdGhlIHNpbXVsY2FzdCBjb2RlIGluIHNpbXVsY2FzdC5qcyB1c2VzIGl0IHRvIGtub3cgd2hhdCdzIGdvaW5nXG4gICAgICAgICAgICAvLyB0byBiZSBzdHJlYW1lZCBieSB0aGUgYnJpZGdlIHdoZW4vaWYgdGhlIGVuZHBvaW50IGdldHMgYmFjayBpbnRvXG4gICAgICAgICAgICAvLyB0aGUgbGFzdE4gc2V0LlxuXG4gICAgICAgICAgICBpZiAobGFzdE5Db3VudCAhPSAtMVxuICAgICAgICAgICAgICAgICYmIChsYXN0TkNvdW50IDwgMSB8fCBsYXN0TkVuZHBvaW50c0NhY2hlLmluZGV4T2YocmVzb3VyY2UpID09PSAtMSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwcmltYXJ5U1NSQyA9IGVzbC5zaW11bGNhc3RMYXllci5wcmltYXJ5U1NSQztcblxuICAgICAgICAgICAgLy8gR2V0IHNlc3Npb24gYW5kIHN0cmVhbSBmcm9tIHByaW1hcnkgc3NyYy5cbiAgICAgICAgICAgIHZhciByZXMgPSBzaW11bGNhc3QuZ2V0UmVjZWl2aW5nVmlkZW9TdHJlYW1CeVNTUkMocHJpbWFyeVNTUkMpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSByZXMuc2Vzc2lvbjtcbiAgICAgICAgICAgIHZhciBlbGVjdGVkU3RyZWFtID0gcmVzLnN0cmVhbTtcblxuICAgICAgICAgICAgaWYgKHNlc3Npb24gJiYgZWxlY3RlZFN0cmVhbSkge1xuICAgICAgICAgICAgICAgIHZhciBtc2lkID0gc2ltdWxjYXN0LmdldFJlbW90ZVZpZGVvU3RyZWFtSWRCeVNTUkMocHJpbWFyeVNTUkMpO1xuXG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdTd2l0Y2hpbmcgc2ltdWxjYXN0IHN1YnN0cmVhbS4nKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oW2VzbCwgcHJpbWFyeVNTUkMsIG1zaWQsIHNlc3Npb24sIGVsZWN0ZWRTdHJlYW1dKTtcblxuICAgICAgICAgICAgICAgIHZhciBtc2lkUGFydHMgPSBtc2lkLnNwbGl0KCcgJyk7XG4gICAgICAgICAgICAgICAgdmFyIHNlbFJlbW90ZVZpZGVvID0gJChbJyMnLCAncmVtb3RlVmlkZW9fJywgc2Vzc2lvbi5zaWQsICdfJywgbXNpZFBhcnRzWzBdXS5qb2luKCcnKSk7XG5cbiAgICAgICAgICAgICAgICB2YXIgdXBkYXRlTGFyZ2VWaWRlbyA9IChTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChzc3JjMmppZFtwcmltYXJ5U1NSQ10pXG4gICAgICAgICAgICAgICAgICAgID09IGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgICAgIHZhciB1cGRhdGVGb2N1c2VkVmlkZW9TcmMgPSAoZm9jdXNlZFZpZGVvSW5mbyAmJiBmb2N1c2VkVmlkZW9JbmZvLnNyYyAmJiBmb2N1c2VkVmlkZW9JbmZvLnNyYyAhPSAnJyAmJlxuICAgICAgICAgICAgICAgICAgICAoUlRDLmdldFZpZGVvU3JjKHNlbFJlbW90ZVZpZGVvWzBdKSA9PSBmb2N1c2VkVmlkZW9JbmZvLnNyYykpO1xuXG4gICAgICAgICAgICAgICAgdmFyIGVsZWN0ZWRTdHJlYW1Vcmw7XG4gICAgICAgICAgICAgICAgaWYgKGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkX3NzcmMgPT0gcHJpbWFyeVNTUkMpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBSVEMuc2V0VmlkZW9TcmMoc2VsUmVtb3RlVmlkZW9bMF0sIFJUQy5nZXRWaWRlb1NyYyhsYXJnZVZpZGVvU3RhdGUucHJlbG9hZFswXSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWRcbiAgICAgICAgICAgICAgICAgICAgICAgICYmIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICQobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQpLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWRfc3NyYyA9IDA7XG5cbiAgICAgICAgICAgICAgICAgICAgUlRDLmF0dGFjaE1lZGlhU3RyZWFtKHNlbFJlbW90ZVZpZGVvLCBlbGVjdGVkU3RyZWFtKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgamlkID0gc3NyYzJqaWRbcHJpbWFyeVNTUkNdO1xuICAgICAgICAgICAgICAgIGppZDJTc3JjW2ppZF0gPSBwcmltYXJ5U1NSQztcblxuICAgICAgICAgICAgICAgIGlmICh1cGRhdGVMYXJnZVZpZGVvKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oUlRDLmdldFZpZGVvU3JjKHNlbFJlbW90ZVZpZGVvWzBdKSwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCkpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh1cGRhdGVGb2N1c2VkVmlkZW9TcmMpIHtcbiAgICAgICAgICAgICAgICAgICAgZm9jdXNlZFZpZGVvSW5mby5zcmMgPSBSVEMuZ2V0VmlkZW9TcmMoc2VsUmVtb3RlVmlkZW9bMF0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciB2aWRlb0lkO1xuICAgICAgICAgICAgICAgIGlmKHJlc291cmNlID09IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQpKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdmlkZW9JZCA9IFwibG9jYWxWaWRlb0NvbnRhaW5lclwiO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB2aWRlb0lkID0gXCJwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgY29ubmVjdGlvbkluZGljYXRvciA9IFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW3ZpZGVvSWRdO1xuICAgICAgICAgICAgICAgIGlmKGNvbm5lY3Rpb25JbmRpY2F0b3IpXG4gICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25JbmRpY2F0b3IudXBkYXRlUG9wb3ZlckRhdGEoKTtcblxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdDb3VsZCBub3QgZmluZCBhIHN0cmVhbSBvciBhIHNlc3Npb24uJywgc2Vzc2lvbiwgZWxlY3RlZFN0cmVhbSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyBsb2NhbCBzdGF0c1xuICAgICAqIEBwYXJhbSBwZXJjZW50XG4gICAgICogQHBhcmFtIG9iamVjdFxuICAgICAqL1xuICAgIG15LnVwZGF0ZUxvY2FsQ29ubmVjdGlvblN0YXRzID0gZnVuY3Rpb24gKHBlcmNlbnQsIG9iamVjdCkge1xuICAgICAgICB2YXIgcmVzb2x1dGlvbiA9IG51bGw7XG4gICAgICAgIGlmKG9iamVjdC5yZXNvbHV0aW9uICE9PSBudWxsKVxuICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHV0aW9uID0gb2JqZWN0LnJlc29sdXRpb247XG4gICAgICAgICAgICBvYmplY3QucmVzb2x1dGlvbiA9IHJlc29sdXRpb25bY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZF07XG4gICAgICAgICAgICBkZWxldGUgcmVzb2x1dGlvbltjb25uZWN0aW9uLmVtdWMubXlyb29tamlkXTtcbiAgICAgICAgfVxuICAgICAgICB1cGRhdGVTdGF0c0luZGljYXRvcihcImxvY2FsVmlkZW9Db250YWluZXJcIiwgcGVyY2VudCwgb2JqZWN0KTtcbiAgICAgICAgZm9yKHZhciBqaWQgaW4gcmVzb2x1dGlvbilcbiAgICAgICAge1xuICAgICAgICAgICAgaWYocmVzb2x1dGlvbltqaWRdID09PSBudWxsKVxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgdmFyIGlkID0gJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuICAgICAgICAgICAgaWYoVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbaWRdKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW2lkXS51cGRhdGVSZXNvbHV0aW9uKHJlc29sdXRpb25bamlkXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHJlbW90ZSBzdGF0cy5cbiAgICAgKiBAcGFyYW0gamlkIHRoZSBqaWQgYXNzb2NpYXRlZCB3aXRoIHRoZSBzdGF0c1xuICAgICAqIEBwYXJhbSBwZXJjZW50IHRoZSBjb25uZWN0aW9uIHF1YWxpdHkgcGVyY2VudFxuICAgICAqIEBwYXJhbSBvYmplY3QgdGhlIHN0YXRzIGRhdGFcbiAgICAgKi9cbiAgICBteS51cGRhdGVDb25uZWN0aW9uU3RhdHMgPSBmdW5jdGlvbiAoamlkLCBwZXJjZW50LCBvYmplY3QpIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcblxuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkO1xuICAgICAgICB1cGRhdGVTdGF0c0luZGljYXRvcih2aWRlb1NwYW5JZCwgcGVyY2VudCwgb2JqZWN0KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgY29ubmVjdGlvblxuICAgICAqIEBwYXJhbSBqaWRcbiAgICAgKi9cbiAgICBteS5yZW1vdmVDb25uZWN0aW9uSW5kaWNhdG9yID0gZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1sncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCldKVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpXS5yZW1vdmUoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSGlkZXMgdGhlIGNvbm5lY3Rpb24gaW5kaWNhdG9yXG4gICAgICogQHBhcmFtIGppZFxuICAgICAqL1xuICAgIG15LmhpZGVDb25uZWN0aW9uSW5kaWNhdG9yID0gZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1sncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCldKVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpXS5oaWRlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEhpZGVzIGFsbCB0aGUgaW5kaWNhdG9yc1xuICAgICAqL1xuICAgIG15Lm9uU3RhdHNTdG9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBmb3IodmFyIGluZGljYXRvciBpbiBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9ycylcbiAgICAgICAge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbaW5kaWNhdG9yXS5oaWRlSW5kaWNhdG9yKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIG15O1xufShWaWRlb0xheW91dCB8fCB7fSkpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFZpZGVvTGF5b3V0OyIsIi8vdmFyIG5vdW5zID0gW1xuLy9dO1xudmFyIHBsdXJhbE5vdW5zID0gW1xuICAgIFwiQWxpZW5zXCIsIFwiQW5pbWFsc1wiLCBcIkFudGVsb3Blc1wiLCBcIkFudHNcIiwgXCJBcGVzXCIsIFwiQXBwbGVzXCIsIFwiQmFib29uc1wiLCBcIkJhY3RlcmlhXCIsIFwiQmFkZ2Vyc1wiLCBcIkJhbmFuYXNcIiwgXCJCYXRzXCIsXG4gICAgXCJCZWFyc1wiLCBcIkJpcmRzXCIsIFwiQm9ub2Jvc1wiLCBcIkJyaWRlc1wiLCBcIkJ1Z3NcIiwgXCJCdWxsc1wiLCBcIkJ1dHRlcmZsaWVzXCIsIFwiQ2hlZXRhaHNcIixcbiAgICBcIkNoZXJyaWVzXCIsIFwiQ2hpY2tlblwiLCBcIkNoaWxkcmVuXCIsIFwiQ2hpbXBzXCIsIFwiQ2xvd25zXCIsIFwiQ293c1wiLCBcIkNyZWF0dXJlc1wiLCBcIkRpbm9zYXVyc1wiLCBcIkRvZ3NcIiwgXCJEb2xwaGluc1wiLFxuICAgIFwiRG9ua2V5c1wiLCBcIkRyYWdvbnNcIiwgXCJEdWNrc1wiLCBcIkR3YXJmc1wiLCBcIkVhZ2xlc1wiLCBcIkVsZXBoYW50c1wiLCBcIkVsdmVzXCIsIFwiRkFJTFwiLCBcIkZhdGhlcnNcIixcbiAgICBcIkZpc2hcIiwgXCJGbG93ZXJzXCIsIFwiRnJvZ3NcIiwgXCJGcnVpdFwiLCBcIkZ1bmdpXCIsIFwiR2FsYXhpZXNcIiwgXCJHZWVzZVwiLCBcIkdvYXRzXCIsXG4gICAgXCJHb3JpbGxhc1wiLCBcIkhlZGdlaG9nc1wiLCBcIkhpcHBvc1wiLCBcIkhvcnNlc1wiLCBcIkh1bnRlcnNcIiwgXCJJbnNlY3RzXCIsIFwiS2lkc1wiLCBcIktuaWdodHNcIixcbiAgICBcIkxlbW9uc1wiLCBcIkxlbXVyc1wiLCBcIkxlb3BhcmRzXCIsIFwiTGlmZUZvcm1zXCIsIFwiTGlvbnNcIiwgXCJMaXphcmRzXCIsIFwiTWljZVwiLCBcIk1vbmtleXNcIiwgXCJNb25zdGVyc1wiLFxuICAgIFwiTXVzaHJvb21zXCIsIFwiT2N0b3BvZGVzXCIsIFwiT3Jhbmdlc1wiLCBcIk9yYW5ndXRhbnNcIiwgXCJPcmdhbmlzbXNcIiwgXCJQYW50c1wiLCBcIlBhcnJvdHNcIiwgXCJQZW5ndWluc1wiLFxuICAgIFwiUGVvcGxlXCIsIFwiUGlnZW9uc1wiLCBcIlBpZ3NcIiwgXCJQaW5lYXBwbGVzXCIsIFwiUGxhbnRzXCIsIFwiUG90YXRvZXNcIiwgXCJQcmllc3RzXCIsIFwiUmF0c1wiLCBcIlJlcHRpbGVzXCIsIFwiUmVwdGlsaWFuc1wiLFxuICAgIFwiUmhpbm9zXCIsIFwiU2VhZ3VsbHNcIiwgXCJTaGVlcFwiLCBcIlNpYmxpbmdzXCIsIFwiU25ha2VzXCIsIFwiU3BhZ2hldHRpXCIsIFwiU3BpZGVyc1wiLCBcIlNxdWlkXCIsIFwiU3F1aXJyZWxzXCIsXG4gICAgXCJTdGFyc1wiLCBcIlN0dWRlbnRzXCIsIFwiVGVhY2hlcnNcIiwgXCJUaWdlcnNcIiwgXCJUb21hdG9lc1wiLCBcIlRyZWVzXCIsIFwiVmFtcGlyZXNcIiwgXCJWZWdldGFibGVzXCIsIFwiVmlydXNlc1wiLCBcIlZ1bGNhbnNcIixcbiAgICBcIldhcmV3b2x2ZXNcIiwgXCJXZWFzZWxzXCIsIFwiV2hhbGVzXCIsIFwiV2l0Y2hlc1wiLCBcIldpemFyZHNcIiwgXCJXb2x2ZXNcIiwgXCJXb3JrZXJzXCIsIFwiV29ybXNcIiwgXCJaZWJyYXNcIlxuXTtcbi8vdmFyIHBsYWNlcyA9IFtcbi8vXCJQdWJcIiwgXCJVbml2ZXJzaXR5XCIsIFwiQWlycG9ydFwiLCBcIkxpYnJhcnlcIiwgXCJNYWxsXCIsIFwiVGhlYXRlclwiLCBcIlN0YWRpdW1cIiwgXCJPZmZpY2VcIiwgXCJTaG93XCIsIFwiR2FsbG93c1wiLCBcIkJlYWNoXCIsXG4vLyBcIkNlbWV0ZXJ5XCIsIFwiSG9zcGl0YWxcIiwgXCJSZWNlcHRpb25cIiwgXCJSZXN0YXVyYW50XCIsIFwiQmFyXCIsIFwiQ2h1cmNoXCIsIFwiSG91c2VcIiwgXCJTY2hvb2xcIiwgXCJTcXVhcmVcIiwgXCJWaWxsYWdlXCIsXG4vLyBcIkNpbmVtYVwiLCBcIk1vdmllc1wiLCBcIlBhcnR5XCIsIFwiUmVzdHJvb21cIiwgXCJFbmRcIiwgXCJKYWlsXCIsIFwiUG9zdE9mZmljZVwiLCBcIlN0YXRpb25cIiwgXCJDaXJjdXNcIiwgXCJHYXRlc1wiLCBcIkVudHJhbmNlXCIsXG4vLyBcIkJyaWRnZVwiXG4vL107XG52YXIgdmVyYnMgPSBbXG4gICAgXCJBYmFuZG9uXCIsIFwiQWRhcHRcIiwgXCJBZHZlcnRpc2VcIiwgXCJBbnN3ZXJcIiwgXCJBbnRpY2lwYXRlXCIsIFwiQXBwcmVjaWF0ZVwiLFxuICAgIFwiQXBwcm9hY2hcIiwgXCJBcmd1ZVwiLCBcIkFza1wiLCBcIkJpdGVcIiwgXCJCbG9zc29tXCIsIFwiQmx1c2hcIiwgXCJCcmVhdGhlXCIsIFwiQnJlZWRcIiwgXCJCcmliZVwiLCBcIkJ1cm5cIiwgXCJDYWxjdWxhdGVcIixcbiAgICBcIkNsZWFuXCIsIFwiQ29kZVwiLCBcIkNvbW11bmljYXRlXCIsIFwiQ29tcHV0ZVwiLCBcIkNvbmZlc3NcIiwgXCJDb25maXNjYXRlXCIsIFwiQ29uanVnYXRlXCIsIFwiQ29uanVyZVwiLCBcIkNvbnN1bWVcIixcbiAgICBcIkNvbnRlbXBsYXRlXCIsIFwiQ3Jhd2xcIiwgXCJEYW5jZVwiLCBcIkRlbGVnYXRlXCIsIFwiRGV2b3VyXCIsIFwiRGV2ZWxvcFwiLCBcIkRpZmZlclwiLCBcIkRpc2N1c3NcIixcbiAgICBcIkRpc3NvbHZlXCIsIFwiRHJpbmtcIiwgXCJFYXRcIiwgXCJFbGFib3JhdGVcIiwgXCJFbWFuY2lwYXRlXCIsIFwiRXN0aW1hdGVcIiwgXCJFeHBpcmVcIiwgXCJFeHRpbmd1aXNoXCIsXG4gICAgXCJFeHRyYWN0XCIsIFwiRkFJTFwiLCBcIkZhY2lsaXRhdGVcIiwgXCJGYWxsXCIsIFwiRmVlZFwiLCBcIkZpbmlzaFwiLCBcIkZsb3NzXCIsIFwiRmx5XCIsIFwiRm9sbG93XCIsIFwiRnJhZ21lbnRcIiwgXCJGcmVlemVcIixcbiAgICBcIkdhdGhlclwiLCBcIkdsb3dcIiwgXCJHcm93XCIsIFwiSGV4XCIsIFwiSGlkZVwiLCBcIkh1Z1wiLCBcIkh1cnJ5XCIsIFwiSW1wcm92ZVwiLCBcIkludGVyc2VjdFwiLCBcIkludmVzdGlnYXRlXCIsIFwiSmlueFwiLFxuICAgIFwiSm9rZVwiLCBcIkp1YmlsYXRlXCIsIFwiS2lzc1wiLCBcIkxhdWdoXCIsIFwiTWFuYWdlXCIsIFwiTWVldFwiLCBcIk1lcmdlXCIsIFwiTW92ZVwiLCBcIk9iamVjdFwiLCBcIk9ic2VydmVcIiwgXCJPZmZlclwiLFxuICAgIFwiUGFpbnRcIiwgXCJQYXJ0aWNpcGF0ZVwiLCBcIlBhcnR5XCIsIFwiUGVyZm9ybVwiLCBcIlBsYW5cIiwgXCJQdXJzdWVcIiwgXCJQaWVyY2VcIiwgXCJQbGF5XCIsIFwiUG9zdHBvbmVcIiwgXCJQcmF5XCIsIFwiUHJvY2xhaW1cIixcbiAgICBcIlF1ZXN0aW9uXCIsIFwiUmVhZFwiLCBcIlJlY2tvblwiLCBcIlJlam9pY2VcIiwgXCJSZXByZXNlbnRcIiwgXCJSZXNpemVcIiwgXCJSaHltZVwiLCBcIlNjcmVhbVwiLCBcIlNlYXJjaFwiLCBcIlNlbGVjdFwiLCBcIlNoYXJlXCIsIFwiU2hvb3RcIixcbiAgICBcIlNob3V0XCIsIFwiU2lnbmFsXCIsIFwiU2luZ1wiLCBcIlNrYXRlXCIsIFwiU2xlZXBcIiwgXCJTbWlsZVwiLCBcIlNtb2tlXCIsIFwiU29sdmVcIiwgXCJTcGVsbFwiLCBcIlN0ZWVyXCIsIFwiU3RpbmtcIixcbiAgICBcIlN1YnN0aXR1dGVcIiwgXCJTd2ltXCIsIFwiVGFzdGVcIiwgXCJUZWFjaFwiLCBcIlRlcm1pbmF0ZVwiLCBcIlRoaW5rXCIsIFwiVHlwZVwiLCBcIlVuaXRlXCIsIFwiVmFuaXNoXCIsIFwiV29yc2hpcFwiXG5dO1xudmFyIGFkdmVyYnMgPSBbXG4gICAgXCJBYnNlbnRseVwiLCBcIkFjY3VyYXRlbHlcIiwgXCJBY2N1c2luZ2x5XCIsIFwiQWRvcmFibHlcIiwgXCJBbGxUaGVUaW1lXCIsIFwiQWxvbmVcIiwgXCJBbHdheXNcIiwgXCJBbWF6aW5nbHlcIiwgXCJBbmdyaWx5XCIsXG4gICAgXCJBbnhpb3VzbHlcIiwgXCJBbnl3aGVyZVwiLCBcIkFwcGFsbGluZ2x5XCIsIFwiQXBwYXJlbnRseVwiLCBcIkFydGljdWxhdGVseVwiLCBcIkFzdG9uaXNoaW5nbHlcIiwgXCJCYWRseVwiLCBcIkJhcmVseVwiLFxuICAgIFwiQmVhdXRpZnVsbHlcIiwgXCJCbGluZGx5XCIsIFwiQnJhdmVseVwiLCBcIkJyaWdodGx5XCIsIFwiQnJpc2tseVwiLCBcIkJydXRhbGx5XCIsIFwiQ2FsbWx5XCIsIFwiQ2FyZWZ1bGx5XCIsIFwiQ2FzdWFsbHlcIixcbiAgICBcIkNhdXRpb3VzbHlcIiwgXCJDbGV2ZXJseVwiLCBcIkNvbnN0YW50bHlcIiwgXCJDb3JyZWN0bHlcIiwgXCJDcmF6aWx5XCIsIFwiQ3VyaW91c2x5XCIsIFwiQ3luaWNhbGx5XCIsIFwiRGFpbHlcIixcbiAgICBcIkRhbmdlcm91c2x5XCIsIFwiRGVsaWJlcmF0ZWx5XCIsIFwiRGVsaWNhdGVseVwiLCBcIkRlc3BlcmF0ZWx5XCIsIFwiRGlzY3JlZXRseVwiLCBcIkVhZ2VybHlcIiwgXCJFYXNpbHlcIiwgXCJFdXBob3JpY2x5XCIsXG4gICAgXCJFdmVubHlcIiwgXCJFdmVyeXdoZXJlXCIsIFwiRXhhY3RseVwiLCBcIkV4cGVjdGFudGx5XCIsIFwiRXh0ZW5zaXZlbHlcIiwgXCJGQUlMXCIsIFwiRmVyb2Npb3VzbHlcIiwgXCJGaWVyY2VseVwiLCBcIkZpbmVseVwiLFxuICAgIFwiRmxhdGx5XCIsIFwiRnJlcXVlbnRseVwiLCBcIkZyaWdodGVuaW5nbHlcIiwgXCJHZW50bHlcIiwgXCJHbG9yaW91c2x5XCIsIFwiR3JpbWx5XCIsIFwiR3VpbHRpbHlcIiwgXCJIYXBwaWx5XCIsXG4gICAgXCJIYXJkXCIsIFwiSGFzdGlseVwiLCBcIkhlcm9pY2FsbHlcIiwgXCJIaWdoXCIsIFwiSGlnaGx5XCIsIFwiSG91cmx5XCIsIFwiSHVtYmx5XCIsIFwiSHlzdGVyaWNhbGx5XCIsIFwiSW1tZW5zZWx5XCIsXG4gICAgXCJJbXBhcnRpYWxseVwiLCBcIkltcG9saXRlbHlcIiwgXCJJbmRpZmZlcmVudGx5XCIsIFwiSW50ZW5zZWx5XCIsIFwiSmVhbG91c2x5XCIsIFwiSm92aWFsbHlcIiwgXCJLaW5kbHlcIiwgXCJMYXppbHlcIixcbiAgICBcIkxpZ2h0bHlcIiwgXCJMb3VkbHlcIiwgXCJMb3ZpbmdseVwiLCBcIkxveWFsbHlcIiwgXCJNYWduaWZpY2VudGx5XCIsIFwiTWFsZXZvbGVudGx5XCIsIFwiTWVycmlseVwiLCBcIk1pZ2h0aWx5XCIsIFwiTWlzZXJhYmx5XCIsXG4gICAgXCJNeXN0ZXJpb3VzbHlcIiwgXCJOT1RcIiwgXCJOZXJ2b3VzbHlcIiwgXCJOaWNlbHlcIiwgXCJOb3doZXJlXCIsIFwiT2JqZWN0aXZlbHlcIiwgXCJPYm5veGlvdXNseVwiLCBcIk9ic2Vzc2l2ZWx5XCIsXG4gICAgXCJPYnZpb3VzbHlcIiwgXCJPZnRlblwiLCBcIlBhaW5mdWxseVwiLCBcIlBhdGllbnRseVwiLCBcIlBsYXlmdWxseVwiLCBcIlBvbGl0ZWx5XCIsIFwiUG9vcmx5XCIsIFwiUHJlY2lzZWx5XCIsIFwiUHJvbXB0bHlcIixcbiAgICBcIlF1aWNrbHlcIiwgXCJRdWlldGx5XCIsIFwiUmFuZG9tbHlcIiwgXCJSYXBpZGx5XCIsIFwiUmFyZWx5XCIsIFwiUmVja2xlc3NseVwiLCBcIlJlZ3VsYXJseVwiLCBcIlJlbW9yc2VmdWxseVwiLCBcIlJlc3BvbnNpYmx5XCIsXG4gICAgXCJSdWRlbHlcIiwgXCJSdXRobGVzc2x5XCIsIFwiU2FkbHlcIiwgXCJTY29ybmZ1bGx5XCIsIFwiU2VhbWxlc3NseVwiLCBcIlNlbGRvbVwiLCBcIlNlbGZpc2hseVwiLCBcIlNlcmlvdXNseVwiLCBcIlNoYWtpbHlcIixcbiAgICBcIlNoYXJwbHlcIiwgXCJTaWRld2F5c1wiLCBcIlNpbGVudGx5XCIsIFwiU2xlZXBpbHlcIiwgXCJTbGlnaHRseVwiLCBcIlNsb3dseVwiLCBcIlNseWx5XCIsIFwiU21vb3RobHlcIiwgXCJTb2Z0bHlcIiwgXCJTb2xlbW5seVwiLCBcIlN0ZWFkaWx5XCIsIFwiU3Rlcm5seVwiLCBcIlN0cmFuZ2VseVwiLCBcIlN0cm9uZ2x5XCIsIFwiU3R1bm5pbmdseVwiLCBcIlN1cmVseVwiLCBcIlRlbmRlcmx5XCIsIFwiVGhvdWdodGZ1bGx5XCIsXG4gICAgXCJUaWdodGx5XCIsIFwiVW5lYXNpbHlcIiwgXCJWYW5pc2hpbmdseVwiLCBcIlZpb2xlbnRseVwiLCBcIldhcm1seVwiLCBcIldlYWtseVwiLCBcIldlYXJpbHlcIiwgXCJXZWVrbHlcIiwgXCJXZWlyZGx5XCIsIFwiV2VsbFwiLFxuICAgIFwiV2VsbFwiLCBcIldpY2tlZGx5XCIsIFwiV2lsZGx5XCIsIFwiV2lzZWx5XCIsIFwiV29uZGVyZnVsbHlcIiwgXCJZZWFybHlcIlxuXTtcbnZhciBhZGplY3RpdmVzID0gW1xuICAgIFwiQWJvbWluYWJsZVwiLCBcIkFjY3VyYXRlXCIsIFwiQWRvcmFibGVcIiwgXCJBbGxcIiwgXCJBbGxlZ2VkXCIsIFwiQW5jaWVudFwiLCBcIkFuZ3J5XCIsIFwiQW5ncnlcIiwgXCJBbnhpb3VzXCIsIFwiQXBwYWxsaW5nXCIsXG4gICAgXCJBcHBhcmVudFwiLCBcIkFzdG9uaXNoaW5nXCIsIFwiQXR0cmFjdGl2ZVwiLCBcIkF3ZXNvbWVcIiwgXCJCYWJ5XCIsIFwiQmFkXCIsIFwiQmVhdXRpZnVsXCIsIFwiQmVuaWduXCIsIFwiQmlnXCIsIFwiQml0dGVyXCIsXG4gICAgXCJCbGluZFwiLCBcIkJsdWVcIiwgXCJCb2xkXCIsIFwiQnJhdmVcIiwgXCJCcmlnaHRcIiwgXCJCcmlza1wiLCBcIkNhbG1cIiwgXCJDYW1vdWZsYWdlZFwiLCBcIkNhc3VhbFwiLCBcIkNhdXRpb3VzXCIsXG4gICAgXCJDaG9wcHlcIiwgXCJDaG9zZW5cIiwgXCJDbGV2ZXJcIiwgXCJDb2xkXCIsIFwiQ29vbFwiLCBcIkNyYXdseVwiLCBcIkNyYXp5XCIsIFwiQ3JlZXB5XCIsIFwiQ3J1ZWxcIiwgXCJDdXJpb3VzXCIsIFwiQ3luaWNhbFwiLFxuICAgIFwiRGFuZ2Vyb3VzXCIsIFwiRGFya1wiLCBcIkRlbGljYXRlXCIsIFwiRGVzcGVyYXRlXCIsIFwiRGlmZmljdWx0XCIsIFwiRGlzY3JlZXRcIiwgXCJEaXNndWlzZWRcIiwgXCJEaXp6eVwiLFxuICAgIFwiRHVtYlwiLCBcIkVhZ2VyXCIsIFwiRWFzeVwiLCBcIkVkZ3lcIiwgXCJFbGVjdHJpY1wiLCBcIkVsZWdhbnRcIiwgXCJFbWFuY2lwYXRlZFwiLCBcIkVub3Jtb3VzXCIsIFwiRXVwaG9yaWNcIiwgXCJFdmlsXCIsXG4gICAgXCJGQUlMXCIsIFwiRmFzdFwiLCBcIkZlcm9jaW91c1wiLCBcIkZpZXJjZVwiLCBcIkZpbmVcIiwgXCJGbGF3ZWRcIiwgXCJGbHlpbmdcIiwgXCJGb29saXNoXCIsIFwiRm94eVwiLFxuICAgIFwiRnJlZXppbmdcIiwgXCJGdW5ueVwiLCBcIkZ1cmlvdXNcIiwgXCJHZW50bGVcIiwgXCJHbG9yaW91c1wiLCBcIkdvbGRlblwiLCBcIkdvb2RcIiwgXCJHcmVlblwiLCBcIkdyZWVuXCIsIFwiR3VpbHR5XCIsXG4gICAgXCJIYWlyeVwiLCBcIkhhcHB5XCIsIFwiSGFyZFwiLCBcIkhhc3R5XCIsIFwiSGF6eVwiLCBcIkhlcm9pY1wiLCBcIkhvc3RpbGVcIiwgXCJIb3RcIiwgXCJIdW1ibGVcIiwgXCJIdW1vbmdvdXNcIixcbiAgICBcIkh1bW9yb3VzXCIsIFwiSHlzdGVyaWNhbFwiLCBcIklkZWFsaXN0aWNcIiwgXCJJZ25vcmFudFwiLCBcIkltbWVuc2VcIiwgXCJJbXBhcnRpYWxcIiwgXCJJbXBvbGl0ZVwiLCBcIkluZGlmZmVyZW50XCIsXG4gICAgXCJJbmZ1cmlhdGVkXCIsIFwiSW5zaWdodGZ1bFwiLCBcIkludGVuc2VcIiwgXCJJbnRlcmVzdGluZ1wiLCBcIkludGltaWRhdGVkXCIsIFwiSW50cmlndWluZ1wiLCBcIkplYWxvdXNcIiwgXCJKb2xseVwiLCBcIkpvdmlhbFwiLFxuICAgIFwiSnVtcHlcIiwgXCJLaW5kXCIsIFwiTGF1Z2hpbmdcIiwgXCJMYXp5XCIsIFwiTGlxdWlkXCIsIFwiTG9uZWx5XCIsIFwiTG9uZ2luZ1wiLCBcIkxvdWRcIiwgXCJMb3ZpbmdcIiwgXCJMb3lhbFwiLCBcIk1hY2FicmVcIiwgXCJNYWRcIixcbiAgICBcIk1hZ2ljYWxcIiwgXCJNYWduaWZpY2VudFwiLCBcIk1hbGV2b2xlbnRcIiwgXCJNZWRpZXZhbFwiLCBcIk1lbW9yYWJsZVwiLCBcIk1lcmVcIiwgXCJNZXJyeVwiLCBcIk1pZ2h0eVwiLFxuICAgIFwiTWlzY2hpZXZvdXNcIiwgXCJNaXNlcmFibGVcIiwgXCJNb2RpZmllZFwiLCBcIk1vb2R5XCIsIFwiTW9zdFwiLCBcIk15c3RlcmlvdXNcIiwgXCJNeXN0aWNhbFwiLCBcIk5lZWR5XCIsXG4gICAgXCJOZXJ2b3VzXCIsIFwiTmljZVwiLCBcIk9iamVjdGl2ZVwiLCBcIk9ibm94aW91c1wiLCBcIk9ic2Vzc2l2ZVwiLCBcIk9idmlvdXNcIiwgXCJPcGluaW9uYXRlZFwiLCBcIk9yYW5nZVwiLFxuICAgIFwiUGFpbmZ1bFwiLCBcIlBhc3Npb25hdGVcIiwgXCJQZXJmZWN0XCIsIFwiUGlua1wiLCBcIlBsYXlmdWxcIiwgXCJQb2lzb25vdXNcIiwgXCJQb2xpdGVcIiwgXCJQb29yXCIsIFwiUG9wdWxhclwiLCBcIlBvd2VyZnVsXCIsXG4gICAgXCJQcmVjaXNlXCIsIFwiUHJlc2VydmVkXCIsIFwiUHJldHR5XCIsIFwiUHVycGxlXCIsIFwiUXVpY2tcIiwgXCJRdWlldFwiLCBcIlJhbmRvbVwiLCBcIlJhcGlkXCIsIFwiUmFyZVwiLCBcIlJlYWxcIixcbiAgICBcIlJlYXNzdXJpbmdcIiwgXCJSZWNrbGVzc1wiLCBcIlJlZFwiLCBcIlJlZ3VsYXJcIiwgXCJSZW1vcnNlZnVsXCIsIFwiUmVzcG9uc2libGVcIiwgXCJSaWNoXCIsIFwiUnVkZVwiLCBcIlJ1dGhsZXNzXCIsXG4gICAgXCJTYWRcIiwgXCJTY2FyZWRcIiwgXCJTY2FyeVwiLCBcIlNjb3JuZnVsXCIsIFwiU2NyZWFtaW5nXCIsIFwiU2VsZmlzaFwiLCBcIlNlcmlvdXNcIiwgXCJTaGFkeVwiLCBcIlNoYWt5XCIsIFwiU2hhcnBcIixcbiAgICBcIlNoaW55XCIsIFwiU2h5XCIsIFwiU2ltcGxlXCIsIFwiU2xlZXB5XCIsIFwiU2xvd1wiLCBcIlNseVwiLCBcIlNtYWxsXCIsIFwiU21hcnRcIiwgXCJTbWVsbHlcIiwgXCJTbWlsaW5nXCIsIFwiU21vb3RoXCIsXG4gICAgXCJTbXVnXCIsIFwiU29iZXJcIiwgXCJTb2Z0XCIsIFwiU29sZW1uXCIsIFwiU3F1YXJlXCIsIFwiU3F1YXJlXCIsIFwiU3RlYWR5XCIsIFwiU3RyYW5nZVwiLCBcIlN0cm9uZ1wiLFxuICAgIFwiU3R1bm5pbmdcIiwgXCJTdWJqZWN0aXZlXCIsIFwiU3VjY2Vzc2Z1bFwiLCBcIlN1cmx5XCIsIFwiU3dlZXRcIiwgXCJUYWN0ZnVsXCIsIFwiVGVuc2VcIixcbiAgICBcIlRob3VnaHRmdWxcIiwgXCJUaWdodFwiLCBcIlRpbnlcIiwgXCJUb2xlcmFudFwiLCBcIlVuZWFzeVwiLCBcIlVuaXF1ZVwiLCBcIlVuc2VlblwiLCBcIldhcm1cIiwgXCJXZWFrXCIsXG4gICAgXCJXZWlyZFwiLCBcIldlbGxDb29rZWRcIiwgXCJXaWxkXCIsIFwiV2lzZVwiLCBcIldpdHR5XCIsIFwiV29uZGVyZnVsXCIsIFwiV29ycmllZFwiLCBcIlllbGxvd1wiLCBcIllvdW5nXCIsXG4gICAgXCJaZWFsb3VzXCJcbiAgICBdO1xuLy92YXIgcHJvbm91bnMgPSBbXG4vL107XG4vL3ZhciBjb25qdW5jdGlvbnMgPSBbXG4vL1wiQW5kXCIsIFwiT3JcIiwgXCJGb3JcIiwgXCJBYm92ZVwiLCBcIkJlZm9yZVwiLCBcIkFnYWluc3RcIiwgXCJCZXR3ZWVuXCJcbi8vXTtcblxuLypcbiAqIE1hcHMgYSBzdHJpbmcgKGNhdGVnb3J5IG5hbWUpIHRvIHRoZSBhcnJheSBvZiB3b3JkcyBmcm9tIHRoYXQgY2F0ZWdvcnkuXG4gKi9cbnZhciBDQVRFR09SSUVTID1cbntcbiAgICAvL1wiX05PVU5fXCI6IG5vdW5zLFxuICAgIFwiX1BMVVJBTE5PVU5fXCI6IHBsdXJhbE5vdW5zLFxuICAgIC8vXCJfUExBQ0VfXCI6IHBsYWNlcyxcbiAgICBcIl9WRVJCX1wiOiB2ZXJicyxcbiAgICBcIl9BRFZFUkJfXCI6IGFkdmVyYnMsXG4gICAgXCJfQURKRUNUSVZFX1wiOiBhZGplY3RpdmVzXG4gICAgLy9cIl9QUk9OT1VOX1wiOiBwcm9ub3VucyxcbiAgICAvL1wiX0NPTkpVTkNUSU9OX1wiOiBjb25qdW5jdGlvbnMsXG59O1xuXG52YXIgUEFUVEVSTlMgPSBbXG4gICAgXCJfQURKRUNUSVZFX19QTFVSQUxOT1VOX19WRVJCX19BRFZFUkJfXCJcblxuICAgIC8vIEJlYXV0aWZ1bEZ1bmdpT3JTcGFnaGV0dGlcbiAgICAvL1wiX0FESkVDVElWRV9fUExVUkFMTk9VTl9fQ09OSlVOQ1RJT05fX1BMVVJBTE5PVU5fXCIsXG5cbiAgICAvLyBBbWF6aW5nbHlTY2FyeVRveVxuICAgIC8vXCJfQURWRVJCX19BREpFQ1RJVkVfX05PVU5fXCIsXG5cbiAgICAvLyBOZWl0aGVyVHJhc2hOb3JSaWZsZVxuICAgIC8vXCJOZWl0aGVyX05PVU5fTm9yX05PVU5fXCIsXG4gICAgLy9cIkVpdGhlcl9OT1VOX09yX05PVU5fXCIsXG5cbiAgICAvLyBFaXRoZXJDb3B1bGF0ZU9ySW52ZXN0aWdhdGVcbiAgICAvL1wiRWl0aGVyX1ZFUkJfT3JfVkVSQl9cIixcbiAgICAvL1wiTmVpdGhlcl9WRVJCX05vcl9WRVJCX1wiLFxuXG4gICAgLy9cIlRoZV9BREpFQ1RJVkVfX0FESkVDVElWRV9fTk9VTl9cIixcbiAgICAvL1wiVGhlX0FEVkVSQl9fQURKRUNUSVZFX19OT1VOX1wiLFxuICAgIC8vXCJUaGVfQURWRVJCX19BREpFQ1RJVkVfX05PVU5fc1wiLFxuICAgIC8vXCJUaGVfQURWRVJCX19BREpFQ1RJVkVfX1BMVVJBTE5PVU5fX1ZFUkJfXCIsXG5cbiAgICAvLyBXb2x2ZXNDb21wdXRlQmFkbHlcbiAgICAvL1wiX1BMVVJBTE5PVU5fX1ZFUkJfX0FEVkVSQl9cIixcblxuICAgIC8vIFVuaXRlRmFjaWxpdGF0ZUFuZE1lcmdlXG4gICAgLy9cIl9WRVJCX19WRVJCX0FuZF9WRVJCX1wiLFxuXG4gICAgLy9OYXN0eVdpdGNoZXNBdFRoZVB1YlxuICAgIC8vXCJfQURKRUNUSVZFX19QTFVSQUxOT1VOX0F0VGhlX1BMQUNFX1wiLFxuXTtcblxuXG4vKlxuICogUmV0dXJucyBhIHJhbmRvbSBlbGVtZW50IGZyb20gdGhlIGFycmF5ICdhcnInXG4gKi9cbmZ1bmN0aW9uIHJhbmRvbUVsZW1lbnQoYXJyKVxue1xuICAgIHJldHVybiBhcnJbTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogYXJyLmxlbmd0aCldO1xufVxuXG4vKlxuICogUmV0dXJucyB0cnVlIGlmIHRoZSBzdHJpbmcgJ3MnIGNvbnRhaW5zIG9uZSBvZiB0aGVcbiAqIHRlbXBsYXRlIHN0cmluZ3MuXG4gKi9cbmZ1bmN0aW9uIGhhc1RlbXBsYXRlKHMpXG57XG4gICAgZm9yICh2YXIgdGVtcGxhdGUgaW4gQ0FURUdPUklFUyl7XG4gICAgICAgIGlmIChzLmluZGV4T2YodGVtcGxhdGUpID49IDApe1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIG5ldyByb29tIG5hbWUuXG4gKi9cbnZhciBSb29tTmFtZUdlbmVyYXRvciA9IHtcbiAgICBnZW5lcmF0ZVJvb21XaXRob3V0U2VwYXJhdG9yOiBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICAvLyBOb3RlIHRoYXQgaWYgbW9yZSB0aGFuIG9uZSBwYXR0ZXJuIGlzIGF2YWlsYWJsZSwgdGhlIGNob2ljZSBvZiAnbmFtZScgd29uJ3QgYmUgcmFuZG9tIChuYW1lcyBmcm9tIHBhdHRlcm5zXG4gICAgICAgIC8vIHdpdGggZmV3ZXIgb3B0aW9ucyB3aWxsIGhhdmUgaGlnaGVyIHByb2JhYmlsaXR5IG9mIGJlaW5nIGNob3NlbiB0aGF0IG5hbWVzIGZyb20gcGF0dGVybnMgd2l0aCBtb3JlIG9wdGlvbnMpLlxuICAgICAgICB2YXIgbmFtZSA9IHJhbmRvbUVsZW1lbnQoUEFUVEVSTlMpO1xuICAgICAgICB2YXIgd29yZDtcbiAgICAgICAgd2hpbGUgKGhhc1RlbXBsYXRlKG5hbWUpKXtcbiAgICAgICAgICAgIGZvciAodmFyIHRlbXBsYXRlIGluIENBVEVHT1JJRVMpe1xuICAgICAgICAgICAgICAgIHdvcmQgPSByYW5kb21FbGVtZW50KENBVEVHT1JJRVNbdGVtcGxhdGVdKTtcbiAgICAgICAgICAgICAgICBuYW1lID0gbmFtZS5yZXBsYWNlKHRlbXBsYXRlLCB3b3JkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBuYW1lO1xuICAgIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSb29tTmFtZUdlbmVyYXRvcjtcbiIsInZhciBhbmltYXRlVGltZW91dCwgdXBkYXRlVGltZW91dDtcblxudmFyIFJvb21OYW1lR2VuZXJhdG9yID0gcmVxdWlyZShcIi4vUm9vbW5hbWVHZW5lcmF0b3JcIik7XG5cbmZ1bmN0aW9uIGVudGVyX3Jvb20oKVxue1xuICAgIHZhciB2YWwgPSAkKFwiI2VudGVyX3Jvb21fZmllbGRcIikudmFsKCk7XG4gICAgaWYoIXZhbCkge1xuICAgICAgICB2YWwgPSAkKFwiI2VudGVyX3Jvb21fZmllbGRcIikuYXR0cihcInJvb21fbmFtZVwiKTtcbiAgICB9XG4gICAgaWYgKHZhbCkge1xuICAgICAgICB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUgPSBcIi9cIiArIHZhbDtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGFuaW1hdGUod29yZCkge1xuICAgIHZhciBjdXJyZW50VmFsID0gJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLmF0dHIoXCJwbGFjZWhvbGRlclwiKTtcbiAgICAkKFwiI2VudGVyX3Jvb21fZmllbGRcIikuYXR0cihcInBsYWNlaG9sZGVyXCIsIGN1cnJlbnRWYWwgKyB3b3JkLnN1YnN0cigwLCAxKSk7XG4gICAgYW5pbWF0ZVRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICBhbmltYXRlKHdvcmQuc3Vic3RyaW5nKDEsIHdvcmQubGVuZ3RoKSlcbiAgICB9LCA3MCk7XG59XG5cbmZ1bmN0aW9uIHVwZGF0ZV9yb29tbmFtZSgpXG57XG4gICAgdmFyIHdvcmQgPSBSb29tTmFtZUdlbmVyYXRvci5nZW5lcmF0ZVJvb21XaXRob3V0U2VwYXJhdG9yKCk7XG4gICAgJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLmF0dHIoXCJyb29tX25hbWVcIiwgd29yZCk7XG4gICAgJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLmF0dHIoXCJwbGFjZWhvbGRlclwiLCBcIlwiKTtcbiAgICBjbGVhclRpbWVvdXQoYW5pbWF0ZVRpbWVvdXQpO1xuICAgIGFuaW1hdGUod29yZCk7XG4gICAgdXBkYXRlVGltZW91dCA9IHNldFRpbWVvdXQodXBkYXRlX3Jvb21uYW1lLCAxMDAwMCk7XG59XG5cblxuZnVuY3Rpb24gc2V0dXBXZWxjb21lUGFnZSgpXG57XG4gICAgJChcIiN2aWRlb2NvbmZlcmVuY2VfcGFnZVwiKS5oaWRlKCk7XG4gICAgJChcIiNkb21haW5fbmFtZVwiKS50ZXh0KFxuICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLnByb3RvY29sICsgXCIvL1wiICsgd2luZG93LmxvY2F0aW9uLmhvc3QgKyBcIi9cIik7XG4gICAgJChcInNwYW5bbmFtZT0nYXBwTmFtZSddXCIpLnRleHQoaW50ZXJmYWNlQ29uZmlnLkFQUF9OQU1FKTtcblxuICAgIGlmIChpbnRlcmZhY2VDb25maWcuU0hPV19KSVRTSV9XQVRFUk1BUkspIHtcbiAgICAgICAgdmFyIGxlZnRXYXRlcm1hcmtEaXZcbiAgICAgICAgICAgID0gJChcIiN3ZWxjb21lX3BhZ2VfaGVhZGVyIGRpdltjbGFzcz0nd2F0ZXJtYXJrIGxlZnR3YXRlcm1hcmsnXVwiKTtcbiAgICAgICAgaWYobGVmdFdhdGVybWFya0RpdiAmJiBsZWZ0V2F0ZXJtYXJrRGl2Lmxlbmd0aCA+IDApXG4gICAgICAgIHtcbiAgICAgICAgICAgIGxlZnRXYXRlcm1hcmtEaXYuY3NzKHtkaXNwbGF5OiAnYmxvY2snfSk7XG4gICAgICAgICAgICBsZWZ0V2F0ZXJtYXJrRGl2LnBhcmVudCgpLmdldCgwKS5ocmVmXG4gICAgICAgICAgICAgICAgPSBpbnRlcmZhY2VDb25maWcuSklUU0lfV0FURVJNQVJLX0xJTks7XG4gICAgICAgIH1cblxuICAgIH1cblxuICAgIGlmIChpbnRlcmZhY2VDb25maWcuU0hPV19CUkFORF9XQVRFUk1BUkspIHtcbiAgICAgICAgdmFyIHJpZ2h0V2F0ZXJtYXJrRGl2XG4gICAgICAgICAgICA9ICQoXCIjd2VsY29tZV9wYWdlX2hlYWRlciBkaXZbY2xhc3M9J3dhdGVybWFyayByaWdodHdhdGVybWFyayddXCIpO1xuICAgICAgICBpZihyaWdodFdhdGVybWFya0RpdiAmJiByaWdodFdhdGVybWFya0Rpdi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICByaWdodFdhdGVybWFya0Rpdi5jc3Moe2Rpc3BsYXk6ICdibG9jayd9KTtcbiAgICAgICAgICAgIHJpZ2h0V2F0ZXJtYXJrRGl2LnBhcmVudCgpLmdldCgwKS5ocmVmXG4gICAgICAgICAgICAgICAgPSBpbnRlcmZhY2VDb25maWcuQlJBTkRfV0FURVJNQVJLX0xJTks7XG4gICAgICAgICAgICByaWdodFdhdGVybWFya0Rpdi5nZXQoMCkuc3R5bGUuYmFja2dyb3VuZEltYWdlXG4gICAgICAgICAgICAgICAgPSBcInVybChpbWFnZXMvcmlnaHR3YXRlcm1hcmsucG5nKVwiO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGludGVyZmFjZUNvbmZpZy5TSE9XX1BPV0VSRURfQlkpIHtcbiAgICAgICAgJChcIiN3ZWxjb21lX3BhZ2VfaGVhZGVyPmFbY2xhc3M9J3Bvd2VyZWRieSddXCIpXG4gICAgICAgICAgICAuY3NzKHtkaXNwbGF5OiAnYmxvY2snfSk7XG4gICAgfVxuXG4gICAgJChcIiNlbnRlcl9yb29tX2J1dHRvblwiKS5jbGljayhmdW5jdGlvbigpXG4gICAge1xuICAgICAgICBlbnRlcl9yb29tKCk7XG4gICAgfSk7XG5cbiAgICAkKFwiI2VudGVyX3Jvb21fZmllbGRcIikua2V5ZG93bihmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgaWYgKGV2ZW50LmtleUNvZGUgPT09IDEzIC8qIGVudGVyICovKSB7XG4gICAgICAgICAgICBlbnRlcl9yb29tKCk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIGlmICghKGludGVyZmFjZUNvbmZpZy5HRU5FUkFURV9ST09NTkFNRVNfT05fV0VMQ09NRV9QQUdFID09PSBmYWxzZSkpe1xuICAgICAgICB2YXIgdXBkYXRlVGltZW91dDtcbiAgICAgICAgdmFyIGFuaW1hdGVUaW1lb3V0O1xuICAgICAgICAkKFwiI3JlbG9hZF9yb29tbmFtZVwiKS5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodXBkYXRlVGltZW91dCk7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQoYW5pbWF0ZVRpbWVvdXQpO1xuICAgICAgICAgICAgdXBkYXRlX3Jvb21uYW1lKCk7XG4gICAgICAgIH0pO1xuICAgICAgICAkKFwiI3JlbG9hZF9yb29tbmFtZVwiKS5zaG93KCk7XG5cblxuICAgICAgICB1cGRhdGVfcm9vbW5hbWUoKTtcbiAgICB9XG5cbiAgICAkKFwiI2Rpc2FibGVfd2VsY29tZVwiKS5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uud2VsY29tZVBhZ2VEaXNhYmxlZFxuICAgICAgICAgICAgPSAkKFwiI2Rpc2FibGVfd2VsY29tZVwiKS5pcyhcIjpjaGVja2VkXCIpO1xuICAgIH0pO1xuXG59XG5cbm1vZHVsZS5leHBvcnRzID0gc2V0dXBXZWxjb21lUGFnZTsiXX0=