1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723 |
- 'use strict';
- var obsidian = require('obsidian');
- var state = require('@codemirror/state');
- var view = require('@codemirror/view');
- var language = require('@codemirror/language');
- class LuxonError extends Error {}
- class InvalidDateTimeError extends LuxonError {
- constructor(reason) {
- super(`Invalid DateTime: ${reason.toMessage()}`);
- }
- }
- class InvalidIntervalError extends LuxonError {
- constructor(reason) {
- super(`Invalid Interval: ${reason.toMessage()}`);
- }
- }
- class InvalidDurationError extends LuxonError {
- constructor(reason) {
- super(`Invalid Duration: ${reason.toMessage()}`);
- }
- }
- class ConflictingSpecificationError extends LuxonError {}
- class InvalidUnitError extends LuxonError {
- constructor(unit) {
- super(`Invalid unit ${unit}`);
- }
- }
- class InvalidArgumentError extends LuxonError {}
- class ZoneIsAbstractError extends LuxonError {
- constructor() {
- super("Zone is an abstract class");
- }
- }
- const n$1 = "numeric",
- s$2 = "short",
- l$2 = "long";
- const DATE_SHORT = {
- year: n$1,
- month: n$1,
- day: n$1,
- };
- const DATE_MED = {
- year: n$1,
- month: s$2,
- day: n$1,
- };
- const DATE_MED_WITH_WEEKDAY = {
- year: n$1,
- month: s$2,
- day: n$1,
- weekday: s$2,
- };
- const DATE_FULL = {
- year: n$1,
- month: l$2,
- day: n$1,
- };
- const DATE_HUGE = {
- year: n$1,
- month: l$2,
- day: n$1,
- weekday: l$2,
- };
- const TIME_SIMPLE = {
- hour: n$1,
- minute: n$1,
- };
- const TIME_WITH_SECONDS = {
- hour: n$1,
- minute: n$1,
- second: n$1,
- };
- const TIME_WITH_SHORT_OFFSET = {
- hour: n$1,
- minute: n$1,
- second: n$1,
- timeZoneName: s$2,
- };
- const TIME_WITH_LONG_OFFSET = {
- hour: n$1,
- minute: n$1,
- second: n$1,
- timeZoneName: l$2,
- };
- const TIME_24_SIMPLE = {
- hour: n$1,
- minute: n$1,
- hourCycle: "h23",
- };
- const TIME_24_WITH_SECONDS = {
- hour: n$1,
- minute: n$1,
- second: n$1,
- hourCycle: "h23",
- };
- const TIME_24_WITH_SHORT_OFFSET = {
- hour: n$1,
- minute: n$1,
- second: n$1,
- hourCycle: "h23",
- timeZoneName: s$2,
- };
- const TIME_24_WITH_LONG_OFFSET = {
- hour: n$1,
- minute: n$1,
- second: n$1,
- hourCycle: "h23",
- timeZoneName: l$2,
- };
- const DATETIME_SHORT = {
- year: n$1,
- month: n$1,
- day: n$1,
- hour: n$1,
- minute: n$1,
- };
- const DATETIME_SHORT_WITH_SECONDS = {
- year: n$1,
- month: n$1,
- day: n$1,
- hour: n$1,
- minute: n$1,
- second: n$1,
- };
- const DATETIME_MED = {
- year: n$1,
- month: s$2,
- day: n$1,
- hour: n$1,
- minute: n$1,
- };
- const DATETIME_MED_WITH_SECONDS = {
- year: n$1,
- month: s$2,
- day: n$1,
- hour: n$1,
- minute: n$1,
- second: n$1,
- };
- const DATETIME_MED_WITH_WEEKDAY = {
- year: n$1,
- month: s$2,
- day: n$1,
- weekday: s$2,
- hour: n$1,
- minute: n$1,
- };
- const DATETIME_FULL = {
- year: n$1,
- month: l$2,
- day: n$1,
- hour: n$1,
- minute: n$1,
- timeZoneName: s$2,
- };
- const DATETIME_FULL_WITH_SECONDS = {
- year: n$1,
- month: l$2,
- day: n$1,
- hour: n$1,
- minute: n$1,
- second: n$1,
- timeZoneName: s$2,
- };
- const DATETIME_HUGE = {
- year: n$1,
- month: l$2,
- day: n$1,
- weekday: l$2,
- hour: n$1,
- minute: n$1,
- timeZoneName: l$2,
- };
- const DATETIME_HUGE_WITH_SECONDS = {
- year: n$1,
- month: l$2,
- day: n$1,
- weekday: l$2,
- hour: n$1,
- minute: n$1,
- second: n$1,
- timeZoneName: l$2,
- };
- class Zone {
-
- get type() {
- throw new ZoneIsAbstractError();
- }
-
- get name() {
- throw new ZoneIsAbstractError();
- }
- get ianaName() {
- return this.name;
- }
-
- get isUniversal() {
- throw new ZoneIsAbstractError();
- }
-
- offsetName(ts, opts) {
- throw new ZoneIsAbstractError();
- }
-
- formatOffset(ts, format) {
- throw new ZoneIsAbstractError();
- }
-
- offset(ts) {
- throw new ZoneIsAbstractError();
- }
-
- equals(otherZone) {
- throw new ZoneIsAbstractError();
- }
-
- get isValid() {
- throw new ZoneIsAbstractError();
- }
- }
- let singleton$1 = null;
- class SystemZone extends Zone {
-
- static get instance() {
- if (singleton$1 === null) {
- singleton$1 = new SystemZone();
- }
- return singleton$1;
- }
-
- get type() {
- return "system";
- }
-
- get name() {
- return new Intl.DateTimeFormat().resolvedOptions().timeZone;
- }
-
- get isUniversal() {
- return false;
- }
-
- offsetName(ts, { format, locale }) {
- return parseZoneInfo(ts, format, locale);
- }
-
- formatOffset(ts, format) {
- return formatOffset(this.offset(ts), format);
- }
-
- offset(ts) {
- return -new Date(ts).getTimezoneOffset();
- }
-
- equals(otherZone) {
- return otherZone.type === "system";
- }
-
- get isValid() {
- return true;
- }
- }
- let dtfCache = {};
- function makeDTF(zone) {
- if (!dtfCache[zone]) {
- dtfCache[zone] = new Intl.DateTimeFormat("en-US", {
- hour12: false,
- timeZone: zone,
- year: "numeric",
- month: "2-digit",
- day: "2-digit",
- hour: "2-digit",
- minute: "2-digit",
- second: "2-digit",
- era: "short",
- });
- }
- return dtfCache[zone];
- }
- const typeToPos = {
- year: 0,
- month: 1,
- day: 2,
- era: 3,
- hour: 4,
- minute: 5,
- second: 6,
- };
- function hackyOffset(dtf, date) {
- const formatted = dtf.format(date).replace(/\u200E/g, ""),
- parsed = /(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted),
- [, fMonth, fDay, fYear, fadOrBc, fHour, fMinute, fSecond] = parsed;
- return [fYear, fMonth, fDay, fadOrBc, fHour, fMinute, fSecond];
- }
- function partsOffset(dtf, date) {
- const formatted = dtf.formatToParts(date);
- const filled = [];
- for (let i = 0; i < formatted.length; i++) {
- const { type, value } = formatted[i];
- const pos = typeToPos[type];
- if (type === "era") {
- filled[pos] = value;
- } else if (!isUndefined(pos)) {
- filled[pos] = parseInt(value, 10);
- }
- }
- return filled;
- }
- let ianaZoneCache = {};
- class IANAZone extends Zone {
-
- static create(name) {
- if (!ianaZoneCache[name]) {
- ianaZoneCache[name] = new IANAZone(name);
- }
- return ianaZoneCache[name];
- }
-
- static resetCache() {
- ianaZoneCache = {};
- dtfCache = {};
- }
-
- static isValidSpecifier(s) {
- return this.isValidZone(s);
- }
-
- static isValidZone(zone) {
- if (!zone) {
- return false;
- }
- try {
- new Intl.DateTimeFormat("en-US", { timeZone: zone }).format();
- return true;
- } catch (e) {
- return false;
- }
- }
- constructor(name) {
- super();
-
- this.zoneName = name;
-
- this.valid = IANAZone.isValidZone(name);
- }
-
- get type() {
- return "iana";
- }
-
- get name() {
- return this.zoneName;
- }
-
- get isUniversal() {
- return false;
- }
-
- offsetName(ts, { format, locale }) {
- return parseZoneInfo(ts, format, locale, this.name);
- }
-
- formatOffset(ts, format) {
- return formatOffset(this.offset(ts), format);
- }
-
- offset(ts) {
- const date = new Date(ts);
- if (isNaN(date)) return NaN;
- const dtf = makeDTF(this.name);
- let [year, month, day, adOrBc, hour, minute, second] = dtf.formatToParts
- ? partsOffset(dtf, date)
- : hackyOffset(dtf, date);
- if (adOrBc === "BC") {
- year = -Math.abs(year) + 1;
- }
-
- const adjustedHour = hour === 24 ? 0 : hour;
- const asUTC = objToLocalTS({
- year,
- month,
- day,
- hour: adjustedHour,
- minute,
- second,
- millisecond: 0,
- });
- let asTS = +date;
- const over = asTS % 1000;
- asTS -= over >= 0 ? over : 1000 + over;
- return (asUTC - asTS) / (60 * 1000);
- }
-
- equals(otherZone) {
- return otherZone.type === "iana" && otherZone.name === this.name;
- }
-
- get isValid() {
- return this.valid;
- }
- }
- let intlLFCache = {};
- function getCachedLF(locString, opts = {}) {
- const key = JSON.stringify([locString, opts]);
- let dtf = intlLFCache[key];
- if (!dtf) {
- dtf = new Intl.ListFormat(locString, opts);
- intlLFCache[key] = dtf;
- }
- return dtf;
- }
- let intlDTCache = {};
- function getCachedDTF(locString, opts = {}) {
- const key = JSON.stringify([locString, opts]);
- let dtf = intlDTCache[key];
- if (!dtf) {
- dtf = new Intl.DateTimeFormat(locString, opts);
- intlDTCache[key] = dtf;
- }
- return dtf;
- }
- let intlNumCache = {};
- function getCachedINF(locString, opts = {}) {
- const key = JSON.stringify([locString, opts]);
- let inf = intlNumCache[key];
- if (!inf) {
- inf = new Intl.NumberFormat(locString, opts);
- intlNumCache[key] = inf;
- }
- return inf;
- }
- let intlRelCache = {};
- function getCachedRTF(locString, opts = {}) {
- const { base, ...cacheKeyOpts } = opts;
- const key = JSON.stringify([locString, cacheKeyOpts]);
- let inf = intlRelCache[key];
- if (!inf) {
- inf = new Intl.RelativeTimeFormat(locString, opts);
- intlRelCache[key] = inf;
- }
- return inf;
- }
- let sysLocaleCache = null;
- function systemLocale() {
- if (sysLocaleCache) {
- return sysLocaleCache;
- } else {
- sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
- return sysLocaleCache;
- }
- }
- function parseLocaleString(localeStr) {
-
-
-
-
-
-
-
-
-
- const xIndex = localeStr.indexOf("-x-");
- if (xIndex !== -1) {
- localeStr = localeStr.substring(0, xIndex);
- }
- const uIndex = localeStr.indexOf("-u-");
- if (uIndex === -1) {
- return [localeStr];
- } else {
- let options;
- let selectedStr;
- try {
- options = getCachedDTF(localeStr).resolvedOptions();
- selectedStr = localeStr;
- } catch (e) {
- const smaller = localeStr.substring(0, uIndex);
- options = getCachedDTF(smaller).resolvedOptions();
- selectedStr = smaller;
- }
- const { numberingSystem, calendar } = options;
- return [selectedStr, numberingSystem, calendar];
- }
- }
- function intlConfigString(localeStr, numberingSystem, outputCalendar) {
- if (outputCalendar || numberingSystem) {
- if (!localeStr.includes("-u-")) {
- localeStr += "-u";
- }
- if (outputCalendar) {
- localeStr += `-ca-${outputCalendar}`;
- }
- if (numberingSystem) {
- localeStr += `-nu-${numberingSystem}`;
- }
- return localeStr;
- } else {
- return localeStr;
- }
- }
- function mapMonths(f) {
- const ms = [];
- for (let i = 1; i <= 12; i++) {
- const dt = DateTime.utc(2009, i, 1);
- ms.push(f(dt));
- }
- return ms;
- }
- function mapWeekdays(f) {
- const ms = [];
- for (let i = 1; i <= 7; i++) {
- const dt = DateTime.utc(2016, 11, 13 + i);
- ms.push(f(dt));
- }
- return ms;
- }
- function listStuff(loc, length, englishFn, intlFn) {
- const mode = loc.listingMode();
- if (mode === "error") {
- return null;
- } else if (mode === "en") {
- return englishFn(length);
- } else {
- return intlFn(length);
- }
- }
- function supportsFastNumbers(loc) {
- if (loc.numberingSystem && loc.numberingSystem !== "latn") {
- return false;
- } else {
- return (
- loc.numberingSystem === "latn" ||
- !loc.locale ||
- loc.locale.startsWith("en") ||
- new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn"
- );
- }
- }
- class PolyNumberFormatter {
- constructor(intl, forceSimple, opts) {
- this.padTo = opts.padTo || 0;
- this.floor = opts.floor || false;
- const { padTo, floor, ...otherOpts } = opts;
- if (!forceSimple || Object.keys(otherOpts).length > 0) {
- const intlOpts = { useGrouping: false, ...opts };
- if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
- this.inf = getCachedINF(intl, intlOpts);
- }
- }
- format(i) {
- if (this.inf) {
- const fixed = this.floor ? Math.floor(i) : i;
- return this.inf.format(fixed);
- } else {
-
- const fixed = this.floor ? Math.floor(i) : roundTo(i, 3);
- return padStart(fixed, this.padTo);
- }
- }
- }
- class PolyDateFormatter {
- constructor(dt, intl, opts) {
- this.opts = opts;
- this.originalZone = undefined;
- let z = undefined;
- if (this.opts.timeZone) {
-
- this.dt = dt;
- } else if (dt.zone.type === "fixed") {
-
-
-
-
-
-
- const gmtOffset = -1 * (dt.offset / 60);
- const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
- if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
- z = offsetZ;
- this.dt = dt;
- } else {
-
-
- z = "UTC";
- this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
- this.originalZone = dt.zone;
- }
- } else if (dt.zone.type === "system") {
- this.dt = dt;
- } else if (dt.zone.type === "iana") {
- this.dt = dt;
- z = dt.zone.name;
- } else {
-
-
- z = "UTC";
- this.dt = dt.setZone("UTC").plus({ minutes: dt.offset });
- this.originalZone = dt.zone;
- }
- const intlOpts = { ...this.opts };
- intlOpts.timeZone = intlOpts.timeZone || z;
- this.dtf = getCachedDTF(intl, intlOpts);
- }
- format() {
- if (this.originalZone) {
-
-
- return this.formatToParts()
- .map(({ value }) => value)
- .join("");
- }
- return this.dtf.format(this.dt.toJSDate());
- }
- formatToParts() {
- const parts = this.dtf.formatToParts(this.dt.toJSDate());
- if (this.originalZone) {
- return parts.map((part) => {
- if (part.type === "timeZoneName") {
- const offsetName = this.originalZone.offsetName(this.dt.ts, {
- locale: this.dt.locale,
- format: this.opts.timeZoneName,
- });
- return {
- ...part,
- value: offsetName,
- };
- } else {
- return part;
- }
- });
- }
- return parts;
- }
- resolvedOptions() {
- return this.dtf.resolvedOptions();
- }
- }
- class PolyRelFormatter {
- constructor(intl, isEnglish, opts) {
- this.opts = { style: "long", ...opts };
- if (!isEnglish && hasRelative()) {
- this.rtf = getCachedRTF(intl, opts);
- }
- }
- format(count, unit) {
- if (this.rtf) {
- return this.rtf.format(count, unit);
- } else {
- return formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
- }
- }
- formatToParts(count, unit) {
- if (this.rtf) {
- return this.rtf.formatToParts(count, unit);
- } else {
- return [];
- }
- }
- }
- class Locale {
- static fromOpts(opts) {
- return Locale.create(opts.locale, opts.numberingSystem, opts.outputCalendar, opts.defaultToEN);
- }
- static create(locale, numberingSystem, outputCalendar, defaultToEN = false) {
- const specifiedLocale = locale || Settings.defaultLocale;
-
- const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
- const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
- const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
- return new Locale(localeR, numberingSystemR, outputCalendarR, specifiedLocale);
- }
- static resetCache() {
- sysLocaleCache = null;
- intlDTCache = {};
- intlNumCache = {};
- intlRelCache = {};
- }
- static fromObject({ locale, numberingSystem, outputCalendar } = {}) {
- return Locale.create(locale, numberingSystem, outputCalendar);
- }
- constructor(locale, numbering, outputCalendar, specifiedLocale) {
- const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
- this.locale = parsedLocale;
- this.numberingSystem = numbering || parsedNumberingSystem || null;
- this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
- this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
- this.weekdaysCache = { format: {}, standalone: {} };
- this.monthsCache = { format: {}, standalone: {} };
- this.meridiemCache = null;
- this.eraCache = {};
- this.specifiedLocale = specifiedLocale;
- this.fastNumbersCached = null;
- }
- get fastNumbers() {
- if (this.fastNumbersCached == null) {
- this.fastNumbersCached = supportsFastNumbers(this);
- }
- return this.fastNumbersCached;
- }
- listingMode() {
- const isActuallyEn = this.isEnglish();
- const hasNoWeirdness =
- (this.numberingSystem === null || this.numberingSystem === "latn") &&
- (this.outputCalendar === null || this.outputCalendar === "gregory");
- return isActuallyEn && hasNoWeirdness ? "en" : "intl";
- }
- clone(alts) {
- if (!alts || Object.getOwnPropertyNames(alts).length === 0) {
- return this;
- } else {
- return Locale.create(
- alts.locale || this.specifiedLocale,
- alts.numberingSystem || this.numberingSystem,
- alts.outputCalendar || this.outputCalendar,
- alts.defaultToEN || false
- );
- }
- }
- redefaultToEN(alts = {}) {
- return this.clone({ ...alts, defaultToEN: true });
- }
- redefaultToSystem(alts = {}) {
- return this.clone({ ...alts, defaultToEN: false });
- }
- months(length, format = false) {
- return listStuff(this, length, months, () => {
- const intl = format ? { month: length, day: "numeric" } : { month: length },
- formatStr = format ? "format" : "standalone";
- if (!this.monthsCache[formatStr][length]) {
- this.monthsCache[formatStr][length] = mapMonths((dt) => this.extract(dt, intl, "month"));
- }
- return this.monthsCache[formatStr][length];
- });
- }
- weekdays(length, format = false) {
- return listStuff(this, length, weekdays, () => {
- const intl = format
- ? { weekday: length, year: "numeric", month: "long", day: "numeric" }
- : { weekday: length },
- formatStr = format ? "format" : "standalone";
- if (!this.weekdaysCache[formatStr][length]) {
- this.weekdaysCache[formatStr][length] = mapWeekdays((dt) =>
- this.extract(dt, intl, "weekday")
- );
- }
- return this.weekdaysCache[formatStr][length];
- });
- }
- meridiems() {
- return listStuff(
- this,
- undefined,
- () => meridiems,
- () => {
-
-
- if (!this.meridiemCache) {
- const intl = { hour: "numeric", hourCycle: "h12" };
- this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(
- (dt) => this.extract(dt, intl, "dayperiod")
- );
- }
- return this.meridiemCache;
- }
- );
- }
- eras(length) {
- return listStuff(this, length, eras, () => {
- const intl = { era: length };
-
-
- if (!this.eraCache[length]) {
- this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map((dt) =>
- this.extract(dt, intl, "era")
- );
- }
- return this.eraCache[length];
- });
- }
- extract(dt, intlOpts, field) {
- const df = this.dtFormatter(dt, intlOpts),
- results = df.formatToParts(),
- matching = results.find((m) => m.type.toLowerCase() === field);
- return matching ? matching.value : null;
- }
- numberFormatter(opts = {}) {
-
-
- return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
- }
- dtFormatter(dt, intlOpts = {}) {
- return new PolyDateFormatter(dt, this.intl, intlOpts);
- }
- relFormatter(opts = {}) {
- return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
- }
- listFormatter(opts = {}) {
- return getCachedLF(this.intl, opts);
- }
- isEnglish() {
- return (
- this.locale === "en" ||
- this.locale.toLowerCase() === "en-us" ||
- new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us")
- );
- }
- equals(other) {
- return (
- this.locale === other.locale &&
- this.numberingSystem === other.numberingSystem &&
- this.outputCalendar === other.outputCalendar
- );
- }
- }
- let singleton = null;
- class FixedOffsetZone extends Zone {
-
- static get utcInstance() {
- if (singleton === null) {
- singleton = new FixedOffsetZone(0);
- }
- return singleton;
- }
-
- static instance(offset) {
- return offset === 0 ? FixedOffsetZone.utcInstance : new FixedOffsetZone(offset);
- }
-
- static parseSpecifier(s) {
- if (s) {
- const r = s.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i);
- if (r) {
- return new FixedOffsetZone(signedOffset(r[1], r[2]));
- }
- }
- return null;
- }
- constructor(offset) {
- super();
-
- this.fixed = offset;
- }
-
- get type() {
- return "fixed";
- }
-
- get name() {
- return this.fixed === 0 ? "UTC" : `UTC${formatOffset(this.fixed, "narrow")}`;
- }
- get ianaName() {
- if (this.fixed === 0) {
- return "Etc/UTC";
- } else {
- return `Etc/GMT${formatOffset(-this.fixed, "narrow")}`;
- }
- }
-
- offsetName() {
- return this.name;
- }
-
- formatOffset(ts, format) {
- return formatOffset(this.fixed, format);
- }
-
- get isUniversal() {
- return true;
- }
-
- offset() {
- return this.fixed;
- }
-
- equals(otherZone) {
- return otherZone.type === "fixed" && otherZone.fixed === this.fixed;
- }
-
- get isValid() {
- return true;
- }
- }
- class InvalidZone extends Zone {
- constructor(zoneName) {
- super();
-
- this.zoneName = zoneName;
- }
-
- get type() {
- return "invalid";
- }
-
- get name() {
- return this.zoneName;
- }
-
- get isUniversal() {
- return false;
- }
-
- offsetName() {
- return null;
- }
-
- formatOffset() {
- return "";
- }
-
- offset() {
- return NaN;
- }
-
- equals() {
- return false;
- }
-
- get isValid() {
- return false;
- }
- }
- function normalizeZone(input, defaultZone) {
- if (isUndefined(input) || input === null) {
- return defaultZone;
- } else if (input instanceof Zone) {
- return input;
- } else if (isString(input)) {
- const lowered = input.toLowerCase();
- if (lowered === "default") return defaultZone;
- else if (lowered === "local" || lowered === "system") return SystemZone.instance;
- else if (lowered === "utc" || lowered === "gmt") return FixedOffsetZone.utcInstance;
- else return FixedOffsetZone.parseSpecifier(lowered) || IANAZone.create(input);
- } else if (isNumber(input)) {
- return FixedOffsetZone.instance(input);
- } else if (typeof input === "object" && "offset" in input && typeof input.offset === "function") {
-
-
- return input;
- } else {
- return new InvalidZone(input);
- }
- }
- let now = () => Date.now(),
- defaultZone = "system",
- defaultLocale = null,
- defaultNumberingSystem = null,
- defaultOutputCalendar = null,
- twoDigitCutoffYear = 60,
- throwOnInvalid;
- class Settings {
-
- static get now() {
- return now;
- }
-
- static set now(n) {
- now = n;
- }
-
- static set defaultZone(zone) {
- defaultZone = zone;
- }
-
- static get defaultZone() {
- return normalizeZone(defaultZone, SystemZone.instance);
- }
-
- static get defaultLocale() {
- return defaultLocale;
- }
-
- static set defaultLocale(locale) {
- defaultLocale = locale;
- }
-
- static get defaultNumberingSystem() {
- return defaultNumberingSystem;
- }
-
- static set defaultNumberingSystem(numberingSystem) {
- defaultNumberingSystem = numberingSystem;
- }
-
- static get defaultOutputCalendar() {
- return defaultOutputCalendar;
- }
-
- static set defaultOutputCalendar(outputCalendar) {
- defaultOutputCalendar = outputCalendar;
- }
-
- static get twoDigitCutoffYear() {
- return twoDigitCutoffYear;
- }
-
- static set twoDigitCutoffYear(cutoffYear) {
- twoDigitCutoffYear = cutoffYear % 100;
- }
-
- static get throwOnInvalid() {
- return throwOnInvalid;
- }
-
- static set throwOnInvalid(t) {
- throwOnInvalid = t;
- }
-
- static resetCaches() {
- Locale.resetCache();
- IANAZone.resetCache();
- }
- }
- function isUndefined(o) {
- return typeof o === "undefined";
- }
- function isNumber(o) {
- return typeof o === "number";
- }
- function isInteger(o) {
- return typeof o === "number" && o % 1 === 0;
- }
- function isString(o) {
- return typeof o === "string";
- }
- function isDate(o) {
- return Object.prototype.toString.call(o) === "[object Date]";
- }
- function hasRelative() {
- try {
- return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
- } catch (e) {
- return false;
- }
- }
- function maybeArray(thing) {
- return Array.isArray(thing) ? thing : [thing];
- }
- function bestBy(arr, by, compare) {
- if (arr.length === 0) {
- return undefined;
- }
- return arr.reduce((best, next) => {
- const pair = [by(next), next];
- if (!best) {
- return pair;
- } else if (compare(best[0], pair[0]) === best[0]) {
- return best;
- } else {
- return pair;
- }
- }, null)[1];
- }
- function pick(obj, keys) {
- return keys.reduce((a, k) => {
- a[k] = obj[k];
- return a;
- }, {});
- }
- function hasOwnProperty(obj, prop) {
- return Object.prototype.hasOwnProperty.call(obj, prop);
- }
- function integerBetween(thing, bottom, top) {
- return isInteger(thing) && thing >= bottom && thing <= top;
- }
- function floorMod(x, n) {
- return x - n * Math.floor(x / n);
- }
- function padStart(input, n = 2) {
- const isNeg = input < 0;
- let padded;
- if (isNeg) {
- padded = "-" + ("" + -input).padStart(n, "0");
- } else {
- padded = ("" + input).padStart(n, "0");
- }
- return padded;
- }
- function parseInteger(string) {
- if (isUndefined(string) || string === null || string === "") {
- return undefined;
- } else {
- return parseInt(string, 10);
- }
- }
- function parseFloating(string) {
- if (isUndefined(string) || string === null || string === "") {
- return undefined;
- } else {
- return parseFloat(string);
- }
- }
- function parseMillis(fraction) {
-
- if (isUndefined(fraction) || fraction === null || fraction === "") {
- return undefined;
- } else {
- const f = parseFloat("0." + fraction) * 1000;
- return Math.floor(f);
- }
- }
- function roundTo(number, digits, towardZero = false) {
- const factor = 10 ** digits,
- rounder = towardZero ? Math.trunc : Math.round;
- return rounder(number * factor) / factor;
- }
- function isLeapYear(year) {
- return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
- }
- function daysInYear(year) {
- return isLeapYear(year) ? 366 : 365;
- }
- function daysInMonth(year, month) {
- const modMonth = floorMod(month - 1, 12) + 1,
- modYear = year + (month - modMonth) / 12;
- if (modMonth === 2) {
- return isLeapYear(modYear) ? 29 : 28;
- } else {
- return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
- }
- }
- function objToLocalTS(obj) {
- let d = Date.UTC(
- obj.year,
- obj.month - 1,
- obj.day,
- obj.hour,
- obj.minute,
- obj.second,
- obj.millisecond
- );
-
- if (obj.year < 100 && obj.year >= 0) {
- d = new Date(d);
-
-
-
- d.setUTCFullYear(obj.year, obj.month - 1, obj.day);
- }
- return +d;
- }
- function weeksInWeekYear(weekYear) {
- const p1 =
- (weekYear +
- Math.floor(weekYear / 4) -
- Math.floor(weekYear / 100) +
- Math.floor(weekYear / 400)) %
- 7,
- last = weekYear - 1,
- p2 = (last + Math.floor(last / 4) - Math.floor(last / 100) + Math.floor(last / 400)) % 7;
- return p1 === 4 || p2 === 3 ? 53 : 52;
- }
- function untruncateYear(year) {
- if (year > 99) {
- return year;
- } else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year;
- }
- function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
- const date = new Date(ts),
- intlOpts = {
- hourCycle: "h23",
- year: "numeric",
- month: "2-digit",
- day: "2-digit",
- hour: "2-digit",
- minute: "2-digit",
- };
- if (timeZone) {
- intlOpts.timeZone = timeZone;
- }
- const modified = { timeZoneName: offsetFormat, ...intlOpts };
- const parsed = new Intl.DateTimeFormat(locale, modified)
- .formatToParts(date)
- .find((m) => m.type.toLowerCase() === "timezonename");
- return parsed ? parsed.value : null;
- }
- function signedOffset(offHourStr, offMinuteStr) {
- let offHour = parseInt(offHourStr, 10);
-
- if (Number.isNaN(offHour)) {
- offHour = 0;
- }
- const offMin = parseInt(offMinuteStr, 10) || 0,
- offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
- return offHour * 60 + offMinSigned;
- }
- function asNumber(value) {
- const numericValue = Number(value);
- if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue))
- throw new InvalidArgumentError(`Invalid unit value ${value}`);
- return numericValue;
- }
- function normalizeObject(obj, normalizer) {
- const normalized = {};
- for (const u in obj) {
- if (hasOwnProperty(obj, u)) {
- const v = obj[u];
- if (v === undefined || v === null) continue;
- normalized[normalizer(u)] = asNumber(v);
- }
- }
- return normalized;
- }
- function formatOffset(offset, format) {
- const hours = Math.trunc(Math.abs(offset / 60)),
- minutes = Math.trunc(Math.abs(offset % 60)),
- sign = offset >= 0 ? "+" : "-";
- switch (format) {
- case "short":
- return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
- case "narrow":
- return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
- case "techie":
- return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
- default:
- throw new RangeError(`Value format ${format} is out of range for property format`);
- }
- }
- function timeObject(obj) {
- return pick(obj, ["hour", "minute", "second", "millisecond"]);
- }
- const monthsLong = [
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December",
- ];
- const monthsShort = [
- "Jan",
- "Feb",
- "Mar",
- "Apr",
- "May",
- "Jun",
- "Jul",
- "Aug",
- "Sep",
- "Oct",
- "Nov",
- "Dec",
- ];
- const monthsNarrow = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
- function months(length) {
- switch (length) {
- case "narrow":
- return [...monthsNarrow];
- case "short":
- return [...monthsShort];
- case "long":
- return [...monthsLong];
- case "numeric":
- return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
- case "2-digit":
- return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
- default:
- return null;
- }
- }
- const weekdaysLong = [
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday",
- "Sunday",
- ];
- const weekdaysShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
- const weekdaysNarrow = ["M", "T", "W", "T", "F", "S", "S"];
- function weekdays(length) {
- switch (length) {
- case "narrow":
- return [...weekdaysNarrow];
- case "short":
- return [...weekdaysShort];
- case "long":
- return [...weekdaysLong];
- case "numeric":
- return ["1", "2", "3", "4", "5", "6", "7"];
- default:
- return null;
- }
- }
- const meridiems = ["AM", "PM"];
- const erasLong = ["Before Christ", "Anno Domini"];
- const erasShort = ["BC", "AD"];
- const erasNarrow = ["B", "A"];
- function eras(length) {
- switch (length) {
- case "narrow":
- return [...erasNarrow];
- case "short":
- return [...erasShort];
- case "long":
- return [...erasLong];
- default:
- return null;
- }
- }
- function meridiemForDateTime(dt) {
- return meridiems[dt.hour < 12 ? 0 : 1];
- }
- function weekdayForDateTime(dt, length) {
- return weekdays(length)[dt.weekday - 1];
- }
- function monthForDateTime(dt, length) {
- return months(length)[dt.month - 1];
- }
- function eraForDateTime(dt, length) {
- return eras(length)[dt.year < 0 ? 0 : 1];
- }
- function formatRelativeTime(unit, count, numeric = "always", narrow = false) {
- const units = {
- years: ["year", "yr."],
- quarters: ["quarter", "qtr."],
- months: ["month", "mo."],
- weeks: ["week", "wk."],
- days: ["day", "day", "days"],
- hours: ["hour", "hr."],
- minutes: ["minute", "min."],
- seconds: ["second", "sec."],
- };
- const lastable = ["hours", "minutes", "seconds"].indexOf(unit) === -1;
- if (numeric === "auto" && lastable) {
- const isDay = unit === "days";
- switch (count) {
- case 1:
- return isDay ? "tomorrow" : `next ${units[unit][0]}`;
- case -1:
- return isDay ? "yesterday" : `last ${units[unit][0]}`;
- case 0:
- return isDay ? "today" : `this ${units[unit][0]}`;
- }
- }
- const isInPast = Object.is(count, -0) || count < 0,
- fmtValue = Math.abs(count),
- singular = fmtValue === 1,
- lilUnits = units[unit],
- fmtUnit = narrow
- ? singular
- ? lilUnits[1]
- : lilUnits[2] || lilUnits[1]
- : singular
- ? units[unit][0]
- : unit;
- return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`;
- }
- function stringifyTokens(splits, tokenToString) {
- let s = "";
- for (const token of splits) {
- if (token.literal) {
- s += token.val;
- } else {
- s += tokenToString(token.val);
- }
- }
- return s;
- }
- const macroTokenToFormatOpts = {
- D: DATE_SHORT,
- DD: DATE_MED,
- DDD: DATE_FULL,
- DDDD: DATE_HUGE,
- t: TIME_SIMPLE,
- tt: TIME_WITH_SECONDS,
- ttt: TIME_WITH_SHORT_OFFSET,
- tttt: TIME_WITH_LONG_OFFSET,
- T: TIME_24_SIMPLE,
- TT: TIME_24_WITH_SECONDS,
- TTT: TIME_24_WITH_SHORT_OFFSET,
- TTTT: TIME_24_WITH_LONG_OFFSET,
- f: DATETIME_SHORT,
- ff: DATETIME_MED,
- fff: DATETIME_FULL,
- ffff: DATETIME_HUGE,
- F: DATETIME_SHORT_WITH_SECONDS,
- FF: DATETIME_MED_WITH_SECONDS,
- FFF: DATETIME_FULL_WITH_SECONDS,
- FFFF: DATETIME_HUGE_WITH_SECONDS,
- };
- class Formatter {
- static create(locale, opts = {}) {
- return new Formatter(locale, opts);
- }
- static parseFormat(fmt) {
-
-
- let current = null,
- currentFull = "",
- bracketed = false;
- const splits = [];
- for (let i = 0; i < fmt.length; i++) {
- const c = fmt.charAt(i);
- if (c === "'") {
- if (currentFull.length > 0) {
- splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
- }
- current = null;
- currentFull = "";
- bracketed = !bracketed;
- } else if (bracketed) {
- currentFull += c;
- } else if (c === current) {
- currentFull += c;
- } else {
- if (currentFull.length > 0) {
- splits.push({ literal: /^\s+$/.test(currentFull), val: currentFull });
- }
- currentFull = c;
- current = c;
- }
- }
- if (currentFull.length > 0) {
- splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
- }
- return splits;
- }
- static macroTokenToFormatOpts(token) {
- return macroTokenToFormatOpts[token];
- }
- constructor(locale, formatOpts) {
- this.opts = formatOpts;
- this.loc = locale;
- this.systemLoc = null;
- }
- formatWithSystemDefault(dt, opts) {
- if (this.systemLoc === null) {
- this.systemLoc = this.loc.redefaultToSystem();
- }
- const df = this.systemLoc.dtFormatter(dt, { ...this.opts, ...opts });
- return df.format();
- }
- dtFormatter(dt, opts = {}) {
- return this.loc.dtFormatter(dt, { ...this.opts, ...opts });
- }
- formatDateTime(dt, opts) {
- return this.dtFormatter(dt, opts).format();
- }
- formatDateTimeParts(dt, opts) {
- return this.dtFormatter(dt, opts).formatToParts();
- }
- formatInterval(interval, opts) {
- const df = this.dtFormatter(interval.start, opts);
- return df.dtf.formatRange(interval.start.toJSDate(), interval.end.toJSDate());
- }
- resolvedOptions(dt, opts) {
- return this.dtFormatter(dt, opts).resolvedOptions();
- }
- num(n, p = 0) {
-
- if (this.opts.forceSimple) {
- return padStart(n, p);
- }
- const opts = { ...this.opts };
- if (p > 0) {
- opts.padTo = p;
- }
- return this.loc.numberFormatter(opts).format(n);
- }
- formatDateTimeFromString(dt, fmt) {
- const knownEnglish = this.loc.listingMode() === "en",
- useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
- string = (opts, extract) => this.loc.extract(dt, opts, extract),
- formatOffset = (opts) => {
- if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {
- return "Z";
- }
- return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : "";
- },
- meridiem = () =>
- knownEnglish
- ? meridiemForDateTime(dt)
- : string({ hour: "numeric", hourCycle: "h12" }, "dayperiod"),
- month = (length, standalone) =>
- knownEnglish
- ? monthForDateTime(dt, length)
- : string(standalone ? { month: length } : { month: length, day: "numeric" }, "month"),
- weekday = (length, standalone) =>
- knownEnglish
- ? weekdayForDateTime(dt, length)
- : string(
- standalone ? { weekday: length } : { weekday: length, month: "long", day: "numeric" },
- "weekday"
- ),
- maybeMacro = (token) => {
- const formatOpts = Formatter.macroTokenToFormatOpts(token);
- if (formatOpts) {
- return this.formatWithSystemDefault(dt, formatOpts);
- } else {
- return token;
- }
- },
- era = (length) =>
- knownEnglish ? eraForDateTime(dt, length) : string({ era: length }, "era"),
- tokenToString = (token) => {
-
- switch (token) {
-
- case "S":
- return this.num(dt.millisecond);
- case "u":
-
- case "SSS":
- return this.num(dt.millisecond, 3);
-
- case "s":
- return this.num(dt.second);
- case "ss":
- return this.num(dt.second, 2);
-
- case "uu":
- return this.num(Math.floor(dt.millisecond / 10), 2);
- case "uuu":
- return this.num(Math.floor(dt.millisecond / 100));
-
- case "m":
- return this.num(dt.minute);
- case "mm":
- return this.num(dt.minute, 2);
-
- case "h":
- return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12);
- case "hh":
- return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2);
- case "H":
- return this.num(dt.hour);
- case "HH":
- return this.num(dt.hour, 2);
-
- case "Z":
-
- return formatOffset({ format: "narrow", allowZ: this.opts.allowZ });
- case "ZZ":
-
- return formatOffset({ format: "short", allowZ: this.opts.allowZ });
- case "ZZZ":
-
- return formatOffset({ format: "techie", allowZ: this.opts.allowZ });
- case "ZZZZ":
-
- return dt.zone.offsetName(dt.ts, { format: "short", locale: this.loc.locale });
- case "ZZZZZ":
-
- return dt.zone.offsetName(dt.ts, { format: "long", locale: this.loc.locale });
-
- case "z":
-
- return dt.zoneName;
-
- case "a":
- return meridiem();
-
- case "d":
- return useDateTimeFormatter ? string({ day: "numeric" }, "day") : this.num(dt.day);
- case "dd":
- return useDateTimeFormatter ? string({ day: "2-digit" }, "day") : this.num(dt.day, 2);
-
- case "c":
-
- return this.num(dt.weekday);
- case "ccc":
-
- return weekday("short", true);
- case "cccc":
-
- return weekday("long", true);
- case "ccccc":
-
- return weekday("narrow", true);
-
- case "E":
-
- return this.num(dt.weekday);
- case "EEE":
-
- return weekday("short", false);
- case "EEEE":
-
- return weekday("long", false);
- case "EEEEE":
-
- return weekday("narrow", false);
-
- case "L":
-
- return useDateTimeFormatter
- ? string({ month: "numeric", day: "numeric" }, "month")
- : this.num(dt.month);
- case "LL":
-
- return useDateTimeFormatter
- ? string({ month: "2-digit", day: "numeric" }, "month")
- : this.num(dt.month, 2);
- case "LLL":
-
- return month("short", true);
- case "LLLL":
-
- return month("long", true);
- case "LLLLL":
-
- return month("narrow", true);
-
- case "M":
-
- return useDateTimeFormatter
- ? string({ month: "numeric" }, "month")
- : this.num(dt.month);
- case "MM":
-
- return useDateTimeFormatter
- ? string({ month: "2-digit" }, "month")
- : this.num(dt.month, 2);
- case "MMM":
-
- return month("short", false);
- case "MMMM":
-
- return month("long", false);
- case "MMMMM":
-
- return month("narrow", false);
-
- case "y":
-
- return useDateTimeFormatter ? string({ year: "numeric" }, "year") : this.num(dt.year);
- case "yy":
-
- return useDateTimeFormatter
- ? string({ year: "2-digit" }, "year")
- : this.num(dt.year.toString().slice(-2), 2);
- case "yyyy":
-
- return useDateTimeFormatter
- ? string({ year: "numeric" }, "year")
- : this.num(dt.year, 4);
- case "yyyyyy":
-
- return useDateTimeFormatter
- ? string({ year: "numeric" }, "year")
- : this.num(dt.year, 6);
-
- case "G":
-
- return era("short");
- case "GG":
-
- return era("long");
- case "GGGGG":
- return era("narrow");
- case "kk":
- return this.num(dt.weekYear.toString().slice(-2), 2);
- case "kkkk":
- return this.num(dt.weekYear, 4);
- case "W":
- return this.num(dt.weekNumber);
- case "WW":
- return this.num(dt.weekNumber, 2);
- case "o":
- return this.num(dt.ordinal);
- case "ooo":
- return this.num(dt.ordinal, 3);
- case "q":
-
- return this.num(dt.quarter);
- case "qq":
-
- return this.num(dt.quarter, 2);
- case "X":
- return this.num(Math.floor(dt.ts / 1000));
- case "x":
- return this.num(dt.ts);
- default:
- return maybeMacro(token);
- }
- };
- return stringifyTokens(Formatter.parseFormat(fmt), tokenToString);
- }
- formatDurationFromString(dur, fmt) {
- const tokenToField = (token) => {
- switch (token[0]) {
- case "S":
- return "millisecond";
- case "s":
- return "second";
- case "m":
- return "minute";
- case "h":
- return "hour";
- case "d":
- return "day";
- case "w":
- return "week";
- case "M":
- return "month";
- case "y":
- return "year";
- default:
- return null;
- }
- },
- tokenToString = (lildur) => (token) => {
- const mapped = tokenToField(token);
- if (mapped) {
- return this.num(lildur.get(mapped), token.length);
- } else {
- return token;
- }
- },
- tokens = Formatter.parseFormat(fmt),
- realTokens = tokens.reduce(
- (found, { literal, val }) => (literal ? found : found.concat(val)),
- []
- ),
- collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t));
- return stringifyTokens(tokens, tokenToString(collapsed));
- }
- }
- class Invalid {
- constructor(reason, explanation) {
- this.reason = reason;
- this.explanation = explanation;
- }
- toMessage() {
- if (this.explanation) {
- return `${this.reason}: ${this.explanation}`;
- } else {
- return this.reason;
- }
- }
- }
- const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
- function combineRegexes(...regexes) {
- const full = regexes.reduce((f, r) => f + r.source, "");
- return RegExp(`^${full}$`);
- }
- function combineExtractors(...extractors) {
- return (m) =>
- extractors
- .reduce(
- ([mergedVals, mergedZone, cursor], ex) => {
- const [val, zone, next] = ex(m, cursor);
- return [{ ...mergedVals, ...val }, zone || mergedZone, next];
- },
- [{}, null, 1]
- )
- .slice(0, 2);
- }
- function parse(s, ...patterns) {
- if (s == null) {
- return [null, null];
- }
- for (const [regex, extractor] of patterns) {
- const m = regex.exec(s);
- if (m) {
- return extractor(m);
- }
- }
- return [null, null];
- }
- function simpleParse(...keys) {
- return (match, cursor) => {
- const ret = {};
- let i;
- for (i = 0; i < keys.length; i++) {
- ret[keys[i]] = parseInteger(match[cursor + i]);
- }
- return [ret, null, cursor + i];
- };
- }
- const offsetRegex = /(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/;
- const isoExtendedZone = `(?:${offsetRegex.source}?(?:\\[(${ianaRegex.source})\\])?)?`;
- const isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/;
- const isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${isoExtendedZone}`);
- const isoTimeExtensionRegex = RegExp(`(?:T${isoTimeRegex.source})?`);
- const isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;
- const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/;
- const isoOrdinalRegex = /(\d{4})-?(\d{3})/;
- const extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekDay");
- const extractISOOrdinalData = simpleParse("year", "ordinal");
- const sqlYmdRegex = /(\d{4})-(\d\d)-(\d\d)/;
- const sqlTimeRegex = RegExp(
- `${isoTimeBaseRegex.source} ?(?:${offsetRegex.source}|(${ianaRegex.source}))?`
- );
- const sqlTimeExtensionRegex = RegExp(`(?: ${sqlTimeRegex.source})?`);
- function int(match, pos, fallback) {
- const m = match[pos];
- return isUndefined(m) ? fallback : parseInteger(m);
- }
- function extractISOYmd(match, cursor) {
- const item = {
- year: int(match, cursor),
- month: int(match, cursor + 1, 1),
- day: int(match, cursor + 2, 1),
- };
- return [item, null, cursor + 3];
- }
- function extractISOTime(match, cursor) {
- const item = {
- hours: int(match, cursor, 0),
- minutes: int(match, cursor + 1, 0),
- seconds: int(match, cursor + 2, 0),
- milliseconds: parseMillis(match[cursor + 3]),
- };
- return [item, null, cursor + 4];
- }
- function extractISOOffset(match, cursor) {
- const local = !match[cursor] && !match[cursor + 1],
- fullOffset = signedOffset(match[cursor + 1], match[cursor + 2]),
- zone = local ? null : FixedOffsetZone.instance(fullOffset);
- return [{}, zone, cursor + 3];
- }
- function extractIANAZone(match, cursor) {
- const zone = match[cursor] ? IANAZone.create(match[cursor]) : null;
- return [{}, zone, cursor + 1];
- }
- const isoTimeOnly = RegExp(`^T?${isoTimeBaseRegex.source}$`);
- const isoDuration =
- /^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/;
- function extractISODuration(match) {
- const [s, yearStr, monthStr, weekStr, dayStr, hourStr, minuteStr, secondStr, millisecondsStr] =
- match;
- const hasNegativePrefix = s[0] === "-";
- const negativeSeconds = secondStr && secondStr[0] === "-";
- const maybeNegate = (num, force = false) =>
- num !== undefined && (force || (num && hasNegativePrefix)) ? -num : num;
- return [
- {
- years: maybeNegate(parseFloating(yearStr)),
- months: maybeNegate(parseFloating(monthStr)),
- weeks: maybeNegate(parseFloating(weekStr)),
- days: maybeNegate(parseFloating(dayStr)),
- hours: maybeNegate(parseFloating(hourStr)),
- minutes: maybeNegate(parseFloating(minuteStr)),
- seconds: maybeNegate(parseFloating(secondStr), secondStr === "-0"),
- milliseconds: maybeNegate(parseMillis(millisecondsStr), negativeSeconds),
- },
- ];
- }
- const obsOffsets = {
- GMT: 0,
- EDT: -4 * 60,
- EST: -5 * 60,
- CDT: -5 * 60,
- CST: -6 * 60,
- MDT: -6 * 60,
- MST: -7 * 60,
- PDT: -7 * 60,
- PST: -8 * 60,
- };
- function fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
- const result = {
- year: yearStr.length === 2 ? untruncateYear(parseInteger(yearStr)) : parseInteger(yearStr),
- month: monthsShort.indexOf(monthStr) + 1,
- day: parseInteger(dayStr),
- hour: parseInteger(hourStr),
- minute: parseInteger(minuteStr),
- };
- if (secondStr) result.second = parseInteger(secondStr);
- if (weekdayStr) {
- result.weekday =
- weekdayStr.length > 3
- ? weekdaysLong.indexOf(weekdayStr) + 1
- : weekdaysShort.indexOf(weekdayStr) + 1;
- }
- return result;
- }
- const rfc2822 =
- /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;
- function extractRFC2822(match) {
- const [
- ,
- weekdayStr,
- dayStr,
- monthStr,
- yearStr,
- hourStr,
- minuteStr,
- secondStr,
- obsOffset,
- milOffset,
- offHourStr,
- offMinuteStr,
- ] = match,
- result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
- let offset;
- if (obsOffset) {
- offset = obsOffsets[obsOffset];
- } else if (milOffset) {
- offset = 0;
- } else {
- offset = signedOffset(offHourStr, offMinuteStr);
- }
- return [result, new FixedOffsetZone(offset)];
- }
- function preprocessRFC2822(s) {
-
- return s
- .replace(/\([^()]*\)|[\n\t]/g, " ")
- .replace(/(\s\s+)/g, " ")
- .trim();
- }
- const rfc1123 =
- /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,
- rfc850 =
- /^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,
- ascii =
- /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;
- function extractRFC1123Or850(match) {
- const [, weekdayStr, dayStr, monthStr, yearStr, hourStr, minuteStr, secondStr] = match,
- result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
- return [result, FixedOffsetZone.utcInstance];
- }
- function extractASCII(match) {
- const [, weekdayStr, monthStr, dayStr, hourStr, minuteStr, secondStr, yearStr] = match,
- result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
- return [result, FixedOffsetZone.utcInstance];
- }
- const isoYmdWithTimeExtensionRegex = combineRegexes(isoYmdRegex, isoTimeExtensionRegex);
- const isoWeekWithTimeExtensionRegex = combineRegexes(isoWeekRegex, isoTimeExtensionRegex);
- const isoOrdinalWithTimeExtensionRegex = combineRegexes(isoOrdinalRegex, isoTimeExtensionRegex);
- const isoTimeCombinedRegex = combineRegexes(isoTimeRegex);
- const extractISOYmdTimeAndOffset = combineExtractors(
- extractISOYmd,
- extractISOTime,
- extractISOOffset,
- extractIANAZone
- );
- const extractISOWeekTimeAndOffset = combineExtractors(
- extractISOWeekData,
- extractISOTime,
- extractISOOffset,
- extractIANAZone
- );
- const extractISOOrdinalDateAndTime = combineExtractors(
- extractISOOrdinalData,
- extractISOTime,
- extractISOOffset,
- extractIANAZone
- );
- const extractISOTimeAndOffset = combineExtractors(
- extractISOTime,
- extractISOOffset,
- extractIANAZone
- );
- function parseISODate(s) {
- return parse(
- s,
- [isoYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset],
- [isoWeekWithTimeExtensionRegex, extractISOWeekTimeAndOffset],
- [isoOrdinalWithTimeExtensionRegex, extractISOOrdinalDateAndTime],
- [isoTimeCombinedRegex, extractISOTimeAndOffset]
- );
- }
- function parseRFC2822Date(s) {
- return parse(preprocessRFC2822(s), [rfc2822, extractRFC2822]);
- }
- function parseHTTPDate(s) {
- return parse(
- s,
- [rfc1123, extractRFC1123Or850],
- [rfc850, extractRFC1123Or850],
- [ascii, extractASCII]
- );
- }
- function parseISODuration(s) {
- return parse(s, [isoDuration, extractISODuration]);
- }
- const extractISOTimeOnly = combineExtractors(extractISOTime);
- function parseISOTimeOnly(s) {
- return parse(s, [isoTimeOnly, extractISOTimeOnly]);
- }
- const sqlYmdWithTimeExtensionRegex = combineRegexes(sqlYmdRegex, sqlTimeExtensionRegex);
- const sqlTimeCombinedRegex = combineRegexes(sqlTimeRegex);
- const extractISOTimeOffsetAndIANAZone = combineExtractors(
- extractISOTime,
- extractISOOffset,
- extractIANAZone
- );
- function parseSQL(s) {
- return parse(
- s,
- [sqlYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset],
- [sqlTimeCombinedRegex, extractISOTimeOffsetAndIANAZone]
- );
- }
- const INVALID$2 = "Invalid Duration";
- const lowOrderMatrix = {
- weeks: {
- days: 7,
- hours: 7 * 24,
- minutes: 7 * 24 * 60,
- seconds: 7 * 24 * 60 * 60,
- milliseconds: 7 * 24 * 60 * 60 * 1000,
- },
- days: {
- hours: 24,
- minutes: 24 * 60,
- seconds: 24 * 60 * 60,
- milliseconds: 24 * 60 * 60 * 1000,
- },
- hours: { minutes: 60, seconds: 60 * 60, milliseconds: 60 * 60 * 1000 },
- minutes: { seconds: 60, milliseconds: 60 * 1000 },
- seconds: { milliseconds: 1000 },
- },
- casualMatrix = {
- years: {
- quarters: 4,
- months: 12,
- weeks: 52,
- days: 365,
- hours: 365 * 24,
- minutes: 365 * 24 * 60,
- seconds: 365 * 24 * 60 * 60,
- milliseconds: 365 * 24 * 60 * 60 * 1000,
- },
- quarters: {
- months: 3,
- weeks: 13,
- days: 91,
- hours: 91 * 24,
- minutes: 91 * 24 * 60,
- seconds: 91 * 24 * 60 * 60,
- milliseconds: 91 * 24 * 60 * 60 * 1000,
- },
- months: {
- weeks: 4,
- days: 30,
- hours: 30 * 24,
- minutes: 30 * 24 * 60,
- seconds: 30 * 24 * 60 * 60,
- milliseconds: 30 * 24 * 60 * 60 * 1000,
- },
- ...lowOrderMatrix,
- },
- daysInYearAccurate = 146097.0 / 400,
- daysInMonthAccurate = 146097.0 / 4800,
- accurateMatrix = {
- years: {
- quarters: 4,
- months: 12,
- weeks: daysInYearAccurate / 7,
- days: daysInYearAccurate,
- hours: daysInYearAccurate * 24,
- minutes: daysInYearAccurate * 24 * 60,
- seconds: daysInYearAccurate * 24 * 60 * 60,
- milliseconds: daysInYearAccurate * 24 * 60 * 60 * 1000,
- },
- quarters: {
- months: 3,
- weeks: daysInYearAccurate / 28,
- days: daysInYearAccurate / 4,
- hours: (daysInYearAccurate * 24) / 4,
- minutes: (daysInYearAccurate * 24 * 60) / 4,
- seconds: (daysInYearAccurate * 24 * 60 * 60) / 4,
- milliseconds: (daysInYearAccurate * 24 * 60 * 60 * 1000) / 4,
- },
- months: {
- weeks: daysInMonthAccurate / 7,
- days: daysInMonthAccurate,
- hours: daysInMonthAccurate * 24,
- minutes: daysInMonthAccurate * 24 * 60,
- seconds: daysInMonthAccurate * 24 * 60 * 60,
- milliseconds: daysInMonthAccurate * 24 * 60 * 60 * 1000,
- },
- ...lowOrderMatrix,
- };
- const orderedUnits$1 = [
- "years",
- "quarters",
- "months",
- "weeks",
- "days",
- "hours",
- "minutes",
- "seconds",
- "milliseconds",
- ];
- const reverseUnits = orderedUnits$1.slice(0).reverse();
- function clone$1(dur, alts, clear = false) {
-
- const conf = {
- values: clear ? alts.values : { ...dur.values, ...(alts.values || {}) },
- loc: dur.loc.clone(alts.loc),
- conversionAccuracy: alts.conversionAccuracy || dur.conversionAccuracy,
- matrix: alts.matrix || dur.matrix,
- };
- return new Duration(conf);
- }
- function durationToMillis(matrix, vals) {
- let sum = vals.milliseconds ?? 0;
- for (const unit of reverseUnits.slice(1)) {
- if (vals[unit]) {
- sum += vals[unit] * matrix[unit]["milliseconds"];
- }
- }
- return sum;
- }
- function normalizeValues(matrix, vals) {
-
-
- const factor = durationToMillis(matrix, vals) < 0 ? -1 : 1;
- orderedUnits$1.reduceRight((previous, current) => {
- if (!isUndefined(vals[current])) {
- if (previous) {
- const previousVal = vals[previous] * factor;
- const conv = matrix[current][previous];
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- const rollUp = Math.floor(previousVal / conv);
- vals[current] += rollUp * factor;
- vals[previous] -= rollUp * conv * factor;
- }
- return current;
- } else {
- return previous;
- }
- }, null);
-
-
- orderedUnits$1.reduce((previous, current) => {
- if (!isUndefined(vals[current])) {
- if (previous) {
- const fraction = vals[previous] % 1;
- vals[previous] -= fraction;
- vals[current] += fraction * matrix[previous][current];
- }
- return current;
- } else {
- return previous;
- }
- }, null);
- }
- function removeZeroes(vals) {
- const newVals = {};
- for (const [key, value] of Object.entries(vals)) {
- if (value !== 0) {
- newVals[key] = value;
- }
- }
- return newVals;
- }
- class Duration {
-
- constructor(config) {
- const accurate = config.conversionAccuracy === "longterm" || false;
- let matrix = accurate ? accurateMatrix : casualMatrix;
- if (config.matrix) {
- matrix = config.matrix;
- }
-
- this.values = config.values;
-
- this.loc = config.loc || Locale.create();
-
- this.conversionAccuracy = accurate ? "longterm" : "casual";
-
- this.invalid = config.invalid || null;
-
- this.matrix = matrix;
-
- this.isLuxonDuration = true;
- }
-
- static fromMillis(count, opts) {
- return Duration.fromObject({ milliseconds: count }, opts);
- }
-
- static fromObject(obj, opts = {}) {
- if (obj == null || typeof obj !== "object") {
- throw new InvalidArgumentError(
- `Duration.fromObject: argument expected to be an object, got ${
- obj === null ? "null" : typeof obj
- }`
- );
- }
- return new Duration({
- values: normalizeObject(obj, Duration.normalizeUnit),
- loc: Locale.fromObject(opts),
- conversionAccuracy: opts.conversionAccuracy,
- matrix: opts.matrix,
- });
- }
-
- static fromDurationLike(durationLike) {
- if (isNumber(durationLike)) {
- return Duration.fromMillis(durationLike);
- } else if (Duration.isDuration(durationLike)) {
- return durationLike;
- } else if (typeof durationLike === "object") {
- return Duration.fromObject(durationLike);
- } else {
- throw new InvalidArgumentError(
- `Unknown duration argument ${durationLike} of type ${typeof durationLike}`
- );
- }
- }
-
- static fromISO(text, opts) {
- const [parsed] = parseISODuration(text);
- if (parsed) {
- return Duration.fromObject(parsed, opts);
- } else {
- return Duration.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`);
- }
- }
-
- static fromISOTime(text, opts) {
- const [parsed] = parseISOTimeOnly(text);
- if (parsed) {
- return Duration.fromObject(parsed, opts);
- } else {
- return Duration.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`);
- }
- }
-
- static invalid(reason, explanation = null) {
- if (!reason) {
- throw new InvalidArgumentError("need to specify a reason the Duration is invalid");
- }
- const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
- if (Settings.throwOnInvalid) {
- throw new InvalidDurationError(invalid);
- } else {
- return new Duration({ invalid });
- }
- }
-
- static normalizeUnit(unit) {
- const normalized = {
- year: "years",
- years: "years",
- quarter: "quarters",
- quarters: "quarters",
- month: "months",
- months: "months",
- week: "weeks",
- weeks: "weeks",
- day: "days",
- days: "days",
- hour: "hours",
- hours: "hours",
- minute: "minutes",
- minutes: "minutes",
- second: "seconds",
- seconds: "seconds",
- millisecond: "milliseconds",
- milliseconds: "milliseconds",
- }[unit ? unit.toLowerCase() : unit];
- if (!normalized) throw new InvalidUnitError(unit);
- return normalized;
- }
-
- static isDuration(o) {
- return (o && o.isLuxonDuration) || false;
- }
-
- get locale() {
- return this.isValid ? this.loc.locale : null;
- }
-
- get numberingSystem() {
- return this.isValid ? this.loc.numberingSystem : null;
- }
-
- toFormat(fmt, opts = {}) {
-
- const fmtOpts = {
- ...opts,
- floor: opts.round !== false && opts.floor !== false,
- };
- return this.isValid
- ? Formatter.create(this.loc, fmtOpts).formatDurationFromString(this, fmt)
- : INVALID$2;
- }
-
- toHuman(opts = {}) {
- if (!this.isValid) return INVALID$2;
- const l = orderedUnits$1
- .map((unit) => {
- const val = this.values[unit];
- if (isUndefined(val)) {
- return null;
- }
- return this.loc
- .numberFormatter({ style: "unit", unitDisplay: "long", ...opts, unit: unit.slice(0, -1) })
- .format(val);
- })
- .filter((n) => n);
- return this.loc
- .listFormatter({ type: "conjunction", style: opts.listStyle || "narrow", ...opts })
- .format(l);
- }
-
- toObject() {
- if (!this.isValid) return {};
- return { ...this.values };
- }
-
- toISO() {
-
- if (!this.isValid) return null;
- let s = "P";
- if (this.years !== 0) s += this.years + "Y";
- if (this.months !== 0 || this.quarters !== 0) s += this.months + this.quarters * 3 + "M";
- if (this.weeks !== 0) s += this.weeks + "W";
- if (this.days !== 0) s += this.days + "D";
- if (this.hours !== 0 || this.minutes !== 0 || this.seconds !== 0 || this.milliseconds !== 0)
- s += "T";
- if (this.hours !== 0) s += this.hours + "H";
- if (this.minutes !== 0) s += this.minutes + "M";
- if (this.seconds !== 0 || this.milliseconds !== 0)
-
-
- s += roundTo(this.seconds + this.milliseconds / 1000, 3) + "S";
- if (s === "P") s += "T0S";
- return s;
- }
-
- toISOTime(opts = {}) {
- if (!this.isValid) return null;
- const millis = this.toMillis();
- if (millis < 0 || millis >= 86400000) return null;
- opts = {
- suppressMilliseconds: false,
- suppressSeconds: false,
- includePrefix: false,
- format: "extended",
- ...opts,
- includeOffset: false,
- };
- const dateTime = DateTime.fromMillis(millis, { zone: "UTC" });
- return dateTime.toISOTime(opts);
- }
-
- toJSON() {
- return this.toISO();
- }
-
- toString() {
- return this.toISO();
- }
-
- toMillis() {
- if (!this.isValid) return NaN;
- return durationToMillis(this.matrix, this.values);
- }
-
- valueOf() {
- return this.toMillis();
- }
-
- plus(duration) {
- if (!this.isValid) return this;
- const dur = Duration.fromDurationLike(duration),
- result = {};
- for (const k of orderedUnits$1) {
- if (hasOwnProperty(dur.values, k) || hasOwnProperty(this.values, k)) {
- result[k] = dur.get(k) + this.get(k);
- }
- }
- return clone$1(this, { values: result }, true);
- }
-
- minus(duration) {
- if (!this.isValid) return this;
- const dur = Duration.fromDurationLike(duration);
- return this.plus(dur.negate());
- }
-
- mapUnits(fn) {
- if (!this.isValid) return this;
- const result = {};
- for (const k of Object.keys(this.values)) {
- result[k] = asNumber(fn(this.values[k], k));
- }
- return clone$1(this, { values: result }, true);
- }
-
- get(unit) {
- return this[Duration.normalizeUnit(unit)];
- }
-
- set(values) {
- if (!this.isValid) return this;
- const mixed = { ...this.values, ...normalizeObject(values, Duration.normalizeUnit) };
- return clone$1(this, { values: mixed });
- }
-
- reconfigure({ locale, numberingSystem, conversionAccuracy, matrix } = {}) {
- const loc = this.loc.clone({ locale, numberingSystem });
- const opts = { loc, matrix, conversionAccuracy };
- return clone$1(this, opts);
- }
-
- as(unit) {
- return this.isValid ? this.shiftTo(unit).get(unit) : NaN;
- }
-
- normalize() {
- if (!this.isValid) return this;
- const vals = this.toObject();
- normalizeValues(this.matrix, vals);
- return clone$1(this, { values: vals }, true);
- }
-
- rescale() {
- if (!this.isValid) return this;
- const vals = removeZeroes(this.normalize().shiftToAll().toObject());
- return clone$1(this, { values: vals }, true);
- }
-
- shiftTo(...units) {
- if (!this.isValid) return this;
- if (units.length === 0) {
- return this;
- }
- units = units.map((u) => Duration.normalizeUnit(u));
- const built = {},
- accumulated = {},
- vals = this.toObject();
- let lastUnit;
- for (const k of orderedUnits$1) {
- if (units.indexOf(k) >= 0) {
- lastUnit = k;
- let own = 0;
-
- for (const ak in accumulated) {
- own += this.matrix[ak][k] * accumulated[ak];
- accumulated[ak] = 0;
- }
-
- if (isNumber(vals[k])) {
- own += vals[k];
- }
-
-
- const i = Math.trunc(own);
- built[k] = i;
- accumulated[k] = (own * 1000 - i * 1000) / 1000;
-
- } else if (isNumber(vals[k])) {
- accumulated[k] = vals[k];
- }
- }
-
-
- for (const key in accumulated) {
- if (accumulated[key] !== 0) {
- built[lastUnit] +=
- key === lastUnit ? accumulated[key] : accumulated[key] / this.matrix[lastUnit][key];
- }
- }
- normalizeValues(this.matrix, built);
- return clone$1(this, { values: built }, true);
- }
-
- shiftToAll() {
- if (!this.isValid) return this;
- return this.shiftTo(
- "years",
- "months",
- "weeks",
- "days",
- "hours",
- "minutes",
- "seconds",
- "milliseconds"
- );
- }
-
- negate() {
- if (!this.isValid) return this;
- const negated = {};
- for (const k of Object.keys(this.values)) {
- negated[k] = this.values[k] === 0 ? 0 : -this.values[k];
- }
- return clone$1(this, { values: negated }, true);
- }
-
- get years() {
- return this.isValid ? this.values.years || 0 : NaN;
- }
-
- get quarters() {
- return this.isValid ? this.values.quarters || 0 : NaN;
- }
-
- get months() {
- return this.isValid ? this.values.months || 0 : NaN;
- }
-
- get weeks() {
- return this.isValid ? this.values.weeks || 0 : NaN;
- }
-
- get days() {
- return this.isValid ? this.values.days || 0 : NaN;
- }
-
- get hours() {
- return this.isValid ? this.values.hours || 0 : NaN;
- }
-
- get minutes() {
- return this.isValid ? this.values.minutes || 0 : NaN;
- }
-
- get seconds() {
- return this.isValid ? this.values.seconds || 0 : NaN;
- }
-
- get milliseconds() {
- return this.isValid ? this.values.milliseconds || 0 : NaN;
- }
-
- get isValid() {
- return this.invalid === null;
- }
-
- get invalidReason() {
- return this.invalid ? this.invalid.reason : null;
- }
-
- get invalidExplanation() {
- return this.invalid ? this.invalid.explanation : null;
- }
-
- equals(other) {
- if (!this.isValid || !other.isValid) {
- return false;
- }
- if (!this.loc.equals(other.loc)) {
- return false;
- }
- function eq(v1, v2) {
-
- if (v1 === undefined || v1 === 0) return v2 === undefined || v2 === 0;
- return v1 === v2;
- }
- for (const u of orderedUnits$1) {
- if (!eq(this.values[u], other.values[u])) {
- return false;
- }
- }
- return true;
- }
- }
- const INVALID$1 = "Invalid Interval";
- function validateStartEnd(start, end) {
- if (!start || !start.isValid) {
- return Interval.invalid("missing or invalid start");
- } else if (!end || !end.isValid) {
- return Interval.invalid("missing or invalid end");
- } else if (end < start) {
- return Interval.invalid(
- "end before start",
- `The end of an interval must be after its start, but you had start=${start.toISO()} and end=${end.toISO()}`
- );
- } else {
- return null;
- }
- }
- class Interval {
-
- constructor(config) {
-
- this.s = config.start;
-
- this.e = config.end;
-
- this.invalid = config.invalid || null;
-
- this.isLuxonInterval = true;
- }
-
- static invalid(reason, explanation = null) {
- if (!reason) {
- throw new InvalidArgumentError("need to specify a reason the Interval is invalid");
- }
- const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
- if (Settings.throwOnInvalid) {
- throw new InvalidIntervalError(invalid);
- } else {
- return new Interval({ invalid });
- }
- }
-
- static fromDateTimes(start, end) {
- const builtStart = friendlyDateTime(start),
- builtEnd = friendlyDateTime(end);
- const validateError = validateStartEnd(builtStart, builtEnd);
- if (validateError == null) {
- return new Interval({
- start: builtStart,
- end: builtEnd,
- });
- } else {
- return validateError;
- }
- }
-
- static after(start, duration) {
- const dur = Duration.fromDurationLike(duration),
- dt = friendlyDateTime(start);
- return Interval.fromDateTimes(dt, dt.plus(dur));
- }
-
- static before(end, duration) {
- const dur = Duration.fromDurationLike(duration),
- dt = friendlyDateTime(end);
- return Interval.fromDateTimes(dt.minus(dur), dt);
- }
-
- static fromISO(text, opts) {
- const [s, e] = (text || "").split("/", 2);
- if (s && e) {
- let start, startIsValid;
- try {
- start = DateTime.fromISO(s, opts);
- startIsValid = start.isValid;
- } catch (e) {
- startIsValid = false;
- }
- let end, endIsValid;
- try {
- end = DateTime.fromISO(e, opts);
- endIsValid = end.isValid;
- } catch (e) {
- endIsValid = false;
- }
- if (startIsValid && endIsValid) {
- return Interval.fromDateTimes(start, end);
- }
- if (startIsValid) {
- const dur = Duration.fromISO(e, opts);
- if (dur.isValid) {
- return Interval.after(start, dur);
- }
- } else if (endIsValid) {
- const dur = Duration.fromISO(s, opts);
- if (dur.isValid) {
- return Interval.before(end, dur);
- }
- }
- }
- return Interval.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`);
- }
-
- static isInterval(o) {
- return (o && o.isLuxonInterval) || false;
- }
-
- get start() {
- return this.isValid ? this.s : null;
- }
-
- get end() {
- return this.isValid ? this.e : null;
- }
-
- get isValid() {
- return this.invalidReason === null;
- }
-
- get invalidReason() {
- return this.invalid ? this.invalid.reason : null;
- }
-
- get invalidExplanation() {
- return this.invalid ? this.invalid.explanation : null;
- }
-
- length(unit = "milliseconds") {
- return this.isValid ? this.toDuration(...[unit]).get(unit) : NaN;
- }
-
- count(unit = "milliseconds") {
- if (!this.isValid) return NaN;
- const start = this.start.startOf(unit),
- end = this.end.startOf(unit);
- return Math.floor(end.diff(start, unit).get(unit)) + (end.valueOf() !== this.end.valueOf());
- }
-
- hasSame(unit) {
- return this.isValid ? this.isEmpty() || this.e.minus(1).hasSame(this.s, unit) : false;
- }
-
- isEmpty() {
- return this.s.valueOf() === this.e.valueOf();
- }
-
- isAfter(dateTime) {
- if (!this.isValid) return false;
- return this.s > dateTime;
- }
-
- isBefore(dateTime) {
- if (!this.isValid) return false;
- return this.e <= dateTime;
- }
-
- contains(dateTime) {
- if (!this.isValid) return false;
- return this.s <= dateTime && this.e > dateTime;
- }
-
- set({ start, end } = {}) {
- if (!this.isValid) return this;
- return Interval.fromDateTimes(start || this.s, end || this.e);
- }
-
- splitAt(...dateTimes) {
- if (!this.isValid) return [];
- const sorted = dateTimes
- .map(friendlyDateTime)
- .filter((d) => this.contains(d))
- .sort(),
- results = [];
- let { s } = this,
- i = 0;
- while (s < this.e) {
- const added = sorted[i] || this.e,
- next = +added > +this.e ? this.e : added;
- results.push(Interval.fromDateTimes(s, next));
- s = next;
- i += 1;
- }
- return results;
- }
-
- splitBy(duration) {
- const dur = Duration.fromDurationLike(duration);
- if (!this.isValid || !dur.isValid || dur.as("milliseconds") === 0) {
- return [];
- }
- let { s } = this,
- idx = 1,
- next;
- const results = [];
- while (s < this.e) {
- const added = this.start.plus(dur.mapUnits((x) => x * idx));
- next = +added > +this.e ? this.e : added;
- results.push(Interval.fromDateTimes(s, next));
- s = next;
- idx += 1;
- }
- return results;
- }
-
- divideEqually(numberOfParts) {
- if (!this.isValid) return [];
- return this.splitBy(this.length() / numberOfParts).slice(0, numberOfParts);
- }
-
- overlaps(other) {
- return this.e > other.s && this.s < other.e;
- }
-
- abutsStart(other) {
- if (!this.isValid) return false;
- return +this.e === +other.s;
- }
-
- abutsEnd(other) {
- if (!this.isValid) return false;
- return +other.e === +this.s;
- }
-
- engulfs(other) {
- if (!this.isValid) return false;
- return this.s <= other.s && this.e >= other.e;
- }
-
- equals(other) {
- if (!this.isValid || !other.isValid) {
- return false;
- }
- return this.s.equals(other.s) && this.e.equals(other.e);
- }
-
- intersection(other) {
- if (!this.isValid) return this;
- const s = this.s > other.s ? this.s : other.s,
- e = this.e < other.e ? this.e : other.e;
- if (s >= e) {
- return null;
- } else {
- return Interval.fromDateTimes(s, e);
- }
- }
-
- union(other) {
- if (!this.isValid) return this;
- const s = this.s < other.s ? this.s : other.s,
- e = this.e > other.e ? this.e : other.e;
- return Interval.fromDateTimes(s, e);
- }
-
- static merge(intervals) {
- const [found, final] = intervals
- .sort((a, b) => a.s - b.s)
- .reduce(
- ([sofar, current], item) => {
- if (!current) {
- return [sofar, item];
- } else if (current.overlaps(item) || current.abutsStart(item)) {
- return [sofar, current.union(item)];
- } else {
- return [sofar.concat([current]), item];
- }
- },
- [[], null]
- );
- if (final) {
- found.push(final);
- }
- return found;
- }
-
- static xor(intervals) {
- let start = null,
- currentCount = 0;
- const results = [],
- ends = intervals.map((i) => [
- { time: i.s, type: "s" },
- { time: i.e, type: "e" },
- ]),
- flattened = Array.prototype.concat(...ends),
- arr = flattened.sort((a, b) => a.time - b.time);
- for (const i of arr) {
- currentCount += i.type === "s" ? 1 : -1;
- if (currentCount === 1) {
- start = i.time;
- } else {
- if (start && +start !== +i.time) {
- results.push(Interval.fromDateTimes(start, i.time));
- }
- start = null;
- }
- }
- return Interval.merge(results);
- }
-
- difference(...intervals) {
- return Interval.xor([this].concat(intervals))
- .map((i) => this.intersection(i))
- .filter((i) => i && !i.isEmpty());
- }
-
- toString() {
- if (!this.isValid) return INVALID$1;
- return `[${this.s.toISO()} – ${this.e.toISO()})`;
- }
-
- toLocaleString(formatOpts = DATE_SHORT, opts = {}) {
- return this.isValid
- ? Formatter.create(this.s.loc.clone(opts), formatOpts).formatInterval(this)
- : INVALID$1;
- }
-
- toISO(opts) {
- if (!this.isValid) return INVALID$1;
- return `${this.s.toISO(opts)}/${this.e.toISO(opts)}`;
- }
-
- toISODate() {
- if (!this.isValid) return INVALID$1;
- return `${this.s.toISODate()}/${this.e.toISODate()}`;
- }
-
- toISOTime(opts) {
- if (!this.isValid) return INVALID$1;
- return `${this.s.toISOTime(opts)}/${this.e.toISOTime(opts)}`;
- }
-
- toFormat(dateFormat, { separator = " – " } = {}) {
- if (!this.isValid) return INVALID$1;
- return `${this.s.toFormat(dateFormat)}${separator}${this.e.toFormat(dateFormat)}`;
- }
-
- toDuration(unit, opts) {
- if (!this.isValid) {
- return Duration.invalid(this.invalidReason);
- }
- return this.e.diff(this.s, unit, opts);
- }
-
- mapEndpoints(mapFn) {
- return Interval.fromDateTimes(mapFn(this.s), mapFn(this.e));
- }
- }
- class Info {
-
- static hasDST(zone = Settings.defaultZone) {
- const proto = DateTime.now().setZone(zone).set({ month: 12 });
- return !zone.isUniversal && proto.offset !== proto.set({ month: 6 }).offset;
- }
-
- static isValidIANAZone(zone) {
- return IANAZone.isValidZone(zone);
- }
-
- static normalizeZone(input) {
- return normalizeZone(input, Settings.defaultZone);
- }
-
- static months(
- length = "long",
- { locale = null, numberingSystem = null, locObj = null, outputCalendar = "gregory" } = {}
- ) {
- return (locObj || Locale.create(locale, numberingSystem, outputCalendar)).months(length);
- }
-
- static monthsFormat(
- length = "long",
- { locale = null, numberingSystem = null, locObj = null, outputCalendar = "gregory" } = {}
- ) {
- return (locObj || Locale.create(locale, numberingSystem, outputCalendar)).months(length, true);
- }
-
- static weekdays(length = "long", { locale = null, numberingSystem = null, locObj = null } = {}) {
- return (locObj || Locale.create(locale, numberingSystem, null)).weekdays(length);
- }
-
- static weekdaysFormat(
- length = "long",
- { locale = null, numberingSystem = null, locObj = null } = {}
- ) {
- return (locObj || Locale.create(locale, numberingSystem, null)).weekdays(length, true);
- }
-
- static meridiems({ locale = null } = {}) {
- return Locale.create(locale).meridiems();
- }
-
- static eras(length = "short", { locale = null } = {}) {
- return Locale.create(locale, null, "gregory").eras(length);
- }
-
- static features() {
- return { relative: hasRelative() };
- }
- }
- function dayDiff(earlier, later) {
- const utcDayStart = (dt) => dt.toUTC(0, { keepLocalTime: true }).startOf("day").valueOf(),
- ms = utcDayStart(later) - utcDayStart(earlier);
- return Math.floor(Duration.fromMillis(ms).as("days"));
- }
- function highOrderDiffs(cursor, later, units) {
- const differs = [
- ["years", (a, b) => b.year - a.year],
- ["quarters", (a, b) => b.quarter - a.quarter + (b.year - a.year) * 4],
- ["months", (a, b) => b.month - a.month + (b.year - a.year) * 12],
- [
- "weeks",
- (a, b) => {
- const days = dayDiff(a, b);
- return (days - (days % 7)) / 7;
- },
- ],
- ["days", dayDiff],
- ];
- const results = {};
- const earlier = cursor;
- let lowestOrder, highWater;
-
- for (const [unit, differ] of differs) {
- if (units.indexOf(unit) >= 0) {
- lowestOrder = unit;
- results[unit] = differ(cursor, later);
- highWater = earlier.plus(results);
- if (highWater > later) {
-
- results[unit]--;
- cursor = earlier.plus(results);
-
-
-
- if (cursor > later) {
-
- highWater = cursor;
-
- results[unit]--;
- cursor = earlier.plus(results);
- }
- } else {
- cursor = highWater;
- }
- }
- }
- return [cursor, results, highWater, lowestOrder];
- }
- function diff (earlier, later, units, opts) {
- let [cursor, results, highWater, lowestOrder] = highOrderDiffs(earlier, later, units);
- const remainingMillis = later - cursor;
- const lowerOrderUnits = units.filter(
- (u) => ["hours", "minutes", "seconds", "milliseconds"].indexOf(u) >= 0
- );
- if (lowerOrderUnits.length === 0) {
- if (highWater < later) {
- highWater = cursor.plus({ [lowestOrder]: 1 });
- }
- if (highWater !== cursor) {
- results[lowestOrder] = (results[lowestOrder] || 0) + remainingMillis / (highWater - cursor);
- }
- }
- const duration = Duration.fromObject(results, opts);
- if (lowerOrderUnits.length > 0) {
- return Duration.fromMillis(remainingMillis, opts)
- .shiftTo(...lowerOrderUnits)
- .plus(duration);
- } else {
- return duration;
- }
- }
- const numberingSystems = {
- arab: "[\u0660-\u0669]",
- arabext: "[\u06F0-\u06F9]",
- bali: "[\u1B50-\u1B59]",
- beng: "[\u09E6-\u09EF]",
- deva: "[\u0966-\u096F]",
- fullwide: "[\uFF10-\uFF19]",
- gujr: "[\u0AE6-\u0AEF]",
- hanidec: "[〇|一|二|三|四|五|六|七|八|九]",
- khmr: "[\u17E0-\u17E9]",
- knda: "[\u0CE6-\u0CEF]",
- laoo: "[\u0ED0-\u0ED9]",
- limb: "[\u1946-\u194F]",
- mlym: "[\u0D66-\u0D6F]",
- mong: "[\u1810-\u1819]",
- mymr: "[\u1040-\u1049]",
- orya: "[\u0B66-\u0B6F]",
- tamldec: "[\u0BE6-\u0BEF]",
- telu: "[\u0C66-\u0C6F]",
- thai: "[\u0E50-\u0E59]",
- tibt: "[\u0F20-\u0F29]",
- latn: "\\d",
- };
- const numberingSystemsUTF16 = {
- arab: [1632, 1641],
- arabext: [1776, 1785],
- bali: [6992, 7001],
- beng: [2534, 2543],
- deva: [2406, 2415],
- fullwide: [65296, 65303],
- gujr: [2790, 2799],
- khmr: [6112, 6121],
- knda: [3302, 3311],
- laoo: [3792, 3801],
- limb: [6470, 6479],
- mlym: [3430, 3439],
- mong: [6160, 6169],
- mymr: [4160, 4169],
- orya: [2918, 2927],
- tamldec: [3046, 3055],
- telu: [3174, 3183],
- thai: [3664, 3673],
- tibt: [3872, 3881],
- };
- const hanidecChars = numberingSystems.hanidec.replace(/[\[|\]]/g, "").split("");
- function parseDigits(str) {
- let value = parseInt(str, 10);
- if (isNaN(value)) {
- value = "";
- for (let i = 0; i < str.length; i++) {
- const code = str.charCodeAt(i);
- if (str[i].search(numberingSystems.hanidec) !== -1) {
- value += hanidecChars.indexOf(str[i]);
- } else {
- for (const key in numberingSystemsUTF16) {
- const [min, max] = numberingSystemsUTF16[key];
- if (code >= min && code <= max) {
- value += code - min;
- }
- }
- }
- }
- return parseInt(value, 10);
- } else {
- return value;
- }
- }
- function digitRegex({ numberingSystem }, append = "") {
- return new RegExp(`${numberingSystems[numberingSystem || "latn"]}${append}`);
- }
- const MISSING_FTP = "missing Intl.DateTimeFormat.formatToParts support";
- function intUnit(regex, post = (i) => i) {
- return { regex, deser: ([s]) => post(parseDigits(s)) };
- }
- const NBSP = String.fromCharCode(160);
- const spaceOrNBSP = `[ ${NBSP}]`;
- const spaceOrNBSPRegExp = new RegExp(spaceOrNBSP, "g");
- function fixListRegex(s) {
-
-
- return s.replace(/\./g, "\\.?").replace(spaceOrNBSPRegExp, spaceOrNBSP);
- }
- function stripInsensitivities(s) {
- return s
- .replace(/\./g, "")
- .replace(spaceOrNBSPRegExp, " ")
- .toLowerCase();
- }
- function oneOf(strings, startIndex) {
- if (strings === null) {
- return null;
- } else {
- return {
- regex: RegExp(strings.map(fixListRegex).join("|")),
- deser: ([s]) =>
- strings.findIndex((i) => stripInsensitivities(s) === stripInsensitivities(i)) + startIndex,
- };
- }
- }
- function offset(regex, groups) {
- return { regex, deser: ([, h, m]) => signedOffset(h, m), groups };
- }
- function simple(regex) {
- return { regex, deser: ([s]) => s };
- }
- function escapeToken(value) {
- return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
- }
- function unitForToken(token, loc) {
- const one = digitRegex(loc),
- two = digitRegex(loc, "{2}"),
- three = digitRegex(loc, "{3}"),
- four = digitRegex(loc, "{4}"),
- six = digitRegex(loc, "{6}"),
- oneOrTwo = digitRegex(loc, "{1,2}"),
- oneToThree = digitRegex(loc, "{1,3}"),
- oneToSix = digitRegex(loc, "{1,6}"),
- oneToNine = digitRegex(loc, "{1,9}"),
- twoToFour = digitRegex(loc, "{2,4}"),
- fourToSix = digitRegex(loc, "{4,6}"),
- literal = (t) => ({ regex: RegExp(escapeToken(t.val)), deser: ([s]) => s, literal: true }),
- unitate = (t) => {
- if (token.literal) {
- return literal(t);
- }
- switch (t.val) {
-
- case "G":
- return oneOf(loc.eras("short"), 0);
- case "GG":
- return oneOf(loc.eras("long"), 0);
-
- case "y":
- return intUnit(oneToSix);
- case "yy":
- return intUnit(twoToFour, untruncateYear);
- case "yyyy":
- return intUnit(four);
- case "yyyyy":
- return intUnit(fourToSix);
- case "yyyyyy":
- return intUnit(six);
-
- case "M":
- return intUnit(oneOrTwo);
- case "MM":
- return intUnit(two);
- case "MMM":
- return oneOf(loc.months("short", true), 1);
- case "MMMM":
- return oneOf(loc.months("long", true), 1);
- case "L":
- return intUnit(oneOrTwo);
- case "LL":
- return intUnit(two);
- case "LLL":
- return oneOf(loc.months("short", false), 1);
- case "LLLL":
- return oneOf(loc.months("long", false), 1);
-
- case "d":
- return intUnit(oneOrTwo);
- case "dd":
- return intUnit(two);
-
- case "o":
- return intUnit(oneToThree);
- case "ooo":
- return intUnit(three);
-
- case "HH":
- return intUnit(two);
- case "H":
- return intUnit(oneOrTwo);
- case "hh":
- return intUnit(two);
- case "h":
- return intUnit(oneOrTwo);
- case "mm":
- return intUnit(two);
- case "m":
- return intUnit(oneOrTwo);
- case "q":
- return intUnit(oneOrTwo);
- case "qq":
- return intUnit(two);
- case "s":
- return intUnit(oneOrTwo);
- case "ss":
- return intUnit(two);
- case "S":
- return intUnit(oneToThree);
- case "SSS":
- return intUnit(three);
- case "u":
- return simple(oneToNine);
- case "uu":
- return simple(oneOrTwo);
- case "uuu":
- return intUnit(one);
-
- case "a":
- return oneOf(loc.meridiems(), 0);
-
- case "kkkk":
- return intUnit(four);
- case "kk":
- return intUnit(twoToFour, untruncateYear);
-
- case "W":
- return intUnit(oneOrTwo);
- case "WW":
- return intUnit(two);
-
- case "E":
- case "c":
- return intUnit(one);
- case "EEE":
- return oneOf(loc.weekdays("short", false), 1);
- case "EEEE":
- return oneOf(loc.weekdays("long", false), 1);
- case "ccc":
- return oneOf(loc.weekdays("short", true), 1);
- case "cccc":
- return oneOf(loc.weekdays("long", true), 1);
-
- case "Z":
- case "ZZ":
- return offset(new RegExp(`([+-]${oneOrTwo.source})(?::(${two.source}))?`), 2);
- case "ZZZ":
- return offset(new RegExp(`([+-]${oneOrTwo.source})(${two.source})?`), 2);
-
-
- case "z":
- return simple(/[a-z_+-/]{1,256}?/i);
-
-
- case " ":
- return simple(/[^\S\n\r]/);
- default:
- return literal(t);
- }
- };
- const unit = unitate(token) || {
- invalidReason: MISSING_FTP,
- };
- unit.token = token;
- return unit;
- }
- const partTypeStyleToTokenVal = {
- year: {
- "2-digit": "yy",
- numeric: "yyyyy",
- },
- month: {
- numeric: "M",
- "2-digit": "MM",
- short: "MMM",
- long: "MMMM",
- },
- day: {
- numeric: "d",
- "2-digit": "dd",
- },
- weekday: {
- short: "EEE",
- long: "EEEE",
- },
- dayperiod: "a",
- dayPeriod: "a",
- hour12: {
- numeric: "h",
- "2-digit": "hh",
- },
- hour24: {
- numeric: "H",
- "2-digit": "HH",
- },
- minute: {
- numeric: "m",
- "2-digit": "mm",
- },
- second: {
- numeric: "s",
- "2-digit": "ss",
- },
- timeZoneName: {
- long: "ZZZZZ",
- short: "ZZZ",
- },
- };
- function tokenForPart(part, formatOpts, resolvedOpts) {
- const { type, value } = part;
- if (type === "literal") {
- const isSpace = /^\s+$/.test(value);
- return {
- literal: !isSpace,
- val: isSpace ? " " : value,
- };
- }
- const style = formatOpts[type];
-
-
-
- let actualType = type;
- if (type === "hour") {
- if (formatOpts.hour12 != null) {
- actualType = formatOpts.hour12 ? "hour12" : "hour24";
- } else if (formatOpts.hourCycle != null) {
- if (formatOpts.hourCycle === "h11" || formatOpts.hourCycle === "h12") {
- actualType = "hour12";
- } else {
- actualType = "hour24";
- }
- } else {
-
-
- actualType = resolvedOpts.hour12 ? "hour12" : "hour24";
- }
- }
- let val = partTypeStyleToTokenVal[actualType];
- if (typeof val === "object") {
- val = val[style];
- }
- if (val) {
- return {
- literal: false,
- val,
- };
- }
- return undefined;
- }
- function buildRegex(units) {
- const re = units.map((u) => u.regex).reduce((f, r) => `${f}(${r.source})`, "");
- return [`^${re}$`, units];
- }
- function match(input, regex, handlers) {
- const matches = input.match(regex);
- if (matches) {
- const all = {};
- let matchIndex = 1;
- for (const i in handlers) {
- if (hasOwnProperty(handlers, i)) {
- const h = handlers[i],
- groups = h.groups ? h.groups + 1 : 1;
- if (!h.literal && h.token) {
- all[h.token.val[0]] = h.deser(matches.slice(matchIndex, matchIndex + groups));
- }
- matchIndex += groups;
- }
- }
- return [matches, all];
- } else {
- return [matches, {}];
- }
- }
- function dateTimeFromMatches(matches) {
- const toField = (token) => {
- switch (token) {
- case "S":
- return "millisecond";
- case "s":
- return "second";
- case "m":
- return "minute";
- case "h":
- case "H":
- return "hour";
- case "d":
- return "day";
- case "o":
- return "ordinal";
- case "L":
- case "M":
- return "month";
- case "y":
- return "year";
- case "E":
- case "c":
- return "weekday";
- case "W":
- return "weekNumber";
- case "k":
- return "weekYear";
- case "q":
- return "quarter";
- default:
- return null;
- }
- };
- let zone = null;
- let specificOffset;
- if (!isUndefined(matches.z)) {
- zone = IANAZone.create(matches.z);
- }
- if (!isUndefined(matches.Z)) {
- if (!zone) {
- zone = new FixedOffsetZone(matches.Z);
- }
- specificOffset = matches.Z;
- }
- if (!isUndefined(matches.q)) {
- matches.M = (matches.q - 1) * 3 + 1;
- }
- if (!isUndefined(matches.h)) {
- if (matches.h < 12 && matches.a === 1) {
- matches.h += 12;
- } else if (matches.h === 12 && matches.a === 0) {
- matches.h = 0;
- }
- }
- if (matches.G === 0 && matches.y) {
- matches.y = -matches.y;
- }
- if (!isUndefined(matches.u)) {
- matches.S = parseMillis(matches.u);
- }
- const vals = Object.keys(matches).reduce((r, k) => {
- const f = toField(k);
- if (f) {
- r[f] = matches[k];
- }
- return r;
- }, {});
- return [vals, zone, specificOffset];
- }
- let dummyDateTimeCache = null;
- function getDummyDateTime() {
- if (!dummyDateTimeCache) {
- dummyDateTimeCache = DateTime.fromMillis(1555555555555);
- }
- return dummyDateTimeCache;
- }
- function maybeExpandMacroToken(token, locale) {
- if (token.literal) {
- return token;
- }
- const formatOpts = Formatter.macroTokenToFormatOpts(token.val);
- const tokens = formatOptsToTokens(formatOpts, locale);
- if (tokens == null || tokens.includes(undefined)) {
- return token;
- }
- return tokens;
- }
- function expandMacroTokens(tokens, locale) {
- return Array.prototype.concat(...tokens.map((t) => maybeExpandMacroToken(t, locale)));
- }
- function explainFromTokens(locale, input, format) {
- const tokens = expandMacroTokens(Formatter.parseFormat(format), locale),
- units = tokens.map((t) => unitForToken(t, locale)),
- disqualifyingUnit = units.find((t) => t.invalidReason);
- if (disqualifyingUnit) {
- return { input, tokens, invalidReason: disqualifyingUnit.invalidReason };
- } else {
- const [regexString, handlers] = buildRegex(units),
- regex = RegExp(regexString, "i"),
- [rawMatches, matches] = match(input, regex, handlers),
- [result, zone, specificOffset] = matches
- ? dateTimeFromMatches(matches)
- : [null, null, undefined];
- if (hasOwnProperty(matches, "a") && hasOwnProperty(matches, "H")) {
- throw new ConflictingSpecificationError(
- "Can't include meridiem when specifying 24-hour format"
- );
- }
- return { input, tokens, regex, rawMatches, matches, result, zone, specificOffset };
- }
- }
- function parseFromTokens(locale, input, format) {
- const { result, zone, specificOffset, invalidReason } = explainFromTokens(locale, input, format);
- return [result, zone, specificOffset, invalidReason];
- }
- function formatOptsToTokens(formatOpts, locale) {
- if (!formatOpts) {
- return null;
- }
- const formatter = Formatter.create(locale, formatOpts);
- const df = formatter.dtFormatter(getDummyDateTime());
- const parts = df.formatToParts();
- const resolvedOpts = df.resolvedOptions();
- return parts.map((p) => tokenForPart(p, formatOpts, resolvedOpts));
- }
- const nonLeapLadder = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
- leapLadder = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335];
- function unitOutOfRange(unit, value) {
- return new Invalid(
- "unit out of range",
- `you specified ${value} (of type ${typeof value}) as a ${unit}, which is invalid`
- );
- }
- function dayOfWeek(year, month, day) {
- const d = new Date(Date.UTC(year, month - 1, day));
- if (year < 100 && year >= 0) {
- d.setUTCFullYear(d.getUTCFullYear() - 1900);
- }
- const js = d.getUTCDay();
- return js === 0 ? 7 : js;
- }
- function computeOrdinal(year, month, day) {
- return day + (isLeapYear(year) ? leapLadder : nonLeapLadder)[month - 1];
- }
- function uncomputeOrdinal(year, ordinal) {
- const table = isLeapYear(year) ? leapLadder : nonLeapLadder,
- month0 = table.findIndex((i) => i < ordinal),
- day = ordinal - table[month0];
- return { month: month0 + 1, day };
- }
- function gregorianToWeek(gregObj) {
- const { year, month, day } = gregObj,
- ordinal = computeOrdinal(year, month, day),
- weekday = dayOfWeek(year, month, day);
- let weekNumber = Math.floor((ordinal - weekday + 10) / 7),
- weekYear;
- if (weekNumber < 1) {
- weekYear = year - 1;
- weekNumber = weeksInWeekYear(weekYear);
- } else if (weekNumber > weeksInWeekYear(year)) {
- weekYear = year + 1;
- weekNumber = 1;
- } else {
- weekYear = year;
- }
- return { weekYear, weekNumber, weekday, ...timeObject(gregObj) };
- }
- function weekToGregorian(weekData) {
- const { weekYear, weekNumber, weekday } = weekData,
- weekdayOfJan4 = dayOfWeek(weekYear, 1, 4),
- yearInDays = daysInYear(weekYear);
- let ordinal = weekNumber * 7 + weekday - weekdayOfJan4 - 3,
- year;
- if (ordinal < 1) {
- year = weekYear - 1;
- ordinal += daysInYear(year);
- } else if (ordinal > yearInDays) {
- year = weekYear + 1;
- ordinal -= daysInYear(weekYear);
- } else {
- year = weekYear;
- }
- const { month, day } = uncomputeOrdinal(year, ordinal);
- return { year, month, day, ...timeObject(weekData) };
- }
- function gregorianToOrdinal(gregData) {
- const { year, month, day } = gregData;
- const ordinal = computeOrdinal(year, month, day);
- return { year, ordinal, ...timeObject(gregData) };
- }
- function ordinalToGregorian(ordinalData) {
- const { year, ordinal } = ordinalData;
- const { month, day } = uncomputeOrdinal(year, ordinal);
- return { year, month, day, ...timeObject(ordinalData) };
- }
- function hasInvalidWeekData(obj) {
- const validYear = isInteger(obj.weekYear),
- validWeek = integerBetween(obj.weekNumber, 1, weeksInWeekYear(obj.weekYear)),
- validWeekday = integerBetween(obj.weekday, 1, 7);
- if (!validYear) {
- return unitOutOfRange("weekYear", obj.weekYear);
- } else if (!validWeek) {
- return unitOutOfRange("week", obj.week);
- } else if (!validWeekday) {
- return unitOutOfRange("weekday", obj.weekday);
- } else return false;
- }
- function hasInvalidOrdinalData(obj) {
- const validYear = isInteger(obj.year),
- validOrdinal = integerBetween(obj.ordinal, 1, daysInYear(obj.year));
- if (!validYear) {
- return unitOutOfRange("year", obj.year);
- } else if (!validOrdinal) {
- return unitOutOfRange("ordinal", obj.ordinal);
- } else return false;
- }
- function hasInvalidGregorianData(obj) {
- const validYear = isInteger(obj.year),
- validMonth = integerBetween(obj.month, 1, 12),
- validDay = integerBetween(obj.day, 1, daysInMonth(obj.year, obj.month));
- if (!validYear) {
- return unitOutOfRange("year", obj.year);
- } else if (!validMonth) {
- return unitOutOfRange("month", obj.month);
- } else if (!validDay) {
- return unitOutOfRange("day", obj.day);
- } else return false;
- }
- function hasInvalidTimeData(obj) {
- const { hour, minute, second, millisecond } = obj;
- const validHour =
- integerBetween(hour, 0, 23) ||
- (hour === 24 && minute === 0 && second === 0 && millisecond === 0),
- validMinute = integerBetween(minute, 0, 59),
- validSecond = integerBetween(second, 0, 59),
- validMillisecond = integerBetween(millisecond, 0, 999);
- if (!validHour) {
- return unitOutOfRange("hour", hour);
- } else if (!validMinute) {
- return unitOutOfRange("minute", minute);
- } else if (!validSecond) {
- return unitOutOfRange("second", second);
- } else if (!validMillisecond) {
- return unitOutOfRange("millisecond", millisecond);
- } else return false;
- }
- const INVALID = "Invalid DateTime";
- const MAX_DATE = 8.64e15;
- function unsupportedZone(zone) {
- return new Invalid("unsupported zone", `the zone "${zone.name}" is not supported`);
- }
- function possiblyCachedWeekData(dt) {
- if (dt.weekData === null) {
- dt.weekData = gregorianToWeek(dt.c);
- }
- return dt.weekData;
- }
- function clone(inst, alts) {
- const current = {
- ts: inst.ts,
- zone: inst.zone,
- c: inst.c,
- o: inst.o,
- loc: inst.loc,
- invalid: inst.invalid,
- };
- return new DateTime({ ...current, ...alts, old: current });
- }
- function fixOffset(localTS, o, tz) {
-
- let utcGuess = localTS - o * 60 * 1000;
-
- const o2 = tz.offset(utcGuess);
-
- if (o === o2) {
- return [utcGuess, o];
- }
-
- utcGuess -= (o2 - o) * 60 * 1000;
-
- const o3 = tz.offset(utcGuess);
- if (o2 === o3) {
- return [utcGuess, o2];
- }
-
- return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)];
- }
- function tsToObj(ts, offset) {
- ts += offset * 60 * 1000;
- const d = new Date(ts);
- return {
- year: d.getUTCFullYear(),
- month: d.getUTCMonth() + 1,
- day: d.getUTCDate(),
- hour: d.getUTCHours(),
- minute: d.getUTCMinutes(),
- second: d.getUTCSeconds(),
- millisecond: d.getUTCMilliseconds(),
- };
- }
- function objToTS(obj, offset, zone) {
- return fixOffset(objToLocalTS(obj), offset, zone);
- }
- function adjustTime(inst, dur) {
- const oPre = inst.o,
- year = inst.c.year + Math.trunc(dur.years),
- month = inst.c.month + Math.trunc(dur.months) + Math.trunc(dur.quarters) * 3,
- c = {
- ...inst.c,
- year,
- month,
- day:
- Math.min(inst.c.day, daysInMonth(year, month)) +
- Math.trunc(dur.days) +
- Math.trunc(dur.weeks) * 7,
- },
- millisToAdd = Duration.fromObject({
- years: dur.years - Math.trunc(dur.years),
- quarters: dur.quarters - Math.trunc(dur.quarters),
- months: dur.months - Math.trunc(dur.months),
- weeks: dur.weeks - Math.trunc(dur.weeks),
- days: dur.days - Math.trunc(dur.days),
- hours: dur.hours,
- minutes: dur.minutes,
- seconds: dur.seconds,
- milliseconds: dur.milliseconds,
- }).as("milliseconds"),
- localTS = objToLocalTS(c);
- let [ts, o] = fixOffset(localTS, oPre, inst.zone);
- if (millisToAdd !== 0) {
- ts += millisToAdd;
-
- o = inst.zone.offset(ts);
- }
- return { ts, o };
- }
- function parseDataToDateTime(parsed, parsedZone, opts, format, text, specificOffset) {
- const { setZone, zone } = opts;
- if ((parsed && Object.keys(parsed).length !== 0) || parsedZone) {
- const interpretationZone = parsedZone || zone,
- inst = DateTime.fromObject(parsed, {
- ...opts,
- zone: interpretationZone,
- specificOffset,
- });
- return setZone ? inst : inst.setZone(zone);
- } else {
- return DateTime.invalid(
- new Invalid("unparsable", `the input "${text}" can't be parsed as ${format}`)
- );
- }
- }
- function toTechFormat(dt, format, allowZ = true) {
- return dt.isValid
- ? Formatter.create(Locale.create("en-US"), {
- allowZ,
- forceSimple: true,
- }).formatDateTimeFromString(dt, format)
- : null;
- }
- function toISODate(o, extended) {
- const longFormat = o.c.year > 9999 || o.c.year < 0;
- let c = "";
- if (longFormat && o.c.year >= 0) c += "+";
- c += padStart(o.c.year, longFormat ? 6 : 4);
- if (extended) {
- c += "-";
- c += padStart(o.c.month);
- c += "-";
- c += padStart(o.c.day);
- } else {
- c += padStart(o.c.month);
- c += padStart(o.c.day);
- }
- return c;
- }
- function toISOTime(
- o,
- extended,
- suppressSeconds,
- suppressMilliseconds,
- includeOffset,
- extendedZone
- ) {
- let c = padStart(o.c.hour);
- if (extended) {
- c += ":";
- c += padStart(o.c.minute);
- if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) {
- c += ":";
- }
- } else {
- c += padStart(o.c.minute);
- }
- if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) {
- c += padStart(o.c.second);
- if (o.c.millisecond !== 0 || !suppressMilliseconds) {
- c += ".";
- c += padStart(o.c.millisecond, 3);
- }
- }
- if (includeOffset) {
- if (o.isOffsetFixed && o.offset === 0 && !extendedZone) {
- c += "Z";
- } else if (o.o < 0) {
- c += "-";
- c += padStart(Math.trunc(-o.o / 60));
- c += ":";
- c += padStart(Math.trunc(-o.o % 60));
- } else {
- c += "+";
- c += padStart(Math.trunc(o.o / 60));
- c += ":";
- c += padStart(Math.trunc(o.o % 60));
- }
- }
- if (extendedZone) {
- c += "[" + o.zone.ianaName + "]";
- }
- return c;
- }
- const defaultUnitValues = {
- month: 1,
- day: 1,
- hour: 0,
- minute: 0,
- second: 0,
- millisecond: 0,
- },
- defaultWeekUnitValues = {
- weekNumber: 1,
- weekday: 1,
- hour: 0,
- minute: 0,
- second: 0,
- millisecond: 0,
- },
- defaultOrdinalUnitValues = {
- ordinal: 1,
- hour: 0,
- minute: 0,
- second: 0,
- millisecond: 0,
- };
- const orderedUnits = ["year", "month", "day", "hour", "minute", "second", "millisecond"],
- orderedWeekUnits = [
- "weekYear",
- "weekNumber",
- "weekday",
- "hour",
- "minute",
- "second",
- "millisecond",
- ],
- orderedOrdinalUnits = ["year", "ordinal", "hour", "minute", "second", "millisecond"];
- function normalizeUnit(unit) {
- const normalized = {
- year: "year",
- years: "year",
- month: "month",
- months: "month",
- day: "day",
- days: "day",
- hour: "hour",
- hours: "hour",
- minute: "minute",
- minutes: "minute",
- quarter: "quarter",
- quarters: "quarter",
- second: "second",
- seconds: "second",
- millisecond: "millisecond",
- milliseconds: "millisecond",
- weekday: "weekday",
- weekdays: "weekday",
- weeknumber: "weekNumber",
- weeksnumber: "weekNumber",
- weeknumbers: "weekNumber",
- weekyear: "weekYear",
- weekyears: "weekYear",
- ordinal: "ordinal",
- }[unit.toLowerCase()];
- if (!normalized) throw new InvalidUnitError(unit);
- return normalized;
- }
- function quickDT(obj, opts) {
- const zone = normalizeZone(opts.zone, Settings.defaultZone),
- loc = Locale.fromObject(opts),
- tsNow = Settings.now();
- let ts, o;
-
- if (!isUndefined(obj.year)) {
- for (const u of orderedUnits) {
- if (isUndefined(obj[u])) {
- obj[u] = defaultUnitValues[u];
- }
- }
- const invalid = hasInvalidGregorianData(obj) || hasInvalidTimeData(obj);
- if (invalid) {
- return DateTime.invalid(invalid);
- }
- const offsetProvis = zone.offset(tsNow);
- [ts, o] = objToTS(obj, offsetProvis, zone);
- } else {
- ts = tsNow;
- }
- return new DateTime({ ts, zone, loc, o });
- }
- function diffRelative(start, end, opts) {
- const round = isUndefined(opts.round) ? true : opts.round,
- format = (c, unit) => {
- c = roundTo(c, round || opts.calendary ? 0 : 2, true);
- const formatter = end.loc.clone(opts).relFormatter(opts);
- return formatter.format(c, unit);
- },
- differ = (unit) => {
- if (opts.calendary) {
- if (!end.hasSame(start, unit)) {
- return end.startOf(unit).diff(start.startOf(unit), unit).get(unit);
- } else return 0;
- } else {
- return end.diff(start, unit).get(unit);
- }
- };
- if (opts.unit) {
- return format(differ(opts.unit), opts.unit);
- }
- for (const unit of opts.units) {
- const count = differ(unit);
- if (Math.abs(count) >= 1) {
- return format(count, unit);
- }
- }
- return format(start > end ? -0 : 0, opts.units[opts.units.length - 1]);
- }
- function lastOpts(argList) {
- let opts = {},
- args;
- if (argList.length > 0 && typeof argList[argList.length - 1] === "object") {
- opts = argList[argList.length - 1];
- args = Array.from(argList).slice(0, argList.length - 1);
- } else {
- args = Array.from(argList);
- }
- return [opts, args];
- }
- class DateTime {
-
- constructor(config) {
- const zone = config.zone || Settings.defaultZone;
- let invalid =
- config.invalid ||
- (Number.isNaN(config.ts) ? new Invalid("invalid input") : null) ||
- (!zone.isValid ? unsupportedZone(zone) : null);
-
- this.ts = isUndefined(config.ts) ? Settings.now() : config.ts;
- let c = null,
- o = null;
- if (!invalid) {
- const unchanged = config.old && config.old.ts === this.ts && config.old.zone.equals(zone);
- if (unchanged) {
- [c, o] = [config.old.c, config.old.o];
- } else {
- const ot = zone.offset(this.ts);
- c = tsToObj(this.ts, ot);
- invalid = Number.isNaN(c.year) ? new Invalid("invalid input") : null;
- c = invalid ? null : c;
- o = invalid ? null : ot;
- }
- }
-
- this._zone = zone;
-
- this.loc = config.loc || Locale.create();
-
- this.invalid = invalid;
-
- this.weekData = null;
-
- this.c = c;
-
- this.o = o;
-
- this.isLuxonDateTime = true;
- }
-
-
- static now() {
- return new DateTime({});
- }
-
- static local() {
- const [opts, args] = lastOpts(arguments),
- [year, month, day, hour, minute, second, millisecond] = args;
- return quickDT({ year, month, day, hour, minute, second, millisecond }, opts);
- }
-
- static utc() {
- const [opts, args] = lastOpts(arguments),
- [year, month, day, hour, minute, second, millisecond] = args;
- opts.zone = FixedOffsetZone.utcInstance;
- return quickDT({ year, month, day, hour, minute, second, millisecond }, opts);
- }
-
- static fromJSDate(date, options = {}) {
- const ts = isDate(date) ? date.valueOf() : NaN;
- if (Number.isNaN(ts)) {
- return DateTime.invalid("invalid input");
- }
- const zoneToUse = normalizeZone(options.zone, Settings.defaultZone);
- if (!zoneToUse.isValid) {
- return DateTime.invalid(unsupportedZone(zoneToUse));
- }
- return new DateTime({
- ts: ts,
- zone: zoneToUse,
- loc: Locale.fromObject(options),
- });
- }
-
- static fromMillis(milliseconds, options = {}) {
- if (!isNumber(milliseconds)) {
- throw new InvalidArgumentError(
- `fromMillis requires a numerical input, but received a ${typeof milliseconds} with value ${milliseconds}`
- );
- } else if (milliseconds < -MAX_DATE || milliseconds > MAX_DATE) {
-
- return DateTime.invalid("Timestamp out of range");
- } else {
- return new DateTime({
- ts: milliseconds,
- zone: normalizeZone(options.zone, Settings.defaultZone),
- loc: Locale.fromObject(options),
- });
- }
- }
-
- static fromSeconds(seconds, options = {}) {
- if (!isNumber(seconds)) {
- throw new InvalidArgumentError("fromSeconds requires a numerical input");
- } else {
- return new DateTime({
- ts: seconds * 1000,
- zone: normalizeZone(options.zone, Settings.defaultZone),
- loc: Locale.fromObject(options),
- });
- }
- }
-
- static fromObject(obj, opts = {}) {
- obj = obj || {};
- const zoneToUse = normalizeZone(opts.zone, Settings.defaultZone);
- if (!zoneToUse.isValid) {
- return DateTime.invalid(unsupportedZone(zoneToUse));
- }
- const tsNow = Settings.now(),
- offsetProvis = !isUndefined(opts.specificOffset)
- ? opts.specificOffset
- : zoneToUse.offset(tsNow),
- normalized = normalizeObject(obj, normalizeUnit),
- containsOrdinal = !isUndefined(normalized.ordinal),
- containsGregorYear = !isUndefined(normalized.year),
- containsGregorMD = !isUndefined(normalized.month) || !isUndefined(normalized.day),
- containsGregor = containsGregorYear || containsGregorMD,
- definiteWeekDef = normalized.weekYear || normalized.weekNumber,
- loc = Locale.fromObject(opts);
-
-
-
-
-
- if ((containsGregor || containsOrdinal) && definiteWeekDef) {
- throw new ConflictingSpecificationError(
- "Can't mix weekYear/weekNumber units with year/month/day or ordinals"
- );
- }
- if (containsGregorMD && containsOrdinal) {
- throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day");
- }
- const useWeekData = definiteWeekDef || (normalized.weekday && !containsGregor);
-
- let units,
- defaultValues,
- objNow = tsToObj(tsNow, offsetProvis);
- if (useWeekData) {
- units = orderedWeekUnits;
- defaultValues = defaultWeekUnitValues;
- objNow = gregorianToWeek(objNow);
- } else if (containsOrdinal) {
- units = orderedOrdinalUnits;
- defaultValues = defaultOrdinalUnitValues;
- objNow = gregorianToOrdinal(objNow);
- } else {
- units = orderedUnits;
- defaultValues = defaultUnitValues;
- }
-
- let foundFirst = false;
- for (const u of units) {
- const v = normalized[u];
- if (!isUndefined(v)) {
- foundFirst = true;
- } else if (foundFirst) {
- normalized[u] = defaultValues[u];
- } else {
- normalized[u] = objNow[u];
- }
- }
-
- const higherOrderInvalid = useWeekData
- ? hasInvalidWeekData(normalized)
- : containsOrdinal
- ? hasInvalidOrdinalData(normalized)
- : hasInvalidGregorianData(normalized),
- invalid = higherOrderInvalid || hasInvalidTimeData(normalized);
- if (invalid) {
- return DateTime.invalid(invalid);
- }
-
- const gregorian = useWeekData
- ? weekToGregorian(normalized)
- : containsOrdinal
- ? ordinalToGregorian(normalized)
- : normalized,
- [tsFinal, offsetFinal] = objToTS(gregorian, offsetProvis, zoneToUse),
- inst = new DateTime({
- ts: tsFinal,
- zone: zoneToUse,
- o: offsetFinal,
- loc,
- });
-
- if (normalized.weekday && containsGregor && obj.weekday !== inst.weekday) {
- return DateTime.invalid(
- "mismatched weekday",
- `you can't specify both a weekday of ${normalized.weekday} and a date of ${inst.toISO()}`
- );
- }
- return inst;
- }
-
- static fromISO(text, opts = {}) {
- const [vals, parsedZone] = parseISODate(text);
- return parseDataToDateTime(vals, parsedZone, opts, "ISO 8601", text);
- }
-
- static fromRFC2822(text, opts = {}) {
- const [vals, parsedZone] = parseRFC2822Date(text);
- return parseDataToDateTime(vals, parsedZone, opts, "RFC 2822", text);
- }
-
- static fromHTTP(text, opts = {}) {
- const [vals, parsedZone] = parseHTTPDate(text);
- return parseDataToDateTime(vals, parsedZone, opts, "HTTP", opts);
- }
-
- static fromFormat(text, fmt, opts = {}) {
- if (isUndefined(text) || isUndefined(fmt)) {
- throw new InvalidArgumentError("fromFormat requires an input string and a format");
- }
- const { locale = null, numberingSystem = null } = opts,
- localeToUse = Locale.fromOpts({
- locale,
- numberingSystem,
- defaultToEN: true,
- }),
- [vals, parsedZone, specificOffset, invalid] = parseFromTokens(localeToUse, text, fmt);
- if (invalid) {
- return DateTime.invalid(invalid);
- } else {
- return parseDataToDateTime(vals, parsedZone, opts, `format ${fmt}`, text, specificOffset);
- }
- }
-
- static fromString(text, fmt, opts = {}) {
- return DateTime.fromFormat(text, fmt, opts);
- }
-
- static fromSQL(text, opts = {}) {
- const [vals, parsedZone] = parseSQL(text);
- return parseDataToDateTime(vals, parsedZone, opts, "SQL", text);
- }
-
- static invalid(reason, explanation = null) {
- if (!reason) {
- throw new InvalidArgumentError("need to specify a reason the DateTime is invalid");
- }
- const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
- if (Settings.throwOnInvalid) {
- throw new InvalidDateTimeError(invalid);
- } else {
- return new DateTime({ invalid });
- }
- }
-
- static isDateTime(o) {
- return (o && o.isLuxonDateTime) || false;
- }
-
- static parseFormatForOpts(formatOpts, localeOpts = {}) {
- const tokenList = formatOptsToTokens(formatOpts, Locale.fromObject(localeOpts));
- return !tokenList ? null : tokenList.map((t) => (t ? t.val : null)).join("");
- }
-
- static expandFormat(fmt, localeOpts = {}) {
- const expanded = expandMacroTokens(Formatter.parseFormat(fmt), Locale.fromObject(localeOpts));
- return expanded.map((t) => t.val).join("");
- }
-
-
- get(unit) {
- return this[unit];
- }
-
- get isValid() {
- return this.invalid === null;
- }
-
- get invalidReason() {
- return this.invalid ? this.invalid.reason : null;
- }
-
- get invalidExplanation() {
- return this.invalid ? this.invalid.explanation : null;
- }
-
- get locale() {
- return this.isValid ? this.loc.locale : null;
- }
-
- get numberingSystem() {
- return this.isValid ? this.loc.numberingSystem : null;
- }
-
- get outputCalendar() {
- return this.isValid ? this.loc.outputCalendar : null;
- }
-
- get zone() {
- return this._zone;
- }
-
- get zoneName() {
- return this.isValid ? this.zone.name : null;
- }
-
- get year() {
- return this.isValid ? this.c.year : NaN;
- }
-
- get quarter() {
- return this.isValid ? Math.ceil(this.c.month / 3) : NaN;
- }
-
- get month() {
- return this.isValid ? this.c.month : NaN;
- }
-
- get day() {
- return this.isValid ? this.c.day : NaN;
- }
-
- get hour() {
- return this.isValid ? this.c.hour : NaN;
- }
-
- get minute() {
- return this.isValid ? this.c.minute : NaN;
- }
-
- get second() {
- return this.isValid ? this.c.second : NaN;
- }
-
- get millisecond() {
- return this.isValid ? this.c.millisecond : NaN;
- }
-
- get weekYear() {
- return this.isValid ? possiblyCachedWeekData(this).weekYear : NaN;
- }
-
- get weekNumber() {
- return this.isValid ? possiblyCachedWeekData(this).weekNumber : NaN;
- }
-
- get weekday() {
- return this.isValid ? possiblyCachedWeekData(this).weekday : NaN;
- }
-
- get ordinal() {
- return this.isValid ? gregorianToOrdinal(this.c).ordinal : NaN;
- }
-
- get monthShort() {
- return this.isValid ? Info.months("short", { locObj: this.loc })[this.month - 1] : null;
- }
-
- get monthLong() {
- return this.isValid ? Info.months("long", { locObj: this.loc })[this.month - 1] : null;
- }
-
- get weekdayShort() {
- return this.isValid ? Info.weekdays("short", { locObj: this.loc })[this.weekday - 1] : null;
- }
-
- get weekdayLong() {
- return this.isValid ? Info.weekdays("long", { locObj: this.loc })[this.weekday - 1] : null;
- }
-
- get offset() {
- return this.isValid ? +this.o : NaN;
- }
-
- get offsetNameShort() {
- if (this.isValid) {
- return this.zone.offsetName(this.ts, {
- format: "short",
- locale: this.locale,
- });
- } else {
- return null;
- }
- }
-
- get offsetNameLong() {
- if (this.isValid) {
- return this.zone.offsetName(this.ts, {
- format: "long",
- locale: this.locale,
- });
- } else {
- return null;
- }
- }
-
- get isOffsetFixed() {
- return this.isValid ? this.zone.isUniversal : null;
- }
-
- get isInDST() {
- if (this.isOffsetFixed) {
- return false;
- } else {
- return (
- this.offset > this.set({ month: 1, day: 1 }).offset ||
- this.offset > this.set({ month: 5 }).offset
- );
- }
- }
-
- getPossibleOffsets() {
- if (!this.isValid || this.isOffsetFixed) {
- return [this];
- }
- const dayMs = 86400000;
- const minuteMs = 60000;
- const localTS = objToLocalTS(this.c);
- const oEarlier = this.zone.offset(localTS - dayMs);
- const oLater = this.zone.offset(localTS + dayMs);
- const o1 = this.zone.offset(localTS - oEarlier * minuteMs);
- const o2 = this.zone.offset(localTS - oLater * minuteMs);
- if (o1 === o2) {
- return [this];
- }
- const ts1 = localTS - o1 * minuteMs;
- const ts2 = localTS - o2 * minuteMs;
- const c1 = tsToObj(ts1, o1);
- const c2 = tsToObj(ts2, o2);
- if (
- c1.hour === c2.hour &&
- c1.minute === c2.minute &&
- c1.second === c2.second &&
- c1.millisecond === c2.millisecond
- ) {
- return [clone(this, { ts: ts1 }), clone(this, { ts: ts2 })];
- }
- return [this];
- }
-
- get isInLeapYear() {
- return isLeapYear(this.year);
- }
-
- get daysInMonth() {
- return daysInMonth(this.year, this.month);
- }
-
- get daysInYear() {
- return this.isValid ? daysInYear(this.year) : NaN;
- }
-
- get weeksInWeekYear() {
- return this.isValid ? weeksInWeekYear(this.weekYear) : NaN;
- }
-
- resolvedLocaleOptions(opts = {}) {
- const { locale, numberingSystem, calendar } = Formatter.create(
- this.loc.clone(opts),
- opts
- ).resolvedOptions(this);
- return { locale, numberingSystem, outputCalendar: calendar };
- }
-
-
- toUTC(offset = 0, opts = {}) {
- return this.setZone(FixedOffsetZone.instance(offset), opts);
- }
-
- toLocal() {
- return this.setZone(Settings.defaultZone);
- }
-
- setZone(zone, { keepLocalTime = false, keepCalendarTime = false } = {}) {
- zone = normalizeZone(zone, Settings.defaultZone);
- if (zone.equals(this.zone)) {
- return this;
- } else if (!zone.isValid) {
- return DateTime.invalid(unsupportedZone(zone));
- } else {
- let newTS = this.ts;
- if (keepLocalTime || keepCalendarTime) {
- const offsetGuess = zone.offset(this.ts);
- const asObj = this.toObject();
- [newTS] = objToTS(asObj, offsetGuess, zone);
- }
- return clone(this, { ts: newTS, zone });
- }
- }
-
- reconfigure({ locale, numberingSystem, outputCalendar } = {}) {
- const loc = this.loc.clone({ locale, numberingSystem, outputCalendar });
- return clone(this, { loc });
- }
-
- setLocale(locale) {
- return this.reconfigure({ locale });
- }
-
- set(values) {
- if (!this.isValid) return this;
- const normalized = normalizeObject(values, normalizeUnit),
- settingWeekStuff =
- !isUndefined(normalized.weekYear) ||
- !isUndefined(normalized.weekNumber) ||
- !isUndefined(normalized.weekday),
- containsOrdinal = !isUndefined(normalized.ordinal),
- containsGregorYear = !isUndefined(normalized.year),
- containsGregorMD = !isUndefined(normalized.month) || !isUndefined(normalized.day),
- containsGregor = containsGregorYear || containsGregorMD,
- definiteWeekDef = normalized.weekYear || normalized.weekNumber;
- if ((containsGregor || containsOrdinal) && definiteWeekDef) {
- throw new ConflictingSpecificationError(
- "Can't mix weekYear/weekNumber units with year/month/day or ordinals"
- );
- }
- if (containsGregorMD && containsOrdinal) {
- throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day");
- }
- let mixed;
- if (settingWeekStuff) {
- mixed = weekToGregorian({ ...gregorianToWeek(this.c), ...normalized });
- } else if (!isUndefined(normalized.ordinal)) {
- mixed = ordinalToGregorian({ ...gregorianToOrdinal(this.c), ...normalized });
- } else {
- mixed = { ...this.toObject(), ...normalized };
-
-
- if (isUndefined(normalized.day)) {
- mixed.day = Math.min(daysInMonth(mixed.year, mixed.month), mixed.day);
- }
- }
- const [ts, o] = objToTS(mixed, this.o, this.zone);
- return clone(this, { ts, o });
- }
-
- plus(duration) {
- if (!this.isValid) return this;
- const dur = Duration.fromDurationLike(duration);
- return clone(this, adjustTime(this, dur));
- }
-
- minus(duration) {
- if (!this.isValid) return this;
- const dur = Duration.fromDurationLike(duration).negate();
- return clone(this, adjustTime(this, dur));
- }
-
- startOf(unit) {
- if (!this.isValid) return this;
- const o = {},
- normalizedUnit = Duration.normalizeUnit(unit);
- switch (normalizedUnit) {
- case "years":
- o.month = 1;
-
- case "quarters":
- case "months":
- o.day = 1;
-
- case "weeks":
- case "days":
- o.hour = 0;
-
- case "hours":
- o.minute = 0;
-
- case "minutes":
- o.second = 0;
-
- case "seconds":
- o.millisecond = 0;
- break;
-
- }
- if (normalizedUnit === "weeks") {
- o.weekday = 1;
- }
- if (normalizedUnit === "quarters") {
- const q = Math.ceil(this.month / 3);
- o.month = (q - 1) * 3 + 1;
- }
- return this.set(o);
- }
-
- endOf(unit) {
- return this.isValid
- ? this.plus({ [unit]: 1 })
- .startOf(unit)
- .minus(1)
- : this;
- }
-
-
- toFormat(fmt, opts = {}) {
- return this.isValid
- ? Formatter.create(this.loc.redefaultToEN(opts)).formatDateTimeFromString(this, fmt)
- : INVALID;
- }
-
- toLocaleString(formatOpts = DATE_SHORT, opts = {}) {
- return this.isValid
- ? Formatter.create(this.loc.clone(opts), formatOpts).formatDateTime(this)
- : INVALID;
- }
-
- toLocaleParts(opts = {}) {
- return this.isValid
- ? Formatter.create(this.loc.clone(opts), opts).formatDateTimeParts(this)
- : [];
- }
-
- toISO({
- format = "extended",
- suppressSeconds = false,
- suppressMilliseconds = false,
- includeOffset = true,
- extendedZone = false,
- } = {}) {
- if (!this.isValid) {
- return null;
- }
- const ext = format === "extended";
- let c = toISODate(this, ext);
- c += "T";
- c += toISOTime(this, ext, suppressSeconds, suppressMilliseconds, includeOffset, extendedZone);
- return c;
- }
-
- toISODate({ format = "extended" } = {}) {
- if (!this.isValid) {
- return null;
- }
- return toISODate(this, format === "extended");
- }
-
- toISOWeekDate() {
- return toTechFormat(this, "kkkk-'W'WW-c");
- }
-
- toISOTime({
- suppressMilliseconds = false,
- suppressSeconds = false,
- includeOffset = true,
- includePrefix = false,
- extendedZone = false,
- format = "extended",
- } = {}) {
- if (!this.isValid) {
- return null;
- }
- let c = includePrefix ? "T" : "";
- return (
- c +
- toISOTime(
- this,
- format === "extended",
- suppressSeconds,
- suppressMilliseconds,
- includeOffset,
- extendedZone
- )
- );
- }
-
- toRFC2822() {
- return toTechFormat(this, "EEE, dd LLL yyyy HH:mm:ss ZZZ", false);
- }
-
- toHTTP() {
- return toTechFormat(this.toUTC(), "EEE, dd LLL yyyy HH:mm:ss 'GMT'");
- }
-
- toSQLDate() {
- if (!this.isValid) {
- return null;
- }
- return toISODate(this, true);
- }
-
- toSQLTime({ includeOffset = true, includeZone = false, includeOffsetSpace = true } = {}) {
- let fmt = "HH:mm:ss.SSS";
- if (includeZone || includeOffset) {
- if (includeOffsetSpace) {
- fmt += " ";
- }
- if (includeZone) {
- fmt += "z";
- } else if (includeOffset) {
- fmt += "ZZ";
- }
- }
- return toTechFormat(this, fmt, true);
- }
-
- toSQL(opts = {}) {
- if (!this.isValid) {
- return null;
- }
- return `${this.toSQLDate()} ${this.toSQLTime(opts)}`;
- }
-
- toString() {
- return this.isValid ? this.toISO() : INVALID;
- }
-
- valueOf() {
- return this.toMillis();
- }
-
- toMillis() {
- return this.isValid ? this.ts : NaN;
- }
-
- toSeconds() {
- return this.isValid ? this.ts / 1000 : NaN;
- }
-
- toUnixInteger() {
- return this.isValid ? Math.floor(this.ts / 1000) : NaN;
- }
-
- toJSON() {
- return this.toISO();
- }
-
- toBSON() {
- return this.toJSDate();
- }
-
- toObject(opts = {}) {
- if (!this.isValid) return {};
- const base = { ...this.c };
- if (opts.includeConfig) {
- base.outputCalendar = this.outputCalendar;
- base.numberingSystem = this.loc.numberingSystem;
- base.locale = this.loc.locale;
- }
- return base;
- }
-
- toJSDate() {
- return new Date(this.isValid ? this.ts : NaN);
- }
-
-
- diff(otherDateTime, unit = "milliseconds", opts = {}) {
- if (!this.isValid || !otherDateTime.isValid) {
- return Duration.invalid("created by diffing an invalid DateTime");
- }
- const durOpts = { locale: this.locale, numberingSystem: this.numberingSystem, ...opts };
- const units = maybeArray(unit).map(Duration.normalizeUnit),
- otherIsLater = otherDateTime.valueOf() > this.valueOf(),
- earlier = otherIsLater ? this : otherDateTime,
- later = otherIsLater ? otherDateTime : this,
- diffed = diff(earlier, later, units, durOpts);
- return otherIsLater ? diffed.negate() : diffed;
- }
-
- diffNow(unit = "milliseconds", opts = {}) {
- return this.diff(DateTime.now(), unit, opts);
- }
-
- until(otherDateTime) {
- return this.isValid ? Interval.fromDateTimes(this, otherDateTime) : this;
- }
-
- hasSame(otherDateTime, unit) {
- if (!this.isValid) return false;
- const inputMs = otherDateTime.valueOf();
- const adjustedToZone = this.setZone(otherDateTime.zone, { keepLocalTime: true });
- return adjustedToZone.startOf(unit) <= inputMs && inputMs <= adjustedToZone.endOf(unit);
- }
-
- equals(other) {
- return (
- this.isValid &&
- other.isValid &&
- this.valueOf() === other.valueOf() &&
- this.zone.equals(other.zone) &&
- this.loc.equals(other.loc)
- );
- }
-
- toRelative(options = {}) {
- if (!this.isValid) return null;
- const base = options.base || DateTime.fromObject({}, { zone: this.zone }),
- padding = options.padding ? (this < base ? -options.padding : options.padding) : 0;
- let units = ["years", "months", "days", "hours", "minutes", "seconds"];
- let unit = options.unit;
- if (Array.isArray(options.unit)) {
- units = options.unit;
- unit = undefined;
- }
- return diffRelative(base, this.plus(padding), {
- ...options,
- numeric: "always",
- units,
- unit,
- });
- }
-
- toRelativeCalendar(options = {}) {
- if (!this.isValid) return null;
- return diffRelative(options.base || DateTime.fromObject({}, { zone: this.zone }), this, {
- ...options,
- numeric: "auto",
- units: ["years", "months", "days"],
- calendary: true,
- });
- }
-
- static min(...dateTimes) {
- if (!dateTimes.every(DateTime.isDateTime)) {
- throw new InvalidArgumentError("min requires all arguments be DateTimes");
- }
- return bestBy(dateTimes, (i) => i.valueOf(), Math.min);
- }
-
- static max(...dateTimes) {
- if (!dateTimes.every(DateTime.isDateTime)) {
- throw new InvalidArgumentError("max requires all arguments be DateTimes");
- }
- return bestBy(dateTimes, (i) => i.valueOf(), Math.max);
- }
-
-
- static fromFormatExplain(text, fmt, options = {}) {
- const { locale = null, numberingSystem = null } = options,
- localeToUse = Locale.fromOpts({
- locale,
- numberingSystem,
- defaultToEN: true,
- });
- return explainFromTokens(localeToUse, text, fmt);
- }
-
- static fromStringExplain(text, fmt, options = {}) {
- return DateTime.fromFormatExplain(text, fmt, options);
- }
-
-
- static get DATE_SHORT() {
- return DATE_SHORT;
- }
-
- static get DATE_MED() {
- return DATE_MED;
- }
-
- static get DATE_MED_WITH_WEEKDAY() {
- return DATE_MED_WITH_WEEKDAY;
- }
-
- static get DATE_FULL() {
- return DATE_FULL;
- }
-
- static get DATE_HUGE() {
- return DATE_HUGE;
- }
-
- static get TIME_SIMPLE() {
- return TIME_SIMPLE;
- }
-
- static get TIME_WITH_SECONDS() {
- return TIME_WITH_SECONDS;
- }
-
- static get TIME_WITH_SHORT_OFFSET() {
- return TIME_WITH_SHORT_OFFSET;
- }
-
- static get TIME_WITH_LONG_OFFSET() {
- return TIME_WITH_LONG_OFFSET;
- }
-
- static get TIME_24_SIMPLE() {
- return TIME_24_SIMPLE;
- }
-
- static get TIME_24_WITH_SECONDS() {
- return TIME_24_WITH_SECONDS;
- }
-
- static get TIME_24_WITH_SHORT_OFFSET() {
- return TIME_24_WITH_SHORT_OFFSET;
- }
-
- static get TIME_24_WITH_LONG_OFFSET() {
- return TIME_24_WITH_LONG_OFFSET;
- }
-
- static get DATETIME_SHORT() {
- return DATETIME_SHORT;
- }
-
- static get DATETIME_SHORT_WITH_SECONDS() {
- return DATETIME_SHORT_WITH_SECONDS;
- }
-
- static get DATETIME_MED() {
- return DATETIME_MED;
- }
-
- static get DATETIME_MED_WITH_SECONDS() {
- return DATETIME_MED_WITH_SECONDS;
- }
-
- static get DATETIME_MED_WITH_WEEKDAY() {
- return DATETIME_MED_WITH_WEEKDAY;
- }
-
- static get DATETIME_FULL() {
- return DATETIME_FULL;
- }
-
- static get DATETIME_FULL_WITH_SECONDS() {
- return DATETIME_FULL_WITH_SECONDS;
- }
-
- static get DATETIME_HUGE() {
- return DATETIME_HUGE;
- }
-
- static get DATETIME_HUGE_WITH_SECONDS() {
- return DATETIME_HUGE_WITH_SECONDS;
- }
- }
- function friendlyDateTime(dateTimeish) {
- if (DateTime.isDateTime(dateTimeish)) {
- return dateTimeish;
- } else if (dateTimeish && dateTimeish.valueOf && isNumber(dateTimeish.valueOf())) {
- return DateTime.fromJSDate(dateTimeish);
- } else if (dateTimeish && typeof dateTimeish === "object") {
- return DateTime.fromObject(dateTimeish);
- } else {
- throw new InvalidArgumentError(
- `Unknown datetime argument: ${dateTimeish}, of type ${typeof dateTimeish}`
- );
- }
- }
- const VERSION = "3.4.3";
- var Luxon = Object.freeze({
- __proto__: null,
- VERSION: VERSION,
- DateTime: DateTime,
- Duration: Duration,
- Interval: Interval,
- Info: Info,
- Zone: Zone,
- FixedOffsetZone: FixedOffsetZone,
- IANAZone: IANAZone,
- InvalidZone: InvalidZone,
- SystemZone: SystemZone,
- Settings: Settings
- });
- const DEFAULT_QUERY_SETTINGS = {
- renderNullAs: "\\-",
- taskCompletionTracking: false,
- taskCompletionUseEmojiShorthand: false,
- taskCompletionText: "completion",
- taskCompletionDateFormat: "yyyy-MM-dd",
- recursiveSubTaskCompletion: false,
- warnOnEmptyResult: true,
- refreshEnabled: true,
- refreshInterval: 2500,
- defaultDateFormat: "MMMM dd, yyyy",
- defaultDateTimeFormat: "h:mm a - MMMM dd, yyyy",
- maxRecursiveRenderDepth: 4,
- tableIdColumnName: "File",
- tableGroupColumnName: "Group",
- showResultCount: true,
- };
- const DEFAULT_EXPORT_SETTINGS = {
- allowHtml: true,
- };
- const DEFAULT_SETTINGS = {
- ...DEFAULT_QUERY_SETTINGS,
- ...DEFAULT_EXPORT_SETTINGS,
- ...{
- inlineQueryPrefix: "=",
- inlineJsQueryPrefix: "$=",
- inlineQueriesInCodeblocks: true,
- enableInlineDataview: true,
- enableDataviewJs: false,
- enableInlineDataviewJs: false,
- prettyRenderInlineFields: true,
- prettyRenderInlineFieldsInLivePreview: true,
- dataviewJsKeyword: "dataviewjs",
- },
- };
- class Success {
- value;
- successful;
- constructor(value) {
- this.value = value;
- this.successful = true;
- }
- map(f) {
- return new Success(f(this.value));
- }
- flatMap(f) {
- return f(this.value);
- }
- mapErr(f) {
- return this;
- }
- bimap(succ, _fail) {
- return this.map(succ);
- }
- orElse(_value) {
- return this.value;
- }
- cast() {
- return this;
- }
- orElseThrow(_message) {
- return this.value;
- }
- }
- class Failure {
- error;
- successful;
- constructor(error) {
- this.error = error;
- this.successful = false;
- }
- map(_f) {
- return this;
- }
- flatMap(_f) {
- return this;
- }
- mapErr(f) {
- return new Failure(f(this.error));
- }
- bimap(_succ, fail) {
- return this.mapErr(fail);
- }
- orElse(value) {
- return value;
- }
- cast() {
- return this;
- }
- orElseThrow(message) {
- if (message)
- throw new Error(message(this.error));
- else
- throw new Error("" + this.error);
- }
- }
- var Result;
- (function (Result) {
-
- function success(value) {
- return new Success(value);
- }
- Result.success = success;
-
- function failure(error) {
- return new Failure(error);
- }
- Result.failure = failure;
-
- function flatMap2(first, second, f) {
- if (first.successful) {
- if (second.successful)
- return f(first.value, second.value);
- else
- return failure(second.error);
- }
- else {
- return failure(first.error);
- }
- }
- Result.flatMap2 = flatMap2;
-
- function map2(first, second, f) {
- return flatMap2(first, second, (a, b) => success(f(a, b)));
- }
- Result.map2 = map2;
- })(Result || (Result = {}));
- var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
- function getDefaultExportFromCjs (x) {
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
- }
- var parsimmon_umd_min = {exports: {}};
- parsimmon_umd_min.exports;
- (function (module, exports) {
- !function(n,t){module.exports=t();}("undefined"!=typeof self?self:commonjsGlobal,function(){return function(n){var t={};function r(e){if(t[e])return t[e].exports;var u=t[e]={i:e,l:!1,exports:{}};return n[e].call(u.exports,u,u.exports,r),u.l=!0,u.exports}return r.m=n,r.c=t,r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e});},r.r=function(n){Object.defineProperty(n,"__esModule",{value:!0});},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},r.p="",r(r.s=0)}([function(n,t,r){function e(n){if(!(this instanceof e))return new e(n);this._=n;}var u=e.prototype;function o(n,t){for(var r=0;r<n;r++)t(r);}function i(n,t,r){return function(n,t){o(t.length,function(r){n(t[r],r,t);});}(function(r,e,u){t=n(t,r,e,u);},r),t}function a(n,t){return i(function(t,r,e,u){return t.concat([n(r,e,u)])},[],t)}function f(n,t){var r={v:0,buf:t};return o(n,function(){var n;r={v:r.v<<1|(n=r.buf,n[0]>>7),buf:function(n){var t=i(function(n,t,r,e){return n.concat(r===e.length-1?Buffer.from([t,0]).readUInt16BE(0):e.readUInt16BE(r))},[],n);return Buffer.from(a(function(n){return (n<<1&65535)>>8},t))}(r.buf)};}),r}function c(){return "undefined"!=typeof Buffer}function s(){if(!c())throw new Error("Buffer global does not exist; please use webpack if you need to parse Buffers in the browser.")}function l(n){s();var t=i(function(n,t){return n+t},0,n);if(t%8!=0)throw new Error("The bits ["+n.join(", ")+"] add up to "+t+" which is not an even number of bytes; the total should be divisible by 8");var r,u=t/8,o=(r=function(n){return n>48},i(function(n,t){return n||(r(t)?t:n)},null,n));if(o)throw new Error(o+" bit range requested exceeds 48 bit (6 byte) Number max.");return new e(function(t,r){var e=u+r;return e>t.length?x(r,u.toString()+" bytes"):b(e,i(function(n,t){var r=f(t,n.buf);return {coll:n.coll.concat(r.v),buf:r.buf}},{coll:[],buf:t.slice(r,e)},n).coll)})}function h(n,t){return new e(function(r,e){return s(),e+t>r.length?x(e,t+" bytes for "+n):b(e+t,r.slice(e,e+t))})}function p(n,t){if("number"!=typeof(r=t)||Math.floor(r)!==r||t<0||t>6)throw new Error(n+" requires integer length in range [0, 6].");var r;}function d(n){return p("uintBE",n),h("uintBE("+n+")",n).map(function(t){return t.readUIntBE(0,n)})}function v(n){return p("uintLE",n),h("uintLE("+n+")",n).map(function(t){return t.readUIntLE(0,n)})}function g(n){return p("intBE",n),h("intBE("+n+")",n).map(function(t){return t.readIntBE(0,n)})}function m(n){return p("intLE",n),h("intLE("+n+")",n).map(function(t){return t.readIntLE(0,n)})}function y(n){return n instanceof e}function E(n){return "[object Array]"==={}.toString.call(n)}function w(n){return c()&&Buffer.isBuffer(n)}function b(n,t){return {status:!0,index:n,value:t,furthest:-1,expected:[]}}function x(n,t){return E(t)||(t=[t]),{status:!1,index:-1,value:null,furthest:n,expected:t}}function B(n,t){if(!t)return n;if(n.furthest>t.furthest)return n;var r=n.furthest===t.furthest?function(n,t){if(function(){if(void 0!==e._supportsSet)return e._supportsSet;var n="undefined"!=typeof Set;return e._supportsSet=n,n}()&&Array.from){for(var r=new Set(n),u=0;u<t.length;u++)r.add(t[u]);var o=Array.from(r);return o.sort(),o}for(var i={},a=0;a<n.length;a++)i[n[a]]=!0;for(var f=0;f<t.length;f++)i[t[f]]=!0;var c=[];for(var s in i)({}).hasOwnProperty.call(i,s)&&c.push(s);return c.sort(),c}(n.expected,t.expected):t.expected;return {status:n.status,index:n.index,value:n.value,furthest:t.furthest,expected:r}}var j={};function S(n,t){if(w(n))return {offset:t,line:-1,column:-1};n in j||(j[n]={});for(var r=j[n],e=0,u=0,o=0,i=t;i>=0;){if(i in r){e=r[i].line,0===o&&(o=r[i].lineStart);break}("\n"===n.charAt(i)||"\r"===n.charAt(i)&&"\n"!==n.charAt(i+1))&&(u++,0===o&&(o=i+1)),i--;}var a=e+u,f=t-o;return r[t]={line:a,lineStart:o},{offset:t,line:a+1,column:f+1}}function _(n){if(!y(n))throw new Error("not a parser: "+n)}function L(n,t){return "string"==typeof n?n.charAt(t):n[t]}function O(n){if("number"!=typeof n)throw new Error("not a number: "+n)}function k(n){if("function"!=typeof n)throw new Error("not a function: "+n)}function P(n){if("string"!=typeof n)throw new Error("not a string: "+n)}var q=2,A=3,I=8,F=5*I,M=4*I,z=" ";function R(n,t){return new Array(t+1).join(n)}function U(n,t,r){var e=t-n.length;return e<=0?n:R(r,e)+n}function W(n,t,r,e){return {from:n-t>0?n-t:0,to:n+r>e?e:n+r}}function D(n,t){var r,e,u,o,f,c=t.index,s=c.offset,l=1;if(s===n.length)return "Got the end of the input";if(w(n)){var h=s-s%I,p=s-h,d=W(h,F,M+I,n.length),v=a(function(n){return a(function(n){return U(n.toString(16),2,"0")},n)},function(n,t){var r=n.length,e=[],u=0;if(r<=t)return [n.slice()];for(var o=0;o<r;o++)e[u]||e.push([]),e[u].push(n[o]),(o+1)%t==0&&u++;return e}(n.slice(d.from,d.to).toJSON().data,I));o=function(n){return 0===n.from&&1===n.to?{from:n.from,to:n.to}:{from:n.from/I,to:Math.floor(n.to/I)}}(d),e=h/I,r=3*p,p>=4&&(r+=1),l=2,u=a(function(n){return n.length<=4?n.join(" "):n.slice(0,4).join(" ")+" "+n.slice(4).join(" ")},v),(f=(8*(o.to>0?o.to-1:o.to)).toString(16).length)<2&&(f=2);}else {var g=n.split(/\r\n|[\n\r\u2028\u2029]/);r=c.column-1,e=c.line-1,o=W(e,q,A,g.length),u=g.slice(o.from,o.to),f=o.to.toString().length;}var m=e-o.from;return w(n)&&(f=(8*(o.to>0?o.to-1:o.to)).toString(16).length)<2&&(f=2),i(function(t,e,u){var i,a=u===m,c=a?"> ":z;return i=w(n)?U((8*(o.from+u)).toString(16),f,"0"):U((o.from+u+1).toString(),f," "),[].concat(t,[c+i+" | "+e],a?[z+R(" ",f)+" | "+U("",r," ")+R("^",l)]:[])},[],u).join("\n")}function N(n,t){return ["\n","-- PARSING FAILED "+R("-",50),"\n\n",D(n,t),"\n\n",(r=t.expected,1===r.length?"Expected:\n\n"+r[0]:"Expected one of the following: \n\n"+r.join(", ")),"\n"].join("");var r;}function G(n){return void 0!==n.flags?n.flags:[n.global?"g":"",n.ignoreCase?"i":"",n.multiline?"m":"",n.unicode?"u":"",n.sticky?"y":""].join("")}function C(){for(var n=[].slice.call(arguments),t=n.length,r=0;r<t;r+=1)_(n[r]);return e(function(r,e){for(var u,o=new Array(t),i=0;i<t;i+=1){if(!(u=B(n[i]._(r,e),u)).status)return u;o[i]=u.value,e=u.index;}return B(b(e,o),u)})}function J(){var n=[].slice.call(arguments);if(0===n.length)throw new Error("seqMap needs at least one argument");var t=n.pop();return k(t),C.apply(null,n).map(function(n){return t.apply(null,n)})}function T(){var n=[].slice.call(arguments),t=n.length;if(0===t)return Y("zero alternates");for(var r=0;r<t;r+=1)_(n[r]);return e(function(t,r){for(var e,u=0;u<n.length;u+=1)if((e=B(n[u]._(t,r),e)).status)return e;return e})}function V(n,t){return H(n,t).or(X([]))}function H(n,t){return _(n),_(t),J(n,t.then(n).many(),function(n,t){return [n].concat(t)})}function K(n){P(n);var t="'"+n+"'";return e(function(r,e){var u=e+n.length,o=r.slice(e,u);return o===n?b(u,o):x(e,t)})}function Q(n,t){!function(n){if(!(n instanceof RegExp))throw new Error("not a regexp: "+n);for(var t=G(n),r=0;r<t.length;r++){var e=t.charAt(r);if("i"!==e&&"m"!==e&&"u"!==e&&"s"!==e)throw new Error('unsupported regexp flag "'+e+'": '+n)}}(n),arguments.length>=2?O(t):t=0;var r=function(n){return RegExp("^(?:"+n.source+")",G(n))}(n),u=""+n;return e(function(n,e){var o=r.exec(n.slice(e));if(o){if(0<=t&&t<=o.length){var i=o[0],a=o[t];return b(e+i.length,a)}return x(e,"valid match group (0 to "+o.length+") in "+u)}return x(e,u)})}function X(n){return e(function(t,r){return b(r,n)})}function Y(n){return e(function(t,r){return x(r,n)})}function Z(n){if(y(n))return e(function(t,r){var e=n._(t,r);return e.index=r,e.value="",e});if("string"==typeof n)return Z(K(n));if(n instanceof RegExp)return Z(Q(n));throw new Error("not a string, regexp, or parser: "+n)}function $(n){return _(n),e(function(t,r){var e=n._(t,r),u=t.slice(r,e.index);return e.status?x(r,'not "'+u+'"'):b(r,null)})}function nn(n){return k(n),e(function(t,r){var e=L(t,r);return r<t.length&&n(e)?b(r+1,e):x(r,"a character/byte matching "+n)})}function tn(n,t){arguments.length<2&&(t=n,n=void 0);var r=e(function(n,e){return r._=t()._,r._(n,e)});return n?r.desc(n):r}function rn(){return Y("fantasy-land/empty")}u.parse=function(n){if("string"!=typeof n&&!w(n))throw new Error(".parse must be called with a string or Buffer as its argument");var t,r=this.skip(an)._(n,0);return t=r.status?{status:!0,value:r.value}:{status:!1,index:S(n,r.furthest),expected:r.expected},delete j[n],t},u.tryParse=function(n){var t=this.parse(n);if(t.status)return t.value;var r=N(n,t),e=new Error(r);throw e.type="ParsimmonError",e.result=t,e},u.assert=function(n,t){return this.chain(function(r){return n(r)?X(r):Y(t)})},u.or=function(n){return T(this,n)},u.trim=function(n){return this.wrap(n,n)},u.wrap=function(n,t){return J(n,this,t,function(n,t){return t})},u.thru=function(n){return n(this)},u.then=function(n){return _(n),C(this,n).map(function(n){return n[1]})},u.many=function(){var n=this;return e(function(t,r){for(var e=[],u=void 0;;){if(!(u=B(n._(t,r),u)).status)return B(b(r,e),u);if(r===u.index)throw new Error("infinite loop detected in .many() parser --- calling .many() on a parser which can accept zero characters is usually the cause");r=u.index,e.push(u.value);}})},u.tieWith=function(n){return P(n),this.map(function(t){if(function(n){if(!E(n))throw new Error("not an array: "+n)}(t),t.length){P(t[0]);for(var r=t[0],e=1;e<t.length;e++)P(t[e]),r+=n+t[e];return r}return ""})},u.tie=function(){return this.tieWith("")},u.times=function(n,t){var r=this;return arguments.length<2&&(t=n),O(n),O(t),e(function(e,u){for(var o=[],i=void 0,a=void 0,f=0;f<n;f+=1){if(a=B(i=r._(e,u),a),!i.status)return a;u=i.index,o.push(i.value);}for(;f<t&&(a=B(i=r._(e,u),a),i.status);f+=1)u=i.index,o.push(i.value);return B(b(u,o),a)})},u.result=function(n){return this.map(function(){return n})},u.atMost=function(n){return this.times(0,n)},u.atLeast=function(n){return J(this.times(n),this.many(),function(n,t){return n.concat(t)})},u.map=function(n){k(n);var t=this;return e(function(r,e){var u=t._(r,e);return u.status?B(b(u.index,n(u.value)),u):u})},u.contramap=function(n){k(n);var t=this;return e(function(r,e){var u=t.parse(n(r.slice(e)));return u.status?b(e+r.length,u.value):u})},u.promap=function(n,t){return k(n),k(t),this.contramap(n).map(t)},u.skip=function(n){return C(this,n).map(function(n){return n[0]})},u.mark=function(){return J(en,this,en,function(n,t,r){return {start:n,value:t,end:r}})},u.node=function(n){return J(en,this,en,function(t,r,e){return {name:n,value:r,start:t,end:e}})},u.sepBy=function(n){return V(this,n)},u.sepBy1=function(n){return H(this,n)},u.lookahead=function(n){return this.skip(Z(n))},u.notFollowedBy=function(n){return this.skip($(n))},u.desc=function(n){E(n)||(n=[n]);var t=this;return e(function(r,e){var u=t._(r,e);return u.status||(u.expected=n),u})},u.fallback=function(n){return this.or(X(n))},u.ap=function(n){return J(n,this,function(n,t){return n(t)})},u.chain=function(n){var t=this;return e(function(r,e){var u=t._(r,e);return u.status?B(n(u.value)._(r,u.index),u):u})},u.concat=u.or,u.empty=rn,u.of=X,u["fantasy-land/ap"]=u.ap,u["fantasy-land/chain"]=u.chain,u["fantasy-land/concat"]=u.concat,u["fantasy-land/empty"]=u.empty,u["fantasy-land/of"]=u.of,u["fantasy-land/map"]=u.map;var en=e(function(n,t){return b(t,S(n,t))}),un=e(function(n,t){return t>=n.length?x(t,"any character/byte"):b(t+1,L(n,t))}),on=e(function(n,t){return b(n.length,n.slice(t))}),an=e(function(n,t){return t<n.length?x(t,"EOF"):b(t,null)}),fn=Q(/[0-9]/).desc("a digit"),cn=Q(/[0-9]*/).desc("optional digits"),sn=Q(/[a-z]/i).desc("a letter"),ln=Q(/[a-z]*/i).desc("optional letters"),hn=Q(/\s*/).desc("optional whitespace"),pn=Q(/\s+/).desc("whitespace"),dn=K("\r"),vn=K("\n"),gn=K("\r\n"),mn=T(gn,vn,dn).desc("newline"),yn=T(mn,an);e.all=on,e.alt=T,e.any=un,e.cr=dn,e.createLanguage=function(n){var t={};for(var r in n)({}).hasOwnProperty.call(n,r)&&function(r){t[r]=tn(function(){return n[r](t)});}(r);return t},e.crlf=gn,e.custom=function(n){return e(n(b,x))},e.digit=fn,e.digits=cn,e.empty=rn,e.end=yn,e.eof=an,e.fail=Y,e.formatError=N,e.index=en,e.isParser=y,e.lazy=tn,e.letter=sn,e.letters=ln,e.lf=vn,e.lookahead=Z,e.makeFailure=x,e.makeSuccess=b,e.newline=mn,e.noneOf=function(n){return nn(function(t){return n.indexOf(t)<0}).desc("none of '"+n+"'")},e.notFollowedBy=$,e.of=X,e.oneOf=function(n){for(var t=n.split(""),r=0;r<t.length;r++)t[r]="'"+t[r]+"'";return nn(function(t){return n.indexOf(t)>=0}).desc(t)},e.optWhitespace=hn,e.Parser=e,e.range=function(n,t){return nn(function(r){return n<=r&&r<=t}).desc(n+"-"+t)},e.regex=Q,e.regexp=Q,e.sepBy=V,e.sepBy1=H,e.seq=C,e.seqMap=J,e.seqObj=function(){for(var n,t={},r=0,u=(n=arguments,Array.prototype.slice.call(n)),o=u.length,i=0;i<o;i+=1){var a=u[i];if(!y(a)){if(E(a)&&2===a.length&&"string"==typeof a[0]&&y(a[1])){var f=a[0];if(Object.prototype.hasOwnProperty.call(t,f))throw new Error("seqObj: duplicate key "+f);t[f]=!0,r++;continue}throw new Error("seqObj arguments must be parsers or [string, parser] array pairs.")}}if(0===r)throw new Error("seqObj expects at least one named parser, found zero");return e(function(n,t){for(var r,e={},i=0;i<o;i+=1){var a,f;if(E(u[i])?(a=u[i][0],f=u[i][1]):(a=null,f=u[i]),!(r=B(f._(n,t),r)).status)return r;a&&(e[a]=r.value),t=r.index;}return B(b(t,e),r)})},e.string=K,e.succeed=X,e.takeWhile=function(n){return k(n),e(function(t,r){for(var e=r;e<t.length&&n(L(t,e));)e++;return b(e,t.slice(r,e))})},e.test=nn,e.whitespace=pn,e["fantasy-land/empty"]=rn,e["fantasy-land/of"]=X,e.Binary={bitSeq:l,bitSeqObj:function(n){s();var t={},r=0,e=a(function(n){if(E(n)){var e=n;if(2!==e.length)throw new Error("["+e.join(", ")+"] should be length 2, got length "+e.length);if(P(e[0]),O(e[1]),Object.prototype.hasOwnProperty.call(t,e[0]))throw new Error("duplicate key in bitSeqObj: "+e[0]);return t[e[0]]=!0,r++,e}return O(n),[null,n]},n);if(r<1)throw new Error("bitSeqObj expects at least one named pair, got ["+n.join(", ")+"]");var u=a(function(n){return n[0]},e);return l(a(function(n){return n[1]},e)).map(function(n){return i(function(n,t){return null!==t[0]&&(n[t[0]]=t[1]),n},{},a(function(t,r){return [t,n[r]]},u))})},byte:function(n){if(s(),O(n),n>255)throw new Error("Value specified to byte constructor ("+n+"=0x"+n.toString(16)+") is larger in value than a single byte.");var t=(n>15?"0x":"0x0")+n.toString(16);return e(function(r,e){var u=L(r,e);return u===n?b(e+1,u):x(e,t)})},buffer:function(n){return h("buffer",n).map(function(n){return Buffer.from(n)})},encodedString:function(n,t){return h("string",t).map(function(t){return t.toString(n)})},uintBE:d,uint8BE:d(1),uint16BE:d(2),uint32BE:d(4),uintLE:v,uint8LE:v(1),uint16LE:v(2),uint32LE:v(4),intBE:g,int8BE:g(1),int16BE:g(2),int32BE:g(4),intLE:m,int8LE:m(1),int16LE:m(2),int32LE:m(4),floatBE:h("floatBE",4).map(function(n){return n.readFloatBE(0)}),floatLE:h("floatLE",4).map(function(n){return n.readFloatLE(0)}),doubleBE:h("doubleBE",8).map(function(n){return n.readDoubleBE(0)}),doubleLE:h("doubleLE",8).map(function(n){return n.readDoubleLE(0)})},n.exports=e;}])});
- } (parsimmon_umd_min, parsimmon_umd_min.exports));
- var parsimmon_umd_minExports = parsimmon_umd_min.exports;
- var emojiRegex = () => {
-
- return /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC08\uDC26](?:\u200D\u2B1B)?|[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC2\uDECE-\uDEDB\uDEE0-\uDEE8]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;
- };
- function normalizeDuration(dur) {
- if (dur === undefined || dur === null)
- return dur;
- return dur.shiftToAll().normalize();
- }
- function stripTime(dt) {
- if (dt === null || dt === undefined)
- return dt;
- return DateTime.fromObject({
- year: dt.year,
- month: dt.month,
- day: dt.day,
- });
- }
- function getParentFolder(path) {
- return path.split("/").slice(0, -1).join("/");
- }
- function getFileTitle(path) {
- if (path.includes("/"))
- path = path.substring(path.lastIndexOf("/") + 1);
- if (path.endsWith(".md"))
- path = path.substring(0, path.length - 3);
- return path;
- }
- function getExtension(path) {
- if (!path.includes("."))
- return "";
- return path.substring(path.lastIndexOf(".") + 1);
- }
- function extractSubtags(tag) {
- let result = [tag];
- while (tag.includes("/")) {
- tag = tag.substring(0, tag.lastIndexOf("/"));
- result.push(tag);
- }
- return result;
- }
- function tryOrPropogate(func) {
- try {
- return func();
- }
- catch (error) {
- return Result.failure("" + error + "\n\n" + error.stack);
- }
- }
- async function asyncTryOrPropogate(func) {
- try {
- return await func();
- }
- catch (error) {
- return Result.failure("" + error + "\n\n" + error.stack);
- }
- }
- function escapeRegex(str) {
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
- }
- const VAR_NAME_CANONICALIZER = parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regex(new RegExp(emojiRegex(), "")), parsimmon_umd_minExports.regex(/[0-9\p{Letter}_-]+/u).map(str => str.toLocaleLowerCase()), parsimmon_umd_minExports.whitespace.map(_ => "-"), parsimmon_umd_minExports.any.map(_ => ""))
- .many()
- .map(result => result.join(""));
- function canonicalizeVarName(name) {
- return VAR_NAME_CANONICALIZER.tryParse(name);
- }
- const HEADER_CANONICALIZER = parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regex(new RegExp(emojiRegex(), "")), parsimmon_umd_minExports.regex(/[0-9\p{Letter}_-]+/u), parsimmon_umd_minExports.whitespace.map(_ => " "), parsimmon_umd_minExports.any.map(_ => " "))
- .many()
- .map(result => {
- return result.join("").split(/\s+/).join(" ").trim();
- });
- function normalizeHeaderForLink(header) {
- return HEADER_CANONICALIZER.tryParse(header);
- }
- function renderMinimalDate(time, settings, locale) {
-
- if (time.second == 0 && time.minute == 0 && time.hour == 0) {
- return time.toLocal().toFormat(settings.defaultDateFormat, { locale });
- }
- return time.toLocal().toFormat(settings.defaultDateTimeFormat, { locale });
- }
- function renderMinimalDuration(dur) {
- dur = normalizeDuration(dur);
-
- dur = Duration.fromObject(Object.fromEntries(Object.entries(dur.toObject()).filter(([, quantity]) => quantity != 0)));
- return dur.toHuman();
- }
- function setsEqual(first, second) {
- if (first.size != second.size)
- return false;
- for (let elem of first)
- if (!second.has(elem))
- return false;
- return true;
- }
- var Values;
- (function (Values) {
-
- function toString(field, setting = DEFAULT_QUERY_SETTINGS, recursive = false) {
- let wrapped = wrapValue(field);
- if (!wrapped)
- return setting.renderNullAs;
- switch (wrapped.type) {
- case "null":
- return setting.renderNullAs;
- case "string":
- return wrapped.value;
- case "number":
- case "boolean":
- return "" + wrapped.value;
- case "html":
- return wrapped.value.outerHTML;
- case "widget":
- return wrapped.value.markdown();
- case "link":
- return wrapped.value.markdown();
- case "function":
- return "<function>";
- case "array":
- let result = "";
- if (recursive)
- result += "[";
- result += wrapped.value.map(f => toString(f, setting, true)).join(", ");
- if (recursive)
- result += "]";
- return result;
- case "object":
- return ("{ " +
- Object.entries(wrapped.value)
- .map(e => e[0] + ": " + toString(e[1], setting, true))
- .join(", ") +
- " }");
- case "date":
- if (wrapped.value.second == 0 && wrapped.value.hour == 0 && wrapped.value.minute == 0) {
- return wrapped.value.toFormat(setting.defaultDateFormat);
- }
- return wrapped.value.toFormat(setting.defaultDateTimeFormat);
- case "duration":
- return renderMinimalDuration(wrapped.value);
- }
- }
- Values.toString = toString;
-
- function wrapValue(val) {
- if (isNull(val))
- return { type: "null", value: val };
- else if (isNumber(val))
- return { type: "number", value: val };
- else if (isString(val))
- return { type: "string", value: val };
- else if (isBoolean(val))
- return { type: "boolean", value: val };
- else if (isDuration(val))
- return { type: "duration", value: val };
- else if (isDate(val))
- return { type: "date", value: val };
- else if (isWidget(val))
- return { type: "widget", value: val };
- else if (isArray(val))
- return { type: "array", value: val };
- else if (isLink(val))
- return { type: "link", value: val };
- else if (isFunction(val))
- return { type: "function", value: val };
- else if (isHtml(val))
- return { type: "html", value: val };
- else if (isObject(val))
- return { type: "object", value: val };
- else
- return undefined;
- }
- Values.wrapValue = wrapValue;
-
- function mapLeaves(val, func) {
- if (isObject(val)) {
- let result = {};
- for (let [key, value] of Object.entries(val))
- result[key] = mapLeaves(value, func);
- return result;
- }
- else if (isArray(val)) {
- let result = [];
- for (let value of val)
- result.push(mapLeaves(value, func));
- return result;
- }
- else {
- return func(val);
- }
- }
- Values.mapLeaves = mapLeaves;
-
- function compareValue(val1, val2, linkNormalizer) {
-
- if (val1 === undefined)
- val1 = null;
- if (val2 === undefined)
- val2 = null;
- if (val1 === null && val2 === null)
- return 0;
- else if (val1 === null)
- return -1;
- else if (val2 === null)
- return 1;
-
- let wrap1 = wrapValue(val1);
- let wrap2 = wrapValue(val2);
- if (wrap1 === undefined && wrap2 === undefined)
- return 0;
- else if (wrap1 === undefined)
- return -1;
- else if (wrap2 === undefined)
- return 1;
-
- if (wrap1.type != wrap2.type)
- return wrap1.type.localeCompare(wrap2.type);
- if (wrap1.value === wrap2.value)
- return 0;
- switch (wrap1.type) {
- case "string":
- return wrap1.value.localeCompare(wrap2.value);
- case "number":
- if (wrap1.value < wrap2.value)
- return -1;
- else if (wrap1.value == wrap2.value)
- return 0;
- return 1;
- case "null":
- return 0;
- case "boolean":
- if (wrap1.value == wrap2.value)
- return 0;
- else
- return wrap1.value ? 1 : -1;
- case "link":
- let link1 = wrap1.value;
- let link2 = wrap2.value;
- let normalize = linkNormalizer ?? ((x) => x);
-
- let pathCompare = normalize(link1.path).localeCompare(normalize(link2.path));
- if (pathCompare != 0)
- return pathCompare;
-
- let typeCompare = link1.type.localeCompare(link2.type);
- if (typeCompare != 0)
- return typeCompare;
-
- if (link1.subpath && !link2.subpath)
- return 1;
- if (!link1.subpath && link2.subpath)
- return -1;
- if (!link1.subpath && !link2.subpath)
- return 0;
-
- return (link1.subpath ?? "").localeCompare(link2.subpath ?? "");
- case "date":
- return wrap1.value < wrap2.value
- ? -1
- : wrap1.value.equals(wrap2.value)
- ? 0
- : 1;
- case "duration":
- return wrap1.value < wrap2.value
- ? -1
- : wrap1.value.equals(wrap2.value)
- ? 0
- : 1;
- case "array":
- let f1 = wrap1.value;
- let f2 = wrap2.value;
- for (let index = 0; index < Math.min(f1.length, f2.length); index++) {
- let comp = compareValue(f1[index], f2[index]);
- if (comp != 0)
- return comp;
- }
- return f1.length - f2.length;
- case "object":
- let o1 = wrap1.value;
- let o2 = wrap2.value;
- let k1 = Array.from(Object.keys(o1));
- let k2 = Array.from(Object.keys(o2));
- k1.sort();
- k2.sort();
- let keyCompare = compareValue(k1, k2);
- if (keyCompare != 0)
- return keyCompare;
- for (let key of k1) {
- let comp = compareValue(o1[key], o2[key]);
- if (comp != 0)
- return comp;
- }
- return 0;
- case "widget":
- case "html":
- case "function":
- return 0;
- }
- }
- Values.compareValue = compareValue;
-
- function typeOf(val) {
- return wrapValue(val)?.type;
- }
- Values.typeOf = typeOf;
-
- function isTruthy(field) {
- let wrapped = wrapValue(field);
- if (!wrapped)
- return false;
- switch (wrapped.type) {
- case "number":
- return wrapped.value != 0;
- case "string":
- return wrapped.value.length > 0;
- case "boolean":
- return wrapped.value;
- case "link":
- return !!wrapped.value.path;
- case "date":
- return wrapped.value.toMillis() != 0;
- case "duration":
- return wrapped.value.as("seconds") != 0;
- case "object":
- return Object.keys(wrapped.value).length > 0;
- case "array":
- return wrapped.value.length > 0;
- case "null":
- return false;
- case "html":
- case "widget":
- case "function":
- return true;
- }
- }
- Values.isTruthy = isTruthy;
-
- function deepCopy(field) {
- if (field === null || field === undefined)
- return field;
- if (Values.isArray(field)) {
- return [].concat(field.map(v => deepCopy(v)));
- }
- else if (Values.isObject(field)) {
- let result = {};
- for (let [key, value] of Object.entries(field))
- result[key] = deepCopy(value);
- return result;
- }
- else {
- return field;
- }
- }
- Values.deepCopy = deepCopy;
- function isString(val) {
- return typeof val == "string";
- }
- Values.isString = isString;
- function isNumber(val) {
- return typeof val == "number";
- }
- Values.isNumber = isNumber;
- function isDate(val) {
- return val instanceof DateTime;
- }
- Values.isDate = isDate;
- function isDuration(val) {
- return val instanceof Duration;
- }
- Values.isDuration = isDuration;
- function isNull(val) {
- return val === null || val === undefined;
- }
- Values.isNull = isNull;
- function isArray(val) {
- return Array.isArray(val);
- }
- Values.isArray = isArray;
- function isBoolean(val) {
- return typeof val === "boolean";
- }
- Values.isBoolean = isBoolean;
- function isLink(val) {
- return val instanceof Link;
- }
- Values.isLink = isLink;
- function isWidget(val) {
- return val instanceof Widget;
- }
- Values.isWidget = isWidget;
- function isHtml(val) {
- if (typeof HTMLElement !== "undefined") {
- return val instanceof HTMLElement;
- }
- else {
- return false;
- }
- }
- Values.isHtml = isHtml;
-
- function isObject(val) {
- return (typeof val == "object" &&
- !isHtml(val) &&
- !isWidget(val) &&
- !isArray(val) &&
- !isDuration(val) &&
- !isDate(val) &&
- !isLink(val) &&
- val !== undefined &&
- !isNull(val));
- }
- Values.isObject = isObject;
- function isFunction(val) {
- return typeof val == "function";
- }
- Values.isFunction = isFunction;
- })(Values || (Values = {}));
- var Groupings;
- (function (Groupings) {
-
- function isElementGroup(entry) {
- return Values.isObject(entry) && Object.keys(entry).length == 2 && "key" in entry && "rows" in entry;
- }
- Groupings.isElementGroup = isElementGroup;
-
- function isGrouping(entry) {
- for (let element of entry)
- if (!isElementGroup(element))
- return false;
- return true;
- }
- Groupings.isGrouping = isGrouping;
-
- function count(elements) {
- if (isGrouping(elements)) {
- let result = 0;
- for (let subgroup of elements)
- result += count(subgroup.rows);
- return result;
- }
- else {
- return elements.length;
- }
- }
- Groupings.count = count;
- })(Groupings || (Groupings = {}));
- class Link {
-
- path;
-
- display;
-
- subpath;
-
- embed;
-
- type;
-
- static file(path, embed = false, display) {
- return new Link({
- path,
- embed,
- display,
- subpath: undefined,
- type: "file",
- });
- }
- static infer(linkpath, embed = false, display) {
- if (linkpath.includes("#^")) {
- let split = linkpath.split("#^");
- return Link.block(split[0], split[1], embed, display);
- }
- else if (linkpath.includes("#")) {
- let split = linkpath.split("#");
- return Link.header(split[0], split[1], embed, display);
- }
- else
- return Link.file(linkpath, embed, display);
- }
-
- static header(path, header, embed, display) {
-
- return new Link({
- path,
- embed,
- display,
- subpath: normalizeHeaderForLink(header),
- type: "header",
- });
- }
-
- static block(path, blockId, embed, display) {
- return new Link({
- path,
- embed,
- display,
- subpath: blockId,
- type: "block",
- });
- }
- static fromObject(object) {
- return new Link(object);
- }
- constructor(fields) {
- Object.assign(this, fields);
- }
-
- equals(other) {
- if (other == undefined || other == null)
- return false;
- return this.path == other.path && this.type == other.type && this.subpath == other.subpath;
- }
-
- toString() {
- return this.markdown();
- }
-
- toObject() {
- return { path: this.path, type: this.type, subpath: this.subpath, display: this.display, embed: this.embed };
- }
-
-
- withPath(path) {
- return new Link(Object.assign({}, this, { path }));
- }
-
- withDisplay(display) {
- return new Link(Object.assign({}, this, { display }));
- }
-
- withHeader(header) {
- return Link.header(this.path, header, this.embed, this.display);
- }
-
- toFile() {
- return Link.file(this.path, this.embed, this.display);
- }
-
- toEmbed() {
- if (this.embed) {
- return this;
- }
- else {
- let link = new Link(this);
- link.embed = true;
- return link;
- }
- }
-
- fromEmbed() {
- if (!this.embed) {
- return this;
- }
- else {
- let link = new Link(this);
- link.embed = false;
- return link;
- }
- }
-
- markdown() {
- let result = (this.embed ? "!" : "") + "[[" + this.obsidianLink();
- if (this.display) {
- result += "|" + this.display;
- }
- else {
- result += "|" + getFileTitle(this.path);
- if (this.type == "header" || this.type == "block")
- result += " > " + this.subpath;
- }
- result += "]]";
- return result;
- }
-
- obsidianLink() {
- const escaped = this.path.replaceAll("|", "\\|");
- if (this.type == "header")
- return escaped + "#" + this.subpath?.replaceAll("|", "\\|");
- if (this.type == "block")
- return escaped + "#^" + this.subpath?.replaceAll("|", "\\|");
- else
- return escaped;
- }
-
- fileName() {
- return getFileTitle(this.path).replace(".md", "");
- }
- }
- class Widget {
- $widget;
- constructor($widget) {
- this.$widget = $widget;
- }
- }
- class ListPairWidget extends Widget {
- key;
- value;
- constructor(key, value) {
- super("dataview:list-pair");
- this.key = key;
- this.value = value;
- }
- markdown() {
- return `${Values.toString(this.key)}: ${Values.toString(this.value)}`;
- }
- }
- class ExternalLinkWidget extends Widget {
- url;
- display;
- constructor(url, display) {
- super("dataview:external-link");
- this.url = url;
- this.display = display;
- }
- markdown() {
- return `[${this.display ?? this.url}](${this.url})`;
- }
- }
- var Widgets;
- (function (Widgets) {
-
- function listPair(key, value) {
- return new ListPairWidget(key, value);
- }
- Widgets.listPair = listPair;
-
- function externalLink(url, display) {
- return new ExternalLinkWidget(url, display);
- }
- Widgets.externalLink = externalLink;
-
- function isListPair(widget) {
- return widget.$widget === "dataview:list-pair";
- }
- Widgets.isListPair = isListPair;
- function isExternalLink(widget) {
- return widget.$widget === "dataview:external-link";
- }
- Widgets.isExternalLink = isExternalLink;
-
- function isBuiltin(widget) {
- return isListPair(widget) || isExternalLink(widget);
- }
- Widgets.isBuiltin = isBuiltin;
- })(Widgets || (Widgets = {}));
- class DataArrayImpl {
- values;
- settings;
- defaultComparator;
- static ARRAY_FUNCTIONS = new Set([
- "where",
- "filter",
- "map",
- "flatMap",
- "mutate",
- "slice",
- "concat",
- "indexOf",
- "limit",
- "find",
- "findIndex",
- "includes",
- "join",
- "sort",
- "sortInPlace",
- "groupBy",
- "groupIn",
- "distinct",
- "every",
- "some",
- "none",
- "first",
- "last",
- "to",
- "into",
- "lwrap",
- "expand",
- "forEach",
- "length",
- "values",
- "array",
- "defaultComparator",
- "toString",
- "settings",
- "sum",
- "avg",
- "min",
- "max",
- ]);
- static ARRAY_PROXY = {
- get: function (target, prop, reciever) {
- if (typeof prop === "symbol")
- return target[prop];
- else if (typeof prop === "number")
- return target.values[prop];
- else if (prop === "constructor")
- return target.values.constructor;
- else if (!isNaN(parseInt(prop)))
- return target.values[parseInt(prop)];
- else if (DataArrayImpl.ARRAY_FUNCTIONS.has(prop.toString()))
- return target[prop.toString()];
- return target.to(prop);
- },
- };
- static wrap(arr, settings, defaultComparator = Values.compareValue) {
- return new Proxy(new DataArrayImpl(arr, settings, defaultComparator), DataArrayImpl.ARRAY_PROXY);
- }
- length;
- constructor(values, settings, defaultComparator = Values.compareValue) {
- this.values = values;
- this.settings = settings;
- this.defaultComparator = defaultComparator;
- this.length = values.length;
- }
- lwrap(values) {
- return DataArrayImpl.wrap(values, this.settings, this.defaultComparator);
- }
- where(predicate) {
- return this.lwrap(this.values.filter(predicate));
- }
- filter(predicate) {
- return this.where(predicate);
- }
- map(f) {
- return this.lwrap(this.values.map(f));
- }
- flatMap(f) {
- let result = [];
- for (let index = 0; index < this.length; index++) {
- let value = f(this.values[index], index, this.values);
- if (!value || value.length == 0)
- continue;
- for (let r of value)
- result.push(r);
- }
- return this.lwrap(result);
- }
- mutate(f) {
- for (let index = 0; index < this.values.length; index++) {
- f(this.values[index], index, this.values);
- }
- return this;
- }
- limit(count) {
- return this.lwrap(this.values.slice(0, count));
- }
- slice(start, end) {
- return this.lwrap(this.values.slice(start, end));
- }
- concat(other) {
- return this.lwrap(this.values.concat(other.values));
- }
-
- indexOf(element, fromIndex) {
- return this.findIndex(e => this.defaultComparator(e, element) == 0, fromIndex);
- }
-
- find(pred) {
- let index = this.findIndex(pred);
- if (index == -1)
- return undefined;
- else
- return this.values[index];
- }
- findIndex(pred, fromIndex) {
- for (let index = fromIndex ?? 0; index < this.length; index++) {
- if (pred(this.values[index], index, this.values))
- return index;
- }
- return -1;
- }
- includes(element) {
- return this.indexOf(element, 0) != -1;
- }
- join(sep) {
- return this.map(s => Values.toString(s, this.settings))
- .array()
- .join(sep ?? ", ");
- }
- sort(key, direction, comparator) {
- if (this.values.length == 0)
- return this;
- let realComparator = comparator ?? this.defaultComparator;
- let realKey = key ?? ((l) => l);
-
- let copy = [].concat(this.array()).map((elem, index) => {
- return { index: index, value: elem };
- });
- copy.sort((a, b) => {
- let aKey = realKey(a.value, a.index, this.values);
- let bKey = realKey(b.value, b.index, this.values);
- return direction === "desc" ? -realComparator(aKey, bKey) : realComparator(aKey, bKey);
- });
- return this.lwrap(copy.map(e => e.value));
- }
- sortInPlace(key, direction, comparator) {
- if (this.values.length == 0)
- return this;
- let realComparator = comparator ?? this.defaultComparator;
- let realKey = key ?? ((l) => l);
- this.values.sort((a, b) => {
- let aKey = realKey(a);
- let bKey = realKey(b);
- return direction == "desc" ? -realComparator(aKey, bKey) : realComparator(aKey, bKey);
- });
- return this;
- }
- groupBy(key, comparator) {
- if (this.values.length == 0)
- return this.lwrap([]);
-
-
- let intermediate = this.sort(key, "asc", comparator);
- comparator = comparator ?? this.defaultComparator;
- let result = [];
- let currentRow = [intermediate[0]];
- let current = key(intermediate[0], 0, intermediate.values);
- for (let index = 1; index < intermediate.length; index++) {
- let newKey = key(intermediate[index], index, intermediate.values);
- if (comparator(current, newKey) != 0) {
- result.push({ key: current, rows: this.lwrap(currentRow) });
- current = newKey;
- currentRow = [intermediate[index]];
- }
- else {
- currentRow.push(intermediate[index]);
- }
- }
- result.push({ key: current, rows: this.lwrap(currentRow) });
- return this.lwrap(result);
- }
- groupIn(key, comparator) {
- if (Groupings.isGrouping(this.values)) {
- return this.map(v => {
- return {
- key: v.key,
- rows: DataArray.wrap(v.rows, this.settings).groupIn(key, comparator),
- };
- });
- }
- else {
- return this.groupBy(key, comparator);
- }
- }
- distinct(key, comparator) {
- if (this.values.length == 0)
- return this;
- let realKey = key ?? (x => x);
-
- let intermediate = this.map((x, index) => {
- return { key: realKey(x, index, this.values), value: x };
- }).sort(x => x.key, "asc", comparator);
- comparator = comparator ?? this.defaultComparator;
- let result = [intermediate[0].value];
- for (let index = 1; index < intermediate.length; index++) {
- if (comparator(intermediate[index - 1].key, intermediate[index].key) != 0) {
- result.push(intermediate[index].value);
- }
- }
- return this.lwrap(result);
- }
- every(f) {
- return this.values.every(f);
- }
- some(f) {
- return this.values.some(f);
- }
- none(f) {
- return this.values.every((v, i, a) => !f(v, i, a));
- }
- first() {
- return this.values.length > 0 ? this.values[0] : undefined;
- }
- last() {
- return this.values.length > 0 ? this.values[this.values.length - 1] : undefined;
- }
- to(key) {
- let result = [];
- for (let child of this.values) {
- let value = child[key];
- if (value === undefined || value === null)
- continue;
- if (Array.isArray(value) || DataArray.isDataArray(value))
- value.forEach(v => result.push(v));
- else
- result.push(value);
- }
- return this.lwrap(result);
- }
- into(key) {
- let result = [];
- for (let child of this.values) {
- let value = child[key];
- if (value === undefined || value === null)
- continue;
- result.push(value);
- }
- return this.lwrap(result);
- }
- expand(key) {
- let result = [];
- let queue = [].concat(this.values);
- while (queue.length > 0) {
- let next = queue.pop();
- let value = next[key];
- if (value === undefined || value === null)
- continue;
- if (Array.isArray(value))
- value.forEach(v => queue.push(v));
- else if (value instanceof DataArrayImpl)
- value.forEach(v => queue.push(v));
- else
- queue.push(value);
- result.push(next);
- }
- return this.lwrap(result);
- }
- forEach(f) {
- for (let index = 0; index < this.values.length; index++) {
- f(this.values[index], index, this.values);
- }
- }
- sum() {
- return this.values.reduce((a, b) => a + b, 0);
- }
- avg() {
- return this.sum() / this.values.length;
- }
- min() {
- return Math.min(...this.values);
- }
- max() {
- return Math.max(...this.values);
- }
- array() {
- return [].concat(this.values);
- }
- [Symbol.iterator]() {
- return this.values[Symbol.iterator]();
- }
- toString() {
- return "[" + this.values.join(", ") + "]";
- }
- }
- var DataArray;
- (function (DataArray) {
-
- function wrap(raw, settings) {
- if (isDataArray(raw))
- return raw;
- return DataArrayImpl.wrap(raw, settings);
- }
- DataArray.wrap = wrap;
-
- function from(raw, settings) {
- if (isDataArray(raw))
- return raw;
- let data = [];
- for (let elem of raw)
- data.push(elem);
- return DataArrayImpl.wrap(data, settings);
- }
- DataArray.from = from;
-
- function isDataArray(obj) {
- return obj instanceof DataArrayImpl;
- }
- DataArray.isDataArray = isDataArray;
- })(DataArray || (DataArray = {}));
- const oldArrayIsArray = Array.isArray;
- Array.isArray = (arg) => {
- return oldArrayIsArray(arg) || DataArray.isDataArray(arg);
- };
- function currentLocale() {
- if (typeof window === "undefined")
- return "en-US";
- return window.navigator.language;
- }
- async function renderCompactMarkdown(app, markdown, container, sourcePath, component, isInlineFieldLivePreview = false) {
-
- if (isInlineFieldLivePreview) {
- await renderCompactMarkdownForInlineFieldLivePreview(app, markdown, container, sourcePath, component);
- }
- else {
- let subcontainer = container.createSpan();
- await obsidian.MarkdownRenderer.render(app, markdown, subcontainer, sourcePath, component);
- let paragraph = subcontainer.querySelector(":scope > p");
- if (subcontainer.children.length == 1 && paragraph) {
- while (paragraph.firstChild) {
- subcontainer.appendChild(paragraph.firstChild);
- }
- subcontainer.removeChild(paragraph);
- }
- }
- }
- async function renderCompactMarkdownForInlineFieldLivePreview(app, markdown, container, sourcePath, component) {
- const tmpContainer = createSpan();
- await obsidian.MarkdownRenderer.render(app, markdown, tmpContainer, sourcePath, component);
- let paragraph = tmpContainer.querySelector(":scope > p");
- if (tmpContainer.childNodes.length == 1 && paragraph) {
- container.replaceChildren(...paragraph.childNodes);
- }
- else {
- container.replaceChildren(...tmpContainer.childNodes);
- }
- tmpContainer.remove();
- }
- function renderErrorPre(container, error) {
- let pre = container.createEl("pre", { cls: ["dataview", "dataview-error"] });
- pre.appendText(error);
- return pre;
- }
- function renderCodeBlock(container, source, language) {
- let code = container.createEl("code", { cls: ["dataview"] });
- if (language)
- code.classList.add("language-" + language);
- code.appendText(source);
- return code;
- }
- async function renderValue(app, field, container, originFile, component, settings, expandList = false, context = "root", depth = 0, isInlineFieldLivePreview = false) {
-
- if (depth > settings.maxRecursiveRenderDepth) {
- container.appendText("...");
- return;
- }
- if (Values.isNull(field)) {
- await renderCompactMarkdown(app, settings.renderNullAs, container, originFile, component, isInlineFieldLivePreview);
- }
- else if (Values.isDate(field)) {
- container.appendText(renderMinimalDate(field, settings, currentLocale()));
- }
- else if (Values.isDuration(field)) {
- container.appendText(renderMinimalDuration(field));
- }
- else if (Values.isString(field) || Values.isBoolean(field) || Values.isNumber(field)) {
- await renderCompactMarkdown(app, "" + field, container, originFile, component, isInlineFieldLivePreview);
- }
- else if (Values.isLink(field)) {
- await renderCompactMarkdown(app, field.markdown(), container, originFile, component, isInlineFieldLivePreview);
- }
- else if (Values.isHtml(field)) {
- container.appendChild(field);
- }
- else if (Values.isWidget(field)) {
- if (Widgets.isListPair(field)) {
- await renderValue(app, field.key, container, originFile, component, settings, expandList, context, depth, isInlineFieldLivePreview);
- container.appendText(": ");
- await renderValue(app, field.value, container, originFile, component, settings, expandList, context, depth, isInlineFieldLivePreview);
- }
- else if (Widgets.isExternalLink(field)) {
- let elem = document.createElement("a");
- elem.textContent = field.display ?? field.url;
- elem.rel = "noopener";
- elem.target = "_blank";
- elem.classList.add("external-link");
- elem.href = field.url;
- container.appendChild(elem);
- }
- else {
- container.appendText(`<unknown widget '${field.$widget}>`);
- }
- }
- else if (Values.isFunction(field)) {
- container.appendText("<function>");
- }
- else if (Values.isArray(field) || DataArray.isDataArray(field)) {
- if (expandList) {
- let list = container.createEl("ul", {
- cls: [
- "dataview",
- "dataview-ul",
- context == "list" ? "dataview-result-list-ul" : "dataview-result-list-root-ul",
- ],
- });
- for (let child of field) {
- let li = list.createEl("li", { cls: "dataview-result-list-li" });
- await renderValue(app, child, li, originFile, component, settings, expandList, "list", depth + 1, isInlineFieldLivePreview);
- }
- }
- else {
- if (field.length == 0) {
- container.appendText("<empty list>");
- return;
- }
- let span = container.createEl("span", { cls: ["dataview", "dataview-result-list-span"] });
- let first = true;
- for (let val of field) {
- if (first)
- first = false;
- else
- span.appendText(", ");
- await renderValue(app, val, span, originFile, component, settings, expandList, "list", depth + 1, isInlineFieldLivePreview);
- }
- }
- }
- else if (Values.isObject(field)) {
-
- if (field?.constructor?.name && field?.constructor?.name != "Object") {
- container.appendText(`<${field.constructor.name}>`);
- return;
- }
- if (expandList) {
- let list = container.createEl("ul", { cls: ["dataview", "dataview-ul", "dataview-result-object-ul"] });
- for (let [key, value] of Object.entries(field)) {
- let li = list.createEl("li", { cls: ["dataview", "dataview-li", "dataview-result-object-li"] });
- li.appendText(key + ": ");
- await renderValue(app, value, li, originFile, component, settings, expandList, "list", depth + 1, isInlineFieldLivePreview);
- }
- }
- else {
- if (Object.keys(field).length == 0) {
- container.appendText("<empty object>");
- return;
- }
- let span = container.createEl("span", { cls: ["dataview", "dataview-result-object-span"] });
- let first = true;
- for (let [key, value] of Object.entries(field)) {
- if (first)
- first = false;
- else
- span.appendText(", ");
- span.appendText(key + ": ");
- await renderValue(app, value, span, originFile, component, settings, expandList, "list", depth + 1, isInlineFieldLivePreview);
- }
- }
- }
- else {
- container.appendText("Unrecognized: " + JSON.stringify(field));
- }
- }
- var papaparse_min = {exports: {}};
- papaparse_min.exports;
- (function (module, exports) {
- !function(e,t){module.exports=t();}(commonjsGlobal,function s(){var f="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==f?f:{};var n=!f.document&&!!f.postMessage,o=f.IS_PAPA_WORKER||!1,a={},u=0,b={parse:function(e,t){var r=(t=t||{}).dynamicTyping||!1;J(r)&&(t.dynamicTypingFunction=r,r={});if(t.dynamicTyping=r,t.transform=!!J(t.transform)&&t.transform,t.worker&&b.WORKERS_SUPPORTED){var i=function(){if(!b.WORKERS_SUPPORTED)return !1;var e=(r=f.URL||f.webkitURL||null,i=s.toString(),b.BLOB_URL||(b.BLOB_URL=r.createObjectURL(new Blob(["var global = (function() { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } return {}; })(); global.IS_PAPA_WORKER=true; ","(",i,")();"],{type:"text/javascript"})))),t=new f.Worker(e);var r,i;return t.onmessage=_,t.id=u++,a[t.id]=t}();return i.userStep=t.step,i.userChunk=t.chunk,i.userComplete=t.complete,i.userError=t.error,t.step=J(t.step),t.chunk=J(t.chunk),t.complete=J(t.complete),t.error=J(t.error),delete t.worker,void i.postMessage({input:e,config:t,workerId:i.id})}var n=null;b.NODE_STREAM_INPUT,"string"==typeof e?(e=function(e){if(65279===e.charCodeAt(0))return e.slice(1);return e}(e),n=t.download?new l(t):new p(t)):!0===e.readable&&J(e.read)&&J(e.on)?n=new g(t):(f.File&&e instanceof File||e instanceof Object)&&(n=new c(t));return n.stream(e)},unparse:function(e,t){var n=!1,_=!0,m=",",y="\r\n",s='"',a=s+s,r=!1,i=null,o=!1;!function(){if("object"!=typeof t)return;"string"!=typeof t.delimiter||b.BAD_DELIMITERS.filter(function(e){return -1!==t.delimiter.indexOf(e)}).length||(m=t.delimiter);("boolean"==typeof t.quotes||"function"==typeof t.quotes||Array.isArray(t.quotes))&&(n=t.quotes);"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(r=t.skipEmptyLines);"string"==typeof t.newline&&(y=t.newline);"string"==typeof t.quoteChar&&(s=t.quoteChar);"boolean"==typeof t.header&&(_=t.header);if(Array.isArray(t.columns)){if(0===t.columns.length)throw new Error("Option columns is empty");i=t.columns;}void 0!==t.escapeChar&&(a=t.escapeChar+s);("boolean"==typeof t.escapeFormulae||t.escapeFormulae instanceof RegExp)&&(o=t.escapeFormulae instanceof RegExp?t.escapeFormulae:/^[=+\-@\t\r].*$/);}();var u=new RegExp(Q(s),"g");"string"==typeof e&&(e=JSON.parse(e));if(Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return h(null,e,r);if("object"==typeof e[0])return h(i||Object.keys(e[0]),e,r)}else if("object"==typeof e)return "string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields||i),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:"object"==typeof e.data[0]?Object.keys(e.data[0]):[]),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),h(e.fields||[],e.data||[],r);throw new Error("Unable to serialize unrecognized input");function h(e,t,r){var i="";"string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t));var n=Array.isArray(e)&&0<e.length,s=!Array.isArray(t[0]);if(n&&_){for(var a=0;a<e.length;a++)0<a&&(i+=m),i+=v(e[a],a);0<t.length&&(i+=y);}for(var o=0;o<t.length;o++){var u=n?e.length:t[o].length,h=!1,f=n?0===Object.keys(t[o]).length:0===t[o].length;if(r&&!n&&(h="greedy"===r?""===t[o].join("").trim():1===t[o].length&&0===t[o][0].length),"greedy"===r&&n){for(var d=[],l=0;l<u;l++){var c=s?e[l]:l;d.push(t[o][c]);}h=""===d.join("").trim();}if(!h){for(var p=0;p<u;p++){0<p&&!f&&(i+=m);var g=n&&s?e[p]:p;i+=v(t[o][g],p);}o<t.length-1&&(!r||0<u&&!f)&&(i+=y);}}return i}function v(e,t){if(null==e)return "";if(e.constructor===Date)return JSON.stringify(e).slice(1,25);var r=!1;o&&"string"==typeof e&&o.test(e)&&(e="'"+e,r=!0);var i=e.toString().replace(u,a);return (r=r||!0===n||"function"==typeof n&&n(e,t)||Array.isArray(n)&&n[t]||function(e,t){for(var r=0;r<t.length;r++)if(-1<e.indexOf(t[r]))return !0;return !1}(i,b.BAD_DELIMITERS)||-1<i.indexOf(m)||" "===i.charAt(0)||" "===i.charAt(i.length-1))?s+i+s:i}}};if(b.RECORD_SEP=String.fromCharCode(30),b.UNIT_SEP=String.fromCharCode(31),b.BYTE_ORDER_MARK="\ufeff",b.BAD_DELIMITERS=["\r","\n",'"',b.BYTE_ORDER_MARK],b.WORKERS_SUPPORTED=!n&&!!f.Worker,b.NODE_STREAM_INPUT=1,b.LocalChunkSize=10485760,b.RemoteChunkSize=5242880,b.DefaultDelimiter=",",b.Parser=E,b.ParserHandle=r,b.NetworkStreamer=l,b.FileStreamer=c,b.StringStreamer=p,b.ReadableStreamStreamer=g,f.jQuery){var d=f.jQuery;d.fn.parse=function(o){var r=o.config||{},u=[];return this.each(function(e){if(!("INPUT"===d(this).prop("tagName").toUpperCase()&&"file"===d(this).attr("type").toLowerCase()&&f.FileReader)||!this.files||0===this.files.length)return !0;for(var t=0;t<this.files.length;t++)u.push({file:this.files[t],inputElem:this,instanceConfig:d.extend({},r)});}),e(),this;function e(){if(0!==u.length){var e,t,r,i,n=u[0];if(J(o.before)){var s=o.before(n.file,n.inputElem);if("object"==typeof s){if("abort"===s.action)return e="AbortError",t=n.file,r=n.inputElem,i=s.reason,void(J(o.error)&&o.error({name:e},t,r,i));if("skip"===s.action)return void h();"object"==typeof s.config&&(n.instanceConfig=d.extend(n.instanceConfig,s.config));}else if("skip"===s)return void h()}var a=n.instanceConfig.complete;n.instanceConfig.complete=function(e){J(a)&&a(e,n.file,n.inputElem),h();},b.parse(n.file,n.instanceConfig);}else J(o.complete)&&o.complete();}function h(){u.splice(0,1),e();}};}function h(e){this._handle=null,this._finished=!1,this._completed=!1,this._halted=!1,this._input=null,this._baseIndex=0,this._partialLine="",this._rowCount=0,this._start=0,this._nextChunk=null,this.isFirstChunk=!0,this._completeResults={data:[],errors:[],meta:{}},function(e){var t=w(e);t.chunkSize=parseInt(t.chunkSize),e.step||e.chunk||(t.chunkSize=null);this._handle=new r(t),(this._handle.streamer=this)._config=t;}.call(this,e),this.parseChunk=function(e,t){if(this.isFirstChunk&&J(this._config.beforeFirstChunk)){var r=this._config.beforeFirstChunk(e);void 0!==r&&(e=r);}this.isFirstChunk=!1,this._halted=!1;var i=this._partialLine+e;this._partialLine="";var n=this._handle.parse(i,this._baseIndex,!this._finished);if(!this._handle.paused()&&!this._handle.aborted()){var s=n.meta.cursor;this._finished||(this._partialLine=i.substring(s-this._baseIndex),this._baseIndex=s),n&&n.data&&(this._rowCount+=n.data.length);var a=this._finished||this._config.preview&&this._rowCount>=this._config.preview;if(o)f.postMessage({results:n,workerId:b.WORKER_ID,finished:a});else if(J(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0;}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!J(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0;},this._sendError=function(e){J(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:b.WORKER_ID,error:e,finished:!1});};}function l(e){var i;(e=e||{}).chunkSize||(e.chunkSize=b.RemoteChunkSize),h.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded();}:function(){this._readChunk();},this.stream=function(e){this._input=e,this._nextChunk();},this._readChunk=function(){if(this._finished)this._chunkLoaded();else {if(i=new XMLHttpRequest,this._config.withCredentials&&(i.withCredentials=this._config.withCredentials),n||(i.onload=v(this._chunkLoaded,this),i.onerror=v(this._chunkError,this)),i.open(this._config.downloadRequestBody?"POST":"GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)i.setRequestHeader(t,e[t]);}if(this._config.chunkSize){var r=this._start+this._config.chunkSize-1;i.setRequestHeader("Range","bytes="+this._start+"-"+r);}try{i.send(this._config.downloadRequestBody);}catch(e){this._chunkError(e.message);}n&&0===i.status&&this._chunkError();}},this._chunkLoaded=function(){4===i.readyState&&(i.status<200||400<=i.status?this._chunkError():(this._start+=this._config.chunkSize?this._config.chunkSize:i.responseText.length,this._finished=!this._config.chunkSize||this._start>=function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return -1;return parseInt(t.substring(t.lastIndexOf("/")+1))}(i),this.parseChunk(i.responseText)));},this._chunkError=function(e){var t=i.statusText||e;this._sendError(new Error(t));};}function c(e){var i,n;(e=e||{}).chunkSize||(e.chunkSize=b.LocalChunkSize),h.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((i=new FileReader).onload=v(this._chunkLoaded,this),i.onerror=v(this._chunkError,this)):i=new FileReaderSync,this._nextChunk();},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount<this._config.preview)||this._readChunk();},this._readChunk=function(){var e=this._input;if(this._config.chunkSize){var t=Math.min(this._start+this._config.chunkSize,this._input.size);e=n.call(e,this._start,t);}var r=i.readAsText(e,this._config.encoding);s||this._chunkLoaded({target:{result:r}});},this._chunkLoaded=function(e){this._start+=this._config.chunkSize,this._finished=!this._config.chunkSize||this._start>=this._input.size,this.parseChunk(e.target.result);},this._chunkError=function(){this._sendError(i.error);};}function p(e){var r;h.call(this,e=e||{}),this.stream=function(e){return r=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e,t=this._config.chunkSize;return t?(e=r.substring(0,t),r=r.substring(t)):(e=r,r=""),this._finished=!r,this.parseChunk(e)}};}function g(e){h.call(this,e=e||{});var t=[],r=!0,i=!1;this.pause=function(){h.prototype.pause.apply(this,arguments),this._input.pause();},this.resume=function(){h.prototype.resume.apply(this,arguments),this._input.resume();},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError);},this._checkIsFinished=function(){i&&1===t.length&&(this._finished=!0);},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):r=!0;},this._streamData=v(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),r&&(r=!1,this._checkIsFinished(),this.parseChunk(t.shift()));}catch(e){this._streamError(e);}},this),this._streamError=v(function(e){this._streamCleanUp(),this._sendError(e);},this),this._streamEnd=v(function(){this._streamCleanUp(),i=!0,this._streamData("");},this),this._streamCleanUp=v(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError);},this);}function r(m){var a,o,u,i=Math.pow(2,53),n=-i,s=/^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/,h=/^((\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)))$/,t=this,r=0,f=0,d=!1,e=!1,l=[],c={data:[],errors:[],meta:{}};if(J(m.step)){var p=m.step;m.step=function(e){if(c=e,_())g();else {if(g(),0===c.data.length)return;r+=e.data.length,m.preview&&r>m.preview?o.abort():(c.data=c.data[0],p(c,t));}};}function y(e){return "greedy"===m.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function g(){return c&&u&&(k("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+b.DefaultDelimiter+"'"),u=!1),m.skipEmptyLines&&(c.data=c.data.filter(function(e){return !y(e)})),_()&&function(){if(!c)return;function e(e,t){J(m.transformHeader)&&(e=m.transformHeader(e,t)),l.push(e);}if(Array.isArray(c.data[0])){for(var t=0;_()&&t<c.data.length;t++)c.data[t].forEach(e);c.data.splice(0,1);}else c.data.forEach(e);}(),function(){if(!c||!m.header&&!m.dynamicTyping&&!m.transform)return c;function e(e,t){var r,i=m.header?{}:[];for(r=0;r<e.length;r++){var n=r,s=e[r];m.header&&(n=r>=l.length?"__parsed_extra":l[r]),m.transform&&(s=m.transform(s,n)),s=v(n,s),"__parsed_extra"===n?(i[n]=i[n]||[],i[n].push(s)):i[n]=s;}return m.header&&(r>l.length?k("FieldMismatch","TooManyFields","Too many fields: expected "+l.length+" fields but parsed "+r,f+t):r<l.length&&k("FieldMismatch","TooFewFields","Too few fields: expected "+l.length+" fields but parsed "+r,f+t)),i}var t=1;!c.data.length||Array.isArray(c.data[0])?(c.data=c.data.map(e),t=c.data.length):c.data=e(c.data,0);m.header&&c.meta&&(c.meta.fields=l);return f+=t,c}()}function _(){return m.header&&0===l.length}function v(e,t){return r=e,m.dynamicTypingFunction&&void 0===m.dynamicTyping[r]&&(m.dynamicTyping[r]=m.dynamicTypingFunction(r)),!0===(m.dynamicTyping[r]||m.dynamicTyping)?"true"===t||"TRUE"===t||"false"!==t&&"FALSE"!==t&&(function(e){if(s.test(e)){var t=parseFloat(e);if(n<t&&t<i)return !0}return !1}(t)?parseFloat(t):h.test(t)?new Date(t):""===t?null:t):t;var r;}function k(e,t,r,i){var n={type:e,code:t,message:r};void 0!==i&&(n.row=i),c.errors.push(n);}this.parse=function(e,t,r){var i=m.quoteChar||'"';if(m.newline||(m.newline=function(e,t){e=e.substring(0,1048576);var r=new RegExp(Q(t)+"([^]*?)"+Q(t),"gm"),i=(e=e.replace(r,"")).split("\r"),n=e.split("\n"),s=1<n.length&&n[0].length<i[0].length;if(1===i.length||s)return "\n";for(var a=0,o=0;o<i.length;o++)"\n"===i[o][0]&&a++;return a>=i.length/2?"\r\n":"\r"}(e,i)),u=!1,m.delimiter)J(m.delimiter)&&(m.delimiter=m.delimiter(e),c.meta.delimiter=m.delimiter);else {var n=function(e,t,r,i,n){var s,a,o,u;n=n||[",","\t","|",";",b.RECORD_SEP,b.UNIT_SEP];for(var h=0;h<n.length;h++){var f=n[h],d=0,l=0,c=0;o=void 0;for(var p=new E({comments:i,delimiter:f,newline:t,preview:10}).parse(e),g=0;g<p.data.length;g++)if(r&&y(p.data[g]))c++;else {var _=p.data[g].length;l+=_,void 0!==o?0<_&&(d+=Math.abs(_-o),o=_):o=_;}0<p.data.length&&(l/=p.data.length-c),(void 0===a||d<=a)&&(void 0===u||u<l)&&1.99<l&&(a=d,s=f,u=l);}return {successful:!!(m.delimiter=s),bestDelimiter:s}}(e,m.newline,m.skipEmptyLines,m.comments,m.delimitersToGuess);n.successful?m.delimiter=n.bestDelimiter:(u=!0,m.delimiter=b.DefaultDelimiter),c.meta.delimiter=m.delimiter;}var s=w(m);return m.preview&&m.header&&s.preview++,a=e,o=new E(s),c=o.parse(a,t,r),g(),d?{meta:{paused:!0}}:c||{meta:{paused:!1}}},this.paused=function(){return d},this.pause=function(){d=!0,o.abort(),a=J(m.chunk)?"":a.substring(o.getCharIndex());},this.resume=function(){t.streamer._halted?(d=!1,t.streamer.parseChunk(a,!0)):setTimeout(t.resume,3);},this.aborted=function(){return e},this.abort=function(){e=!0,o.abort(),c.meta.aborted=!0,J(m.complete)&&m.complete(c),a="";};}function Q(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function E(j){var z,M=(j=j||{}).delimiter,P=j.newline,U=j.comments,q=j.step,N=j.preview,B=j.fastMode,K=z=void 0===j.quoteChar||null===j.quoteChar?'"':j.quoteChar;if(void 0!==j.escapeChar&&(K=j.escapeChar),("string"!=typeof M||-1<b.BAD_DELIMITERS.indexOf(M))&&(M=","),U===M)throw new Error("Comment character same as delimiter");!0===U?U="#":("string"!=typeof U||-1<b.BAD_DELIMITERS.indexOf(U))&&(U=!1),"\n"!==P&&"\r"!==P&&"\r\n"!==P&&(P="\n");var W=0,H=!1;this.parse=function(i,t,r){if("string"!=typeof i)throw new Error("Input must be a string");var n=i.length,e=M.length,s=P.length,a=U.length,o=J(q),u=[],h=[],f=[],d=W=0;if(!i)return L();if(j.header&&!t){var l=i.split(P)[0].split(M),c=[],p={},g=!1;for(var _ in l){var m=l[_];J(j.transformHeader)&&(m=j.transformHeader(m,_));var y=m,v=p[m]||0;for(0<v&&(g=!0,y=m+"_"+v),p[m]=v+1;c.includes(y);)y=y+"_"+v;c.push(y);}if(g){var k=i.split(P);k[0]=c.join(M),i=k.join(P);}}if(B||!1!==B&&-1===i.indexOf(z)){for(var b=i.split(P),E=0;E<b.length;E++){if(f=b[E],W+=f.length,E!==b.length-1)W+=P.length;else if(r)return L();if(!U||f.substring(0,a)!==U){if(o){if(u=[],I(f.split(M)),F(),H)return L()}else I(f.split(M));if(N&&N<=E)return u=u.slice(0,N),L(!0)}}return L()}for(var w=i.indexOf(M,W),R=i.indexOf(P,W),C=new RegExp(Q(K)+Q(z),"g"),S=i.indexOf(z,W);;)if(i[W]!==z)if(U&&0===f.length&&i.substring(W,W+a)===U){if(-1===R)return L();W=R+s,R=i.indexOf(P,W),w=i.indexOf(M,W);}else if(-1!==w&&(w<R||-1===R))f.push(i.substring(W,w)),W=w+e,w=i.indexOf(M,W);else {if(-1===R)break;if(f.push(i.substring(W,R)),D(R+s),o&&(F(),H))return L();if(N&&u.length>=N)return L(!0)}else for(S=W,W++;;){if(-1===(S=i.indexOf(z,S+1)))return r||h.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:u.length,index:W}),T();if(S===n-1)return T(i.substring(W,S).replace(C,z));if(z!==K||i[S+1]!==K){if(z===K||0===S||i[S-1]!==K){-1!==w&&w<S+1&&(w=i.indexOf(M,S+1)),-1!==R&&R<S+1&&(R=i.indexOf(P,S+1));var O=A(-1===R?w:Math.min(w,R));if(i.substr(S+1+O,e)===M){f.push(i.substring(W,S).replace(C,z)),i[W=S+1+O+e]!==z&&(S=i.indexOf(z,W)),w=i.indexOf(M,W),R=i.indexOf(P,W);break}var x=A(R);if(i.substring(S+1+x,S+1+x+s)===P){if(f.push(i.substring(W,S).replace(C,z)),D(S+1+x+s),w=i.indexOf(M,W),S=i.indexOf(z,W),o&&(F(),H))return L();if(N&&u.length>=N)return L(!0);break}h.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:u.length,index:W}),S++;}}else S++;}return T();function I(e){u.push(e),d=W;}function A(e){var t=0;if(-1!==e){var r=i.substring(S+1,e);r&&""===r.trim()&&(t=r.length);}return t}function T(e){return r||(void 0===e&&(e=i.substring(W)),f.push(e),W=n,I(f),o&&F()),L()}function D(e){W=e,I(f),f=[],R=i.indexOf(P,W);}function L(e){return {data:u,errors:h,meta:{delimiter:M,linebreak:P,aborted:H,truncated:!!e,cursor:d+(t||0)}}}function F(){q(L()),u=[],h=[];}},this.abort=function(){H=!0;},this.getCharIndex=function(){return W};}function _(e){var t=e.data,r=a[t.workerId],i=!1;if(t.error)r.userError(t.error,t.file);else if(t.results&&t.results.data){var n={abort:function(){i=!0,m(t.workerId,{data:[],errors:[],meta:{aborted:!0}});},pause:y,resume:y};if(J(r.userStep)){for(var s=0;s<t.results.data.length&&(r.userStep({data:t.results.data[s],errors:t.results.errors,meta:t.results.meta},n),!i);s++);delete t.results;}else J(r.userChunk)&&(r.userChunk(t.results,n,t.file),delete t.results);}t.finished&&!i&&m(t.workerId,t.results);}function m(e,t){var r=a[e];J(r.userComplete)&&r.userComplete(t),r.terminate(),delete a[e];}function y(){throw new Error("Not implemented.")}function w(e){if("object"!=typeof e||null===e)return e;var t=Array.isArray(e)?[]:{};for(var r in e)t[r]=w(e[r]);return t}function v(e,t){return function(){e.apply(t,arguments);}}function J(e){return "function"==typeof e}return o&&(f.onmessage=function(e){var t=e.data;void 0===b.WORKER_ID&&t&&(b.WORKER_ID=t.workerId);if("string"==typeof t.input)f.postMessage({workerId:b.WORKER_ID,results:b.parse(t.input,t.config),finished:!0});else if(f.File&&t.input instanceof File||t.input instanceof Object){var r=b.parse(t.input,t.config);r&&f.postMessage({workerId:b.WORKER_ID,results:r,finished:!0});}}),(l.prototype=Object.create(h.prototype)).constructor=l,(c.prototype=Object.create(h.prototype)).constructor=c,(p.prototype=Object.create(p.prototype)).constructor=p,(g.prototype=Object.create(h.prototype)).constructor=g,b});
- } (papaparse_min, papaparse_min.exports));
- var papaparse_minExports = papaparse_min.exports;
- var Fields;
- (function (Fields) {
- function variable(name) {
- return { type: "variable", name };
- }
- Fields.variable = variable;
- function literal(value) {
- return { type: "literal", value };
- }
- Fields.literal = literal;
- function binaryOp(left, op, right) {
- return { type: "binaryop", left, op, right };
- }
- Fields.binaryOp = binaryOp;
- function index(obj, index) {
- return { type: "index", object: obj, index };
- }
- Fields.index = index;
-
- function indexVariable(name) {
- let parts = name.split(".");
- let result = Fields.variable(parts[0]);
- for (let index = 1; index < parts.length; index++) {
- result = Fields.index(result, Fields.literal(parts[index]));
- }
- return result;
- }
- Fields.indexVariable = indexVariable;
- function lambda(args, value) {
- return { type: "lambda", arguments: args, value };
- }
- Fields.lambda = lambda;
- function func(func, args) {
- return { type: "function", func, arguments: args };
- }
- Fields.func = func;
- function list(values) {
- return { type: "list", values };
- }
- Fields.list = list;
- function object(values) {
- return { type: "object", values };
- }
- Fields.object = object;
- function negate(child) {
- return { type: "negated", child };
- }
- Fields.negate = negate;
- function isCompareOp(op) {
- return op == "<=" || op == "<" || op == ">" || op == ">=" || op == "!=" || op == "=";
- }
- Fields.isCompareOp = isCompareOp;
- Fields.NULL = Fields.literal(null);
- })(Fields || (Fields = {}));
- var Sources;
- (function (Sources) {
-
- function tag(tag) {
- return { type: "tag", tag };
- }
- Sources.tag = tag;
-
- function csv(path) {
- return { type: "csv", path };
- }
- Sources.csv = csv;
-
- function folder(prefix) {
- return { type: "folder", folder: prefix };
- }
- Sources.folder = folder;
-
- function link(file, incoming) {
- return { type: "link", file, direction: incoming ? "incoming" : "outgoing" };
- }
- Sources.link = link;
-
- function binaryOp(left, op, right) {
- return { type: "binaryop", left, op, right };
- }
- Sources.binaryOp = binaryOp;
-
- function and(left, right) {
- return { type: "binaryop", left, op: "&", right };
- }
- Sources.and = and;
-
- function or(left, right) {
- return { type: "binaryop", left, op: "|", right };
- }
- Sources.or = or;
-
- function negate(child) {
- return { type: "negate", child };
- }
- Sources.negate = negate;
- function empty() {
- return { type: "empty" };
- }
- Sources.empty = empty;
- })(Sources || (Sources = {}));
- const EMOJI_REGEX = new RegExp(emojiRegex(), "");
- const DURATION_TYPES = {
- year: Duration.fromObject({ years: 1 }),
- years: Duration.fromObject({ years: 1 }),
- yr: Duration.fromObject({ years: 1 }),
- yrs: Duration.fromObject({ years: 1 }),
- month: Duration.fromObject({ months: 1 }),
- months: Duration.fromObject({ months: 1 }),
- mo: Duration.fromObject({ months: 1 }),
- mos: Duration.fromObject({ months: 1 }),
- week: Duration.fromObject({ weeks: 1 }),
- weeks: Duration.fromObject({ weeks: 1 }),
- wk: Duration.fromObject({ weeks: 1 }),
- wks: Duration.fromObject({ weeks: 1 }),
- w: Duration.fromObject({ weeks: 1 }),
- day: Duration.fromObject({ days: 1 }),
- days: Duration.fromObject({ days: 1 }),
- d: Duration.fromObject({ days: 1 }),
- hour: Duration.fromObject({ hours: 1 }),
- hours: Duration.fromObject({ hours: 1 }),
- hr: Duration.fromObject({ hours: 1 }),
- hrs: Duration.fromObject({ hours: 1 }),
- h: Duration.fromObject({ hours: 1 }),
- minute: Duration.fromObject({ minutes: 1 }),
- minutes: Duration.fromObject({ minutes: 1 }),
- min: Duration.fromObject({ minutes: 1 }),
- mins: Duration.fromObject({ minutes: 1 }),
- m: Duration.fromObject({ minutes: 1 }),
- second: Duration.fromObject({ seconds: 1 }),
- seconds: Duration.fromObject({ seconds: 1 }),
- sec: Duration.fromObject({ seconds: 1 }),
- secs: Duration.fromObject({ seconds: 1 }),
- s: Duration.fromObject({ seconds: 1 }),
- };
- const DATE_SHORTHANDS = {
- now: () => DateTime.local(),
- today: () => DateTime.local().startOf("day"),
- yesterday: () => DateTime.local()
- .startOf("day")
- .minus(Duration.fromObject({ days: 1 })),
- tomorrow: () => DateTime.local()
- .startOf("day")
- .plus(Duration.fromObject({ days: 1 })),
- sow: () => DateTime.local().startOf("week"),
- "start-of-week": () => DateTime.local().startOf("week"),
- eow: () => DateTime.local().endOf("week"),
- "end-of-week": () => DateTime.local().endOf("week"),
- soy: () => DateTime.local().startOf("year"),
- "start-of-year": () => DateTime.local().startOf("year"),
- eoy: () => DateTime.local().endOf("year"),
- "end-of-year": () => DateTime.local().endOf("year"),
- som: () => DateTime.local().startOf("month"),
- "start-of-month": () => DateTime.local().startOf("month"),
- eom: () => DateTime.local().endOf("month"),
- "end-of-month": () => DateTime.local().endOf("month"),
- };
- const KEYWORDS = ["FROM", "WHERE", "LIMIT", "GROUP", "FLATTEN"];
- function splitOnUnescapedPipe(link) {
- let pipe = -1;
- while ((pipe = link.indexOf("|", pipe + 1)) >= 0) {
- if (pipe > 0 && link[pipe - 1] == "\\")
- continue;
- return [link.substring(0, pipe).replace(/\\\|/g, "|"), link.substring(pipe + 1)];
- }
- return [link.replace(/\\\|/g, "|"), undefined];
- }
- function parseInnerLink(rawlink) {
- let [link, display] = splitOnUnescapedPipe(rawlink);
- return Link.infer(link, false, display);
- }
- function createBinaryParser(child, sep, combine) {
- return parsimmon_umd_minExports.seqMap(child, parsimmon_umd_minExports.seq(parsimmon_umd_minExports.optWhitespace, sep, parsimmon_umd_minExports.optWhitespace, child).many(), (first, rest) => {
- if (rest.length == 0)
- return first;
- let node = combine(first, rest[0][1], rest[0][3]);
- for (let index = 1; index < rest.length; index++) {
- node = combine(node, rest[index][1], rest[index][3]);
- }
- return node;
- });
- }
- function chainOpt(base, ...funcs) {
- return parsimmon_umd_minExports.custom((success, failure) => {
- return (input, i) => {
- let result = base._(input, i);
- if (!result.status)
- return result;
- for (let func of funcs) {
- let next = func(result.value)._(input, result.index);
- if (!next.status)
- return result;
- result = next;
- }
- return result;
- };
- });
- }
- const EXPRESSION = parsimmon_umd_minExports.createLanguage({
-
- number: q => parsimmon_umd_minExports.regexp(/-?[0-9]+(\.[0-9]+)?/)
- .map(str => Number.parseFloat(str))
- .desc("number"),
-
- string: q => parsimmon_umd_minExports.string('"')
- .then(parsimmon_umd_minExports.alt(q.escapeCharacter, parsimmon_umd_minExports.noneOf('"\\'))
- .atLeast(0)
- .map(chars => chars.join("")))
- .skip(parsimmon_umd_minExports.string('"'))
- .desc("string"),
- escapeCharacter: _ => parsimmon_umd_minExports.string("\\")
- .then(parsimmon_umd_minExports.any)
- .map(escaped => {
-
- if (escaped === '"')
- return '"';
- if (escaped === "\\")
- return "\\";
- else
- return "\\" + escaped;
- }),
-
- bool: _ => parsimmon_umd_minExports.regexp(/true|false|True|False/)
- .map(str => str.toLowerCase() == "true")
- .desc("boolean ('true' or 'false')"),
-
- tag: _ => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("#"), parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(/[^\u2000-\u206F\u2E00-\u2E7F'!"#$%&()*+,.:;<=>?@^`{|}~\[\]\\\s]/).desc("text")).many(), (start, rest) => start + rest.join("")).desc("tag ('#hello/stuff')"),
-
- identifier: _ => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(/\p{Letter}/u), parsimmon_umd_minExports.regexp(EMOJI_REGEX).desc("text")), parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(/[0-9\p{Letter}_-]/u), parsimmon_umd_minExports.regexp(EMOJI_REGEX).desc("text")).many(), (first, rest) => first + rest.join("")).desc("variable identifier"),
-
- link: _ => parsimmon_umd_minExports.regexp(/\[\[([^\[\]]*?)\]\]/u, 1)
- .map(linkInner => parseInnerLink(linkInner))
- .desc("file link"),
-
-
- embedLink: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("!").atMost(1), q.link, (p, l) => {
- if (p.length > 0)
- l.embed = true;
- return l;
- }).desc("file link"),
-
- binaryPlusMinus: _ => parsimmon_umd_minExports.regexp(/\+|-/)
- .map(str => str)
- .desc("'+' or '-'"),
-
- binaryMulDiv: _ => parsimmon_umd_minExports.regexp(/\*|\/|%/)
- .map(str => str)
- .desc("'*' or '/' or '%'"),
-
- binaryCompareOp: _ => parsimmon_umd_minExports.regexp(/>=|<=|!=|>|<|=/)
- .map(str => str)
- .desc("'>=' or '<=' or '!=' or '=' or '>' or '<'"),
-
- binaryBooleanOp: _ => parsimmon_umd_minExports.regexp(/and|or|&|\|/i)
- .map(str => {
- if (str.toLowerCase() == "and")
- return "&";
- else if (str.toLowerCase() == "or")
- return "|";
- else
- return str;
- })
- .desc("'and' or 'or'"),
-
- rootDate: _ => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/\d{4}/), parsimmon_umd_minExports.string("-"), parsimmon_umd_minExports.regexp(/\d{2}/), (year, _, month) => {
- return DateTime.fromObject({ year: Number.parseInt(year), month: Number.parseInt(month) });
- }).desc("date in format YYYY-MM[-DDTHH-MM-SS.MS]"),
- dateShorthand: _ => parsimmon_umd_minExports.alt(...Object.keys(DATE_SHORTHANDS)
- .sort((a, b) => b.length - a.length)
- .map(parsimmon_umd_minExports.string)),
- date: q => chainOpt(q.rootDate, (ym) => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("-"), parsimmon_umd_minExports.regexp(/\d{2}/), (_, day) => ym.set({ day: Number.parseInt(day) })), (ymd) => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("T"), parsimmon_umd_minExports.regexp(/\d{2}/), (_, hour) => ymd.set({ hour: Number.parseInt(hour) })), (ymdh) => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string(":"), parsimmon_umd_minExports.regexp(/\d{2}/), (_, minute) => ymdh.set({ minute: Number.parseInt(minute) })), (ymdhm) => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string(":"), parsimmon_umd_minExports.regexp(/\d{2}/), (_, second) => ymdhm.set({ second: Number.parseInt(second) })), (ymdhms) => parsimmon_umd_minExports.alt(parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("."), parsimmon_umd_minExports.regexp(/\d{3}/), (_, millisecond) => ymdhms.set({ millisecond: Number.parseInt(millisecond) })), parsimmon_umd_minExports.succeed(ymdhms)
- ), (dt) => parsimmon_umd_minExports.alt(parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("+").or(parsimmon_umd_minExports.string("-")), parsimmon_umd_minExports.regexp(/\d{1,2}(:\d{2})?/), (pm, hr) => dt.setZone("UTC" + pm + hr, { keepLocalTime: true })), parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("Z"), () => dt.setZone("utc", { keepLocalTime: true })), parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("["), parsimmon_umd_minExports.regexp(/[0-9A-Za-z+-\/]+/u), parsimmon_umd_minExports.string("]"), (_a, zone, _b) => dt.setZone(zone, { keepLocalTime: true }))))
- .assert((dt) => dt.isValid, "valid date")
- .desc("date in format YYYY-MM[-DDTHH-MM-SS.MS]"),
-
- datePlus: q => parsimmon_umd_minExports.alt(q.dateShorthand.map(d => DATE_SHORTHANDS[d]()), q.date).desc("date in format YYYY-MM[-DDTHH-MM-SS.MS] or in shorthand"),
-
- durationType: _ => parsimmon_umd_minExports.alt(...Object.keys(DURATION_TYPES)
- .sort((a, b) => b.length - a.length)
- .map(parsimmon_umd_minExports.string)),
- duration: q => parsimmon_umd_minExports.seqMap(q.number, parsimmon_umd_minExports.optWhitespace, q.durationType, (count, _, t) => DURATION_TYPES[t].mapUnits(x => x * count))
- .sepBy1(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace).or(parsimmon_umd_minExports.optWhitespace))
- .map(durations => durations.reduce((p, c) => p.plus(c)))
- .desc("duration like 4hr2min"),
-
- rawNull: _ => parsimmon_umd_minExports.string("null"),
-
- tagSource: q => q.tag.map(tag => Sources.tag(tag)),
- csvSource: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("csv(").skip(parsimmon_umd_minExports.optWhitespace), q.string, parsimmon_umd_minExports.string(")"), (_1, path, _2) => Sources.csv(path)),
- linkIncomingSource: q => q.link.map(link => Sources.link(link.path, true)),
- linkOutgoingSource: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("outgoing(").skip(parsimmon_umd_minExports.optWhitespace), q.link, parsimmon_umd_minExports.string(")"), (_1, link, _2) => Sources.link(link.path, false)),
- folderSource: q => q.string.map(str => Sources.folder(str)),
- parensSource: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("("), parsimmon_umd_minExports.optWhitespace, q.source, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (_1, _2, field, _3, _4) => field),
- negateSource: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.alt(parsimmon_umd_minExports.string("-"), parsimmon_umd_minExports.string("!")), q.atomSource, (_, source) => Sources.negate(source)),
- atomSource: q => parsimmon_umd_minExports.alt(q.parensSource, q.negateSource, q.linkOutgoingSource, q.linkIncomingSource, q.folderSource, q.tagSource, q.csvSource),
- binaryOpSource: q => createBinaryParser(q.atomSource, q.binaryBooleanOp.map(s => s), Sources.binaryOp),
- source: q => q.binaryOpSource,
-
- variableField: q => q.identifier
- .chain(r => {
- if (KEYWORDS.includes(r.toUpperCase())) {
- return parsimmon_umd_minExports.fail("Variable fields cannot be a keyword (" + KEYWORDS.join(" or ") + ")");
- }
- else {
- return parsimmon_umd_minExports.succeed(Fields.variable(r));
- }
- })
- .desc("variable"),
- numberField: q => q.number.map(val => Fields.literal(val)).desc("number"),
- stringField: q => q.string.map(val => Fields.literal(val)).desc("string"),
- boolField: q => q.bool.map(val => Fields.literal(val)).desc("boolean"),
- dateField: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("date("), parsimmon_umd_minExports.optWhitespace, q.datePlus, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (prefix, _1, date, _2, postfix) => Fields.literal(date)).desc("date"),
- durationField: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("dur("), parsimmon_umd_minExports.optWhitespace, q.duration, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (prefix, _1, dur, _2, postfix) => Fields.literal(dur)).desc("duration"),
- nullField: q => q.rawNull.map(_ => Fields.NULL),
- linkField: q => q.link.map(f => Fields.literal(f)),
- listField: q => q.field
- .sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace))
- .wrap(parsimmon_umd_minExports.string("[").skip(parsimmon_umd_minExports.optWhitespace), parsimmon_umd_minExports.optWhitespace.then(parsimmon_umd_minExports.string("]")))
- .map(l => Fields.list(l))
- .desc("list ('[1, 2, 3]')"),
- objectField: q => parsimmon_umd_minExports.seqMap(q.identifier.or(q.string), parsimmon_umd_minExports.string(":").trim(parsimmon_umd_minExports.optWhitespace), q.field, (name, _sep, value) => {
- return { name, value };
- })
- .sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace))
- .wrap(parsimmon_umd_minExports.string("{").skip(parsimmon_umd_minExports.optWhitespace), parsimmon_umd_minExports.optWhitespace.then(parsimmon_umd_minExports.string("}")))
- .map(vals => {
- let res = {};
- for (let entry of vals)
- res[entry.name] = entry.value;
- return Fields.object(res);
- })
- .desc("object ('{ a: 1, b: 2 }')"),
- atomInlineField: q => parsimmon_umd_minExports.alt(q.date, q.duration.map(d => normalizeDuration(d)), q.string, q.tag, q.embedLink, q.bool, q.number, q.rawNull),
- inlineFieldList: q => q.atomInlineField.sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace).lookahead(q.atomInlineField)),
- inlineField: q => parsimmon_umd_minExports.alt(parsimmon_umd_minExports.seqMap(q.atomInlineField, parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace), q.inlineFieldList, (f, _s, l) => [f].concat(l)), q.atomInlineField),
- atomField: q => parsimmon_umd_minExports.alt(
-
- q.embedLink.map(l => Fields.literal(l)), q.negatedField, q.linkField, q.listField, q.objectField, q.lambdaField, q.parensField, q.boolField, q.numberField, q.stringField, q.dateField, q.durationField, q.nullField, q.variableField),
- indexField: q => parsimmon_umd_minExports.seqMap(q.atomField, parsimmon_umd_minExports.alt(q.dotPostfix, q.indexPostfix, q.functionPostfix).many(), (obj, postfixes) => {
- let result = obj;
- for (let post of postfixes) {
- switch (post.type) {
- case "dot":
- result = Fields.index(result, Fields.literal(post.field));
- break;
- case "index":
- result = Fields.index(result, post.field);
- break;
- case "function":
- result = Fields.func(result, post.fields);
- break;
- }
- }
- return result;
- }),
- negatedField: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("!"), q.indexField, (_, field) => Fields.negate(field)).desc("negated field"),
- parensField: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("("), parsimmon_umd_minExports.optWhitespace, q.field, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (_1, _2, field, _3, _4) => field),
- lambdaField: q => parsimmon_umd_minExports.seqMap(q.identifier
- .sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace))
- .wrap(parsimmon_umd_minExports.string("(").trim(parsimmon_umd_minExports.optWhitespace), parsimmon_umd_minExports.string(")").trim(parsimmon_umd_minExports.optWhitespace)), parsimmon_umd_minExports.string("=>").trim(parsimmon_umd_minExports.optWhitespace), q.field, (ident, _ignore, value) => {
- return { type: "lambda", arguments: ident, value };
- }),
- dotPostfix: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("."), q.identifier, (_, field) => {
- return { type: "dot", field: field };
- }),
- indexPostfix: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("["), parsimmon_umd_minExports.optWhitespace, q.field, parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string("]"), (_, _2, field, _3, _4) => {
- return { type: "index", field };
- }),
- functionPostfix: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.string("("), parsimmon_umd_minExports.optWhitespace, q.field.sepBy(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace)), parsimmon_umd_minExports.optWhitespace, parsimmon_umd_minExports.string(")"), (_, _1, fields, _2, _3) => {
- return { type: "function", fields };
- }),
-
- binaryMulDivField: q => createBinaryParser(q.indexField, q.binaryMulDiv, Fields.binaryOp),
- binaryPlusMinusField: q => createBinaryParser(q.binaryMulDivField, q.binaryPlusMinus, Fields.binaryOp),
- binaryCompareField: q => createBinaryParser(q.binaryPlusMinusField, q.binaryCompareOp, Fields.binaryOp),
- binaryBooleanField: q => createBinaryParser(q.binaryCompareField, q.binaryBooleanOp, Fields.binaryOp),
- binaryOpField: q => q.binaryBooleanField,
- field: q => q.binaryOpField,
- });
- function parseField(text) {
- try {
- return Result.success(EXPRESSION.field.tryParse(text));
- }
- catch (error) {
- return Result.failure("" + error);
- }
- }
- const INLINE_FIELD_WRAPPERS = Object.freeze({
- "[": "]",
- "(": ")",
- });
- function findClosing(line, start, open, close) {
- let nesting = 0;
- let escaped = false;
- for (let index = start; index < line.length; index++) {
- let char = line.charAt(index);
-
- if (char == "\\") {
- escaped = !escaped;
- continue;
- }
-
- if (escaped) {
- escaped = false;
- continue;
- }
- if (char == open)
- nesting++;
- else if (char == close)
- nesting--;
-
- if (nesting < 0)
- return { value: line.substring(start, index).trim(), endIndex: index + 1 };
- escaped = false;
- }
- return undefined;
- }
- function findSeparator(line, start) {
- let sep = line.indexOf("::", start);
- if (sep < 0)
- return undefined;
- return { key: line.substring(start, sep).trim(), valueIndex: sep + 2 };
- }
- function findSpecificInlineField(line, start) {
- let open = line.charAt(start);
- let key = findSeparator(line, start + 1);
- if (key === undefined)
- return undefined;
-
- for (let sep of Object.keys(INLINE_FIELD_WRAPPERS).concat(Object.values(INLINE_FIELD_WRAPPERS))) {
- if (key.key.includes(sep))
- return undefined;
- }
- let value = findClosing(line, key.valueIndex, open, INLINE_FIELD_WRAPPERS[open]);
- if (value === undefined)
- return undefined;
- return {
- key: key.key,
- value: value.value,
- start: start,
- startValue: key.valueIndex,
- end: value.endIndex,
- wrapping: open,
- };
- }
- function parseInlineValue(value) {
-
-
- if (value.trim() == "")
- return null;
-
-
-
- let inline = EXPRESSION.inlineField.parse(value);
- if (inline.status)
- return inline.value;
- else
- return value;
- }
- function extractInlineFields(line, includeTaskFields = false) {
- let fields = [];
- for (let wrapper of Object.keys(INLINE_FIELD_WRAPPERS)) {
- let foundIndex = line.indexOf(wrapper);
- while (foundIndex >= 0) {
- let parsedField = findSpecificInlineField(line, foundIndex);
- if (!parsedField) {
- foundIndex = line.indexOf(wrapper, foundIndex + 1);
- continue;
- }
- fields.push(parsedField);
- foundIndex = line.indexOf(wrapper, parsedField.end);
- }
- }
- if (includeTaskFields)
- fields = fields.concat(extractSpecialTaskFields(line));
- fields.sort((a, b) => a.start - b.start);
- let filteredFields = [];
- for (let i = 0; i < fields.length; i++) {
- if (i == 0 || filteredFields[filteredFields.length - 1].end < fields[i].start) {
- filteredFields.push(fields[i]);
- }
- }
- return filteredFields;
- }
- const FULL_LINE_KEY_PART = parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(new RegExp(emojiRegex(), "u")), parsimmon_umd_minExports.regexp(/[0-9\p{Letter}\w\s_/-]+/u))
- .many()
- .map(parts => parts.join(""));
- parsimmon_umd_minExports.regexp(/[^0-9\w\p{Letter}]*/u)
- .then(FULL_LINE_KEY_PART)
- .skip(parsimmon_umd_minExports.regexp(/[_\*~`]*/u));
- const CREATED_DATE_REGEX = /\u{2795}\s*(\d{4}-\d{2}-\d{2})/u;
- const DUE_DATE_REGEX = /(?:\u{1F4C5}|\u{1F4C6}|\u{1F5D3}\u{FE0F}?)\s*(\d{4}-\d{2}-\d{2})/u;
- const DONE_DATE_REGEX = /\u{2705}\s*(\d{4}-\d{2}-\d{2})/u;
- const SCHEDULED_DATE_REGEX = /[\u{23F3}\u{231B}]\s*(\d{4}-\d{2}-\d{2})/u;
- const START_DATE_REGEX = /\u{1F6EB}\s*(\d{4}-\d{2}-\d{2})/u;
- const EMOJI_REGEXES = [
- { regex: CREATED_DATE_REGEX, key: "created" },
- { regex: START_DATE_REGEX, key: "start" },
- { regex: SCHEDULED_DATE_REGEX, key: "scheduled" },
- { regex: DUE_DATE_REGEX, key: "due" },
- { regex: DONE_DATE_REGEX, key: "completion" },
- ];
- function extractSpecialTaskFields(line) {
- let results = [];
- for (let { regex, key } of EMOJI_REGEXES) {
- const match = regex.exec(line);
- if (!match)
- continue;
- results.push({
- key,
- value: match[1],
- start: match.index,
- startValue: match.index + 1,
- end: match.index + match[0].length,
- wrapping: "emoji-shorthand",
- });
- }
- return results;
- }
- function setInlineField(source, key, value) {
- let existing = extractInlineFields(source);
- let existingKeys = existing.filter(f => f.key == key);
-
- if (existingKeys.length > 2 || (existingKeys.length == 0 && !value))
- return source;
- let existingKey = existingKeys[0];
- let annotation = value ? `[${key}:: ${value}]` : "";
- if (existingKey) {
- let prefix = source.substring(0, existingKey.start);
- let suffix = source.substring(existingKey.end);
- if (annotation)
- return `${prefix}${annotation}${suffix}`;
- else
- return `${prefix}${suffix.trimStart()}`;
- }
- else if (annotation) {
- return `${source.trimEnd()} ${annotation}`;
- }
- return source;
- }
- function setEmojiShorthandCompletionField(source, value) {
- const existing = extractInlineFields(source, true);
- const existingKeys = existing.filter(f => f.key === "completion" && f.wrapping === "emoji-shorthand");
-
- if (existingKeys.length > 2 || (existingKeys.length == 0 && !value))
- return source;
-
- const annotation = value ? ` ✅ ${value}` : "";
- let existingKey = existingKeys[0];
- if (existingKey) {
- const prefix = source.substring(0, existingKey.start);
- const suffix = source.substring(existingKey.end);
- return `${prefix.trimEnd()}${annotation}${suffix}`;
- }
- else {
- return `${source.trimEnd()}${annotation}`;
- }
- }
- class PageMetadata {
-
- path;
-
- ctime;
-
- mtime;
-
- size;
-
- day;
-
- title;
-
- fields;
-
- tags;
-
- aliases;
-
- links;
-
- lists;
-
- frontmatter;
- constructor(path, init) {
- this.path = path;
- this.fields = new Map();
- this.frontmatter = {};
- this.tags = new Set();
- this.aliases = new Set();
- this.links = [];
- Object.assign(this, init);
- this.lists = (this.lists || []).map(l => new ListItem$1(l));
- }
-
- static canonicalize(data, linkNormalizer) {
-
- if (data.frontmatter) {
- data.frontmatter = Values.mapLeaves(data.frontmatter, t => Values.isLink(t) ? linkNormalizer(t) : t);
- }
- if (data.fields) {
- for (let [key, value] of data.fields.entries()) {
- data.fields.set(key, Values.mapLeaves(value, t => (Values.isLink(t) ? linkNormalizer(t) : t)));
- }
- }
- if (data.lists) {
- for (let item of data.lists) {
- for (let [key, value] of item.fields.entries()) {
- item.fields.set(key, value.map(x => Values.mapLeaves(x, t => (Values.isLink(t) ? linkNormalizer(t) : t))));
- }
- }
- }
- if (data.links) {
- data.links = data.links.map(l => linkNormalizer(l));
- }
-
-
-
- return new PageMetadata(data.path, data);
- }
-
- name() {
- return getFileTitle(this.path);
- }
-
- folder() {
- return getParentFolder(this.path);
- }
-
- extension() {
- return getExtension(this.path);
- }
-
- fullTags() {
- let result = new Set();
- for (let tag of this.tags) {
- for (let subtag of extractSubtags(tag))
- result.add(subtag);
- }
- return result;
- }
-
- fileLinks() {
-
-
- let distinctLinks = new Set(this.links);
- return Array.from(distinctLinks);
- }
-
- serialize(index, cache) {
-
- let realCache = cache ?? new ListSerializationCache(this.lists);
- let result = {
- file: {
- path: this.path,
- folder: this.folder(),
- name: this.name(),
- link: Link.file(this.path),
- outlinks: this.fileLinks(),
- inlinks: Array.from(index.links.getInverse(this.path)).map(l => Link.file(l)),
- etags: Array.from(this.tags),
- tags: Array.from(this.fullTags()),
- aliases: Array.from(this.aliases),
- lists: this.lists.map(l => realCache.get(l.line)),
- tasks: this.lists.filter(l => !!l.task).map(l => realCache.get(l.line)),
- ctime: this.ctime,
- cday: stripTime(this.ctime),
- mtime: this.mtime,
- mday: stripTime(this.mtime),
- size: this.size,
- starred: index.starred.starred(this.path),
- frontmatter: Values.deepCopy(this.frontmatter),
- ext: this.extension(),
- },
- };
-
- if (this.day)
- result.file.day = this.day;
-
- for (let [key, value] of this.fields.entries()) {
- if (key in result)
- continue;
- result[key] = value;
- }
- return result;
- }
- }
- class ListItem$1 {
-
- symbol;
-
- link;
-
- section;
-
- text;
-
- line;
-
- lineCount;
-
- list;
-
- links;
-
- tags;
-
- position;
-
- parent;
-
- children;
-
- blockId;
-
- fields;
- task;
- constructor(init) {
- Object.assign(this, init);
- this.fields = this.fields || new Map();
- this.tags = this.tags || new Set();
- this.children = this.children || [];
- this.links = this.links || [];
- }
- id() {
- return `${this.file().path}-${this.line}`;
- }
- file() {
- return this.link.toFile();
- }
- markdown() {
- if (this.task)
- return `${this.symbol} [${this.task.completed ? "x" : " "}] ${this.text}`;
- else
- return `${this.symbol} ${this.text}`;
- }
- created() {
- return (this.fields.get("created") ?? this.fields.get("ctime") ?? this.fields.get("cday"))?.[0];
- }
- due() {
- return (this.fields.get("due") ?? this.fields.get("duetime") ?? this.fields.get("dueday"))?.[0];
- }
- completed() {
- return (this.fields.get("completed") ??
- this.fields.get("completion") ??
- this.fields.get("comptime") ??
- this.fields.get("compday"))?.[0];
- }
- start() {
- return this.fields.get("start")?.[0];
- }
- scheduled() {
- return this.fields.get("scheduled")?.[0];
- }
-
- serialize(cache) {
-
- let children = this.children.map(l => cache.get(l)).filter((l) => l !== undefined);
- let result = {
- symbol: this.symbol,
- link: this.link,
- section: this.section,
- text: this.text,
- tags: Array.from(this.tags),
- line: this.line,
- lineCount: this.lineCount,
- list: this.list,
- outlinks: Array.from(this.links),
- path: this.link.path,
- children: children,
- task: !!this.task,
- annotated: this.fields.size > 0,
- position: Values.deepCopy(this.position),
- subtasks: children,
- real: !!this.task,
- header: this.section,
- };
- if (this.parent || this.parent === 0)
- result.parent = this.parent;
- if (this.blockId)
- result.blockId = this.blockId;
- addFields(this.fields, result);
- if (this.task) {
- result.status = this.task.status;
- result.checked = this.task.checked;
- result.completed = this.task.completed;
- result.fullyCompleted = this.task.fullyCompleted;
- let created = this.created(), due = this.due(), completed = this.completed(), start = this.start(), scheduled = this.scheduled();
- if (created)
- result.created = Values.deepCopy(created);
- if (due)
- result.due = Values.deepCopy(due);
- if (completed)
- result.completion = Values.deepCopy(completed);
- if (start)
- result.start = Values.deepCopy(start);
- if (scheduled)
- result.scheduled = Values.deepCopy(scheduled);
- }
- return result;
- }
- }
- class ListSerializationCache {
- listItems;
- cache;
- seen;
- constructor(listItems) {
- this.listItems = {};
- this.cache = {};
- this.seen = new Set();
- for (let item of listItems)
- this.listItems[item.line] = item;
- }
- get(lineno) {
- if (lineno in this.cache)
- return this.cache[lineno];
- else if (this.seen.has(lineno)) {
- console.log(`Dataview: Encountered a circular list (line number ${lineno}; children ${this.listItems[lineno].children.join(", ")})`);
- return undefined;
- }
- this.seen.add(lineno);
- let result = this.listItems[lineno].serialize(this);
- this.cache[lineno] = result;
- return result;
- }
- }
- function addFields(fields, target) {
- for (let [key, values] of fields.entries()) {
- if (key in target)
- continue;
- target[key] = values.length == 1 ? values[0] : values;
- }
- return target;
- }
- const LIST_ITEM_REGEX = /^[\s>]*(\d+\.|\d+\)|\*|-|\+)\s*(\[.{0,1}\])?\s*(.*)$/mu;
- function parseFrontmatter(value) {
- if (value == null) {
- return null;
- }
- else if (typeof value === "object") {
- if (Array.isArray(value)) {
- let result = [];
- for (let child of value) {
- result.push(parseFrontmatter(child));
- }
- return result;
- }
- else if (value instanceof Date) {
- let dateParse = DateTime.fromJSDate(value);
- return dateParse;
- }
- else {
- let object = value;
- let result = {};
- for (let key in object) {
- result[key] = parseFrontmatter(object[key]);
- }
- return result;
- }
- }
- else if (typeof value === "number") {
- return value;
- }
- else if (typeof value === "boolean") {
- return value;
- }
- else if (typeof value === "string") {
- let dateParse = EXPRESSION.date.parse(value);
- if (dateParse.status)
- return dateParse.value;
- let durationParse = EXPRESSION.duration.parse(value);
- if (durationParse.status)
- return durationParse.value;
- let linkParse = EXPRESSION.embedLink.parse(value);
- if (linkParse.status)
- return linkParse.value;
- return value;
- }
-
- return null;
- }
- function parseCsv(content) {
- let parsed = papaparse_minExports.parse(content, {
- header: true,
- skipEmptyLines: true,
- comments: "#",
- dynamicTyping: true,
- });
- let rows = [];
- for (let parsedRow of parsed.data) {
- let fields = parseFrontmatter(parsedRow);
- let result = {};
- for (let [key, value] of Object.entries(fields)) {
- result[key] = value;
- result[canonicalizeVarName(key)] = value;
- }
- rows.push(result);
- }
- return rows;
- }
- var Transferable;
- (function (Transferable) {
-
- function transferable(value) {
-
- if (value instanceof Map) {
- let copied = new Map();
- for (let [key, val] of value.entries())
- copied.set(transferable(key), transferable(val));
- return copied;
- }
- else if (value instanceof Set) {
- let copied = new Set();
- for (let val of value)
- copied.add(transferable(val));
- return copied;
- }
- let wrapped = Values.wrapValue(value);
- if (wrapped === undefined)
- throw Error("Unrecognized transferable value: " + value);
- switch (wrapped.type) {
- case "null":
- case "number":
- case "string":
- case "boolean":
- return wrapped.value;
- case "date":
- return {
- "___transfer-type": "date",
- value: transferable(wrapped.value.toObject()),
- options: {
- zone: wrapped.value.zone.equals(SystemZone.instance) ? undefined : wrapped.value.zoneName,
- },
- };
- case "duration":
- return { "___transfer-type": "duration", value: transferable(wrapped.value.toObject()) };
- case "array":
- return wrapped.value.map(v => transferable(v));
- case "link":
- return { "___transfer-type": "link", value: transferable(wrapped.value.toObject()) };
- case "object":
- let result = {};
- for (let [key, value] of Object.entries(wrapped.value))
- result[key] = transferable(value);
- return result;
- }
- }
- Transferable.transferable = transferable;
-
- function value(transferable) {
- if (transferable === null) {
- return null;
- }
- else if (transferable === undefined) {
- return undefined;
- }
- else if (transferable instanceof Map) {
- let real = new Map();
- for (let [key, val] of transferable.entries())
- real.set(value(key), value(val));
- return real;
- }
- else if (transferable instanceof Set) {
- let real = new Set();
- for (let val of transferable)
- real.add(value(val));
- return real;
- }
- else if (Array.isArray(transferable)) {
- return transferable.map(v => value(v));
- }
- else if (typeof transferable === "object") {
- if ("___transfer-type" in transferable) {
- switch (transferable["___transfer-type"]) {
- case "date":
- let dateOpts = value(transferable.options);
- let dateData = value(transferable.value);
- return DateTime.fromObject(dateData, { zone: dateOpts.zone });
- case "duration":
- return Duration.fromObject(value(transferable.value));
- case "link":
- return Link.fromObject(value(transferable.value));
- default:
- throw Error(`Unrecognized transfer type '${transferable["___transfer-type"]}'`);
- }
- }
- let result = {};
- for (let [key, val] of Object.entries(transferable))
- result[key] = value(val);
- return result;
- }
- return transferable;
- }
- Transferable.value = value;
- })(Transferable || (Transferable = {}));
- function commonjsRequire(path) {
- throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
- }
- var localforage$1 = {exports: {}};
- localforage$1.exports;
- (function (module, exports) {
- (function(f){{module.exports=f();}})(function(){return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof commonjsRequire=="function"&&commonjsRequire;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 commonjsRequire=="function"&&commonjsRequire;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
- (function (global){
- var Mutation = global.MutationObserver || global.WebKitMutationObserver;
- var scheduleDrain;
- {
- if (Mutation) {
- var called = 0;
- var observer = new Mutation(nextTick);
- var element = global.document.createTextNode('');
- observer.observe(element, {
- characterData: true
- });
- scheduleDrain = function () {
- element.data = (called = ++called % 2);
- };
- } else if (!global.setImmediate && typeof global.MessageChannel !== 'undefined') {
- var channel = new global.MessageChannel();
- channel.port1.onmessage = nextTick;
- scheduleDrain = function () {
- channel.port2.postMessage(0);
- };
- } else if ('document' in global && 'onreadystatechange' in global.document.createElement('script')) {
- scheduleDrain = function () {
-
-
- var scriptEl = global.document.createElement('script');
- scriptEl.onreadystatechange = function () {
- nextTick();
- scriptEl.onreadystatechange = null;
- scriptEl.parentNode.removeChild(scriptEl);
- scriptEl = null;
- };
- global.document.documentElement.appendChild(scriptEl);
- };
- } else {
- scheduleDrain = function () {
- setTimeout(nextTick, 0);
- };
- }
- }
- var draining;
- var queue = [];
-
- function nextTick() {
- draining = true;
- var i, oldQueue;
- var len = queue.length;
- while (len) {
- oldQueue = queue;
- queue = [];
- i = -1;
- while (++i < len) {
- oldQueue[i]();
- }
- len = queue.length;
- }
- draining = false;
- }
- module.exports = immediate;
- function immediate(task) {
- if (queue.push(task) === 1 && !draining) {
- scheduleDrain();
- }
- }
- }).call(this,typeof commonjsGlobal !== "undefined" ? commonjsGlobal : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
- },{}],2:[function(_dereq_,module,exports){
- var immediate = _dereq_(1);
-
- function INTERNAL() {}
- var handlers = {};
- var REJECTED = ['REJECTED'];
- var FULFILLED = ['FULFILLED'];
- var PENDING = ['PENDING'];
- module.exports = Promise;
- function Promise(resolver) {
- if (typeof resolver !== 'function') {
- throw new TypeError('resolver must be a function');
- }
- this.state = PENDING;
- this.queue = [];
- this.outcome = void 0;
- if (resolver !== INTERNAL) {
- safelyResolveThenable(this, resolver);
- }
- }
- Promise.prototype["catch"] = function (onRejected) {
- return this.then(null, onRejected);
- };
- Promise.prototype.then = function (onFulfilled, onRejected) {
- if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
- typeof onRejected !== 'function' && this.state === REJECTED) {
- return this;
- }
- var promise = new this.constructor(INTERNAL);
- if (this.state !== PENDING) {
- var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
- unwrap(promise, resolver, this.outcome);
- } else {
- this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
- }
- return promise;
- };
- function QueueItem(promise, onFulfilled, onRejected) {
- this.promise = promise;
- if (typeof onFulfilled === 'function') {
- this.onFulfilled = onFulfilled;
- this.callFulfilled = this.otherCallFulfilled;
- }
- if (typeof onRejected === 'function') {
- this.onRejected = onRejected;
- this.callRejected = this.otherCallRejected;
- }
- }
- QueueItem.prototype.callFulfilled = function (value) {
- handlers.resolve(this.promise, value);
- };
- QueueItem.prototype.otherCallFulfilled = function (value) {
- unwrap(this.promise, this.onFulfilled, value);
- };
- QueueItem.prototype.callRejected = function (value) {
- handlers.reject(this.promise, value);
- };
- QueueItem.prototype.otherCallRejected = function (value) {
- unwrap(this.promise, this.onRejected, value);
- };
- function unwrap(promise, func, value) {
- immediate(function () {
- var returnValue;
- try {
- returnValue = func(value);
- } catch (e) {
- return handlers.reject(promise, e);
- }
- if (returnValue === promise) {
- handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
- } else {
- handlers.resolve(promise, returnValue);
- }
- });
- }
- handlers.resolve = function (self, value) {
- var result = tryCatch(getThen, value);
- if (result.status === 'error') {
- return handlers.reject(self, result.value);
- }
- var thenable = result.value;
- if (thenable) {
- safelyResolveThenable(self, thenable);
- } else {
- self.state = FULFILLED;
- self.outcome = value;
- var i = -1;
- var len = self.queue.length;
- while (++i < len) {
- self.queue[i].callFulfilled(value);
- }
- }
- return self;
- };
- handlers.reject = function (self, error) {
- self.state = REJECTED;
- self.outcome = error;
- var i = -1;
- var len = self.queue.length;
- while (++i < len) {
- self.queue[i].callRejected(error);
- }
- return self;
- };
- function getThen(obj) {
-
- var then = obj && obj.then;
- if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') {
- return function appyThen() {
- then.apply(obj, arguments);
- };
- }
- }
- function safelyResolveThenable(self, thenable) {
-
- var called = false;
- function onError(value) {
- if (called) {
- return;
- }
- called = true;
- handlers.reject(self, value);
- }
- function onSuccess(value) {
- if (called) {
- return;
- }
- called = true;
- handlers.resolve(self, value);
- }
- function tryToUnwrap() {
- thenable(onSuccess, onError);
- }
- var result = tryCatch(tryToUnwrap);
- if (result.status === 'error') {
- onError(result.value);
- }
- }
- function tryCatch(func, value) {
- var out = {};
- try {
- out.value = func(value);
- out.status = 'success';
- } catch (e) {
- out.status = 'error';
- out.value = e;
- }
- return out;
- }
- Promise.resolve = resolve;
- function resolve(value) {
- if (value instanceof this) {
- return value;
- }
- return handlers.resolve(new this(INTERNAL), value);
- }
- Promise.reject = reject;
- function reject(reason) {
- var promise = new this(INTERNAL);
- return handlers.reject(promise, reason);
- }
- Promise.all = all;
- function all(iterable) {
- var self = this;
- if (Object.prototype.toString.call(iterable) !== '[object Array]') {
- return this.reject(new TypeError('must be an array'));
- }
- var len = iterable.length;
- var called = false;
- if (!len) {
- return this.resolve([]);
- }
- var values = new Array(len);
- var resolved = 0;
- var i = -1;
- var promise = new this(INTERNAL);
- while (++i < len) {
- allResolver(iterable[i], i);
- }
- return promise;
- function allResolver(value, i) {
- self.resolve(value).then(resolveFromAll, function (error) {
- if (!called) {
- called = true;
- handlers.reject(promise, error);
- }
- });
- function resolveFromAll(outValue) {
- values[i] = outValue;
- if (++resolved === len && !called) {
- called = true;
- handlers.resolve(promise, values);
- }
- }
- }
- }
- Promise.race = race;
- function race(iterable) {
- var self = this;
- if (Object.prototype.toString.call(iterable) !== '[object Array]') {
- return this.reject(new TypeError('must be an array'));
- }
- var len = iterable.length;
- var called = false;
- if (!len) {
- return this.resolve([]);
- }
- var i = -1;
- var promise = new this(INTERNAL);
- while (++i < len) {
- resolver(iterable[i]);
- }
- return promise;
- function resolver(value) {
- self.resolve(value).then(function (response) {
- if (!called) {
- called = true;
- handlers.resolve(promise, response);
- }
- }, function (error) {
- if (!called) {
- called = true;
- handlers.reject(promise, error);
- }
- });
- }
- }
- },{"1":1}],3:[function(_dereq_,module,exports){
- (function (global){
- if (typeof global.Promise !== 'function') {
- global.Promise = _dereq_(2);
- }
- }).call(this,typeof commonjsGlobal !== "undefined" ? commonjsGlobal : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
- },{"2":2}],4:[function(_dereq_,module,exports){
- var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- function getIDB() {
-
- try {
- if (typeof indexedDB !== 'undefined') {
- return indexedDB;
- }
- if (typeof webkitIndexedDB !== 'undefined') {
- return webkitIndexedDB;
- }
- if (typeof mozIndexedDB !== 'undefined') {
- return mozIndexedDB;
- }
- if (typeof OIndexedDB !== 'undefined') {
- return OIndexedDB;
- }
- if (typeof msIndexedDB !== 'undefined') {
- return msIndexedDB;
- }
- } catch (e) {
- return;
- }
- }
- var idb = getIDB();
- function isIndexedDBValid() {
- try {
-
-
- if (!idb || !idb.open) {
- return false;
- }
-
-
-
-
- var isSafari = typeof openDatabase !== 'undefined' && /(Safari|iPhone|iPad|iPod)/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) && !/BlackBerry/.test(navigator.platform);
- var hasFetch = typeof fetch === 'function' && fetch.toString().indexOf('[native code') !== -1;
-
-
-
-
-
-
- return (!isSafari || hasFetch) && typeof indexedDB !== 'undefined' &&
-
-
-
-
- typeof IDBKeyRange !== 'undefined';
- } catch (e) {
- return false;
- }
- }
-
-
-
-
-
-
- function createBlob(parts, properties) {
-
- parts = parts || [];
- properties = properties || {};
- try {
- return new Blob(parts, properties);
- } catch (e) {
- if (e.name !== 'TypeError') {
- throw e;
- }
- var Builder = typeof BlobBuilder !== 'undefined' ? BlobBuilder : typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder : typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder : WebKitBlobBuilder;
- var builder = new Builder();
- for (var i = 0; i < parts.length; i += 1) {
- builder.append(parts[i]);
- }
- return builder.getBlob(properties.type);
- }
- }
-
-
- if (typeof Promise === 'undefined') {
-
-
- _dereq_(3);
- }
- var Promise$1 = Promise;
- function executeCallback(promise, callback) {
- if (callback) {
- promise.then(function (result) {
- callback(null, result);
- }, function (error) {
- callback(error);
- });
- }
- }
- function executeTwoCallbacks(promise, callback, errorCallback) {
- if (typeof callback === 'function') {
- promise.then(callback);
- }
- if (typeof errorCallback === 'function') {
- promise["catch"](errorCallback);
- }
- }
- function normalizeKey(key) {
-
- if (typeof key !== 'string') {
- console.warn(key + ' used as a key, but it is not a string.');
- key = String(key);
- }
- return key;
- }
- function getCallback() {
- if (arguments.length && typeof arguments[arguments.length - 1] === 'function') {
- return arguments[arguments.length - 1];
- }
- }
-
-
- var DETECT_BLOB_SUPPORT_STORE = 'local-forage-detect-blob-support';
- var supportsBlobs = void 0;
- var dbContexts = {};
- var toString = Object.prototype.toString;
-
- var READ_ONLY = 'readonly';
- var READ_WRITE = 'readwrite';
-
-
-
-
-
- function _binStringToArrayBuffer(bin) {
- var length = bin.length;
- var buf = new ArrayBuffer(length);
- var arr = new Uint8Array(buf);
- for (var i = 0; i < length; i++) {
- arr[i] = bin.charCodeAt(i);
- }
- return buf;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- function _checkBlobSupportWithoutCaching(idb) {
- return new Promise$1(function (resolve) {
- var txn = idb.transaction(DETECT_BLOB_SUPPORT_STORE, READ_WRITE);
- var blob = createBlob(['']);
- txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key');
- txn.onabort = function (e) {
-
-
- e.preventDefault();
- e.stopPropagation();
- resolve(false);
- };
- txn.oncomplete = function () {
- var matchedChrome = navigator.userAgent.match(/Chrome\/(\d+)/);
- var matchedEdge = navigator.userAgent.match(/Edge\//);
-
-
- resolve(matchedEdge || !matchedChrome || parseInt(matchedChrome[1], 10) >= 43);
- };
- })["catch"](function () {
- return false;
- });
- }
- function _checkBlobSupport(idb) {
- if (typeof supportsBlobs === 'boolean') {
- return Promise$1.resolve(supportsBlobs);
- }
- return _checkBlobSupportWithoutCaching(idb).then(function (value) {
- supportsBlobs = value;
- return supportsBlobs;
- });
- }
- function _deferReadiness(dbInfo) {
- var dbContext = dbContexts[dbInfo.name];
-
- var deferredOperation = {};
- deferredOperation.promise = new Promise$1(function (resolve, reject) {
- deferredOperation.resolve = resolve;
- deferredOperation.reject = reject;
- });
-
- dbContext.deferredOperations.push(deferredOperation);
-
- if (!dbContext.dbReady) {
- dbContext.dbReady = deferredOperation.promise;
- } else {
- dbContext.dbReady = dbContext.dbReady.then(function () {
- return deferredOperation.promise;
- });
- }
- }
- function _advanceReadiness(dbInfo) {
- var dbContext = dbContexts[dbInfo.name];
-
- var deferredOperation = dbContext.deferredOperations.pop();
-
-
- if (deferredOperation) {
- deferredOperation.resolve();
- return deferredOperation.promise;
- }
- }
- function _rejectReadiness(dbInfo, err) {
- var dbContext = dbContexts[dbInfo.name];
-
- var deferredOperation = dbContext.deferredOperations.pop();
-
-
- if (deferredOperation) {
- deferredOperation.reject(err);
- return deferredOperation.promise;
- }
- }
- function _getConnection(dbInfo, upgradeNeeded) {
- return new Promise$1(function (resolve, reject) {
- dbContexts[dbInfo.name] = dbContexts[dbInfo.name] || createDbContext();
- if (dbInfo.db) {
- if (upgradeNeeded) {
- _deferReadiness(dbInfo);
- dbInfo.db.close();
- } else {
- return resolve(dbInfo.db);
- }
- }
- var dbArgs = [dbInfo.name];
- if (upgradeNeeded) {
- dbArgs.push(dbInfo.version);
- }
- var openreq = idb.open.apply(idb, dbArgs);
- if (upgradeNeeded) {
- openreq.onupgradeneeded = function (e) {
- var db = openreq.result;
- try {
- db.createObjectStore(dbInfo.storeName);
- if (e.oldVersion <= 1) {
-
- db.createObjectStore(DETECT_BLOB_SUPPORT_STORE);
- }
- } catch (ex) {
- if (ex.name === 'ConstraintError') {
- console.warn('The database "' + dbInfo.name + '"' + ' has been upgraded from version ' + e.oldVersion + ' to version ' + e.newVersion + ', but the storage "' + dbInfo.storeName + '" already exists.');
- } else {
- throw ex;
- }
- }
- };
- }
- openreq.onerror = function (e) {
- e.preventDefault();
- reject(openreq.error);
- };
- openreq.onsuccess = function () {
- var db = openreq.result;
- db.onversionchange = function (e) {
-
-
-
-
-
- e.target.close();
- };
- resolve(db);
- _advanceReadiness(dbInfo);
- };
- });
- }
- function _getOriginalConnection(dbInfo) {
- return _getConnection(dbInfo, false);
- }
- function _getUpgradedConnection(dbInfo) {
- return _getConnection(dbInfo, true);
- }
- function _isUpgradeNeeded(dbInfo, defaultVersion) {
- if (!dbInfo.db) {
- return true;
- }
- var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName);
- var isDowngrade = dbInfo.version < dbInfo.db.version;
- var isUpgrade = dbInfo.version > dbInfo.db.version;
- if (isDowngrade) {
-
-
- if (dbInfo.version !== defaultVersion) {
- console.warn('The database "' + dbInfo.name + '"' + " can't be downgraded from version " + dbInfo.db.version + ' to version ' + dbInfo.version + '.');
- }
-
- dbInfo.version = dbInfo.db.version;
- }
- if (isUpgrade || isNewStore) {
-
-
-
- if (isNewStore) {
- var incVersion = dbInfo.db.version + 1;
- if (incVersion > dbInfo.version) {
- dbInfo.version = incVersion;
- }
- }
- return true;
- }
- return false;
- }
-
- function _encodeBlob(blob) {
- return new Promise$1(function (resolve, reject) {
- var reader = new FileReader();
- reader.onerror = reject;
- reader.onloadend = function (e) {
- var base64 = btoa(e.target.result || '');
- resolve({
- __local_forage_encoded_blob: true,
- data: base64,
- type: blob.type
- });
- };
- reader.readAsBinaryString(blob);
- });
- }
-
- function _decodeBlob(encodedBlob) {
- var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data));
- return createBlob([arrayBuff], { type: encodedBlob.type });
- }
-
- function _isEncodedBlob(value) {
- return value && value.__local_forage_encoded_blob;
- }
-
-
-
-
- function _fullyReady(callback) {
- var self = this;
- var promise = self._initReady().then(function () {
- var dbContext = dbContexts[self._dbInfo.name];
- if (dbContext && dbContext.dbReady) {
- return dbContext.dbReady;
- }
- });
- executeTwoCallbacks(promise, callback, callback);
- return promise;
- }
-
-
-
- function _tryReconnect(dbInfo) {
- _deferReadiness(dbInfo);
- var dbContext = dbContexts[dbInfo.name];
- var forages = dbContext.forages;
- for (var i = 0; i < forages.length; i++) {
- var forage = forages[i];
- if (forage._dbInfo.db) {
- forage._dbInfo.db.close();
- forage._dbInfo.db = null;
- }
- }
- dbInfo.db = null;
- return _getOriginalConnection(dbInfo).then(function (db) {
- dbInfo.db = db;
- if (_isUpgradeNeeded(dbInfo)) {
-
- return _getUpgradedConnection(dbInfo);
- }
- return db;
- }).then(function (db) {
-
-
- dbInfo.db = dbContext.db = db;
- for (var i = 0; i < forages.length; i++) {
- forages[i]._dbInfo.db = db;
- }
- })["catch"](function (err) {
- _rejectReadiness(dbInfo, err);
- throw err;
- });
- }
-
-
- function createTransaction(dbInfo, mode, callback, retries) {
- if (retries === undefined) {
- retries = 1;
- }
- try {
- var tx = dbInfo.db.transaction(dbInfo.storeName, mode);
- callback(null, tx);
- } catch (err) {
- if (retries > 0 && (!dbInfo.db || err.name === 'InvalidStateError' || err.name === 'NotFoundError')) {
- return Promise$1.resolve().then(function () {
- if (!dbInfo.db || err.name === 'NotFoundError' && !dbInfo.db.objectStoreNames.contains(dbInfo.storeName) && dbInfo.version <= dbInfo.db.version) {
-
- if (dbInfo.db) {
- dbInfo.version = dbInfo.db.version + 1;
- }
-
- return _getUpgradedConnection(dbInfo);
- }
- }).then(function () {
- return _tryReconnect(dbInfo).then(function () {
- createTransaction(dbInfo, mode, callback, retries - 1);
- });
- })["catch"](callback);
- }
- callback(err);
- }
- }
- function createDbContext() {
- return {
-
- forages: [],
-
- db: null,
-
- dbReady: null,
-
- deferredOperations: []
- };
- }
-
-
- function _initStorage(options) {
- var self = this;
- var dbInfo = {
- db: null
- };
- if (options) {
- for (var i in options) {
- dbInfo[i] = options[i];
- }
- }
-
- var dbContext = dbContexts[dbInfo.name];
-
- if (!dbContext) {
- dbContext = createDbContext();
-
- dbContexts[dbInfo.name] = dbContext;
- }
-
- dbContext.forages.push(self);
-
- if (!self._initReady) {
- self._initReady = self.ready;
- self.ready = _fullyReady;
- }
-
- var initPromises = [];
- function ignoreErrors() {
-
-
- return Promise$1.resolve();
- }
- for (var j = 0; j < dbContext.forages.length; j++) {
- var forage = dbContext.forages[j];
- if (forage !== self) {
-
- initPromises.push(forage._initReady()["catch"](ignoreErrors));
- }
- }
-
- var forages = dbContext.forages.slice(0);
-
-
- return Promise$1.all(initPromises).then(function () {
- dbInfo.db = dbContext.db;
-
- return _getOriginalConnection(dbInfo);
- }).then(function (db) {
- dbInfo.db = db;
- if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) {
-
- return _getUpgradedConnection(dbInfo);
- }
- return db;
- }).then(function (db) {
- dbInfo.db = dbContext.db = db;
- self._dbInfo = dbInfo;
-
- for (var k = 0; k < forages.length; k++) {
- var forage = forages[k];
- if (forage !== self) {
-
- forage._dbInfo.db = dbInfo.db;
- forage._dbInfo.version = dbInfo.version;
- }
- }
- });
- }
- function getItem(key, callback) {
- var self = this;
- key = normalizeKey(key);
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) {
- if (err) {
- return reject(err);
- }
- try {
- var store = transaction.objectStore(self._dbInfo.storeName);
- var req = store.get(key);
- req.onsuccess = function () {
- var value = req.result;
- if (value === undefined) {
- value = null;
- }
- if (_isEncodedBlob(value)) {
- value = _decodeBlob(value);
- }
- resolve(value);
- };
- req.onerror = function () {
- reject(req.error);
- };
- } catch (e) {
- reject(e);
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
-
- function iterate(iterator, callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) {
- if (err) {
- return reject(err);
- }
- try {
- var store = transaction.objectStore(self._dbInfo.storeName);
- var req = store.openCursor();
- var iterationNumber = 1;
- req.onsuccess = function () {
- var cursor = req.result;
- if (cursor) {
- var value = cursor.value;
- if (_isEncodedBlob(value)) {
- value = _decodeBlob(value);
- }
- var result = iterator(value, cursor.key, iterationNumber++);
-
-
-
- if (result !== void 0) {
- resolve(result);
- } else {
- cursor["continue"]();
- }
- } else {
- resolve();
- }
- };
- req.onerror = function () {
- reject(req.error);
- };
- } catch (e) {
- reject(e);
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function setItem(key, value, callback) {
- var self = this;
- key = normalizeKey(key);
- var promise = new Promise$1(function (resolve, reject) {
- var dbInfo;
- self.ready().then(function () {
- dbInfo = self._dbInfo;
- if (toString.call(value) === '[object Blob]') {
- return _checkBlobSupport(dbInfo.db).then(function (blobSupport) {
- if (blobSupport) {
- return value;
- }
- return _encodeBlob(value);
- });
- }
- return value;
- }).then(function (value) {
- createTransaction(self._dbInfo, READ_WRITE, function (err, transaction) {
- if (err) {
- return reject(err);
- }
- try {
- var store = transaction.objectStore(self._dbInfo.storeName);
-
-
-
-
- if (value === null) {
- value = undefined;
- }
- var req = store.put(value, key);
- transaction.oncomplete = function () {
-
-
-
-
-
-
- if (value === undefined) {
- value = null;
- }
- resolve(value);
- };
- transaction.onabort = transaction.onerror = function () {
- var err = req.error ? req.error : req.transaction.error;
- reject(err);
- };
- } catch (e) {
- reject(e);
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function removeItem(key, callback) {
- var self = this;
- key = normalizeKey(key);
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- createTransaction(self._dbInfo, READ_WRITE, function (err, transaction) {
- if (err) {
- return reject(err);
- }
- try {
- var store = transaction.objectStore(self._dbInfo.storeName);
-
-
-
-
-
- var req = store["delete"](key);
- transaction.oncomplete = function () {
- resolve();
- };
- transaction.onerror = function () {
- reject(req.error);
- };
-
-
- transaction.onabort = function () {
- var err = req.error ? req.error : req.transaction.error;
- reject(err);
- };
- } catch (e) {
- reject(e);
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function clear(callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- createTransaction(self._dbInfo, READ_WRITE, function (err, transaction) {
- if (err) {
- return reject(err);
- }
- try {
- var store = transaction.objectStore(self._dbInfo.storeName);
- var req = store.clear();
- transaction.oncomplete = function () {
- resolve();
- };
- transaction.onabort = transaction.onerror = function () {
- var err = req.error ? req.error : req.transaction.error;
- reject(err);
- };
- } catch (e) {
- reject(e);
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function length(callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) {
- if (err) {
- return reject(err);
- }
- try {
- var store = transaction.objectStore(self._dbInfo.storeName);
- var req = store.count();
- req.onsuccess = function () {
- resolve(req.result);
- };
- req.onerror = function () {
- reject(req.error);
- };
- } catch (e) {
- reject(e);
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function key(n, callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- if (n < 0) {
- resolve(null);
- return;
- }
- self.ready().then(function () {
- createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) {
- if (err) {
- return reject(err);
- }
- try {
- var store = transaction.objectStore(self._dbInfo.storeName);
- var advanced = false;
- var req = store.openKeyCursor();
- req.onsuccess = function () {
- var cursor = req.result;
- if (!cursor) {
-
- resolve(null);
- return;
- }
- if (n === 0) {
-
-
- resolve(cursor.key);
- } else {
- if (!advanced) {
-
-
- advanced = true;
- cursor.advance(n);
- } else {
-
- resolve(cursor.key);
- }
- }
- };
- req.onerror = function () {
- reject(req.error);
- };
- } catch (e) {
- reject(e);
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function keys(callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) {
- if (err) {
- return reject(err);
- }
- try {
- var store = transaction.objectStore(self._dbInfo.storeName);
- var req = store.openKeyCursor();
- var keys = [];
- req.onsuccess = function () {
- var cursor = req.result;
- if (!cursor) {
- resolve(keys);
- return;
- }
- keys.push(cursor.key);
- cursor["continue"]();
- };
- req.onerror = function () {
- reject(req.error);
- };
- } catch (e) {
- reject(e);
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function dropInstance(options, callback) {
- callback = getCallback.apply(this, arguments);
- var currentConfig = this.config();
- options = typeof options !== 'function' && options || {};
- if (!options.name) {
- options.name = options.name || currentConfig.name;
- options.storeName = options.storeName || currentConfig.storeName;
- }
- var self = this;
- var promise;
- if (!options.name) {
- promise = Promise$1.reject('Invalid arguments');
- } else {
- var isCurrentDb = options.name === currentConfig.name && self._dbInfo.db;
- var dbPromise = isCurrentDb ? Promise$1.resolve(self._dbInfo.db) : _getOriginalConnection(options).then(function (db) {
- var dbContext = dbContexts[options.name];
- var forages = dbContext.forages;
- dbContext.db = db;
- for (var i = 0; i < forages.length; i++) {
- forages[i]._dbInfo.db = db;
- }
- return db;
- });
- if (!options.storeName) {
- promise = dbPromise.then(function (db) {
- _deferReadiness(options);
- var dbContext = dbContexts[options.name];
- var forages = dbContext.forages;
- db.close();
- for (var i = 0; i < forages.length; i++) {
- var forage = forages[i];
- forage._dbInfo.db = null;
- }
- var dropDBPromise = new Promise$1(function (resolve, reject) {
- var req = idb.deleteDatabase(options.name);
- req.onerror = function () {
- var db = req.result;
- if (db) {
- db.close();
- }
- reject(req.error);
- };
- req.onblocked = function () {
-
-
- console.warn('dropInstance blocked for database "' + options.name + '" until all open connections are closed');
- };
- req.onsuccess = function () {
- var db = req.result;
- if (db) {
- db.close();
- }
- resolve(db);
- };
- });
- return dropDBPromise.then(function (db) {
- dbContext.db = db;
- for (var i = 0; i < forages.length; i++) {
- var _forage = forages[i];
- _advanceReadiness(_forage._dbInfo);
- }
- })["catch"](function (err) {
- (_rejectReadiness(options, err) || Promise$1.resolve())["catch"](function () {});
- throw err;
- });
- });
- } else {
- promise = dbPromise.then(function (db) {
- if (!db.objectStoreNames.contains(options.storeName)) {
- return;
- }
- var newVersion = db.version + 1;
- _deferReadiness(options);
- var dbContext = dbContexts[options.name];
- var forages = dbContext.forages;
- db.close();
- for (var i = 0; i < forages.length; i++) {
- var forage = forages[i];
- forage._dbInfo.db = null;
- forage._dbInfo.version = newVersion;
- }
- var dropObjectPromise = new Promise$1(function (resolve, reject) {
- var req = idb.open(options.name, newVersion);
- req.onerror = function (err) {
- var db = req.result;
- db.close();
- reject(err);
- };
- req.onupgradeneeded = function () {
- var db = req.result;
- db.deleteObjectStore(options.storeName);
- };
- req.onsuccess = function () {
- var db = req.result;
- db.close();
- resolve(db);
- };
- });
- return dropObjectPromise.then(function (db) {
- dbContext.db = db;
- for (var j = 0; j < forages.length; j++) {
- var _forage2 = forages[j];
- _forage2._dbInfo.db = db;
- _advanceReadiness(_forage2._dbInfo);
- }
- })["catch"](function (err) {
- (_rejectReadiness(options, err) || Promise$1.resolve())["catch"](function () {});
- throw err;
- });
- });
- }
- }
- executeCallback(promise, callback);
- return promise;
- }
- var asyncStorage = {
- _driver: 'asyncStorage',
- _initStorage: _initStorage,
- _support: isIndexedDBValid(),
- iterate: iterate,
- getItem: getItem,
- setItem: setItem,
- removeItem: removeItem,
- clear: clear,
- length: length,
- key: key,
- keys: keys,
- dropInstance: dropInstance
- };
- function isWebSQLValid() {
- return typeof openDatabase === 'function';
- }
-
-
-
- var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
- var BLOB_TYPE_PREFIX = '~~local_forage_type~';
- var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
- var SERIALIZED_MARKER = '__lfsc__:';
- var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
-
- var TYPE_ARRAYBUFFER = 'arbf';
- var TYPE_BLOB = 'blob';
- var TYPE_INT8ARRAY = 'si08';
- var TYPE_UINT8ARRAY = 'ui08';
- var TYPE_UINT8CLAMPEDARRAY = 'uic8';
- var TYPE_INT16ARRAY = 'si16';
- var TYPE_INT32ARRAY = 'si32';
- var TYPE_UINT16ARRAY = 'ur16';
- var TYPE_UINT32ARRAY = 'ui32';
- var TYPE_FLOAT32ARRAY = 'fl32';
- var TYPE_FLOAT64ARRAY = 'fl64';
- var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;
- var toString$1 = Object.prototype.toString;
- function stringToBuffer(serializedString) {
-
- var bufferLength = serializedString.length * 0.75;
- var len = serializedString.length;
- var i;
- var p = 0;
- var encoded1, encoded2, encoded3, encoded4;
- if (serializedString[serializedString.length - 1] === '=') {
- bufferLength--;
- if (serializedString[serializedString.length - 2] === '=') {
- bufferLength--;
- }
- }
- var buffer = new ArrayBuffer(bufferLength);
- var bytes = new Uint8Array(buffer);
- for (i = 0; i < len; i += 4) {
- encoded1 = BASE_CHARS.indexOf(serializedString[i]);
- encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);
- encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);
- encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);
-
- bytes[p++] = encoded1 << 2 | encoded2 >> 4;
- bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;
- bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;
- }
- return buffer;
- }
-
-
- function bufferToString(buffer) {
-
- var bytes = new Uint8Array(buffer);
- var base64String = '';
- var i;
- for (i = 0; i < bytes.length; i += 3) {
-
- base64String += BASE_CHARS[bytes[i] >> 2];
- base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];
- base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];
- base64String += BASE_CHARS[bytes[i + 2] & 63];
- }
- if (bytes.length % 3 === 2) {
- base64String = base64String.substring(0, base64String.length - 1) + '=';
- } else if (bytes.length % 3 === 1) {
- base64String = base64String.substring(0, base64String.length - 2) + '==';
- }
- return base64String;
- }
-
-
-
- function serialize(value, callback) {
- var valueType = '';
- if (value) {
- valueType = toString$1.call(value);
- }
-
-
-
-
- if (value && (valueType === '[object ArrayBuffer]' || value.buffer && toString$1.call(value.buffer) === '[object ArrayBuffer]')) {
-
-
- var buffer;
- var marker = SERIALIZED_MARKER;
- if (value instanceof ArrayBuffer) {
- buffer = value;
- marker += TYPE_ARRAYBUFFER;
- } else {
- buffer = value.buffer;
- if (valueType === '[object Int8Array]') {
- marker += TYPE_INT8ARRAY;
- } else if (valueType === '[object Uint8Array]') {
- marker += TYPE_UINT8ARRAY;
- } else if (valueType === '[object Uint8ClampedArray]') {
- marker += TYPE_UINT8CLAMPEDARRAY;
- } else if (valueType === '[object Int16Array]') {
- marker += TYPE_INT16ARRAY;
- } else if (valueType === '[object Uint16Array]') {
- marker += TYPE_UINT16ARRAY;
- } else if (valueType === '[object Int32Array]') {
- marker += TYPE_INT32ARRAY;
- } else if (valueType === '[object Uint32Array]') {
- marker += TYPE_UINT32ARRAY;
- } else if (valueType === '[object Float32Array]') {
- marker += TYPE_FLOAT32ARRAY;
- } else if (valueType === '[object Float64Array]') {
- marker += TYPE_FLOAT64ARRAY;
- } else {
- callback(new Error('Failed to get type for BinaryArray'));
- }
- }
- callback(marker + bufferToString(buffer));
- } else if (valueType === '[object Blob]') {
-
- var fileReader = new FileReader();
- fileReader.onload = function () {
-
- var str = BLOB_TYPE_PREFIX + value.type + '~' + bufferToString(this.result);
- callback(SERIALIZED_MARKER + TYPE_BLOB + str);
- };
- fileReader.readAsArrayBuffer(value);
- } else {
- try {
- callback(JSON.stringify(value));
- } catch (e) {
- console.error("Couldn't convert value into a JSON string: ", value);
- callback(null, e);
- }
- }
- }
-
-
-
-
-
-
-
-
- function deserialize(value) {
-
-
-
- if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {
- return JSON.parse(value);
- }
-
-
-
- var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
- var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);
- var blobType;
-
-
- if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
- var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
- blobType = matcher[1];
- serializedString = serializedString.substring(matcher[0].length);
- }
- var buffer = stringToBuffer(serializedString);
-
-
- switch (type) {
- case TYPE_ARRAYBUFFER:
- return buffer;
- case TYPE_BLOB:
- return createBlob([buffer], { type: blobType });
- case TYPE_INT8ARRAY:
- return new Int8Array(buffer);
- case TYPE_UINT8ARRAY:
- return new Uint8Array(buffer);
- case TYPE_UINT8CLAMPEDARRAY:
- return new Uint8ClampedArray(buffer);
- case TYPE_INT16ARRAY:
- return new Int16Array(buffer);
- case TYPE_UINT16ARRAY:
- return new Uint16Array(buffer);
- case TYPE_INT32ARRAY:
- return new Int32Array(buffer);
- case TYPE_UINT32ARRAY:
- return new Uint32Array(buffer);
- case TYPE_FLOAT32ARRAY:
- return new Float32Array(buffer);
- case TYPE_FLOAT64ARRAY:
- return new Float64Array(buffer);
- default:
- throw new Error('Unkown type: ' + type);
- }
- }
- var localforageSerializer = {
- serialize: serialize,
- deserialize: deserialize,
- stringToBuffer: stringToBuffer,
- bufferToString: bufferToString
- };
-
- function createDbTable(t, dbInfo, callback, errorCallback) {
- t.executeSql('CREATE TABLE IF NOT EXISTS ' + dbInfo.storeName + ' ' + '(id INTEGER PRIMARY KEY, key unique, value)', [], callback, errorCallback);
- }
-
-
- function _initStorage$1(options) {
- var self = this;
- var dbInfo = {
- db: null
- };
- if (options) {
- for (var i in options) {
- dbInfo[i] = typeof options[i] !== 'string' ? options[i].toString() : options[i];
- }
- }
- var dbInfoPromise = new Promise$1(function (resolve, reject) {
-
-
- try {
- dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version), dbInfo.description, dbInfo.size);
- } catch (e) {
- return reject(e);
- }
-
- dbInfo.db.transaction(function (t) {
- createDbTable(t, dbInfo, function () {
- self._dbInfo = dbInfo;
- resolve();
- }, function (t, error) {
- reject(error);
- });
- }, reject);
- });
- dbInfo.serializer = localforageSerializer;
- return dbInfoPromise;
- }
- function tryExecuteSql(t, dbInfo, sqlStatement, args, callback, errorCallback) {
- t.executeSql(sqlStatement, args, callback, function (t, error) {
- if (error.code === error.SYNTAX_ERR) {
- t.executeSql('SELECT name FROM sqlite_master ' + "WHERE type='table' AND name = ?", [dbInfo.storeName], function (t, results) {
- if (!results.rows.length) {
-
-
- createDbTable(t, dbInfo, function () {
- t.executeSql(sqlStatement, args, callback, errorCallback);
- }, errorCallback);
- } else {
- errorCallback(t, error);
- }
- }, errorCallback);
- } else {
- errorCallback(t, error);
- }
- }, errorCallback);
- }
- function getItem$1(key, callback) {
- var self = this;
- key = normalizeKey(key);
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- var dbInfo = self._dbInfo;
- dbInfo.db.transaction(function (t) {
- tryExecuteSql(t, dbInfo, 'SELECT * FROM ' + dbInfo.storeName + ' WHERE key = ? LIMIT 1', [key], function (t, results) {
- var result = results.rows.length ? results.rows.item(0).value : null;
-
-
- if (result) {
- result = dbInfo.serializer.deserialize(result);
- }
- resolve(result);
- }, function (t, error) {
- reject(error);
- });
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function iterate$1(iterator, callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- var dbInfo = self._dbInfo;
- dbInfo.db.transaction(function (t) {
- tryExecuteSql(t, dbInfo, 'SELECT * FROM ' + dbInfo.storeName, [], function (t, results) {
- var rows = results.rows;
- var length = rows.length;
- for (var i = 0; i < length; i++) {
- var item = rows.item(i);
- var result = item.value;
-
-
- if (result) {
- result = dbInfo.serializer.deserialize(result);
- }
- result = iterator(result, item.key, i + 1);
-
-
- if (result !== void 0) {
- resolve(result);
- return;
- }
- }
- resolve();
- }, function (t, error) {
- reject(error);
- });
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function _setItem(key, value, callback, retriesLeft) {
- var self = this;
- key = normalizeKey(key);
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
-
-
-
- if (value === undefined) {
- value = null;
- }
-
- var originalValue = value;
- var dbInfo = self._dbInfo;
- dbInfo.serializer.serialize(value, function (value, error) {
- if (error) {
- reject(error);
- } else {
- dbInfo.db.transaction(function (t) {
- tryExecuteSql(t, dbInfo, 'INSERT OR REPLACE INTO ' + dbInfo.storeName + ' ' + '(key, value) VALUES (?, ?)', [key, value], function () {
- resolve(originalValue);
- }, function (t, error) {
- reject(error);
- });
- }, function (sqlError) {
-
-
- if (sqlError.code === sqlError.QUOTA_ERR) {
-
-
-
-
-
-
-
- if (retriesLeft > 0) {
- resolve(_setItem.apply(self, [key, originalValue, callback, retriesLeft - 1]));
- return;
- }
- reject(sqlError);
- }
- });
- }
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function setItem$1(key, value, callback) {
- return _setItem.apply(this, [key, value, callback, 1]);
- }
- function removeItem$1(key, callback) {
- var self = this;
- key = normalizeKey(key);
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- var dbInfo = self._dbInfo;
- dbInfo.db.transaction(function (t) {
- tryExecuteSql(t, dbInfo, 'DELETE FROM ' + dbInfo.storeName + ' WHERE key = ?', [key], function () {
- resolve();
- }, function (t, error) {
- reject(error);
- });
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
-
-
- function clear$1(callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- var dbInfo = self._dbInfo;
- dbInfo.db.transaction(function (t) {
- tryExecuteSql(t, dbInfo, 'DELETE FROM ' + dbInfo.storeName, [], function () {
- resolve();
- }, function (t, error) {
- reject(error);
- });
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
-
-
- function length$1(callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- var dbInfo = self._dbInfo;
- dbInfo.db.transaction(function (t) {
-
- tryExecuteSql(t, dbInfo, 'SELECT COUNT(key) as c FROM ' + dbInfo.storeName, [], function (t, results) {
- var result = results.rows.item(0).c;
- resolve(result);
- }, function (t, error) {
- reject(error);
- });
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
-
-
-
-
-
-
-
- function key$1(n, callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- var dbInfo = self._dbInfo;
- dbInfo.db.transaction(function (t) {
- tryExecuteSql(t, dbInfo, 'SELECT key FROM ' + dbInfo.storeName + ' WHERE id = ? LIMIT 1', [n + 1], function (t, results) {
- var result = results.rows.length ? results.rows.item(0).key : null;
- resolve(result);
- }, function (t, error) {
- reject(error);
- });
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
- function keys$1(callback) {
- var self = this;
- var promise = new Promise$1(function (resolve, reject) {
- self.ready().then(function () {
- var dbInfo = self._dbInfo;
- dbInfo.db.transaction(function (t) {
- tryExecuteSql(t, dbInfo, 'SELECT key FROM ' + dbInfo.storeName, [], function (t, results) {
- var keys = [];
- for (var i = 0; i < results.rows.length; i++) {
- keys.push(results.rows.item(i).key);
- }
- resolve(keys);
- }, function (t, error) {
- reject(error);
- });
- });
- })["catch"](reject);
- });
- executeCallback(promise, callback);
- return promise;
- }
-
-
- function getAllStoreNames(db) {
- return new Promise$1(function (resolve, reject) {
- db.transaction(function (t) {
- t.executeSql('SELECT name FROM sqlite_master ' + "WHERE type='table' AND name <> '__WebKitDatabaseInfoTable__'", [], function (t, results) {
- var storeNames = [];
- for (var i = 0; i < results.rows.length; i++) {
- storeNames.push(results.rows.item(i).name);
- }
- resolve({
- db: db,
- storeNames: storeNames
- });
- }, function (t, error) {
- reject(error);
- });
- }, function (sqlError) {
- reject(sqlError);
- });
- });
- }
- function dropInstance$1(options, callback) {
- callback = getCallback.apply(this, arguments);
- var currentConfig = this.config();
- options = typeof options !== 'function' && options || {};
- if (!options.name) {
- options.name = options.name || currentConfig.name;
- options.storeName = options.storeName || currentConfig.storeName;
- }
- var self = this;
- var promise;
- if (!options.name) {
- promise = Promise$1.reject('Invalid arguments');
- } else {
- promise = new Promise$1(function (resolve) {
- var db;
- if (options.name === currentConfig.name) {
-
- db = self._dbInfo.db;
- } else {
- db = openDatabase(options.name, '', '', 0);
- }
- if (!options.storeName) {
-
- resolve(getAllStoreNames(db));
- } else {
- resolve({
- db: db,
- storeNames: [options.storeName]
- });
- }
- }).then(function (operationInfo) {
- return new Promise$1(function (resolve, reject) {
- operationInfo.db.transaction(function (t) {
- function dropTable(storeName) {
- return new Promise$1(function (resolve, reject) {
- t.executeSql('DROP TABLE IF EXISTS ' + storeName, [], function () {
- resolve();
- }, function (t, error) {
- reject(error);
- });
- });
- }
- var operations = [];
- for (var i = 0, len = operationInfo.storeNames.length; i < len; i++) {
- operations.push(dropTable(operationInfo.storeNames[i]));
- }
- Promise$1.all(operations).then(function () {
- resolve();
- })["catch"](function (e) {
- reject(e);
- });
- }, function (sqlError) {
- reject(sqlError);
- });
- });
- });
- }
- executeCallback(promise, callback);
- return promise;
- }
- var webSQLStorage = {
- _driver: 'webSQLStorage',
- _initStorage: _initStorage$1,
- _support: isWebSQLValid(),
- iterate: iterate$1,
- getItem: getItem$1,
- setItem: setItem$1,
- removeItem: removeItem$1,
- clear: clear$1,
- length: length$1,
- key: key$1,
- keys: keys$1,
- dropInstance: dropInstance$1
- };
- function isLocalStorageValid() {
- try {
- return typeof localStorage !== 'undefined' && 'setItem' in localStorage &&
-
- !!localStorage.setItem;
- } catch (e) {
- return false;
- }
- }
- function _getKeyPrefix(options, defaultConfig) {
- var keyPrefix = options.name + '/';
- if (options.storeName !== defaultConfig.storeName) {
- keyPrefix += options.storeName + '/';
- }
- return keyPrefix;
- }
-
- function checkIfLocalStorageThrows() {
- var localStorageTestKey = '_localforage_support_test';
- try {
- localStorage.setItem(localStorageTestKey, true);
- localStorage.removeItem(localStorageTestKey);
- return false;
- } catch (e) {
- return true;
- }
- }
-
-
-
-
- function _isLocalStorageUsable() {
- return !checkIfLocalStorageThrows() || localStorage.length > 0;
- }
-
- function _initStorage$2(options) {
- var self = this;
- var dbInfo = {};
- if (options) {
- for (var i in options) {
- dbInfo[i] = options[i];
- }
- }
- dbInfo.keyPrefix = _getKeyPrefix(options, self._defaultConfig);
- if (!_isLocalStorageUsable()) {
- return Promise$1.reject();
- }
- self._dbInfo = dbInfo;
- dbInfo.serializer = localforageSerializer;
- return Promise$1.resolve();
- }
-
-
- function clear$2(callback) {
- var self = this;
- var promise = self.ready().then(function () {
- var keyPrefix = self._dbInfo.keyPrefix;
- for (var i = localStorage.length - 1; i >= 0; i--) {
- var key = localStorage.key(i);
- if (key.indexOf(keyPrefix) === 0) {
- localStorage.removeItem(key);
- }
- }
- });
- executeCallback(promise, callback);
- return promise;
- }
-
-
-
- function getItem$2(key, callback) {
- var self = this;
- key = normalizeKey(key);
- var promise = self.ready().then(function () {
- var dbInfo = self._dbInfo;
- var result = localStorage.getItem(dbInfo.keyPrefix + key);
-
-
-
-
- if (result) {
- result = dbInfo.serializer.deserialize(result);
- }
- return result;
- });
- executeCallback(promise, callback);
- return promise;
- }
-
- function iterate$2(iterator, callback) {
- var self = this;
- var promise = self.ready().then(function () {
- var dbInfo = self._dbInfo;
- var keyPrefix = dbInfo.keyPrefix;
- var keyPrefixLength = keyPrefix.length;
- var length = localStorage.length;
-
-
-
-
-
-
- var iterationNumber = 1;
- for (var i = 0; i < length; i++) {
- var key = localStorage.key(i);
- if (key.indexOf(keyPrefix) !== 0) {
- continue;
- }
- var value = localStorage.getItem(key);
-
-
-
-
- if (value) {
- value = dbInfo.serializer.deserialize(value);
- }
- value = iterator(value, key.substring(keyPrefixLength), iterationNumber++);
- if (value !== void 0) {
- return value;
- }
- }
- });
- executeCallback(promise, callback);
- return promise;
- }
-
- function key$2(n, callback) {
- var self = this;
- var promise = self.ready().then(function () {
- var dbInfo = self._dbInfo;
- var result;
- try {
- result = localStorage.key(n);
- } catch (error) {
- result = null;
- }
-
- if (result) {
- result = result.substring(dbInfo.keyPrefix.length);
- }
- return result;
- });
- executeCallback(promise, callback);
- return promise;
- }
- function keys$2(callback) {
- var self = this;
- var promise = self.ready().then(function () {
- var dbInfo = self._dbInfo;
- var length = localStorage.length;
- var keys = [];
- for (var i = 0; i < length; i++) {
- var itemKey = localStorage.key(i);
- if (itemKey.indexOf(dbInfo.keyPrefix) === 0) {
- keys.push(itemKey.substring(dbInfo.keyPrefix.length));
- }
- }
- return keys;
- });
- executeCallback(promise, callback);
- return promise;
- }
-
- function length$2(callback) {
- var self = this;
- var promise = self.keys().then(function (keys) {
- return keys.length;
- });
- executeCallback(promise, callback);
- return promise;
- }
-
- function removeItem$2(key, callback) {
- var self = this;
- key = normalizeKey(key);
- var promise = self.ready().then(function () {
- var dbInfo = self._dbInfo;
- localStorage.removeItem(dbInfo.keyPrefix + key);
- });
- executeCallback(promise, callback);
- return promise;
- }
-
-
-
-
- function setItem$2(key, value, callback) {
- var self = this;
- key = normalizeKey(key);
- var promise = self.ready().then(function () {
-
-
- if (value === undefined) {
- value = null;
- }
-
- var originalValue = value;
- return new Promise$1(function (resolve, reject) {
- var dbInfo = self._dbInfo;
- dbInfo.serializer.serialize(value, function (value, error) {
- if (error) {
- reject(error);
- } else {
- try {
- localStorage.setItem(dbInfo.keyPrefix + key, value);
- resolve(originalValue);
- } catch (e) {
-
-
- if (e.name === 'QuotaExceededError' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
- reject(e);
- }
- reject(e);
- }
- }
- });
- });
- });
- executeCallback(promise, callback);
- return promise;
- }
- function dropInstance$2(options, callback) {
- callback = getCallback.apply(this, arguments);
- options = typeof options !== 'function' && options || {};
- if (!options.name) {
- var currentConfig = this.config();
- options.name = options.name || currentConfig.name;
- options.storeName = options.storeName || currentConfig.storeName;
- }
- var self = this;
- var promise;
- if (!options.name) {
- promise = Promise$1.reject('Invalid arguments');
- } else {
- promise = new Promise$1(function (resolve) {
- if (!options.storeName) {
- resolve(options.name + '/');
- } else {
- resolve(_getKeyPrefix(options, self._defaultConfig));
- }
- }).then(function (keyPrefix) {
- for (var i = localStorage.length - 1; i >= 0; i--) {
- var key = localStorage.key(i);
- if (key.indexOf(keyPrefix) === 0) {
- localStorage.removeItem(key);
- }
- }
- });
- }
- executeCallback(promise, callback);
- return promise;
- }
- var localStorageWrapper = {
- _driver: 'localStorageWrapper',
- _initStorage: _initStorage$2,
- _support: isLocalStorageValid(),
- iterate: iterate$2,
- getItem: getItem$2,
- setItem: setItem$2,
- removeItem: removeItem$2,
- clear: clear$2,
- length: length$2,
- key: key$2,
- keys: keys$2,
- dropInstance: dropInstance$2
- };
- var sameValue = function sameValue(x, y) {
- return x === y || typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y);
- };
- var includes = function includes(array, searchElement) {
- var len = array.length;
- var i = 0;
- while (i < len) {
- if (sameValue(array[i], searchElement)) {
- return true;
- }
- i++;
- }
- return false;
- };
- var isArray = Array.isArray || function (arg) {
- return Object.prototype.toString.call(arg) === '[object Array]';
- };
-
-
- var DefinedDrivers = {};
- var DriverSupport = {};
- var DefaultDrivers = {
- INDEXEDDB: asyncStorage,
- WEBSQL: webSQLStorage,
- LOCALSTORAGE: localStorageWrapper
- };
- var DefaultDriverOrder = [DefaultDrivers.INDEXEDDB._driver, DefaultDrivers.WEBSQL._driver, DefaultDrivers.LOCALSTORAGE._driver];
- var OptionalDriverMethods = ['dropInstance'];
- var LibraryMethods = ['clear', 'getItem', 'iterate', 'key', 'keys', 'length', 'removeItem', 'setItem'].concat(OptionalDriverMethods);
- var DefaultConfig = {
- description: '',
- driver: DefaultDriverOrder.slice(),
- name: 'localforage',
-
-
- size: 4980736,
- storeName: 'keyvaluepairs',
- version: 1.0
- };
- function callWhenReady(localForageInstance, libraryMethod) {
- localForageInstance[libraryMethod] = function () {
- var _args = arguments;
- return localForageInstance.ready().then(function () {
- return localForageInstance[libraryMethod].apply(localForageInstance, _args);
- });
- };
- }
- function extend() {
- for (var i = 1; i < arguments.length; i++) {
- var arg = arguments[i];
- if (arg) {
- for (var _key in arg) {
- if (arg.hasOwnProperty(_key)) {
- if (isArray(arg[_key])) {
- arguments[0][_key] = arg[_key].slice();
- } else {
- arguments[0][_key] = arg[_key];
- }
- }
- }
- }
- }
- return arguments[0];
- }
- var LocalForage = function () {
- function LocalForage(options) {
- _classCallCheck(this, LocalForage);
- for (var driverTypeKey in DefaultDrivers) {
- if (DefaultDrivers.hasOwnProperty(driverTypeKey)) {
- var driver = DefaultDrivers[driverTypeKey];
- var driverName = driver._driver;
- this[driverTypeKey] = driverName;
- if (!DefinedDrivers[driverName]) {
-
-
-
- this.defineDriver(driver);
- }
- }
- }
- this._defaultConfig = extend({}, DefaultConfig);
- this._config = extend({}, this._defaultConfig, options);
- this._driverSet = null;
- this._initDriver = null;
- this._ready = false;
- this._dbInfo = null;
- this._wrapLibraryMethodsWithReady();
- this.setDriver(this._config.driver)["catch"](function () {});
- }
-
-
-
-
- LocalForage.prototype.config = function config(options) {
-
-
-
- if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object') {
-
-
- if (this._ready) {
- return new Error("Can't call config() after localforage " + 'has been used.');
- }
- for (var i in options) {
- if (i === 'storeName') {
- options[i] = options[i].replace(/\W/g, '_');
- }
- if (i === 'version' && typeof options[i] !== 'number') {
- return new Error('Database version must be a number.');
- }
- this._config[i] = options[i];
- }
-
-
- if ('driver' in options && options.driver) {
- return this.setDriver(this._config.driver);
- }
- return true;
- } else if (typeof options === 'string') {
- return this._config[options];
- } else {
- return this._config;
- }
- };
-
-
- LocalForage.prototype.defineDriver = function defineDriver(driverObject, callback, errorCallback) {
- var promise = new Promise$1(function (resolve, reject) {
- try {
- var driverName = driverObject._driver;
- var complianceError = new Error('Custom driver not compliant; see ' + 'https://mozilla.github.io/localForage/#definedriver');
-
-
- if (!driverObject._driver) {
- reject(complianceError);
- return;
- }
- var driverMethods = LibraryMethods.concat('_initStorage');
- for (var i = 0, len = driverMethods.length; i < len; i++) {
- var driverMethodName = driverMethods[i];
-
-
- var isRequired = !includes(OptionalDriverMethods, driverMethodName);
- if ((isRequired || driverObject[driverMethodName]) && typeof driverObject[driverMethodName] !== 'function') {
- reject(complianceError);
- return;
- }
- }
- var configureMissingMethods = function configureMissingMethods() {
- var methodNotImplementedFactory = function methodNotImplementedFactory(methodName) {
- return function () {
- var error = new Error('Method ' + methodName + ' is not implemented by the current driver');
- var promise = Promise$1.reject(error);
- executeCallback(promise, arguments[arguments.length - 1]);
- return promise;
- };
- };
- for (var _i = 0, _len = OptionalDriverMethods.length; _i < _len; _i++) {
- var optionalDriverMethod = OptionalDriverMethods[_i];
- if (!driverObject[optionalDriverMethod]) {
- driverObject[optionalDriverMethod] = methodNotImplementedFactory(optionalDriverMethod);
- }
- }
- };
- configureMissingMethods();
- var setDriverSupport = function setDriverSupport(support) {
- if (DefinedDrivers[driverName]) {
- console.info('Redefining LocalForage driver: ' + driverName);
- }
- DefinedDrivers[driverName] = driverObject;
- DriverSupport[driverName] = support;
-
-
-
- resolve();
- };
- if ('_support' in driverObject) {
- if (driverObject._support && typeof driverObject._support === 'function') {
- driverObject._support().then(setDriverSupport, reject);
- } else {
- setDriverSupport(!!driverObject._support);
- }
- } else {
- setDriverSupport(true);
- }
- } catch (e) {
- reject(e);
- }
- });
- executeTwoCallbacks(promise, callback, errorCallback);
- return promise;
- };
- LocalForage.prototype.driver = function driver() {
- return this._driver || null;
- };
- LocalForage.prototype.getDriver = function getDriver(driverName, callback, errorCallback) {
- var getDriverPromise = DefinedDrivers[driverName] ? Promise$1.resolve(DefinedDrivers[driverName]) : Promise$1.reject(new Error('Driver not found.'));
- executeTwoCallbacks(getDriverPromise, callback, errorCallback);
- return getDriverPromise;
- };
- LocalForage.prototype.getSerializer = function getSerializer(callback) {
- var serializerPromise = Promise$1.resolve(localforageSerializer);
- executeTwoCallbacks(serializerPromise, callback);
- return serializerPromise;
- };
- LocalForage.prototype.ready = function ready(callback) {
- var self = this;
- var promise = self._driverSet.then(function () {
- if (self._ready === null) {
- self._ready = self._initDriver();
- }
- return self._ready;
- });
- executeTwoCallbacks(promise, callback, callback);
- return promise;
- };
- LocalForage.prototype.setDriver = function setDriver(drivers, callback, errorCallback) {
- var self = this;
- if (!isArray(drivers)) {
- drivers = [drivers];
- }
- var supportedDrivers = this._getSupportedDrivers(drivers);
- function setDriverToConfig() {
- self._config.driver = self.driver();
- }
- function extendSelfWithDriver(driver) {
- self._extend(driver);
- setDriverToConfig();
- self._ready = self._initStorage(self._config);
- return self._ready;
- }
- function initDriver(supportedDrivers) {
- return function () {
- var currentDriverIndex = 0;
- function driverPromiseLoop() {
- while (currentDriverIndex < supportedDrivers.length) {
- var driverName = supportedDrivers[currentDriverIndex];
- currentDriverIndex++;
- self._dbInfo = null;
- self._ready = null;
- return self.getDriver(driverName).then(extendSelfWithDriver)["catch"](driverPromiseLoop);
- }
- setDriverToConfig();
- var error = new Error('No available storage method found.');
- self._driverSet = Promise$1.reject(error);
- return self._driverSet;
- }
- return driverPromiseLoop();
- };
- }
-
-
-
- var oldDriverSetDone = this._driverSet !== null ? this._driverSet["catch"](function () {
- return Promise$1.resolve();
- }) : Promise$1.resolve();
- this._driverSet = oldDriverSetDone.then(function () {
- var driverName = supportedDrivers[0];
- self._dbInfo = null;
- self._ready = null;
- return self.getDriver(driverName).then(function (driver) {
- self._driver = driver._driver;
- setDriverToConfig();
- self._wrapLibraryMethodsWithReady();
- self._initDriver = initDriver(supportedDrivers);
- });
- })["catch"](function () {
- setDriverToConfig();
- var error = new Error('No available storage method found.');
- self._driverSet = Promise$1.reject(error);
- return self._driverSet;
- });
- executeTwoCallbacks(this._driverSet, callback, errorCallback);
- return this._driverSet;
- };
- LocalForage.prototype.supports = function supports(driverName) {
- return !!DriverSupport[driverName];
- };
- LocalForage.prototype._extend = function _extend(libraryMethodsAndProperties) {
- extend(this, libraryMethodsAndProperties);
- };
- LocalForage.prototype._getSupportedDrivers = function _getSupportedDrivers(drivers) {
- var supportedDrivers = [];
- for (var i = 0, len = drivers.length; i < len; i++) {
- var driverName = drivers[i];
- if (this.supports(driverName)) {
- supportedDrivers.push(driverName);
- }
- }
- return supportedDrivers;
- };
- LocalForage.prototype._wrapLibraryMethodsWithReady = function _wrapLibraryMethodsWithReady() {
-
-
-
-
- for (var i = 0, len = LibraryMethods.length; i < len; i++) {
- callWhenReady(this, LibraryMethods[i]);
- }
- };
- LocalForage.prototype.createInstance = function createInstance(options) {
- return new LocalForage(options);
- };
- return LocalForage;
- }();
-
-
- var localforage_js = new LocalForage();
- module.exports = localforage_js;
- },{"3":3}]},{},[4])(4)
- });
- } (localforage$1, localforage$1.exports));
- var localforageExports = localforage$1.exports;
- var localforage = getDefaultExportFromCjs(localforageExports);
- class LocalStorageCache {
- appId;
- version;
- persister;
- constructor(appId, version) {
- this.appId = appId;
- this.version = version;
- this.persister = localforage.createInstance({
- name: "dataview/cache/" + appId,
- driver: [localforage.INDEXEDDB],
- description: "Cache metadata about files and sections in the dataview index.",
- });
- }
-
- async recreate() {
- await localforage.dropInstance({ name: "dataview/cache/" + this.appId });
- this.persister = localforage.createInstance({
- name: "dataview/cache/" + this.appId,
- driver: [localforage.INDEXEDDB],
- description: "Cache metadata about files and sections in the dataview index.",
- });
- }
-
- async loadFile(path) {
- return this.persister.getItem(this.fileKey(path)).then(raw => {
- let result = raw;
- if (result)
- result.data = Transferable.value(result.data);
- return result;
- });
- }
-
- async storeFile(path, data) {
- await this.persister.setItem(this.fileKey(path), {
- version: this.version,
- time: Date.now(),
- data: Transferable.transferable(data),
- });
- }
-
- async synchronize(existing) {
- let keys = new Set(await this.allFiles());
- for (let exist of existing)
- keys.delete(exist);
-
- for (let key of keys)
- await this.persister.removeItem(this.fileKey(key));
- return keys;
- }
-
- async allKeys() {
- return this.persister.keys();
- }
-
- async allFiles() {
- let keys = await this.allKeys();
- return keys.filter(k => k.startsWith("file:")).map(k => k.substring(5));
- }
- fileKey(path) {
- return "file:" + path;
- }
- }
- function decodeBase64(base64, enableUnicode) {
- var binaryString = atob(base64);
- if (enableUnicode) {
- var binaryView = new Uint8Array(binaryString.length);
- for (var i = 0, n = binaryString.length; i < n; ++i) {
- binaryView[i] = binaryString.charCodeAt(i);
- }
- return String.fromCharCode.apply(null, new Uint16Array(binaryView.buffer));
- }
- return binaryString;
- }
- function createURL(base64, sourcemapArg, enableUnicodeArg) {
- var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
- var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
- var source = decodeBase64(base64, enableUnicode);
- var start = source.indexOf('\n', 10) + 1;
- var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
- var blob = new Blob([body], { type: 'application/javascript' });
- return URL.createObjectURL(blob);
- }
- function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
- var url;
- return function WorkerFactory(options) {
- url = url || createURL(base64, sourcemapArg, enableUnicodeArg);
- return new Worker(url, options);
- };
- }
- var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24gKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgLy8gdGhlc2UgYXJlbid0IHJlYWxseSBwcml2YXRlLCBidXQgbm9yIGFyZSB0aGV5IHJlYWxseSB1c2VmdWwgdG8gZG9jdW1lbnQKCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KICBjbGFzcyBMdXhvbkVycm9yIGV4dGVuZHMgRXJyb3Ige30KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KICBjbGFzcyBJbnZhbGlkRGF0ZVRpbWVFcnJvciBleHRlbmRzIEx1eG9uRXJyb3IgewogICAgY29uc3RydWN0b3IocmVhc29uKSB7CiAgICAgIHN1cGVyKGBJbnZhbGlkIERhdGVUaW1lOiAke3JlYXNvbi50b01lc3NhZ2UoKX1gKTsKICAgIH0KICB9CgogIC8qKgogICAqIEBwcml2YXRlCiAgICovCiAgY2xhc3MgSW52YWxpZEludGVydmFsRXJyb3IgZXh0ZW5kcyBMdXhvbkVycm9yIHsKICAgIGNvbnN0cnVjdG9yKHJlYXNvbikgewogICAgICBzdXBlcihgSW52YWxpZCBJbnRlcnZhbDogJHtyZWFzb24udG9NZXNzYWdlKCl9YCk7CiAgICB9CiAgfQoKICAvKioKICAgKiBAcHJpdmF0ZQogICAqLwogIGNsYXNzIEludmFsaWREdXJhdGlvbkVycm9yIGV4dGVuZHMgTHV4b25FcnJvciB7CiAgICBjb25zdHJ1Y3RvcihyZWFzb24pIHsKICAgICAgc3VwZXIoYEludmFsaWQgRHVyYXRpb246ICR7cmVhc29uLnRvTWVzc2FnZSgpfWApOwogICAgfQogIH0KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KICBjbGFzcyBDb25mbGljdGluZ1NwZWNpZmljYXRpb25FcnJvciBleHRlbmRzIEx1eG9uRXJyb3Ige30KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KICBjbGFzcyBJbnZhbGlkVW5pdEVycm9yIGV4dGVuZHMgTHV4b25FcnJvciB7CiAgICBjb25zdHJ1Y3Rvcih1bml0KSB7CiAgICAgIHN1cGVyKGBJbnZhbGlkIHVuaXQgJHt1bml0fWApOwogICAgfQogIH0KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KICBjbGFzcyBJbnZhbGlkQXJndW1lbnRFcnJvciBleHRlbmRzIEx1eG9uRXJyb3Ige30KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KICBjbGFzcyBab25lSXNBYnN0cmFjdEVycm9yIGV4dGVuZHMgTHV4b25FcnJvciB7CiAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgc3VwZXIoIlpvbmUgaXMgYW4gYWJzdHJhY3QgY2xhc3MiKTsKICAgIH0KICB9CgogIC8qKgogICAqIEBwcml2YXRlCiAgICovCgogIGNvbnN0IG4gPSAibnVtZXJpYyIsCiAgICBzID0gInNob3J0IiwKICAgIGwgPSAibG9uZyI7CgogIGNvbnN0IERBVEVfU0hPUlQgPSB7CiAgICB5ZWFyOiBuLAogICAgbW9udGg6IG4sCiAgICBkYXk6IG4sCiAgfTsKCiAgY29uc3QgREFURV9NRUQgPSB7CiAgICB5ZWFyOiBuLAogICAgbW9udGg6IHMsCiAgICBkYXk6IG4sCiAgfTsKCiAgY29uc3QgREFURV9NRURfV0lUSF9XRUVLREFZID0gewogICAgeWVhcjogbiwKICAgIG1vbnRoOiBzLAogICAgZGF5OiBuLAogICAgd2Vla2RheTogcywKICB9OwoKICBjb25zdCBEQVRFX0ZVTEwgPSB7CiAgICB5ZWFyOiBuLAogICAgbW9udGg6IGwsCiAgICBkYXk6IG4sCiAgfTsKCiAgY29uc3QgREFURV9IVUdFID0gewogICAgeWVhcjogbiwKICAgIG1vbnRoOiBsLAogICAgZGF5OiBuLAogICAgd2Vla2RheTogbCwKICB9OwoKICBjb25zdCBUSU1FX1NJTVBMRSA9IHsKICAgIGhvdXI6IG4sCiAgICBtaW51dGU6IG4sCiAgfTsKCiAgY29uc3QgVElNRV9XSVRIX1NFQ09ORFMgPSB7CiAgICBob3VyOiBuLAogICAgbWludXRlOiBuLAogICAgc2Vjb25kOiBuLAogIH07CgogIGNvbnN0IFRJTUVfV0lUSF9TSE9SVF9PRkZTRVQgPSB7CiAgICBob3VyOiBuLAogICAgbWludXRlOiBuLAogICAgc2Vjb25kOiBuLAogICAgdGltZVpvbmVOYW1lOiBzLAogIH07CgogIGNvbnN0IFRJTUVfV0lUSF9MT05HX09GRlNFVCA9IHsKICAgIGhvdXI6IG4sCiAgICBtaW51dGU6IG4sCiAgICBzZWNvbmQ6IG4sCiAgICB0aW1lWm9uZU5hbWU6IGwsCiAgfTsKCiAgY29uc3QgVElNRV8yNF9TSU1QTEUgPSB7CiAgICBob3VyOiBuLAogICAgbWludXRlOiBuLAogICAgaG91ckN5Y2xlOiAiaDIzIiwKICB9OwoKICBjb25zdCBUSU1FXzI0X1dJVEhfU0VDT05EUyA9IHsKICAgIGhvdXI6IG4sCiAgICBtaW51dGU6IG4sCiAgICBzZWNvbmQ6IG4sCiAgICBob3VyQ3ljbGU6ICJoMjMiLAogIH07CgogIGNvbnN0IFRJTUVfMjRfV0lUSF9TSE9SVF9PRkZTRVQgPSB7CiAgICBob3VyOiBuLAogICAgbWludXRlOiBuLAogICAgc2Vjb25kOiBuLAogICAgaG91ckN5Y2xlOiAiaDIzIiwKICAgIHRpbWVab25lTmFtZTogcywKICB9OwoKICBjb25zdCBUSU1FXzI0X1dJVEhfTE9OR19PRkZTRVQgPSB7CiAgICBob3VyOiBuLAogICAgbWludXRlOiBuLAogICAgc2Vjb25kOiBuLAogICAgaG91ckN5Y2xlOiAiaDIzIiwKICAgIHRpbWVab25lTmFtZTogbCwKICB9OwoKICBjb25zdCBEQVRFVElNRV9TSE9SVCA9IHsKICAgIHllYXI6IG4sCiAgICBtb250aDogbiwKICAgIGRheTogbiwKICAgIGhvdXI6IG4sCiAgICBtaW51dGU6IG4sCiAgfTsKCiAgY29uc3QgREFURVRJTUVfU0hPUlRfV0lUSF9TRUNPTkRTID0gewogICAgeWVhcjogbiwKICAgIG1vbnRoOiBuLAogICAgZGF5OiBuLAogICAgaG91cjogbiwKICAgIG1pbnV0ZTogbiwKICAgIHNlY29uZDogbiwKICB9OwoKICBjb25zdCBEQVRFVElNRV9NRUQgPSB7CiAgICB5ZWFyOiBuLAogICAgbW9udGg6IHMsCiAgICBkYXk6IG4sCiAgICBob3VyOiBuLAogICAgbWludXRlOiBuLAogIH07CgogIGNvbnN0IERBVEVUSU1FX01FRF9XSVRIX1NFQ09ORFMgPSB7CiAgICB5ZWFyOiBuLAogICAgbW9udGg6IHMsCiAgICBkYXk6IG4sCiAgICBob3VyOiBuLAogICAgbWludXRlOiBuLAogICAgc2Vjb25kOiBuLAogIH07CgogIGNvbnN0IERBVEVUSU1FX01FRF9XSVRIX1dFRUtEQVkgPSB7CiAgICB5ZWFyOiBuLAogICAgbW9udGg6IHMsCiAgICBkYXk6IG4sCiAgICB3ZWVrZGF5OiBzLAogICAgaG91cjogbiwKICAgIG1pbnV0ZTogbiwKICB9OwoKICBjb25zdCBEQVRFVElNRV9GVUxMID0gewogICAgeWVhcjogbiwKICAgIG1vbnRoOiBsLAogICAgZGF5OiBuLAogICAgaG91cjogbiwKICAgIG1pbnV0ZTogbiwKICAgIHRpbWVab25lTmFtZTogcywKICB9OwoKICBjb25zdCBEQVRFVElNRV9GVUxMX1dJVEhfU0VDT05EUyA9IHsKICAgIHllYXI6IG4sCiAgICBtb250aDogbCwKICAgIGRheTogbiwKICAgIGhvdXI6IG4sCiAgICBtaW51dGU6IG4sCiAgICBzZWNvbmQ6IG4sCiAgICB0aW1lWm9uZU5hbWU6IHMsCiAgfTsKCiAgY29uc3QgREFURVRJTUVfSFVHRSA9IHsKICAgIHllYXI6IG4sCiAgICBtb250aDogbCwKICAgIGRheTogbiwKICAgIHdlZWtkYXk6IGwsCiAgICBob3VyOiBuLAogICAgbWludXRlOiBuLAogICAgdGltZVpvbmVOYW1lOiBsLAogIH07CgogIGNvbnN0IERBVEVUSU1FX0hVR0VfV0lUSF9TRUNPTkRTID0gewogICAgeWVhcjogbiwKICAgIG1vbnRoOiBsLAogICAgZGF5OiBuLAogICAgd2Vla2RheTogbCwKICAgIGhvdXI6IG4sCiAgICBtaW51dGU6IG4sCiAgICBzZWNvbmQ6IG4sCiAgICB0aW1lWm9uZU5hbWU6IGwsCiAgfTsKCiAgLyoqCiAgICogQGludGVyZmFjZQogICAqLwogIGNsYXNzIFpvbmUgewogICAgLyoqCiAgICAgKiBUaGUgdHlwZSBvZiB6b25lCiAgICAgKiBAYWJzdHJhY3QKICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIGdldCB0eXBlKCkgewogICAgICB0aHJvdyBuZXcgWm9uZUlzQWJzdHJhY3RFcnJvcigpOwogICAgfQoKICAgIC8qKgogICAgICogVGhlIG5hbWUgb2YgdGhpcyB6b25lLgogICAgICogQGFic3RyYWN0CiAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICovCiAgICBnZXQgbmFtZSgpIHsKICAgICAgdGhyb3cgbmV3IFpvbmVJc0Fic3RyYWN0RXJyb3IoKTsKICAgIH0KCiAgICBnZXQgaWFuYU5hbWUoKSB7CiAgICAgIHJldHVybiB0aGlzLm5hbWU7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhlIG9mZnNldCBpcyBrbm93biB0byBiZSBmaXhlZCBmb3IgdGhlIHdob2xlIHllYXIuCiAgICAgKiBAYWJzdHJhY3QKICAgICAqIEB0eXBlIHtib29sZWFufQogICAgICovCiAgICBnZXQgaXNVbml2ZXJzYWwoKSB7CiAgICAgIHRocm93IG5ldyBab25lSXNBYnN0cmFjdEVycm9yKCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBvZmZzZXQncyBjb21tb24gbmFtZSAoc3VjaCBhcyBFU1QpIGF0IHRoZSBzcGVjaWZpZWQgdGltZXN0YW1wCiAgICAgKiBAYWJzdHJhY3QKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0cyAtIEVwb2NoIG1pbGxpc2Vjb25kcyBmb3Igd2hpY2ggdG8gZ2V0IHRoZSBuYW1lCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIE9wdGlvbnMgdG8gYWZmZWN0IHRoZSBmb3JtYXQKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLmZvcm1hdCAtIFdoYXQgc3R5bGUgb2Ygb2Zmc2V0IHRvIHJldHVybi4gQWNjZXB0cyAnbG9uZycgb3IgJ3Nob3J0Jy4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLmxvY2FsZSAtIFdoYXQgbG9jYWxlIHRvIHJldHVybiB0aGUgb2Zmc2V0IG5hbWUgaW4uCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9CiAgICAgKi8KICAgIG9mZnNldE5hbWUodHMsIG9wdHMpIHsKICAgICAgdGhyb3cgbmV3IFpvbmVJc0Fic3RyYWN0RXJyb3IoKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIG9mZnNldCdzIHZhbHVlIGFzIGEgc3RyaW5nCiAgICAgKiBAYWJzdHJhY3QKICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0cyAtIEVwb2NoIG1pbGxpc2Vjb25kcyBmb3Igd2hpY2ggdG8gZ2V0IHRoZSBvZmZzZXQKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBmb3JtYXQgLSBXaGF0IHN0eWxlIG9mIG9mZnNldCB0byByZXR1cm4uCiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgQWNjZXB0cyAnbmFycm93JywgJ3Nob3J0Jywgb3IgJ3RlY2hpZScuIFJldHVybmluZyAnKzYnLCAnKzA2OjAwJywgb3IgJyswNjAwJyByZXNwZWN0aXZlbHkKICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgZm9ybWF0T2Zmc2V0KHRzLCBmb3JtYXQpIHsKICAgICAgdGhyb3cgbmV3IFpvbmVJc0Fic3RyYWN0RXJyb3IoKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiB0aGUgb2Zmc2V0IGluIG1pbnV0ZXMgZm9yIHRoaXMgem9uZSBhdCB0aGUgc3BlY2lmaWVkIHRpbWVzdGFtcC4KICAgICAqIEBhYnN0cmFjdAogICAgICogQHBhcmFtIHtudW1iZXJ9IHRzIC0gRXBvY2ggbWlsbGlzZWNvbmRzIGZvciB3aGljaCB0byBjb21wdXRlIHRoZSBvZmZzZXQKICAgICAqIEByZXR1cm4ge251bWJlcn0KICAgICAqLwogICAgb2Zmc2V0KHRzKSB7CiAgICAgIHRocm93IG5ldyBab25lSXNBYnN0cmFjdEVycm9yKCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gd2hldGhlciB0aGlzIFpvbmUgaXMgZXF1YWwgdG8gYW5vdGhlciB6b25lCiAgICAgKiBAYWJzdHJhY3QKICAgICAqIEBwYXJhbSB7Wm9uZX0gb3RoZXJab25lIC0gdGhlIHpvbmUgdG8gY29tcGFyZQogICAgICogQHJldHVybiB7Ym9vbGVhbn0KICAgICAqLwogICAgZXF1YWxzKG90aGVyWm9uZSkgewogICAgICB0aHJvdyBuZXcgWm9uZUlzQWJzdHJhY3RFcnJvcigpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIHdoZXRoZXIgdGhpcyBab25lIGlzIHZhbGlkLgogICAgICogQGFic3RyYWN0CiAgICAgKiBAdHlwZSB7Ym9vbGVhbn0KICAgICAqLwogICAgZ2V0IGlzVmFsaWQoKSB7CiAgICAgIHRocm93IG5ldyBab25lSXNBYnN0cmFjdEVycm9yKCk7CiAgICB9CiAgfQoKICBsZXQgc2luZ2xldG9uJDEgPSBudWxsOwoKICAvKioKICAgKiBSZXByZXNlbnRzIHRoZSBsb2NhbCB6b25lIGZvciB0aGlzIEphdmFTY3JpcHQgZW52aXJvbm1lbnQuCiAgICogQGltcGxlbWVudHMge1pvbmV9CiAgICovCiAgY2xhc3MgU3lzdGVtWm9uZSBleHRlbmRzIFpvbmUgewogICAgLyoqCiAgICAgKiBHZXQgYSBzaW5nbGV0b24gaW5zdGFuY2Ugb2YgdGhlIGxvY2FsIHpvbmUKICAgICAqIEByZXR1cm4ge1N5c3RlbVpvbmV9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgaW5zdGFuY2UoKSB7CiAgICAgIGlmIChzaW5nbGV0b24kMSA9PT0gbnVsbCkgewogICAgICAgIHNpbmdsZXRvbiQxID0gbmV3IFN5c3RlbVpvbmUoKTsKICAgICAgfQogICAgICByZXR1cm4gc2luZ2xldG9uJDE7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGdldCB0eXBlKCkgewogICAgICByZXR1cm4gInN5c3RlbSI7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGdldCBuYW1lKCkgewogICAgICByZXR1cm4gbmV3IEludGwuRGF0ZVRpbWVGb3JtYXQoKS5yZXNvbHZlZE9wdGlvbnMoKS50aW1lWm9uZTsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgZ2V0IGlzVW5pdmVyc2FsKCkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIG9mZnNldE5hbWUodHMsIHsgZm9ybWF0LCBsb2NhbGUgfSkgewogICAgICByZXR1cm4gcGFyc2Vab25lSW5mbyh0cywgZm9ybWF0LCBsb2NhbGUpOwogICAgfQoKICAgIC8qKiBAb3ZlcnJpZGUgKiovCiAgICBmb3JtYXRPZmZzZXQodHMsIGZvcm1hdCkgewogICAgICByZXR1cm4gZm9ybWF0T2Zmc2V0KHRoaXMub2Zmc2V0KHRzKSwgZm9ybWF0KTsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgb2Zmc2V0KHRzKSB7CiAgICAgIHJldHVybiAtbmV3IERhdGUodHMpLmdldFRpbWV6b25lT2Zmc2V0KCk7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGVxdWFscyhvdGhlclpvbmUpIHsKICAgICAgcmV0dXJuIG90aGVyWm9uZS50eXBlID09PSAic3lzdGVtIjsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgZ2V0IGlzVmFsaWQoKSB7CiAgICAgIHJldHVybiB0cnVlOwogICAgfQogIH0KCiAgbGV0IGR0ZkNhY2hlID0ge307CiAgZnVuY3Rpb24gbWFrZURURih6b25lKSB7CiAgICBpZiAoIWR0ZkNhY2hlW3pvbmVdKSB7CiAgICAgIGR0ZkNhY2hlW3pvbmVdID0gbmV3IEludGwuRGF0ZVRpbWVGb3JtYXQoImVuLVVTIiwgewogICAgICAgIGhvdXIxMjogZmFsc2UsCiAgICAgICAgdGltZVpvbmU6IHpvbmUsCiAgICAgICAgeWVhcjogIm51bWVyaWMiLAogICAgICAgIG1vbnRoOiAiMi1kaWdpdCIsCiAgICAgICAgZGF5OiAiMi1kaWdpdCIsCiAgICAgICAgaG91cjogIjItZGlnaXQiLAogICAgICAgIG1pbnV0ZTogIjItZGlnaXQiLAogICAgICAgIHNlY29uZDogIjItZGlnaXQiLAogICAgICAgIGVyYTogInNob3J0IiwKICAgICAgfSk7CiAgICB9CiAgICByZXR1cm4gZHRmQ2FjaGVbem9uZV07CiAgfQoKICBjb25zdCB0eXBlVG9Qb3MgPSB7CiAgICB5ZWFyOiAwLAogICAgbW9udGg6IDEsCiAgICBkYXk6IDIsCiAgICBlcmE6IDMsCiAgICBob3VyOiA0LAogICAgbWludXRlOiA1LAogICAgc2Vjb25kOiA2LAogIH07CgogIGZ1bmN0aW9uIGhhY2t5T2Zmc2V0KGR0ZiwgZGF0ZSkgewogICAgY29uc3QgZm9ybWF0dGVkID0gZHRmLmZvcm1hdChkYXRlKS5yZXBsYWNlKC9cdTIwMEUvZywgIiIpLAogICAgICBwYXJzZWQgPSAvKFxkKylcLyhcZCspXC8oXGQrKSAoQUR8QkMpLD8gKFxkKyk6KFxkKyk6KFxkKykvLmV4ZWMoZm9ybWF0dGVkKSwKICAgICAgWywgZk1vbnRoLCBmRGF5LCBmWWVhciwgZmFkT3JCYywgZkhvdXIsIGZNaW51dGUsIGZTZWNvbmRdID0gcGFyc2VkOwogICAgcmV0dXJuIFtmWWVhciwgZk1vbnRoLCBmRGF5LCBmYWRPckJjLCBmSG91ciwgZk1pbnV0ZSwgZlNlY29uZF07CiAgfQoKICBmdW5jdGlvbiBwYXJ0c09mZnNldChkdGYsIGRhdGUpIHsKICAgIGNvbnN0IGZvcm1hdHRlZCA9IGR0Zi5mb3JtYXRUb1BhcnRzKGRhdGUpOwogICAgY29uc3QgZmlsbGVkID0gW107CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGZvcm1hdHRlZC5sZW5ndGg7IGkrKykgewogICAgICBjb25zdCB7IHR5cGUsIHZhbHVlIH0gPSBmb3JtYXR0ZWRbaV07CiAgICAgIGNvbnN0IHBvcyA9IHR5cGVUb1Bvc1t0eXBlXTsKCiAgICAgIGlmICh0eXBlID09PSAiZXJhIikgewogICAgICAgIGZpbGxlZFtwb3NdID0gdmFsdWU7CiAgICAgIH0gZWxzZSBpZiAoIWlzVW5kZWZpbmVkKHBvcykpIHsKICAgICAgICBmaWxsZWRbcG9zXSA9IHBhcnNlSW50KHZhbHVlLCAxMCk7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBmaWxsZWQ7CiAgfQoKICBsZXQgaWFuYVpvbmVDYWNoZSA9IHt9OwogIC8qKgogICAqIEEgem9uZSBpZGVudGlmaWVkIGJ5IGFuIElBTkEgaWRlbnRpZmllciwgbGlrZSBBbWVyaWNhL05ld19Zb3JrCiAgICogQGltcGxlbWVudHMge1pvbmV9CiAgICovCiAgY2xhc3MgSUFOQVpvbmUgZXh0ZW5kcyBab25lIHsKICAgIC8qKgogICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBab25lIG5hbWUKICAgICAqIEByZXR1cm4ge0lBTkFab25lfQogICAgICovCiAgICBzdGF0aWMgY3JlYXRlKG5hbWUpIHsKICAgICAgaWYgKCFpYW5hWm9uZUNhY2hlW25hbWVdKSB7CiAgICAgICAgaWFuYVpvbmVDYWNoZVtuYW1lXSA9IG5ldyBJQU5BWm9uZShuYW1lKTsKICAgICAgfQogICAgICByZXR1cm4gaWFuYVpvbmVDYWNoZVtuYW1lXTsKICAgIH0KCiAgICAvKioKICAgICAqIFJlc2V0IGxvY2FsIGNhY2hlcy4gU2hvdWxkIG9ubHkgYmUgbmVjZXNzYXJ5IGluIHRlc3Rpbmcgc2NlbmFyaW9zLgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgc3RhdGljIHJlc2V0Q2FjaGUoKSB7CiAgICAgIGlhbmFab25lQ2FjaGUgPSB7fTsKICAgICAgZHRmQ2FjaGUgPSB7fTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgd2hldGhlciB0aGUgcHJvdmlkZWQgc3RyaW5nIGlzIGEgdmFsaWQgc3BlY2lmaWVyLiBUaGlzIG9ubHkgY2hlY2tzIHRoZSBzdHJpbmcncyBmb3JtYXQsIG5vdCB0aGF0IHRoZSBzcGVjaWZpZXIgaWRlbnRpZmllcyBhIGtub3duIHpvbmU7IHNlZSBpc1ZhbGlkWm9uZSBmb3IgdGhhdC4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzIC0gVGhlIHN0cmluZyB0byBjaGVjayB2YWxpZGl0eSBvbgogICAgICogQGV4YW1wbGUgSUFOQVpvbmUuaXNWYWxpZFNwZWNpZmllcigiQW1lcmljYS9OZXdfWW9yayIpIC8vPT4gdHJ1ZQogICAgICogQGV4YW1wbGUgSUFOQVpvbmUuaXNWYWxpZFNwZWNpZmllcigiU3BvcnR+fmJsb3JwIikgLy89PiBmYWxzZQogICAgICogQGRlcHJlY2F0ZWQgVGhpcyBtZXRob2QgcmV0dXJucyBmYWxzZSBmb3Igc29tZSB2YWxpZCBJQU5BIG5hbWVzLiBVc2UgaXNWYWxpZFpvbmUgaW5zdGVhZC4KICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIHN0YXRpYyBpc1ZhbGlkU3BlY2lmaWVyKHMpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZFpvbmUocyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhlIHByb3ZpZGVkIHN0cmluZyBpZGVudGlmaWVzIGEgcmVhbCB6b25lCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gem9uZSAtIFRoZSBzdHJpbmcgdG8gY2hlY2sKICAgICAqIEBleGFtcGxlIElBTkFab25lLmlzVmFsaWRab25lKCJBbWVyaWNhL05ld19Zb3JrIikgLy89PiB0cnVlCiAgICAgKiBAZXhhbXBsZSBJQU5BWm9uZS5pc1ZhbGlkWm9uZSgiRmFudGFzaWEvQ2FzdGxlIikgLy89PiBmYWxzZQogICAgICogQGV4YW1wbGUgSUFOQVpvbmUuaXNWYWxpZFpvbmUoIlNwb3J0fn5ibG9ycCIpIC8vPT4gZmFsc2UKICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIHN0YXRpYyBpc1ZhbGlkWm9uZSh6b25lKSB7CiAgICAgIGlmICghem9uZSkgewogICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgfQogICAgICB0cnkgewogICAgICAgIG5ldyBJbnRsLkRhdGVUaW1lRm9ybWF0KCJlbi1VUyIsIHsgdGltZVpvbmU6IHpvbmUgfSkuZm9ybWF0KCk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgIH0KICAgIH0KCiAgICBjb25zdHJ1Y3RvcihuYW1lKSB7CiAgICAgIHN1cGVyKCk7CiAgICAgIC8qKiBAcHJpdmF0ZSAqKi8KICAgICAgdGhpcy56b25lTmFtZSA9IG5hbWU7CiAgICAgIC8qKiBAcHJpdmF0ZSAqKi8KICAgICAgdGhpcy52YWxpZCA9IElBTkFab25lLmlzVmFsaWRab25lKG5hbWUpOwogICAgfQoKICAgIC8qKiBAb3ZlcnJpZGUgKiovCiAgICBnZXQgdHlwZSgpIHsKICAgICAgcmV0dXJuICJpYW5hIjsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgZ2V0IG5hbWUoKSB7CiAgICAgIHJldHVybiB0aGlzLnpvbmVOYW1lOwogICAgfQoKICAgIC8qKiBAb3ZlcnJpZGUgKiovCiAgICBnZXQgaXNVbml2ZXJzYWwoKSB7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgb2Zmc2V0TmFtZSh0cywgeyBmb3JtYXQsIGxvY2FsZSB9KSB7CiAgICAgIHJldHVybiBwYXJzZVpvbmVJbmZvKHRzLCBmb3JtYXQsIGxvY2FsZSwgdGhpcy5uYW1lKTsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgZm9ybWF0T2Zmc2V0KHRzLCBmb3JtYXQpIHsKICAgICAgcmV0dXJuIGZvcm1hdE9mZnNldCh0aGlzLm9mZnNldCh0cyksIGZvcm1hdCk7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIG9mZnNldCh0cykgewogICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUodHMpOwoKICAgICAgaWYgKGlzTmFOKGRhdGUpKSByZXR1cm4gTmFOOwoKICAgICAgY29uc3QgZHRmID0gbWFrZURURih0aGlzLm5hbWUpOwogICAgICBsZXQgW3llYXIsIG1vbnRoLCBkYXksIGFkT3JCYywgaG91ciwgbWludXRlLCBzZWNvbmRdID0gZHRmLmZvcm1hdFRvUGFydHMKICAgICAgICA/IHBhcnRzT2Zmc2V0KGR0ZiwgZGF0ZSkKICAgICAgICA6IGhhY2t5T2Zmc2V0KGR0ZiwgZGF0ZSk7CgogICAgICBpZiAoYWRPckJjID09PSAiQkMiKSB7CiAgICAgICAgeWVhciA9IC1NYXRoLmFicyh5ZWFyKSArIDE7CiAgICAgIH0KCiAgICAgIC8vIGJlY2F1c2Ugd2UncmUgdXNpbmcgaG91cjEyIGFuZCBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0xMDI1NTY0JmNhbj0yJnE9JTIyMjQlM0EwMCUyMiUyMGRhdGV0aW1lZm9ybWF0CiAgICAgIGNvbnN0IGFkanVzdGVkSG91ciA9IGhvdXIgPT09IDI0ID8gMCA6IGhvdXI7CgogICAgICBjb25zdCBhc1VUQyA9IG9ialRvTG9jYWxUUyh7CiAgICAgICAgeWVhciwKICAgICAgICBtb250aCwKICAgICAgICBkYXksCiAgICAgICAgaG91cjogYWRqdXN0ZWRIb3VyLAogICAgICAgIG1pbnV0ZSwKICAgICAgICBzZWNvbmQsCiAgICAgICAgbWlsbGlzZWNvbmQ6IDAsCiAgICAgIH0pOwoKICAgICAgbGV0IGFzVFMgPSArZGF0ZTsKICAgICAgY29uc3Qgb3ZlciA9IGFzVFMgJSAxMDAwOwogICAgICBhc1RTIC09IG92ZXIgPj0gMCA/IG92ZXIgOiAxMDAwICsgb3ZlcjsKICAgICAgcmV0dXJuIChhc1VUQyAtIGFzVFMpIC8gKDYwICogMTAwMCk7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGVxdWFscyhvdGhlclpvbmUpIHsKICAgICAgcmV0dXJuIG90aGVyWm9uZS50eXBlID09PSAiaWFuYSIgJiYgb3RoZXJab25lLm5hbWUgPT09IHRoaXMubmFtZTsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgZ2V0IGlzVmFsaWQoKSB7CiAgICAgIHJldHVybiB0aGlzLnZhbGlkOwogICAgfQogIH0KCiAgLy8gdG9kbyAtIHJlbWFwIGNhY2hpbmcKCiAgbGV0IGludGxMRkNhY2hlID0ge307CiAgZnVuY3Rpb24gZ2V0Q2FjaGVkTEYobG9jU3RyaW5nLCBvcHRzID0ge30pIHsKICAgIGNvbnN0IGtleSA9IEpTT04uc3RyaW5naWZ5KFtsb2NTdHJpbmcsIG9wdHNdKTsKICAgIGxldCBkdGYgPSBpbnRsTEZDYWNoZVtrZXldOwogICAgaWYgKCFkdGYpIHsKICAgICAgZHRmID0gbmV3IEludGwuTGlzdEZvcm1hdChsb2NTdHJpbmcsIG9wdHMpOwogICAgICBpbnRsTEZDYWNoZVtrZXldID0gZHRmOwogICAgfQogICAgcmV0dXJuIGR0ZjsKICB9CgogIGxldCBpbnRsRFRDYWNoZSA9IHt9OwogIGZ1bmN0aW9uIGdldENhY2hlZERURihsb2NTdHJpbmcsIG9wdHMgPSB7fSkgewogICAgY29uc3Qga2V5ID0gSlNPTi5zdHJpbmdpZnkoW2xvY1N0cmluZywgb3B0c10pOwogICAgbGV0IGR0ZiA9IGludGxEVENhY2hlW2tleV07CiAgICBpZiAoIWR0ZikgewogICAgICBkdGYgPSBuZXcgSW50bC5EYXRlVGltZUZvcm1hdChsb2NTdHJpbmcsIG9wdHMpOwogICAgICBpbnRsRFRDYWNoZVtrZXldID0gZHRmOwogICAgfQogICAgcmV0dXJuIGR0ZjsKICB9CgogIGxldCBpbnRsTnVtQ2FjaGUgPSB7fTsKICBmdW5jdGlvbiBnZXRDYWNoZWRJTkYobG9jU3RyaW5nLCBvcHRzID0ge30pIHsKICAgIGNvbnN0IGtleSA9IEpTT04uc3RyaW5naWZ5KFtsb2NTdHJpbmcsIG9wdHNdKTsKICAgIGxldCBpbmYgPSBpbnRsTnVtQ2FjaGVba2V5XTsKICAgIGlmICghaW5mKSB7CiAgICAgIGluZiA9IG5ldyBJbnRsLk51bWJlckZvcm1hdChsb2NTdHJpbmcsIG9wdHMpOwogICAgICBpbnRsTnVtQ2FjaGVba2V5XSA9IGluZjsKICAgIH0KICAgIHJldHVybiBpbmY7CiAgfQoKICBsZXQgaW50bFJlbENhY2hlID0ge307CiAgZnVuY3Rpb24gZ2V0Q2FjaGVkUlRGKGxvY1N0cmluZywgb3B0cyA9IHt9KSB7CiAgICBjb25zdCB7IGJhc2UsIC4uLmNhY2hlS2V5T3B0cyB9ID0gb3B0czsgLy8gZXhjbHVkZSBgYmFzZWAgZnJvbSB0aGUgb3B0aW9ucwogICAgY29uc3Qga2V5ID0gSlNPTi5zdHJpbmdpZnkoW2xvY1N0cmluZywgY2FjaGVLZXlPcHRzXSk7CiAgICBsZXQgaW5mID0gaW50bFJlbENhY2hlW2tleV07CiAgICBpZiAoIWluZikgewogICAgICBpbmYgPSBuZXcgSW50bC5SZWxhdGl2ZVRpbWVGb3JtYXQobG9jU3RyaW5nLCBvcHRzKTsKICAgICAgaW50bFJlbENhY2hlW2tleV0gPSBpbmY7CiAgICB9CiAgICByZXR1cm4gaW5mOwogIH0KCiAgbGV0IHN5c0xvY2FsZUNhY2hlID0gbnVsbDsKICBmdW5jdGlvbiBzeXN0ZW1Mb2NhbGUoKSB7CiAgICBpZiAoc3lzTG9jYWxlQ2FjaGUpIHsKICAgICAgcmV0dXJuIHN5c0xvY2FsZUNhY2hlOwogICAgfSBlbHNlIHsKICAgICAgc3lzTG9jYWxlQ2FjaGUgPSBuZXcgSW50bC5EYXRlVGltZUZvcm1hdCgpLnJlc29sdmVkT3B0aW9ucygpLmxvY2FsZTsKICAgICAgcmV0dXJuIHN5c0xvY2FsZUNhY2hlOwogICAgfQogIH0KCiAgZnVuY3Rpb24gcGFyc2VMb2NhbGVTdHJpbmcobG9jYWxlU3RyKSB7CiAgICAvLyBJIHJlYWxseSB3YW50IHRvIGF2b2lkIHdyaXRpbmcgYSBCQ1AgNDcgcGFyc2VyCiAgICAvLyBzZWUsIGUuZy4gaHR0cHM6Ly9naXRodWIuY29tL3dvb29ybS9iY3AtNDcKICAgIC8vIEluc3RlYWQsIHdlJ2xsIGRvIHRoaXM6CgogICAgLy8gYSkgaWYgdGhlIHN0cmluZyBoYXMgbm8gLXUgZXh0ZW5zaW9ucywganVzdCBsZWF2ZSBpdCBhbG9uZQogICAgLy8gYikgaWYgaXQgZG9lcywgdXNlIEludGwgdG8gcmVzb2x2ZSBldmVyeXRoaW5nCiAgICAvLyBjKSBpZiBJbnRsIGZhaWxzLCB0cnkgYWdhaW4gd2l0aG91dCB0aGUgLXUKCiAgICAvLyBwcml2YXRlIHN1YnRhZ3MgYW5kIHVuaWNvZGUgc3VidGFncyBoYXZlIG9yZGVyaW5nIHJlcXVpcmVtZW50cywKICAgIC8vIGFuZCB3ZSdyZSBub3QgcHJvcGVybHkgcGFyc2luZyB0aGlzLCBzbyBqdXN0IHN0cmlwIG91dCB0aGUKICAgIC8vIHByaXZhdGUgb25lcyBpZiB0aGV5IGV4aXN0LgogICAgY29uc3QgeEluZGV4ID0gbG9jYWxlU3RyLmluZGV4T2YoIi14LSIpOwogICAgaWYgKHhJbmRleCAhPT0gLTEpIHsKICAgICAgbG9jYWxlU3RyID0gbG9jYWxlU3RyLnN1YnN0cmluZygwLCB4SW5kZXgpOwogICAgfQoKICAgIGNvbnN0IHVJbmRleCA9IGxvY2FsZVN0ci5pbmRleE9mKCItdS0iKTsKICAgIGlmICh1SW5kZXggPT09IC0xKSB7CiAgICAgIHJldHVybiBbbG9jYWxlU3RyXTsKICAgIH0gZWxzZSB7CiAgICAgIGxldCBvcHRpb25zOwogICAgICBsZXQgc2VsZWN0ZWRTdHI7CiAgICAgIHRyeSB7CiAgICAgICAgb3B0aW9ucyA9IGdldENhY2hlZERURihsb2NhbGVTdHIpLnJlc29sdmVkT3B0aW9ucygpOwogICAgICAgIHNlbGVjdGVkU3RyID0gbG9jYWxlU3RyOwogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgY29uc3Qgc21hbGxlciA9IGxvY2FsZVN0ci5zdWJzdHJpbmcoMCwgdUluZGV4KTsKICAgICAgICBvcHRpb25zID0gZ2V0Q2FjaGVkRFRGKHNtYWxsZXIpLnJlc29sdmVkT3B0aW9ucygpOwogICAgICAgIHNlbGVjdGVkU3RyID0gc21hbGxlcjsKICAgICAgfQoKICAgICAgY29uc3QgeyBudW1iZXJpbmdTeXN0ZW0sIGNhbGVuZGFyIH0gPSBvcHRpb25zOwogICAgICByZXR1cm4gW3NlbGVjdGVkU3RyLCBudW1iZXJpbmdTeXN0ZW0sIGNhbGVuZGFyXTsKICAgIH0KICB9CgogIGZ1bmN0aW9uIGludGxDb25maWdTdHJpbmcobG9jYWxlU3RyLCBudW1iZXJpbmdTeXN0ZW0sIG91dHB1dENhbGVuZGFyKSB7CiAgICBpZiAob3V0cHV0Q2FsZW5kYXIgfHwgbnVtYmVyaW5nU3lzdGVtKSB7CiAgICAgIGlmICghbG9jYWxlU3RyLmluY2x1ZGVzKCItdS0iKSkgewogICAgICAgIGxvY2FsZVN0ciArPSAiLXUiOwogICAgICB9CgogICAgICBpZiAob3V0cHV0Q2FsZW5kYXIpIHsKICAgICAgICBsb2NhbGVTdHIgKz0gYC1jYS0ke291dHB1dENhbGVuZGFyfWA7CiAgICAgIH0KCiAgICAgIGlmIChudW1iZXJpbmdTeXN0ZW0pIHsKICAgICAgICBsb2NhbGVTdHIgKz0gYC1udS0ke251bWJlcmluZ1N5c3RlbX1gOwogICAgICB9CiAgICAgIHJldHVybiBsb2NhbGVTdHI7CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gbG9jYWxlU3RyOwogICAgfQogIH0KCiAgZnVuY3Rpb24gbWFwTW9udGhzKGYpIHsKICAgIGNvbnN0IG1zID0gW107CiAgICBmb3IgKGxldCBpID0gMTsgaSA8PSAxMjsgaSsrKSB7CiAgICAgIGNvbnN0IGR0ID0gRGF0ZVRpbWUudXRjKDIwMDksIGksIDEpOwogICAgICBtcy5wdXNoKGYoZHQpKTsKICAgIH0KICAgIHJldHVybiBtczsKICB9CgogIGZ1bmN0aW9uIG1hcFdlZWtkYXlzKGYpIHsKICAgIGNvbnN0IG1zID0gW107CiAgICBmb3IgKGxldCBpID0gMTsgaSA8PSA3OyBpKyspIHsKICAgICAgY29uc3QgZHQgPSBEYXRlVGltZS51dGMoMjAxNiwgMTEsIDEzICsgaSk7CiAgICAgIG1zLnB1c2goZihkdCkpOwogICAgfQogICAgcmV0dXJuIG1zOwogIH0KCiAgZnVuY3Rpb24gbGlzdFN0dWZmKGxvYywgbGVuZ3RoLCBlbmdsaXNoRm4sIGludGxGbikgewogICAgY29uc3QgbW9kZSA9IGxvYy5saXN0aW5nTW9kZSgpOwoKICAgIGlmIChtb2RlID09PSAiZXJyb3IiKSB7CiAgICAgIHJldHVybiBudWxsOwogICAgfSBlbHNlIGlmIChtb2RlID09PSAiZW4iKSB7CiAgICAgIHJldHVybiBlbmdsaXNoRm4obGVuZ3RoKTsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiBpbnRsRm4obGVuZ3RoKTsKICAgIH0KICB9CgogIGZ1bmN0aW9uIHN1cHBvcnRzRmFzdE51bWJlcnMobG9jKSB7CiAgICBpZiAobG9jLm51bWJlcmluZ1N5c3RlbSAmJiBsb2MubnVtYmVyaW5nU3lzdGVtICE9PSAibGF0biIpIHsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuICgKICAgICAgICBsb2MubnVtYmVyaW5nU3lzdGVtID09PSAibGF0biIgfHwKICAgICAgICAhbG9jLmxvY2FsZSB8fAogICAgICAgIGxvYy5sb2NhbGUuc3RhcnRzV2l0aCgiZW4iKSB8fAogICAgICAgIG5ldyBJbnRsLkRhdGVUaW1lRm9ybWF0KGxvYy5pbnRsKS5yZXNvbHZlZE9wdGlvbnMoKS5udW1iZXJpbmdTeXN0ZW0gPT09ICJsYXRuIgogICAgICApOwogICAgfQogIH0KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KCiAgY2xhc3MgUG9seU51bWJlckZvcm1hdHRlciB7CiAgICBjb25zdHJ1Y3RvcihpbnRsLCBmb3JjZVNpbXBsZSwgb3B0cykgewogICAgICB0aGlzLnBhZFRvID0gb3B0cy5wYWRUbyB8fCAwOwogICAgICB0aGlzLmZsb29yID0gb3B0cy5mbG9vciB8fCBmYWxzZTsKCiAgICAgIGNvbnN0IHsgcGFkVG8sIGZsb29yLCAuLi5vdGhlck9wdHMgfSA9IG9wdHM7CgogICAgICBpZiAoIWZvcmNlU2ltcGxlIHx8IE9iamVjdC5rZXlzKG90aGVyT3B0cykubGVuZ3RoID4gMCkgewogICAgICAgIGNvbnN0IGludGxPcHRzID0geyB1c2VHcm91cGluZzogZmFsc2UsIC4uLm9wdHMgfTsKICAgICAgICBpZiAob3B0cy5wYWRUbyA+IDApIGludGxPcHRzLm1pbmltdW1JbnRlZ2VyRGlnaXRzID0gb3B0cy5wYWRUbzsKICAgICAgICB0aGlzLmluZiA9IGdldENhY2hlZElORihpbnRsLCBpbnRsT3B0cyk7CiAgICAgIH0KICAgIH0KCiAgICBmb3JtYXQoaSkgewogICAgICBpZiAodGhpcy5pbmYpIHsKICAgICAgICBjb25zdCBmaXhlZCA9IHRoaXMuZmxvb3IgPyBNYXRoLmZsb29yKGkpIDogaTsKICAgICAgICByZXR1cm4gdGhpcy5pbmYuZm9ybWF0KGZpeGVkKTsKICAgICAgfSBlbHNlIHsKICAgICAgICAvLyB0byBtYXRjaCB0aGUgYnJvd3NlcidzIG51bWJlcmZvcm1hdHRlciBkZWZhdWx0cwogICAgICAgIGNvbnN0IGZpeGVkID0gdGhpcy5mbG9vciA/IE1hdGguZmxvb3IoaSkgOiByb3VuZFRvKGksIDMpOwogICAgICAgIHJldHVybiBwYWRTdGFydChmaXhlZCwgdGhpcy5wYWRUbyk7CiAgICAgIH0KICAgIH0KICB9CgogIC8qKgogICAqIEBwcml2YXRlCiAgICovCgogIGNsYXNzIFBvbHlEYXRlRm9ybWF0dGVyIHsKICAgIGNvbnN0cnVjdG9yKGR0LCBpbnRsLCBvcHRzKSB7CiAgICAgIHRoaXMub3B0cyA9IG9wdHM7CiAgICAgIHRoaXMub3JpZ2luYWxab25lID0gdW5kZWZpbmVkOwoKICAgICAgbGV0IHogPSB1bmRlZmluZWQ7CiAgICAgIGlmICh0aGlzLm9wdHMudGltZVpvbmUpIHsKICAgICAgICAvLyBEb24ndCBhcHBseSBhbnkgd29ya2Fyb3VuZHMgaWYgYSB0aW1lWm9uZSBpcyBleHBsaWNpdGx5IHByb3ZpZGVkIGluIG9wdHMKICAgICAgICB0aGlzLmR0ID0gZHQ7CiAgICAgIH0gZWxzZSBpZiAoZHQuem9uZS50eXBlID09PSAiZml4ZWQiKSB7CiAgICAgICAgLy8gVVRDLTggb3IgRXRjL1VUQy04IGFyZSBub3QgcGFydCBvZiB0emRhdGEsIG9ubHkgRXRjL0dNVCs4IGFuZCB0aGUgbGlrZS4KICAgICAgICAvLyBUaGF0IGlzIHdoeSBmaXhlZC1vZmZzZXQgVFogaXMgc2V0IHRvIHRoYXQgdW5sZXNzIGl0IGlzOgogICAgICAgIC8vIDEuIFJlcHJlc2VudGluZyBvZmZzZXQgMCB3aGVuIFVUQyBpcyB1c2VkIHRvIG1haW50YWluIHByZXZpb3VzIGJlaGF2aW9yIGFuZCBkb2VzIG5vdCBiZWNvbWUgR01ULgogICAgICAgIC8vIDIuIFVuc3VwcG9ydGVkIGJ5IHRoZSBicm93c2VyOgogICAgICAgIC8vICAgIC0gc29tZSBkbyBub3Qgc3VwcG9ydCBFdGMvCiAgICAgICAgLy8gICAgLSA8IEV0Yy9HTVQtMTQsID4gRXRjL0dNVCsxMiwgYW5kIDMwLW1pbnV0ZSBvciA0NS1taW51dGUgb2Zmc2V0cyBhcmUgbm90IHBhcnQgb2YgdHpkYXRhCiAgICAgICAgY29uc3QgZ210T2Zmc2V0ID0gLTEgKiAoZHQub2Zmc2V0IC8gNjApOwogICAgICAgIGNvbnN0IG9mZnNldFogPSBnbXRPZmZzZXQgPj0gMCA/IGBFdGMvR01UKyR7Z210T2Zmc2V0fWAgOiBgRXRjL0dNVCR7Z210T2Zmc2V0fWA7CiAgICAgICAgaWYgKGR0Lm9mZnNldCAhPT0gMCAmJiBJQU5BWm9uZS5jcmVhdGUob2Zmc2V0WikudmFsaWQpIHsKICAgICAgICAgIHogPSBvZmZzZXRaOwogICAgICAgICAgdGhpcy5kdCA9IGR0OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAvLyBOb3QgYWxsIGZpeGVkLW9mZnNldCB6b25lcyBsaWtlIEV0Yy8rNDozMCBhcmUgcHJlc2VudCBpbiB0emRhdGEgc28KICAgICAgICAgIC8vIHdlIG1hbnVhbGx5IGFwcGx5IHRoZSBvZmZzZXQgYW5kIHN1YnN0aXR1dGUgdGhlIHpvbmUgYXMgbmVlZGVkLgogICAgICAgICAgeiA9ICJVVEMiOwogICAgICAgICAgdGhpcy5kdCA9IGR0Lm9mZnNldCA9PT0gMCA/IGR0IDogZHQuc2V0Wm9uZSgiVVRDIikucGx1cyh7IG1pbnV0ZXM6IGR0Lm9mZnNldCB9KTsKICAgICAgICAgIHRoaXMub3JpZ2luYWxab25lID0gZHQuem9uZTsKICAgICAgICB9CiAgICAgIH0gZWxzZSBpZiAoZHQuem9uZS50eXBlID09PSAic3lzdGVtIikgewogICAgICAgIHRoaXMuZHQgPSBkdDsKICAgICAgfSBlbHNlIGlmIChkdC56b25lLnR5cGUgPT09ICJpYW5hIikgewogICAgICAgIHRoaXMuZHQgPSBkdDsKICAgICAgICB6ID0gZHQuem9uZS5uYW1lOwogICAgICB9IGVsc2UgewogICAgICAgIC8vIEN1c3RvbSB6b25lcyBjYW4gaGF2ZSBhbnkgb2Zmc2V0IC8gb2Zmc2V0TmFtZSBzbyB3ZSBqdXN0IG1hbnVhbGx5CiAgICAgICAgLy8gYXBwbHkgdGhlIG9mZnNldCBhbmQgc3Vic3RpdHV0ZSB0aGUgem9uZSBhcyBuZWVkZWQuCiAgICAgICAgeiA9ICJVVEMiOwogICAgICAgIHRoaXMuZHQgPSBkdC5zZXRab25lKCJVVEMiKS5wbHVzKHsgbWludXRlczogZHQub2Zmc2V0IH0pOwogICAgICAgIHRoaXMub3JpZ2luYWxab25lID0gZHQuem9uZTsKICAgICAgfQoKICAgICAgY29uc3QgaW50bE9wdHMgPSB7IC4uLnRoaXMub3B0cyB9OwogICAgICBpbnRsT3B0cy50aW1lWm9uZSA9IGludGxPcHRzLnRpbWVab25lIHx8IHo7CiAgICAgIHRoaXMuZHRmID0gZ2V0Q2FjaGVkRFRGKGludGwsIGludGxPcHRzKTsKICAgIH0KCiAgICBmb3JtYXQoKSB7CiAgICAgIGlmICh0aGlzLm9yaWdpbmFsWm9uZSkgewogICAgICAgIC8vIElmIHdlIGhhdmUgdG8gc3Vic3RpdHV0ZSBpbiB0aGUgYWN0dWFsIHpvbmUgbmFtZSwgd2UgaGF2ZSB0byB1c2UKICAgICAgICAvLyBmb3JtYXRUb1BhcnRzIHNvIHRoYXQgdGhlIHRpbWV6b25lIGNhbiBiZSByZXBsYWNlZC4KICAgICAgICByZXR1cm4gdGhpcy5mb3JtYXRUb1BhcnRzKCkKICAgICAgICAgIC5tYXAoKHsgdmFsdWUgfSkgPT4gdmFsdWUpCiAgICAgICAgICAuam9pbigiIik7CiAgICAgIH0KICAgICAgcmV0dXJuIHRoaXMuZHRmLmZvcm1hdCh0aGlzLmR0LnRvSlNEYXRlKCkpOwogICAgfQoKICAgIGZvcm1hdFRvUGFydHMoKSB7CiAgICAgIGNvbnN0IHBhcnRzID0gdGhpcy5kdGYuZm9ybWF0VG9QYXJ0cyh0aGlzLmR0LnRvSlNEYXRlKCkpOwogICAgICBpZiAodGhpcy5vcmlnaW5hbFpvbmUpIHsKICAgICAgICByZXR1cm4gcGFydHMubWFwKChwYXJ0KSA9PiB7CiAgICAgICAgICBpZiAocGFydC50eXBlID09PSAidGltZVpvbmVOYW1lIikgewogICAgICAgICAgICBjb25zdCBvZmZzZXROYW1lID0gdGhpcy5vcmlnaW5hbFpvbmUub2Zmc2V0TmFtZSh0aGlzLmR0LnRzLCB7CiAgICAgICAgICAgICAgbG9jYWxlOiB0aGlzLmR0LmxvY2FsZSwKICAgICAgICAgICAgICBmb3JtYXQ6IHRoaXMub3B0cy50aW1lWm9uZU5hbWUsCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgIC4uLnBhcnQsCiAgICAgICAgICAgICAgdmFsdWU6IG9mZnNldE5hbWUsCiAgICAgICAgICAgIH07CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gcGFydDsKICAgICAgICAgIH0KICAgICAgICB9KTsKICAgICAgfQogICAgICByZXR1cm4gcGFydHM7CiAgICB9CgogICAgcmVzb2x2ZWRPcHRpb25zKCkgewogICAgICByZXR1cm4gdGhpcy5kdGYucmVzb2x2ZWRPcHRpb25zKCk7CiAgICB9CiAgfQoKICAvKioKICAgKiBAcHJpdmF0ZQogICAqLwogIGNsYXNzIFBvbHlSZWxGb3JtYXR0ZXIgewogICAgY29uc3RydWN0b3IoaW50bCwgaXNFbmdsaXNoLCBvcHRzKSB7CiAgICAgIHRoaXMub3B0cyA9IHsgc3R5bGU6ICJsb25nIiwgLi4ub3B0cyB9OwogICAgICBpZiAoIWlzRW5nbGlzaCAmJiBoYXNSZWxhdGl2ZSgpKSB7CiAgICAgICAgdGhpcy5ydGYgPSBnZXRDYWNoZWRSVEYoaW50bCwgb3B0cyk7CiAgICAgIH0KICAgIH0KCiAgICBmb3JtYXQoY291bnQsIHVuaXQpIHsKICAgICAgaWYgKHRoaXMucnRmKSB7CiAgICAgICAgcmV0dXJuIHRoaXMucnRmLmZvcm1hdChjb3VudCwgdW5pdCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIGZvcm1hdFJlbGF0aXZlVGltZSh1bml0LCBjb3VudCwgdGhpcy5vcHRzLm51bWVyaWMsIHRoaXMub3B0cy5zdHlsZSAhPT0gImxvbmciKTsKICAgICAgfQogICAgfQoKICAgIGZvcm1hdFRvUGFydHMoY291bnQsIHVuaXQpIHsKICAgICAgaWYgKHRoaXMucnRmKSB7CiAgICAgICAgcmV0dXJuIHRoaXMucnRmLmZvcm1hdFRvUGFydHMoY291bnQsIHVuaXQpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBbXTsKICAgICAgfQogICAgfQogIH0KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KCiAgY2xhc3MgTG9jYWxlIHsKICAgIHN0YXRpYyBmcm9tT3B0cyhvcHRzKSB7CiAgICAgIHJldHVybiBMb2NhbGUuY3JlYXRlKG9wdHMubG9jYWxlLCBvcHRzLm51bWJlcmluZ1N5c3RlbSwgb3B0cy5vdXRwdXRDYWxlbmRhciwgb3B0cy5kZWZhdWx0VG9FTik7CiAgICB9CgogICAgc3RhdGljIGNyZWF0ZShsb2NhbGUsIG51bWJlcmluZ1N5c3RlbSwgb3V0cHV0Q2FsZW5kYXIsIGRlZmF1bHRUb0VOID0gZmFsc2UpIHsKICAgICAgY29uc3Qgc3BlY2lmaWVkTG9jYWxlID0gbG9jYWxlIHx8IFNldHRpbmdzLmRlZmF1bHRMb2NhbGU7CiAgICAgIC8vIHRoZSBzeXN0ZW0gbG9jYWxlIGlzIHVzZWZ1bCBmb3IgaHVtYW4gcmVhZGFibGUgc3RyaW5ncyBidXQgYW5ub3lpbmcgZm9yIHBhcnNpbmcvZm9ybWF0dGluZyBrbm93biBmb3JtYXRzCiAgICAgIGNvbnN0IGxvY2FsZVIgPSBzcGVjaWZpZWRMb2NhbGUgfHwgKGRlZmF1bHRUb0VOID8gImVuLVVTIiA6IHN5c3RlbUxvY2FsZSgpKTsKICAgICAgY29uc3QgbnVtYmVyaW5nU3lzdGVtUiA9IG51bWJlcmluZ1N5c3RlbSB8fCBTZXR0aW5ncy5kZWZhdWx0TnVtYmVyaW5nU3lzdGVtOwogICAgICBjb25zdCBvdXRwdXRDYWxlbmRhclIgPSBvdXRwdXRDYWxlbmRhciB8fCBTZXR0aW5ncy5kZWZhdWx0T3V0cHV0Q2FsZW5kYXI7CiAgICAgIHJldHVybiBuZXcgTG9jYWxlKGxvY2FsZVIsIG51bWJlcmluZ1N5c3RlbVIsIG91dHB1dENhbGVuZGFyUiwgc3BlY2lmaWVkTG9jYWxlKTsKICAgIH0KCiAgICBzdGF0aWMgcmVzZXRDYWNoZSgpIHsKICAgICAgc3lzTG9jYWxlQ2FjaGUgPSBudWxsOwogICAgICBpbnRsRFRDYWNoZSA9IHt9OwogICAgICBpbnRsTnVtQ2FjaGUgPSB7fTsKICAgICAgaW50bFJlbENhY2hlID0ge307CiAgICB9CgogICAgc3RhdGljIGZyb21PYmplY3QoeyBsb2NhbGUsIG51bWJlcmluZ1N5c3RlbSwgb3V0cHV0Q2FsZW5kYXIgfSA9IHt9KSB7CiAgICAgIHJldHVybiBMb2NhbGUuY3JlYXRlKGxvY2FsZSwgbnVtYmVyaW5nU3lzdGVtLCBvdXRwdXRDYWxlbmRhcik7CiAgICB9CgogICAgY29uc3RydWN0b3IobG9jYWxlLCBudW1iZXJpbmcsIG91dHB1dENhbGVuZGFyLCBzcGVjaWZpZWRMb2NhbGUpIHsKICAgICAgY29uc3QgW3BhcnNlZExvY2FsZSwgcGFyc2VkTnVtYmVyaW5nU3lzdGVtLCBwYXJzZWRPdXRwdXRDYWxlbmRhcl0gPSBwYXJzZUxvY2FsZVN0cmluZyhsb2NhbGUpOwoKICAgICAgdGhpcy5sb2NhbGUgPSBwYXJzZWRMb2NhbGU7CiAgICAgIHRoaXMubnVtYmVyaW5nU3lzdGVtID0gbnVtYmVyaW5nIHx8IHBhcnNlZE51bWJlcmluZ1N5c3RlbSB8fCBudWxsOwogICAgICB0aGlzLm91dHB1dENhbGVuZGFyID0gb3V0cHV0Q2FsZW5kYXIgfHwgcGFyc2VkT3V0cHV0Q2FsZW5kYXIgfHwgbnVsbDsKICAgICAgdGhpcy5pbnRsID0gaW50bENvbmZpZ1N0cmluZyh0aGlzLmxvY2FsZSwgdGhpcy5udW1iZXJpbmdTeXN0ZW0sIHRoaXMub3V0cHV0Q2FsZW5kYXIpOwoKICAgICAgdGhpcy53ZWVrZGF5c0NhY2hlID0geyBmb3JtYXQ6IHt9LCBzdGFuZGFsb25lOiB7fSB9OwogICAgICB0aGlzLm1vbnRoc0NhY2hlID0geyBmb3JtYXQ6IHt9LCBzdGFuZGFsb25lOiB7fSB9OwogICAgICB0aGlzLm1lcmlkaWVtQ2FjaGUgPSBudWxsOwogICAgICB0aGlzLmVyYUNhY2hlID0ge307CgogICAgICB0aGlzLnNwZWNpZmllZExvY2FsZSA9IHNwZWNpZmllZExvY2FsZTsKICAgICAgdGhpcy5mYXN0TnVtYmVyc0NhY2hlZCA9IG51bGw7CiAgICB9CgogICAgZ2V0IGZhc3ROdW1iZXJzKCkgewogICAgICBpZiAodGhpcy5mYXN0TnVtYmVyc0NhY2hlZCA9PSBudWxsKSB7CiAgICAgICAgdGhpcy5mYXN0TnVtYmVyc0NhY2hlZCA9IHN1cHBvcnRzRmFzdE51bWJlcnModGhpcyk7CiAgICAgIH0KCiAgICAgIHJldHVybiB0aGlzLmZhc3ROdW1iZXJzQ2FjaGVkOwogICAgfQoKICAgIGxpc3RpbmdNb2RlKCkgewogICAgICBjb25zdCBpc0FjdHVhbGx5RW4gPSB0aGlzLmlzRW5nbGlzaCgpOwogICAgICBjb25zdCBoYXNOb1dlaXJkbmVzcyA9CiAgICAgICAgKHRoaXMubnVtYmVyaW5nU3lzdGVtID09PSBudWxsIHx8IHRoaXMubnVtYmVyaW5nU3lzdGVtID09PSAibGF0biIpICYmCiAgICAgICAgKHRoaXMub3V0cHV0Q2FsZW5kYXIgPT09IG51bGwgfHwgdGhpcy5vdXRwdXRDYWxlbmRhciA9PT0gImdyZWdvcnkiKTsKICAgICAgcmV0dXJuIGlzQWN0dWFsbHlFbiAmJiBoYXNOb1dlaXJkbmVzcyA/ICJlbiIgOiAiaW50bCI7CiAgICB9CgogICAgY2xvbmUoYWx0cykgewogICAgICBpZiAoIWFsdHMgfHwgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoYWx0cykubGVuZ3RoID09PSAwKSB7CiAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIExvY2FsZS5jcmVhdGUoCiAgICAgICAgICBhbHRzLmxvY2FsZSB8fCB0aGlzLnNwZWNpZmllZExvY2FsZSwKICAgICAgICAgIGFsdHMubnVtYmVyaW5nU3lzdGVtIHx8IHRoaXMubnVtYmVyaW5nU3lzdGVtLAogICAgICAgICAgYWx0cy5vdXRwdXRDYWxlbmRhciB8fCB0aGlzLm91dHB1dENhbGVuZGFyLAogICAgICAgICAgYWx0cy5kZWZhdWx0VG9FTiB8fCBmYWxzZQogICAgICAgICk7CiAgICAgIH0KICAgIH0KCiAgICByZWRlZmF1bHRUb0VOKGFsdHMgPSB7fSkgewogICAgICByZXR1cm4gdGhpcy5jbG9uZSh7IC4uLmFsdHMsIGRlZmF1bHRUb0VOOiB0cnVlIH0pOwogICAgfQoKICAgIHJlZGVmYXVsdFRvU3lzdGVtKGFsdHMgPSB7fSkgewogICAgICByZXR1cm4gdGhpcy5jbG9uZSh7IC4uLmFsdHMsIGRlZmF1bHRUb0VOOiBmYWxzZSB9KTsKICAgIH0KCiAgICBtb250aHMobGVuZ3RoLCBmb3JtYXQgPSBmYWxzZSkgewogICAgICByZXR1cm4gbGlzdFN0dWZmKHRoaXMsIGxlbmd0aCwgbW9udGhzLCAoKSA9PiB7CiAgICAgICAgY29uc3QgaW50bCA9IGZvcm1hdCA/IHsgbW9udGg6IGxlbmd0aCwgZGF5OiAibnVtZXJpYyIgfSA6IHsgbW9udGg6IGxlbmd0aCB9LAogICAgICAgICAgZm9ybWF0U3RyID0gZm9ybWF0ID8gImZvcm1hdCIgOiAic3RhbmRhbG9uZSI7CiAgICAgICAgaWYgKCF0aGlzLm1vbnRoc0NhY2hlW2Zvcm1hdFN0cl1bbGVuZ3RoXSkgewogICAgICAgICAgdGhpcy5tb250aHNDYWNoZVtmb3JtYXRTdHJdW2xlbmd0aF0gPSBtYXBNb250aHMoKGR0KSA9PiB0aGlzLmV4dHJhY3QoZHQsIGludGwsICJtb250aCIpKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRoaXMubW9udGhzQ2FjaGVbZm9ybWF0U3RyXVtsZW5ndGhdOwogICAgICB9KTsKICAgIH0KCiAgICB3ZWVrZGF5cyhsZW5ndGgsIGZvcm1hdCA9IGZhbHNlKSB7CiAgICAgIHJldHVybiBsaXN0U3R1ZmYodGhpcywgbGVuZ3RoLCB3ZWVrZGF5cywgKCkgPT4gewogICAgICAgIGNvbnN0IGludGwgPSBmb3JtYXQKICAgICAgICAgICAgPyB7IHdlZWtkYXk6IGxlbmd0aCwgeWVhcjogIm51bWVyaWMiLCBtb250aDogImxvbmciLCBkYXk6ICJudW1lcmljIiB9CiAgICAgICAgICAgIDogeyB3ZWVrZGF5OiBsZW5ndGggfSwKICAgICAgICAgIGZvcm1hdFN0ciA9IGZvcm1hdCA/ICJmb3JtYXQiIDogInN0YW5kYWxvbmUiOwogICAgICAgIGlmICghdGhpcy53ZWVrZGF5c0NhY2hlW2Zvcm1hdFN0cl1bbGVuZ3RoXSkgewogICAgICAgICAgdGhpcy53ZWVrZGF5c0NhY2hlW2Zvcm1hdFN0cl1bbGVuZ3RoXSA9IG1hcFdlZWtkYXlzKChkdCkgPT4KICAgICAgICAgICAgdGhpcy5leHRyYWN0KGR0LCBpbnRsLCAid2Vla2RheSIpCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdGhpcy53ZWVrZGF5c0NhY2hlW2Zvcm1hdFN0cl1bbGVuZ3RoXTsKICAgICAgfSk7CiAgICB9CgogICAgbWVyaWRpZW1zKCkgewogICAgICByZXR1cm4gbGlzdFN0dWZmKAogICAgICAgIHRoaXMsCiAgICAgICAgdW5kZWZpbmVkLAogICAgICAgICgpID0+IG1lcmlkaWVtcywKICAgICAgICAoKSA9PiB7CiAgICAgICAgICAvLyBJbiB0aGVvcnkgdGhlcmUgY291bGQgYmUgYXJpYml0cmFyeSBkYXkgcGVyaW9kcy4gV2UncmUgZ29ubmEgYXNzdW1lIHRoZXJlIGFyZSBleGFjdGx5IHR3bwogICAgICAgICAgLy8gZm9yIEFNIGFuZCBQTS4gVGhpcyBpcyBwcm9iYWJseSB3cm9uZywgYnV0IGl0J3MgbWFrZXMgcGFyc2luZyB3YXkgZWFzaWVyLgogICAgICAgICAgaWYgKCF0aGlzLm1lcmlkaWVtQ2FjaGUpIHsKICAgICAgICAgICAgY29uc3QgaW50bCA9IHsgaG91cjogIm51bWVyaWMiLCBob3VyQ3ljbGU6ICJoMTIiIH07CiAgICAgICAgICAgIHRoaXMubWVyaWRpZW1DYWNoZSA9IFtEYXRlVGltZS51dGMoMjAxNiwgMTEsIDEzLCA5KSwgRGF0ZVRpbWUudXRjKDIwMTYsIDExLCAxMywgMTkpXS5tYXAoCiAgICAgICAgICAgICAgKGR0KSA9PiB0aGlzLmV4dHJhY3QoZHQsIGludGwsICJkYXlwZXJpb2QiKQogICAgICAgICAgICApOwogICAgICAgICAgfQoKICAgICAgICAgIHJldHVybiB0aGlzLm1lcmlkaWVtQ2FjaGU7CiAgICAgICAgfQogICAgICApOwogICAgfQoKICAgIGVyYXMobGVuZ3RoKSB7CiAgICAgIHJldHVybiBsaXN0U3R1ZmYodGhpcywgbGVuZ3RoLCBlcmFzLCAoKSA9PiB7CiAgICAgICAgY29uc3QgaW50bCA9IHsgZXJhOiBsZW5ndGggfTsKCiAgICAgICAgLy8gVGhpcyBpcyBwcm9ibGVtYXRpYy4gRGlmZmVyZW50IGNhbGVuZGFycyBhcmUgZ29pbmcgdG8gZGVmaW5lIGVyYXMgdG90YWxseSBkaWZmZXJlbnRseS4gV2hhdCBJIG5lZWQgaXMgdGhlIG1pbmltdW0gc2V0IG9mIGRhdGVzCiAgICAgICAgLy8gdG8gZGVmaW5pdGVseSBlbnVtZXJhdGUgdGhlbS4KICAgICAgICBpZiAoIXRoaXMuZXJhQ2FjaGVbbGVuZ3RoXSkgewogICAgICAgICAgdGhpcy5lcmFDYWNoZVtsZW5ndGhdID0gW0RhdGVUaW1lLnV0YygtNDAsIDEsIDEpLCBEYXRlVGltZS51dGMoMjAxNywgMSwgMSldLm1hcCgoZHQpID0+CiAgICAgICAgICAgIHRoaXMuZXh0cmFjdChkdCwgaW50bCwgImVyYSIpCiAgICAgICAgICApOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIHRoaXMuZXJhQ2FjaGVbbGVuZ3RoXTsKICAgICAgfSk7CiAgICB9CgogICAgZXh0cmFjdChkdCwgaW50bE9wdHMsIGZpZWxkKSB7CiAgICAgIGNvbnN0IGRmID0gdGhpcy5kdEZvcm1hdHRlcihkdCwgaW50bE9wdHMpLAogICAgICAgIHJlc3VsdHMgPSBkZi5mb3JtYXRUb1BhcnRzKCksCiAgICAgICAgbWF0Y2hpbmcgPSByZXN1bHRzLmZpbmQoKG0pID0+IG0udHlwZS50b0xvd2VyQ2FzZSgpID09PSBmaWVsZCk7CiAgICAgIHJldHVybiBtYXRjaGluZyA/IG1hdGNoaW5nLnZhbHVlIDogbnVsbDsKICAgIH0KCiAgICBudW1iZXJGb3JtYXR0ZXIob3B0cyA9IHt9KSB7CiAgICAgIC8vIHRoaXMgZm9yY2VzaW1wbGUgb3B0aW9uIGlzIG5ldmVyIHVzZWQgKHRoZSBvbmx5IGNhbGxlciBzaG9ydC1jaXJjdWl0cyBvbiBpdCwgYnV0IGl0IHNlZW1zIHNhZmVyIHRvIGxlYXZlKQogICAgICAvLyAoaW4gY29udHJhc3QsIHRoZSByZXN0IG9mIHRoZSBjb25kaXRpb24gaXMgdXNlZCBoZWF2aWx5KQogICAgICByZXR1cm4gbmV3IFBvbHlOdW1iZXJGb3JtYXR0ZXIodGhpcy5pbnRsLCBvcHRzLmZvcmNlU2ltcGxlIHx8IHRoaXMuZmFzdE51bWJlcnMsIG9wdHMpOwogICAgfQoKICAgIGR0Rm9ybWF0dGVyKGR0LCBpbnRsT3B0cyA9IHt9KSB7CiAgICAgIHJldHVybiBuZXcgUG9seURhdGVGb3JtYXR0ZXIoZHQsIHRoaXMuaW50bCwgaW50bE9wdHMpOwogICAgfQoKICAgIHJlbEZvcm1hdHRlcihvcHRzID0ge30pIHsKICAgICAgcmV0dXJuIG5ldyBQb2x5UmVsRm9ybWF0dGVyKHRoaXMuaW50bCwgdGhpcy5pc0VuZ2xpc2goKSwgb3B0cyk7CiAgICB9CgogICAgbGlzdEZvcm1hdHRlcihvcHRzID0ge30pIHsKICAgICAgcmV0dXJuIGdldENhY2hlZExGKHRoaXMuaW50bCwgb3B0cyk7CiAgICB9CgogICAgaXNFbmdsaXNoKCkgewogICAgICByZXR1cm4gKAogICAgICAgIHRoaXMubG9jYWxlID09PSAiZW4iIHx8CiAgICAgICAgdGhpcy5sb2NhbGUudG9Mb3dlckNhc2UoKSA9PT0gImVuLXVzIiB8fAogICAgICAgIG5ldyBJbnRsLkRhdGVUaW1lRm9ybWF0KHRoaXMuaW50bCkucmVzb2x2ZWRPcHRpb25zKCkubG9jYWxlLnN0YXJ0c1dpdGgoImVuLXVzIikKICAgICAgKTsKICAgIH0KCiAgICBlcXVhbHMob3RoZXIpIHsKICAgICAgcmV0dXJuICgKICAgICAgICB0aGlzLmxvY2FsZSA9PT0gb3RoZXIubG9jYWxlICYmCiAgICAgICAgdGhpcy5udW1iZXJpbmdTeXN0ZW0gPT09IG90aGVyLm51bWJlcmluZ1N5c3RlbSAmJgogICAgICAgIHRoaXMub3V0cHV0Q2FsZW5kYXIgPT09IG90aGVyLm91dHB1dENhbGVuZGFyCiAgICAgICk7CiAgICB9CiAgfQoKICBsZXQgc2luZ2xldG9uID0gbnVsbDsKCiAgLyoqCiAgICogQSB6b25lIHdpdGggYSBmaXhlZCBvZmZzZXQgKG1lYW5pbmcgbm8gRFNUKQogICAqIEBpbXBsZW1lbnRzIHtab25lfQogICAqLwogIGNsYXNzIEZpeGVkT2Zmc2V0Wm9uZSBleHRlbmRzIFpvbmUgewogICAgLyoqCiAgICAgKiBHZXQgYSBzaW5nbGV0b24gaW5zdGFuY2Ugb2YgVVRDCiAgICAgKiBAcmV0dXJuIHtGaXhlZE9mZnNldFpvbmV9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgdXRjSW5zdGFuY2UoKSB7CiAgICAgIGlmIChzaW5nbGV0b24gPT09IG51bGwpIHsKICAgICAgICBzaW5nbGV0b24gPSBuZXcgRml4ZWRPZmZzZXRab25lKDApOwogICAgICB9CiAgICAgIHJldHVybiBzaW5nbGV0b247CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgYW4gaW5zdGFuY2Ugd2l0aCBhIHNwZWNpZmllZCBvZmZzZXQKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvZmZzZXQgLSBUaGUgb2Zmc2V0IGluIG1pbnV0ZXMKICAgICAqIEByZXR1cm4ge0ZpeGVkT2Zmc2V0Wm9uZX0KICAgICAqLwogICAgc3RhdGljIGluc3RhbmNlKG9mZnNldCkgewogICAgICByZXR1cm4gb2Zmc2V0ID09PSAwID8gRml4ZWRPZmZzZXRab25lLnV0Y0luc3RhbmNlIDogbmV3IEZpeGVkT2Zmc2V0Wm9uZShvZmZzZXQpOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IGFuIGluc3RhbmNlIG9mIEZpeGVkT2Zmc2V0Wm9uZSBmcm9tIGEgVVRDIG9mZnNldCBzdHJpbmcsIGxpa2UgIlVUQys2IgogICAgICogQHBhcmFtIHtzdHJpbmd9IHMgLSBUaGUgb2Zmc2V0IHN0cmluZyB0byBwYXJzZQogICAgICogQGV4YW1wbGUgRml4ZWRPZmZzZXRab25lLnBhcnNlU3BlY2lmaWVyKCJVVEMrNiIpCiAgICAgKiBAZXhhbXBsZSBGaXhlZE9mZnNldFpvbmUucGFyc2VTcGVjaWZpZXIoIlVUQyswNiIpCiAgICAgKiBAZXhhbXBsZSBGaXhlZE9mZnNldFpvbmUucGFyc2VTcGVjaWZpZXIoIlVUQy02OjAwIikKICAgICAqIEByZXR1cm4ge0ZpeGVkT2Zmc2V0Wm9uZX0KICAgICAqLwogICAgc3RhdGljIHBhcnNlU3BlY2lmaWVyKHMpIHsKICAgICAgaWYgKHMpIHsKICAgICAgICBjb25zdCByID0gcy5tYXRjaCgvXnV0Yyg/OihbKy1dXGR7MSwyfSkoPzo6KFxkezJ9KSk/KT8kL2kpOwogICAgICAgIGlmIChyKSB7CiAgICAgICAgICByZXR1cm4gbmV3IEZpeGVkT2Zmc2V0Wm9uZShzaWduZWRPZmZzZXQoclsxXSwgclsyXSkpOwogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gbnVsbDsKICAgIH0KCiAgICBjb25zdHJ1Y3RvcihvZmZzZXQpIHsKICAgICAgc3VwZXIoKTsKICAgICAgLyoqIEBwcml2YXRlICoqLwogICAgICB0aGlzLmZpeGVkID0gb2Zmc2V0OwogICAgfQoKICAgIC8qKiBAb3ZlcnJpZGUgKiovCiAgICBnZXQgdHlwZSgpIHsKICAgICAgcmV0dXJuICJmaXhlZCI7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGdldCBuYW1lKCkgewogICAgICByZXR1cm4gdGhpcy5maXhlZCA9PT0gMCA/ICJVVEMiIDogYFVUQyR7Zm9ybWF0T2Zmc2V0KHRoaXMuZml4ZWQsICJuYXJyb3ciKX1gOwogICAgfQoKICAgIGdldCBpYW5hTmFtZSgpIHsKICAgICAgaWYgKHRoaXMuZml4ZWQgPT09IDApIHsKICAgICAgICByZXR1cm4gIkV0Yy9VVEMiOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBgRXRjL0dNVCR7Zm9ybWF0T2Zmc2V0KC10aGlzLmZpeGVkLCAibmFycm93Iil9YDsKICAgICAgfQogICAgfQoKICAgIC8qKiBAb3ZlcnJpZGUgKiovCiAgICBvZmZzZXROYW1lKCkgewogICAgICByZXR1cm4gdGhpcy5uYW1lOwogICAgfQoKICAgIC8qKiBAb3ZlcnJpZGUgKiovCiAgICBmb3JtYXRPZmZzZXQodHMsIGZvcm1hdCkgewogICAgICByZXR1cm4gZm9ybWF0T2Zmc2V0KHRoaXMuZml4ZWQsIGZvcm1hdCk7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGdldCBpc1VuaXZlcnNhbCgpIHsKICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIG9mZnNldCgpIHsKICAgICAgcmV0dXJuIHRoaXMuZml4ZWQ7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGVxdWFscyhvdGhlclpvbmUpIHsKICAgICAgcmV0dXJuIG90aGVyWm9uZS50eXBlID09PSAiZml4ZWQiICYmIG90aGVyWm9uZS5maXhlZCA9PT0gdGhpcy5maXhlZDsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgZ2V0IGlzVmFsaWQoKSB7CiAgICAgIHJldHVybiB0cnVlOwogICAgfQogIH0KCiAgLyoqCiAgICogQSB6b25lIHRoYXQgZmFpbGVkIHRvIHBhcnNlLiBZb3Ugc2hvdWxkIG5ldmVyIG5lZWQgdG8gaW5zdGFudGlhdGUgdGhpcy4KICAgKiBAaW1wbGVtZW50cyB7Wm9uZX0KICAgKi8KICBjbGFzcyBJbnZhbGlkWm9uZSBleHRlbmRzIFpvbmUgewogICAgY29uc3RydWN0b3Ioem9uZU5hbWUpIHsKICAgICAgc3VwZXIoKTsKICAgICAgLyoqICBAcHJpdmF0ZSAqLwogICAgICB0aGlzLnpvbmVOYW1lID0gem9uZU5hbWU7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGdldCB0eXBlKCkgewogICAgICByZXR1cm4gImludmFsaWQiOwogICAgfQoKICAgIC8qKiBAb3ZlcnJpZGUgKiovCiAgICBnZXQgbmFtZSgpIHsKICAgICAgcmV0dXJuIHRoaXMuem9uZU5hbWU7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGdldCBpc1VuaXZlcnNhbCgpIHsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQoKICAgIC8qKiBAb3ZlcnJpZGUgKiovCiAgICBvZmZzZXROYW1lKCkgewogICAgICByZXR1cm4gbnVsbDsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgZm9ybWF0T2Zmc2V0KCkgewogICAgICByZXR1cm4gIiI7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIG9mZnNldCgpIHsKICAgICAgcmV0dXJuIE5hTjsKICAgIH0KCiAgICAvKiogQG92ZXJyaWRlICoqLwogICAgZXF1YWxzKCkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgLyoqIEBvdmVycmlkZSAqKi8KICAgIGdldCBpc1ZhbGlkKCkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgfQoKICAvKioKICAgKiBAcHJpdmF0ZQogICAqLwoKICBmdW5jdGlvbiBub3JtYWxpemVab25lKGlucHV0LCBkZWZhdWx0Wm9uZSkgewogICAgaWYgKGlzVW5kZWZpbmVkKGlucHV0KSB8fCBpbnB1dCA9PT0gbnVsbCkgewogICAgICByZXR1cm4gZGVmYXVsdFpvbmU7CiAgICB9IGVsc2UgaWYgKGlucHV0IGluc3RhbmNlb2YgWm9uZSkgewogICAgICByZXR1cm4gaW5wdXQ7CiAgICB9IGVsc2UgaWYgKGlzU3RyaW5nKGlucHV0KSkgewogICAgICBjb25zdCBsb3dlcmVkID0gaW5wdXQudG9Mb3dlckNhc2UoKTsKICAgICAgaWYgKGxvd2VyZWQgPT09ICJkZWZhdWx0IikgcmV0dXJuIGRlZmF1bHRab25lOwogICAgICBlbHNlIGlmIChsb3dlcmVkID09PSAibG9jYWwiIHx8IGxvd2VyZWQgPT09ICJzeXN0ZW0iKSByZXR1cm4gU3lzdGVtWm9uZS5pbnN0YW5jZTsKICAgICAgZWxzZSBpZiAobG93ZXJlZCA9PT0gInV0YyIgfHwgbG93ZXJlZCA9PT0gImdtdCIpIHJldHVybiBGaXhlZE9mZnNldFpvbmUudXRjSW5zdGFuY2U7CiAgICAgIGVsc2UgcmV0dXJuIEZpeGVkT2Zmc2V0Wm9uZS5wYXJzZVNwZWNpZmllcihsb3dlcmVkKSB8fCBJQU5BWm9uZS5jcmVhdGUoaW5wdXQpOwogICAgfSBlbHNlIGlmIChpc051bWJlcihpbnB1dCkpIHsKICAgICAgcmV0dXJuIEZpeGVkT2Zmc2V0Wm9uZS5pbnN0YW5jZShpbnB1dCk7CiAgICB9IGVsc2UgaWYgKHR5cGVvZiBpbnB1dCA9PT0gIm9iamVjdCIgJiYgIm9mZnNldCIgaW4gaW5wdXQgJiYgdHlwZW9mIGlucHV0Lm9mZnNldCA9PT0gImZ1bmN0aW9uIikgewogICAgICAvLyBUaGlzIGlzIGR1bWIsIGJ1dCB0aGUgaW5zdGFuY2VvZiBjaGVjayBhYm92ZSBkb2Vzbid0IHNlZW0gdG8gcmVhbGx5IHdvcmsKICAgICAgLy8gc28gd2UncmUgZHVjayBjaGVja2luZyBpdAogICAgICByZXR1cm4gaW5wdXQ7CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gbmV3IEludmFsaWRab25lKGlucHV0KTsKICAgIH0KICB9CgogIGxldCBub3cgPSAoKSA9PiBEYXRlLm5vdygpLAogICAgZGVmYXVsdFpvbmUgPSAic3lzdGVtIiwKICAgIGRlZmF1bHRMb2NhbGUgPSBudWxsLAogICAgZGVmYXVsdE51bWJlcmluZ1N5c3RlbSA9IG51bGwsCiAgICBkZWZhdWx0T3V0cHV0Q2FsZW5kYXIgPSBudWxsLAogICAgdHdvRGlnaXRDdXRvZmZZZWFyID0gNjAsCiAgICB0aHJvd09uSW52YWxpZDsKCiAgLyoqCiAgICogU2V0dGluZ3MgY29udGFpbnMgc3RhdGljIGdldHRlcnMgYW5kIHNldHRlcnMgdGhhdCBjb250cm9sIEx1eG9uJ3Mgb3ZlcmFsbCBiZWhhdmlvci4gTHV4b24gaXMgYSBzaW1wbGUgbGlicmFyeSB3aXRoIGZldyBvcHRpb25zLCBidXQgdGhlIG9uZXMgaXQgZG9lcyBoYXZlIGxpdmUgaGVyZS4KICAgKi8KICBjbGFzcyBTZXR0aW5ncyB7CiAgICAvKioKICAgICAqIEdldCB0aGUgY2FsbGJhY2sgZm9yIHJldHVybmluZyB0aGUgY3VycmVudCB0aW1lc3RhbXAuCiAgICAgKiBAdHlwZSB7ZnVuY3Rpb259CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgbm93KCkgewogICAgICByZXR1cm4gbm93OwogICAgfQoKICAgIC8qKgogICAgICogU2V0IHRoZSBjYWxsYmFjayBmb3IgcmV0dXJuaW5nIHRoZSBjdXJyZW50IHRpbWVzdGFtcC4KICAgICAqIFRoZSBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgbnVtYmVyLCB3aGljaCB3aWxsIGJlIGludGVycHJldGVkIGFzIGFuIEVwb2NoIG1pbGxpc2Vjb25kIGNvdW50CiAgICAgKiBAdHlwZSB7ZnVuY3Rpb259CiAgICAgKiBAZXhhbXBsZSBTZXR0aW5ncy5ub3cgPSAoKSA9PiBEYXRlLm5vdygpICsgMzAwMCAvLyBwcmV0ZW5kIGl0IGlzIDMgc2Vjb25kcyBpbiB0aGUgZnV0dXJlCiAgICAgKiBAZXhhbXBsZSBTZXR0aW5ncy5ub3cgPSAoKSA9PiAwIC8vIGFsd2F5cyBwcmV0ZW5kIGl0J3MgSmFuIDEsIDE5NzAgYXQgbWlkbmlnaHQgaW4gVVRDIHRpbWUKICAgICAqLwogICAgc3RhdGljIHNldCBub3cobikgewogICAgICBub3cgPSBuOwogICAgfQoKICAgIC8qKgogICAgICogU2V0IHRoZSBkZWZhdWx0IHRpbWUgem9uZSB0byBjcmVhdGUgRGF0ZVRpbWVzIGluLiBEb2VzIG5vdCBhZmZlY3QgZXhpc3RpbmcgaW5zdGFuY2VzLgogICAgICogVXNlIHRoZSB2YWx1ZSAic3lzdGVtIiB0byByZXNldCB0aGlzIHZhbHVlIHRvIHRoZSBzeXN0ZW0ncyB0aW1lIHpvbmUuCiAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICovCiAgICBzdGF0aWMgc2V0IGRlZmF1bHRab25lKHpvbmUpIHsKICAgICAgZGVmYXVsdFpvbmUgPSB6b25lOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBkZWZhdWx0IHRpbWUgem9uZSBvYmplY3QgY3VycmVudGx5IHVzZWQgdG8gY3JlYXRlIERhdGVUaW1lcy4gRG9lcyBub3QgYWZmZWN0IGV4aXN0aW5nIGluc3RhbmNlcy4KICAgICAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBzeXN0ZW0ncyB0aW1lIHpvbmUgKHRoZSBvbmUgc2V0IG9uIHRoZSBtYWNoaW5lIHRoYXQgcnVucyB0aGlzIGNvZGUpLgogICAgICogQHR5cGUge1pvbmV9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgZGVmYXVsdFpvbmUoKSB7CiAgICAgIHJldHVybiBub3JtYWxpemVab25lKGRlZmF1bHRab25lLCBTeXN0ZW1ab25lLmluc3RhbmNlKTsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgZGVmYXVsdCBsb2NhbGUgdG8gY3JlYXRlIERhdGVUaW1lcyB3aXRoLiBEb2VzIG5vdCBhZmZlY3QgZXhpc3RpbmcgaW5zdGFuY2VzLgogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgc3RhdGljIGdldCBkZWZhdWx0TG9jYWxlKCkgewogICAgICByZXR1cm4gZGVmYXVsdExvY2FsZTsKICAgIH0KCiAgICAvKioKICAgICAqIFNldCB0aGUgZGVmYXVsdCBsb2NhbGUgdG8gY3JlYXRlIERhdGVUaW1lcyB3aXRoLiBEb2VzIG5vdCBhZmZlY3QgZXhpc3RpbmcgaW5zdGFuY2VzLgogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgc3RhdGljIHNldCBkZWZhdWx0TG9jYWxlKGxvY2FsZSkgewogICAgICBkZWZhdWx0TG9jYWxlID0gbG9jYWxlOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBkZWZhdWx0IG51bWJlcmluZyBzeXN0ZW0gdG8gY3JlYXRlIERhdGVUaW1lcyB3aXRoLiBEb2VzIG5vdCBhZmZlY3QgZXhpc3RpbmcgaW5zdGFuY2VzLgogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgc3RhdGljIGdldCBkZWZhdWx0TnVtYmVyaW5nU3lzdGVtKCkgewogICAgICByZXR1cm4gZGVmYXVsdE51bWJlcmluZ1N5c3RlbTsKICAgIH0KCiAgICAvKioKICAgICAqIFNldCB0aGUgZGVmYXVsdCBudW1iZXJpbmcgc3lzdGVtIHRvIGNyZWF0ZSBEYXRlVGltZXMgd2l0aC4gRG9lcyBub3QgYWZmZWN0IGV4aXN0aW5nIGluc3RhbmNlcy4KICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIHN0YXRpYyBzZXQgZGVmYXVsdE51bWJlcmluZ1N5c3RlbShudW1iZXJpbmdTeXN0ZW0pIHsKICAgICAgZGVmYXVsdE51bWJlcmluZ1N5c3RlbSA9IG51bWJlcmluZ1N5c3RlbTsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgZGVmYXVsdCBvdXRwdXQgY2FsZW5kYXIgdG8gY3JlYXRlIERhdGVUaW1lcyB3aXRoLiBEb2VzIG5vdCBhZmZlY3QgZXhpc3RpbmcgaW5zdGFuY2VzLgogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgc3RhdGljIGdldCBkZWZhdWx0T3V0cHV0Q2FsZW5kYXIoKSB7CiAgICAgIHJldHVybiBkZWZhdWx0T3V0cHV0Q2FsZW5kYXI7CiAgICB9CgogICAgLyoqCiAgICAgKiBTZXQgdGhlIGRlZmF1bHQgb3V0cHV0IGNhbGVuZGFyIHRvIGNyZWF0ZSBEYXRlVGltZXMgd2l0aC4gRG9lcyBub3QgYWZmZWN0IGV4aXN0aW5nIGluc3RhbmNlcy4KICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIHN0YXRpYyBzZXQgZGVmYXVsdE91dHB1dENhbGVuZGFyKG91dHB1dENhbGVuZGFyKSB7CiAgICAgIGRlZmF1bHRPdXRwdXRDYWxlbmRhciA9IG91dHB1dENhbGVuZGFyOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBjdXRvZmYgeWVhciBhZnRlciB3aGljaCBhIHN0cmluZyBlbmNvZGluZyBhIHllYXIgYXMgdHdvIGRpZ2l0cyBpcyBpbnRlcnByZXRlZCB0byBvY2N1ciBpbiB0aGUgY3VycmVudCBjZW50dXJ5LgogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgc3RhdGljIGdldCB0d29EaWdpdEN1dG9mZlllYXIoKSB7CiAgICAgIHJldHVybiB0d29EaWdpdEN1dG9mZlllYXI7CiAgICB9CgogICAgLyoqCiAgICAgKiBTZXQgdGhlIGN1dG9mZiB5ZWFyIGFmdGVyIHdoaWNoIGEgc3RyaW5nIGVuY29kaW5nIGEgeWVhciBhcyB0d28gZGlnaXRzIGlzIGludGVycHJldGVkIHRvIG9jY3VyIGluIHRoZSBjdXJyZW50IGNlbnR1cnkuCiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICogQGV4YW1wbGUgU2V0dGluZ3MudHdvRGlnaXRDdXRvZmZZZWFyID0gMCAvLyBjdXQtb2ZmIHllYXIgaXMgMCwgc28gYWxsICd5eScgYXJlIGludGVycHJldGVkIGFzIGN1cnJlbnQgY2VudHVyeQogICAgICogQGV4YW1wbGUgU2V0dGluZ3MudHdvRGlnaXRDdXRvZmZZZWFyID0gNTAgLy8gJzQ5JyAtPiAxOTQ5OyAnNTAnIC0+IDIwNTAKICAgICAqIEBleGFtcGxlIFNldHRpbmdzLnR3b0RpZ2l0Q3V0b2ZmWWVhciA9IDE5NTAgLy8gaW50ZXJwcmV0ZWQgYXMgNTAKICAgICAqIEBleGFtcGxlIFNldHRpbmdzLnR3b0RpZ2l0Q3V0b2ZmWWVhciA9IDIwNTAgLy8gQUxTTyBpbnRlcnByZXRlZCBhcyA1MAogICAgICovCiAgICBzdGF0aWMgc2V0IHR3b0RpZ2l0Q3V0b2ZmWWVhcihjdXRvZmZZZWFyKSB7CiAgICAgIHR3b0RpZ2l0Q3V0b2ZmWWVhciA9IGN1dG9mZlllYXIgJSAxMDA7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgd2hldGhlciBMdXhvbiB3aWxsIHRocm93IHdoZW4gaXQgZW5jb3VudGVycyBpbnZhbGlkIERhdGVUaW1lcywgRHVyYXRpb25zLCBvciBJbnRlcnZhbHMKICAgICAqIEB0eXBlIHtib29sZWFufQogICAgICovCiAgICBzdGF0aWMgZ2V0IHRocm93T25JbnZhbGlkKCkgewogICAgICByZXR1cm4gdGhyb3dPbkludmFsaWQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBTZXQgd2hldGhlciBMdXhvbiB3aWxsIHRocm93IHdoZW4gaXQgZW5jb3VudGVycyBpbnZhbGlkIERhdGVUaW1lcywgRHVyYXRpb25zLCBvciBJbnRlcnZhbHMKICAgICAqIEB0eXBlIHtib29sZWFufQogICAgICovCiAgICBzdGF0aWMgc2V0IHRocm93T25JbnZhbGlkKHQpIHsKICAgICAgdGhyb3dPbkludmFsaWQgPSB0OwogICAgfQoKICAgIC8qKgogICAgICogUmVzZXQgTHV4b24ncyBnbG9iYWwgY2FjaGVzLiBTaG91bGQgb25seSBiZSBuZWNlc3NhcnkgaW4gdGVzdGluZyBzY2VuYXJpb3MuCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBzdGF0aWMgcmVzZXRDYWNoZXMoKSB7CiAgICAgIExvY2FsZS5yZXNldENhY2hlKCk7CiAgICAgIElBTkFab25lLnJlc2V0Q2FjaGUoKTsKICAgIH0KICB9CgogIC8qCiAgICBUaGlzIGlzIGp1c3QgYSBqdW5rIGRyYXdlciwgY29udGFpbmluZyBhbnl0aGluZyB1c2VkIGFjcm9zcyBtdWx0aXBsZSBjbGFzc2VzLgogICAgQmVjYXVzZSBMdXhvbiBpcyBzbWFsbChpc2gpLCB0aGlzIHNob3VsZCBzdGF5IHNtYWxsIGFuZCB3ZSB3b24ndCB3b3JyeSBhYm91dCBzcGxpdHRpbmcKICAgIGl0IHVwIGludG8sIHNheSwgcGFyc2luZ1V0aWwuanMgYW5kIGJhc2ljVXRpbC5qcyBhbmQgc28gb24uIEJ1dCB0aGV5IGFyZSBkaXZpZGVkIHVwIGJ5IGZlYXR1cmUgYXJlYS4KICAqLwoKICAvKioKICAgKiBAcHJpdmF0ZQogICAqLwoKICAvLyBUWVBFUwoKICBmdW5jdGlvbiBpc1VuZGVmaW5lZChvKSB7CiAgICByZXR1cm4gdHlwZW9mIG8gPT09ICJ1bmRlZmluZWQiOwogIH0KCiAgZnVuY3Rpb24gaXNOdW1iZXIobykgewogICAgcmV0dXJuIHR5cGVvZiBvID09PSAibnVtYmVyIjsKICB9CgogIGZ1bmN0aW9uIGlzSW50ZWdlcihvKSB7CiAgICByZXR1cm4gdHlwZW9mIG8gPT09ICJudW1iZXIiICYmIG8gJSAxID09PSAwOwogIH0KCiAgZnVuY3Rpb24gaXNTdHJpbmcobykgewogICAgcmV0dXJuIHR5cGVvZiBvID09PSAic3RyaW5nIjsKICB9CgogIGZ1bmN0aW9uIGlzRGF0ZShvKSB7CiAgICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG8pID09PSAiW29iamVjdCBEYXRlXSI7CiAgfQoKICAvLyBDQVBBQklMSVRJRVMKCiAgZnVuY3Rpb24gaGFzUmVsYXRpdmUoKSB7CiAgICB0cnkgewogICAgICByZXR1cm4gdHlwZW9mIEludGwgIT09ICJ1bmRlZmluZWQiICYmICEhSW50bC5SZWxhdGl2ZVRpbWVGb3JtYXQ7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICB9CgogIC8vIE9CSkVDVFMgQU5EIEFSUkFZUwoKICBmdW5jdGlvbiBtYXliZUFycmF5KHRoaW5nKSB7CiAgICByZXR1cm4gQXJyYXkuaXNBcnJheSh0aGluZykgPyB0aGluZyA6IFt0aGluZ107CiAgfQoKICBmdW5jdGlvbiBiZXN0QnkoYXJyLCBieSwgY29tcGFyZSkgewogICAgaWYgKGFyci5sZW5ndGggPT09IDApIHsKICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgIH0KICAgIHJldHVybiBhcnIucmVkdWNlKChiZXN0LCBuZXh0KSA9PiB7CiAgICAgIGNvbnN0IHBhaXIgPSBbYnkobmV4dCksIG5leHRdOwogICAgICBpZiAoIWJlc3QpIHsKICAgICAgICByZXR1cm4gcGFpcjsKICAgICAgfSBlbHNlIGlmIChjb21wYXJlKGJlc3RbMF0sIHBhaXJbMF0pID09PSBiZXN0WzBdKSB7CiAgICAgICAgcmV0dXJuIGJlc3Q7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHBhaXI7CiAgICAgIH0KICAgIH0sIG51bGwpWzFdOwogIH0KCiAgZnVuY3Rpb24gcGljayhvYmosIGtleXMpIHsKICAgIHJldHVybiBrZXlzLnJlZHVjZSgoYSwgaykgPT4gewogICAgICBhW2tdID0gb2JqW2tdOwogICAgICByZXR1cm4gYTsKICAgIH0sIHt9KTsKICB9CgogIGZ1bmN0aW9uIGhhc093blByb3BlcnR5KG9iaiwgcHJvcCkgewogICAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIHByb3ApOwogIH0KCiAgLy8gTlVNQkVSUyBBTkQgU1RSSU5HUwoKICBmdW5jdGlvbiBpbnRlZ2VyQmV0d2Vlbih0aGluZywgYm90dG9tLCB0b3ApIHsKICAgIHJldHVybiBpc0ludGVnZXIodGhpbmcpICYmIHRoaW5nID49IGJvdHRvbSAmJiB0aGluZyA8PSB0b3A7CiAgfQoKICAvLyB4ICUgbiBidXQgdGFrZXMgdGhlIHNpZ24gb2YgbiBpbnN0ZWFkIG9mIHgKICBmdW5jdGlvbiBmbG9vck1vZCh4LCBuKSB7CiAgICByZXR1cm4geCAtIG4gKiBNYXRoLmZsb29yKHggLyBuKTsKICB9CgogIGZ1bmN0aW9uIHBhZFN0YXJ0KGlucHV0LCBuID0gMikgewogICAgY29uc3QgaXNOZWcgPSBpbnB1dCA8IDA7CiAgICBsZXQgcGFkZGVkOwogICAgaWYgKGlzTmVnKSB7CiAgICAgIHBhZGRlZCA9ICItIiArICgiIiArIC1pbnB1dCkucGFkU3RhcnQobiwgIjAiKTsKICAgIH0gZWxzZSB7CiAgICAgIHBhZGRlZCA9ICgiIiArIGlucHV0KS5wYWRTdGFydChuLCAiMCIpOwogICAgfQogICAgcmV0dXJuIHBhZGRlZDsKICB9CgogIGZ1bmN0aW9uIHBhcnNlSW50ZWdlcihzdHJpbmcpIHsKICAgIGlmIChpc1VuZGVmaW5lZChzdHJpbmcpIHx8IHN0cmluZyA9PT0gbnVsbCB8fCBzdHJpbmcgPT09ICIiKSB7CiAgICAgIHJldHVybiB1bmRlZmluZWQ7CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gcGFyc2VJbnQoc3RyaW5nLCAxMCk7CiAgICB9CiAgfQoKICBmdW5jdGlvbiBwYXJzZUZsb2F0aW5nKHN0cmluZykgewogICAgaWYgKGlzVW5kZWZpbmVkKHN0cmluZykgfHwgc3RyaW5nID09PSBudWxsIHx8IHN0cmluZyA9PT0gIiIpIHsKICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiBwYXJzZUZsb2F0KHN0cmluZyk7CiAgICB9CiAgfQoKICBmdW5jdGlvbiBwYXJzZU1pbGxpcyhmcmFjdGlvbikgewogICAgLy8gUmV0dXJuIHVuZGVmaW5lZCAoaW5zdGVhZCBvZiAwKSBpbiB0aGVzZSBjYXNlcywgd2hlcmUgZnJhY3Rpb24gaXMgbm90IHNldAogICAgaWYgKGlzVW5kZWZpbmVkKGZyYWN0aW9uKSB8fCBmcmFjdGlvbiA9PT0gbnVsbCB8fCBmcmFjdGlvbiA9PT0gIiIpIHsKICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0IGYgPSBwYXJzZUZsb2F0KCIwLiIgKyBmcmFjdGlvbikgKiAxMDAwOwogICAgICByZXR1cm4gTWF0aC5mbG9vcihmKTsKICAgIH0KICB9CgogIGZ1bmN0aW9uIHJvdW5kVG8obnVtYmVyLCBkaWdpdHMsIHRvd2FyZFplcm8gPSBmYWxzZSkgewogICAgY29uc3QgZmFjdG9yID0gMTAgKiogZGlnaXRzLAogICAgICByb3VuZGVyID0gdG93YXJkWmVybyA/IE1hdGgudHJ1bmMgOiBNYXRoLnJvdW5kOwogICAgcmV0dXJuIHJvdW5kZXIobnVtYmVyICogZmFjdG9yKSAvIGZhY3RvcjsKICB9CgogIC8vIERBVEUgQkFTSUNTCgogIGZ1bmN0aW9uIGlzTGVhcFllYXIoeWVhcikgewogICAgcmV0dXJuIHllYXIgJSA0ID09PSAwICYmICh5ZWFyICUgMTAwICE9PSAwIHx8IHllYXIgJSA0MDAgPT09IDApOwogIH0KCiAgZnVuY3Rpb24gZGF5c0luWWVhcih5ZWFyKSB7CiAgICByZXR1cm4gaXNMZWFwWWVhcih5ZWFyKSA/IDM2NiA6IDM2NTsKICB9CgogIGZ1bmN0aW9uIGRheXNJbk1vbnRoKHllYXIsIG1vbnRoKSB7CiAgICBjb25zdCBtb2RNb250aCA9IGZsb29yTW9kKG1vbnRoIC0gMSwgMTIpICsgMSwKICAgICAgbW9kWWVhciA9IHllYXIgKyAobW9udGggLSBtb2RNb250aCkgLyAxMjsKCiAgICBpZiAobW9kTW9udGggPT09IDIpIHsKICAgICAgcmV0dXJuIGlzTGVhcFllYXIobW9kWWVhcikgPyAyOSA6IDI4OwogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuIFszMSwgbnVsbCwgMzEsIDMwLCAzMSwgMzAsIDMxLCAzMSwgMzAsIDMxLCAzMCwgMzFdW21vZE1vbnRoIC0gMV07CiAgICB9CiAgfQoKICAvLyBjb252ZXJ0IGEgY2FsZW5kYXIgb2JqZWN0IHRvIGEgbG9jYWwgdGltZXN0YW1wIChlcG9jaCwgYnV0IHdpdGggdGhlIG9mZnNldCBiYWtlZCBpbikKICBmdW5jdGlvbiBvYmpUb0xvY2FsVFMob2JqKSB7CiAgICBsZXQgZCA9IERhdGUuVVRDKAogICAgICBvYmoueWVhciwKICAgICAgb2JqLm1vbnRoIC0gMSwKICAgICAgb2JqLmRheSwKICAgICAgb2JqLmhvdXIsCiAgICAgIG9iai5taW51dGUsCiAgICAgIG9iai5zZWNvbmQsCiAgICAgIG9iai5taWxsaXNlY29uZAogICAgKTsKCiAgICAvLyBmb3IgbGVnYWN5IHJlYXNvbnMsIHllYXJzIGJldHdlZW4gMCBhbmQgOTkgYXJlIGludGVycHJldGVkIGFzIDE5WFg7IHJldmVydCB0aGF0CiAgICBpZiAob2JqLnllYXIgPCAxMDAgJiYgb2JqLnllYXIgPj0gMCkgewogICAgICBkID0gbmV3IERhdGUoZCk7CiAgICAgIC8vIHNldCB0aGUgbW9udGggYW5kIGRheSBhZ2FpbiwgdGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSB5ZWFyIDIwMDAgaXMgYSBsZWFwIHllYXIsIGJ1dCB5ZWFyIDEwMCBpcyBub3QKICAgICAgLy8gc28gaWYgb2JqLnllYXIgaXMgaW4gOTksIGJ1dCBvYmouZGF5IG1ha2VzIGl0IHJvbGwgb3ZlciBpbnRvIHllYXIgMTAwLAogICAgICAvLyB0aGUgY2FsY3VsYXRpb25zIGRvbmUgYnkgRGF0ZS5VVEMgYXJlIHVzaW5nIHllYXIgMjAwMCAtIHdoaWNoIGlzIGluY29ycmVjdAogICAgICBkLnNldFVUQ0Z1bGxZZWFyKG9iai55ZWFyLCBvYmoubW9udGggLSAxLCBvYmouZGF5KTsKICAgIH0KICAgIHJldHVybiArZDsKICB9CgogIGZ1bmN0aW9uIHdlZWtzSW5XZWVrWWVhcih3ZWVrWWVhcikgewogICAgY29uc3QgcDEgPQogICAgICAgICh3ZWVrWWVhciArCiAgICAgICAgICBNYXRoLmZsb29yKHdlZWtZZWFyIC8gNCkgLQogICAgICAgICAgTWF0aC5mbG9vcih3ZWVrWWVhciAvIDEwMCkgKwogICAgICAgICAgTWF0aC5mbG9vcih3ZWVrWWVhciAvIDQwMCkpICUKICAgICAgICA3LAogICAgICBsYXN0ID0gd2Vla1llYXIgLSAxLAogICAgICBwMiA9IChsYXN0ICsgTWF0aC5mbG9vcihsYXN0IC8gNCkgLSBNYXRoLmZsb29yKGxhc3QgLyAxMDApICsgTWF0aC5mbG9vcihsYXN0IC8gNDAwKSkgJSA3OwogICAgcmV0dXJuIHAxID09PSA0IHx8IHAyID09PSAzID8gNTMgOiA1MjsKICB9CgogIGZ1bmN0aW9uIHVudHJ1bmNhdGVZZWFyKHllYXIpIHsKICAgIGlmICh5ZWFyID4gOTkpIHsKICAgICAgcmV0dXJuIHllYXI7CiAgICB9IGVsc2UgcmV0dXJuIHllYXIgPiBTZXR0aW5ncy50d29EaWdpdEN1dG9mZlllYXIgPyAxOTAwICsgeWVhciA6IDIwMDAgKyB5ZWFyOwogIH0KCiAgLy8gUEFSU0lORwoKICBmdW5jdGlvbiBwYXJzZVpvbmVJbmZvKHRzLCBvZmZzZXRGb3JtYXQsIGxvY2FsZSwgdGltZVpvbmUgPSBudWxsKSB7CiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUodHMpLAogICAgICBpbnRsT3B0cyA9IHsKICAgICAgICBob3VyQ3ljbGU6ICJoMjMiLAogICAgICAgIHllYXI6ICJudW1lcmljIiwKICAgICAgICBtb250aDogIjItZGlnaXQiLAogICAgICAgIGRheTogIjItZGlnaXQiLAogICAgICAgIGhvdXI6ICIyLWRpZ2l0IiwKICAgICAgICBtaW51dGU6ICIyLWRpZ2l0IiwKICAgICAgfTsKCiAgICBpZiAodGltZVpvbmUpIHsKICAgICAgaW50bE9wdHMudGltZVpvbmUgPSB0aW1lWm9uZTsKICAgIH0KCiAgICBjb25zdCBtb2RpZmllZCA9IHsgdGltZVpvbmVOYW1lOiBvZmZzZXRGb3JtYXQsIC4uLmludGxPcHRzIH07CgogICAgY29uc3QgcGFyc2VkID0gbmV3IEludGwuRGF0ZVRpbWVGb3JtYXQobG9jYWxlLCBtb2RpZmllZCkKICAgICAgLmZvcm1hdFRvUGFydHMoZGF0ZSkKICAgICAgLmZpbmQoKG0pID0+IG0udHlwZS50b0xvd2VyQ2FzZSgpID09PSAidGltZXpvbmVuYW1lIik7CiAgICByZXR1cm4gcGFyc2VkID8gcGFyc2VkLnZhbHVlIDogbnVsbDsKICB9CgogIC8vIHNpZ25lZE9mZnNldCgnLTUnLCAnMzAnKSAtPiAtMzMwCiAgZnVuY3Rpb24gc2lnbmVkT2Zmc2V0KG9mZkhvdXJTdHIsIG9mZk1pbnV0ZVN0cikgewogICAgbGV0IG9mZkhvdXIgPSBwYXJzZUludChvZmZIb3VyU3RyLCAxMCk7CgogICAgLy8gZG9uJ3QgfHwgdGhpcyBiZWNhdXNlIHdlIHdhbnQgdG8gcHJlc2VydmUgLTAKICAgIGlmIChOdW1iZXIuaXNOYU4ob2ZmSG91cikpIHsKICAgICAgb2ZmSG91ciA9IDA7CiAgICB9CgogICAgY29uc3Qgb2ZmTWluID0gcGFyc2VJbnQob2ZmTWludXRlU3RyLCAxMCkgfHwgMCwKICAgICAgb2ZmTWluU2lnbmVkID0gb2ZmSG91ciA8IDAgfHwgT2JqZWN0LmlzKG9mZkhvdXIsIC0wKSA/IC1vZmZNaW4gOiBvZmZNaW47CiAgICByZXR1cm4gb2ZmSG91ciAqIDYwICsgb2ZmTWluU2lnbmVkOwogIH0KCiAgLy8gQ09FUkNJT04KCiAgZnVuY3Rpb24gYXNOdW1iZXIodmFsdWUpIHsKICAgIGNvbnN0IG51bWVyaWNWYWx1ZSA9IE51bWJlcih2YWx1ZSk7CiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAiYm9vbGVhbiIgfHwgdmFsdWUgPT09ICIiIHx8IE51bWJlci5pc05hTihudW1lcmljVmFsdWUpKQogICAgICB0aHJvdyBuZXcgSW52YWxpZEFyZ3VtZW50RXJyb3IoYEludmFsaWQgdW5pdCB2YWx1ZSAke3ZhbHVlfWApOwogICAgcmV0dXJuIG51bWVyaWNWYWx1ZTsKICB9CgogIGZ1bmN0aW9uIG5vcm1hbGl6ZU9iamVjdChvYmosIG5vcm1hbGl6ZXIpIHsKICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSB7fTsKICAgIGZvciAoY29uc3QgdSBpbiBvYmopIHsKICAgICAgaWYgKGhhc093blByb3BlcnR5KG9iaiwgdSkpIHsKICAgICAgICBjb25zdCB2ID0gb2JqW3VdOwogICAgICAgIGlmICh2ID09PSB1bmRlZmluZWQgfHwgdiA9PT0gbnVsbCkgY29udGludWU7CiAgICAgICAgbm9ybWFsaXplZFtub3JtYWxpemVyKHUpXSA9IGFzTnVtYmVyKHYpOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gbm9ybWFsaXplZDsKICB9CgogIGZ1bmN0aW9uIGZvcm1hdE9mZnNldChvZmZzZXQsIGZvcm1hdCkgewogICAgY29uc3QgaG91cnMgPSBNYXRoLnRydW5jKE1hdGguYWJzKG9mZnNldCAvIDYwKSksCiAgICAgIG1pbnV0ZXMgPSBNYXRoLnRydW5jKE1hdGguYWJzKG9mZnNldCAlIDYwKSksCiAgICAgIHNpZ24gPSBvZmZzZXQgPj0gMCA/ICIrIiA6ICItIjsKCiAgICBzd2l0Y2ggKGZvcm1hdCkgewogICAgICBjYXNlICJzaG9ydCI6CiAgICAgICAgcmV0dXJuIGAke3NpZ259JHtwYWRTdGFydChob3VycywgMil9OiR7cGFkU3RhcnQobWludXRlcywgMil9YDsKICAgICAgY2FzZSAibmFycm93IjoKICAgICAgICByZXR1cm4gYCR7c2lnbn0ke2hvdXJzfSR7bWludXRlcyA+IDAgPyBgOiR7bWludXRlc31gIDogIiJ9YDsKICAgICAgY2FzZSAidGVjaGllIjoKICAgICAgICByZXR1cm4gYCR7c2lnbn0ke3BhZFN0YXJ0KGhvdXJzLCAyKX0ke3BhZFN0YXJ0KG1pbnV0ZXMsIDIpfWA7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoYFZhbHVlIGZvcm1hdCAke2Zvcm1hdH0gaXMgb3V0IG9mIHJhbmdlIGZvciBwcm9wZXJ0eSBmb3JtYXRgKTsKICAgIH0KICB9CgogIGZ1bmN0aW9uIHRpbWVPYmplY3Qob2JqKSB7CiAgICByZXR1cm4gcGljayhvYmosIFsiaG91ciIsICJtaW51dGUiLCAic2Vjb25kIiwgIm1pbGxpc2Vjb25kIl0pOwogIH0KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KCiAgY29uc3QgbW9udGhzTG9uZyA9IFsKICAgICJKYW51YXJ5IiwKICAgICJGZWJydWFyeSIsCiAgICAiTWFyY2giLAogICAgIkFwcmlsIiwKICAgICJNYXkiLAogICAgIkp1bmUiLAogICAgIkp1bHkiLAogICAgIkF1Z3VzdCIsCiAgICAiU2VwdGVtYmVyIiwKICAgICJPY3RvYmVyIiwKICAgICJOb3ZlbWJlciIsCiAgICAiRGVjZW1iZXIiLAogIF07CgogIGNvbnN0IG1vbnRoc1Nob3J0ID0gWwogICAgIkphbiIsCiAgICAiRmViIiwKICAgICJNYXIiLAogICAgIkFwciIsCiAgICAiTWF5IiwKICAgICJKdW4iLAogICAgIkp1bCIsCiAgICAiQXVnIiwKICAgICJTZXAiLAogICAgIk9jdCIsCiAgICAiTm92IiwKICAgICJEZWMiLAogIF07CgogIGNvbnN0IG1vbnRoc05hcnJvdyA9IFsiSiIsICJGIiwgIk0iLCAiQSIsICJNIiwgIkoiLCAiSiIsICJBIiwgIlMiLCAiTyIsICJOIiwgIkQiXTsKCiAgZnVuY3Rpb24gbW9udGhzKGxlbmd0aCkgewogICAgc3dpdGNoIChsZW5ndGgpIHsKICAgICAgY2FzZSAibmFycm93IjoKICAgICAgICByZXR1cm4gWy4uLm1vbnRoc05hcnJvd107CiAgICAgIGNhc2UgInNob3J0IjoKICAgICAgICByZXR1cm4gWy4uLm1vbnRoc1Nob3J0XTsKICAgICAgY2FzZSAibG9uZyI6CiAgICAgICAgcmV0dXJuIFsuLi5tb250aHNMb25nXTsKICAgICAgY2FzZSAibnVtZXJpYyI6CiAgICAgICAgcmV0dXJuIFsiMSIsICIyIiwgIjMiLCAiNCIsICI1IiwgIjYiLCAiNyIsICI4IiwgIjkiLCAiMTAiLCAiMTEiLCAiMTIiXTsKICAgICAgY2FzZSAiMi1kaWdpdCI6CiAgICAgICAgcmV0dXJuIFsiMDEiLCAiMDIiLCAiMDMiLCAiMDQiLCAiMDUiLCAiMDYiLCAiMDciLCAiMDgiLCAiMDkiLCAiMTAiLCAiMTEiLCAiMTIiXTsKICAgICAgZGVmYXVsdDoKICAgICAgICByZXR1cm4gbnVsbDsKICAgIH0KICB9CgogIGNvbnN0IHdlZWtkYXlzTG9uZyA9IFsKICAgICJNb25kYXkiLAogICAgIlR1ZXNkYXkiLAogICAgIldlZG5lc2RheSIsCiAgICAiVGh1cnNkYXkiLAogICAgIkZyaWRheSIsCiAgICAiU2F0dXJkYXkiLAogICAgIlN1bmRheSIsCiAgXTsKCiAgY29uc3Qgd2Vla2RheXNTaG9ydCA9IFsiTW9uIiwgIlR1ZSIsICJXZWQiLCAiVGh1IiwgIkZyaSIsICJTYXQiLCAiU3VuIl07CgogIGNvbnN0IHdlZWtkYXlzTmFycm93ID0gWyJNIiwgIlQiLCAiVyIsICJUIiwgIkYiLCAiUyIsICJTIl07CgogIGZ1bmN0aW9uIHdlZWtkYXlzKGxlbmd0aCkgewogICAgc3dpdGNoIChsZW5ndGgpIHsKICAgICAgY2FzZSAibmFycm93IjoKICAgICAgICByZXR1cm4gWy4uLndlZWtkYXlzTmFycm93XTsKICAgICAgY2FzZSAic2hvcnQiOgogICAgICAgIHJldHVybiBbLi4ud2Vla2RheXNTaG9ydF07CiAgICAgIGNhc2UgImxvbmciOgogICAgICAgIHJldHVybiBbLi4ud2Vla2RheXNMb25nXTsKICAgICAgY2FzZSAibnVtZXJpYyI6CiAgICAgICAgcmV0dXJuIFsiMSIsICIyIiwgIjMiLCAiNCIsICI1IiwgIjYiLCAiNyJdOwogICAgICBkZWZhdWx0OgogICAgICAgIHJldHVybiBudWxsOwogICAgfQogIH0KCiAgY29uc3QgbWVyaWRpZW1zID0gWyJBTSIsICJQTSJdOwoKICBjb25zdCBlcmFzTG9uZyA9IFsiQmVmb3JlIENocmlzdCIsICJBbm5vIERvbWluaSJdOwoKICBjb25zdCBlcmFzU2hvcnQgPSBbIkJDIiwgIkFEIl07CgogIGNvbnN0IGVyYXNOYXJyb3cgPSBbIkIiLCAiQSJdOwoKICBmdW5jdGlvbiBlcmFzKGxlbmd0aCkgewogICAgc3dpdGNoIChsZW5ndGgpIHsKICAgICAgY2FzZSAibmFycm93IjoKICAgICAgICByZXR1cm4gWy4uLmVyYXNOYXJyb3ddOwogICAgICBjYXNlICJzaG9ydCI6CiAgICAgICAgcmV0dXJuIFsuLi5lcmFzU2hvcnRdOwogICAgICBjYXNlICJsb25nIjoKICAgICAgICByZXR1cm4gWy4uLmVyYXNMb25nXTsKICAgICAgZGVmYXVsdDoKICAgICAgICByZXR1cm4gbnVsbDsKICAgIH0KICB9CgogIGZ1bmN0aW9uIG1lcmlkaWVtRm9yRGF0ZVRpbWUoZHQpIHsKICAgIHJldHVybiBtZXJpZGllbXNbZHQuaG91ciA8IDEyID8gMCA6IDFdOwogIH0KCiAgZnVuY3Rpb24gd2Vla2RheUZvckRhdGVUaW1lKGR0LCBsZW5ndGgpIHsKICAgIHJldHVybiB3ZWVrZGF5cyhsZW5ndGgpW2R0LndlZWtkYXkgLSAxXTsKICB9CgogIGZ1bmN0aW9uIG1vbnRoRm9yRGF0ZVRpbWUoZHQsIGxlbmd0aCkgewogICAgcmV0dXJuIG1vbnRocyhsZW5ndGgpW2R0Lm1vbnRoIC0gMV07CiAgfQoKICBmdW5jdGlvbiBlcmFGb3JEYXRlVGltZShkdCwgbGVuZ3RoKSB7CiAgICByZXR1cm4gZXJhcyhsZW5ndGgpW2R0LnllYXIgPCAwID8gMCA6IDFdOwogIH0KCiAgZnVuY3Rpb24gZm9ybWF0UmVsYXRpdmVUaW1lKHVuaXQsIGNvdW50LCBudW1lcmljID0gImFsd2F5cyIsIG5hcnJvdyA9IGZhbHNlKSB7CiAgICBjb25zdCB1bml0cyA9IHsKICAgICAgeWVhcnM6IFsieWVhciIsICJ5ci4iXSwKICAgICAgcXVhcnRlcnM6IFsicXVhcnRlciIsICJxdHIuIl0sCiAgICAgIG1vbnRoczogWyJtb250aCIsICJtby4iXSwKICAgICAgd2Vla3M6IFsid2VlayIsICJ3ay4iXSwKICAgICAgZGF5czogWyJkYXkiLCAiZGF5IiwgImRheXMiXSwKICAgICAgaG91cnM6IFsiaG91ciIsICJoci4iXSwKICAgICAgbWludXRlczogWyJtaW51dGUiLCAibWluLiJdLAogICAgICBzZWNvbmRzOiBbInNlY29uZCIsICJzZWMuIl0sCiAgICB9OwoKICAgIGNvbnN0IGxhc3RhYmxlID0gWyJob3VycyIsICJtaW51dGVzIiwgInNlY29uZHMiXS5pbmRleE9mKHVuaXQpID09PSAtMTsKCiAgICBpZiAobnVtZXJpYyA9PT0gImF1dG8iICYmIGxhc3RhYmxlKSB7CiAgICAgIGNvbnN0IGlzRGF5ID0gdW5pdCA9PT0gImRheXMiOwogICAgICBzd2l0Y2ggKGNvdW50KSB7CiAgICAgICAgY2FzZSAxOgogICAgICAgICAgcmV0dXJuIGlzRGF5ID8gInRvbW9ycm93IiA6IGBuZXh0ICR7dW5pdHNbdW5pdF1bMF19YDsKICAgICAgICBjYXNlIC0xOgogICAgICAgICAgcmV0dXJuIGlzRGF5ID8gInllc3RlcmRheSIgOiBgbGFzdCAke3VuaXRzW3VuaXRdWzBdfWA7CiAgICAgICAgY2FzZSAwOgogICAgICAgICAgcmV0dXJuIGlzRGF5ID8gInRvZGF5IiA6IGB0aGlzICR7dW5pdHNbdW5pdF1bMF19YDsKICAgICAgfQogICAgfQoKICAgIGNvbnN0IGlzSW5QYXN0ID0gT2JqZWN0LmlzKGNvdW50LCAtMCkgfHwgY291bnQgPCAwLAogICAgICBmbXRWYWx1ZSA9IE1hdGguYWJzKGNvdW50KSwKICAgICAgc2luZ3VsYXIgPSBmbXRWYWx1ZSA9PT0gMSwKICAgICAgbGlsVW5pdHMgPSB1bml0c1t1bml0XSwKICAgICAgZm10VW5pdCA9IG5hcnJvdwogICAgICAgID8gc2luZ3VsYXIKICAgICAgICAgID8gbGlsVW5pdHNbMV0KICAgICAgICAgIDogbGlsVW5pdHNbMl0gfHwgbGlsVW5pdHNbMV0KICAgICAgICA6IHNpbmd1bGFyCiAgICAgICAgPyB1bml0c1t1bml0XVswXQogICAgICAgIDogdW5pdDsKICAgIHJldHVybiBpc0luUGFzdCA/IGAke2ZtdFZhbHVlfSAke2ZtdFVuaXR9IGFnb2AgOiBgaW4gJHtmbXRWYWx1ZX0gJHtmbXRVbml0fWA7CiAgfQoKICBmdW5jdGlvbiBzdHJpbmdpZnlUb2tlbnMoc3BsaXRzLCB0b2tlblRvU3RyaW5nKSB7CiAgICBsZXQgcyA9ICIiOwogICAgZm9yIChjb25zdCB0b2tlbiBvZiBzcGxpdHMpIHsKICAgICAgaWYgKHRva2VuLmxpdGVyYWwpIHsKICAgICAgICBzICs9IHRva2VuLnZhbDsKICAgICAgfSBlbHNlIHsKICAgICAgICBzICs9IHRva2VuVG9TdHJpbmcodG9rZW4udmFsKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHM7CiAgfQoKICBjb25zdCBtYWNyb1Rva2VuVG9Gb3JtYXRPcHRzID0gewogICAgRDogREFURV9TSE9SVCwKICAgIEREOiBEQVRFX01FRCwKICAgIERERDogREFURV9GVUxMLAogICAgRERERDogREFURV9IVUdFLAogICAgdDogVElNRV9TSU1QTEUsCiAgICB0dDogVElNRV9XSVRIX1NFQ09ORFMsCiAgICB0dHQ6IFRJTUVfV0lUSF9TSE9SVF9PRkZTRVQsCiAgICB0dHR0OiBUSU1FX1dJVEhfTE9OR19PRkZTRVQsCiAgICBUOiBUSU1FXzI0X1NJTVBMRSwKICAgIFRUOiBUSU1FXzI0X1dJVEhfU0VDT05EUywKICAgIFRUVDogVElNRV8yNF9XSVRIX1NIT1JUX09GRlNFVCwKICAgIFRUVFQ6IFRJTUVfMjRfV0lUSF9MT05HX09GRlNFVCwKICAgIGY6IERBVEVUSU1FX1NIT1JULAogICAgZmY6IERBVEVUSU1FX01FRCwKICAgIGZmZjogREFURVRJTUVfRlVMTCwKICAgIGZmZmY6IERBVEVUSU1FX0hVR0UsCiAgICBGOiBEQVRFVElNRV9TSE9SVF9XSVRIX1NFQ09ORFMsCiAgICBGRjogREFURVRJTUVfTUVEX1dJVEhfU0VDT05EUywKICAgIEZGRjogREFURVRJTUVfRlVMTF9XSVRIX1NFQ09ORFMsCiAgICBGRkZGOiBEQVRFVElNRV9IVUdFX1dJVEhfU0VDT05EUywKICB9OwoKICAvKioKICAgKiBAcHJpdmF0ZQogICAqLwoKICBjbGFzcyBGb3JtYXR0ZXIgewogICAgc3RhdGljIGNyZWF0ZShsb2NhbGUsIG9wdHMgPSB7fSkgewogICAgICByZXR1cm4gbmV3IEZvcm1hdHRlcihsb2NhbGUsIG9wdHMpOwogICAgfQoKICAgIHN0YXRpYyBwYXJzZUZvcm1hdChmbXQpIHsKICAgICAgLy8gd2hpdGUtc3BhY2UgaXMgYWx3YXlzIGNvbnNpZGVyZWQgYSBsaXRlcmFsIGluIHVzZXItcHJvdmlkZWQgZm9ybWF0cwogICAgICAvLyB0aGUgIiAiIHRva2VuIGhhcyBhIHNwZWNpYWwgbWVhbmluZyAoc2VlIHVuaXRGb3JUb2tlbikKCiAgICAgIGxldCBjdXJyZW50ID0gbnVsbCwKICAgICAgICBjdXJyZW50RnVsbCA9ICIiLAogICAgICAgIGJyYWNrZXRlZCA9IGZhbHNlOwogICAgICBjb25zdCBzcGxpdHMgPSBbXTsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBmbXQubGVuZ3RoOyBpKyspIHsKICAgICAgICBjb25zdCBjID0gZm10LmNoYXJBdChpKTsKICAgICAgICBpZiAoYyA9PT0gIiciKSB7CiAgICAgICAgICBpZiAoY3VycmVudEZ1bGwubGVuZ3RoID4gMCkgewogICAgICAgICAgICBzcGxpdHMucHVzaCh7IGxpdGVyYWw6IGJyYWNrZXRlZCB8fCAvXlxzKyQvLnRlc3QoY3VycmVudEZ1bGwpLCB2YWw6IGN1cnJlbnRGdWxsIH0pOwogICAgICAgICAgfQogICAgICAgICAgY3VycmVudCA9IG51bGw7CiAgICAgICAgICBjdXJyZW50RnVsbCA9ICIiOwogICAgICAgICAgYnJhY2tldGVkID0gIWJyYWNrZXRlZDsKICAgICAgICB9IGVsc2UgaWYgKGJyYWNrZXRlZCkgewogICAgICAgICAgY3VycmVudEZ1bGwgKz0gYzsKICAgICAgICB9IGVsc2UgaWYgKGMgPT09IGN1cnJlbnQpIHsKICAgICAgICAgIGN1cnJlbnRGdWxsICs9IGM7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGlmIChjdXJyZW50RnVsbC5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgIHNwbGl0cy5wdXNoKHsgbGl0ZXJhbDogL15ccyskLy50ZXN0KGN1cnJlbnRGdWxsKSwgdmFsOiBjdXJyZW50RnVsbCB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGN1cnJlbnRGdWxsID0gYzsKICAgICAgICAgIGN1cnJlbnQgPSBjOwogICAgICAgIH0KICAgICAgfQoKICAgICAgaWYgKGN1cnJlbnRGdWxsLmxlbmd0aCA+IDApIHsKICAgICAgICBzcGxpdHMucHVzaCh7IGxpdGVyYWw6IGJyYWNrZXRlZCB8fCAvXlxzKyQvLnRlc3QoY3VycmVudEZ1bGwpLCB2YWw6IGN1cnJlbnRGdWxsIH0pOwogICAgICB9CgogICAgICByZXR1cm4gc3BsaXRzOwogICAgfQoKICAgIHN0YXRpYyBtYWNyb1Rva2VuVG9Gb3JtYXRPcHRzKHRva2VuKSB7CiAgICAgIHJldHVybiBtYWNyb1Rva2VuVG9Gb3JtYXRPcHRzW3Rva2VuXTsKICAgIH0KCiAgICBjb25zdHJ1Y3Rvcihsb2NhbGUsIGZvcm1hdE9wdHMpIHsKICAgICAgdGhpcy5vcHRzID0gZm9ybWF0T3B0czsKICAgICAgdGhpcy5sb2MgPSBsb2NhbGU7CiAgICAgIHRoaXMuc3lzdGVtTG9jID0gbnVsbDsKICAgIH0KCiAgICBmb3JtYXRXaXRoU3lzdGVtRGVmYXVsdChkdCwgb3B0cykgewogICAgICBpZiAodGhpcy5zeXN0ZW1Mb2MgPT09IG51bGwpIHsKICAgICAgICB0aGlzLnN5c3RlbUxvYyA9IHRoaXMubG9jLnJlZGVmYXVsdFRvU3lzdGVtKCk7CiAgICAgIH0KICAgICAgY29uc3QgZGYgPSB0aGlzLnN5c3RlbUxvYy5kdEZvcm1hdHRlcihkdCwgeyAuLi50aGlzLm9wdHMsIC4uLm9wdHMgfSk7CiAgICAgIHJldHVybiBkZi5mb3JtYXQoKTsKICAgIH0KCiAgICBkdEZvcm1hdHRlcihkdCwgb3B0cyA9IHt9KSB7CiAgICAgIHJldHVybiB0aGlzLmxvYy5kdEZvcm1hdHRlcihkdCwgeyAuLi50aGlzLm9wdHMsIC4uLm9wdHMgfSk7CiAgICB9CgogICAgZm9ybWF0RGF0ZVRpbWUoZHQsIG9wdHMpIHsKICAgICAgcmV0dXJuIHRoaXMuZHRGb3JtYXR0ZXIoZHQsIG9wdHMpLmZvcm1hdCgpOwogICAgfQoKICAgIGZvcm1hdERhdGVUaW1lUGFydHMoZHQsIG9wdHMpIHsKICAgICAgcmV0dXJuIHRoaXMuZHRGb3JtYXR0ZXIoZHQsIG9wdHMpLmZvcm1hdFRvUGFydHMoKTsKICAgIH0KCiAgICBmb3JtYXRJbnRlcnZhbChpbnRlcnZhbCwgb3B0cykgewogICAgICBjb25zdCBkZiA9IHRoaXMuZHRGb3JtYXR0ZXIoaW50ZXJ2YWwuc3RhcnQsIG9wdHMpOwogICAgICByZXR1cm4gZGYuZHRmLmZvcm1hdFJhbmdlKGludGVydmFsLnN0YXJ0LnRvSlNEYXRlKCksIGludGVydmFsLmVuZC50b0pTRGF0ZSgpKTsKICAgIH0KCiAgICByZXNvbHZlZE9wdGlvbnMoZHQsIG9wdHMpIHsKICAgICAgcmV0dXJuIHRoaXMuZHRGb3JtYXR0ZXIoZHQsIG9wdHMpLnJlc29sdmVkT3B0aW9ucygpOwogICAgfQoKICAgIG51bShuLCBwID0gMCkgewogICAgICAvLyB3ZSBnZXQgc29tZSBwZXJmIG91dCBvZiBkb2luZyB0aGlzIGhlcmUsIGFubm95aW5nbHkKICAgICAgaWYgKHRoaXMub3B0cy5mb3JjZVNpbXBsZSkgewogICAgICAgIHJldHVybiBwYWRTdGFydChuLCBwKTsKICAgICAgfQoKICAgICAgY29uc3Qgb3B0cyA9IHsgLi4udGhpcy5vcHRzIH07CgogICAgICBpZiAocCA+IDApIHsKICAgICAgICBvcHRzLnBhZFRvID0gcDsKICAgICAgfQoKICAgICAgcmV0dXJuIHRoaXMubG9jLm51bWJlckZvcm1hdHRlcihvcHRzKS5mb3JtYXQobik7CiAgICB9CgogICAgZm9ybWF0RGF0ZVRpbWVGcm9tU3RyaW5nKGR0LCBmbXQpIHsKICAgICAgY29uc3Qga25vd25FbmdsaXNoID0gdGhpcy5sb2MubGlzdGluZ01vZGUoKSA9PT0gImVuIiwKICAgICAgICB1c2VEYXRlVGltZUZvcm1hdHRlciA9IHRoaXMubG9jLm91dHB1dENhbGVuZGFyICYmIHRoaXMubG9jLm91dHB1dENhbGVuZGFyICE9PSAiZ3JlZ29yeSIsCiAgICAgICAgc3RyaW5nID0gKG9wdHMsIGV4dHJhY3QpID0+IHRoaXMubG9jLmV4dHJhY3QoZHQsIG9wdHMsIGV4dHJhY3QpLAogICAgICAgIGZvcm1hdE9mZnNldCA9IChvcHRzKSA9PiB7CiAgICAgICAgICBpZiAoZHQuaXNPZmZzZXRGaXhlZCAmJiBkdC5vZmZzZXQgPT09IDAgJiYgb3B0cy5hbGxvd1opIHsKICAgICAgICAgICAgcmV0dXJuICJaIjsKICAgICAgICAgIH0KCiAgICAgICAgICByZXR1cm4gZHQuaXNWYWxpZCA/IGR0LnpvbmUuZm9ybWF0T2Zmc2V0KGR0LnRzLCBvcHRzLmZvcm1hdCkgOiAiIjsKICAgICAgICB9LAogICAgICAgIG1lcmlkaWVtID0gKCkgPT4KICAgICAgICAgIGtub3duRW5nbGlzaAogICAgICAgICAgICA/IG1lcmlkaWVtRm9yRGF0ZVRpbWUoZHQpCiAgICAgICAgICAgIDogc3RyaW5nKHsgaG91cjogIm51bWVyaWMiLCBob3VyQ3ljbGU6ICJoMTIiIH0sICJkYXlwZXJpb2QiKSwKICAgICAgICBtb250aCA9IChsZW5ndGgsIHN0YW5kYWxvbmUpID0+CiAgICAgICAgICBrbm93bkVuZ2xpc2gKICAgICAgICAgICAgPyBtb250aEZvckRhdGVUaW1lKGR0LCBsZW5ndGgpCiAgICAgICAgICAgIDogc3RyaW5nKHN0YW5kYWxvbmUgPyB7IG1vbnRoOiBsZW5ndGggfSA6IHsgbW9udGg6IGxlbmd0aCwgZGF5OiAibnVtZXJpYyIgfSwgIm1vbnRoIiksCiAgICAgICAgd2Vla2RheSA9IChsZW5ndGgsIHN0YW5kYWxvbmUpID0+CiAgICAgICAgICBrbm93bkVuZ2xpc2gKICAgICAgICAgICAgPyB3ZWVrZGF5Rm9yRGF0ZVRpbWUoZHQsIGxlbmd0aCkKICAgICAgICAgICAgOiBzdHJpbmcoCiAgICAgICAgICAgICAgICBzdGFuZGFsb25lID8geyB3ZWVrZGF5OiBsZW5ndGggfSA6IHsgd2Vla2RheTogbGVuZ3RoLCBtb250aDogImxvbmciLCBkYXk6ICJudW1lcmljIiB9LAogICAgICAgICAgICAgICAgIndlZWtkYXkiCiAgICAgICAgICAgICAgKSwKICAgICAgICBtYXliZU1hY3JvID0gKHRva2VuKSA9PiB7CiAgICAgICAgICBjb25zdCBmb3JtYXRPcHRzID0gRm9ybWF0dGVyLm1hY3JvVG9rZW5Ub0Zvcm1hdE9wdHModG9rZW4pOwogICAgICAgICAgaWYgKGZvcm1hdE9wdHMpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZm9ybWF0V2l0aFN5c3RlbURlZmF1bHQoZHQsIGZvcm1hdE9wdHMpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuIHRva2VuOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgZXJhID0gKGxlbmd0aCkgPT4KICAgICAgICAgIGtub3duRW5nbGlzaCA/IGVyYUZvckRhdGVUaW1lKGR0LCBsZW5ndGgpIDogc3RyaW5nKHsgZXJhOiBsZW5ndGggfSwgImVyYSIpLAogICAgICAgIHRva2VuVG9TdHJpbmcgPSAodG9rZW4pID0+IHsKICAgICAgICAgIC8vIFdoZXJlIHBvc3NpYmxlOiBodHRwczovL2NsZHIudW5pY29kZS5vcmcvdHJhbnNsYXRpb24vZGF0ZS10aW1lL2RhdGUtdGltZS1zeW1ib2xzCiAgICAgICAgICBzd2l0Y2ggKHRva2VuKSB7CiAgICAgICAgICAgIC8vIG1zCiAgICAgICAgICAgIGNhc2UgIlMiOgogICAgICAgICAgICAgIHJldHVybiB0aGlzLm51bShkdC5taWxsaXNlY29uZCk7CiAgICAgICAgICAgIGNhc2UgInUiOgogICAgICAgICAgICAvLyBmYWxscyB0aHJvdWdoCiAgICAgICAgICAgIGNhc2UgIlNTUyI6CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0Lm1pbGxpc2Vjb25kLCAzKTsKICAgICAgICAgICAgLy8gc2Vjb25kcwogICAgICAgICAgICBjYXNlICJzIjoKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oZHQuc2Vjb25kKTsKICAgICAgICAgICAgY2FzZSAic3MiOgogICAgICAgICAgICAgIHJldHVybiB0aGlzLm51bShkdC5zZWNvbmQsIDIpOwogICAgICAgICAgICAvLyBmcmFjdGlvbmFsIHNlY29uZHMKICAgICAgICAgICAgY2FzZSAidXUiOgogICAgICAgICAgICAgIHJldHVybiB0aGlzLm51bShNYXRoLmZsb29yKGR0Lm1pbGxpc2Vjb25kIC8gMTApLCAyKTsKICAgICAgICAgICAgY2FzZSAidXV1IjoKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oTWF0aC5mbG9vcihkdC5taWxsaXNlY29uZCAvIDEwMCkpOwogICAgICAgICAgICAvLyBtaW51dGVzCiAgICAgICAgICAgIGNhc2UgIm0iOgogICAgICAgICAgICAgIHJldHVybiB0aGlzLm51bShkdC5taW51dGUpOwogICAgICAgICAgICBjYXNlICJtbSI6CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0Lm1pbnV0ZSwgMik7CiAgICAgICAgICAgIC8vIGhvdXJzCiAgICAgICAgICAgIGNhc2UgImgiOgogICAgICAgICAgICAgIHJldHVybiB0aGlzLm51bShkdC5ob3VyICUgMTIgPT09IDAgPyAxMiA6IGR0LmhvdXIgJSAxMik7CiAgICAgICAgICAgIGNhc2UgImhoIjoKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oZHQuaG91ciAlIDEyID09PSAwID8gMTIgOiBkdC5ob3VyICUgMTIsIDIpOwogICAgICAgICAgICBjYXNlICJIIjoKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oZHQuaG91cik7CiAgICAgICAgICAgIGNhc2UgIkhIIjoKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oZHQuaG91ciwgMik7CiAgICAgICAgICAgIC8vIG9mZnNldAogICAgICAgICAgICBjYXNlICJaIjoKICAgICAgICAgICAgICAvLyBsaWtlICs2CiAgICAgICAgICAgICAgcmV0dXJuIGZvcm1hdE9mZnNldCh7IGZvcm1hdDogIm5hcnJvdyIsIGFsbG93WjogdGhpcy5vcHRzLmFsbG93WiB9KTsKICAgICAgICAgICAgY2FzZSAiWloiOgogICAgICAgICAgICAgIC8vIGxpa2UgKzA2OjAwCiAgICAgICAgICAgICAgcmV0dXJuIGZvcm1hdE9mZnNldCh7IGZvcm1hdDogInNob3J0IiwgYWxsb3daOiB0aGlzLm9wdHMuYWxsb3daIH0pOwogICAgICAgICAgICBjYXNlICJaWloiOgogICAgICAgICAgICAgIC8vIGxpa2UgKzA2MDAKICAgICAgICAgICAgICByZXR1cm4gZm9ybWF0T2Zmc2V0KHsgZm9ybWF0OiAidGVjaGllIiwgYWxsb3daOiB0aGlzLm9wdHMuYWxsb3daIH0pOwogICAgICAgICAgICBjYXNlICJaWlpaIjoKICAgICAgICAgICAgICAvLyBsaWtlIEVTVAogICAgICAgICAgICAgIHJldHVybiBkdC56b25lLm9mZnNldE5hbWUoZHQudHMsIHsgZm9ybWF0OiAic2hvcnQiLCBsb2NhbGU6IHRoaXMubG9jLmxvY2FsZSB9KTsKICAgICAgICAgICAgY2FzZSAiWlpaWloiOgogICAgICAgICAgICAgIC8vIGxpa2UgRWFzdGVybiBTdGFuZGFyZCBUaW1lCiAgICAgICAgICAgICAgcmV0dXJuIGR0LnpvbmUub2Zmc2V0TmFtZShkdC50cywgeyBmb3JtYXQ6ICJsb25nIiwgbG9jYWxlOiB0aGlzLmxvYy5sb2NhbGUgfSk7CiAgICAgICAgICAgIC8vIHpvbmUKICAgICAgICAgICAgY2FzZSAieiI6CiAgICAgICAgICAgICAgLy8gbGlrZSBBbWVyaWNhL05ld19Zb3JrCiAgICAgICAgICAgICAgcmV0dXJuIGR0LnpvbmVOYW1lOwogICAgICAgICAgICAvLyBtZXJpZGllbXMKICAgICAgICAgICAgY2FzZSAiYSI6CiAgICAgICAgICAgICAgcmV0dXJuIG1lcmlkaWVtKCk7CiAgICAgICAgICAgIC8vIGRhdGVzCiAgICAgICAgICAgIGNhc2UgImQiOgogICAgICAgICAgICAgIHJldHVybiB1c2VEYXRlVGltZUZvcm1hdHRlciA/IHN0cmluZyh7IGRheTogIm51bWVyaWMiIH0sICJkYXkiKSA6IHRoaXMubnVtKGR0LmRheSk7CiAgICAgICAgICAgIGNhc2UgImRkIjoKICAgICAgICAgICAgICByZXR1cm4gdXNlRGF0ZVRpbWVGb3JtYXR0ZXIgPyBzdHJpbmcoeyBkYXk6ICIyLWRpZ2l0IiB9LCAiZGF5IikgOiB0aGlzLm51bShkdC5kYXksIDIpOwogICAgICAgICAgICAvLyB3ZWVrZGF5cyAtIHN0YW5kYWxvbmUKICAgICAgICAgICAgY2FzZSAiYyI6CiAgICAgICAgICAgICAgLy8gbGlrZSAxCiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0LndlZWtkYXkpOwogICAgICAgICAgICBjYXNlICJjY2MiOgogICAgICAgICAgICAgIC8vIGxpa2UgJ1R1ZXMnCiAgICAgICAgICAgICAgcmV0dXJuIHdlZWtkYXkoInNob3J0IiwgdHJ1ZSk7CiAgICAgICAgICAgIGNhc2UgImNjY2MiOgogICAgICAgICAgICAgIC8vIGxpa2UgJ1R1ZXNkYXknCiAgICAgICAgICAgICAgcmV0dXJuIHdlZWtkYXkoImxvbmciLCB0cnVlKTsKICAgICAgICAgICAgY2FzZSAiY2NjY2MiOgogICAgICAgICAgICAgIC8vIGxpa2UgJ1QnCiAgICAgICAgICAgICAgcmV0dXJuIHdlZWtkYXkoIm5hcnJvdyIsIHRydWUpOwogICAgICAgICAgICAvLyB3ZWVrZGF5cyAtIGZvcm1hdAogICAgICAgICAgICBjYXNlICJFIjoKICAgICAgICAgICAgICAvLyBsaWtlIDEKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oZHQud2Vla2RheSk7CiAgICAgICAgICAgIGNhc2UgIkVFRSI6CiAgICAgICAgICAgICAgLy8gbGlrZSAnVHVlcycKICAgICAgICAgICAgICByZXR1cm4gd2Vla2RheSgic2hvcnQiLCBmYWxzZSk7CiAgICAgICAgICAgIGNhc2UgIkVFRUUiOgogICAgICAgICAgICAgIC8vIGxpa2UgJ1R1ZXNkYXknCiAgICAgICAgICAgICAgcmV0dXJuIHdlZWtkYXkoImxvbmciLCBmYWxzZSk7CiAgICAgICAgICAgIGNhc2UgIkVFRUVFIjoKICAgICAgICAgICAgICAvLyBsaWtlICdUJwogICAgICAgICAgICAgIHJldHVybiB3ZWVrZGF5KCJuYXJyb3ciLCBmYWxzZSk7CiAgICAgICAgICAgIC8vIG1vbnRocyAtIHN0YW5kYWxvbmUKICAgICAgICAgICAgY2FzZSAiTCI6CiAgICAgICAgICAgICAgLy8gbGlrZSAxCiAgICAgICAgICAgICAgcmV0dXJuIHVzZURhdGVUaW1lRm9ybWF0dGVyCiAgICAgICAgICAgICAgICA/IHN0cmluZyh7IG1vbnRoOiAibnVtZXJpYyIsIGRheTogIm51bWVyaWMiIH0sICJtb250aCIpCiAgICAgICAgICAgICAgICA6IHRoaXMubnVtKGR0Lm1vbnRoKTsKICAgICAgICAgICAgY2FzZSAiTEwiOgogICAgICAgICAgICAgIC8vIGxpa2UgMDEsIGRvZXNuJ3Qgc2VlbSB0byB3b3JrCiAgICAgICAgICAgICAgcmV0dXJuIHVzZURhdGVUaW1lRm9ybWF0dGVyCiAgICAgICAgICAgICAgICA/IHN0cmluZyh7IG1vbnRoOiAiMi1kaWdpdCIsIGRheTogIm51bWVyaWMiIH0sICJtb250aCIpCiAgICAgICAgICAgICAgICA6IHRoaXMubnVtKGR0Lm1vbnRoLCAyKTsKICAgICAgICAgICAgY2FzZSAiTExMIjoKICAgICAgICAgICAgICAvLyBsaWtlIEphbgogICAgICAgICAgICAgIHJldHVybiBtb250aCgic2hvcnQiLCB0cnVlKTsKICAgICAgICAgICAgY2FzZSAiTExMTCI6CiAgICAgICAgICAgICAgLy8gbGlrZSBKYW51YXJ5CiAgICAgICAgICAgICAgcmV0dXJuIG1vbnRoKCJsb25nIiwgdHJ1ZSk7CiAgICAgICAgICAgIGNhc2UgIkxMTExMIjoKICAgICAgICAgICAgICAvLyBsaWtlIEoKICAgICAgICAgICAgICByZXR1cm4gbW9udGgoIm5hcnJvdyIsIHRydWUpOwogICAgICAgICAgICAvLyBtb250aHMgLSBmb3JtYXQKICAgICAgICAgICAgY2FzZSAiTSI6CiAgICAgICAgICAgICAgLy8gbGlrZSAxCiAgICAgICAgICAgICAgcmV0dXJuIHVzZURhdGVUaW1lRm9ybWF0dGVyCiAgICAgICAgICAgICAgICA/IHN0cmluZyh7IG1vbnRoOiAibnVtZXJpYyIgfSwgIm1vbnRoIikKICAgICAgICAgICAgICAgIDogdGhpcy5udW0oZHQubW9udGgpOwogICAgICAgICAgICBjYXNlICJNTSI6CiAgICAgICAgICAgICAgLy8gbGlrZSAwMQogICAgICAgICAgICAgIHJldHVybiB1c2VEYXRlVGltZUZvcm1hdHRlcgogICAgICAgICAgICAgICAgPyBzdHJpbmcoeyBtb250aDogIjItZGlnaXQiIH0sICJtb250aCIpCiAgICAgICAgICAgICAgICA6IHRoaXMubnVtKGR0Lm1vbnRoLCAyKTsKICAgICAgICAgICAgY2FzZSAiTU1NIjoKICAgICAgICAgICAgICAvLyBsaWtlIEphbgogICAgICAgICAgICAgIHJldHVybiBtb250aCgic2hvcnQiLCBmYWxzZSk7CiAgICAgICAgICAgIGNhc2UgIk1NTU0iOgogICAgICAgICAgICAgIC8vIGxpa2UgSmFudWFyeQogICAgICAgICAgICAgIHJldHVybiBtb250aCgibG9uZyIsIGZhbHNlKTsKICAgICAgICAgICAgY2FzZSAiTU1NTU0iOgogICAgICAgICAgICAgIC8vIGxpa2UgSgogICAgICAgICAgICAgIHJldHVybiBtb250aCgibmFycm93IiwgZmFsc2UpOwogICAgICAgICAgICAvLyB5ZWFycwogICAgICAgICAgICBjYXNlICJ5IjoKICAgICAgICAgICAgICAvLyBsaWtlIDIwMTQKICAgICAgICAgICAgICByZXR1cm4gdXNlRGF0ZVRpbWVGb3JtYXR0ZXIgPyBzdHJpbmcoeyB5ZWFyOiAibnVtZXJpYyIgfSwgInllYXIiKSA6IHRoaXMubnVtKGR0LnllYXIpOwogICAgICAgICAgICBjYXNlICJ5eSI6CiAgICAgICAgICAgICAgLy8gbGlrZSAxNAogICAgICAgICAgICAgIHJldHVybiB1c2VEYXRlVGltZUZvcm1hdHRlcgogICAgICAgICAgICAgICAgPyBzdHJpbmcoeyB5ZWFyOiAiMi1kaWdpdCIgfSwgInllYXIiKQogICAgICAgICAgICAgICAgOiB0aGlzLm51bShkdC55ZWFyLnRvU3RyaW5nKCkuc2xpY2UoLTIpLCAyKTsKICAgICAgICAgICAgY2FzZSAieXl5eSI6CiAgICAgICAgICAgICAgLy8gbGlrZSAwMDEyCiAgICAgICAgICAgICAgcmV0dXJuIHVzZURhdGVUaW1lRm9ybWF0dGVyCiAgICAgICAgICAgICAgICA/IHN0cmluZyh7IHllYXI6ICJudW1lcmljIiB9LCAieWVhciIpCiAgICAgICAgICAgICAgICA6IHRoaXMubnVtKGR0LnllYXIsIDQpOwogICAgICAgICAgICBjYXNlICJ5eXl5eXkiOgogICAgICAgICAgICAgIC8vIGxpa2UgMDAwMDEyCiAgICAgICAgICAgICAgcmV0dXJuIHVzZURhdGVUaW1lRm9ybWF0dGVyCiAgICAgICAgICAgICAgICA/IHN0cmluZyh7IHllYXI6ICJudW1lcmljIiB9LCAieWVhciIpCiAgICAgICAgICAgICAgICA6IHRoaXMubnVtKGR0LnllYXIsIDYpOwogICAgICAgICAgICAvLyBlcmFzCiAgICAgICAgICAgIGNhc2UgIkciOgogICAgICAgICAgICAgIC8vIGxpa2UgQUQKICAgICAgICAgICAgICByZXR1cm4gZXJhKCJzaG9ydCIpOwogICAgICAgICAgICBjYXNlICJHRyI6CiAgICAgICAgICAgICAgLy8gbGlrZSBBbm5vIERvbWluaQogICAgICAgICAgICAgIHJldHVybiBlcmEoImxvbmciKTsKICAgICAgICAgICAgY2FzZSAiR0dHR0ciOgogICAgICAgICAgICAgIHJldHVybiBlcmEoIm5hcnJvdyIpOwogICAgICAgICAgICBjYXNlICJrayI6CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0LndlZWtZZWFyLnRvU3RyaW5nKCkuc2xpY2UoLTIpLCAyKTsKICAgICAgICAgICAgY2FzZSAia2trayI6CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0LndlZWtZZWFyLCA0KTsKICAgICAgICAgICAgY2FzZSAiVyI6CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0LndlZWtOdW1iZXIpOwogICAgICAgICAgICBjYXNlICJXVyI6CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0LndlZWtOdW1iZXIsIDIpOwogICAgICAgICAgICBjYXNlICJvIjoKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oZHQub3JkaW5hbCk7CiAgICAgICAgICAgIGNhc2UgIm9vbyI6CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0Lm9yZGluYWwsIDMpOwogICAgICAgICAgICBjYXNlICJxIjoKICAgICAgICAgICAgICAvLyBsaWtlIDEKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oZHQucXVhcnRlcik7CiAgICAgICAgICAgIGNhc2UgInFxIjoKICAgICAgICAgICAgICAvLyBsaWtlIDAxCiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0LnF1YXJ0ZXIsIDIpOwogICAgICAgICAgICBjYXNlICJYIjoKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5udW0oTWF0aC5mbG9vcihkdC50cyAvIDEwMDApKTsKICAgICAgICAgICAgY2FzZSAieCI6CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGR0LnRzKTsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICByZXR1cm4gbWF5YmVNYWNybyh0b2tlbik7CiAgICAgICAgICB9CiAgICAgICAgfTsKCiAgICAgIHJldHVybiBzdHJpbmdpZnlUb2tlbnMoRm9ybWF0dGVyLnBhcnNlRm9ybWF0KGZtdCksIHRva2VuVG9TdHJpbmcpOwogICAgfQoKICAgIGZvcm1hdER1cmF0aW9uRnJvbVN0cmluZyhkdXIsIGZtdCkgewogICAgICBjb25zdCB0b2tlblRvRmllbGQgPSAodG9rZW4pID0+IHsKICAgICAgICAgIHN3aXRjaCAodG9rZW5bMF0pIHsKICAgICAgICAgICAgY2FzZSAiUyI6CiAgICAgICAgICAgICAgcmV0dXJuICJtaWxsaXNlY29uZCI7CiAgICAgICAgICAgIGNhc2UgInMiOgogICAgICAgICAgICAgIHJldHVybiAic2Vjb25kIjsKICAgICAgICAgICAgY2FzZSAibSI6CiAgICAgICAgICAgICAgcmV0dXJuICJtaW51dGUiOwogICAgICAgICAgICBjYXNlICJoIjoKICAgICAgICAgICAgICByZXR1cm4gImhvdXIiOwogICAgICAgICAgICBjYXNlICJkIjoKICAgICAgICAgICAgICByZXR1cm4gImRheSI7CiAgICAgICAgICAgIGNhc2UgInciOgogICAgICAgICAgICAgIHJldHVybiAid2VlayI7CiAgICAgICAgICAgIGNhc2UgIk0iOgogICAgICAgICAgICAgIHJldHVybiAibW9udGgiOwogICAgICAgICAgICBjYXNlICJ5IjoKICAgICAgICAgICAgICByZXR1cm4gInllYXIiOwogICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgdG9rZW5Ub1N0cmluZyA9IChsaWxkdXIpID0+ICh0b2tlbikgPT4gewogICAgICAgICAgY29uc3QgbWFwcGVkID0gdG9rZW5Ub0ZpZWxkKHRva2VuKTsKICAgICAgICAgIGlmIChtYXBwZWQpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMubnVtKGxpbGR1ci5nZXQobWFwcGVkKSwgdG9rZW4ubGVuZ3RoKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJldHVybiB0b2tlbjsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHRva2VucyA9IEZvcm1hdHRlci5wYXJzZUZvcm1hdChmbXQpLAogICAgICAgIHJlYWxUb2tlbnMgPSB0b2tlbnMucmVkdWNlKAogICAgICAgICAgKGZvdW5kLCB7IGxpdGVyYWwsIHZhbCB9KSA9PiAobGl0ZXJhbCA/IGZvdW5kIDogZm91bmQuY29uY2F0KHZhbCkpLAogICAgICAgICAgW10KICAgICAgICApLAogICAgICAgIGNvbGxhcHNlZCA9IGR1ci5zaGlmdFRvKC4uLnJlYWxUb2tlbnMubWFwKHRva2VuVG9GaWVsZCkuZmlsdGVyKCh0KSA9PiB0KSk7CiAgICAgIHJldHVybiBzdHJpbmdpZnlUb2tlbnModG9rZW5zLCB0b2tlblRvU3RyaW5nKGNvbGxhcHNlZCkpOwogICAgfQogIH0KCiAgY2xhc3MgSW52YWxpZCB7CiAgICBjb25zdHJ1Y3RvcihyZWFzb24sIGV4cGxhbmF0aW9uKSB7CiAgICAgIHRoaXMucmVhc29uID0gcmVhc29uOwogICAgICB0aGlzLmV4cGxhbmF0aW9uID0gZXhwbGFuYXRpb247CiAgICB9CgogICAgdG9NZXNzYWdlKCkgewogICAgICBpZiAodGhpcy5leHBsYW5hdGlvbikgewogICAgICAgIHJldHVybiBgJHt0aGlzLnJlYXNvbn06ICR7dGhpcy5leHBsYW5hdGlvbn1gOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiB0aGlzLnJlYXNvbjsKICAgICAgfQogICAgfQogIH0KCiAgLyoKICAgKiBUaGlzIGZpbGUgaGFuZGxlcyBwYXJzaW5nIGZvciB3ZWxsLXNwZWNpZmllZCBmb3JtYXRzLiBIZXJlJ3MgaG93IGl0IHdvcmtzOgogICAqIFR3byB0aGluZ3MgZ28gaW50byBwYXJzaW5nOiBhIHJlZ2V4IHRvIG1hdGNoIHdpdGggYW5kIGFuIGV4dHJhY3RvciB0byB0YWtlIGFwYXJ0IHRoZSBncm91cHMgaW4gdGhlIG1hdGNoLgogICAqIEFuIGV4dHJhY3RvciBpcyBqdXN0IGEgZnVuY3Rpb24gdGhhdCB0YWtlcyBhIHJlZ2V4IG1hdGNoIGFycmF5IGFuZCByZXR1cm5zIGEgeyB5ZWFyOiAuLi4sIG1vbnRoOiAuLi4gfSBvYmplY3QKICAgKiBwYXJzZSgpIGRvZXMgdGhlIHdvcmsgb2YgZXhlY3V0aW5nIHRoZSByZWdleCBhbmQgYXBwbHlpbmcgdGhlIGV4dHJhY3Rvci4gSXQgdGFrZXMgbXVsdGlwbGUgcmVnZXgvZXh0cmFjdG9yIHBhaXJzIHRvIHRyeSBpbiBzZXF1ZW5jZS4KICAgKiBFeHRyYWN0b3JzIGNhbiB0YWtlIGEgImN1cnNvciIgcmVwcmVzZW50aW5nIHRoZSBvZmZzZXQgaW4gdGhlIG1hdGNoIHRvIGxvb2sgYXQuIFRoaXMgbWFrZXMgaXQgZWFzeSB0byBjb21iaW5lIGV4dHJhY3RvcnMuCiAgICogY29tYmluZUV4dHJhY3RvcnMoKSBkb2VzIHRoZSB3b3JrIG9mIGNvbWJpbmluZyB0aGVtLCBrZWVwaW5nIHRyYWNrIG9mIHRoZSBjdXJzb3IgdGhyb3VnaCBtdWx0aXBsZSBleHRyYWN0aW9ucy4KICAgKiBTb21lIGV4dHJhY3Rpb25zIGFyZSBzdXBlciBkdW1iIGFuZCBzaW1wbGVQYXJzZSBhbmQgZnJvbVN0cmluZ3MgaGVscCBEUlkgdGhlbS4KICAgKi8KCiAgY29uc3QgaWFuYVJlZ2V4ID0gL1tBLVphLXpfKy1dezEsMjU2fSg/Ojo/XC9bQS1aYS16MC05XystXXsxLDI1Nn0oPzpcL1tBLVphLXowLTlfKy1dezEsMjU2fSk/KT8vOwoKICBmdW5jdGlvbiBjb21iaW5lUmVnZXhlcyguLi5yZWdleGVzKSB7CiAgICBjb25zdCBmdWxsID0gcmVnZXhlcy5yZWR1Y2UoKGYsIHIpID0+IGYgKyByLnNvdXJjZSwgIiIpOwogICAgcmV0dXJuIFJlZ0V4cChgXiR7ZnVsbH0kYCk7CiAgfQoKICBmdW5jdGlvbiBjb21iaW5lRXh0cmFjdG9ycyguLi5leHRyYWN0b3JzKSB7CiAgICByZXR1cm4gKG0pID0+CiAgICAgIGV4dHJhY3RvcnMKICAgICAgICAucmVkdWNlKAogICAgICAgICAgKFttZXJnZWRWYWxzLCBtZXJnZWRab25lLCBjdXJzb3JdLCBleCkgPT4gewogICAgICAgICAgICBjb25zdCBbdmFsLCB6b25lLCBuZXh0XSA9IGV4KG0sIGN1cnNvcik7CiAgICAgICAgICAgIHJldHVybiBbeyAuLi5tZXJnZWRWYWxzLCAuLi52YWwgfSwgem9uZSB8fCBtZXJnZWRab25lLCBuZXh0XTsKICAgICAgICAgIH0sCiAgICAgICAgICBbe30sIG51bGwsIDFdCiAgICAgICAgKQogICAgICAgIC5zbGljZSgwLCAyKTsKICB9CgogIGZ1bmN0aW9uIHBhcnNlKHMsIC4uLnBhdHRlcm5zKSB7CiAgICBpZiAocyA9PSBudWxsKSB7CiAgICAgIHJldHVybiBbbnVsbCwgbnVsbF07CiAgICB9CgogICAgZm9yIChjb25zdCBbcmVnZXgsIGV4dHJhY3Rvcl0gb2YgcGF0dGVybnMpIHsKICAgICAgY29uc3QgbSA9IHJlZ2V4LmV4ZWMocyk7CiAgICAgIGlmIChtKSB7CiAgICAgICAgcmV0dXJuIGV4dHJhY3RvcihtKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIFtudWxsLCBudWxsXTsKICB9CgogIGZ1bmN0aW9uIHNpbXBsZVBhcnNlKC4uLmtleXMpIHsKICAgIHJldHVybiAobWF0Y2gsIGN1cnNvcikgPT4gewogICAgICBjb25zdCByZXQgPSB7fTsKICAgICAgbGV0IGk7CgogICAgICBmb3IgKGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7IGkrKykgewogICAgICAgIHJldFtrZXlzW2ldXSA9IHBhcnNlSW50ZWdlcihtYXRjaFtjdXJzb3IgKyBpXSk7CiAgICAgIH0KICAgICAgcmV0dXJuIFtyZXQsIG51bGwsIGN1cnNvciArIGldOwogICAgfTsKICB9CgogIC8vIElTTyBhbmQgU1FMIHBhcnNpbmcKICBjb25zdCBvZmZzZXRSZWdleCA9IC8oPzooWil8KFsrLV1cZFxkKSg/Ojo/KFxkXGQpKT8pLzsKICBjb25zdCBpc29FeHRlbmRlZFpvbmUgPSBgKD86JHtvZmZzZXRSZWdleC5zb3VyY2V9Pyg/OlxcWygke2lhbmFSZWdleC5zb3VyY2V9KVxcXSk/KT9gOwogIGNvbnN0IGlzb1RpbWVCYXNlUmVnZXggPSAvKFxkXGQpKD86Oj8oXGRcZCkoPzo6PyhcZFxkKSg/OlsuLF0oXGR7MSwzMH0pKT8pPyk/LzsKICBjb25zdCBpc29UaW1lUmVnZXggPSBSZWdFeHAoYCR7aXNvVGltZUJhc2VSZWdleC5zb3VyY2V9JHtpc29FeHRlbmRlZFpvbmV9YCk7CiAgY29uc3QgaXNvVGltZUV4dGVuc2lvblJlZ2V4ID0gUmVnRXhwKGAoPzpUJHtpc29UaW1lUmVnZXguc291cmNlfSk/YCk7CiAgY29uc3QgaXNvWW1kUmVnZXggPSAvKFsrLV1cZHs2fXxcZHs0fSkoPzotPyhcZFxkKSg/Oi0/KFxkXGQpKT8pPy87CiAgY29uc3QgaXNvV2Vla1JlZ2V4ID0gLyhcZHs0fSktP1coXGRcZCkoPzotPyhcZCkpPy87CiAgY29uc3QgaXNvT3JkaW5hbFJlZ2V4ID0gLyhcZHs0fSktPyhcZHszfSkvOwogIGNvbnN0IGV4dHJhY3RJU09XZWVrRGF0YSA9IHNpbXBsZVBhcnNlKCJ3ZWVrWWVhciIsICJ3ZWVrTnVtYmVyIiwgIndlZWtEYXkiKTsKICBjb25zdCBleHRyYWN0SVNPT3JkaW5hbERhdGEgPSBzaW1wbGVQYXJzZSgieWVhciIsICJvcmRpbmFsIik7CiAgY29uc3Qgc3FsWW1kUmVnZXggPSAvKFxkezR9KS0oXGRcZCktKFxkXGQpLzsgLy8gZHVtYmVkLWRvd24gdmVyc2lvbiBvZiB0aGUgSVNPIG9uZQogIGNvbnN0IHNxbFRpbWVSZWdleCA9IFJlZ0V4cCgKICAgIGAke2lzb1RpbWVCYXNlUmVnZXguc291cmNlfSA/KD86JHtvZmZzZXRSZWdleC5zb3VyY2V9fCgke2lhbmFSZWdleC5zb3VyY2V9KSk/YAogICk7CiAgY29uc3Qgc3FsVGltZUV4dGVuc2lvblJlZ2V4ID0gUmVnRXhwKGAoPzogJHtzcWxUaW1lUmVnZXguc291cmNlfSk/YCk7CgogIGZ1bmN0aW9uIGludChtYXRjaCwgcG9zLCBmYWxsYmFjaykgewogICAgY29uc3QgbSA9IG1hdGNoW3Bvc107CiAgICByZXR1cm4gaXNVbmRlZmluZWQobSkgPyBmYWxsYmFjayA6IHBhcnNlSW50ZWdlcihtKTsKICB9CgogIGZ1bmN0aW9uIGV4dHJhY3RJU09ZbWQobWF0Y2gsIGN1cnNvcikgewogICAgY29uc3QgaXRlbSA9IHsKICAgICAgeWVhcjogaW50KG1hdGNoLCBjdXJzb3IpLAogICAgICBtb250aDogaW50KG1hdGNoLCBjdXJzb3IgKyAxLCAxKSwKICAgICAgZGF5OiBpbnQobWF0Y2gsIGN1cnNvciArIDIsIDEpLAogICAgfTsKCiAgICByZXR1cm4gW2l0ZW0sIG51bGwsIGN1cnNvciArIDNdOwogIH0KCiAgZnVuY3Rpb24gZXh0cmFjdElTT1RpbWUobWF0Y2gsIGN1cnNvcikgewogICAgY29uc3QgaXRlbSA9IHsKICAgICAgaG91cnM6IGludChtYXRjaCwgY3Vyc29yLCAwKSwKICAgICAgbWludXRlczogaW50KG1hdGNoLCBjdXJzb3IgKyAxLCAwKSwKICAgICAgc2Vjb25kczogaW50KG1hdGNoLCBjdXJzb3IgKyAyLCAwKSwKICAgICAgbWlsbGlzZWNvbmRzOiBwYXJzZU1pbGxpcyhtYXRjaFtjdXJzb3IgKyAzXSksCiAgICB9OwoKICAgIHJldHVybiBbaXRlbSwgbnVsbCwgY3Vyc29yICsgNF07CiAgfQoKICBmdW5jdGlvbiBleHRyYWN0SVNPT2Zmc2V0KG1hdGNoLCBjdXJzb3IpIHsKICAgIGNvbnN0IGxvY2FsID0gIW1hdGNoW2N1cnNvcl0gJiYgIW1hdGNoW2N1cnNvciArIDFdLAogICAgICBmdWxsT2Zmc2V0ID0gc2lnbmVkT2Zmc2V0KG1hdGNoW2N1cnNvciArIDFdLCBtYXRjaFtjdXJzb3IgKyAyXSksCiAgICAgIHpvbmUgPSBsb2NhbCA/IG51bGwgOiBGaXhlZE9mZnNldFpvbmUuaW5zdGFuY2UoZnVsbE9mZnNldCk7CiAgICByZXR1cm4gW3t9LCB6b25lLCBjdXJzb3IgKyAzXTsKICB9CgogIGZ1bmN0aW9uIGV4dHJhY3RJQU5BWm9uZShtYXRjaCwgY3Vyc29yKSB7CiAgICBjb25zdCB6b25lID0gbWF0Y2hbY3Vyc29yXSA/IElBTkFab25lLmNyZWF0ZShtYXRjaFtjdXJzb3JdKSA6IG51bGw7CiAgICByZXR1cm4gW3t9LCB6b25lLCBjdXJzb3IgKyAxXTsKICB9CgogIC8vIElTTyB0aW1lIHBhcnNpbmcKCiAgY29uc3QgaXNvVGltZU9ubHkgPSBSZWdFeHAoYF5UPyR7aXNvVGltZUJhc2VSZWdleC5zb3VyY2V9JGApOwoKICAvLyBJU08gZHVyYXRpb24gcGFyc2luZwoKICBjb25zdCBpc29EdXJhdGlvbiA9CiAgICAvXi0/UCg/Oig/OigtP1xkezEsMjB9KD86XC5cZHsxLDIwfSk/KVkpPyg/OigtP1xkezEsMjB9KD86XC5cZHsxLDIwfSk/KU0pPyg/OigtP1xkezEsMjB9KD86XC5cZHsxLDIwfSk/KVcpPyg/OigtP1xkezEsMjB9KD86XC5cZHsxLDIwfSk/KUQpPyg/OlQoPzooLT9cZHsxLDIwfSg/OlwuXGR7MSwyMH0pPylIKT8oPzooLT9cZHsxLDIwfSg/OlwuXGR7MSwyMH0pPylNKT8oPzooLT9cZHsxLDIwfSkoPzpbLixdKC0/XGR7MSwyMH0pKT9TKT8pPykkLzsKCiAgZnVuY3Rpb24gZXh0cmFjdElTT0R1cmF0aW9uKG1hdGNoKSB7CiAgICBjb25zdCBbcywgeWVhclN0ciwgbW9udGhTdHIsIHdlZWtTdHIsIGRheVN0ciwgaG91clN0ciwgbWludXRlU3RyLCBzZWNvbmRTdHIsIG1pbGxpc2Vjb25kc1N0cl0gPQogICAgICBtYXRjaDsKCiAgICBjb25zdCBoYXNOZWdhdGl2ZVByZWZpeCA9IHNbMF0gPT09ICItIjsKICAgIGNvbnN0IG5lZ2F0aXZlU2Vjb25kcyA9IHNlY29uZFN0ciAmJiBzZWNvbmRTdHJbMF0gPT09ICItIjsKCiAgICBjb25zdCBtYXliZU5lZ2F0ZSA9IChudW0sIGZvcmNlID0gZmFsc2UpID0+CiAgICAgIG51bSAhPT0gdW5kZWZpbmVkICYmIChmb3JjZSB8fCAobnVtICYmIGhhc05lZ2F0aXZlUHJlZml4KSkgPyAtbnVtIDogbnVtOwoKICAgIHJldHVybiBbCiAgICAgIHsKICAgICAgICB5ZWFyczogbWF5YmVOZWdhdGUocGFyc2VGbG9hdGluZyh5ZWFyU3RyKSksCiAgICAgICAgbW9udGhzOiBtYXliZU5lZ2F0ZShwYXJzZUZsb2F0aW5nKG1vbnRoU3RyKSksCiAgICAgICAgd2Vla3M6IG1heWJlTmVnYXRlKHBhcnNlRmxvYXRpbmcod2Vla1N0cikpLAogICAgICAgIGRheXM6IG1heWJlTmVnYXRlKHBhcnNlRmxvYXRpbmcoZGF5U3RyKSksCiAgICAgICAgaG91cnM6IG1heWJlTmVnYXRlKHBhcnNlRmxvYXRpbmcoaG91clN0cikpLAogICAgICAgIG1pbnV0ZXM6IG1heWJlTmVnYXRlKHBhcnNlRmxvYXRpbmcobWludXRlU3RyKSksCiAgICAgICAgc2Vjb25kczogbWF5YmVOZWdhdGUocGFyc2VGbG9hdGluZyhzZWNvbmRTdHIpLCBzZWNvbmRTdHIgPT09ICItMCIpLAogICAgICAgIG1pbGxpc2Vjb25kczogbWF5YmVOZWdhdGUocGFyc2VNaWxsaXMobWlsbGlzZWNvbmRzU3RyKSwgbmVnYXRpdmVTZWNvbmRzKSwKICAgICAgfSwKICAgIF07CiAgfQoKICAvLyBUaGVzZSBhcmUgYSBsaXR0bGUgYnJhaW5kZWFkLiBFRFQgKnNob3VsZCogdGVsbCB1cyB0aGF0IHdlJ3JlIGluLCBzYXksIEFtZXJpY2EvTmV3X1lvcmsKICAvLyBhbmQgbm90IGp1c3QgdGhhdCB3ZSdyZSBpbiAtMjQwICpyaWdodCBub3cqLiBCdXQgc2luY2UgSSBkb24ndCB0aGluayB0aGVzZSBhcmUgdXNlZCB0aGF0IG9mdGVuCiAgLy8gSSdtIGp1c3QgZ29pbmcgdG8gaWdub3JlIHRoYXQKICBjb25zdCBvYnNPZmZzZXRzID0gewogICAgR01UOiAwLAogICAgRURUOiAtNCAqIDYwLAogICAgRVNUOiAtNSAqIDYwLAogICAgQ0RUOiAtNSAqIDYwLAogICAgQ1NUOiAtNiAqIDYwLAogICAgTURUOiAtNiAqIDYwLAogICAgTVNUOiAtNyAqIDYwLAogICAgUERUOiAtNyAqIDYwLAogICAgUFNUOiAtOCAqIDYwLAogIH07CgogIGZ1bmN0aW9uIGZyb21TdHJpbmdzKHdlZWtkYXlTdHIsIHllYXJTdHIsIG1vbnRoU3RyLCBkYXlTdHIsIGhvdXJTdHIsIG1pbnV0ZVN0ciwgc2Vjb25kU3RyKSB7CiAgICBjb25zdCByZXN1bHQgPSB7CiAgICAgIHllYXI6IHllYXJTdHIubGVuZ3RoID09PSAyID8gdW50cnVuY2F0ZVllYXIocGFyc2VJbnRlZ2VyKHllYXJTdHIpKSA6IHBhcnNlSW50ZWdlcih5ZWFyU3RyKSwKICAgICAgbW9udGg6IG1vbnRoc1Nob3J0LmluZGV4T2YobW9udGhTdHIpICsgMSwKICAgICAgZGF5OiBwYXJzZUludGVnZXIoZGF5U3RyKSwKICAgICAgaG91cjogcGFyc2VJbnRlZ2VyKGhvdXJTdHIpLAogICAgICBtaW51dGU6IHBhcnNlSW50ZWdlcihtaW51dGVTdHIpLAogICAgfTsKCiAgICBpZiAoc2Vjb25kU3RyKSByZXN1bHQuc2Vjb25kID0gcGFyc2VJbnRlZ2VyKHNlY29uZFN0cik7CiAgICBpZiAod2Vla2RheVN0cikgewogICAgICByZXN1bHQud2Vla2RheSA9CiAgICAgICAgd2Vla2RheVN0ci5sZW5ndGggPiAzCiAgICAgICAgICA/IHdlZWtkYXlzTG9uZy5pbmRleE9mKHdlZWtkYXlTdHIpICsgMQogICAgICAgICAgOiB3ZWVrZGF5c1Nob3J0LmluZGV4T2Yod2Vla2RheVN0cikgKyAxOwogICAgfQoKICAgIHJldHVybiByZXN1bHQ7CiAgfQoKICAvLyBSRkMgMjgyMi81MzIyCiAgY29uc3QgcmZjMjgyMiA9CiAgICAvXig/OihNb258VHVlfFdlZHxUaHV8RnJpfFNhdHxTdW4pLFxzKT8oXGR7MSwyfSlccyhKYW58RmVifE1hcnxBcHJ8TWF5fEp1bnxKdWx8QXVnfFNlcHxPY3R8Tm92fERlYylccyhcZHsyLDR9KVxzKFxkXGQpOihcZFxkKSg/OjooXGRcZCkpP1xzKD86KFVUfEdNVHxbRUNNUF1bU0RdVCl8KFtael0pfCg/OihbKy1dXGRcZCkoXGRcZCkpKSQvOwoKICBmdW5jdGlvbiBleHRyYWN0UkZDMjgyMihtYXRjaCkgewogICAgY29uc3QgWwogICAgICAgICwKICAgICAgICB3ZWVrZGF5U3RyLAogICAgICAgIGRheVN0ciwKICAgICAgICBtb250aFN0ciwKICAgICAgICB5ZWFyU3RyLAogICAgICAgIGhvdXJTdHIsCiAgICAgICAgbWludXRlU3RyLAogICAgICAgIHNlY29uZFN0ciwKICAgICAgICBvYnNPZmZzZXQsCiAgICAgICAgbWlsT2Zmc2V0LAogICAgICAgIG9mZkhvdXJTdHIsCiAgICAgICAgb2ZmTWludXRlU3RyLAogICAgICBdID0gbWF0Y2gsCiAgICAgIHJlc3VsdCA9IGZyb21TdHJpbmdzKHdlZWtkYXlTdHIsIHllYXJTdHIsIG1vbnRoU3RyLCBkYXlTdHIsIGhvdXJTdHIsIG1pbnV0ZVN0ciwgc2Vjb25kU3RyKTsKCiAgICBsZXQgb2Zmc2V0OwogICAgaWYgKG9ic09mZnNldCkgewogICAgICBvZmZzZXQgPSBvYnNPZmZzZXRzW29ic09mZnNldF07CiAgICB9IGVsc2UgaWYgKG1pbE9mZnNldCkgewogICAgICBvZmZzZXQgPSAwOwogICAgfSBlbHNlIHsKICAgICAgb2Zmc2V0ID0gc2lnbmVkT2Zmc2V0KG9mZkhvdXJTdHIsIG9mZk1pbnV0ZVN0cik7CiAgICB9CgogICAgcmV0dXJuIFtyZXN1bHQsIG5ldyBGaXhlZE9mZnNldFpvbmUob2Zmc2V0KV07CiAgfQoKICBmdW5jdGlvbiBwcmVwcm9jZXNzUkZDMjgyMihzKSB7CiAgICAvLyBSZW1vdmUgY29tbWVudHMgYW5kIGZvbGRpbmcgd2hpdGVzcGFjZSBhbmQgcmVwbGFjZSBtdWx0aXBsZS1zcGFjZXMgd2l0aCBhIHNpbmdsZSBzcGFjZQogICAgcmV0dXJuIHMKICAgICAgLnJlcGxhY2UoL1woW14oKV0qXCl8W1xuXHRdL2csICIgIikKICAgICAgLnJlcGxhY2UoLyhcc1xzKykvZywgIiAiKQogICAgICAudHJpbSgpOwogIH0KCiAgLy8gaHR0cCBkYXRlCgogIGNvbnN0IHJmYzExMjMgPQogICAgICAvXihNb258VHVlfFdlZHxUaHV8RnJpfFNhdHxTdW4pLCAoXGRcZCkgKEphbnxGZWJ8TWFyfEFwcnxNYXl8SnVufEp1bHxBdWd8U2VwfE9jdHxOb3Z8RGVjKSAoXGR7NH0pIChcZFxkKTooXGRcZCk6KFxkXGQpIEdNVCQvLAogICAgcmZjODUwID0KICAgICAgL14oTW9uZGF5fFR1ZXNkYXl8V2VkbmVzZGF5fFRodXJzZGF5fEZyaWRheXxTYXR1cmRheXxTdW5kYXkpLCAoXGRcZCktKEphbnxGZWJ8TWFyfEFwcnxNYXl8SnVufEp1bHxBdWd8U2VwfE9jdHxOb3Z8RGVjKS0oXGRcZCkgKFxkXGQpOihcZFxkKTooXGRcZCkgR01UJC8sCiAgICBhc2NpaSA9CiAgICAgIC9eKE1vbnxUdWV8V2VkfFRodXxGcml8U2F0fFN1bikgKEphbnxGZWJ8TWFyfEFwcnxNYXl8SnVufEp1bHxBdWd8U2VwfE9jdHxOb3Z8RGVjKSAoIFxkfFxkXGQpIChcZFxkKTooXGRcZCk6KFxkXGQpIChcZHs0fSkkLzsKCiAgZnVuY3Rpb24gZXh0cmFjdFJGQzExMjNPcjg1MChtYXRjaCkgewogICAgY29uc3QgWywgd2Vla2RheVN0ciwgZGF5U3RyLCBtb250aFN0ciwgeWVhclN0ciwgaG91clN0ciwgbWludXRlU3RyLCBzZWNvbmRTdHJdID0gbWF0Y2gsCiAgICAgIHJlc3VsdCA9IGZyb21TdHJpbmdzKHdlZWtkYXlTdHIsIHllYXJTdHIsIG1vbnRoU3RyLCBkYXlTdHIsIGhvdXJTdHIsIG1pbnV0ZVN0ciwgc2Vjb25kU3RyKTsKICAgIHJldHVybiBbcmVzdWx0LCBGaXhlZE9mZnNldFpvbmUudXRjSW5zdGFuY2VdOwogIH0KCiAgZnVuY3Rpb24gZXh0cmFjdEFTQ0lJKG1hdGNoKSB7CiAgICBjb25zdCBbLCB3ZWVrZGF5U3RyLCBtb250aFN0ciwgZGF5U3RyLCBob3VyU3RyLCBtaW51dGVTdHIsIHNlY29uZFN0ciwgeWVhclN0cl0gPSBtYXRjaCwKICAgICAgcmVzdWx0ID0gZnJvbVN0cmluZ3Mod2Vla2RheVN0ciwgeWVhclN0ciwgbW9udGhTdHIsIGRheVN0ciwgaG91clN0ciwgbWludXRlU3RyLCBzZWNvbmRTdHIpOwogICAgcmV0dXJuIFtyZXN1bHQsIEZpeGVkT2Zmc2V0Wm9uZS51dGNJbnN0YW5jZV07CiAgfQoKICBjb25zdCBpc29ZbWRXaXRoVGltZUV4dGVuc2lvblJlZ2V4ID0gY29tYmluZVJlZ2V4ZXMoaXNvWW1kUmVnZXgsIGlzb1RpbWVFeHRlbnNpb25SZWdleCk7CiAgY29uc3QgaXNvV2Vla1dpdGhUaW1lRXh0ZW5zaW9uUmVnZXggPSBjb21iaW5lUmVnZXhlcyhpc29XZWVrUmVnZXgsIGlzb1RpbWVFeHRlbnNpb25SZWdleCk7CiAgY29uc3QgaXNvT3JkaW5hbFdpdGhUaW1lRXh0ZW5zaW9uUmVnZXggPSBjb21iaW5lUmVnZXhlcyhpc29PcmRpbmFsUmVnZXgsIGlzb1RpbWVFeHRlbnNpb25SZWdleCk7CiAgY29uc3QgaXNvVGltZUNvbWJpbmVkUmVnZXggPSBjb21iaW5lUmVnZXhlcyhpc29UaW1lUmVnZXgpOwoKICBjb25zdCBleHRyYWN0SVNPWW1kVGltZUFuZE9mZnNldCA9IGNvbWJpbmVFeHRyYWN0b3JzKAogICAgZXh0cmFjdElTT1ltZCwKICAgIGV4dHJhY3RJU09UaW1lLAogICAgZXh0cmFjdElTT09mZnNldCwKICAgIGV4dHJhY3RJQU5BWm9uZQogICk7CiAgY29uc3QgZXh0cmFjdElTT1dlZWtUaW1lQW5kT2Zmc2V0ID0gY29tYmluZUV4dHJhY3RvcnMoCiAgICBleHRyYWN0SVNPV2Vla0RhdGEsCiAgICBleHRyYWN0SVNPVGltZSwKICAgIGV4dHJhY3RJU09PZmZzZXQsCiAgICBleHRyYWN0SUFOQVpvbmUKICApOwogIGNvbnN0IGV4dHJhY3RJU09PcmRpbmFsRGF0ZUFuZFRpbWUgPSBjb21iaW5lRXh0cmFjdG9ycygKICAgIGV4dHJhY3RJU09PcmRpbmFsRGF0YSwKICAgIGV4dHJhY3RJU09UaW1lLAogICAgZXh0cmFjdElTT09mZnNldCwKICAgIGV4dHJhY3RJQU5BWm9uZQogICk7CiAgY29uc3QgZXh0cmFjdElTT1RpbWVBbmRPZmZzZXQgPSBjb21iaW5lRXh0cmFjdG9ycygKICAgIGV4dHJhY3RJU09UaW1lLAogICAgZXh0cmFjdElTT09mZnNldCwKICAgIGV4dHJhY3RJQU5BWm9uZQogICk7CgogIC8qCiAgICogQHByaXZhdGUKICAgKi8KCiAgZnVuY3Rpb24gcGFyc2VJU09EYXRlKHMpIHsKICAgIHJldHVybiBwYXJzZSgKICAgICAgcywKICAgICAgW2lzb1ltZFdpdGhUaW1lRXh0ZW5zaW9uUmVnZXgsIGV4dHJhY3RJU09ZbWRUaW1lQW5kT2Zmc2V0XSwKICAgICAgW2lzb1dlZWtXaXRoVGltZUV4dGVuc2lvblJlZ2V4LCBleHRyYWN0SVNPV2Vla1RpbWVBbmRPZmZzZXRdLAogICAgICBbaXNvT3JkaW5hbFdpdGhUaW1lRXh0ZW5zaW9uUmVnZXgsIGV4dHJhY3RJU09PcmRpbmFsRGF0ZUFuZFRpbWVdLAogICAgICBbaXNvVGltZUNvbWJpbmVkUmVnZXgsIGV4dHJhY3RJU09UaW1lQW5kT2Zmc2V0XQogICAgKTsKICB9CgogIGZ1bmN0aW9uIHBhcnNlUkZDMjgyMkRhdGUocykgewogICAgcmV0dXJuIHBhcnNlKHByZXByb2Nlc3NSRkMyODIyKHMpLCBbcmZjMjgyMiwgZXh0cmFjdFJGQzI4MjJdKTsKICB9CgogIGZ1bmN0aW9uIHBhcnNlSFRUUERhdGUocykgewogICAgcmV0dXJuIHBhcnNlKAogICAgICBzLAogICAgICBbcmZjMTEyMywgZXh0cmFjdFJGQzExMjNPcjg1MF0sCiAgICAgIFtyZmM4NTAsIGV4dHJhY3RSRkMxMTIzT3I4NTBdLAogICAgICBbYXNjaWksIGV4dHJhY3RBU0NJSV0KICAgICk7CiAgfQoKICBmdW5jdGlvbiBwYXJzZUlTT0R1cmF0aW9uKHMpIHsKICAgIHJldHVybiBwYXJzZShzLCBbaXNvRHVyYXRpb24sIGV4dHJhY3RJU09EdXJhdGlvbl0pOwogIH0KCiAgY29uc3QgZXh0cmFjdElTT1RpbWVPbmx5ID0gY29tYmluZUV4dHJhY3RvcnMoZXh0cmFjdElTT1RpbWUpOwoKICBmdW5jdGlvbiBwYXJzZUlTT1RpbWVPbmx5KHMpIHsKICAgIHJldHVybiBwYXJzZShzLCBbaXNvVGltZU9ubHksIGV4dHJhY3RJU09UaW1lT25seV0pOwogIH0KCiAgY29uc3Qgc3FsWW1kV2l0aFRpbWVFeHRlbnNpb25SZWdleCA9IGNvbWJpbmVSZWdleGVzKHNxbFltZFJlZ2V4LCBzcWxUaW1lRXh0ZW5zaW9uUmVnZXgpOwogIGNvbnN0IHNxbFRpbWVDb21iaW5lZFJlZ2V4ID0gY29tYmluZVJlZ2V4ZXMoc3FsVGltZVJlZ2V4KTsKCiAgY29uc3QgZXh0cmFjdElTT1RpbWVPZmZzZXRBbmRJQU5BWm9uZSA9IGNvbWJpbmVFeHRyYWN0b3JzKAogICAgZXh0cmFjdElTT1RpbWUsCiAgICBleHRyYWN0SVNPT2Zmc2V0LAogICAgZXh0cmFjdElBTkFab25lCiAgKTsKCiAgZnVuY3Rpb24gcGFyc2VTUUwocykgewogICAgcmV0dXJuIHBhcnNlKAogICAgICBzLAogICAgICBbc3FsWW1kV2l0aFRpbWVFeHRlbnNpb25SZWdleCwgZXh0cmFjdElTT1ltZFRpbWVBbmRPZmZzZXRdLAogICAgICBbc3FsVGltZUNvbWJpbmVkUmVnZXgsIGV4dHJhY3RJU09UaW1lT2Zmc2V0QW5kSUFOQVpvbmVdCiAgICApOwogIH0KCiAgY29uc3QgSU5WQUxJRCQyID0gIkludmFsaWQgRHVyYXRpb24iOwoKICAvLyB1bml0IGNvbnZlcnNpb24gY29uc3RhbnRzCiAgY29uc3QgbG93T3JkZXJNYXRyaXggPSB7CiAgICAgIHdlZWtzOiB7CiAgICAgICAgZGF5czogNywKICAgICAgICBob3VyczogNyAqIDI0LAogICAgICAgIG1pbnV0ZXM6IDcgKiAyNCAqIDYwLAogICAgICAgIHNlY29uZHM6IDcgKiAyNCAqIDYwICogNjAsCiAgICAgICAgbWlsbGlzZWNvbmRzOiA3ICogMjQgKiA2MCAqIDYwICogMTAwMCwKICAgICAgfSwKICAgICAgZGF5czogewogICAgICAgIGhvdXJzOiAyNCwKICAgICAgICBtaW51dGVzOiAyNCAqIDYwLAogICAgICAgIHNlY29uZHM6IDI0ICogNjAgKiA2MCwKICAgICAgICBtaWxsaXNlY29uZHM6IDI0ICogNjAgKiA2MCAqIDEwMDAsCiAgICAgIH0sCiAgICAgIGhvdXJzOiB7IG1pbnV0ZXM6IDYwLCBzZWNvbmRzOiA2MCAqIDYwLCBtaWxsaXNlY29uZHM6IDYwICogNjAgKiAxMDAwIH0sCiAgICAgIG1pbnV0ZXM6IHsgc2Vjb25kczogNjAsIG1pbGxpc2Vjb25kczogNjAgKiAxMDAwIH0sCiAgICAgIHNlY29uZHM6IHsgbWlsbGlzZWNvbmRzOiAxMDAwIH0sCiAgICB9LAogICAgY2FzdWFsTWF0cml4ID0gewogICAgICB5ZWFyczogewogICAgICAgIHF1YXJ0ZXJzOiA0LAogICAgICAgIG1vbnRoczogMTIsCiAgICAgICAgd2Vla3M6IDUyLAogICAgICAgIGRheXM6IDM2NSwKICAgICAgICBob3VyczogMzY1ICogMjQsCiAgICAgICAgbWludXRlczogMzY1ICogMjQgKiA2MCwKICAgICAgICBzZWNvbmRzOiAzNjUgKiAyNCAqIDYwICogNjAsCiAgICAgICAgbWlsbGlzZWNvbmRzOiAzNjUgKiAyNCAqIDYwICogNjAgKiAxMDAwLAogICAgICB9LAogICAgICBxdWFydGVyczogewogICAgICAgIG1vbnRoczogMywKICAgICAgICB3ZWVrczogMTMsCiAgICAgICAgZGF5czogOTEsCiAgICAgICAgaG91cnM6IDkxICogMjQsCiAgICAgICAgbWludXRlczogOTEgKiAyNCAqIDYwLAogICAgICAgIHNlY29uZHM6IDkxICogMjQgKiA2MCAqIDYwLAogICAgICAgIG1pbGxpc2Vjb25kczogOTEgKiAyNCAqIDYwICogNjAgKiAxMDAwLAogICAgICB9LAogICAgICBtb250aHM6IHsKICAgICAgICB3ZWVrczogNCwKICAgICAgICBkYXlzOiAzMCwKICAgICAgICBob3VyczogMzAgKiAyNCwKICAgICAgICBtaW51dGVzOiAzMCAqIDI0ICogNjAsCiAgICAgICAgc2Vjb25kczogMzAgKiAyNCAqIDYwICogNjAsCiAgICAgICAgbWlsbGlzZWNvbmRzOiAzMCAqIDI0ICogNjAgKiA2MCAqIDEwMDAsCiAgICAgIH0sCgogICAgICAuLi5sb3dPcmRlck1hdHJpeCwKICAgIH0sCiAgICBkYXlzSW5ZZWFyQWNjdXJhdGUgPSAxNDYwOTcuMCAvIDQwMCwKICAgIGRheXNJbk1vbnRoQWNjdXJhdGUgPSAxNDYwOTcuMCAvIDQ4MDAsCiAgICBhY2N1cmF0ZU1hdHJpeCA9IHsKICAgICAgeWVhcnM6IHsKICAgICAgICBxdWFydGVyczogNCwKICAgICAgICBtb250aHM6IDEyLAogICAgICAgIHdlZWtzOiBkYXlzSW5ZZWFyQWNjdXJhdGUgLyA3LAogICAgICAgIGRheXM6IGRheXNJblllYXJBY2N1cmF0ZSwKICAgICAgICBob3VyczogZGF5c0luWWVhckFjY3VyYXRlICogMjQsCiAgICAgICAgbWludXRlczogZGF5c0luWWVhckFjY3VyYXRlICogMjQgKiA2MCwKICAgICAgICBzZWNvbmRzOiBkYXlzSW5ZZWFyQWNjdXJhdGUgKiAyNCAqIDYwICogNjAsCiAgICAgICAgbWlsbGlzZWNvbmRzOiBkYXlzSW5ZZWFyQWNjdXJhdGUgKiAyNCAqIDYwICogNjAgKiAxMDAwLAogICAgICB9LAogICAgICBxdWFydGVyczogewogICAgICAgIG1vbnRoczogMywKICAgICAgICB3ZWVrczogZGF5c0luWWVhckFjY3VyYXRlIC8gMjgsCiAgICAgICAgZGF5czogZGF5c0luWWVhckFjY3VyYXRlIC8gNCwKICAgICAgICBob3VyczogKGRheXNJblllYXJBY2N1cmF0ZSAqIDI0KSAvIDQsCiAgICAgICAgbWludXRlczogKGRheXNJblllYXJBY2N1cmF0ZSAqIDI0ICogNjApIC8gNCwKICAgICAgICBzZWNvbmRzOiAoZGF5c0luWWVhckFjY3VyYXRlICogMjQgKiA2MCAqIDYwKSAvIDQsCiAgICAgICAgbWlsbGlzZWNvbmRzOiAoZGF5c0luWWVhckFjY3VyYXRlICogMjQgKiA2MCAqIDYwICogMTAwMCkgLyA0LAogICAgICB9LAogICAgICBtb250aHM6IHsKICAgICAgICB3ZWVrczogZGF5c0luTW9udGhBY2N1cmF0ZSAvIDcsCiAgICAgICAgZGF5czogZGF5c0luTW9udGhBY2N1cmF0ZSwKICAgICAgICBob3VyczogZGF5c0luTW9udGhBY2N1cmF0ZSAqIDI0LAogICAgICAgIG1pbnV0ZXM6IGRheXNJbk1vbnRoQWNjdXJhdGUgKiAyNCAqIDYwLAogICAgICAgIHNlY29uZHM6IGRheXNJbk1vbnRoQWNjdXJhdGUgKiAyNCAqIDYwICogNjAsCiAgICAgICAgbWlsbGlzZWNvbmRzOiBkYXlzSW5Nb250aEFjY3VyYXRlICogMjQgKiA2MCAqIDYwICogMTAwMCwKICAgICAgfSwKICAgICAgLi4ubG93T3JkZXJNYXRyaXgsCiAgICB9OwoKICAvLyB1bml0cyBvcmRlcmVkIGJ5IHNpemUKICBjb25zdCBvcmRlcmVkVW5pdHMkMSA9IFsKICAgICJ5ZWFycyIsCiAgICAicXVhcnRlcnMiLAogICAgIm1vbnRocyIsCiAgICAid2Vla3MiLAogICAgImRheXMiLAogICAgImhvdXJzIiwKICAgICJtaW51dGVzIiwKICAgICJzZWNvbmRzIiwKICAgICJtaWxsaXNlY29uZHMiLAogIF07CgogIGNvbnN0IHJldmVyc2VVbml0cyA9IG9yZGVyZWRVbml0cyQxLnNsaWNlKDApLnJldmVyc2UoKTsKCiAgLy8gY2xvbmUgcmVhbGx5IG1lYW5zICJjcmVhdGUgYW5vdGhlciBpbnN0YW5jZSBqdXN0IGxpa2UgdGhpcyBvbmUsIGJ1dCB3aXRoIHRoZXNlIGNoYW5nZXMiCiAgZnVuY3Rpb24gY2xvbmUkMShkdXIsIGFsdHMsIGNsZWFyID0gZmFsc2UpIHsKICAgIC8vIGRlZXAgbWVyZ2UgZm9yIHZhbHMKICAgIGNvbnN0IGNvbmYgPSB7CiAgICAgIHZhbHVlczogY2xlYXIgPyBhbHRzLnZhbHVlcyA6IHsgLi4uZHVyLnZhbHVlcywgLi4uKGFsdHMudmFsdWVzIHx8IHt9KSB9LAogICAgICBsb2M6IGR1ci5sb2MuY2xvbmUoYWx0cy5sb2MpLAogICAgICBjb252ZXJzaW9uQWNjdXJhY3k6IGFsdHMuY29udmVyc2lvbkFjY3VyYWN5IHx8IGR1ci5jb252ZXJzaW9uQWNjdXJhY3ksCiAgICAgIG1hdHJpeDogYWx0cy5tYXRyaXggfHwgZHVyLm1hdHJpeCwKICAgIH07CiAgICByZXR1cm4gbmV3IER1cmF0aW9uKGNvbmYpOwogIH0KCiAgZnVuY3Rpb24gZHVyYXRpb25Ub01pbGxpcyhtYXRyaXgsIHZhbHMpIHsKICAgIGxldCBzdW0gPSB2YWxzLm1pbGxpc2Vjb25kcyA/PyAwOwogICAgZm9yIChjb25zdCB1bml0IG9mIHJldmVyc2VVbml0cy5zbGljZSgxKSkgewogICAgICBpZiAodmFsc1t1bml0XSkgewogICAgICAgIHN1bSArPSB2YWxzW3VuaXRdICogbWF0cml4W3VuaXRdWyJtaWxsaXNlY29uZHMiXTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHN1bTsKICB9CgogIC8vIE5COiBtdXRhdGVzIHBhcmFtZXRlcnMKICBmdW5jdGlvbiBub3JtYWxpemVWYWx1ZXMobWF0cml4LCB2YWxzKSB7CiAgICAvLyB0aGUgbG9naWMgYmVsb3cgYXNzdW1lcyB0aGUgb3ZlcmFsbCB2YWx1ZSBvZiB0aGUgZHVyYXRpb24gaXMgcG9zaXRpdmUKICAgIC8vIGlmIHRoaXMgaXMgbm90IHRoZSBjYXNlLCBmYWN0b3IgaXMgdXNlZCB0byBtYWtlIGl0IHNvCiAgICBjb25zdCBmYWN0b3IgPSBkdXJhdGlvblRvTWlsbGlzKG1hdHJpeCwgdmFscykgPCAwID8gLTEgOiAxOwoKICAgIG9yZGVyZWRVbml0cyQxLnJlZHVjZVJpZ2h0KChwcmV2aW91cywgY3VycmVudCkgPT4gewogICAgICBpZiAoIWlzVW5kZWZpbmVkKHZhbHNbY3VycmVudF0pKSB7CiAgICAgICAgaWYgKHByZXZpb3VzKSB7CiAgICAgICAgICBjb25zdCBwcmV2aW91c1ZhbCA9IHZhbHNbcHJldmlvdXNdICogZmFjdG9yOwogICAgICAgICAgY29uc3QgY29udiA9IG1hdHJpeFtjdXJyZW50XVtwcmV2aW91c107CgogICAgICAgICAgLy8gaWYgKHByZXZpb3VzVmFsIDwgMCk6CiAgICAgICAgICAvLyBsb3dlciBvcmRlciB1bml0IGlzIG5lZ2F0aXZlIChlLmcuIHsgeWVhcnM6IDIsIGRheXM6IC0yIH0pCiAgICAgICAgICAvLyBub3JtYWxpemUgdGhpcyBieSByZWR1Y2luZyB0aGUgaGlnaGVyIG9yZGVyIHVuaXQgYnkgdGhlIGFwcHJvcHJpYXRlIGFtb3VudAogICAgICAgICAgLy8gYW5kIGluY3JlYXNpbmcgdGhlIGxvd2VyIG9yZGVyIHVuaXQKICAgICAgICAgIC8vIHRoaXMgY2FuIG5ldmVyIG1ha2UgdGhlIGhpZ2hlciBvcmRlciB1bml0IG5lZ2F0aXZlLCBiZWNhdXNlIHRoaXMgZnVuY3Rpb24gb25seSBvcGVyYXRlcwogICAgICAgICAgLy8gb24gcG9zaXRpdmUgZHVyYXRpb25zLCBzbyB0aGUgYW1vdW50IG9mIHRpbWUgcmVwcmVzZW50ZWQgYnkgdGhlIGxvd2VyIG9yZGVyIHVuaXQgY2Fubm90CiAgICAgICAgICAvLyBiZSBsYXJnZXIgdGhhbiB0aGUgaGlnaGVyIG9yZGVyIHVuaXQKICAgICAgICAgIC8vIGVsc2U6CiAgICAgICAgICAvLyBsb3dlciBvcmRlciB1bml0IGlzIHBvc2l0aXZlIChlLmcuIHsgeWVhcnM6IDIsIGRheXM6IDQ1MCB9IG9yIHsgeWVhcnM6IC0yLCBkYXlzOiA0NTAgfSkKICAgICAgICAgIC8vIGluIHRoaXMgY2FzZSB3ZSBhdHRlbXB0IHRvIGNvbnZlcnQgYXMgbXVjaCBhcyBwb3NzaWJsZSBmcm9tIHRoZSBsb3dlciBvcmRlciB1bml0IGludG8KICAgICAgICAgIC8vIHRoZSBoaWdoZXIgb3JkZXIgb25lCiAgICAgICAgICAvLwogICAgICAgICAgLy8gTWF0aC5mbG9vciB0YWtlcyBjYXJlIG9mIGJvdGggb2YgdGhlc2UgY2FzZXMsIHJvdW5kaW5nIGF3YXkgZnJvbSAwCiAgICAgICAgICAvLyBpZiBwcmV2aW91c1ZhbCA8IDAgaXQgbWFrZXMgdGhlIGFic29sdXRlIHZhbHVlIGxhcmdlcgogICAgICAgICAgLy8gaWYgcHJldmlvdXNWYWwgPj0gaXQgbWFrZXMgdGhlIGFic29sdXRlIHZhbHVlIHNtYWxsZXIKICAgICAgICAgIGNvbnN0IHJvbGxVcCA9IE1hdGguZmxvb3IocHJldmlvdXNWYWwgLyBjb252KTsKICAgICAgICAgIHZhbHNbY3VycmVudF0gKz0gcm9sbFVwICogZmFjdG9yOwogICAgICAgICAgdmFsc1twcmV2aW91c10gLT0gcm9sbFVwICogY29udiAqIGZhY3RvcjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGN1cnJlbnQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHByZXZpb3VzOwogICAgICB9CiAgICB9LCBudWxsKTsKCiAgICAvLyB0cnkgdG8gY29udmVydCBhbnkgZGVjaW1hbHMgaW50byBzbWFsbGVyIHVuaXRzIGlmIHBvc3NpYmxlCiAgICAvLyBmb3IgZXhhbXBsZSBmb3IgeyB5ZWFyczogMi41LCBkYXlzOiAwLCBzZWNvbmRzOiAwIH0gd2Ugd2FudCB0byBnZXQgeyB5ZWFyczogMiwgZGF5czogMTgyLCBob3VyczogMTIgfQogICAgb3JkZXJlZFVuaXRzJDEucmVkdWNlKChwcmV2aW91cywgY3VycmVudCkgPT4gewogICAgICBpZiAoIWlzVW5kZWZpbmVkKHZhbHNbY3VycmVudF0pKSB7CiAgICAgICAgaWYgKHByZXZpb3VzKSB7CiAgICAgICAgICBjb25zdCBmcmFjdGlvbiA9IHZhbHNbcHJldmlvdXNdICUgMTsKICAgICAgICAgIHZhbHNbcHJldmlvdXNdIC09IGZyYWN0aW9uOwogICAgICAgICAgdmFsc1tjdXJyZW50XSArPSBmcmFjdGlvbiAqIG1hdHJpeFtwcmV2aW91c11bY3VycmVudF07CiAgICAgICAgfQogICAgICAgIHJldHVybiBjdXJyZW50OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBwcmV2aW91czsKICAgICAgfQogICAgfSwgbnVsbCk7CiAgfQoKICAvLyBSZW1vdmUgYWxsIHByb3BlcnRpZXMgd2l0aCBhIHZhbHVlIG9mIDAgZnJvbSBhbiBvYmplY3QKICBmdW5jdGlvbiByZW1vdmVaZXJvZXModmFscykgewogICAgY29uc3QgbmV3VmFscyA9IHt9OwogICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXModmFscykpIHsKICAgICAgaWYgKHZhbHVlICE9PSAwKSB7CiAgICAgICAgbmV3VmFsc1trZXldID0gdmFsdWU7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBuZXdWYWxzOwogIH0KCiAgLyoqCiAgICogQSBEdXJhdGlvbiBvYmplY3QgcmVwcmVzZW50cyBhIHBlcmlvZCBvZiB0aW1lLCBsaWtlICIyIG1vbnRocyIgb3IgIjEgZGF5LCAxIGhvdXIiLiBDb25jZXB0dWFsbHksIGl0J3MganVzdCBhIG1hcCBvZiB1bml0cyB0byB0aGVpciBxdWFudGl0aWVzLCBhY2NvbXBhbmllZCBieSBzb21lIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBhbmQgbWV0aG9kcyBmb3IgY3JlYXRpbmcsIHBhcnNpbmcsIGludGVycm9nYXRpbmcsIHRyYW5zZm9ybWluZywgYW5kIGZvcm1hdHRpbmcgdGhlbS4gVGhleSBjYW4gYmUgdXNlZCBvbiB0aGVpciBvd24gb3IgaW4gY29uanVuY3Rpb24gd2l0aCBvdGhlciBMdXhvbiB0eXBlczsgZm9yIGV4YW1wbGUsIHlvdSBjYW4gdXNlIHtAbGluayBEYXRlVGltZSNwbHVzfSB0byBhZGQgYSBEdXJhdGlvbiBvYmplY3QgdG8gYSBEYXRlVGltZSwgcHJvZHVjaW5nIGFub3RoZXIgRGF0ZVRpbWUuCiAgICoKICAgKiBIZXJlIGlzIGEgYnJpZWYgb3ZlcnZpZXcgb2YgY29tbW9ubHkgdXNlZCBtZXRob2RzIGFuZCBnZXR0ZXJzIGluIER1cmF0aW9uOgogICAqCiAgICogKiAqKkNyZWF0aW9uKiogVG8gY3JlYXRlIGEgRHVyYXRpb24sIHVzZSB7QGxpbmsgRHVyYXRpb24uZnJvbU1pbGxpc30sIHtAbGluayBEdXJhdGlvbi5mcm9tT2JqZWN0fSwgb3Ige0BsaW5rIER1cmF0aW9uLmZyb21JU099LgogICAqICogKipVbml0IHZhbHVlcyoqIFNlZSB0aGUge0BsaW5rIER1cmF0aW9uI3llYXJzfSwge0BsaW5rIER1cmF0aW9uI21vbnRoc30sIHtAbGluayBEdXJhdGlvbiN3ZWVrc30sIHtAbGluayBEdXJhdGlvbiNkYXlzfSwge0BsaW5rIER1cmF0aW9uI2hvdXJzfSwge0BsaW5rIER1cmF0aW9uI21pbnV0ZXN9LCB7QGxpbmsgRHVyYXRpb24jc2Vjb25kc30sIHtAbGluayBEdXJhdGlvbiNtaWxsaXNlY29uZHN9IGFjY2Vzc29ycy4KICAgKiAqICoqQ29uZmlndXJhdGlvbioqIFNlZSAge0BsaW5rIER1cmF0aW9uI2xvY2FsZX0gYW5kIHtAbGluayBEdXJhdGlvbiNudW1iZXJpbmdTeXN0ZW19IGFjY2Vzc29ycy4KICAgKiAqICoqVHJhbnNmb3JtYXRpb24qKiBUbyBjcmVhdGUgbmV3IER1cmF0aW9ucyBvdXQgb2Ygb2xkIG9uZXMgdXNlIHtAbGluayBEdXJhdGlvbiNwbHVzfSwge0BsaW5rIER1cmF0aW9uI21pbnVzfSwge0BsaW5rIER1cmF0aW9uI25vcm1hbGl6ZX0sIHtAbGluayBEdXJhdGlvbiNzZXR9LCB7QGxpbmsgRHVyYXRpb24jcmVjb25maWd1cmV9LCB7QGxpbmsgRHVyYXRpb24jc2hpZnRUb30sIGFuZCB7QGxpbmsgRHVyYXRpb24jbmVnYXRlfS4KICAgKiAqICoqT3V0cHV0KiogVG8gY29udmVydCB0aGUgRHVyYXRpb24gaW50byBvdGhlciByZXByZXNlbnRhdGlvbnMsIHNlZSB7QGxpbmsgRHVyYXRpb24jYXN9LCB7QGxpbmsgRHVyYXRpb24jdG9JU099LCB7QGxpbmsgRHVyYXRpb24jdG9Gb3JtYXR9LCBhbmQge0BsaW5rIER1cmF0aW9uI3RvSlNPTn0KICAgKgogICAqIFRoZXJlJ3MgYXJlIG1vcmUgbWV0aG9kcyBkb2N1bWVudGVkIGJlbG93LiBJbiBhZGRpdGlvbiwgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gc3VidGxlciB0b3BpY3MgbGlrZSBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgdmFsaWRpdHksIHNlZSB0aGUgZXh0ZXJuYWwgZG9jdW1lbnRhdGlvbi4KICAgKi8KICBjbGFzcyBEdXJhdGlvbiB7CiAgICAvKioKICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIGNvbnN0cnVjdG9yKGNvbmZpZykgewogICAgICBjb25zdCBhY2N1cmF0ZSA9IGNvbmZpZy5jb252ZXJzaW9uQWNjdXJhY3kgPT09ICJsb25ndGVybSIgfHwgZmFsc2U7CiAgICAgIGxldCBtYXRyaXggPSBhY2N1cmF0ZSA/IGFjY3VyYXRlTWF0cml4IDogY2FzdWFsTWF0cml4OwoKICAgICAgaWYgKGNvbmZpZy5tYXRyaXgpIHsKICAgICAgICBtYXRyaXggPSBjb25maWcubWF0cml4OwogICAgICB9CgogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLnZhbHVlcyA9IGNvbmZpZy52YWx1ZXM7CiAgICAgIC8qKgogICAgICAgKiBAYWNjZXNzIHByaXZhdGUKICAgICAgICovCiAgICAgIHRoaXMubG9jID0gY29uZmlnLmxvYyB8fCBMb2NhbGUuY3JlYXRlKCk7CiAgICAgIC8qKgogICAgICAgKiBAYWNjZXNzIHByaXZhdGUKICAgICAgICovCiAgICAgIHRoaXMuY29udmVyc2lvbkFjY3VyYWN5ID0gYWNjdXJhdGUgPyAibG9uZ3Rlcm0iIDogImNhc3VhbCI7CiAgICAgIC8qKgogICAgICAgKiBAYWNjZXNzIHByaXZhdGUKICAgICAgICovCiAgICAgIHRoaXMuaW52YWxpZCA9IGNvbmZpZy5pbnZhbGlkIHx8IG51bGw7CiAgICAgIC8qKgogICAgICAgKiBAYWNjZXNzIHByaXZhdGUKICAgICAgICovCiAgICAgIHRoaXMubWF0cml4ID0gbWF0cml4OwogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLmlzTHV4b25EdXJhdGlvbiA9IHRydWU7CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgRHVyYXRpb24gZnJvbSBhIG51bWJlciBvZiBtaWxsaXNlY29uZHMuCiAgICAgKiBAcGFyYW0ge251bWJlcn0gY291bnQgb2YgbWlsbGlzZWNvbmRzCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdGlvbnMgZm9yIHBhcnNpbmcKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5sb2NhbGU9J2VuLVVTJ10gLSB0aGUgbG9jYWxlIHRvIHVzZQogICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdHMubnVtYmVyaW5nU3lzdGVtIC0gdGhlIG51bWJlcmluZyBzeXN0ZW0gdG8gdXNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMuY29udmVyc2lvbkFjY3VyYWN5PSdjYXN1YWwnXSAtIHRoZSBjb252ZXJzaW9uIHN5c3RlbSB0byB1c2UKICAgICAqIEByZXR1cm4ge0R1cmF0aW9ufQogICAgICovCiAgICBzdGF0aWMgZnJvbU1pbGxpcyhjb3VudCwgb3B0cykgewogICAgICByZXR1cm4gRHVyYXRpb24uZnJvbU9iamVjdCh7IG1pbGxpc2Vjb25kczogY291bnQgfSwgb3B0cyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgYSBEdXJhdGlvbiBmcm9tIGEgSmF2YVNjcmlwdCBvYmplY3Qgd2l0aCBrZXlzIGxpa2UgJ3llYXJzJyBhbmQgJ2hvdXJzJy4KICAgICAqIElmIHRoaXMgb2JqZWN0IGlzIGVtcHR5IHRoZW4gYSB6ZXJvIG1pbGxpc2Vjb25kcyBkdXJhdGlvbiBpcyByZXR1cm5lZC4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSB0aGUgb2JqZWN0IHRvIGNyZWF0ZSB0aGUgRGF0ZVRpbWUgZnJvbQogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai55ZWFycwogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai5xdWFydGVycwogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai5tb250aHMKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvYmoud2Vla3MKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvYmouZGF5cwogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai5ob3VycwogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai5taW51dGVzCiAgICAgKiBAcGFyYW0ge251bWJlcn0gb2JqLnNlY29uZHMKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvYmoubWlsbGlzZWNvbmRzCiAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdHM9W11dIC0gb3B0aW9ucyBmb3IgY3JlYXRpbmcgdGhpcyBEdXJhdGlvbgogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmxvY2FsZT0nZW4tVVMnXSAtIHRoZSBsb2NhbGUgdG8gdXNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0cy5udW1iZXJpbmdTeXN0ZW0gLSB0aGUgbnVtYmVyaW5nIHN5c3RlbSB0byB1c2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5jb252ZXJzaW9uQWNjdXJhY3k9J2Nhc3VhbCddIC0gdGhlIHByZXNldCBjb252ZXJzaW9uIHN5c3RlbSB0byB1c2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5tYXRyaXg9T2JqZWN0XSAtIHRoZSBjdXN0b20gY29udmVyc2lvbiBzeXN0ZW0gdG8gdXNlCiAgICAgKiBAcmV0dXJuIHtEdXJhdGlvbn0KICAgICAqLwogICAgc3RhdGljIGZyb21PYmplY3Qob2JqLCBvcHRzID0ge30pIHsKICAgICAgaWYgKG9iaiA9PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICJvYmplY3QiKSB7CiAgICAgICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudEVycm9yKAogICAgICAgICAgYER1cmF0aW9uLmZyb21PYmplY3Q6IGFyZ3VtZW50IGV4cGVjdGVkIHRvIGJlIGFuIG9iamVjdCwgZ290ICR7CiAgICAgICAgICBvYmogPT09IG51bGwgPyAibnVsbCIgOiB0eXBlb2Ygb2JqCiAgICAgICAgfWAKICAgICAgICApOwogICAgICB9CgogICAgICByZXR1cm4gbmV3IER1cmF0aW9uKHsKICAgICAgICB2YWx1ZXM6IG5vcm1hbGl6ZU9iamVjdChvYmosIER1cmF0aW9uLm5vcm1hbGl6ZVVuaXQpLAogICAgICAgIGxvYzogTG9jYWxlLmZyb21PYmplY3Qob3B0cyksCiAgICAgICAgY29udmVyc2lvbkFjY3VyYWN5OiBvcHRzLmNvbnZlcnNpb25BY2N1cmFjeSwKICAgICAgICBtYXRyaXg6IG9wdHMubWF0cml4LAogICAgICB9KTsKICAgIH0KCiAgICAvKioKICAgICAqIENyZWF0ZSBhIER1cmF0aW9uIGZyb20gRHVyYXRpb25MaWtlLgogICAgICoKICAgICAqIEBwYXJhbSB7T2JqZWN0IHwgbnVtYmVyIHwgRHVyYXRpb259IGR1cmF0aW9uTGlrZQogICAgICogT25lIG9mOgogICAgICogLSBvYmplY3Qgd2l0aCBrZXlzIGxpa2UgJ3llYXJzJyBhbmQgJ2hvdXJzJy4KICAgICAqIC0gbnVtYmVyIHJlcHJlc2VudGluZyBtaWxsaXNlY29uZHMKICAgICAqIC0gRHVyYXRpb24gaW5zdGFuY2UKICAgICAqIEByZXR1cm4ge0R1cmF0aW9ufQogICAgICovCiAgICBzdGF0aWMgZnJvbUR1cmF0aW9uTGlrZShkdXJhdGlvbkxpa2UpIHsKICAgICAgaWYgKGlzTnVtYmVyKGR1cmF0aW9uTGlrZSkpIHsKICAgICAgICByZXR1cm4gRHVyYXRpb24uZnJvbU1pbGxpcyhkdXJhdGlvbkxpa2UpOwogICAgICB9IGVsc2UgaWYgKER1cmF0aW9uLmlzRHVyYXRpb24oZHVyYXRpb25MaWtlKSkgewogICAgICAgIHJldHVybiBkdXJhdGlvbkxpa2U7CiAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGR1cmF0aW9uTGlrZSA9PT0gIm9iamVjdCIpIHsKICAgICAgICByZXR1cm4gRHVyYXRpb24uZnJvbU9iamVjdChkdXJhdGlvbkxpa2UpOwogICAgICB9IGVsc2UgewogICAgICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRFcnJvcigKICAgICAgICAgIGBVbmtub3duIGR1cmF0aW9uIGFyZ3VtZW50ICR7ZHVyYXRpb25MaWtlfSBvZiB0eXBlICR7dHlwZW9mIGR1cmF0aW9uTGlrZX1gCiAgICAgICAgKTsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGEgRHVyYXRpb24gZnJvbSBhbiBJU08gODYwMSBkdXJhdGlvbiBzdHJpbmcuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIHRleHQgdG8gcGFyc2UKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRzIC0gb3B0aW9ucyBmb3IgcGFyc2luZwogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmxvY2FsZT0nZW4tVVMnXSAtIHRoZSBsb2NhbGUgdG8gdXNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0cy5udW1iZXJpbmdTeXN0ZW0gLSB0aGUgbnVtYmVyaW5nIHN5c3RlbSB0byB1c2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5jb252ZXJzaW9uQWNjdXJhY3k9J2Nhc3VhbCddIC0gdGhlIHByZXNldCBjb252ZXJzaW9uIHN5c3RlbSB0byB1c2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5tYXRyaXg9T2JqZWN0XSAtIHRoZSBwcmVzZXQgY29udmVyc2lvbiBzeXN0ZW0gdG8gdXNlCiAgICAgKiBAc2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0lTT184NjAxI0R1cmF0aW9ucwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbUlTTygnUDNZNk0xVzREVDEySDMwTTVTJykudG9PYmplY3QoKSAvLz0+IHsgeWVhcnM6IDMsIG1vbnRoczogNiwgd2Vla3M6IDEsIGRheXM6IDQsIGhvdXJzOiAxMiwgbWludXRlczogMzAsIHNlY29uZHM6IDUgfQogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbUlTTygnUFQyM0gnKS50b09iamVjdCgpIC8vPT4geyBob3VyczogMjMgfQogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbUlTTygnUDVZM00nKS50b09iamVjdCgpIC8vPT4geyB5ZWFyczogNSwgbW9udGhzOiAzIH0KICAgICAqIEByZXR1cm4ge0R1cmF0aW9ufQogICAgICovCiAgICBzdGF0aWMgZnJvbUlTTyh0ZXh0LCBvcHRzKSB7CiAgICAgIGNvbnN0IFtwYXJzZWRdID0gcGFyc2VJU09EdXJhdGlvbih0ZXh0KTsKICAgICAgaWYgKHBhcnNlZCkgewogICAgICAgIHJldHVybiBEdXJhdGlvbi5mcm9tT2JqZWN0KHBhcnNlZCwgb3B0cyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIER1cmF0aW9uLmludmFsaWQoInVucGFyc2FibGUiLCBgdGhlIGlucHV0ICIke3RleHR9IiBjYW4ndCBiZSBwYXJzZWQgYXMgSVNPIDg2MDFgKTsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGEgRHVyYXRpb24gZnJvbSBhbiBJU08gODYwMSB0aW1lIHN0cmluZy4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gdGV4dCB0byBwYXJzZQogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zIGZvciBwYXJzaW5nCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jYWxlPSdlbi1VUyddIC0gdGhlIGxvY2FsZSB0byB1c2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLm51bWJlcmluZ1N5c3RlbSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtIHRvIHVzZQogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmNvbnZlcnNpb25BY2N1cmFjeT0nY2FzdWFsJ10gLSB0aGUgcHJlc2V0IGNvbnZlcnNpb24gc3lzdGVtIHRvIHVzZQogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLm1hdHJpeD1PYmplY3RdIC0gdGhlIGNvbnZlcnNpb24gc3lzdGVtIHRvIHVzZQogICAgICogQHNlZSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JU09fODYwMSNUaW1lcwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbUlTT1RpbWUoJzExOjIyOjMzLjQ0NCcpLnRvT2JqZWN0KCkgLy89PiB7IGhvdXJzOiAxMSwgbWludXRlczogMjIsIHNlY29uZHM6IDMzLCBtaWxsaXNlY29uZHM6IDQ0NCB9CiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tSVNPVGltZSgnMTE6MDAnKS50b09iamVjdCgpIC8vPT4geyBob3VyczogMTEsIG1pbnV0ZXM6IDAsIHNlY29uZHM6IDAgfQogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbUlTT1RpbWUoJ1QxMTowMCcpLnRvT2JqZWN0KCkgLy89PiB7IGhvdXJzOiAxMSwgbWludXRlczogMCwgc2Vjb25kczogMCB9CiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tSVNPVGltZSgnMTEwMCcpLnRvT2JqZWN0KCkgLy89PiB7IGhvdXJzOiAxMSwgbWludXRlczogMCwgc2Vjb25kczogMCB9CiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tSVNPVGltZSgnVDExMDAnKS50b09iamVjdCgpIC8vPT4geyBob3VyczogMTEsIG1pbnV0ZXM6IDAsIHNlY29uZHM6IDAgfQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIHN0YXRpYyBmcm9tSVNPVGltZSh0ZXh0LCBvcHRzKSB7CiAgICAgIGNvbnN0IFtwYXJzZWRdID0gcGFyc2VJU09UaW1lT25seSh0ZXh0KTsKICAgICAgaWYgKHBhcnNlZCkgewogICAgICAgIHJldHVybiBEdXJhdGlvbi5mcm9tT2JqZWN0KHBhcnNlZCwgb3B0cyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIER1cmF0aW9uLmludmFsaWQoInVucGFyc2FibGUiLCBgdGhlIGlucHV0ICIke3RleHR9IiBjYW4ndCBiZSBwYXJzZWQgYXMgSVNPIDg2MDFgKTsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGFuIGludmFsaWQgRHVyYXRpb24uCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcmVhc29uIC0gc2ltcGxlIHN0cmluZyBvZiB3aHkgdGhpcyBkYXRldGltZSBpcyBpbnZhbGlkLiBTaG91bGQgbm90IGNvbnRhaW4gcGFyYW1ldGVycyBvciBhbnl0aGluZyBlbHNlIGRhdGEtZGVwZW5kZW50CiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW2V4cGxhbmF0aW9uPW51bGxdIC0gbG9uZ2VyIGV4cGxhbmF0aW9uLCBtYXkgaW5jbHVkZSBwYXJhbWV0ZXJzIGFuZCBvdGhlciB1c2VmdWwgZGVidWdnaW5nIGluZm9ybWF0aW9uCiAgICAgKiBAcmV0dXJuIHtEdXJhdGlvbn0KICAgICAqLwogICAgc3RhdGljIGludmFsaWQocmVhc29uLCBleHBsYW5hdGlvbiA9IG51bGwpIHsKICAgICAgaWYgKCFyZWFzb24pIHsKICAgICAgICB0aHJvdyBuZXcgSW52YWxpZEFyZ3VtZW50RXJyb3IoIm5lZWQgdG8gc3BlY2lmeSBhIHJlYXNvbiB0aGUgRHVyYXRpb24gaXMgaW52YWxpZCIpOwogICAgICB9CgogICAgICBjb25zdCBpbnZhbGlkID0gcmVhc29uIGluc3RhbmNlb2YgSW52YWxpZCA/IHJlYXNvbiA6IG5ldyBJbnZhbGlkKHJlYXNvbiwgZXhwbGFuYXRpb24pOwoKICAgICAgaWYgKFNldHRpbmdzLnRocm93T25JbnZhbGlkKSB7CiAgICAgICAgdGhyb3cgbmV3IEludmFsaWREdXJhdGlvbkVycm9yKGludmFsaWQpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBuZXcgRHVyYXRpb24oeyBpbnZhbGlkIH0pOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBzdGF0aWMgbm9ybWFsaXplVW5pdCh1bml0KSB7CiAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSB7CiAgICAgICAgeWVhcjogInllYXJzIiwKICAgICAgICB5ZWFyczogInllYXJzIiwKICAgICAgICBxdWFydGVyOiAicXVhcnRlcnMiLAogICAgICAgIHF1YXJ0ZXJzOiAicXVhcnRlcnMiLAogICAgICAgIG1vbnRoOiAibW9udGhzIiwKICAgICAgICBtb250aHM6ICJtb250aHMiLAogICAgICAgIHdlZWs6ICJ3ZWVrcyIsCiAgICAgICAgd2Vla3M6ICJ3ZWVrcyIsCiAgICAgICAgZGF5OiAiZGF5cyIsCiAgICAgICAgZGF5czogImRheXMiLAogICAgICAgIGhvdXI6ICJob3VycyIsCiAgICAgICAgaG91cnM6ICJob3VycyIsCiAgICAgICAgbWludXRlOiAibWludXRlcyIsCiAgICAgICAgbWludXRlczogIm1pbnV0ZXMiLAogICAgICAgIHNlY29uZDogInNlY29uZHMiLAogICAgICAgIHNlY29uZHM6ICJzZWNvbmRzIiwKICAgICAgICBtaWxsaXNlY29uZDogIm1pbGxpc2Vjb25kcyIsCiAgICAgICAgbWlsbGlzZWNvbmRzOiAibWlsbGlzZWNvbmRzIiwKICAgICAgfVt1bml0ID8gdW5pdC50b0xvd2VyQ2FzZSgpIDogdW5pdF07CgogICAgICBpZiAoIW5vcm1hbGl6ZWQpIHRocm93IG5ldyBJbnZhbGlkVW5pdEVycm9yKHVuaXQpOwoKICAgICAgcmV0dXJuIG5vcm1hbGl6ZWQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBDaGVjayBpZiBhbiBvYmplY3QgaXMgYSBEdXJhdGlvbi4gV29ya3MgYWNyb3NzIGNvbnRleHQgYm91bmRhcmllcwogICAgICogQHBhcmFtIHtvYmplY3R9IG8KICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIHN0YXRpYyBpc0R1cmF0aW9uKG8pIHsKICAgICAgcmV0dXJuIChvICYmIG8uaXNMdXhvbkR1cmF0aW9uKSB8fCBmYWxzZTsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCAgdGhlIGxvY2FsZSBvZiBhIER1cmF0aW9uLCBzdWNoICdlbi1HQicKICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIGdldCBsb2NhbGUoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLmxvYy5sb2NhbGUgOiBudWxsOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBudW1iZXJpbmcgc3lzdGVtIG9mIGEgRHVyYXRpb24sIHN1Y2ggJ2JlbmcnLiBUaGUgbnVtYmVyaW5nIHN5c3RlbSBpcyB1c2VkIHdoZW4gZm9ybWF0dGluZyB0aGUgRHVyYXRpb24KICAgICAqCiAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICovCiAgICBnZXQgbnVtYmVyaW5nU3lzdGVtKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy5sb2MubnVtYmVyaW5nU3lzdGVtIDogbnVsbDsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhpcyBEdXJhdGlvbiBmb3JtYXR0ZWQgYWNjb3JkaW5nIHRvIHRoZSBzcGVjaWZpZWQgZm9ybWF0IHN0cmluZy4gWW91IG1heSB1c2UgdGhlc2UgdG9rZW5zOgogICAgICogKiBgU2AgZm9yIG1pbGxpc2Vjb25kcwogICAgICogKiBgc2AgZm9yIHNlY29uZHMKICAgICAqICogYG1gIGZvciBtaW51dGVzCiAgICAgKiAqIGBoYCBmb3IgaG91cnMKICAgICAqICogYGRgIGZvciBkYXlzCiAgICAgKiAqIGB3YCBmb3Igd2Vla3MKICAgICAqICogYE1gIGZvciBtb250aHMKICAgICAqICogYHlgIGZvciB5ZWFycwogICAgICogTm90ZXM6CiAgICAgKiAqIEFkZCBwYWRkaW5nIGJ5IHJlcGVhdGluZyB0aGUgdG9rZW4sIGUuZy4gInl5IiBwYWRzIHRoZSB5ZWFycyB0byB0d28gZGlnaXRzLCAiaGhoaCIgcGFkcyB0aGUgaG91cnMgb3V0IHRvIGZvdXIgZGlnaXRzCiAgICAgKiAqIFRva2VucyBjYW4gYmUgZXNjYXBlZCBieSB3cmFwcGluZyB3aXRoIHNpbmdsZSBxdW90ZXMuCiAgICAgKiAqIFRoZSBkdXJhdGlvbiB3aWxsIGJlIGNvbnZlcnRlZCB0byB0aGUgc2V0IG9mIHVuaXRzIGluIHRoZSBmb3JtYXQgc3RyaW5nIHVzaW5nIHtAbGluayBEdXJhdGlvbiNzaGlmdFRvfSBhbmQgdGhlIER1cmF0aW9ucydzIGNvbnZlcnNpb24gYWNjdXJhY3kgc2V0dGluZy4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBmbXQgLSB0aGUgZm9ybWF0IHN0cmluZwogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmZsb29yPXRydWVdIC0gZmxvb3IgbnVtZXJpY2FsIHZhbHVlcwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7IHllYXJzOiAxLCBkYXlzOiA2LCBzZWNvbmRzOiAyIH0pLnRvRm9ybWF0KCJ5IGQgcyIpIC8vPT4gIjEgNiAyIgogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7IHllYXJzOiAxLCBkYXlzOiA2LCBzZWNvbmRzOiAyIH0pLnRvRm9ybWF0KCJ5eSBkZCBzc3MiKSAvLz0+ICIwMSAwNiAwMDIiCiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgeWVhcnM6IDEsIGRheXM6IDYsIHNlY29uZHM6IDIgfSkudG9Gb3JtYXQoIk0gUyIpIC8vPT4gIjEyIDUxODQwMjAwMCIKICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9Gb3JtYXQoZm10LCBvcHRzID0ge30pIHsKICAgICAgLy8gcmV2ZXJzZS1jb21wYXQgc2luY2UgMS4yOyB3ZSBhbHdheXMgcm91bmQgZG93biBub3csIG5ldmVyIHVwLCBhbmQgd2UgZG8gaXQgYnkgZGVmYXVsdAogICAgICBjb25zdCBmbXRPcHRzID0gewogICAgICAgIC4uLm9wdHMsCiAgICAgICAgZmxvb3I6IG9wdHMucm91bmQgIT09IGZhbHNlICYmIG9wdHMuZmxvb3IgIT09IGZhbHNlLAogICAgICB9OwogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkCiAgICAgICAgPyBGb3JtYXR0ZXIuY3JlYXRlKHRoaXMubG9jLCBmbXRPcHRzKS5mb3JtYXREdXJhdGlvbkZyb21TdHJpbmcodGhpcywgZm10KQogICAgICAgIDogSU5WQUxJRCQyOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBhIER1cmF0aW9uIHdpdGggYWxsIHVuaXRzIGluY2x1ZGVkLgogICAgICogVG8gbW9kaWZ5IGl0cyBiZWhhdmlvciB1c2UgdGhlIGBsaXN0U3R5bGVgIGFuZCBhbnkgSW50bC5OdW1iZXJGb3JtYXQgb3B0aW9uLCB0aG91Z2ggYHVuaXREaXNwbGF5YCBpcyBlc3BlY2lhbGx5IHJlbGV2YW50LgogICAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9JbnRsL051bWJlckZvcm1hdAogICAgICogQHBhcmFtIG9wdHMgLSBPbiBvcHRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIHRoZSBmb3JtYXR0aW5nLiBBY2NlcHRzIHRoZSBzYW1lIGtleXMgYXMgdGhlIG9wdGlvbnMgcGFyYW1ldGVyIG9mIHRoZSBuYXRpdmUgYEludC5OdW1iZXJGb3JtYXRgIGNvbnN0cnVjdG9yLCBhcyB3ZWxsIGFzIGBsaXN0U3R5bGVgLgogICAgICogQGV4YW1wbGUKICAgICAqIGBgYGpzCiAgICAgKiB2YXIgZHVyID0gRHVyYXRpb24uZnJvbU9iamVjdCh7IGRheXM6IDEsIGhvdXJzOiA1LCBtaW51dGVzOiA2IH0pCiAgICAgKiBkdXIudG9IdW1hbigpIC8vPT4gJzEgZGF5LCA1IGhvdXJzLCA2IG1pbnV0ZXMnCiAgICAgKiBkdXIudG9IdW1hbih7IGxpc3RTdHlsZTogImxvbmciIH0pIC8vPT4gJzEgZGF5LCA1IGhvdXJzLCBhbmQgNiBtaW51dGVzJwogICAgICogZHVyLnRvSHVtYW4oeyB1bml0RGlzcGxheTogInNob3J0IiB9KSAvLz0+ICcxIGRheSwgNSBociwgNiBtaW4nCiAgICAgKiBgYGAKICAgICAqLwogICAgdG9IdW1hbihvcHRzID0ge30pIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiBJTlZBTElEJDI7CgogICAgICBjb25zdCBsID0gb3JkZXJlZFVuaXRzJDEKICAgICAgICAubWFwKCh1bml0KSA9PiB7CiAgICAgICAgICBjb25zdCB2YWwgPSB0aGlzLnZhbHVlc1t1bml0XTsKICAgICAgICAgIGlmIChpc1VuZGVmaW5lZCh2YWwpKSB7CiAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHRoaXMubG9jCiAgICAgICAgICAgIC5udW1iZXJGb3JtYXR0ZXIoeyBzdHlsZTogInVuaXQiLCB1bml0RGlzcGxheTogImxvbmciLCAuLi5vcHRzLCB1bml0OiB1bml0LnNsaWNlKDAsIC0xKSB9KQogICAgICAgICAgICAuZm9ybWF0KHZhbCk7CiAgICAgICAgfSkKICAgICAgICAuZmlsdGVyKChuKSA9PiBuKTsKCiAgICAgIHJldHVybiB0aGlzLmxvYwogICAgICAgIC5saXN0Rm9ybWF0dGVyKHsgdHlwZTogImNvbmp1bmN0aW9uIiwgc3R5bGU6IG9wdHMubGlzdFN0eWxlIHx8ICJuYXJyb3ciLCAuLi5vcHRzIH0pCiAgICAgICAgLmZvcm1hdChsKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYSBKYXZhU2NyaXB0IG9iamVjdCB3aXRoIHRoaXMgRHVyYXRpb24ncyB2YWx1ZXMuCiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgeWVhcnM6IDEsIGRheXM6IDYsIHNlY29uZHM6IDIgfSkudG9PYmplY3QoKSAvLz0+IHsgeWVhcnM6IDEsIGRheXM6IDYsIHNlY29uZHM6IDIgfQogICAgICogQHJldHVybiB7T2JqZWN0fQogICAgICovCiAgICB0b09iamVjdCgpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiB7fTsKICAgICAgcmV0dXJuIHsgLi4udGhpcy52YWx1ZXMgfTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYW4gSVNPIDg2MDEtY29tcGxpYW50IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIER1cmF0aW9uLgogICAgICogQHNlZSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JU09fODYwMSNEdXJhdGlvbnMKICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyB5ZWFyczogMywgc2Vjb25kczogNDUgfSkudG9JU08oKSAvLz0+ICdQM1lUNDVTJwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7IG1vbnRoczogNCwgc2Vjb25kczogNDUgfSkudG9JU08oKSAvLz0+ICdQNE1UNDVTJwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7IG1vbnRoczogNSB9KS50b0lTTygpIC8vPT4gJ1A1TScKICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyBtaW51dGVzOiA1IH0pLnRvSVNPKCkgLy89PiAnUFQ1TScKICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyBtaWxsaXNlY29uZHM6IDYgfSkudG9JU08oKSAvLz0+ICdQVDAuMDA2UycKICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9JU08oKSB7CiAgICAgIC8vIHdlIGNvdWxkIHVzZSB0aGUgZm9ybWF0dGVyLCBidXQgdGhpcyBpcyBhbiBlYXNpZXIgd2F5IHRvIGdldCB0aGUgbWluaW11bSBzdHJpbmcKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiBudWxsOwoKICAgICAgbGV0IHMgPSAiUCI7CiAgICAgIGlmICh0aGlzLnllYXJzICE9PSAwKSBzICs9IHRoaXMueWVhcnMgKyAiWSI7CiAgICAgIGlmICh0aGlzLm1vbnRocyAhPT0gMCB8fCB0aGlzLnF1YXJ0ZXJzICE9PSAwKSBzICs9IHRoaXMubW9udGhzICsgdGhpcy5xdWFydGVycyAqIDMgKyAiTSI7CiAgICAgIGlmICh0aGlzLndlZWtzICE9PSAwKSBzICs9IHRoaXMud2Vla3MgKyAiVyI7CiAgICAgIGlmICh0aGlzLmRheXMgIT09IDApIHMgKz0gdGhpcy5kYXlzICsgIkQiOwogICAgICBpZiAodGhpcy5ob3VycyAhPT0gMCB8fCB0aGlzLm1pbnV0ZXMgIT09IDAgfHwgdGhpcy5zZWNvbmRzICE9PSAwIHx8IHRoaXMubWlsbGlzZWNvbmRzICE9PSAwKQogICAgICAgIHMgKz0gIlQiOwogICAgICBpZiAodGhpcy5ob3VycyAhPT0gMCkgcyArPSB0aGlzLmhvdXJzICsgIkgiOwogICAgICBpZiAodGhpcy5taW51dGVzICE9PSAwKSBzICs9IHRoaXMubWludXRlcyArICJNIjsKICAgICAgaWYgKHRoaXMuc2Vjb25kcyAhPT0gMCB8fCB0aGlzLm1pbGxpc2Vjb25kcyAhPT0gMCkKICAgICAgICAvLyB0aGlzIHdpbGwgaGFuZGxlICJmbG9hdGluZyBwb2ludCBtYWRuZXNzIiBieSByZW1vdmluZyBleHRyYSBkZWNpbWFsIHBsYWNlcwogICAgICAgIC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzU4ODAwNC9pcy1mbG9hdGluZy1wb2ludC1tYXRoLWJyb2tlbgogICAgICAgIHMgKz0gcm91bmRUbyh0aGlzLnNlY29uZHMgKyB0aGlzLm1pbGxpc2Vjb25kcyAvIDEwMDAsIDMpICsgIlMiOwogICAgICBpZiAocyA9PT0gIlAiKSBzICs9ICJUMFMiOwogICAgICByZXR1cm4gczsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYW4gSVNPIDg2MDEtY29tcGxpYW50IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIER1cmF0aW9uLCBmb3JtYXR0ZWQgYXMgYSB0aW1lIG9mIGRheS4KICAgICAqIE5vdGUgdGhhdCB0aGlzIHdpbGwgcmV0dXJuIG51bGwgaWYgdGhlIGR1cmF0aW9uIGlzIGludmFsaWQsIG5lZ2F0aXZlLCBvciBlcXVhbCB0byBvciBncmVhdGVyIHRoYW4gMjQgaG91cnMuCiAgICAgKiBAc2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0lTT184NjAxI1RpbWVzCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdGlvbnMKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuc3VwcHJlc3NNaWxsaXNlY29uZHM9ZmFsc2VdIC0gZXhjbHVkZSBtaWxsaXNlY29uZHMgZnJvbSB0aGUgZm9ybWF0IGlmIHRoZXkncmUgMAogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5zdXBwcmVzc1NlY29uZHM9ZmFsc2VdIC0gZXhjbHVkZSBzZWNvbmRzIGZyb20gdGhlIGZvcm1hdCBpZiB0aGV5J3JlIDAKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuaW5jbHVkZVByZWZpeD1mYWxzZV0gLSBpbmNsdWRlIHRoZSBgVGAgcHJlZml4CiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMuZm9ybWF0PSdleHRlbmRlZCddIC0gY2hvb3NlIGJldHdlZW4gdGhlIGJhc2ljIGFuZCBleHRlbmRlZCBmb3JtYXQKICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyBob3VyczogMTEgfSkudG9JU09UaW1lKCkgLy89PiAnMTE6MDA6MDAuMDAwJwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7IGhvdXJzOiAxMSB9KS50b0lTT1RpbWUoeyBzdXBwcmVzc01pbGxpc2Vjb25kczogdHJ1ZSB9KSAvLz0+ICcxMTowMDowMCcKICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyBob3VyczogMTEgfSkudG9JU09UaW1lKHsgc3VwcHJlc3NTZWNvbmRzOiB0cnVlIH0pIC8vPT4gJzExOjAwJwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7IGhvdXJzOiAxMSB9KS50b0lTT1RpbWUoeyBpbmNsdWRlUHJlZml4OiB0cnVlIH0pIC8vPT4gJ1QxMTowMDowMC4wMDAnCiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgaG91cnM6IDExIH0pLnRvSVNPVGltZSh7IGZvcm1hdDogJ2Jhc2ljJyB9KSAvLz0+ICcxMTAwMDAuMDAwJwogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b0lTT1RpbWUob3B0cyA9IHt9KSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gbnVsbDsKCiAgICAgIGNvbnN0IG1pbGxpcyA9IHRoaXMudG9NaWxsaXMoKTsKICAgICAgaWYgKG1pbGxpcyA8IDAgfHwgbWlsbGlzID49IDg2NDAwMDAwKSByZXR1cm4gbnVsbDsKCiAgICAgIG9wdHMgPSB7CiAgICAgICAgc3VwcHJlc3NNaWxsaXNlY29uZHM6IGZhbHNlLAogICAgICAgIHN1cHByZXNzU2Vjb25kczogZmFsc2UsCiAgICAgICAgaW5jbHVkZVByZWZpeDogZmFsc2UsCiAgICAgICAgZm9ybWF0OiAiZXh0ZW5kZWQiLAogICAgICAgIC4uLm9wdHMsCiAgICAgICAgaW5jbHVkZU9mZnNldDogZmFsc2UsCiAgICAgIH07CgogICAgICBjb25zdCBkYXRlVGltZSA9IERhdGVUaW1lLmZyb21NaWxsaXMobWlsbGlzLCB7IHpvbmU6ICJVVEMiIH0pOwogICAgICByZXR1cm4gZGF0ZVRpbWUudG9JU09UaW1lKG9wdHMpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhbiBJU08gODYwMSByZXByZXNlbnRhdGlvbiBvZiB0aGlzIER1cmF0aW9uIGFwcHJvcHJpYXRlIGZvciB1c2UgaW4gSlNPTi4KICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9KU09OKCkgewogICAgICByZXR1cm4gdGhpcy50b0lTTygpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhbiBJU08gODYwMSByZXByZXNlbnRhdGlvbiBvZiB0aGlzIER1cmF0aW9uIGFwcHJvcHJpYXRlIGZvciB1c2UgaW4gZGVidWdnaW5nLgogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b1N0cmluZygpIHsKICAgICAgcmV0dXJuIHRoaXMudG9JU08oKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYW4gbWlsbGlzZWNvbmRzIHZhbHVlIG9mIHRoaXMgRHVyYXRpb24uCiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9CiAgICAgKi8KICAgIHRvTWlsbGlzKCkgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIE5hTjsKCiAgICAgIHJldHVybiBkdXJhdGlvblRvTWlsbGlzKHRoaXMubWF0cml4LCB0aGlzLnZhbHVlcyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGFuIG1pbGxpc2Vjb25kcyB2YWx1ZSBvZiB0aGlzIER1cmF0aW9uLiBBbGlhcyBvZiB7QGxpbmsgdG9NaWxsaXN9CiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9CiAgICAgKi8KICAgIHZhbHVlT2YoKSB7CiAgICAgIHJldHVybiB0aGlzLnRvTWlsbGlzKCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBNYWtlIHRoaXMgRHVyYXRpb24gbG9uZ2VyIGJ5IHRoZSBzcGVjaWZpZWQgYW1vdW50LiBSZXR1cm4gYSBuZXdseS1jb25zdHJ1Y3RlZCBEdXJhdGlvbi4KICAgICAqIEBwYXJhbSB7RHVyYXRpb258T2JqZWN0fG51bWJlcn0gZHVyYXRpb24gLSBUaGUgYW1vdW50IHRvIGFkZC4gRWl0aGVyIGEgTHV4b24gRHVyYXRpb24sIGEgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcywgdGhlIG9iamVjdCBhcmd1bWVudCB0byBEdXJhdGlvbi5mcm9tT2JqZWN0KCkKICAgICAqIEByZXR1cm4ge0R1cmF0aW9ufQogICAgICovCiAgICBwbHVzKGR1cmF0aW9uKSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gdGhpczsKCiAgICAgIGNvbnN0IGR1ciA9IER1cmF0aW9uLmZyb21EdXJhdGlvbkxpa2UoZHVyYXRpb24pLAogICAgICAgIHJlc3VsdCA9IHt9OwoKICAgICAgZm9yIChjb25zdCBrIG9mIG9yZGVyZWRVbml0cyQxKSB7CiAgICAgICAgaWYgKGhhc093blByb3BlcnR5KGR1ci52YWx1ZXMsIGspIHx8IGhhc093blByb3BlcnR5KHRoaXMudmFsdWVzLCBrKSkgewogICAgICAgICAgcmVzdWx0W2tdID0gZHVyLmdldChrKSArIHRoaXMuZ2V0KGspOwogICAgICAgIH0KICAgICAgfQoKICAgICAgcmV0dXJuIGNsb25lJDEodGhpcywgeyB2YWx1ZXM6IHJlc3VsdCB9LCB0cnVlKTsKICAgIH0KCiAgICAvKioKICAgICAqIE1ha2UgdGhpcyBEdXJhdGlvbiBzaG9ydGVyIGJ5IHRoZSBzcGVjaWZpZWQgYW1vdW50LiBSZXR1cm4gYSBuZXdseS1jb25zdHJ1Y3RlZCBEdXJhdGlvbi4KICAgICAqIEBwYXJhbSB7RHVyYXRpb258T2JqZWN0fG51bWJlcn0gZHVyYXRpb24gLSBUaGUgYW1vdW50IHRvIHN1YnRyYWN0LiBFaXRoZXIgYSBMdXhvbiBEdXJhdGlvbiwgYSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLCB0aGUgb2JqZWN0IGFyZ3VtZW50IHRvIER1cmF0aW9uLmZyb21PYmplY3QoKQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIG1pbnVzKGR1cmF0aW9uKSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gdGhpczsKCiAgICAgIGNvbnN0IGR1ciA9IER1cmF0aW9uLmZyb21EdXJhdGlvbkxpa2UoZHVyYXRpb24pOwogICAgICByZXR1cm4gdGhpcy5wbHVzKGR1ci5uZWdhdGUoKSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBTY2FsZSB0aGlzIER1cmF0aW9uIGJ5IHRoZSBzcGVjaWZpZWQgYW1vdW50LiBSZXR1cm4gYSBuZXdseS1jb25zdHJ1Y3RlZCBEdXJhdGlvbi4KICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGFwcGx5IHRvIGVhY2ggdW5pdC4gQXJpdHkgaXMgMSBvciAyOiB0aGUgdmFsdWUgb2YgdGhlIHVuaXQgYW5kLCBvcHRpb25hbGx5LCB0aGUgdW5pdCBuYW1lLiBNdXN0IHJldHVybiBhIG51bWJlci4KICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyBob3VyczogMSwgbWludXRlczogMzAgfSkubWFwVW5pdHMoeCA9PiB4ICogMikgLy89PiB7IGhvdXJzOiAyLCBtaW51dGVzOiA2MCB9CiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgaG91cnM6IDEsIG1pbnV0ZXM6IDMwIH0pLm1hcFVuaXRzKCh4LCB1KSA9PiB1ID09PSAiaG91cnMiID8geCAqIDIgOiB4KSAvLz0+IHsgaG91cnM6IDIsIG1pbnV0ZXM6IDMwIH0KICAgICAqIEByZXR1cm4ge0R1cmF0aW9ufQogICAgICovCiAgICBtYXBVbml0cyhmbikgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIHRoaXM7CiAgICAgIGNvbnN0IHJlc3VsdCA9IHt9OwogICAgICBmb3IgKGNvbnN0IGsgb2YgT2JqZWN0LmtleXModGhpcy52YWx1ZXMpKSB7CiAgICAgICAgcmVzdWx0W2tdID0gYXNOdW1iZXIoZm4odGhpcy52YWx1ZXNba10sIGspKTsKICAgICAgfQogICAgICByZXR1cm4gY2xvbmUkMSh0aGlzLCB7IHZhbHVlczogcmVzdWx0IH0sIHRydWUpOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSB2YWx1ZSBvZiB1bml0LgogICAgICogQHBhcmFtIHtzdHJpbmd9IHVuaXQgLSBhIHVuaXQgc3VjaCBhcyAnbWludXRlJyBvciAnZGF5JwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7eWVhcnM6IDIsIGRheXM6IDN9KS5nZXQoJ3llYXJzJykgLy89PiAyCiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHt5ZWFyczogMiwgZGF5czogM30pLmdldCgnbW9udGhzJykgLy89PiAwCiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHt5ZWFyczogMiwgZGF5czogM30pLmdldCgnZGF5cycpIC8vPT4gMwogICAgICogQHJldHVybiB7bnVtYmVyfQogICAgICovCiAgICBnZXQodW5pdCkgewogICAgICByZXR1cm4gdGhpc1tEdXJhdGlvbi5ub3JtYWxpemVVbml0KHVuaXQpXTsKICAgIH0KCiAgICAvKioKICAgICAqICJTZXQiIHRoZSB2YWx1ZXMgb2Ygc3BlY2lmaWVkIHVuaXRzLiBSZXR1cm4gYSBuZXdseS1jb25zdHJ1Y3RlZCBEdXJhdGlvbi4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSB2YWx1ZXMgLSBhIG1hcHBpbmcgb2YgdW5pdHMgdG8gbnVtYmVycwogICAgICogQGV4YW1wbGUgZHVyLnNldCh7IHllYXJzOiAyMDE3IH0pCiAgICAgKiBAZXhhbXBsZSBkdXIuc2V0KHsgaG91cnM6IDgsIG1pbnV0ZXM6IDMwIH0pCiAgICAgKiBAcmV0dXJuIHtEdXJhdGlvbn0KICAgICAqLwogICAgc2V0KHZhbHVlcykgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIHRoaXM7CgogICAgICBjb25zdCBtaXhlZCA9IHsgLi4udGhpcy52YWx1ZXMsIC4uLm5vcm1hbGl6ZU9iamVjdCh2YWx1ZXMsIER1cmF0aW9uLm5vcm1hbGl6ZVVuaXQpIH07CiAgICAgIHJldHVybiBjbG9uZSQxKHRoaXMsIHsgdmFsdWVzOiBtaXhlZCB9KTsKICAgIH0KCiAgICAvKioKICAgICAqICJTZXQiIHRoZSBsb2NhbGUgYW5kL29yIG51bWJlcmluZ1N5c3RlbS4gIFJldHVybnMgYSBuZXdseS1jb25zdHJ1Y3RlZCBEdXJhdGlvbi4KICAgICAqIEBleGFtcGxlIGR1ci5yZWNvbmZpZ3VyZSh7IGxvY2FsZTogJ2VuLUdCJyB9KQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIHJlY29uZmlndXJlKHsgbG9jYWxlLCBudW1iZXJpbmdTeXN0ZW0sIGNvbnZlcnNpb25BY2N1cmFjeSwgbWF0cml4IH0gPSB7fSkgewogICAgICBjb25zdCBsb2MgPSB0aGlzLmxvYy5jbG9uZSh7IGxvY2FsZSwgbnVtYmVyaW5nU3lzdGVtIH0pOwogICAgICBjb25zdCBvcHRzID0geyBsb2MsIG1hdHJpeCwgY29udmVyc2lvbkFjY3VyYWN5IH07CiAgICAgIHJldHVybiBjbG9uZSQxKHRoaXMsIG9wdHMpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIHRoZSBsZW5ndGggb2YgdGhlIGR1cmF0aW9uIGluIHRoZSBzcGVjaWZpZWQgdW5pdC4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1bml0IC0gYSB1bml0IHN1Y2ggYXMgJ21pbnV0ZXMnIG9yICdkYXlzJwogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7eWVhcnM6IDF9KS5hcygnZGF5cycpIC8vPT4gMzY1CiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHt5ZWFyczogMX0pLmFzKCdtb250aHMnKSAvLz0+IDEyCiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHtob3VyczogNjB9KS5hcygnZGF5cycpIC8vPT4gMi41CiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9CiAgICAgKi8KICAgIGFzKHVuaXQpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IHRoaXMuc2hpZnRUbyh1bml0KS5nZXQodW5pdCkgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBSZWR1Y2UgdGhpcyBEdXJhdGlvbiB0byBpdHMgY2Fub25pY2FsIHJlcHJlc2VudGF0aW9uIGluIGl0cyBjdXJyZW50IHVuaXRzLgogICAgICogQXNzdW1pbmcgdGhlIG92ZXJhbGwgdmFsdWUgb2YgdGhlIER1cmF0aW9uIGlzIHBvc2l0aXZlLCB0aGlzIG1lYW5zOgogICAgICogLSBleGNlc3NpdmUgdmFsdWVzIGZvciBsb3dlci1vcmRlciB1bml0cyBhcmUgY29udmVydGVkIHRvIGhpZ2hlci1vcmRlciB1bml0cyAoaWYgcG9zc2libGUsIHNlZSBmaXJzdCBhbmQgc2Vjb25kIGV4YW1wbGUpCiAgICAgKiAtIG5lZ2F0aXZlIGxvd2VyLW9yZGVyIHVuaXRzIGFyZSBjb252ZXJ0ZWQgdG8gaGlnaGVyIG9yZGVyIHVuaXRzICh0aGVyZSBtdXN0IGJlIHN1Y2ggYSBoaWdoZXIgb3JkZXIgdW5pdCwgb3RoZXJ3aXNlCiAgICAgKiAgIHRoZSBvdmVyYWxsIHZhbHVlIHdvdWxkIGJlIG5lZ2F0aXZlLCBzZWUgc2Vjb25kIGV4YW1wbGUpCiAgICAgKiAtIGZyYWN0aW9uYWwgdmFsdWVzIGZvciBoaWdoZXItb3JkZXIgdW5pdHMgYXJlIGNvbnZlcnRlZCB0byBsb3dlci1vcmRlciB1bml0cyAoaWYgcG9zc2libGUsIHNlZSBmb3VydGggZXhhbXBsZSkKICAgICAqCiAgICAgKiBJZiB0aGUgb3ZlcmFsbCB2YWx1ZSBpcyBuZWdhdGl2ZSwgdGhlIHJlc3VsdCBvZiB0aGlzIG1ldGhvZCBpcyBlcXVpdmFsZW50IHRvIGB0aGlzLm5lZ2F0ZSgpLm5vcm1hbGl6ZSgpLm5lZ2F0ZSgpYC4KICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyB5ZWFyczogMiwgZGF5czogNTAwMCB9KS5ub3JtYWxpemUoKS50b09iamVjdCgpIC8vPT4geyB5ZWFyczogMTUsIGRheXM6IDI1NSB9CiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgZGF5czogNTAwMCB9KS5ub3JtYWxpemUoKS50b09iamVjdCgpIC8vPT4geyBkYXlzOiA1MDAwIH0KICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyBob3VyczogMTIsIG1pbnV0ZXM6IC00NSB9KS5ub3JtYWxpemUoKS50b09iamVjdCgpIC8vPT4geyBob3VyczogMTEsIG1pbnV0ZXM6IDE1IH0KICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyB5ZWFyczogMi41LCBkYXlzOiAwLCBob3VyczogMCB9KS5ub3JtYWxpemUoKS50b09iamVjdCgpIC8vPT4geyB5ZWFyczogMiwgZGF5czogMTgyLCBob3VyczogMTIgfQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIG5vcm1hbGl6ZSgpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiB0aGlzOwogICAgICBjb25zdCB2YWxzID0gdGhpcy50b09iamVjdCgpOwogICAgICBub3JtYWxpemVWYWx1ZXModGhpcy5tYXRyaXgsIHZhbHMpOwogICAgICByZXR1cm4gY2xvbmUkMSh0aGlzLCB7IHZhbHVlczogdmFscyB9LCB0cnVlKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJlc2NhbGUgdW5pdHMgdG8gaXRzIGxhcmdlc3QgcmVwcmVzZW50YXRpb24KICAgICAqIEBleGFtcGxlIER1cmF0aW9uLmZyb21PYmplY3QoeyBtaWxsaXNlY29uZHM6IDkwMDAwIH0pLnJlc2NhbGUoKS50b09iamVjdCgpIC8vPT4geyBtaW51dGVzOiAxLCBzZWNvbmRzOiAzMCB9CiAgICAgKiBAcmV0dXJuIHtEdXJhdGlvbn0KICAgICAqLwogICAgcmVzY2FsZSgpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiB0aGlzOwogICAgICBjb25zdCB2YWxzID0gcmVtb3ZlWmVyb2VzKHRoaXMubm9ybWFsaXplKCkuc2hpZnRUb0FsbCgpLnRvT2JqZWN0KCkpOwogICAgICByZXR1cm4gY2xvbmUkMSh0aGlzLCB7IHZhbHVlczogdmFscyB9LCB0cnVlKTsKICAgIH0KCiAgICAvKioKICAgICAqIENvbnZlcnQgdGhpcyBEdXJhdGlvbiBpbnRvIGl0cyByZXByZXNlbnRhdGlvbiBpbiBhIGRpZmZlcmVudCBzZXQgb2YgdW5pdHMuCiAgICAgKiBAZXhhbXBsZSBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgaG91cnM6IDEsIHNlY29uZHM6IDMwIH0pLnNoaWZ0VG8oJ21pbnV0ZXMnLCAnbWlsbGlzZWNvbmRzJykudG9PYmplY3QoKSAvLz0+IHsgbWludXRlczogNjAsIG1pbGxpc2Vjb25kczogMzAwMDAgfQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIHNoaWZ0VG8oLi4udW5pdHMpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiB0aGlzOwoKICAgICAgaWYgKHVuaXRzLmxlbmd0aCA9PT0gMCkgewogICAgICAgIHJldHVybiB0aGlzOwogICAgICB9CgogICAgICB1bml0cyA9IHVuaXRzLm1hcCgodSkgPT4gRHVyYXRpb24ubm9ybWFsaXplVW5pdCh1KSk7CgogICAgICBjb25zdCBidWlsdCA9IHt9LAogICAgICAgIGFjY3VtdWxhdGVkID0ge30sCiAgICAgICAgdmFscyA9IHRoaXMudG9PYmplY3QoKTsKICAgICAgbGV0IGxhc3RVbml0OwoKICAgICAgZm9yIChjb25zdCBrIG9mIG9yZGVyZWRVbml0cyQxKSB7CiAgICAgICAgaWYgKHVuaXRzLmluZGV4T2YoaykgPj0gMCkgewogICAgICAgICAgbGFzdFVuaXQgPSBrOwoKICAgICAgICAgIGxldCBvd24gPSAwOwoKICAgICAgICAgIC8vIGFueXRoaW5nIHdlIGhhdmVuJ3QgYm9pbGVkIGRvd24geWV0IHNob3VsZCBnZXQgYm9pbGVkIHRvIHRoaXMgdW5pdAogICAgICAgICAgZm9yIChjb25zdCBhayBpbiBhY2N1bXVsYXRlZCkgewogICAgICAgICAgICBvd24gKz0gdGhpcy5tYXRyaXhbYWtdW2tdICogYWNjdW11bGF0ZWRbYWtdOwogICAgICAgICAgICBhY2N1bXVsYXRlZFtha10gPSAwOwogICAgICAgICAgfQoKICAgICAgICAgIC8vIHBsdXMgYW55dGhpbmcgdGhhdCdzIGFscmVhZHkgaW4gdGhpcyB1bml0CiAgICAgICAgICBpZiAoaXNOdW1iZXIodmFsc1trXSkpIHsKICAgICAgICAgICAgb3duICs9IHZhbHNba107CiAgICAgICAgICB9CgogICAgICAgICAgLy8gb25seSBrZWVwIHRoZSBpbnRlZ2VyIHBhcnQgZm9yIG5vdyBpbiB0aGUgaG9wZXMgb2YgcHV0dGluZyBhbnkgZGVjaW1hbCBwYXJ0CiAgICAgICAgICAvLyBpbnRvIGEgc21hbGxlciB1bml0IGxhdGVyCiAgICAgICAgICBjb25zdCBpID0gTWF0aC50cnVuYyhvd24pOwogICAgICAgICAgYnVpbHRba10gPSBpOwogICAgICAgICAgYWNjdW11bGF0ZWRba10gPSAob3duICogMTAwMCAtIGkgKiAxMDAwKSAvIDEwMDA7CgogICAgICAgICAgLy8gb3RoZXJ3aXNlLCBrZWVwIGl0IGluIHRoZSB3aW5ncyB0byBib2lsIGl0IGxhdGVyCiAgICAgICAgfSBlbHNlIGlmIChpc051bWJlcih2YWxzW2tdKSkgewogICAgICAgICAgYWNjdW11bGF0ZWRba10gPSB2YWxzW2tdOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLy8gYW55dGhpbmcgbGVmdG92ZXIgYmVjb21lcyB0aGUgZGVjaW1hbCBmb3IgdGhlIGxhc3QgdW5pdAogICAgICAvLyBsYXN0VW5pdCBtdXN0IGJlIGRlZmluZWQgc2luY2UgdW5pdHMgaXMgbm90IGVtcHR5CiAgICAgIGZvciAoY29uc3Qga2V5IGluIGFjY3VtdWxhdGVkKSB7CiAgICAgICAgaWYgKGFjY3VtdWxhdGVkW2tleV0gIT09IDApIHsKICAgICAgICAgIGJ1aWx0W2xhc3RVbml0XSArPQogICAgICAgICAgICBrZXkgPT09IGxhc3RVbml0ID8gYWNjdW11bGF0ZWRba2V5XSA6IGFjY3VtdWxhdGVkW2tleV0gLyB0aGlzLm1hdHJpeFtsYXN0VW5pdF1ba2V5XTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIG5vcm1hbGl6ZVZhbHVlcyh0aGlzLm1hdHJpeCwgYnVpbHQpOwogICAgICByZXR1cm4gY2xvbmUkMSh0aGlzLCB7IHZhbHVlczogYnVpbHQgfSwgdHJ1ZSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBTaGlmdCB0aGlzIER1cmF0aW9uIHRvIGFsbCBhdmFpbGFibGUgdW5pdHMuCiAgICAgKiBTYW1lIGFzIHNoaWZ0VG8oInllYXJzIiwgIm1vbnRocyIsICJ3ZWVrcyIsICJkYXlzIiwgImhvdXJzIiwgIm1pbnV0ZXMiLCAic2Vjb25kcyIsICJtaWxsaXNlY29uZHMiKQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIHNoaWZ0VG9BbGwoKSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gdGhpczsKICAgICAgcmV0dXJuIHRoaXMuc2hpZnRUbygKICAgICAgICAieWVhcnMiLAogICAgICAgICJtb250aHMiLAogICAgICAgICJ3ZWVrcyIsCiAgICAgICAgImRheXMiLAogICAgICAgICJob3VycyIsCiAgICAgICAgIm1pbnV0ZXMiLAogICAgICAgICJzZWNvbmRzIiwKICAgICAgICAibWlsbGlzZWNvbmRzIgogICAgICApOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIHRoZSBuZWdhdGl2ZSBvZiB0aGlzIER1cmF0aW9uLgogICAgICogQGV4YW1wbGUgRHVyYXRpb24uZnJvbU9iamVjdCh7IGhvdXJzOiAxLCBzZWNvbmRzOiAzMCB9KS5uZWdhdGUoKS50b09iamVjdCgpIC8vPT4geyBob3VyczogLTEsIHNlY29uZHM6IC0zMCB9CiAgICAgKiBAcmV0dXJuIHtEdXJhdGlvbn0KICAgICAqLwogICAgbmVnYXRlKCkgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIHRoaXM7CiAgICAgIGNvbnN0IG5lZ2F0ZWQgPSB7fTsKICAgICAgZm9yIChjb25zdCBrIG9mIE9iamVjdC5rZXlzKHRoaXMudmFsdWVzKSkgewogICAgICAgIG5lZ2F0ZWRba10gPSB0aGlzLnZhbHVlc1trXSA9PT0gMCA/IDAgOiAtdGhpcy52YWx1ZXNba107CiAgICAgIH0KICAgICAgcmV0dXJuIGNsb25lJDEodGhpcywgeyB2YWx1ZXM6IG5lZ2F0ZWQgfSwgdHJ1ZSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIHllYXJzLgogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IHllYXJzKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy52YWx1ZXMueWVhcnMgfHwgMCA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgcXVhcnRlcnMuCiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICovCiAgICBnZXQgcXVhcnRlcnMoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLnZhbHVlcy5xdWFydGVycyB8fCAwIDogTmFOOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBtb250aHMuCiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICovCiAgICBnZXQgbW9udGhzKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy52YWx1ZXMubW9udGhzIHx8IDAgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIHdlZWtzCiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICovCiAgICBnZXQgd2Vla3MoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLnZhbHVlcy53ZWVrcyB8fCAwIDogTmFOOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBkYXlzLgogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IGRheXMoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLnZhbHVlcy5kYXlzIHx8IDAgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIGhvdXJzLgogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IGhvdXJzKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy52YWx1ZXMuaG91cnMgfHwgMCA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgbWludXRlcy4KICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgKi8KICAgIGdldCBtaW51dGVzKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy52YWx1ZXMubWludXRlcyB8fCAwIDogTmFOOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBzZWNvbmRzLgogICAgICogQHJldHVybiB7bnVtYmVyfQogICAgICovCiAgICBnZXQgc2Vjb25kcygpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IHRoaXMudmFsdWVzLnNlY29uZHMgfHwgMCA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgbWlsbGlzZWNvbmRzLgogICAgICogQHJldHVybiB7bnVtYmVyfQogICAgICovCiAgICBnZXQgbWlsbGlzZWNvbmRzKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy52YWx1ZXMubWlsbGlzZWNvbmRzIHx8IDAgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhlIER1cmF0aW9uIGlzIGludmFsaWQuIEludmFsaWQgZHVyYXRpb25zIGFyZSByZXR1cm5lZCBieSBkaWZmIG9wZXJhdGlvbnMKICAgICAqIG9uIGludmFsaWQgRGF0ZVRpbWVzIG9yIEludGVydmFscy4KICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIGdldCBpc1ZhbGlkKCkgewogICAgICByZXR1cm4gdGhpcy5pbnZhbGlkID09PSBudWxsOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhbiBlcnJvciBjb2RlIGlmIHRoaXMgRHVyYXRpb24gYmVjYW1lIGludmFsaWQsIG9yIG51bGwgaWYgdGhlIER1cmF0aW9uIGlzIHZhbGlkCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9CiAgICAgKi8KICAgIGdldCBpbnZhbGlkUmVhc29uKCkgewogICAgICByZXR1cm4gdGhpcy5pbnZhbGlkID8gdGhpcy5pbnZhbGlkLnJlYXNvbiA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGFuIGV4cGxhbmF0aW9uIG9mIHdoeSB0aGlzIER1cmF0aW9uIGJlY2FtZSBpbnZhbGlkLCBvciBudWxsIGlmIHRoZSBEdXJhdGlvbiBpcyB2YWxpZAogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgZ2V0IGludmFsaWRFeHBsYW5hdGlvbigpIHsKICAgICAgcmV0dXJuIHRoaXMuaW52YWxpZCA/IHRoaXMuaW52YWxpZC5leHBsYW5hdGlvbiA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBFcXVhbGl0eSBjaGVjawogICAgICogVHdvIER1cmF0aW9ucyBhcmUgZXF1YWwgaWZmIHRoZXkgaGF2ZSB0aGUgc2FtZSB1bml0cyBhbmQgdGhlIHNhbWUgdmFsdWVzIGZvciBlYWNoIHVuaXQuCiAgICAgKiBAcGFyYW0ge0R1cmF0aW9ufSBvdGhlcgogICAgICogQHJldHVybiB7Ym9vbGVhbn0KICAgICAqLwogICAgZXF1YWxzKG90aGVyKSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkIHx8ICFvdGhlci5pc1ZhbGlkKSB7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICB9CgogICAgICBpZiAoIXRoaXMubG9jLmVxdWFscyhvdGhlci5sb2MpKSB7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICB9CgogICAgICBmdW5jdGlvbiBlcSh2MSwgdjIpIHsKICAgICAgICAvLyBDb25zaWRlciAwIGFuZCB1bmRlZmluZWQgYXMgZXF1YWwKICAgICAgICBpZiAodjEgPT09IHVuZGVmaW5lZCB8fCB2MSA9PT0gMCkgcmV0dXJuIHYyID09PSB1bmRlZmluZWQgfHwgdjIgPT09IDA7CiAgICAgICAgcmV0dXJuIHYxID09PSB2MjsKICAgICAgfQoKICAgICAgZm9yIChjb25zdCB1IG9mIG9yZGVyZWRVbml0cyQxKSB7CiAgICAgICAgaWYgKCFlcSh0aGlzLnZhbHVlc1t1XSwgb3RoZXIudmFsdWVzW3VdKSkgewogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICB9CgogIGNvbnN0IElOVkFMSUQkMSA9ICJJbnZhbGlkIEludGVydmFsIjsKCiAgLy8gY2hlY2tzIGlmIHRoZSBzdGFydCBpcyBlcXVhbCB0byBvciBiZWZvcmUgdGhlIGVuZAogIGZ1bmN0aW9uIHZhbGlkYXRlU3RhcnRFbmQoc3RhcnQsIGVuZCkgewogICAgaWYgKCFzdGFydCB8fCAhc3RhcnQuaXNWYWxpZCkgewogICAgICByZXR1cm4gSW50ZXJ2YWwuaW52YWxpZCgibWlzc2luZyBvciBpbnZhbGlkIHN0YXJ0Iik7CiAgICB9IGVsc2UgaWYgKCFlbmQgfHwgIWVuZC5pc1ZhbGlkKSB7CiAgICAgIHJldHVybiBJbnRlcnZhbC5pbnZhbGlkKCJtaXNzaW5nIG9yIGludmFsaWQgZW5kIik7CiAgICB9IGVsc2UgaWYgKGVuZCA8IHN0YXJ0KSB7CiAgICAgIHJldHVybiBJbnRlcnZhbC5pbnZhbGlkKAogICAgICAgICJlbmQgYmVmb3JlIHN0YXJ0IiwKICAgICAgICBgVGhlIGVuZCBvZiBhbiBpbnRlcnZhbCBtdXN0IGJlIGFmdGVyIGl0cyBzdGFydCwgYnV0IHlvdSBoYWQgc3RhcnQ9JHtzdGFydC50b0lTTygpfSBhbmQgZW5kPSR7ZW5kLnRvSVNPKCl9YAogICAgICApOwogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuIG51bGw7CiAgICB9CiAgfQoKICAvKioKICAgKiBBbiBJbnRlcnZhbCBvYmplY3QgcmVwcmVzZW50cyBhIGhhbGYtb3BlbiBpbnRlcnZhbCBvZiB0aW1lLCB3aGVyZSBlYWNoIGVuZHBvaW50IGlzIGEge0BsaW5rIERhdGVUaW1lfS4gQ29uY2VwdHVhbGx5LCBpdCdzIGEgY29udGFpbmVyIGZvciB0aG9zZSB0d28gZW5kcG9pbnRzLCBhY2NvbXBhbmllZCBieSBtZXRob2RzIGZvciBjcmVhdGluZywgcGFyc2luZywgaW50ZXJyb2dhdGluZywgY29tcGFyaW5nLCB0cmFuc2Zvcm1pbmcsIGFuZCBmb3JtYXR0aW5nIHRoZW0uCiAgICoKICAgKiBIZXJlIGlzIGEgYnJpZWYgb3ZlcnZpZXcgb2YgdGhlIG1vc3QgY29tbW9ubHkgdXNlZCBtZXRob2RzIGFuZCBnZXR0ZXJzIGluIEludGVydmFsOgogICAqCiAgICogKiAqKkNyZWF0aW9uKiogVG8gY3JlYXRlIGFuIEludGVydmFsLCB1c2Uge0BsaW5rIEludGVydmFsLmZyb21EYXRlVGltZXN9LCB7QGxpbmsgSW50ZXJ2YWwuYWZ0ZXJ9LCB7QGxpbmsgSW50ZXJ2YWwuYmVmb3JlfSwgb3Ige0BsaW5rIEludGVydmFsLmZyb21JU099LgogICAqICogKipBY2Nlc3NvcnMqKiBVc2Uge0BsaW5rIEludGVydmFsI3N0YXJ0fSBhbmQge0BsaW5rIEludGVydmFsI2VuZH0gdG8gZ2V0IHRoZSBzdGFydCBhbmQgZW5kLgogICAqICogKipJbnRlcnJvZ2F0aW9uKiogVG8gYW5hbHl6ZSB0aGUgSW50ZXJ2YWwsIHVzZSB7QGxpbmsgSW50ZXJ2YWwjY291bnR9LCB7QGxpbmsgSW50ZXJ2YWwjbGVuZ3RofSwge0BsaW5rIEludGVydmFsI2hhc1NhbWV9LCB7QGxpbmsgSW50ZXJ2YWwjY29udGFpbnN9LCB7QGxpbmsgSW50ZXJ2YWwjaXNBZnRlcn0sIG9yIHtAbGluayBJbnRlcnZhbCNpc0JlZm9yZX0uCiAgICogKiAqKlRyYW5zZm9ybWF0aW9uKiogVG8gY3JlYXRlIG90aGVyIEludGVydmFscyBvdXQgb2YgdGhpcyBvbmUsIHVzZSB7QGxpbmsgSW50ZXJ2YWwjc2V0fSwge0BsaW5rIEludGVydmFsI3NwbGl0QXR9LCB7QGxpbmsgSW50ZXJ2YWwjc3BsaXRCeX0sIHtAbGluayBJbnRlcnZhbCNkaXZpZGVFcXVhbGx5fSwge0BsaW5rIEludGVydmFsLm1lcmdlfSwge0BsaW5rIEludGVydmFsLnhvcn0sIHtAbGluayBJbnRlcnZhbCN1bmlvbn0sIHtAbGluayBJbnRlcnZhbCNpbnRlcnNlY3Rpb259LCBvciB7QGxpbmsgSW50ZXJ2YWwjZGlmZmVyZW5jZX0uCiAgICogKiAqKkNvbXBhcmlzb24qKiBUbyBjb21wYXJlIHRoaXMgSW50ZXJ2YWwgdG8gYW5vdGhlciBvbmUsIHVzZSB7QGxpbmsgSW50ZXJ2YWwjZXF1YWxzfSwge0BsaW5rIEludGVydmFsI292ZXJsYXBzfSwge0BsaW5rIEludGVydmFsI2FidXRzU3RhcnR9LCB7QGxpbmsgSW50ZXJ2YWwjYWJ1dHNFbmR9LCB7QGxpbmsgSW50ZXJ2YWwjZW5ndWxmc30KICAgKiAqICoqT3V0cHV0KiogVG8gY29udmVydCB0aGUgSW50ZXJ2YWwgaW50byBvdGhlciByZXByZXNlbnRhdGlvbnMsIHNlZSB7QGxpbmsgSW50ZXJ2YWwjdG9TdHJpbmd9LCB7QGxpbmsgSW50ZXJ2YWwjdG9Mb2NhbGVTdHJpbmd9LCB7QGxpbmsgSW50ZXJ2YWwjdG9JU099LCB7QGxpbmsgSW50ZXJ2YWwjdG9JU09EYXRlfSwge0BsaW5rIEludGVydmFsI3RvSVNPVGltZX0sIHtAbGluayBJbnRlcnZhbCN0b0Zvcm1hdH0sIGFuZCB7QGxpbmsgSW50ZXJ2YWwjdG9EdXJhdGlvbn0uCiAgICovCiAgY2xhc3MgSW50ZXJ2YWwgewogICAgLyoqCiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBjb25zdHJ1Y3Rvcihjb25maWcpIHsKICAgICAgLyoqCiAgICAgICAqIEBhY2Nlc3MgcHJpdmF0ZQogICAgICAgKi8KICAgICAgdGhpcy5zID0gY29uZmlnLnN0YXJ0OwogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLmUgPSBjb25maWcuZW5kOwogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLmludmFsaWQgPSBjb25maWcuaW52YWxpZCB8fCBudWxsOwogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLmlzTHV4b25JbnRlcnZhbCA9IHRydWU7CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgYW4gaW52YWxpZCBJbnRlcnZhbC4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSByZWFzb24gLSBzaW1wbGUgc3RyaW5nIG9mIHdoeSB0aGlzIEludGVydmFsIGlzIGludmFsaWQuIFNob3VsZCBub3QgY29udGFpbiBwYXJhbWV0ZXJzIG9yIGFueXRoaW5nIGVsc2UgZGF0YS1kZXBlbmRlbnQKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbZXhwbGFuYXRpb249bnVsbF0gLSBsb25nZXIgZXhwbGFuYXRpb24sIG1heSBpbmNsdWRlIHBhcmFtZXRlcnMgYW5kIG90aGVyIHVzZWZ1bCBkZWJ1Z2dpbmcgaW5mb3JtYXRpb24KICAgICAqIEByZXR1cm4ge0ludGVydmFsfQogICAgICovCiAgICBzdGF0aWMgaW52YWxpZChyZWFzb24sIGV4cGxhbmF0aW9uID0gbnVsbCkgewogICAgICBpZiAoIXJlYXNvbikgewogICAgICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRFcnJvcigibmVlZCB0byBzcGVjaWZ5IGEgcmVhc29uIHRoZSBJbnRlcnZhbCBpcyBpbnZhbGlkIik7CiAgICAgIH0KCiAgICAgIGNvbnN0IGludmFsaWQgPSByZWFzb24gaW5zdGFuY2VvZiBJbnZhbGlkID8gcmVhc29uIDogbmV3IEludmFsaWQocmVhc29uLCBleHBsYW5hdGlvbik7CgogICAgICBpZiAoU2V0dGluZ3MudGhyb3dPbkludmFsaWQpIHsKICAgICAgICB0aHJvdyBuZXcgSW52YWxpZEludGVydmFsRXJyb3IoaW52YWxpZCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIG5ldyBJbnRlcnZhbCh7IGludmFsaWQgfSk7CiAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIENyZWF0ZSBhbiBJbnRlcnZhbCBmcm9tIGEgc3RhcnQgRGF0ZVRpbWUgYW5kIGFuIGVuZCBEYXRlVGltZS4gSW5jbHVzaXZlIG9mIHRoZSBzdGFydCBidXQgbm90IHRoZSBlbmQuCiAgICAgKiBAcGFyYW0ge0RhdGVUaW1lfERhdGV8T2JqZWN0fSBzdGFydAogICAgICogQHBhcmFtIHtEYXRlVGltZXxEYXRlfE9iamVjdH0gZW5kCiAgICAgKiBAcmV0dXJuIHtJbnRlcnZhbH0KICAgICAqLwogICAgc3RhdGljIGZyb21EYXRlVGltZXMoc3RhcnQsIGVuZCkgewogICAgICBjb25zdCBidWlsdFN0YXJ0ID0gZnJpZW5kbHlEYXRlVGltZShzdGFydCksCiAgICAgICAgYnVpbHRFbmQgPSBmcmllbmRseURhdGVUaW1lKGVuZCk7CgogICAgICBjb25zdCB2YWxpZGF0ZUVycm9yID0gdmFsaWRhdGVTdGFydEVuZChidWlsdFN0YXJ0LCBidWlsdEVuZCk7CgogICAgICBpZiAodmFsaWRhdGVFcnJvciA9PSBudWxsKSB7CiAgICAgICAgcmV0dXJuIG5ldyBJbnRlcnZhbCh7CiAgICAgICAgICBzdGFydDogYnVpbHRTdGFydCwKICAgICAgICAgIGVuZDogYnVpbHRFbmQsCiAgICAgICAgfSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHZhbGlkYXRlRXJyb3I7CiAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIENyZWF0ZSBhbiBJbnRlcnZhbCBmcm9tIGEgc3RhcnQgRGF0ZVRpbWUgYW5kIGEgRHVyYXRpb24gdG8gZXh0ZW5kIHRvLgogICAgICogQHBhcmFtIHtEYXRlVGltZXxEYXRlfE9iamVjdH0gc3RhcnQKICAgICAqIEBwYXJhbSB7RHVyYXRpb258T2JqZWN0fG51bWJlcn0gZHVyYXRpb24gLSB0aGUgbGVuZ3RoIG9mIHRoZSBJbnRlcnZhbC4KICAgICAqIEByZXR1cm4ge0ludGVydmFsfQogICAgICovCiAgICBzdGF0aWMgYWZ0ZXIoc3RhcnQsIGR1cmF0aW9uKSB7CiAgICAgIGNvbnN0IGR1ciA9IER1cmF0aW9uLmZyb21EdXJhdGlvbkxpa2UoZHVyYXRpb24pLAogICAgICAgIGR0ID0gZnJpZW5kbHlEYXRlVGltZShzdGFydCk7CiAgICAgIHJldHVybiBJbnRlcnZhbC5mcm9tRGF0ZVRpbWVzKGR0LCBkdC5wbHVzKGR1cikpOwogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGFuIEludGVydmFsIGZyb20gYW4gZW5kIERhdGVUaW1lIGFuZCBhIER1cmF0aW9uIHRvIGV4dGVuZCBiYWNrd2FyZHMgdG8uCiAgICAgKiBAcGFyYW0ge0RhdGVUaW1lfERhdGV8T2JqZWN0fSBlbmQKICAgICAqIEBwYXJhbSB7RHVyYXRpb258T2JqZWN0fG51bWJlcn0gZHVyYXRpb24gLSB0aGUgbGVuZ3RoIG9mIHRoZSBJbnRlcnZhbC4KICAgICAqIEByZXR1cm4ge0ludGVydmFsfQogICAgICovCiAgICBzdGF0aWMgYmVmb3JlKGVuZCwgZHVyYXRpb24pIHsKICAgICAgY29uc3QgZHVyID0gRHVyYXRpb24uZnJvbUR1cmF0aW9uTGlrZShkdXJhdGlvbiksCiAgICAgICAgZHQgPSBmcmllbmRseURhdGVUaW1lKGVuZCk7CiAgICAgIHJldHVybiBJbnRlcnZhbC5mcm9tRGF0ZVRpbWVzKGR0Lm1pbnVzKGR1ciksIGR0KTsKICAgIH0KCiAgICAvKioKICAgICAqIENyZWF0ZSBhbiBJbnRlcnZhbCBmcm9tIGFuIElTTyA4NjAxIHN0cmluZy4KICAgICAqIEFjY2VwdHMgYDxzdGFydD4vPGVuZD5gLCBgPHN0YXJ0Pi88ZHVyYXRpb24+YCwgYW5kIGA8ZHVyYXRpb24+LzxlbmQ+YCBmb3JtYXRzLgogICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSB0aGUgSVNPIHN0cmluZyB0byBwYXJzZQogICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRzXSAtIG9wdGlvbnMgdG8gcGFzcyB7QGxpbmsgRGF0ZVRpbWUjZnJvbUlTT30gYW5kIG9wdGlvbmFsbHkge0BsaW5rIER1cmF0aW9uI2Zyb21JU099CiAgICAgKiBAc2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0lTT184NjAxI1RpbWVfaW50ZXJ2YWxzCiAgICAgKiBAcmV0dXJuIHtJbnRlcnZhbH0KICAgICAqLwogICAgc3RhdGljIGZyb21JU08odGV4dCwgb3B0cykgewogICAgICBjb25zdCBbcywgZV0gPSAodGV4dCB8fCAiIikuc3BsaXQoIi8iLCAyKTsKICAgICAgaWYgKHMgJiYgZSkgewogICAgICAgIGxldCBzdGFydCwgc3RhcnRJc1ZhbGlkOwogICAgICAgIHRyeSB7CiAgICAgICAgICBzdGFydCA9IERhdGVUaW1lLmZyb21JU08ocywgb3B0cyk7CiAgICAgICAgICBzdGFydElzVmFsaWQgPSBzdGFydC5pc1ZhbGlkOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIHN0YXJ0SXNWYWxpZCA9IGZhbHNlOwogICAgICAgIH0KCiAgICAgICAgbGV0IGVuZCwgZW5kSXNWYWxpZDsKICAgICAgICB0cnkgewogICAgICAgICAgZW5kID0gRGF0ZVRpbWUuZnJvbUlTTyhlLCBvcHRzKTsKICAgICAgICAgIGVuZElzVmFsaWQgPSBlbmQuaXNWYWxpZDsKICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICBlbmRJc1ZhbGlkID0gZmFsc2U7CiAgICAgICAgfQoKICAgICAgICBpZiAoc3RhcnRJc1ZhbGlkICYmIGVuZElzVmFsaWQpIHsKICAgICAgICAgIHJldHVybiBJbnRlcnZhbC5mcm9tRGF0ZVRpbWVzKHN0YXJ0LCBlbmQpOwogICAgICAgIH0KCiAgICAgICAgaWYgKHN0YXJ0SXNWYWxpZCkgewogICAgICAgICAgY29uc3QgZHVyID0gRHVyYXRpb24uZnJvbUlTTyhlLCBvcHRzKTsKICAgICAgICAgIGlmIChkdXIuaXNWYWxpZCkgewogICAgICAgICAgICByZXR1cm4gSW50ZXJ2YWwuYWZ0ZXIoc3RhcnQsIGR1cik7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIGlmIChlbmRJc1ZhbGlkKSB7CiAgICAgICAgICBjb25zdCBkdXIgPSBEdXJhdGlvbi5mcm9tSVNPKHMsIG9wdHMpOwogICAgICAgICAgaWYgKGR1ci5pc1ZhbGlkKSB7CiAgICAgICAgICAgIHJldHVybiBJbnRlcnZhbC5iZWZvcmUoZW5kLCBkdXIpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gSW50ZXJ2YWwuaW52YWxpZCgidW5wYXJzYWJsZSIsIGB0aGUgaW5wdXQgIiR7dGV4dH0iIGNhbid0IGJlIHBhcnNlZCBhcyBJU08gODYwMWApOwogICAgfQoKICAgIC8qKgogICAgICogQ2hlY2sgaWYgYW4gb2JqZWN0IGlzIGFuIEludGVydmFsLiBXb3JrcyBhY3Jvc3MgY29udGV4dCBib3VuZGFyaWVzCiAgICAgKiBAcGFyYW0ge29iamVjdH0gbwogICAgICogQHJldHVybiB7Ym9vbGVhbn0KICAgICAqLwogICAgc3RhdGljIGlzSW50ZXJ2YWwobykgewogICAgICByZXR1cm4gKG8gJiYgby5pc0x1eG9uSW50ZXJ2YWwpIHx8IGZhbHNlOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyB0aGUgc3RhcnQgb2YgdGhlIEludGVydmFsCiAgICAgKiBAdHlwZSB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIGdldCBzdGFydCgpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IHRoaXMucyA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBlbmQgb2YgdGhlIEludGVydmFsCiAgICAgKiBAdHlwZSB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIGdldCBlbmQoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLmUgOiBudWxsOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyB3aGV0aGVyIHRoaXMgSW50ZXJ2YWwncyBlbmQgaXMgYXQgbGVhc3QgaXRzIHN0YXJ0LCBtZWFuaW5nIHRoYXQgdGhlIEludGVydmFsIGlzbid0ICdiYWNrd2FyZHMnLgogICAgICogQHR5cGUge2Jvb2xlYW59CiAgICAgKi8KICAgIGdldCBpc1ZhbGlkKCkgewogICAgICByZXR1cm4gdGhpcy5pbnZhbGlkUmVhc29uID09PSBudWxsOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhbiBlcnJvciBjb2RlIGlmIHRoaXMgSW50ZXJ2YWwgaXMgaW52YWxpZCwgb3IgbnVsbCBpZiB0aGUgSW50ZXJ2YWwgaXMgdmFsaWQKICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIGdldCBpbnZhbGlkUmVhc29uKCkgewogICAgICByZXR1cm4gdGhpcy5pbnZhbGlkID8gdGhpcy5pbnZhbGlkLnJlYXNvbiA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGFuIGV4cGxhbmF0aW9uIG9mIHdoeSB0aGlzIEludGVydmFsIGJlY2FtZSBpbnZhbGlkLCBvciBudWxsIGlmIHRoZSBJbnRlcnZhbCBpcyB2YWxpZAogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgZ2V0IGludmFsaWRFeHBsYW5hdGlvbigpIHsKICAgICAgcmV0dXJuIHRoaXMuaW52YWxpZCA/IHRoaXMuaW52YWxpZC5leHBsYW5hdGlvbiA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBsZW5ndGggb2YgdGhlIEludGVydmFsIGluIHRoZSBzcGVjaWZpZWQgdW5pdC4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1bml0IC0gdGhlIHVuaXQgKHN1Y2ggYXMgJ2hvdXJzJyBvciAnZGF5cycpIHRvIHJldHVybiB0aGUgbGVuZ3RoIGluLgogICAgICogQHJldHVybiB7bnVtYmVyfQogICAgICovCiAgICBsZW5ndGgodW5pdCA9ICJtaWxsaXNlY29uZHMiKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLnRvRHVyYXRpb24oLi4uW3VuaXRdKS5nZXQodW5pdCkgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBjb3VudCBvZiBtaW51dGVzLCBob3VycywgZGF5cywgbW9udGhzLCBvciB5ZWFycyBpbmNsdWRlZCBpbiB0aGUgSW50ZXJ2YWwsIGV2ZW4gaW4gcGFydC4KICAgICAqIFVubGlrZSB7QGxpbmsgSW50ZXJ2YWwjbGVuZ3RofSB0aGlzIGNvdW50cyBzZWN0aW9ucyBvZiB0aGUgY2FsZW5kYXIsIG5vdCBwZXJpb2RzIG9mIHRpbWUsIGUuZy4gc3BlY2lmeWluZyAnZGF5JwogICAgICogYXNrcyAnd2hhdCBkYXRlcyBhcmUgaW5jbHVkZWQgaW4gdGhpcyBpbnRlcnZhbD8nLCBub3QgJ2hvdyBtYW55IGRheXMgbG9uZyBpcyB0aGlzIGludGVydmFsPycKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbdW5pdD0nbWlsbGlzZWNvbmRzJ10gLSB0aGUgdW5pdCBvZiB0aW1lIHRvIGNvdW50LgogICAgICogQHJldHVybiB7bnVtYmVyfQogICAgICovCiAgICBjb3VudCh1bml0ID0gIm1pbGxpc2Vjb25kcyIpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiBOYU47CiAgICAgIGNvbnN0IHN0YXJ0ID0gdGhpcy5zdGFydC5zdGFydE9mKHVuaXQpLAogICAgICAgIGVuZCA9IHRoaXMuZW5kLnN0YXJ0T2YodW5pdCk7CiAgICAgIHJldHVybiBNYXRoLmZsb29yKGVuZC5kaWZmKHN0YXJ0LCB1bml0KS5nZXQodW5pdCkpICsgKGVuZC52YWx1ZU9mKCkgIT09IHRoaXMuZW5kLnZhbHVlT2YoKSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhpcyBJbnRlcnZhbCdzIHN0YXJ0IGFuZCBlbmQgYXJlIGJvdGggaW4gdGhlIHNhbWUgdW5pdCBvZiB0aW1lCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdW5pdCAtIHRoZSB1bml0IG9mIHRpbWUgdG8gY2hlY2sgc2FtZW5lc3Mgb24KICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIGhhc1NhbWUodW5pdCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy5pc0VtcHR5KCkgfHwgdGhpcy5lLm1pbnVzKDEpLmhhc1NhbWUodGhpcy5zLCB1bml0KSA6IGZhbHNlOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIHdoZXRoZXIgdGhpcyBJbnRlcnZhbCBoYXMgdGhlIHNhbWUgc3RhcnQgYW5kIGVuZCBEYXRlVGltZXMuCiAgICAgKiBAcmV0dXJuIHtib29sZWFufQogICAgICovCiAgICBpc0VtcHR5KCkgewogICAgICByZXR1cm4gdGhpcy5zLnZhbHVlT2YoKSA9PT0gdGhpcy5lLnZhbHVlT2YoKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiB3aGV0aGVyIHRoaXMgSW50ZXJ2YWwncyBzdGFydCBpcyBhZnRlciB0aGUgc3BlY2lmaWVkIERhdGVUaW1lLgogICAgICogQHBhcmFtIHtEYXRlVGltZX0gZGF0ZVRpbWUKICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIGlzQWZ0ZXIoZGF0ZVRpbWUpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiBmYWxzZTsKICAgICAgcmV0dXJuIHRoaXMucyA+IGRhdGVUaW1lOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIHdoZXRoZXIgdGhpcyBJbnRlcnZhbCdzIGVuZCBpcyBiZWZvcmUgdGhlIHNwZWNpZmllZCBEYXRlVGltZS4KICAgICAqIEBwYXJhbSB7RGF0ZVRpbWV9IGRhdGVUaW1lCiAgICAgKiBAcmV0dXJuIHtib29sZWFufQogICAgICovCiAgICBpc0JlZm9yZShkYXRlVGltZSkgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIGZhbHNlOwogICAgICByZXR1cm4gdGhpcy5lIDw9IGRhdGVUaW1lOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIHdoZXRoZXIgdGhpcyBJbnRlcnZhbCBjb250YWlucyB0aGUgc3BlY2lmaWVkIERhdGVUaW1lLgogICAgICogQHBhcmFtIHtEYXRlVGltZX0gZGF0ZVRpbWUKICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIGNvbnRhaW5zKGRhdGVUaW1lKSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gZmFsc2U7CiAgICAgIHJldHVybiB0aGlzLnMgPD0gZGF0ZVRpbWUgJiYgdGhpcy5lID4gZGF0ZVRpbWU7CiAgICB9CgogICAgLyoqCiAgICAgKiAiU2V0cyIgdGhlIHN0YXJ0IGFuZC9vciBlbmQgZGF0ZXMuIFJldHVybnMgYSBuZXdseS1jb25zdHJ1Y3RlZCBJbnRlcnZhbC4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSB2YWx1ZXMgLSB0aGUgdmFsdWVzIHRvIHNldAogICAgICogQHBhcmFtIHtEYXRlVGltZX0gdmFsdWVzLnN0YXJ0IC0gdGhlIHN0YXJ0aW5nIERhdGVUaW1lCiAgICAgKiBAcGFyYW0ge0RhdGVUaW1lfSB2YWx1ZXMuZW5kIC0gdGhlIGVuZGluZyBEYXRlVGltZQogICAgICogQHJldHVybiB7SW50ZXJ2YWx9CiAgICAgKi8KICAgIHNldCh7IHN0YXJ0LCBlbmQgfSA9IHt9KSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gdGhpczsKICAgICAgcmV0dXJuIEludGVydmFsLmZyb21EYXRlVGltZXMoc3RhcnQgfHwgdGhpcy5zLCBlbmQgfHwgdGhpcy5lKTsKICAgIH0KCiAgICAvKioKICAgICAqIFNwbGl0IHRoaXMgSW50ZXJ2YWwgYXQgZWFjaCBvZiB0aGUgc3BlY2lmaWVkIERhdGVUaW1lcwogICAgICogQHBhcmFtIHsuLi5EYXRlVGltZX0gZGF0ZVRpbWVzIC0gdGhlIHVuaXQgb2YgdGltZSB0byBjb3VudC4KICAgICAqIEByZXR1cm4ge0FycmF5fQogICAgICovCiAgICBzcGxpdEF0KC4uLmRhdGVUaW1lcykgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIFtdOwogICAgICBjb25zdCBzb3J0ZWQgPSBkYXRlVGltZXMKICAgICAgICAgIC5tYXAoZnJpZW5kbHlEYXRlVGltZSkKICAgICAgICAgIC5maWx0ZXIoKGQpID0+IHRoaXMuY29udGFpbnMoZCkpCiAgICAgICAgICAuc29ydCgpLAogICAgICAgIHJlc3VsdHMgPSBbXTsKICAgICAgbGV0IHsgcyB9ID0gdGhpcywKICAgICAgICBpID0gMDsKCiAgICAgIHdoaWxlIChzIDwgdGhpcy5lKSB7CiAgICAgICAgY29uc3QgYWRkZWQgPSBzb3J0ZWRbaV0gfHwgdGhpcy5lLAogICAgICAgICAgbmV4dCA9ICthZGRlZCA+ICt0aGlzLmUgPyB0aGlzLmUgOiBhZGRlZDsKICAgICAgICByZXN1bHRzLnB1c2goSW50ZXJ2YWwuZnJvbURhdGVUaW1lcyhzLCBuZXh0KSk7CiAgICAgICAgcyA9IG5leHQ7CiAgICAgICAgaSArPSAxOwogICAgICB9CgogICAgICByZXR1cm4gcmVzdWx0czsKICAgIH0KCiAgICAvKioKICAgICAqIFNwbGl0IHRoaXMgSW50ZXJ2YWwgaW50byBzbWFsbGVyIEludGVydmFscywgZWFjaCBvZiB0aGUgc3BlY2lmaWVkIGxlbmd0aC4KICAgICAqIExlZnQgb3ZlciB0aW1lIGlzIGdyb3VwZWQgaW50byBhIHNtYWxsZXIgaW50ZXJ2YWwKICAgICAqIEBwYXJhbSB7RHVyYXRpb258T2JqZWN0fG51bWJlcn0gZHVyYXRpb24gLSBUaGUgbGVuZ3RoIG9mIGVhY2ggcmVzdWx0aW5nIGludGVydmFsLgogICAgICogQHJldHVybiB7QXJyYXl9CiAgICAgKi8KICAgIHNwbGl0QnkoZHVyYXRpb24pIHsKICAgICAgY29uc3QgZHVyID0gRHVyYXRpb24uZnJvbUR1cmF0aW9uTGlrZShkdXJhdGlvbik7CgogICAgICBpZiAoIXRoaXMuaXNWYWxpZCB8fCAhZHVyLmlzVmFsaWQgfHwgZHVyLmFzKCJtaWxsaXNlY29uZHMiKSA9PT0gMCkgewogICAgICAgIHJldHVybiBbXTsKICAgICAgfQoKICAgICAgbGV0IHsgcyB9ID0gdGhpcywKICAgICAgICBpZHggPSAxLAogICAgICAgIG5leHQ7CgogICAgICBjb25zdCByZXN1bHRzID0gW107CiAgICAgIHdoaWxlIChzIDwgdGhpcy5lKSB7CiAgICAgICAgY29uc3QgYWRkZWQgPSB0aGlzLnN0YXJ0LnBsdXMoZHVyLm1hcFVuaXRzKCh4KSA9PiB4ICogaWR4KSk7CiAgICAgICAgbmV4dCA9ICthZGRlZCA+ICt0aGlzLmUgPyB0aGlzLmUgOiBhZGRlZDsKICAgICAgICByZXN1bHRzLnB1c2goSW50ZXJ2YWwuZnJvbURhdGVUaW1lcyhzLCBuZXh0KSk7CiAgICAgICAgcyA9IG5leHQ7CiAgICAgICAgaWR4ICs9IDE7CiAgICAgIH0KCiAgICAgIHJldHVybiByZXN1bHRzOwogICAgfQoKICAgIC8qKgogICAgICogU3BsaXQgdGhpcyBJbnRlcnZhbCBpbnRvIHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIHNtYWxsZXIgaW50ZXJ2YWxzLgogICAgICogQHBhcmFtIHtudW1iZXJ9IG51bWJlck9mUGFydHMgLSBUaGUgbnVtYmVyIG9mIEludGVydmFscyB0byBkaXZpZGUgdGhlIEludGVydmFsIGludG8uCiAgICAgKiBAcmV0dXJuIHtBcnJheX0KICAgICAqLwogICAgZGl2aWRlRXF1YWxseShudW1iZXJPZlBhcnRzKSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gW107CiAgICAgIHJldHVybiB0aGlzLnNwbGl0QnkodGhpcy5sZW5ndGgoKSAvIG51bWJlck9mUGFydHMpLnNsaWNlKDAsIG51bWJlck9mUGFydHMpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIHdoZXRoZXIgdGhpcyBJbnRlcnZhbCBvdmVybGFwcyB3aXRoIHRoZSBzcGVjaWZpZWQgSW50ZXJ2YWwKICAgICAqIEBwYXJhbSB7SW50ZXJ2YWx9IG90aGVyCiAgICAgKiBAcmV0dXJuIHtib29sZWFufQogICAgICovCiAgICBvdmVybGFwcyhvdGhlcikgewogICAgICByZXR1cm4gdGhpcy5lID4gb3RoZXIucyAmJiB0aGlzLnMgPCBvdGhlci5lOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIHdoZXRoZXIgdGhpcyBJbnRlcnZhbCdzIGVuZCBpcyBhZGphY2VudCB0byB0aGUgc3BlY2lmaWVkIEludGVydmFsJ3Mgc3RhcnQuCiAgICAgKiBAcGFyYW0ge0ludGVydmFsfSBvdGhlcgogICAgICogQHJldHVybiB7Ym9vbGVhbn0KICAgICAqLwogICAgYWJ1dHNTdGFydChvdGhlcikgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIGZhbHNlOwogICAgICByZXR1cm4gK3RoaXMuZSA9PT0gK290aGVyLnM7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gd2hldGhlciB0aGlzIEludGVydmFsJ3Mgc3RhcnQgaXMgYWRqYWNlbnQgdG8gdGhlIHNwZWNpZmllZCBJbnRlcnZhbCdzIGVuZC4KICAgICAqIEBwYXJhbSB7SW50ZXJ2YWx9IG90aGVyCiAgICAgKiBAcmV0dXJuIHtib29sZWFufQogICAgICovCiAgICBhYnV0c0VuZChvdGhlcikgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIGZhbHNlOwogICAgICByZXR1cm4gK290aGVyLmUgPT09ICt0aGlzLnM7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gd2hldGhlciB0aGlzIEludGVydmFsIGVuZ3VsZnMgdGhlIHN0YXJ0IGFuZCBlbmQgb2YgdGhlIHNwZWNpZmllZCBJbnRlcnZhbC4KICAgICAqIEBwYXJhbSB7SW50ZXJ2YWx9IG90aGVyCiAgICAgKiBAcmV0dXJuIHtib29sZWFufQogICAgICovCiAgICBlbmd1bGZzKG90aGVyKSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gZmFsc2U7CiAgICAgIHJldHVybiB0aGlzLnMgPD0gb3RoZXIucyAmJiB0aGlzLmUgPj0gb3RoZXIuZTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiB3aGV0aGVyIHRoaXMgSW50ZXJ2YWwgaGFzIHRoZSBzYW1lIHN0YXJ0IGFuZCBlbmQgYXMgdGhlIHNwZWNpZmllZCBJbnRlcnZhbC4KICAgICAqIEBwYXJhbSB7SW50ZXJ2YWx9IG90aGVyCiAgICAgKiBAcmV0dXJuIHtib29sZWFufQogICAgICovCiAgICBlcXVhbHMob3RoZXIpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQgfHwgIW90aGVyLmlzVmFsaWQpIHsKICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgIH0KCiAgICAgIHJldHVybiB0aGlzLnMuZXF1YWxzKG90aGVyLnMpICYmIHRoaXMuZS5lcXVhbHMob3RoZXIuZSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gYW4gSW50ZXJ2YWwgcmVwcmVzZW50aW5nIHRoZSBpbnRlcnNlY3Rpb24gb2YgdGhpcyBJbnRlcnZhbCBhbmQgdGhlIHNwZWNpZmllZCBJbnRlcnZhbC4KICAgICAqIFNwZWNpZmljYWxseSwgdGhlIHJlc3VsdGluZyBJbnRlcnZhbCBoYXMgdGhlIG1heGltdW0gc3RhcnQgdGltZSBhbmQgdGhlIG1pbmltdW0gZW5kIHRpbWUgb2YgdGhlIHR3byBJbnRlcnZhbHMuCiAgICAgKiBSZXR1cm5zIG51bGwgaWYgdGhlIGludGVyc2VjdGlvbiBpcyBlbXB0eSwgbWVhbmluZywgdGhlIGludGVydmFscyBkb24ndCBpbnRlcnNlY3QuCiAgICAgKiBAcGFyYW0ge0ludGVydmFsfSBvdGhlcgogICAgICogQHJldHVybiB7SW50ZXJ2YWx9CiAgICAgKi8KICAgIGludGVyc2VjdGlvbihvdGhlcikgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIHRoaXM7CiAgICAgIGNvbnN0IHMgPSB0aGlzLnMgPiBvdGhlci5zID8gdGhpcy5zIDogb3RoZXIucywKICAgICAgICBlID0gdGhpcy5lIDwgb3RoZXIuZSA/IHRoaXMuZSA6IG90aGVyLmU7CgogICAgICBpZiAocyA+PSBlKSB7CiAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEludGVydmFsLmZyb21EYXRlVGltZXMocywgZSk7CiAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiBhbiBJbnRlcnZhbCByZXByZXNlbnRpbmcgdGhlIHVuaW9uIG9mIHRoaXMgSW50ZXJ2YWwgYW5kIHRoZSBzcGVjaWZpZWQgSW50ZXJ2YWwuCiAgICAgKiBTcGVjaWZpY2FsbHksIHRoZSByZXN1bHRpbmcgSW50ZXJ2YWwgaGFzIHRoZSBtaW5pbXVtIHN0YXJ0IHRpbWUgYW5kIHRoZSBtYXhpbXVtIGVuZCB0aW1lIG9mIHRoZSB0d28gSW50ZXJ2YWxzLgogICAgICogQHBhcmFtIHtJbnRlcnZhbH0gb3RoZXIKICAgICAqIEByZXR1cm4ge0ludGVydmFsfQogICAgICovCiAgICB1bmlvbihvdGhlcikgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIHRoaXM7CiAgICAgIGNvbnN0IHMgPSB0aGlzLnMgPCBvdGhlci5zID8gdGhpcy5zIDogb3RoZXIucywKICAgICAgICBlID0gdGhpcy5lID4gb3RoZXIuZSA/IHRoaXMuZSA6IG90aGVyLmU7CiAgICAgIHJldHVybiBJbnRlcnZhbC5mcm9tRGF0ZVRpbWVzKHMsIGUpOwogICAgfQoKICAgIC8qKgogICAgICogTWVyZ2UgYW4gYXJyYXkgb2YgSW50ZXJ2YWxzIGludG8gYSBlcXVpdmFsZW50IG1pbmltYWwgc2V0IG9mIEludGVydmFscy4KICAgICAqIENvbWJpbmVzIG92ZXJsYXBwaW5nIGFuZCBhZGphY2VudCBJbnRlcnZhbHMuCiAgICAgKiBAcGFyYW0ge0FycmF5fSBpbnRlcnZhbHMKICAgICAqIEByZXR1cm4ge0FycmF5fQogICAgICovCiAgICBzdGF0aWMgbWVyZ2UoaW50ZXJ2YWxzKSB7CiAgICAgIGNvbnN0IFtmb3VuZCwgZmluYWxdID0gaW50ZXJ2YWxzCiAgICAgICAgLnNvcnQoKGEsIGIpID0+IGEucyAtIGIucykKICAgICAgICAucmVkdWNlKAogICAgICAgICAgKFtzb2ZhciwgY3VycmVudF0sIGl0ZW0pID0+IHsKICAgICAgICAgICAgaWYgKCFjdXJyZW50KSB7CiAgICAgICAgICAgICAgcmV0dXJuIFtzb2ZhciwgaXRlbV07CiAgICAgICAgICAgIH0gZWxzZSBpZiAoY3VycmVudC5vdmVybGFwcyhpdGVtKSB8fCBjdXJyZW50LmFidXRzU3RhcnQoaXRlbSkpIHsKICAgICAgICAgICAgICByZXR1cm4gW3NvZmFyLCBjdXJyZW50LnVuaW9uKGl0ZW0pXTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICByZXR1cm4gW3NvZmFyLmNvbmNhdChbY3VycmVudF0pLCBpdGVtXTsKICAgICAgICAgICAgfQogICAgICAgICAgfSwKICAgICAgICAgIFtbXSwgbnVsbF0KICAgICAgICApOwogICAgICBpZiAoZmluYWwpIHsKICAgICAgICBmb3VuZC5wdXNoKGZpbmFsKTsKICAgICAgfQogICAgICByZXR1cm4gZm91bmQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gYW4gYXJyYXkgb2YgSW50ZXJ2YWxzIHJlcHJlc2VudGluZyB0aGUgc3BhbnMgb2YgdGltZSB0aGF0IG9ubHkgYXBwZWFyIGluIG9uZSBvZiB0aGUgc3BlY2lmaWVkIEludGVydmFscy4KICAgICAqIEBwYXJhbSB7QXJyYXl9IGludGVydmFscwogICAgICogQHJldHVybiB7QXJyYXl9CiAgICAgKi8KICAgIHN0YXRpYyB4b3IoaW50ZXJ2YWxzKSB7CiAgICAgIGxldCBzdGFydCA9IG51bGwsCiAgICAgICAgY3VycmVudENvdW50ID0gMDsKICAgICAgY29uc3QgcmVzdWx0cyA9IFtdLAogICAgICAgIGVuZHMgPSBpbnRlcnZhbHMubWFwKChpKSA9PiBbCiAgICAgICAgICB7IHRpbWU6IGkucywgdHlwZTogInMiIH0sCiAgICAgICAgICB7IHRpbWU6IGkuZSwgdHlwZTogImUiIH0sCiAgICAgICAgXSksCiAgICAgICAgZmxhdHRlbmVkID0gQXJyYXkucHJvdG90eXBlLmNvbmNhdCguLi5lbmRzKSwKICAgICAgICBhcnIgPSBmbGF0dGVuZWQuc29ydCgoYSwgYikgPT4gYS50aW1lIC0gYi50aW1lKTsKCiAgICAgIGZvciAoY29uc3QgaSBvZiBhcnIpIHsKICAgICAgICBjdXJyZW50Q291bnQgKz0gaS50eXBlID09PSAicyIgPyAxIDogLTE7CgogICAgICAgIGlmIChjdXJyZW50Q291bnQgPT09IDEpIHsKICAgICAgICAgIHN0YXJ0ID0gaS50aW1lOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBpZiAoc3RhcnQgJiYgK3N0YXJ0ICE9PSAraS50aW1lKSB7CiAgICAgICAgICAgIHJlc3VsdHMucHVzaChJbnRlcnZhbC5mcm9tRGF0ZVRpbWVzKHN0YXJ0LCBpLnRpbWUpKTsKICAgICAgICAgIH0KCiAgICAgICAgICBzdGFydCA9IG51bGw7CiAgICAgICAgfQogICAgICB9CgogICAgICByZXR1cm4gSW50ZXJ2YWwubWVyZ2UocmVzdWx0cyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gYW4gSW50ZXJ2YWwgcmVwcmVzZW50aW5nIHRoZSBzcGFuIG9mIHRpbWUgaW4gdGhpcyBJbnRlcnZhbCB0aGF0IGRvZXNuJ3Qgb3ZlcmxhcCB3aXRoIGFueSBvZiB0aGUgc3BlY2lmaWVkIEludGVydmFscy4KICAgICAqIEBwYXJhbSB7Li4uSW50ZXJ2YWx9IGludGVydmFscwogICAgICogQHJldHVybiB7QXJyYXl9CiAgICAgKi8KICAgIGRpZmZlcmVuY2UoLi4uaW50ZXJ2YWxzKSB7CiAgICAgIHJldHVybiBJbnRlcnZhbC54b3IoW3RoaXNdLmNvbmNhdChpbnRlcnZhbHMpKQogICAgICAgIC5tYXAoKGkpID0+IHRoaXMuaW50ZXJzZWN0aW9uKGkpKQogICAgICAgIC5maWx0ZXIoKGkpID0+IGkgJiYgIWkuaXNFbXB0eSgpKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhpcyBJbnRlcnZhbCBhcHByb3ByaWF0ZSBmb3IgZGVidWdnaW5nLgogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b1N0cmluZygpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiBJTlZBTElEJDE7CiAgICAgIHJldHVybiBgWyR7dGhpcy5zLnRvSVNPKCl9IOKAkyAke3RoaXMuZS50b0lTTygpfSlgOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIGxvY2FsaXplZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoaXMgSW50ZXJ2YWwuIEFjY2VwdHMgdGhlIHNhbWUgb3B0aW9ucyBhcyB0aGUKICAgICAqIEludGwuRGF0ZVRpbWVGb3JtYXQgY29uc3RydWN0b3IgYW5kIGFueSBwcmVzZXRzIGRlZmluZWQgYnkgTHV4b24sIHN1Y2ggYXMKICAgICAqIHtAbGluayBEYXRlVGltZS5EQVRFX0ZVTEx9IG9yIHtAbGluayBEYXRlVGltZS5USU1FX1NJTVBMRX0uIFRoZSBleGFjdCBiZWhhdmlvciBvZiB0aGlzIG1ldGhvZAogICAgICogaXMgYnJvd3Nlci1zcGVjaWZpYywgYnV0IGluIGdlbmVyYWwgaXQgd2lsbCByZXR1cm4gYW4gYXBwcm9wcmlhdGUgcmVwcmVzZW50YXRpb24gb2YgdGhlCiAgICAgKiBJbnRlcnZhbCBpbiB0aGUgYXNzaWduZWQgbG9jYWxlLiBEZWZhdWx0cyB0byB0aGUgc3lzdGVtJ3MgbG9jYWxlIGlmIG5vIGxvY2FsZSBoYXMgYmVlbgogICAgICogc3BlY2lmaWVkLgogICAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9EYXRlVGltZUZvcm1hdAogICAgICogQHBhcmFtIHtPYmplY3R9IFtmb3JtYXRPcHRzPURhdGVUaW1lLkRBVEVfU0hPUlRdIC0gRWl0aGVyIGEgRGF0ZVRpbWUgcHJlc2V0IG9yCiAgICAgKiBJbnRsLkRhdGVUaW1lRm9ybWF0IGNvbnN0cnVjdG9yIG9wdGlvbnMuCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIE9wdGlvbnMgdG8gb3ZlcnJpZGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgdGhlIHN0YXJ0IERhdGVUaW1lLgogICAgICogQGV4YW1wbGUgSW50ZXJ2YWwuZnJvbUlTTygnMjAyMi0xMS0wN1QwOTowMFovMjAyMi0xMS0wOFQwOTowMFonKS50b0xvY2FsZVN0cmluZygpOyAvLz0+IDExLzcvMjAyMiDigJMgMTEvOC8yMDIyCiAgICAgKiBAZXhhbXBsZSBJbnRlcnZhbC5mcm9tSVNPKCcyMDIyLTExLTA3VDA5OjAwWi8yMDIyLTExLTA4VDA5OjAwWicpLnRvTG9jYWxlU3RyaW5nKERhdGVUaW1lLkRBVEVfRlVMTCk7IC8vPT4gTm92ZW1iZXIgNyDigJMgOCwgMjAyMgogICAgICogQGV4YW1wbGUgSW50ZXJ2YWwuZnJvbUlTTygnMjAyMi0xMS0wN1QwOTowMFovMjAyMi0xMS0wOFQwOTowMFonKS50b0xvY2FsZVN0cmluZyhEYXRlVGltZS5EQVRFX0ZVTEwsIHsgbG9jYWxlOiAnZnItRlInIH0pOyAvLz0+IDfigJM4IG5vdmVtYnJlIDIwMjIKICAgICAqIEBleGFtcGxlIEludGVydmFsLmZyb21JU08oJzIwMjItMTEtMDdUMTc6MDBaLzIwMjItMTEtMDdUMTk6MDBaJykudG9Mb2NhbGVTdHJpbmcoRGF0ZVRpbWUuVElNRV9TSU1QTEUpOyAvLz0+IDY6MDAg4oCTIDg6MDAgUE0KICAgICAqIEBleGFtcGxlIEludGVydmFsLmZyb21JU08oJzIwMjItMTEtMDdUMTc6MDBaLzIwMjItMTEtMDdUMTk6MDBaJykudG9Mb2NhbGVTdHJpbmcoeyB3ZWVrZGF5OiAnc2hvcnQnLCBtb250aDogJ3Nob3J0JywgZGF5OiAnMi1kaWdpdCcsIGhvdXI6ICcyLWRpZ2l0JywgbWludXRlOiAnMi1kaWdpdCcgfSk7IC8vPT4gTW9uLCBOb3YgMDcsIDY6MDAg4oCTIDg6MDAgcAogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b0xvY2FsZVN0cmluZyhmb3JtYXRPcHRzID0gREFURV9TSE9SVCwgb3B0cyA9IHt9KSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQKICAgICAgICA/IEZvcm1hdHRlci5jcmVhdGUodGhpcy5zLmxvYy5jbG9uZShvcHRzKSwgZm9ybWF0T3B0cykuZm9ybWF0SW50ZXJ2YWwodGhpcykKICAgICAgICA6IElOVkFMSUQkMTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYW4gSVNPIDg2MDEtY29tcGxpYW50IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIEludGVydmFsLgogICAgICogQHNlZSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JU09fODYwMSNUaW1lX2ludGVydmFscwogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBUaGUgc2FtZSBvcHRpb25zIGFzIHtAbGluayBEYXRlVGltZSN0b0lTT30KICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9JU08ob3B0cykgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIElOVkFMSUQkMTsKICAgICAgcmV0dXJuIGAke3RoaXMucy50b0lTTyhvcHRzKX0vJHt0aGlzLmUudG9JU08ob3B0cyl9YDsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYW4gSVNPIDg2MDEtY29tcGxpYW50IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBkYXRlIG9mIHRoaXMgSW50ZXJ2YWwuCiAgICAgKiBUaGUgdGltZSBjb21wb25lbnRzIGFyZSBpZ25vcmVkLgogICAgICogQHNlZSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JU09fODYwMSNUaW1lX2ludGVydmFscwogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b0lTT0RhdGUoKSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gSU5WQUxJRCQxOwogICAgICByZXR1cm4gYCR7dGhpcy5zLnRvSVNPRGF0ZSgpfS8ke3RoaXMuZS50b0lTT0RhdGUoKX1gOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhbiBJU08gODYwMS1jb21wbGlhbnQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRpbWUgb2YgdGhpcyBJbnRlcnZhbC4KICAgICAqIFRoZSBkYXRlIGNvbXBvbmVudHMgYXJlIGlnbm9yZWQuCiAgICAgKiBAc2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0lTT184NjAxI1RpbWVfaW50ZXJ2YWxzCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIFRoZSBzYW1lIG9wdGlvbnMgYXMge0BsaW5rIERhdGVUaW1lI3RvSVNPfQogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b0lTT1RpbWUob3B0cykgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIElOVkFMSUQkMTsKICAgICAgcmV0dXJuIGAke3RoaXMucy50b0lTT1RpbWUob3B0cyl9LyR7dGhpcy5lLnRvSVNPVGltZShvcHRzKX1gOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIEludGVydmFsIGZvcm1hdHRlZCBhY2NvcmRpbmcgdG8gdGhlIHNwZWNpZmllZCBmb3JtYXQKICAgICAqIHN0cmluZy4gKipZb3UgbWF5IG5vdCB3YW50IHRoaXMuKiogU2VlIHtAbGluayBJbnRlcnZhbCN0b0xvY2FsZVN0cmluZ30gZm9yIGEgbW9yZSBmbGV4aWJsZQogICAgICogZm9ybWF0dGluZyB0b29sLgogICAgICogQHBhcmFtIHtzdHJpbmd9IGRhdGVGb3JtYXQgLSBUaGUgZm9ybWF0IHN0cmluZy4gVGhpcyBzdHJpbmcgZm9ybWF0cyB0aGUgc3RhcnQgYW5kIGVuZCB0aW1lLgogICAgICogU2VlIHtAbGluayBEYXRlVGltZSN0b0Zvcm1hdH0gZm9yIGRldGFpbHMuCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIE9wdGlvbnMuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMuc2VwYXJhdG9yID0gICcg4oCTICddIC0gQSBzZXBhcmF0b3IgdG8gcGxhY2UgYmV0d2VlbiB0aGUgc3RhcnQgYW5kIGVuZAogICAgICogcmVwcmVzZW50YXRpb25zLgogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b0Zvcm1hdChkYXRlRm9ybWF0LCB7IHNlcGFyYXRvciA9ICIg4oCTICIgfSA9IHt9KSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gSU5WQUxJRCQxOwogICAgICByZXR1cm4gYCR7dGhpcy5zLnRvRm9ybWF0KGRhdGVGb3JtYXQpfSR7c2VwYXJhdG9yfSR7dGhpcy5lLnRvRm9ybWF0KGRhdGVGb3JtYXQpfWA7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gYSBEdXJhdGlvbiByZXByZXNlbnRpbmcgdGhlIHRpbWUgc3Bhbm5lZCBieSB0aGlzIGludGVydmFsLgogICAgICogQHBhcmFtIHtzdHJpbmd8c3RyaW5nW119IFt1bml0PVsnbWlsbGlzZWNvbmRzJ11dIC0gdGhlIHVuaXQgb3IgdW5pdHMgKHN1Y2ggYXMgJ2hvdXJzJyBvciAnZGF5cycpIHRvIGluY2x1ZGUgaW4gdGhlIGR1cmF0aW9uLgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zIHRoYXQgYWZmZWN0IHRoZSBjcmVhdGlvbiBvZiB0aGUgRHVyYXRpb24KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5jb252ZXJzaW9uQWNjdXJhY3k9J2Nhc3VhbCddIC0gdGhlIGNvbnZlcnNpb24gc3lzdGVtIHRvIHVzZQogICAgICogQGV4YW1wbGUgSW50ZXJ2YWwuZnJvbURhdGVUaW1lcyhkdDEsIGR0MikudG9EdXJhdGlvbigpLnRvT2JqZWN0KCkgLy89PiB7IG1pbGxpc2Vjb25kczogODg0ODkyNTcgfQogICAgICogQGV4YW1wbGUgSW50ZXJ2YWwuZnJvbURhdGVUaW1lcyhkdDEsIGR0MikudG9EdXJhdGlvbignZGF5cycpLnRvT2JqZWN0KCkgLy89PiB7IGRheXM6IDEuMDI0MTgxMjE1Mjc3Nzc3OCB9CiAgICAgKiBAZXhhbXBsZSBJbnRlcnZhbC5mcm9tRGF0ZVRpbWVzKGR0MSwgZHQyKS50b0R1cmF0aW9uKFsnaG91cnMnLCAnbWludXRlcyddKS50b09iamVjdCgpIC8vPT4geyBob3VyczogMjQsIG1pbnV0ZXM6IDM0LjgyMDk1IH0KICAgICAqIEBleGFtcGxlIEludGVydmFsLmZyb21EYXRlVGltZXMoZHQxLCBkdDIpLnRvRHVyYXRpb24oWydob3VycycsICdtaW51dGVzJywgJ3NlY29uZHMnXSkudG9PYmplY3QoKSAvLz0+IHsgaG91cnM6IDI0LCBtaW51dGVzOiAzNCwgc2Vjb25kczogNDkuMjU3IH0KICAgICAqIEBleGFtcGxlIEludGVydmFsLmZyb21EYXRlVGltZXMoZHQxLCBkdDIpLnRvRHVyYXRpb24oJ3NlY29uZHMnKS50b09iamVjdCgpIC8vPT4geyBzZWNvbmRzOiA4ODQ4OS4yNTcgfQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIHRvRHVyYXRpb24odW5pdCwgb3B0cykgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgewogICAgICAgIHJldHVybiBEdXJhdGlvbi5pbnZhbGlkKHRoaXMuaW52YWxpZFJlYXNvbik7CiAgICAgIH0KICAgICAgcmV0dXJuIHRoaXMuZS5kaWZmKHRoaXMucywgdW5pdCwgb3B0cyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSdW4gbWFwRm4gb24gdGhlIGludGVydmFsIHN0YXJ0IGFuZCBlbmQsIHJldHVybmluZyBhIG5ldyBJbnRlcnZhbCBmcm9tIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWVzCiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBtYXBGbgogICAgICogQHJldHVybiB7SW50ZXJ2YWx9CiAgICAgKiBAZXhhbXBsZSBJbnRlcnZhbC5mcm9tRGF0ZVRpbWVzKGR0MSwgZHQyKS5tYXBFbmRwb2ludHMoZW5kcG9pbnQgPT4gZW5kcG9pbnQudG9VVEMoKSkKICAgICAqIEBleGFtcGxlIEludGVydmFsLmZyb21EYXRlVGltZXMoZHQxLCBkdDIpLm1hcEVuZHBvaW50cyhlbmRwb2ludCA9PiBlbmRwb2ludC5wbHVzKHsgaG91cnM6IDIgfSkpCiAgICAgKi8KICAgIG1hcEVuZHBvaW50cyhtYXBGbikgewogICAgICByZXR1cm4gSW50ZXJ2YWwuZnJvbURhdGVUaW1lcyhtYXBGbih0aGlzLnMpLCBtYXBGbih0aGlzLmUpKTsKICAgIH0KICB9CgogIC8qKgogICAqIFRoZSBJbmZvIGNsYXNzIGNvbnRhaW5zIHN0YXRpYyBtZXRob2RzIGZvciByZXRyaWV2aW5nIGdlbmVyYWwgdGltZSBhbmQgZGF0ZSByZWxhdGVkIGRhdGEuIEZvciBleGFtcGxlLCBpdCBoYXMgbWV0aG9kcyBmb3IgZmluZGluZyBvdXQgaWYgYSB0aW1lIHpvbmUgaGFzIGEgRFNULCBmb3IgbGlzdGluZyB0aGUgbW9udGhzIGluIGFueSBzdXBwb3J0ZWQgbG9jYWxlLCBhbmQgZm9yIGRpc2NvdmVyaW5nIHdoaWNoIG9mIEx1eG9uIGZlYXR1cmVzIGFyZSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgZW52aXJvbm1lbnQuCiAgICovCiAgY2xhc3MgSW5mbyB7CiAgICAvKioKICAgICAqIFJldHVybiB3aGV0aGVyIHRoZSBzcGVjaWZpZWQgem9uZSBjb250YWlucyBhIERTVC4KICAgICAqIEBwYXJhbSB7c3RyaW5nfFpvbmV9IFt6b25lPSdsb2NhbCddIC0gWm9uZSB0byBjaGVjay4gRGVmYXVsdHMgdG8gdGhlIGVudmlyb25tZW50J3MgbG9jYWwgem9uZS4KICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIHN0YXRpYyBoYXNEU1Qoem9uZSA9IFNldHRpbmdzLmRlZmF1bHRab25lKSB7CiAgICAgIGNvbnN0IHByb3RvID0gRGF0ZVRpbWUubm93KCkuc2V0Wm9uZSh6b25lKS5zZXQoeyBtb250aDogMTIgfSk7CgogICAgICByZXR1cm4gIXpvbmUuaXNVbml2ZXJzYWwgJiYgcHJvdG8ub2Zmc2V0ICE9PSBwcm90by5zZXQoeyBtb250aDogNiB9KS5vZmZzZXQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gd2hldGhlciB0aGUgc3BlY2lmaWVkIHpvbmUgaXMgYSB2YWxpZCBJQU5BIHNwZWNpZmllci4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSB6b25lIC0gWm9uZSB0byBjaGVjawogICAgICogQHJldHVybiB7Ym9vbGVhbn0KICAgICAqLwogICAgc3RhdGljIGlzVmFsaWRJQU5BWm9uZSh6b25lKSB7CiAgICAgIHJldHVybiBJQU5BWm9uZS5pc1ZhbGlkWm9uZSh6b25lKTsKICAgIH0KCiAgICAvKioKICAgICAqIENvbnZlcnRzIHRoZSBpbnB1dCBpbnRvIGEge0BsaW5rIFpvbmV9IGluc3RhbmNlLgogICAgICoKICAgICAqICogSWYgYGlucHV0YCBpcyBhbHJlYWR5IGEgWm9uZSBpbnN0YW5jZSwgaXQgaXMgcmV0dXJuZWQgdW5jaGFuZ2VkLgogICAgICogKiBJZiBgaW5wdXRgIGlzIGEgc3RyaW5nIGNvbnRhaW5pbmcgYSB2YWxpZCB0aW1lIHpvbmUgbmFtZSwgYSBab25lIGluc3RhbmNlCiAgICAgKiAgIHdpdGggdGhhdCBuYW1lIGlzIHJldHVybmVkLgogICAgICogKiBJZiBgaW5wdXRgIGlzIGEgc3RyaW5nIHRoYXQgZG9lc24ndCByZWZlciB0byBhIGtub3duIHRpbWUgem9uZSwgYSBab25lCiAgICAgKiAgIGluc3RhbmNlIHdpdGgge0BsaW5rIFpvbmUjaXNWYWxpZH0gPT0gZmFsc2UgaXMgcmV0dXJuZWQuCiAgICAgKiAqIElmIGBpbnB1dCBpcyBhIG51bWJlciwgYSBab25lIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBmaXhlZCBvZmZzZXQKICAgICAqICAgaW4gbWludXRlcyBpcyByZXR1cm5lZC4KICAgICAqICogSWYgYGlucHV0YCBpcyBgbnVsbGAgb3IgYHVuZGVmaW5lZGAsIHRoZSBkZWZhdWx0IHpvbmUgaXMgcmV0dXJuZWQuCiAgICAgKiBAcGFyYW0ge3N0cmluZ3xab25lfG51bWJlcn0gW2lucHV0XSAtIHRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQKICAgICAqIEByZXR1cm4ge1pvbmV9CiAgICAgKi8KICAgIHN0YXRpYyBub3JtYWxpemVab25lKGlucHV0KSB7CiAgICAgIHJldHVybiBub3JtYWxpemVab25lKGlucHV0LCBTZXR0aW5ncy5kZWZhdWx0Wm9uZSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gYW4gYXJyYXkgb2Ygc3RhbmRhbG9uZSBtb250aCBuYW1lcy4KICAgICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRGF0ZVRpbWVGb3JtYXQKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbbGVuZ3RoPSdsb25nJ10gLSB0aGUgbGVuZ3RoIG9mIHRoZSBtb250aCByZXByZXNlbnRhdGlvbiwgc3VjaCBhcyAibnVtZXJpYyIsICIyLWRpZ2l0IiwgIm5hcnJvdyIsICJzaG9ydCIsICJsb25nIgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jYWxlXSAtIHRoZSBsb2NhbGUgY29kZQogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLm51bWJlcmluZ1N5c3RlbT1udWxsXSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jT2JqPW51bGxdIC0gYW4gZXhpc3RpbmcgbG9jYWxlIG9iamVjdCB0byB1c2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5vdXRwdXRDYWxlbmRhcj0nZ3JlZ29yeSddIC0gdGhlIGNhbGVuZGFyCiAgICAgKiBAZXhhbXBsZSBJbmZvLm1vbnRocygpWzBdIC8vPT4gJ0phbnVhcnknCiAgICAgKiBAZXhhbXBsZSBJbmZvLm1vbnRocygnc2hvcnQnKVswXSAvLz0+ICdKYW4nCiAgICAgKiBAZXhhbXBsZSBJbmZvLm1vbnRocygnbnVtZXJpYycpWzBdIC8vPT4gJzEnCiAgICAgKiBAZXhhbXBsZSBJbmZvLm1vbnRocygnc2hvcnQnLCB7IGxvY2FsZTogJ2ZyLUNBJyB9IClbMF0gLy89PiAnamFudi4nCiAgICAgKiBAZXhhbXBsZSBJbmZvLm1vbnRocygnbnVtZXJpYycsIHsgbG9jYWxlOiAnYXInIH0pWzBdIC8vPT4gJ9mhJwogICAgICogQGV4YW1wbGUgSW5mby5tb250aHMoJ2xvbmcnLCB7IG91dHB1dENhbGVuZGFyOiAnaXNsYW1pYycgfSlbMF0gLy89PiAnUmFiacq7IEknCiAgICAgKiBAcmV0dXJuIHtBcnJheX0KICAgICAqLwogICAgc3RhdGljIG1vbnRocygKICAgICAgbGVuZ3RoID0gImxvbmciLAogICAgICB7IGxvY2FsZSA9IG51bGwsIG51bWJlcmluZ1N5c3RlbSA9IG51bGwsIGxvY09iaiA9IG51bGwsIG91dHB1dENhbGVuZGFyID0gImdyZWdvcnkiIH0gPSB7fQogICAgKSB7CiAgICAgIHJldHVybiAobG9jT2JqIHx8IExvY2FsZS5jcmVhdGUobG9jYWxlLCBudW1iZXJpbmdTeXN0ZW0sIG91dHB1dENhbGVuZGFyKSkubW9udGhzKGxlbmd0aCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gYW4gYXJyYXkgb2YgZm9ybWF0IG1vbnRoIG5hbWVzLgogICAgICogRm9ybWF0IG1vbnRocyBkaWZmZXIgZnJvbSBzdGFuZGFsb25lIG1vbnRocyBpbiB0aGF0IHRoZXkncmUgbWVhbnQgdG8gYXBwZWFyIG5leHQgdG8gdGhlIGRheSBvZiB0aGUgbW9udGguIEluIHNvbWUgbGFuZ3VhZ2VzLCB0aGF0CiAgICAgKiBjaGFuZ2VzIHRoZSBzdHJpbmcuCiAgICAgKiBTZWUge0BsaW5rIEluZm8jbW9udGhzfQogICAgICogQHBhcmFtIHtzdHJpbmd9IFtsZW5ndGg9J2xvbmcnXSAtIHRoZSBsZW5ndGggb2YgdGhlIG1vbnRoIHJlcHJlc2VudGF0aW9uLCBzdWNoIGFzICJudW1lcmljIiwgIjItZGlnaXQiLCAibmFycm93IiwgInNob3J0IiwgImxvbmciCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdGlvbnMKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5sb2NhbGVdIC0gdGhlIGxvY2FsZSBjb2RlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubnVtYmVyaW5nU3lzdGVtPW51bGxdIC0gdGhlIG51bWJlcmluZyBzeXN0ZW0KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5sb2NPYmo9bnVsbF0gLSBhbiBleGlzdGluZyBsb2NhbGUgb2JqZWN0IHRvIHVzZQogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLm91dHB1dENhbGVuZGFyPSdncmVnb3J5J10gLSB0aGUgY2FsZW5kYXIKICAgICAqIEByZXR1cm4ge0FycmF5fQogICAgICovCiAgICBzdGF0aWMgbW9udGhzRm9ybWF0KAogICAgICBsZW5ndGggPSAibG9uZyIsCiAgICAgIHsgbG9jYWxlID0gbnVsbCwgbnVtYmVyaW5nU3lzdGVtID0gbnVsbCwgbG9jT2JqID0gbnVsbCwgb3V0cHV0Q2FsZW5kYXIgPSAiZ3JlZ29yeSIgfSA9IHt9CiAgICApIHsKICAgICAgcmV0dXJuIChsb2NPYmogfHwgTG9jYWxlLmNyZWF0ZShsb2NhbGUsIG51bWJlcmluZ1N5c3RlbSwgb3V0cHV0Q2FsZW5kYXIpKS5tb250aHMobGVuZ3RoLCB0cnVlKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiBhbiBhcnJheSBvZiBzdGFuZGFsb25lIHdlZWsgbmFtZXMuCiAgICAgKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0RhdGVUaW1lRm9ybWF0CiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW2xlbmd0aD0nbG9uZyddIC0gdGhlIGxlbmd0aCBvZiB0aGUgd2Vla2RheSByZXByZXNlbnRhdGlvbiwgc3VjaCBhcyAibmFycm93IiwgInNob3J0IiwgImxvbmciLgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jYWxlXSAtIHRoZSBsb2NhbGUgY29kZQogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLm51bWJlcmluZ1N5c3RlbT1udWxsXSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jT2JqPW51bGxdIC0gYW4gZXhpc3RpbmcgbG9jYWxlIG9iamVjdCB0byB1c2UKICAgICAqIEBleGFtcGxlIEluZm8ud2Vla2RheXMoKVswXSAvLz0+ICdNb25kYXknCiAgICAgKiBAZXhhbXBsZSBJbmZvLndlZWtkYXlzKCdzaG9ydCcpWzBdIC8vPT4gJ01vbicKICAgICAqIEBleGFtcGxlIEluZm8ud2Vla2RheXMoJ3Nob3J0JywgeyBsb2NhbGU6ICdmci1DQScgfSlbMF0gLy89PiAnbHVuLicKICAgICAqIEBleGFtcGxlIEluZm8ud2Vla2RheXMoJ3Nob3J0JywgeyBsb2NhbGU6ICdhcicgfSlbMF0gLy89PiAn2KfZhNin2KvZhtmK2YYnCiAgICAgKiBAcmV0dXJuIHtBcnJheX0KICAgICAqLwogICAgc3RhdGljIHdlZWtkYXlzKGxlbmd0aCA9ICJsb25nIiwgeyBsb2NhbGUgPSBudWxsLCBudW1iZXJpbmdTeXN0ZW0gPSBudWxsLCBsb2NPYmogPSBudWxsIH0gPSB7fSkgewogICAgICByZXR1cm4gKGxvY09iaiB8fCBMb2NhbGUuY3JlYXRlKGxvY2FsZSwgbnVtYmVyaW5nU3lzdGVtLCBudWxsKSkud2Vla2RheXMobGVuZ3RoKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiBhbiBhcnJheSBvZiBmb3JtYXQgd2VlayBuYW1lcy4KICAgICAqIEZvcm1hdCB3ZWVrZGF5cyBkaWZmZXIgZnJvbSBzdGFuZGFsb25lIHdlZWtkYXlzIGluIHRoYXQgdGhleSdyZSBtZWFudCB0byBhcHBlYXIgbmV4dCB0byBtb3JlIGRhdGUgaW5mb3JtYXRpb24uIEluIHNvbWUgbGFuZ3VhZ2VzLCB0aGF0CiAgICAgKiBjaGFuZ2VzIHRoZSBzdHJpbmcuCiAgICAgKiBTZWUge0BsaW5rIEluZm8jd2Vla2RheXN9CiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW2xlbmd0aD0nbG9uZyddIC0gdGhlIGxlbmd0aCBvZiB0aGUgbW9udGggcmVwcmVzZW50YXRpb24sIHN1Y2ggYXMgIm5hcnJvdyIsICJzaG9ydCIsICJsb25nIi4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRzIC0gb3B0aW9ucwogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmxvY2FsZT1udWxsXSAtIHRoZSBsb2NhbGUgY29kZQogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLm51bWJlcmluZ1N5c3RlbT1udWxsXSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jT2JqPW51bGxdIC0gYW4gZXhpc3RpbmcgbG9jYWxlIG9iamVjdCB0byB1c2UKICAgICAqIEByZXR1cm4ge0FycmF5fQogICAgICovCiAgICBzdGF0aWMgd2Vla2RheXNGb3JtYXQoCiAgICAgIGxlbmd0aCA9ICJsb25nIiwKICAgICAgeyBsb2NhbGUgPSBudWxsLCBudW1iZXJpbmdTeXN0ZW0gPSBudWxsLCBsb2NPYmogPSBudWxsIH0gPSB7fQogICAgKSB7CiAgICAgIHJldHVybiAobG9jT2JqIHx8IExvY2FsZS5jcmVhdGUobG9jYWxlLCBudW1iZXJpbmdTeXN0ZW0sIG51bGwpKS53ZWVrZGF5cyhsZW5ndGgsIHRydWUpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJuIGFuIGFycmF5IG9mIG1lcmlkaWVtcy4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRzIC0gb3B0aW9ucwogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmxvY2FsZV0gLSB0aGUgbG9jYWxlIGNvZGUKICAgICAqIEBleGFtcGxlIEluZm8ubWVyaWRpZW1zKCkgLy89PiBbICdBTScsICdQTScgXQogICAgICogQGV4YW1wbGUgSW5mby5tZXJpZGllbXMoeyBsb2NhbGU6ICdteScgfSkgLy89PiBbICfhgJThgLbhgJThgIDhgLonLCAn4YCK4YCU4YCxJyBdCiAgICAgKiBAcmV0dXJuIHtBcnJheX0KICAgICAqLwogICAgc3RhdGljIG1lcmlkaWVtcyh7IGxvY2FsZSA9IG51bGwgfSA9IHt9KSB7CiAgICAgIHJldHVybiBMb2NhbGUuY3JlYXRlKGxvY2FsZSkubWVyaWRpZW1zKCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gYW4gYXJyYXkgb2YgZXJhcywgc3VjaCBhcyBbJ0JDJywgJ0FEJ10uIFRoZSBsb2NhbGUgY2FuIGJlIHNwZWNpZmllZCwgYnV0IHRoZSBjYWxlbmRhciBzeXN0ZW0gaXMgYWx3YXlzIEdyZWdvcmlhbi4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbbGVuZ3RoPSdzaG9ydCddIC0gdGhlIGxlbmd0aCBvZiB0aGUgZXJhIHJlcHJlc2VudGF0aW9uLCBzdWNoIGFzICJzaG9ydCIgb3IgImxvbmciLgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jYWxlXSAtIHRoZSBsb2NhbGUgY29kZQogICAgICogQGV4YW1wbGUgSW5mby5lcmFzKCkgLy89PiBbICdCQycsICdBRCcgXQogICAgICogQGV4YW1wbGUgSW5mby5lcmFzKCdsb25nJykgLy89PiBbICdCZWZvcmUgQ2hyaXN0JywgJ0Fubm8gRG9taW5pJyBdCiAgICAgKiBAZXhhbXBsZSBJbmZvLmVyYXMoJ2xvbmcnLCB7IGxvY2FsZTogJ2ZyJyB9KSAvLz0+IFsgJ2F2YW50IErDqXN1cy1DaHJpc3QnLCAnYXByw6hzIErDqXN1cy1DaHJpc3QnIF0KICAgICAqIEByZXR1cm4ge0FycmF5fQogICAgICovCiAgICBzdGF0aWMgZXJhcyhsZW5ndGggPSAic2hvcnQiLCB7IGxvY2FsZSA9IG51bGwgfSA9IHt9KSB7CiAgICAgIHJldHVybiBMb2NhbGUuY3JlYXRlKGxvY2FsZSwgbnVsbCwgImdyZWdvcnkiKS5lcmFzKGxlbmd0aCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gdGhlIHNldCBvZiBhdmFpbGFibGUgZmVhdHVyZXMgaW4gdGhpcyBlbnZpcm9ubWVudC4KICAgICAqIFNvbWUgZmVhdHVyZXMgb2YgTHV4b24gYXJlIG5vdCBhdmFpbGFibGUgaW4gYWxsIGVudmlyb25tZW50cy4gRm9yIGV4YW1wbGUsIG9uIG9sZGVyIGJyb3dzZXJzLCByZWxhdGl2ZSB0aW1lIGZvcm1hdHRpbmcgc3VwcG9ydCBpcyBub3QgYXZhaWxhYmxlLiBVc2UgdGhpcyBmdW5jdGlvbiB0byBmaWd1cmUgb3V0IGlmIHRoYXQncyB0aGUgY2FzZS4KICAgICAqIEtleXM6CiAgICAgKiAqIGByZWxhdGl2ZWA6IHdoZXRoZXIgdGhpcyBlbnZpcm9ubWVudCBzdXBwb3J0cyByZWxhdGl2ZSB0aW1lIGZvcm1hdHRpbmcKICAgICAqIEBleGFtcGxlIEluZm8uZmVhdHVyZXMoKSAvLz0+IHsgcmVsYXRpdmU6IGZhbHNlIH0KICAgICAqIEByZXR1cm4ge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGZlYXR1cmVzKCkgewogICAgICByZXR1cm4geyByZWxhdGl2ZTogaGFzUmVsYXRpdmUoKSB9OwogICAgfQogIH0KCiAgZnVuY3Rpb24gZGF5RGlmZihlYXJsaWVyLCBsYXRlcikgewogICAgY29uc3QgdXRjRGF5U3RhcnQgPSAoZHQpID0+IGR0LnRvVVRDKDAsIHsga2VlcExvY2FsVGltZTogdHJ1ZSB9KS5zdGFydE9mKCJkYXkiKS52YWx1ZU9mKCksCiAgICAgIG1zID0gdXRjRGF5U3RhcnQobGF0ZXIpIC0gdXRjRGF5U3RhcnQoZWFybGllcik7CiAgICByZXR1cm4gTWF0aC5mbG9vcihEdXJhdGlvbi5mcm9tTWlsbGlzKG1zKS5hcygiZGF5cyIpKTsKICB9CgogIGZ1bmN0aW9uIGhpZ2hPcmRlckRpZmZzKGN1cnNvciwgbGF0ZXIsIHVuaXRzKSB7CiAgICBjb25zdCBkaWZmZXJzID0gWwogICAgICBbInllYXJzIiwgKGEsIGIpID0+IGIueWVhciAtIGEueWVhcl0sCiAgICAgIFsicXVhcnRlcnMiLCAoYSwgYikgPT4gYi5xdWFydGVyIC0gYS5xdWFydGVyICsgKGIueWVhciAtIGEueWVhcikgKiA0XSwKICAgICAgWyJtb250aHMiLCAoYSwgYikgPT4gYi5tb250aCAtIGEubW9udGggKyAoYi55ZWFyIC0gYS55ZWFyKSAqIDEyXSwKICAgICAgWwogICAgICAgICJ3ZWVrcyIsCiAgICAgICAgKGEsIGIpID0+IHsKICAgICAgICAgIGNvbnN0IGRheXMgPSBkYXlEaWZmKGEsIGIpOwogICAgICAgICAgcmV0dXJuIChkYXlzIC0gKGRheXMgJSA3KSkgLyA3OwogICAgICAgIH0sCiAgICAgIF0sCiAgICAgIFsiZGF5cyIsIGRheURpZmZdLAogICAgXTsKCiAgICBjb25zdCByZXN1bHRzID0ge307CiAgICBjb25zdCBlYXJsaWVyID0gY3Vyc29yOwogICAgbGV0IGxvd2VzdE9yZGVyLCBoaWdoV2F0ZXI7CgogICAgLyogVGhpcyBsb29wIHRyaWVzIHRvIGRpZmYgdXNpbmcgbGFyZ2VyIHVuaXRzIGZpcnN0LgogICAgICAgSWYgd2Ugb3ZlcnNob290LCB3ZSBiYWNrdHJhY2sgYW5kIHRyeSB0aGUgbmV4dCBzbWFsbGVyIHVuaXQuCiAgICAgICAiY3Vyc29yIiBzdGFydHMgb3V0IGF0IHRoZSBlYXJsaWVyIHRpbWVzdGFtcCBhbmQgbW92ZXMgY2xvc2VyIGFuZCBjbG9zZXIgdG8gImxhdGVyIgogICAgICAgYXMgd2UgdXNlIHNtYWxsZXIgYW5kIHNtYWxsZXIgdW5pdHMuCiAgICAgICBoaWdoV2F0ZXIga2VlcHMgdHJhY2sgb2Ygd2hlcmUgd2Ugd291bGQgYmUgaWYgd2UgYWRkZWQgb25lIG1vcmUgb2YgdGhlIHNtYWxsZXN0IHVuaXQsCiAgICAgICB0aGlzIGlzIHVzZWQgbGF0ZXIgdG8gcG90ZW50aWFsbHkgY29udmVydCBhbnkgZGlmZmVyZW5jZSBzbWFsbGVyIHRoYW4gdGhlIHNtYWxsZXN0IGhpZ2hlciBvcmRlciB1bml0CiAgICAgICBpbnRvIGEgZnJhY3Rpb24gb2YgdGhhdCBzbWFsbGVzdCBoaWdoZXIgb3JkZXIgdW5pdAogICAgKi8KICAgIGZvciAoY29uc3QgW3VuaXQsIGRpZmZlcl0gb2YgZGlmZmVycykgewogICAgICBpZiAodW5pdHMuaW5kZXhPZih1bml0KSA+PSAwKSB7CiAgICAgICAgbG93ZXN0T3JkZXIgPSB1bml0OwoKICAgICAgICByZXN1bHRzW3VuaXRdID0gZGlmZmVyKGN1cnNvciwgbGF0ZXIpOwogICAgICAgIGhpZ2hXYXRlciA9IGVhcmxpZXIucGx1cyhyZXN1bHRzKTsKCiAgICAgICAgaWYgKGhpZ2hXYXRlciA+IGxhdGVyKSB7CiAgICAgICAgICAvLyB3ZSBvdmVyc2hvdCB0aGUgZW5kIHBvaW50LCBiYWNrdHJhY2sgY3Vyc29yIGJ5IDEKICAgICAgICAgIHJlc3VsdHNbdW5pdF0tLTsKICAgICAgICAgIGN1cnNvciA9IGVhcmxpZXIucGx1cyhyZXN1bHRzKTsKCiAgICAgICAgICAvLyBpZiB3ZSBhcmUgc3RpbGwgb3ZlcnNob290aW5nIG5vdywgd2UgbmVlZCB0byBiYWNrdHJhY2sgYWdhaW4KICAgICAgICAgIC8vIHRoaXMgaGFwcGVucyBpbiBjZXJ0YWluIHNpdHVhdGlvbnMgd2hlbiBkaWZmaW5nIHRpbWVzIGluIGRpZmZlcmVudCB6b25lcywKICAgICAgICAgIC8vIGJlY2F1c2UgdGhpcyBjYWxjdWxhdGlvbiBpZ25vcmVzIHRpbWUgem9uZXMKICAgICAgICAgIGlmIChjdXJzb3IgPiBsYXRlcikgewogICAgICAgICAgICAvLyBrZWVwIHRoZSAib3ZlcnNob3QgYnkgMSIgYXJvdW5kIGFzIGhpZ2hXYXRlcgogICAgICAgICAgICBoaWdoV2F0ZXIgPSBjdXJzb3I7CiAgICAgICAgICAgIC8vIGJhY2t0cmFjayBjdXJzb3IgYnkgMQogICAgICAgICAgICByZXN1bHRzW3VuaXRdLS07CiAgICAgICAgICAgIGN1cnNvciA9IGVhcmxpZXIucGx1cyhyZXN1bHRzKTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgY3Vyc29yID0gaGlnaFdhdGVyOwogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIHJldHVybiBbY3Vyc29yLCByZXN1bHRzLCBoaWdoV2F0ZXIsIGxvd2VzdE9yZGVyXTsKICB9CgogIGZ1bmN0aW9uIGRpZmYgKGVhcmxpZXIsIGxhdGVyLCB1bml0cywgb3B0cykgewogICAgbGV0IFtjdXJzb3IsIHJlc3VsdHMsIGhpZ2hXYXRlciwgbG93ZXN0T3JkZXJdID0gaGlnaE9yZGVyRGlmZnMoZWFybGllciwgbGF0ZXIsIHVuaXRzKTsKCiAgICBjb25zdCByZW1haW5pbmdNaWxsaXMgPSBsYXRlciAtIGN1cnNvcjsKCiAgICBjb25zdCBsb3dlck9yZGVyVW5pdHMgPSB1bml0cy5maWx0ZXIoCiAgICAgICh1KSA9PiBbImhvdXJzIiwgIm1pbnV0ZXMiLCAic2Vjb25kcyIsICJtaWxsaXNlY29uZHMiXS5pbmRleE9mKHUpID49IDAKICAgICk7CgogICAgaWYgKGxvd2VyT3JkZXJVbml0cy5sZW5ndGggPT09IDApIHsKICAgICAgaWYgKGhpZ2hXYXRlciA8IGxhdGVyKSB7CiAgICAgICAgaGlnaFdhdGVyID0gY3Vyc29yLnBsdXMoeyBbbG93ZXN0T3JkZXJdOiAxIH0pOwogICAgICB9CgogICAgICBpZiAoaGlnaFdhdGVyICE9PSBjdXJzb3IpIHsKICAgICAgICByZXN1bHRzW2xvd2VzdE9yZGVyXSA9IChyZXN1bHRzW2xvd2VzdE9yZGVyXSB8fCAwKSArIHJlbWFpbmluZ01pbGxpcyAvIChoaWdoV2F0ZXIgLSBjdXJzb3IpOwogICAgICB9CiAgICB9CgogICAgY29uc3QgZHVyYXRpb24gPSBEdXJhdGlvbi5mcm9tT2JqZWN0KHJlc3VsdHMsIG9wdHMpOwoKICAgIGlmIChsb3dlck9yZGVyVW5pdHMubGVuZ3RoID4gMCkgewogICAgICByZXR1cm4gRHVyYXRpb24uZnJvbU1pbGxpcyhyZW1haW5pbmdNaWxsaXMsIG9wdHMpCiAgICAgICAgLnNoaWZ0VG8oLi4ubG93ZXJPcmRlclVuaXRzKQogICAgICAgIC5wbHVzKGR1cmF0aW9uKTsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiBkdXJhdGlvbjsKICAgIH0KICB9CgogIGNvbnN0IG51bWJlcmluZ1N5c3RlbXMgPSB7CiAgICBhcmFiOiAiW1x1MDY2MC1cdTA2NjldIiwKICAgIGFyYWJleHQ6ICJbXHUwNkYwLVx1MDZGOV0iLAogICAgYmFsaTogIltcdTFCNTAtXHUxQjU5XSIsCiAgICBiZW5nOiAiW1x1MDlFNi1cdTA5RUZdIiwKICAgIGRldmE6ICJbXHUwOTY2LVx1MDk2Rl0iLAogICAgZnVsbHdpZGU6ICJbXHVGRjEwLVx1RkYxOV0iLAogICAgZ3VqcjogIltcdTBBRTYtXHUwQUVGXSIsCiAgICBoYW5pZGVjOiAiW+OAh3zkuIB85LqMfOS4iXzlm5t85LqUfOWFrXzkuIN85YWrfOS5nV0iLAogICAga2htcjogIltcdTE3RTAtXHUxN0U5XSIsCiAgICBrbmRhOiAiW1x1MENFNi1cdTBDRUZdIiwKICAgIGxhb286ICJbXHUwRUQwLVx1MEVEOV0iLAogICAgbGltYjogIltcdTE5NDYtXHUxOTRGXSIsCiAgICBtbHltOiAiW1x1MEQ2Ni1cdTBENkZdIiwKICAgIG1vbmc6ICJbXHUxODEwLVx1MTgxOV0iLAogICAgbXltcjogIltcdTEwNDAtXHUxMDQ5XSIsCiAgICBvcnlhOiAiW1x1MEI2Ni1cdTBCNkZdIiwKICAgIHRhbWxkZWM6ICJbXHUwQkU2LVx1MEJFRl0iLAogICAgdGVsdTogIltcdTBDNjYtXHUwQzZGXSIsCiAgICB0aGFpOiAiW1x1MEU1MC1cdTBFNTldIiwKICAgIHRpYnQ6ICJbXHUwRjIwLVx1MEYyOV0iLAogICAgbGF0bjogIlxcZCIsCiAgfTsKCiAgY29uc3QgbnVtYmVyaW5nU3lzdGVtc1VURjE2ID0gewogICAgYXJhYjogWzE2MzIsIDE2NDFdLAogICAgYXJhYmV4dDogWzE3NzYsIDE3ODVdLAogICAgYmFsaTogWzY5OTIsIDcwMDFdLAogICAgYmVuZzogWzI1MzQsIDI1NDNdLAogICAgZGV2YTogWzI0MDYsIDI0MTVdLAogICAgZnVsbHdpZGU6IFs2NTI5NiwgNjUzMDNdLAogICAgZ3VqcjogWzI3OTAsIDI3OTldLAogICAga2htcjogWzYxMTIsIDYxMjFdLAogICAga25kYTogWzMzMDIsIDMzMTFdLAogICAgbGFvbzogWzM3OTIsIDM4MDFdLAogICAgbGltYjogWzY0NzAsIDY0NzldLAogICAgbWx5bTogWzM0MzAsIDM0MzldLAogICAgbW9uZzogWzYxNjAsIDYxNjldLAogICAgbXltcjogWzQxNjAsIDQxNjldLAogICAgb3J5YTogWzI5MTgsIDI5MjddLAogICAgdGFtbGRlYzogWzMwNDYsIDMwNTVdLAogICAgdGVsdTogWzMxNzQsIDMxODNdLAogICAgdGhhaTogWzM2NjQsIDM2NzNdLAogICAgdGlidDogWzM4NzIsIDM4ODFdLAogIH07CgogIGNvbnN0IGhhbmlkZWNDaGFycyA9IG51bWJlcmluZ1N5c3RlbXMuaGFuaWRlYy5yZXBsYWNlKC9bXFt8XF1dL2csICIiKS5zcGxpdCgiIik7CgogIGZ1bmN0aW9uIHBhcnNlRGlnaXRzKHN0cikgewogICAgbGV0IHZhbHVlID0gcGFyc2VJbnQoc3RyLCAxMCk7CiAgICBpZiAoaXNOYU4odmFsdWUpKSB7CiAgICAgIHZhbHVlID0gIiI7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgY29uc3QgY29kZSA9IHN0ci5jaGFyQ29kZUF0KGkpOwoKICAgICAgICBpZiAoc3RyW2ldLnNlYXJjaChudW1iZXJpbmdTeXN0ZW1zLmhhbmlkZWMpICE9PSAtMSkgewogICAgICAgICAgdmFsdWUgKz0gaGFuaWRlY0NoYXJzLmluZGV4T2Yoc3RyW2ldKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gbnVtYmVyaW5nU3lzdGVtc1VURjE2KSB7CiAgICAgICAgICAgIGNvbnN0IFttaW4sIG1heF0gPSBudW1iZXJpbmdTeXN0ZW1zVVRGMTZba2V5XTsKICAgICAgICAgICAgaWYgKGNvZGUgPj0gbWluICYmIGNvZGUgPD0gbWF4KSB7CiAgICAgICAgICAgICAgdmFsdWUgKz0gY29kZSAtIG1pbjsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gcGFyc2VJbnQodmFsdWUsIDEwKTsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiB2YWx1ZTsKICAgIH0KICB9CgogIGZ1bmN0aW9uIGRpZ2l0UmVnZXgoeyBudW1iZXJpbmdTeXN0ZW0gfSwgYXBwZW5kID0gIiIpIHsKICAgIHJldHVybiBuZXcgUmVnRXhwKGAke251bWJlcmluZ1N5c3RlbXNbbnVtYmVyaW5nU3lzdGVtIHx8ICJsYXRuIl19JHthcHBlbmR9YCk7CiAgfQoKICBjb25zdCBNSVNTSU5HX0ZUUCA9ICJtaXNzaW5nIEludGwuRGF0ZVRpbWVGb3JtYXQuZm9ybWF0VG9QYXJ0cyBzdXBwb3J0IjsKCiAgZnVuY3Rpb24gaW50VW5pdChyZWdleCwgcG9zdCA9IChpKSA9PiBpKSB7CiAgICByZXR1cm4geyByZWdleCwgZGVzZXI6IChbc10pID0+IHBvc3QocGFyc2VEaWdpdHMocykpIH07CiAgfQoKICBjb25zdCBOQlNQID0gU3RyaW5nLmZyb21DaGFyQ29kZSgxNjApOwogIGNvbnN0IHNwYWNlT3JOQlNQID0gYFsgJHtOQlNQfV1gOwogIGNvbnN0IHNwYWNlT3JOQlNQUmVnRXhwID0gbmV3IFJlZ0V4cChzcGFjZU9yTkJTUCwgImciKTsKCiAgZnVuY3Rpb24gZml4TGlzdFJlZ2V4KHMpIHsKICAgIC8vIG1ha2UgZG90cyBvcHRpb25hbCBhbmQgYWxzbyBtYWtlIHRoZW0gbGl0ZXJhbAogICAgLy8gbWFrZSBzcGFjZSBhbmQgbm9uIGJyZWFrYWJsZSBzcGFjZSBjaGFyYWN0ZXJzIGludGVyY2hhbmdlYWJsZQogICAgcmV0dXJuIHMucmVwbGFjZSgvXC4vZywgIlxcLj8iKS5yZXBsYWNlKHNwYWNlT3JOQlNQUmVnRXhwLCBzcGFjZU9yTkJTUCk7CiAgfQoKICBmdW5jdGlvbiBzdHJpcEluc2Vuc2l0aXZpdGllcyhzKSB7CiAgICByZXR1cm4gcwogICAgICAucmVwbGFjZSgvXC4vZywgIiIpIC8vIGlnbm9yZSBkb3RzIHRoYXQgd2VyZSBtYWRlIG9wdGlvbmFsCiAgICAgIC5yZXBsYWNlKHNwYWNlT3JOQlNQUmVnRXhwLCAiICIpIC8vIGludGVyY2hhbmdlIHNwYWNlIGFuZCBuYnNwCiAgICAgIC50b0xvd2VyQ2FzZSgpOwogIH0KCiAgZnVuY3Rpb24gb25lT2Yoc3RyaW5ncywgc3RhcnRJbmRleCkgewogICAgaWYgKHN0cmluZ3MgPT09IG51bGwpIHsKICAgICAgcmV0dXJuIG51bGw7CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gewogICAgICAgIHJlZ2V4OiBSZWdFeHAoc3RyaW5ncy5tYXAoZml4TGlzdFJlZ2V4KS5qb2luKCJ8IikpLAogICAgICAgIGRlc2VyOiAoW3NdKSA9PgogICAgICAgICAgc3RyaW5ncy5maW5kSW5kZXgoKGkpID0+IHN0cmlwSW5zZW5zaXRpdml0aWVzKHMpID09PSBzdHJpcEluc2Vuc2l0aXZpdGllcyhpKSkgKyBzdGFydEluZGV4LAogICAgICB9OwogICAgfQogIH0KCiAgZnVuY3Rpb24gb2Zmc2V0KHJlZ2V4LCBncm91cHMpIHsKICAgIHJldHVybiB7IHJlZ2V4LCBkZXNlcjogKFssIGgsIG1dKSA9PiBzaWduZWRPZmZzZXQoaCwgbSksIGdyb3VwcyB9OwogIH0KCiAgZnVuY3Rpb24gc2ltcGxlKHJlZ2V4KSB7CiAgICByZXR1cm4geyByZWdleCwgZGVzZXI6IChbc10pID0+IHMgfTsKICB9CgogIGZ1bmN0aW9uIGVzY2FwZVRva2VuKHZhbHVlKSB7CiAgICByZXR1cm4gdmFsdWUucmVwbGFjZSgvW1wtXFtcXXt9KCkqKz8uLFxcXF4kfCNcc10vZywgIlxcJCYiKTsKICB9CgogIC8qKgogICAqIEBwYXJhbSB0b2tlbgogICAqIEBwYXJhbSB7TG9jYWxlfSBsb2MKICAgKi8KICBmdW5jdGlvbiB1bml0Rm9yVG9rZW4odG9rZW4sIGxvYykgewogICAgY29uc3Qgb25lID0gZGlnaXRSZWdleChsb2MpLAogICAgICB0d28gPSBkaWdpdFJlZ2V4KGxvYywgInsyfSIpLAogICAgICB0aHJlZSA9IGRpZ2l0UmVnZXgobG9jLCAiezN9IiksCiAgICAgIGZvdXIgPSBkaWdpdFJlZ2V4KGxvYywgIns0fSIpLAogICAgICBzaXggPSBkaWdpdFJlZ2V4KGxvYywgIns2fSIpLAogICAgICBvbmVPclR3byA9IGRpZ2l0UmVnZXgobG9jLCAiezEsMn0iKSwKICAgICAgb25lVG9UaHJlZSA9IGRpZ2l0UmVnZXgobG9jLCAiezEsM30iKSwKICAgICAgb25lVG9TaXggPSBkaWdpdFJlZ2V4KGxvYywgInsxLDZ9IiksCiAgICAgIG9uZVRvTmluZSA9IGRpZ2l0UmVnZXgobG9jLCAiezEsOX0iKSwKICAgICAgdHdvVG9Gb3VyID0gZGlnaXRSZWdleChsb2MsICJ7Miw0fSIpLAogICAgICBmb3VyVG9TaXggPSBkaWdpdFJlZ2V4KGxvYywgIns0LDZ9IiksCiAgICAgIGxpdGVyYWwgPSAodCkgPT4gKHsgcmVnZXg6IFJlZ0V4cChlc2NhcGVUb2tlbih0LnZhbCkpLCBkZXNlcjogKFtzXSkgPT4gcywgbGl0ZXJhbDogdHJ1ZSB9KSwKICAgICAgdW5pdGF0ZSA9ICh0KSA9PiB7CiAgICAgICAgaWYgKHRva2VuLmxpdGVyYWwpIHsKICAgICAgICAgIHJldHVybiBsaXRlcmFsKHQpOwogICAgICAgIH0KICAgICAgICBzd2l0Y2ggKHQudmFsKSB7CiAgICAgICAgICAvLyBlcmEKICAgICAgICAgIGNhc2UgIkciOgogICAgICAgICAgICByZXR1cm4gb25lT2YobG9jLmVyYXMoInNob3J0IiksIDApOwogICAgICAgICAgY2FzZSAiR0ciOgogICAgICAgICAgICByZXR1cm4gb25lT2YobG9jLmVyYXMoImxvbmciKSwgMCk7CiAgICAgICAgICAvLyB5ZWFycwogICAgICAgICAgY2FzZSAieSI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KG9uZVRvU2l4KTsKICAgICAgICAgIGNhc2UgInl5IjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQodHdvVG9Gb3VyLCB1bnRydW5jYXRlWWVhcik7CiAgICAgICAgICBjYXNlICJ5eXl5IjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQoZm91cik7CiAgICAgICAgICBjYXNlICJ5eXl5eSI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KGZvdXJUb1NpeCk7CiAgICAgICAgICBjYXNlICJ5eXl5eXkiOgogICAgICAgICAgICByZXR1cm4gaW50VW5pdChzaXgpOwogICAgICAgICAgLy8gbW9udGhzCiAgICAgICAgICBjYXNlICJNIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQob25lT3JUd28pOwogICAgICAgICAgY2FzZSAiTU0iOgogICAgICAgICAgICByZXR1cm4gaW50VW5pdCh0d28pOwogICAgICAgICAgY2FzZSAiTU1NIjoKICAgICAgICAgICAgcmV0dXJuIG9uZU9mKGxvYy5tb250aHMoInNob3J0IiwgdHJ1ZSksIDEpOwogICAgICAgICAgY2FzZSAiTU1NTSI6CiAgICAgICAgICAgIHJldHVybiBvbmVPZihsb2MubW9udGhzKCJsb25nIiwgdHJ1ZSksIDEpOwogICAgICAgICAgY2FzZSAiTCI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KG9uZU9yVHdvKTsKICAgICAgICAgIGNhc2UgIkxMIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQodHdvKTsKICAgICAgICAgIGNhc2UgIkxMTCI6CiAgICAgICAgICAgIHJldHVybiBvbmVPZihsb2MubW9udGhzKCJzaG9ydCIsIGZhbHNlKSwgMSk7CiAgICAgICAgICBjYXNlICJMTExMIjoKICAgICAgICAgICAgcmV0dXJuIG9uZU9mKGxvYy5tb250aHMoImxvbmciLCBmYWxzZSksIDEpOwogICAgICAgICAgLy8gZGF0ZXMKICAgICAgICAgIGNhc2UgImQiOgogICAgICAgICAgICByZXR1cm4gaW50VW5pdChvbmVPclR3byk7CiAgICAgICAgICBjYXNlICJkZCI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KHR3byk7CiAgICAgICAgICAvLyBvcmRpbmFscwogICAgICAgICAgY2FzZSAibyI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KG9uZVRvVGhyZWUpOwogICAgICAgICAgY2FzZSAib29vIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQodGhyZWUpOwogICAgICAgICAgLy8gdGltZQogICAgICAgICAgY2FzZSAiSEgiOgogICAgICAgICAgICByZXR1cm4gaW50VW5pdCh0d28pOwogICAgICAgICAgY2FzZSAiSCI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KG9uZU9yVHdvKTsKICAgICAgICAgIGNhc2UgImhoIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQodHdvKTsKICAgICAgICAgIGNhc2UgImgiOgogICAgICAgICAgICByZXR1cm4gaW50VW5pdChvbmVPclR3byk7CiAgICAgICAgICBjYXNlICJtbSI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KHR3byk7CiAgICAgICAgICBjYXNlICJtIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQob25lT3JUd28pOwogICAgICAgICAgY2FzZSAicSI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KG9uZU9yVHdvKTsKICAgICAgICAgIGNhc2UgInFxIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQodHdvKTsKICAgICAgICAgIGNhc2UgInMiOgogICAgICAgICAgICByZXR1cm4gaW50VW5pdChvbmVPclR3byk7CiAgICAgICAgICBjYXNlICJzcyI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KHR3byk7CiAgICAgICAgICBjYXNlICJTIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQob25lVG9UaHJlZSk7CiAgICAgICAgICBjYXNlICJTU1MiOgogICAgICAgICAgICByZXR1cm4gaW50VW5pdCh0aHJlZSk7CiAgICAgICAgICBjYXNlICJ1IjoKICAgICAgICAgICAgcmV0dXJuIHNpbXBsZShvbmVUb05pbmUpOwogICAgICAgICAgY2FzZSAidXUiOgogICAgICAgICAgICByZXR1cm4gc2ltcGxlKG9uZU9yVHdvKTsKICAgICAgICAgIGNhc2UgInV1dSI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KG9uZSk7CiAgICAgICAgICAvLyBtZXJpZGllbQogICAgICAgICAgY2FzZSAiYSI6CiAgICAgICAgICAgIHJldHVybiBvbmVPZihsb2MubWVyaWRpZW1zKCksIDApOwogICAgICAgICAgLy8gd2Vla1llYXIgKGspCiAgICAgICAgICBjYXNlICJra2trIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQoZm91cik7CiAgICAgICAgICBjYXNlICJrayI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KHR3b1RvRm91ciwgdW50cnVuY2F0ZVllYXIpOwogICAgICAgICAgLy8gd2Vla051bWJlciAoVykKICAgICAgICAgIGNhc2UgIlciOgogICAgICAgICAgICByZXR1cm4gaW50VW5pdChvbmVPclR3byk7CiAgICAgICAgICBjYXNlICJXVyI6CiAgICAgICAgICAgIHJldHVybiBpbnRVbml0KHR3byk7CiAgICAgICAgICAvLyB3ZWVrZGF5cwogICAgICAgICAgY2FzZSAiRSI6CiAgICAgICAgICBjYXNlICJjIjoKICAgICAgICAgICAgcmV0dXJuIGludFVuaXQob25lKTsKICAgICAgICAgIGNhc2UgIkVFRSI6CiAgICAgICAgICAgIHJldHVybiBvbmVPZihsb2Mud2Vla2RheXMoInNob3J0IiwgZmFsc2UpLCAxKTsKICAgICAgICAgIGNhc2UgIkVFRUUiOgogICAgICAgICAgICByZXR1cm4gb25lT2YobG9jLndlZWtkYXlzKCJsb25nIiwgZmFsc2UpLCAxKTsKICAgICAgICAgIGNhc2UgImNjYyI6CiAgICAgICAgICAgIHJldHVybiBvbmVPZihsb2Mud2Vla2RheXMoInNob3J0IiwgdHJ1ZSksIDEpOwogICAgICAgICAgY2FzZSAiY2NjYyI6CiAgICAgICAgICAgIHJldHVybiBvbmVPZihsb2Mud2Vla2RheXMoImxvbmciLCB0cnVlKSwgMSk7CiAgICAgICAgICAvLyBvZmZzZXQvem9uZQogICAgICAgICAgY2FzZSAiWiI6CiAgICAgICAgICBjYXNlICJaWiI6CiAgICAgICAgICAgIHJldHVybiBvZmZzZXQobmV3IFJlZ0V4cChgKFsrLV0ke29uZU9yVHdvLnNvdXJjZX0pKD86Oigke3R3by5zb3VyY2V9KSk/YCksIDIpOwogICAgICAgICAgY2FzZSAiWlpaIjoKICAgICAgICAgICAgcmV0dXJuIG9mZnNldChuZXcgUmVnRXhwKGAoWystXSR7b25lT3JUd28uc291cmNlfSkoJHt0d28uc291cmNlfSk/YCksIDIpOwogICAgICAgICAgLy8gd2UgZG9uJ3Qgc3VwcG9ydCBaWlpaIChQU1QpIG9yIFpaWlpaIChQYWNpZmljIFN0YW5kYXJkIFRpbWUpIGluIHBhcnNpbmcKICAgICAgICAgIC8vIGJlY2F1c2Ugd2UgZG9uJ3QgaGF2ZSBhbnkgd2F5IHRvIGZpZ3VyZSBvdXQgd2hhdCB0aGV5IGFyZQogICAgICAgICAgY2FzZSAieiI6CiAgICAgICAgICAgIHJldHVybiBzaW1wbGUoL1thLXpfKy0vXXsxLDI1Nn0/L2kpOwogICAgICAgICAgLy8gdGhpcyBzcGVjaWFsLWNhc2UgInRva2VuIiByZXByZXNlbnRzIGEgcGxhY2Ugd2hlcmUgYSBtYWNyby10b2tlbiBleHBhbmRlZCBpbnRvIGEgd2hpdGUtc3BhY2UgbGl0ZXJhbAogICAgICAgICAgLy8gaW4gdGhpcyBjYXNlIHdlIGFjY2VwdCBhbnkgbm9uLW5ld2xpbmUgd2hpdGUtc3BhY2UKICAgICAgICAgIGNhc2UgIiAiOgogICAgICAgICAgICByZXR1cm4gc2ltcGxlKC9bXlxTXG5ccl0vKTsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHJldHVybiBsaXRlcmFsKHQpOwogICAgICAgIH0KICAgICAgfTsKCiAgICBjb25zdCB1bml0ID0gdW5pdGF0ZSh0b2tlbikgfHwgewogICAgICBpbnZhbGlkUmVhc29uOiBNSVNTSU5HX0ZUUCwKICAgIH07CgogICAgdW5pdC50b2tlbiA9IHRva2VuOwoKICAgIHJldHVybiB1bml0OwogIH0KCiAgY29uc3QgcGFydFR5cGVTdHlsZVRvVG9rZW5WYWwgPSB7CiAgICB5ZWFyOiB7CiAgICAgICIyLWRpZ2l0IjogInl5IiwKICAgICAgbnVtZXJpYzogInl5eXl5IiwKICAgIH0sCiAgICBtb250aDogewogICAgICBudW1lcmljOiAiTSIsCiAgICAgICIyLWRpZ2l0IjogIk1NIiwKICAgICAgc2hvcnQ6ICJNTU0iLAogICAgICBsb25nOiAiTU1NTSIsCiAgICB9LAogICAgZGF5OiB7CiAgICAgIG51bWVyaWM6ICJkIiwKICAgICAgIjItZGlnaXQiOiAiZGQiLAogICAgfSwKICAgIHdlZWtkYXk6IHsKICAgICAgc2hvcnQ6ICJFRUUiLAogICAgICBsb25nOiAiRUVFRSIsCiAgICB9LAogICAgZGF5cGVyaW9kOiAiYSIsCiAgICBkYXlQZXJpb2Q6ICJhIiwKICAgIGhvdXIxMjogewogICAgICBudW1lcmljOiAiaCIsCiAgICAgICIyLWRpZ2l0IjogImhoIiwKICAgIH0sCiAgICBob3VyMjQ6IHsKICAgICAgbnVtZXJpYzogIkgiLAogICAgICAiMi1kaWdpdCI6ICJISCIsCiAgICB9LAogICAgbWludXRlOiB7CiAgICAgIG51bWVyaWM6ICJtIiwKICAgICAgIjItZGlnaXQiOiAibW0iLAogICAgfSwKICAgIHNlY29uZDogewogICAgICBudW1lcmljOiAicyIsCiAgICAgICIyLWRpZ2l0IjogInNzIiwKICAgIH0sCiAgICB0aW1lWm9uZU5hbWU6IHsKICAgICAgbG9uZzogIlpaWlpaIiwKICAgICAgc2hvcnQ6ICJaWloiLAogICAgfSwKICB9OwoKICBmdW5jdGlvbiB0b2tlbkZvclBhcnQocGFydCwgZm9ybWF0T3B0cywgcmVzb2x2ZWRPcHRzKSB7CiAgICBjb25zdCB7IHR5cGUsIHZhbHVlIH0gPSBwYXJ0OwoKICAgIGlmICh0eXBlID09PSAibGl0ZXJhbCIpIHsKICAgICAgY29uc3QgaXNTcGFjZSA9IC9eXHMrJC8udGVzdCh2YWx1ZSk7CiAgICAgIHJldHVybiB7CiAgICAgICAgbGl0ZXJhbDogIWlzU3BhY2UsCiAgICAgICAgdmFsOiBpc1NwYWNlID8gIiAiIDogdmFsdWUsCiAgICAgIH07CiAgICB9CgogICAgY29uc3Qgc3R5bGUgPSBmb3JtYXRPcHRzW3R5cGVdOwoKICAgIC8vIFRoZSB1c2VyIG1pZ2h0IGhhdmUgZXhwbGljaXRseSBzcGVjaWZpZWQgaG91cjEyIG9yIGhvdXJDeWNsZQogICAgLy8gaWYgc28sIHJlc3BlY3QgdGhlaXIgZGVjaXNpb24KICAgIC8vIGlmIG5vdCwgcmVmZXIgYmFjayB0byB0aGUgcmVzb2x2ZWRPcHRzLCB3aGljaCBhcmUgYmFzZWQgb24gdGhlIGxvY2FsZQogICAgbGV0IGFjdHVhbFR5cGUgPSB0eXBlOwogICAgaWYgKHR5cGUgPT09ICJob3VyIikgewogICAgICBpZiAoZm9ybWF0T3B0cy5ob3VyMTIgIT0gbnVsbCkgewogICAgICAgIGFjdHVhbFR5cGUgPSBmb3JtYXRPcHRzLmhvdXIxMiA/ICJob3VyMTIiIDogImhvdXIyNCI7CiAgICAgIH0gZWxzZSBpZiAoZm9ybWF0T3B0cy5ob3VyQ3ljbGUgIT0gbnVsbCkgewogICAgICAgIGlmIChmb3JtYXRPcHRzLmhvdXJDeWNsZSA9PT0gImgxMSIgfHwgZm9ybWF0T3B0cy5ob3VyQ3ljbGUgPT09ICJoMTIiKSB7CiAgICAgICAgICBhY3R1YWxUeXBlID0gImhvdXIxMiI7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGFjdHVhbFR5cGUgPSAiaG91cjI0IjsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgLy8gdG9rZW5zIG9ubHkgZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIDI0IGhvdXJzIG9yIG5vdCwKICAgICAgICAvLyBzbyB3ZSBkbyBub3QgbmVlZCB0byBjaGVjayBob3VyQ3ljbGUgaGVyZSwgd2hpY2ggaXMgbGVzcyBzdXBwb3J0ZWQgYW55d2F5cwogICAgICAgIGFjdHVhbFR5cGUgPSByZXNvbHZlZE9wdHMuaG91cjEyID8gImhvdXIxMiIgOiAiaG91cjI0IjsKICAgICAgfQogICAgfQogICAgbGV0IHZhbCA9IHBhcnRUeXBlU3R5bGVUb1Rva2VuVmFsW2FjdHVhbFR5cGVdOwogICAgaWYgKHR5cGVvZiB2YWwgPT09ICJvYmplY3QiKSB7CiAgICAgIHZhbCA9IHZhbFtzdHlsZV07CiAgICB9CgogICAgaWYgKHZhbCkgewogICAgICByZXR1cm4gewogICAgICAgIGxpdGVyYWw6IGZhbHNlLAogICAgICAgIHZhbCwKICAgICAgfTsKICAgIH0KCiAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KCiAgZnVuY3Rpb24gYnVpbGRSZWdleCh1bml0cykgewogICAgY29uc3QgcmUgPSB1bml0cy5tYXAoKHUpID0+IHUucmVnZXgpLnJlZHVjZSgoZiwgcikgPT4gYCR7Zn0oJHtyLnNvdXJjZX0pYCwgIiIpOwogICAgcmV0dXJuIFtgXiR7cmV9JGAsIHVuaXRzXTsKICB9CgogIGZ1bmN0aW9uIG1hdGNoKGlucHV0LCByZWdleCwgaGFuZGxlcnMpIHsKICAgIGNvbnN0IG1hdGNoZXMgPSBpbnB1dC5tYXRjaChyZWdleCk7CgogICAgaWYgKG1hdGNoZXMpIHsKICAgICAgY29uc3QgYWxsID0ge307CiAgICAgIGxldCBtYXRjaEluZGV4ID0gMTsKICAgICAgZm9yIChjb25zdCBpIGluIGhhbmRsZXJzKSB7CiAgICAgICAgaWYgKGhhc093blByb3BlcnR5KGhhbmRsZXJzLCBpKSkgewogICAgICAgICAgY29uc3QgaCA9IGhhbmRsZXJzW2ldLAogICAgICAgICAgICBncm91cHMgPSBoLmdyb3VwcyA/IGguZ3JvdXBzICsgMSA6IDE7CiAgICAgICAgICBpZiAoIWgubGl0ZXJhbCAmJiBoLnRva2VuKSB7CiAgICAgICAgICAgIGFsbFtoLnRva2VuLnZhbFswXV0gPSBoLmRlc2VyKG1hdGNoZXMuc2xpY2UobWF0Y2hJbmRleCwgbWF0Y2hJbmRleCArIGdyb3VwcykpOwogICAgICAgICAgfQogICAgICAgICAgbWF0Y2hJbmRleCArPSBncm91cHM7CiAgICAgICAgfQogICAgICB9CiAgICAgIHJldHVybiBbbWF0Y2hlcywgYWxsXTsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiBbbWF0Y2hlcywge31dOwogICAgfQogIH0KCiAgZnVuY3Rpb24gZGF0ZVRpbWVGcm9tTWF0Y2hlcyhtYXRjaGVzKSB7CiAgICBjb25zdCB0b0ZpZWxkID0gKHRva2VuKSA9PiB7CiAgICAgIHN3aXRjaCAodG9rZW4pIHsKICAgICAgICBjYXNlICJTIjoKICAgICAgICAgIHJldHVybiAibWlsbGlzZWNvbmQiOwogICAgICAgIGNhc2UgInMiOgogICAgICAgICAgcmV0dXJuICJzZWNvbmQiOwogICAgICAgIGNhc2UgIm0iOgogICAgICAgICAgcmV0dXJuICJtaW51dGUiOwogICAgICAgIGNhc2UgImgiOgogICAgICAgIGNhc2UgIkgiOgogICAgICAgICAgcmV0dXJuICJob3VyIjsKICAgICAgICBjYXNlICJkIjoKICAgICAgICAgIHJldHVybiAiZGF5IjsKICAgICAgICBjYXNlICJvIjoKICAgICAgICAgIHJldHVybiAib3JkaW5hbCI7CiAgICAgICAgY2FzZSAiTCI6CiAgICAgICAgY2FzZSAiTSI6CiAgICAgICAgICByZXR1cm4gIm1vbnRoIjsKICAgICAgICBjYXNlICJ5IjoKICAgICAgICAgIHJldHVybiAieWVhciI7CiAgICAgICAgY2FzZSAiRSI6CiAgICAgICAgY2FzZSAiYyI6CiAgICAgICAgICByZXR1cm4gIndlZWtkYXkiOwogICAgICAgIGNhc2UgIlciOgogICAgICAgICAgcmV0dXJuICJ3ZWVrTnVtYmVyIjsKICAgICAgICBjYXNlICJrIjoKICAgICAgICAgIHJldHVybiAid2Vla1llYXIiOwogICAgICAgIGNhc2UgInEiOgogICAgICAgICAgcmV0dXJuICJxdWFydGVyIjsKICAgICAgICBkZWZhdWx0OgogICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgIH0KICAgIH07CgogICAgbGV0IHpvbmUgPSBudWxsOwogICAgbGV0IHNwZWNpZmljT2Zmc2V0OwogICAgaWYgKCFpc1VuZGVmaW5lZChtYXRjaGVzLnopKSB7CiAgICAgIHpvbmUgPSBJQU5BWm9uZS5jcmVhdGUobWF0Y2hlcy56KTsKICAgIH0KCiAgICBpZiAoIWlzVW5kZWZpbmVkKG1hdGNoZXMuWikpIHsKICAgICAgaWYgKCF6b25lKSB7CiAgICAgICAgem9uZSA9IG5ldyBGaXhlZE9mZnNldFpvbmUobWF0Y2hlcy5aKTsKICAgICAgfQogICAgICBzcGVjaWZpY09mZnNldCA9IG1hdGNoZXMuWjsKICAgIH0KCiAgICBpZiAoIWlzVW5kZWZpbmVkKG1hdGNoZXMucSkpIHsKICAgICAgbWF0Y2hlcy5NID0gKG1hdGNoZXMucSAtIDEpICogMyArIDE7CiAgICB9CgogICAgaWYgKCFpc1VuZGVmaW5lZChtYXRjaGVzLmgpKSB7CiAgICAgIGlmIChtYXRjaGVzLmggPCAxMiAmJiBtYXRjaGVzLmEgPT09IDEpIHsKICAgICAgICBtYXRjaGVzLmggKz0gMTI7CiAgICAgIH0gZWxzZSBpZiAobWF0Y2hlcy5oID09PSAxMiAmJiBtYXRjaGVzLmEgPT09IDApIHsKICAgICAgICBtYXRjaGVzLmggPSAwOwogICAgICB9CiAgICB9CgogICAgaWYgKG1hdGNoZXMuRyA9PT0gMCAmJiBtYXRjaGVzLnkpIHsKICAgICAgbWF0Y2hlcy55ID0gLW1hdGNoZXMueTsKICAgIH0KCiAgICBpZiAoIWlzVW5kZWZpbmVkKG1hdGNoZXMudSkpIHsKICAgICAgbWF0Y2hlcy5TID0gcGFyc2VNaWxsaXMobWF0Y2hlcy51KTsKICAgIH0KCiAgICBjb25zdCB2YWxzID0gT2JqZWN0LmtleXMobWF0Y2hlcykucmVkdWNlKChyLCBrKSA9PiB7CiAgICAgIGNvbnN0IGYgPSB0b0ZpZWxkKGspOwogICAgICBpZiAoZikgewogICAgICAgIHJbZl0gPSBtYXRjaGVzW2tdOwogICAgICB9CgogICAgICByZXR1cm4gcjsKICAgIH0sIHt9KTsKCiAgICByZXR1cm4gW3ZhbHMsIHpvbmUsIHNwZWNpZmljT2Zmc2V0XTsKICB9CgogIGxldCBkdW1teURhdGVUaW1lQ2FjaGUgPSBudWxsOwoKICBmdW5jdGlvbiBnZXREdW1teURhdGVUaW1lKCkgewogICAgaWYgKCFkdW1teURhdGVUaW1lQ2FjaGUpIHsKICAgICAgZHVtbXlEYXRlVGltZUNhY2hlID0gRGF0ZVRpbWUuZnJvbU1pbGxpcygxNTU1NTU1NTU1NTU1KTsKICAgIH0KCiAgICByZXR1cm4gZHVtbXlEYXRlVGltZUNhY2hlOwogIH0KCiAgZnVuY3Rpb24gbWF5YmVFeHBhbmRNYWNyb1Rva2VuKHRva2VuLCBsb2NhbGUpIHsKICAgIGlmICh0b2tlbi5saXRlcmFsKSB7CiAgICAgIHJldHVybiB0b2tlbjsKICAgIH0KCiAgICBjb25zdCBmb3JtYXRPcHRzID0gRm9ybWF0dGVyLm1hY3JvVG9rZW5Ub0Zvcm1hdE9wdHModG9rZW4udmFsKTsKICAgIGNvbnN0IHRva2VucyA9IGZvcm1hdE9wdHNUb1Rva2Vucyhmb3JtYXRPcHRzLCBsb2NhbGUpOwoKICAgIGlmICh0b2tlbnMgPT0gbnVsbCB8fCB0b2tlbnMuaW5jbHVkZXModW5kZWZpbmVkKSkgewogICAgICByZXR1cm4gdG9rZW47CiAgICB9CgogICAgcmV0dXJuIHRva2VuczsKICB9CgogIGZ1bmN0aW9uIGV4cGFuZE1hY3JvVG9rZW5zKHRva2VucywgbG9jYWxlKSB7CiAgICByZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdCguLi50b2tlbnMubWFwKCh0KSA9PiBtYXliZUV4cGFuZE1hY3JvVG9rZW4odCwgbG9jYWxlKSkpOwogIH0KCiAgLyoqCiAgICogQHByaXZhdGUKICAgKi8KCiAgZnVuY3Rpb24gZXhwbGFpbkZyb21Ub2tlbnMobG9jYWxlLCBpbnB1dCwgZm9ybWF0KSB7CiAgICBjb25zdCB0b2tlbnMgPSBleHBhbmRNYWNyb1Rva2VucyhGb3JtYXR0ZXIucGFyc2VGb3JtYXQoZm9ybWF0KSwgbG9jYWxlKSwKICAgICAgdW5pdHMgPSB0b2tlbnMubWFwKCh0KSA9PiB1bml0Rm9yVG9rZW4odCwgbG9jYWxlKSksCiAgICAgIGRpc3F1YWxpZnlpbmdVbml0ID0gdW5pdHMuZmluZCgodCkgPT4gdC5pbnZhbGlkUmVhc29uKTsKCiAgICBpZiAoZGlzcXVhbGlmeWluZ1VuaXQpIHsKICAgICAgcmV0dXJuIHsgaW5wdXQsIHRva2VucywgaW52YWxpZFJlYXNvbjogZGlzcXVhbGlmeWluZ1VuaXQuaW52YWxpZFJlYXNvbiB9OwogICAgfSBlbHNlIHsKICAgICAgY29uc3QgW3JlZ2V4U3RyaW5nLCBoYW5kbGVyc10gPSBidWlsZFJlZ2V4KHVuaXRzKSwKICAgICAgICByZWdleCA9IFJlZ0V4cChyZWdleFN0cmluZywgImkiKSwKICAgICAgICBbcmF3TWF0Y2hlcywgbWF0Y2hlc10gPSBtYXRjaChpbnB1dCwgcmVnZXgsIGhhbmRsZXJzKSwKICAgICAgICBbcmVzdWx0LCB6b25lLCBzcGVjaWZpY09mZnNldF0gPSBtYXRjaGVzCiAgICAgICAgICA/IGRhdGVUaW1lRnJvbU1hdGNoZXMobWF0Y2hlcykKICAgICAgICAgIDogW251bGwsIG51bGwsIHVuZGVmaW5lZF07CiAgICAgIGlmIChoYXNPd25Qcm9wZXJ0eShtYXRjaGVzLCAiYSIpICYmIGhhc093blByb3BlcnR5KG1hdGNoZXMsICJIIikpIHsKICAgICAgICB0aHJvdyBuZXcgQ29uZmxpY3RpbmdTcGVjaWZpY2F0aW9uRXJyb3IoCiAgICAgICAgICAiQ2FuJ3QgaW5jbHVkZSBtZXJpZGllbSB3aGVuIHNwZWNpZnlpbmcgMjQtaG91ciBmb3JtYXQiCiAgICAgICAgKTsKICAgICAgfQogICAgICByZXR1cm4geyBpbnB1dCwgdG9rZW5zLCByZWdleCwgcmF3TWF0Y2hlcywgbWF0Y2hlcywgcmVzdWx0LCB6b25lLCBzcGVjaWZpY09mZnNldCB9OwogICAgfQogIH0KCiAgZnVuY3Rpb24gcGFyc2VGcm9tVG9rZW5zKGxvY2FsZSwgaW5wdXQsIGZvcm1hdCkgewogICAgY29uc3QgeyByZXN1bHQsIHpvbmUsIHNwZWNpZmljT2Zmc2V0LCBpbnZhbGlkUmVhc29uIH0gPSBleHBsYWluRnJvbVRva2Vucyhsb2NhbGUsIGlucHV0LCBmb3JtYXQpOwogICAgcmV0dXJuIFtyZXN1bHQsIHpvbmUsIHNwZWNpZmljT2Zmc2V0LCBpbnZhbGlkUmVhc29uXTsKICB9CgogIGZ1bmN0aW9uIGZvcm1hdE9wdHNUb1Rva2Vucyhmb3JtYXRPcHRzLCBsb2NhbGUpIHsKICAgIGlmICghZm9ybWF0T3B0cykgewogICAgICByZXR1cm4gbnVsbDsKICAgIH0KCiAgICBjb25zdCBmb3JtYXR0ZXIgPSBGb3JtYXR0ZXIuY3JlYXRlKGxvY2FsZSwgZm9ybWF0T3B0cyk7CiAgICBjb25zdCBkZiA9IGZvcm1hdHRlci5kdEZvcm1hdHRlcihnZXREdW1teURhdGVUaW1lKCkpOwogICAgY29uc3QgcGFydHMgPSBkZi5mb3JtYXRUb1BhcnRzKCk7CiAgICBjb25zdCByZXNvbHZlZE9wdHMgPSBkZi5yZXNvbHZlZE9wdGlvbnMoKTsKICAgIHJldHVybiBwYXJ0cy5tYXAoKHApID0+IHRva2VuRm9yUGFydChwLCBmb3JtYXRPcHRzLCByZXNvbHZlZE9wdHMpKTsKICB9CgogIGNvbnN0IG5vbkxlYXBMYWRkZXIgPSBbMCwgMzEsIDU5LCA5MCwgMTIwLCAxNTEsIDE4MSwgMjEyLCAyNDMsIDI3MywgMzA0LCAzMzRdLAogICAgbGVhcExhZGRlciA9IFswLCAzMSwgNjAsIDkxLCAxMjEsIDE1MiwgMTgyLCAyMTMsIDI0NCwgMjc0LCAzMDUsIDMzNV07CgogIGZ1bmN0aW9uIHVuaXRPdXRPZlJhbmdlKHVuaXQsIHZhbHVlKSB7CiAgICByZXR1cm4gbmV3IEludmFsaWQoCiAgICAgICJ1bml0IG91dCBvZiByYW5nZSIsCiAgICAgIGB5b3Ugc3BlY2lmaWVkICR7dmFsdWV9IChvZiB0eXBlICR7dHlwZW9mIHZhbHVlfSkgYXMgYSAke3VuaXR9LCB3aGljaCBpcyBpbnZhbGlkYAogICAgKTsKICB9CgogIGZ1bmN0aW9uIGRheU9mV2Vlayh5ZWFyLCBtb250aCwgZGF5KSB7CiAgICBjb25zdCBkID0gbmV3IERhdGUoRGF0ZS5VVEMoeWVhciwgbW9udGggLSAxLCBkYXkpKTsKCiAgICBpZiAoeWVhciA8IDEwMCAmJiB5ZWFyID49IDApIHsKICAgICAgZC5zZXRVVENGdWxsWWVhcihkLmdldFVUQ0Z1bGxZZWFyKCkgLSAxOTAwKTsKICAgIH0KCiAgICBjb25zdCBqcyA9IGQuZ2V0VVRDRGF5KCk7CgogICAgcmV0dXJuIGpzID09PSAwID8gNyA6IGpzOwogIH0KCiAgZnVuY3Rpb24gY29tcHV0ZU9yZGluYWwoeWVhciwgbW9udGgsIGRheSkgewogICAgcmV0dXJuIGRheSArIChpc0xlYXBZZWFyKHllYXIpID8gbGVhcExhZGRlciA6IG5vbkxlYXBMYWRkZXIpW21vbnRoIC0gMV07CiAgfQoKICBmdW5jdGlvbiB1bmNvbXB1dGVPcmRpbmFsKHllYXIsIG9yZGluYWwpIHsKICAgIGNvbnN0IHRhYmxlID0gaXNMZWFwWWVhcih5ZWFyKSA/IGxlYXBMYWRkZXIgOiBub25MZWFwTGFkZGVyLAogICAgICBtb250aDAgPSB0YWJsZS5maW5kSW5kZXgoKGkpID0+IGkgPCBvcmRpbmFsKSwKICAgICAgZGF5ID0gb3JkaW5hbCAtIHRhYmxlW21vbnRoMF07CiAgICByZXR1cm4geyBtb250aDogbW9udGgwICsgMSwgZGF5IH07CiAgfQoKICAvKioKICAgKiBAcHJpdmF0ZQogICAqLwoKICBmdW5jdGlvbiBncmVnb3JpYW5Ub1dlZWsoZ3JlZ09iaikgewogICAgY29uc3QgeyB5ZWFyLCBtb250aCwgZGF5IH0gPSBncmVnT2JqLAogICAgICBvcmRpbmFsID0gY29tcHV0ZU9yZGluYWwoeWVhciwgbW9udGgsIGRheSksCiAgICAgIHdlZWtkYXkgPSBkYXlPZldlZWsoeWVhciwgbW9udGgsIGRheSk7CgogICAgbGV0IHdlZWtOdW1iZXIgPSBNYXRoLmZsb29yKChvcmRpbmFsIC0gd2Vla2RheSArIDEwKSAvIDcpLAogICAgICB3ZWVrWWVhcjsKCiAgICBpZiAod2Vla051bWJlciA8IDEpIHsKICAgICAgd2Vla1llYXIgPSB5ZWFyIC0gMTsKICAgICAgd2Vla051bWJlciA9IHdlZWtzSW5XZWVrWWVhcih3ZWVrWWVhcik7CiAgICB9IGVsc2UgaWYgKHdlZWtOdW1iZXIgPiB3ZWVrc0luV2Vla1llYXIoeWVhcikpIHsKICAgICAgd2Vla1llYXIgPSB5ZWFyICsgMTsKICAgICAgd2Vla051bWJlciA9IDE7CiAgICB9IGVsc2UgewogICAgICB3ZWVrWWVhciA9IHllYXI7CiAgICB9CgogICAgcmV0dXJuIHsgd2Vla1llYXIsIHdlZWtOdW1iZXIsIHdlZWtkYXksIC4uLnRpbWVPYmplY3QoZ3JlZ09iaikgfTsKICB9CgogIGZ1bmN0aW9uIHdlZWtUb0dyZWdvcmlhbih3ZWVrRGF0YSkgewogICAgY29uc3QgeyB3ZWVrWWVhciwgd2Vla051bWJlciwgd2Vla2RheSB9ID0gd2Vla0RhdGEsCiAgICAgIHdlZWtkYXlPZkphbjQgPSBkYXlPZldlZWsod2Vla1llYXIsIDEsIDQpLAogICAgICB5ZWFySW5EYXlzID0gZGF5c0luWWVhcih3ZWVrWWVhcik7CgogICAgbGV0IG9yZGluYWwgPSB3ZWVrTnVtYmVyICogNyArIHdlZWtkYXkgLSB3ZWVrZGF5T2ZKYW40IC0gMywKICAgICAgeWVhcjsKCiAgICBpZiAob3JkaW5hbCA8IDEpIHsKICAgICAgeWVhciA9IHdlZWtZZWFyIC0gMTsKICAgICAgb3JkaW5hbCArPSBkYXlzSW5ZZWFyKHllYXIpOwogICAgfSBlbHNlIGlmIChvcmRpbmFsID4geWVhckluRGF5cykgewogICAgICB5ZWFyID0gd2Vla1llYXIgKyAxOwogICAgICBvcmRpbmFsIC09IGRheXNJblllYXIod2Vla1llYXIpOwogICAgfSBlbHNlIHsKICAgICAgeWVhciA9IHdlZWtZZWFyOwogICAgfQoKICAgIGNvbnN0IHsgbW9udGgsIGRheSB9ID0gdW5jb21wdXRlT3JkaW5hbCh5ZWFyLCBvcmRpbmFsKTsKICAgIHJldHVybiB7IHllYXIsIG1vbnRoLCBkYXksIC4uLnRpbWVPYmplY3Qod2Vla0RhdGEpIH07CiAgfQoKICBmdW5jdGlvbiBncmVnb3JpYW5Ub09yZGluYWwoZ3JlZ0RhdGEpIHsKICAgIGNvbnN0IHsgeWVhciwgbW9udGgsIGRheSB9ID0gZ3JlZ0RhdGE7CiAgICBjb25zdCBvcmRpbmFsID0gY29tcHV0ZU9yZGluYWwoeWVhciwgbW9udGgsIGRheSk7CiAgICByZXR1cm4geyB5ZWFyLCBvcmRpbmFsLCAuLi50aW1lT2JqZWN0KGdyZWdEYXRhKSB9OwogIH0KCiAgZnVuY3Rpb24gb3JkaW5hbFRvR3JlZ29yaWFuKG9yZGluYWxEYXRhKSB7CiAgICBjb25zdCB7IHllYXIsIG9yZGluYWwgfSA9IG9yZGluYWxEYXRhOwogICAgY29uc3QgeyBtb250aCwgZGF5IH0gPSB1bmNvbXB1dGVPcmRpbmFsKHllYXIsIG9yZGluYWwpOwogICAgcmV0dXJuIHsgeWVhciwgbW9udGgsIGRheSwgLi4udGltZU9iamVjdChvcmRpbmFsRGF0YSkgfTsKICB9CgogIGZ1bmN0aW9uIGhhc0ludmFsaWRXZWVrRGF0YShvYmopIHsKICAgIGNvbnN0IHZhbGlkWWVhciA9IGlzSW50ZWdlcihvYmoud2Vla1llYXIpLAogICAgICB2YWxpZFdlZWsgPSBpbnRlZ2VyQmV0d2VlbihvYmoud2Vla051bWJlciwgMSwgd2Vla3NJbldlZWtZZWFyKG9iai53ZWVrWWVhcikpLAogICAgICB2YWxpZFdlZWtkYXkgPSBpbnRlZ2VyQmV0d2VlbihvYmoud2Vla2RheSwgMSwgNyk7CgogICAgaWYgKCF2YWxpZFllYXIpIHsKICAgICAgcmV0dXJuIHVuaXRPdXRPZlJhbmdlKCJ3ZWVrWWVhciIsIG9iai53ZWVrWWVhcik7CiAgICB9IGVsc2UgaWYgKCF2YWxpZFdlZWspIHsKICAgICAgcmV0dXJuIHVuaXRPdXRPZlJhbmdlKCJ3ZWVrIiwgb2JqLndlZWspOwogICAgfSBlbHNlIGlmICghdmFsaWRXZWVrZGF5KSB7CiAgICAgIHJldHVybiB1bml0T3V0T2ZSYW5nZSgid2Vla2RheSIsIG9iai53ZWVrZGF5KTsKICAgIH0gZWxzZSByZXR1cm4gZmFsc2U7CiAgfQoKICBmdW5jdGlvbiBoYXNJbnZhbGlkT3JkaW5hbERhdGEob2JqKSB7CiAgICBjb25zdCB2YWxpZFllYXIgPSBpc0ludGVnZXIob2JqLnllYXIpLAogICAgICB2YWxpZE9yZGluYWwgPSBpbnRlZ2VyQmV0d2VlbihvYmoub3JkaW5hbCwgMSwgZGF5c0luWWVhcihvYmoueWVhcikpOwoKICAgIGlmICghdmFsaWRZZWFyKSB7CiAgICAgIHJldHVybiB1bml0T3V0T2ZSYW5nZSgieWVhciIsIG9iai55ZWFyKTsKICAgIH0gZWxzZSBpZiAoIXZhbGlkT3JkaW5hbCkgewogICAgICByZXR1cm4gdW5pdE91dE9mUmFuZ2UoIm9yZGluYWwiLCBvYmoub3JkaW5hbCk7CiAgICB9IGVsc2UgcmV0dXJuIGZhbHNlOwogIH0KCiAgZnVuY3Rpb24gaGFzSW52YWxpZEdyZWdvcmlhbkRhdGEob2JqKSB7CiAgICBjb25zdCB2YWxpZFllYXIgPSBpc0ludGVnZXIob2JqLnllYXIpLAogICAgICB2YWxpZE1vbnRoID0gaW50ZWdlckJldHdlZW4ob2JqLm1vbnRoLCAxLCAxMiksCiAgICAgIHZhbGlkRGF5ID0gaW50ZWdlckJldHdlZW4ob2JqLmRheSwgMSwgZGF5c0luTW9udGgob2JqLnllYXIsIG9iai5tb250aCkpOwoKICAgIGlmICghdmFsaWRZZWFyKSB7CiAgICAgIHJldHVybiB1bml0T3V0T2ZSYW5nZSgieWVhciIsIG9iai55ZWFyKTsKICAgIH0gZWxzZSBpZiAoIXZhbGlkTW9udGgpIHsKICAgICAgcmV0dXJuIHVuaXRPdXRPZlJhbmdlKCJtb250aCIsIG9iai5tb250aCk7CiAgICB9IGVsc2UgaWYgKCF2YWxpZERheSkgewogICAgICByZXR1cm4gdW5pdE91dE9mUmFuZ2UoImRheSIsIG9iai5kYXkpOwogICAgfSBlbHNlIHJldHVybiBmYWxzZTsKICB9CgogIGZ1bmN0aW9uIGhhc0ludmFsaWRUaW1lRGF0YShvYmopIHsKICAgIGNvbnN0IHsgaG91ciwgbWludXRlLCBzZWNvbmQsIG1pbGxpc2Vjb25kIH0gPSBvYmo7CiAgICBjb25zdCB2YWxpZEhvdXIgPQogICAgICAgIGludGVnZXJCZXR3ZWVuKGhvdXIsIDAsIDIzKSB8fAogICAgICAgIChob3VyID09PSAyNCAmJiBtaW51dGUgPT09IDAgJiYgc2Vjb25kID09PSAwICYmIG1pbGxpc2Vjb25kID09PSAwKSwKICAgICAgdmFsaWRNaW51dGUgPSBpbnRlZ2VyQmV0d2VlbihtaW51dGUsIDAsIDU5KSwKICAgICAgdmFsaWRTZWNvbmQgPSBpbnRlZ2VyQmV0d2VlbihzZWNvbmQsIDAsIDU5KSwKICAgICAgdmFsaWRNaWxsaXNlY29uZCA9IGludGVnZXJCZXR3ZWVuKG1pbGxpc2Vjb25kLCAwLCA5OTkpOwoKICAgIGlmICghdmFsaWRIb3VyKSB7CiAgICAgIHJldHVybiB1bml0T3V0T2ZSYW5nZSgiaG91ciIsIGhvdXIpOwogICAgfSBlbHNlIGlmICghdmFsaWRNaW51dGUpIHsKICAgICAgcmV0dXJuIHVuaXRPdXRPZlJhbmdlKCJtaW51dGUiLCBtaW51dGUpOwogICAgfSBlbHNlIGlmICghdmFsaWRTZWNvbmQpIHsKICAgICAgcmV0dXJuIHVuaXRPdXRPZlJhbmdlKCJzZWNvbmQiLCBzZWNvbmQpOwogICAgfSBlbHNlIGlmICghdmFsaWRNaWxsaXNlY29uZCkgewogICAgICByZXR1cm4gdW5pdE91dE9mUmFuZ2UoIm1pbGxpc2Vjb25kIiwgbWlsbGlzZWNvbmQpOwogICAgfSBlbHNlIHJldHVybiBmYWxzZTsKICB9CgogIGNvbnN0IElOVkFMSUQgPSAiSW52YWxpZCBEYXRlVGltZSI7CiAgY29uc3QgTUFYX0RBVEUgPSA4LjY0ZTE1OwoKICBmdW5jdGlvbiB1bnN1cHBvcnRlZFpvbmUoem9uZSkgewogICAgcmV0dXJuIG5ldyBJbnZhbGlkKCJ1bnN1cHBvcnRlZCB6b25lIiwgYHRoZSB6b25lICIke3pvbmUubmFtZX0iIGlzIG5vdCBzdXBwb3J0ZWRgKTsKICB9CgogIC8vIHdlIGNhY2hlIHdlZWsgZGF0YSBvbiB0aGUgRFQgb2JqZWN0IGFuZCB0aGlzIGludGVybWVkaWF0ZXMgdGhlIGNhY2hlCiAgZnVuY3Rpb24gcG9zc2libHlDYWNoZWRXZWVrRGF0YShkdCkgewogICAgaWYgKGR0LndlZWtEYXRhID09PSBudWxsKSB7CiAgICAgIGR0LndlZWtEYXRhID0gZ3JlZ29yaWFuVG9XZWVrKGR0LmMpOwogICAgfQogICAgcmV0dXJuIGR0LndlZWtEYXRhOwogIH0KCiAgLy8gY2xvbmUgcmVhbGx5IG1lYW5zLCAibWFrZSBhIG5ldyBvYmplY3Qgd2l0aCB0aGVzZSBtb2RpZmljYXRpb25zIi4gYWxsICJzZXR0ZXJzIiByZWFsbHkgdXNlIHRoaXMKICAvLyB0byBjcmVhdGUgYSBuZXcgb2JqZWN0IHdoaWxlIG9ubHkgY2hhbmdpbmcgc29tZSBvZiB0aGUgcHJvcGVydGllcwogIGZ1bmN0aW9uIGNsb25lKGluc3QsIGFsdHMpIHsKICAgIGNvbnN0IGN1cnJlbnQgPSB7CiAgICAgIHRzOiBpbnN0LnRzLAogICAgICB6b25lOiBpbnN0LnpvbmUsCiAgICAgIGM6IGluc3QuYywKICAgICAgbzogaW5zdC5vLAogICAgICBsb2M6IGluc3QubG9jLAogICAgICBpbnZhbGlkOiBpbnN0LmludmFsaWQsCiAgICB9OwogICAgcmV0dXJuIG5ldyBEYXRlVGltZSh7IC4uLmN1cnJlbnQsIC4uLmFsdHMsIG9sZDogY3VycmVudCB9KTsKICB9CgogIC8vIGZpbmQgdGhlIHJpZ2h0IG9mZnNldCBhIGdpdmVuIGxvY2FsIHRpbWUuIFRoZSBvIGlucHV0IGlzIG91ciBndWVzcywgd2hpY2ggZGV0ZXJtaW5lcyB3aGljaAogIC8vIG9mZnNldCB3ZSdsbCBwaWNrIGluIGFtYmlndW91cyBjYXNlcyAoZS5nLiB0aGVyZSBhcmUgdHdvIDMgQU1zIGIvYyBGYWxsYmFjayBEU1QpCiAgZnVuY3Rpb24gZml4T2Zmc2V0KGxvY2FsVFMsIG8sIHR6KSB7CiAgICAvLyBPdXIgVVRDIHRpbWUgaXMganVzdCBhIGd1ZXNzIGJlY2F1c2Ugb3VyIG9mZnNldCBpcyBqdXN0IGEgZ3Vlc3MKICAgIGxldCB1dGNHdWVzcyA9IGxvY2FsVFMgLSBvICogNjAgKiAxMDAwOwoKICAgIC8vIFRlc3Qgd2hldGhlciB0aGUgem9uZSBtYXRjaGVzIHRoZSBvZmZzZXQgZm9yIHRoaXMgdHMKICAgIGNvbnN0IG8yID0gdHoub2Zmc2V0KHV0Y0d1ZXNzKTsKCiAgICAvLyBJZiBzbywgb2Zmc2V0IGRpZG4ndCBjaGFuZ2UgYW5kIHdlJ3JlIGRvbmUKICAgIGlmIChvID09PSBvMikgewogICAgICByZXR1cm4gW3V0Y0d1ZXNzLCBvXTsKICAgIH0KCiAgICAvLyBJZiBub3QsIGNoYW5nZSB0aGUgdHMgYnkgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIG9mZnNldAogICAgdXRjR3Vlc3MgLT0gKG8yIC0gbykgKiA2MCAqIDEwMDA7CgogICAgLy8gSWYgdGhhdCBnaXZlcyB1cyB0aGUgbG9jYWwgdGltZSB3ZSB3YW50LCB3ZSdyZSBkb25lCiAgICBjb25zdCBvMyA9IHR6Lm9mZnNldCh1dGNHdWVzcyk7CiAgICBpZiAobzIgPT09IG8zKSB7CiAgICAgIHJldHVybiBbdXRjR3Vlc3MsIG8yXTsKICAgIH0KCiAgICAvLyBJZiBpdCdzIGRpZmZlcmVudCwgd2UncmUgaW4gYSBob2xlIHRpbWUuIFRoZSBvZmZzZXQgaGFzIGNoYW5nZWQsIGJ1dCB0aGUgd2UgZG9uJ3QgYWRqdXN0IHRoZSB0aW1lCiAgICByZXR1cm4gW2xvY2FsVFMgLSBNYXRoLm1pbihvMiwgbzMpICogNjAgKiAxMDAwLCBNYXRoLm1heChvMiwgbzMpXTsKICB9CgogIC8vIGNvbnZlcnQgYW4gZXBvY2ggdGltZXN0YW1wIGludG8gYSBjYWxlbmRhciBvYmplY3Qgd2l0aCB0aGUgZ2l2ZW4gb2Zmc2V0CiAgZnVuY3Rpb24gdHNUb09iaih0cywgb2Zmc2V0KSB7CiAgICB0cyArPSBvZmZzZXQgKiA2MCAqIDEwMDA7CgogICAgY29uc3QgZCA9IG5ldyBEYXRlKHRzKTsKCiAgICByZXR1cm4gewogICAgICB5ZWFyOiBkLmdldFVUQ0Z1bGxZZWFyKCksCiAgICAgIG1vbnRoOiBkLmdldFVUQ01vbnRoKCkgKyAxLAogICAgICBkYXk6IGQuZ2V0VVRDRGF0ZSgpLAogICAgICBob3VyOiBkLmdldFVUQ0hvdXJzKCksCiAgICAgIG1pbnV0ZTogZC5nZXRVVENNaW51dGVzKCksCiAgICAgIHNlY29uZDogZC5nZXRVVENTZWNvbmRzKCksCiAgICAgIG1pbGxpc2Vjb25kOiBkLmdldFVUQ01pbGxpc2Vjb25kcygpLAogICAgfTsKICB9CgogIC8vIGNvbnZlcnQgYSBjYWxlbmRhciBvYmplY3QgdG8gYSBlcG9jaCB0aW1lc3RhbXAKICBmdW5jdGlvbiBvYmpUb1RTKG9iaiwgb2Zmc2V0LCB6b25lKSB7CiAgICByZXR1cm4gZml4T2Zmc2V0KG9ialRvTG9jYWxUUyhvYmopLCBvZmZzZXQsIHpvbmUpOwogIH0KCiAgLy8gY3JlYXRlIGEgbmV3IERUIGluc3RhbmNlIGJ5IGFkZGluZyBhIGR1cmF0aW9uLCBhZGp1c3RpbmcgZm9yIERTVHMKICBmdW5jdGlvbiBhZGp1c3RUaW1lKGluc3QsIGR1cikgewogICAgY29uc3Qgb1ByZSA9IGluc3QubywKICAgICAgeWVhciA9IGluc3QuYy55ZWFyICsgTWF0aC50cnVuYyhkdXIueWVhcnMpLAogICAgICBtb250aCA9IGluc3QuYy5tb250aCArIE1hdGgudHJ1bmMoZHVyLm1vbnRocykgKyBNYXRoLnRydW5jKGR1ci5xdWFydGVycykgKiAzLAogICAgICBjID0gewogICAgICAgIC4uLmluc3QuYywKICAgICAgICB5ZWFyLAogICAgICAgIG1vbnRoLAogICAgICAgIGRheToKICAgICAgICAgIE1hdGgubWluKGluc3QuYy5kYXksIGRheXNJbk1vbnRoKHllYXIsIG1vbnRoKSkgKwogICAgICAgICAgTWF0aC50cnVuYyhkdXIuZGF5cykgKwogICAgICAgICAgTWF0aC50cnVuYyhkdXIud2Vla3MpICogNywKICAgICAgfSwKICAgICAgbWlsbGlzVG9BZGQgPSBEdXJhdGlvbi5mcm9tT2JqZWN0KHsKICAgICAgICB5ZWFyczogZHVyLnllYXJzIC0gTWF0aC50cnVuYyhkdXIueWVhcnMpLAogICAgICAgIHF1YXJ0ZXJzOiBkdXIucXVhcnRlcnMgLSBNYXRoLnRydW5jKGR1ci5xdWFydGVycyksCiAgICAgICAgbW9udGhzOiBkdXIubW9udGhzIC0gTWF0aC50cnVuYyhkdXIubW9udGhzKSwKICAgICAgICB3ZWVrczogZHVyLndlZWtzIC0gTWF0aC50cnVuYyhkdXIud2Vla3MpLAogICAgICAgIGRheXM6IGR1ci5kYXlzIC0gTWF0aC50cnVuYyhkdXIuZGF5cyksCiAgICAgICAgaG91cnM6IGR1ci5ob3VycywKICAgICAgICBtaW51dGVzOiBkdXIubWludXRlcywKICAgICAgICBzZWNvbmRzOiBkdXIuc2Vjb25kcywKICAgICAgICBtaWxsaXNlY29uZHM6IGR1ci5taWxsaXNlY29uZHMsCiAgICAgIH0pLmFzKCJtaWxsaXNlY29uZHMiKSwKICAgICAgbG9jYWxUUyA9IG9ialRvTG9jYWxUUyhjKTsKCiAgICBsZXQgW3RzLCBvXSA9IGZpeE9mZnNldChsb2NhbFRTLCBvUHJlLCBpbnN0LnpvbmUpOwoKICAgIGlmIChtaWxsaXNUb0FkZCAhPT0gMCkgewogICAgICB0cyArPSBtaWxsaXNUb0FkZDsKICAgICAgLy8gdGhhdCBjb3VsZCBoYXZlIGNoYW5nZWQgdGhlIG9mZnNldCBieSBnb2luZyBvdmVyIGEgRFNULCBidXQgd2Ugd2FudCB0byBrZWVwIHRoZSB0cyB0aGUgc2FtZQogICAgICBvID0gaW5zdC56b25lLm9mZnNldCh0cyk7CiAgICB9CgogICAgcmV0dXJuIHsgdHMsIG8gfTsKICB9CgogIC8vIGhlbHBlciB1c2VmdWwgaW4gdHVybmluZyB0aGUgcmVzdWx0cyBvZiBwYXJzaW5nIGludG8gcmVhbCBkYXRlcwogIC8vIGJ5IGhhbmRsaW5nIHRoZSB6b25lIG9wdGlvbnMKICBmdW5jdGlvbiBwYXJzZURhdGFUb0RhdGVUaW1lKHBhcnNlZCwgcGFyc2VkWm9uZSwgb3B0cywgZm9ybWF0LCB0ZXh0LCBzcGVjaWZpY09mZnNldCkgewogICAgY29uc3QgeyBzZXRab25lLCB6b25lIH0gPSBvcHRzOwogICAgaWYgKChwYXJzZWQgJiYgT2JqZWN0LmtleXMocGFyc2VkKS5sZW5ndGggIT09IDApIHx8IHBhcnNlZFpvbmUpIHsKICAgICAgY29uc3QgaW50ZXJwcmV0YXRpb25ab25lID0gcGFyc2VkWm9uZSB8fCB6b25lLAogICAgICAgIGluc3QgPSBEYXRlVGltZS5mcm9tT2JqZWN0KHBhcnNlZCwgewogICAgICAgICAgLi4ub3B0cywKICAgICAgICAgIHpvbmU6IGludGVycHJldGF0aW9uWm9uZSwKICAgICAgICAgIHNwZWNpZmljT2Zmc2V0LAogICAgICAgIH0pOwogICAgICByZXR1cm4gc2V0Wm9uZSA/IGluc3QgOiBpbnN0LnNldFpvbmUoem9uZSk7CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gRGF0ZVRpbWUuaW52YWxpZCgKICAgICAgICBuZXcgSW52YWxpZCgidW5wYXJzYWJsZSIsIGB0aGUgaW5wdXQgIiR7dGV4dH0iIGNhbid0IGJlIHBhcnNlZCBhcyAke2Zvcm1hdH1gKQogICAgICApOwogICAgfQogIH0KCiAgLy8gaWYgeW91IHdhbnQgdG8gb3V0cHV0IGEgdGVjaG5pY2FsIGZvcm1hdCAoZS5nLiBSRkMgMjgyMiksIHRoaXMgaGVscGVyCiAgLy8gaGVscHMgaGFuZGxlIHRoZSBkZXRhaWxzCiAgZnVuY3Rpb24gdG9UZWNoRm9ybWF0KGR0LCBmb3JtYXQsIGFsbG93WiA9IHRydWUpIHsKICAgIHJldHVybiBkdC5pc1ZhbGlkCiAgICAgID8gRm9ybWF0dGVyLmNyZWF0ZShMb2NhbGUuY3JlYXRlKCJlbi1VUyIpLCB7CiAgICAgICAgICBhbGxvd1osCiAgICAgICAgICBmb3JjZVNpbXBsZTogdHJ1ZSwKICAgICAgICB9KS5mb3JtYXREYXRlVGltZUZyb21TdHJpbmcoZHQsIGZvcm1hdCkKICAgICAgOiBudWxsOwogIH0KCiAgZnVuY3Rpb24gdG9JU09EYXRlKG8sIGV4dGVuZGVkKSB7CiAgICBjb25zdCBsb25nRm9ybWF0ID0gby5jLnllYXIgPiA5OTk5IHx8IG8uYy55ZWFyIDwgMDsKICAgIGxldCBjID0gIiI7CiAgICBpZiAobG9uZ0Zvcm1hdCAmJiBvLmMueWVhciA+PSAwKSBjICs9ICIrIjsKICAgIGMgKz0gcGFkU3RhcnQoby5jLnllYXIsIGxvbmdGb3JtYXQgPyA2IDogNCk7CgogICAgaWYgKGV4dGVuZGVkKSB7CiAgICAgIGMgKz0gIi0iOwogICAgICBjICs9IHBhZFN0YXJ0KG8uYy5tb250aCk7CiAgICAgIGMgKz0gIi0iOwogICAgICBjICs9IHBhZFN0YXJ0KG8uYy5kYXkpOwogICAgfSBlbHNlIHsKICAgICAgYyArPSBwYWRTdGFydChvLmMubW9udGgpOwogICAgICBjICs9IHBhZFN0YXJ0KG8uYy5kYXkpOwogICAgfQogICAgcmV0dXJuIGM7CiAgfQoKICBmdW5jdGlvbiB0b0lTT1RpbWUoCiAgICBvLAogICAgZXh0ZW5kZWQsCiAgICBzdXBwcmVzc1NlY29uZHMsCiAgICBzdXBwcmVzc01pbGxpc2Vjb25kcywKICAgIGluY2x1ZGVPZmZzZXQsCiAgICBleHRlbmRlZFpvbmUKICApIHsKICAgIGxldCBjID0gcGFkU3RhcnQoby5jLmhvdXIpOwogICAgaWYgKGV4dGVuZGVkKSB7CiAgICAgIGMgKz0gIjoiOwogICAgICBjICs9IHBhZFN0YXJ0KG8uYy5taW51dGUpOwogICAgICBpZiAoby5jLm1pbGxpc2Vjb25kICE9PSAwIHx8IG8uYy5zZWNvbmQgIT09IDAgfHwgIXN1cHByZXNzU2Vjb25kcykgewogICAgICAgIGMgKz0gIjoiOwogICAgICB9CiAgICB9IGVsc2UgewogICAgICBjICs9IHBhZFN0YXJ0KG8uYy5taW51dGUpOwogICAgfQoKICAgIGlmIChvLmMubWlsbGlzZWNvbmQgIT09IDAgfHwgby5jLnNlY29uZCAhPT0gMCB8fCAhc3VwcHJlc3NTZWNvbmRzKSB7CiAgICAgIGMgKz0gcGFkU3RhcnQoby5jLnNlY29uZCk7CgogICAgICBpZiAoby5jLm1pbGxpc2Vjb25kICE9PSAwIHx8ICFzdXBwcmVzc01pbGxpc2Vjb25kcykgewogICAgICAgIGMgKz0gIi4iOwogICAgICAgIGMgKz0gcGFkU3RhcnQoby5jLm1pbGxpc2Vjb25kLCAzKTsKICAgICAgfQogICAgfQoKICAgIGlmIChpbmNsdWRlT2Zmc2V0KSB7CiAgICAgIGlmIChvLmlzT2Zmc2V0Rml4ZWQgJiYgby5vZmZzZXQgPT09IDAgJiYgIWV4dGVuZGVkWm9uZSkgewogICAgICAgIGMgKz0gIloiOwogICAgICB9IGVsc2UgaWYgKG8ubyA8IDApIHsKICAgICAgICBjICs9ICItIjsKICAgICAgICBjICs9IHBhZFN0YXJ0KE1hdGgudHJ1bmMoLW8ubyAvIDYwKSk7CiAgICAgICAgYyArPSAiOiI7CiAgICAgICAgYyArPSBwYWRTdGFydChNYXRoLnRydW5jKC1vLm8gJSA2MCkpOwogICAgICB9IGVsc2UgewogICAgICAgIGMgKz0gIisiOwogICAgICAgIGMgKz0gcGFkU3RhcnQoTWF0aC50cnVuYyhvLm8gLyA2MCkpOwogICAgICAgIGMgKz0gIjoiOwogICAgICAgIGMgKz0gcGFkU3RhcnQoTWF0aC50cnVuYyhvLm8gJSA2MCkpOwogICAgICB9CiAgICB9CgogICAgaWYgKGV4dGVuZGVkWm9uZSkgewogICAgICBjICs9ICJbIiArIG8uem9uZS5pYW5hTmFtZSArICJdIjsKICAgIH0KICAgIHJldHVybiBjOwogIH0KCiAgLy8gZGVmYXVsdHMgZm9yIHVuc3BlY2lmaWVkIHVuaXRzIGluIHRoZSBzdXBwb3J0ZWQgY2FsZW5kYXJzCiAgY29uc3QgZGVmYXVsdFVuaXRWYWx1ZXMgPSB7CiAgICAgIG1vbnRoOiAxLAogICAgICBkYXk6IDEsCiAgICAgIGhvdXI6IDAsCiAgICAgIG1pbnV0ZTogMCwKICAgICAgc2Vjb25kOiAwLAogICAgICBtaWxsaXNlY29uZDogMCwKICAgIH0sCiAgICBkZWZhdWx0V2Vla1VuaXRWYWx1ZXMgPSB7CiAgICAgIHdlZWtOdW1iZXI6IDEsCiAgICAgIHdlZWtkYXk6IDEsCiAgICAgIGhvdXI6IDAsCiAgICAgIG1pbnV0ZTogMCwKICAgICAgc2Vjb25kOiAwLAogICAgICBtaWxsaXNlY29uZDogMCwKICAgIH0sCiAgICBkZWZhdWx0T3JkaW5hbFVuaXRWYWx1ZXMgPSB7CiAgICAgIG9yZGluYWw6IDEsCiAgICAgIGhvdXI6IDAsCiAgICAgIG1pbnV0ZTogMCwKICAgICAgc2Vjb25kOiAwLAogICAgICBtaWxsaXNlY29uZDogMCwKICAgIH07CgogIC8vIFVuaXRzIGluIHRoZSBzdXBwb3J0ZWQgY2FsZW5kYXJzLCBzb3J0ZWQgYnkgYmlnbmVzcwogIGNvbnN0IG9yZGVyZWRVbml0cyA9IFsieWVhciIsICJtb250aCIsICJkYXkiLCAiaG91ciIsICJtaW51dGUiLCAic2Vjb25kIiwgIm1pbGxpc2Vjb25kIl0sCiAgICBvcmRlcmVkV2Vla1VuaXRzID0gWwogICAgICAid2Vla1llYXIiLAogICAgICAid2Vla051bWJlciIsCiAgICAgICJ3ZWVrZGF5IiwKICAgICAgImhvdXIiLAogICAgICAibWludXRlIiwKICAgICAgInNlY29uZCIsCiAgICAgICJtaWxsaXNlY29uZCIsCiAgICBdLAogICAgb3JkZXJlZE9yZGluYWxVbml0cyA9IFsieWVhciIsICJvcmRpbmFsIiwgImhvdXIiLCAibWludXRlIiwgInNlY29uZCIsICJtaWxsaXNlY29uZCJdOwoKICAvLyBzdGFuZGFyZGl6ZSBjYXNlIGFuZCBwbHVyYWxpdHkgaW4gdW5pdHMKICBmdW5jdGlvbiBub3JtYWxpemVVbml0KHVuaXQpIHsKICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSB7CiAgICAgIHllYXI6ICJ5ZWFyIiwKICAgICAgeWVhcnM6ICJ5ZWFyIiwKICAgICAgbW9udGg6ICJtb250aCIsCiAgICAgIG1vbnRoczogIm1vbnRoIiwKICAgICAgZGF5OiAiZGF5IiwKICAgICAgZGF5czogImRheSIsCiAgICAgIGhvdXI6ICJob3VyIiwKICAgICAgaG91cnM6ICJob3VyIiwKICAgICAgbWludXRlOiAibWludXRlIiwKICAgICAgbWludXRlczogIm1pbnV0ZSIsCiAgICAgIHF1YXJ0ZXI6ICJxdWFydGVyIiwKICAgICAgcXVhcnRlcnM6ICJxdWFydGVyIiwKICAgICAgc2Vjb25kOiAic2Vjb25kIiwKICAgICAgc2Vjb25kczogInNlY29uZCIsCiAgICAgIG1pbGxpc2Vjb25kOiAibWlsbGlzZWNvbmQiLAogICAgICBtaWxsaXNlY29uZHM6ICJtaWxsaXNlY29uZCIsCiAgICAgIHdlZWtkYXk6ICJ3ZWVrZGF5IiwKICAgICAgd2Vla2RheXM6ICJ3ZWVrZGF5IiwKICAgICAgd2Vla251bWJlcjogIndlZWtOdW1iZXIiLAogICAgICB3ZWVrc251bWJlcjogIndlZWtOdW1iZXIiLAogICAgICB3ZWVrbnVtYmVyczogIndlZWtOdW1iZXIiLAogICAgICB3ZWVreWVhcjogIndlZWtZZWFyIiwKICAgICAgd2Vla3llYXJzOiAid2Vla1llYXIiLAogICAgICBvcmRpbmFsOiAib3JkaW5hbCIsCiAgICB9W3VuaXQudG9Mb3dlckNhc2UoKV07CgogICAgaWYgKCFub3JtYWxpemVkKSB0aHJvdyBuZXcgSW52YWxpZFVuaXRFcnJvcih1bml0KTsKCiAgICByZXR1cm4gbm9ybWFsaXplZDsKICB9CgogIC8vIHRoaXMgaXMgYSBkdW1iZWQgZG93biB2ZXJzaW9uIG9mIGZyb21PYmplY3QoKSB0aGF0IHJ1bnMgYWJvdXQgNjAlIGZhc3RlcgogIC8vIGJ1dCBkb2Vzbid0IGRvIGFueSB2YWxpZGF0aW9uLCBtYWtlcyBhIGJ1bmNoIG9mIGFzc3VtcHRpb25zIGFib3V0IHdoYXQgdW5pdHMKICAvLyBhcmUgcHJlc2VudCwgYW5kIHNvIG9uLgogIGZ1bmN0aW9uIHF1aWNrRFQob2JqLCBvcHRzKSB7CiAgICBjb25zdCB6b25lID0gbm9ybWFsaXplWm9uZShvcHRzLnpvbmUsIFNldHRpbmdzLmRlZmF1bHRab25lKSwKICAgICAgbG9jID0gTG9jYWxlLmZyb21PYmplY3Qob3B0cyksCiAgICAgIHRzTm93ID0gU2V0dGluZ3Mubm93KCk7CgogICAgbGV0IHRzLCBvOwoKICAgIC8vIGFzc3VtZSB3ZSBoYXZlIHRoZSBoaWdoZXItb3JkZXIgdW5pdHMKICAgIGlmICghaXNVbmRlZmluZWQob2JqLnllYXIpKSB7CiAgICAgIGZvciAoY29uc3QgdSBvZiBvcmRlcmVkVW5pdHMpIHsKICAgICAgICBpZiAoaXNVbmRlZmluZWQob2JqW3VdKSkgewogICAgICAgICAgb2JqW3VdID0gZGVmYXVsdFVuaXRWYWx1ZXNbdV07CiAgICAgICAgfQogICAgICB9CgogICAgICBjb25zdCBpbnZhbGlkID0gaGFzSW52YWxpZEdyZWdvcmlhbkRhdGEob2JqKSB8fCBoYXNJbnZhbGlkVGltZURhdGEob2JqKTsKICAgICAgaWYgKGludmFsaWQpIHsKICAgICAgICByZXR1cm4gRGF0ZVRpbWUuaW52YWxpZChpbnZhbGlkKTsKICAgICAgfQoKICAgICAgY29uc3Qgb2Zmc2V0UHJvdmlzID0gem9uZS5vZmZzZXQodHNOb3cpOwogICAgICBbdHMsIG9dID0gb2JqVG9UUyhvYmosIG9mZnNldFByb3Zpcywgem9uZSk7CiAgICB9IGVsc2UgewogICAgICB0cyA9IHRzTm93OwogICAgfQoKICAgIHJldHVybiBuZXcgRGF0ZVRpbWUoeyB0cywgem9uZSwgbG9jLCBvIH0pOwogIH0KCiAgZnVuY3Rpb24gZGlmZlJlbGF0aXZlKHN0YXJ0LCBlbmQsIG9wdHMpIHsKICAgIGNvbnN0IHJvdW5kID0gaXNVbmRlZmluZWQob3B0cy5yb3VuZCkgPyB0cnVlIDogb3B0cy5yb3VuZCwKICAgICAgZm9ybWF0ID0gKGMsIHVuaXQpID0+IHsKICAgICAgICBjID0gcm91bmRUbyhjLCByb3VuZCB8fCBvcHRzLmNhbGVuZGFyeSA/IDAgOiAyLCB0cnVlKTsKICAgICAgICBjb25zdCBmb3JtYXR0ZXIgPSBlbmQubG9jLmNsb25lKG9wdHMpLnJlbEZvcm1hdHRlcihvcHRzKTsKICAgICAgICByZXR1cm4gZm9ybWF0dGVyLmZvcm1hdChjLCB1bml0KTsKICAgICAgfSwKICAgICAgZGlmZmVyID0gKHVuaXQpID0+IHsKICAgICAgICBpZiAob3B0cy5jYWxlbmRhcnkpIHsKICAgICAgICAgIGlmICghZW5kLmhhc1NhbWUoc3RhcnQsIHVuaXQpKSB7CiAgICAgICAgICAgIHJldHVybiBlbmQuc3RhcnRPZih1bml0KS5kaWZmKHN0YXJ0LnN0YXJ0T2YodW5pdCksIHVuaXQpLmdldCh1bml0KTsKICAgICAgICAgIH0gZWxzZSByZXR1cm4gMDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmV0dXJuIGVuZC5kaWZmKHN0YXJ0LCB1bml0KS5nZXQodW5pdCk7CiAgICAgICAgfQogICAgICB9OwoKICAgIGlmIChvcHRzLnVuaXQpIHsKICAgICAgcmV0dXJuIGZvcm1hdChkaWZmZXIob3B0cy51bml0KSwgb3B0cy51bml0KTsKICAgIH0KCiAgICBmb3IgKGNvbnN0IHVuaXQgb2Ygb3B0cy51bml0cykgewogICAgICBjb25zdCBjb3VudCA9IGRpZmZlcih1bml0KTsKICAgICAgaWYgKE1hdGguYWJzKGNvdW50KSA+PSAxKSB7CiAgICAgICAgcmV0dXJuIGZvcm1hdChjb3VudCwgdW5pdCk7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBmb3JtYXQoc3RhcnQgPiBlbmQgPyAtMCA6IDAsIG9wdHMudW5pdHNbb3B0cy51bml0cy5sZW5ndGggLSAxXSk7CiAgfQoKICBmdW5jdGlvbiBsYXN0T3B0cyhhcmdMaXN0KSB7CiAgICBsZXQgb3B0cyA9IHt9LAogICAgICBhcmdzOwogICAgaWYgKGFyZ0xpc3QubGVuZ3RoID4gMCAmJiB0eXBlb2YgYXJnTGlzdFthcmdMaXN0Lmxlbmd0aCAtIDFdID09PSAib2JqZWN0IikgewogICAgICBvcHRzID0gYXJnTGlzdFthcmdMaXN0Lmxlbmd0aCAtIDFdOwogICAgICBhcmdzID0gQXJyYXkuZnJvbShhcmdMaXN0KS5zbGljZSgwLCBhcmdMaXN0Lmxlbmd0aCAtIDEpOwogICAgfSBlbHNlIHsKICAgICAgYXJncyA9IEFycmF5LmZyb20oYXJnTGlzdCk7CiAgICB9CiAgICByZXR1cm4gW29wdHMsIGFyZ3NdOwogIH0KCiAgLyoqCiAgICogQSBEYXRlVGltZSBpcyBhbiBpbW11dGFibGUgZGF0YSBzdHJ1Y3R1cmUgcmVwcmVzZW50aW5nIGEgc3BlY2lmaWMgZGF0ZSBhbmQgdGltZSBhbmQgYWNjb21wYW55aW5nIG1ldGhvZHMuIEl0IGNvbnRhaW5zIGNsYXNzIGFuZCBpbnN0YW5jZSBtZXRob2RzIGZvciBjcmVhdGluZywgcGFyc2luZywgaW50ZXJyb2dhdGluZywgdHJhbnNmb3JtaW5nLCBhbmQgZm9ybWF0dGluZyB0aGVtLgogICAqCiAgICogQSBEYXRlVGltZSBjb21wcmlzZXMgb2Y6CiAgICogKiBBIHRpbWVzdGFtcC4gRWFjaCBEYXRlVGltZSBpbnN0YW5jZSByZWZlcnMgdG8gYSBzcGVjaWZpYyBtaWxsaXNlY29uZCBvZiB0aGUgVW5peCBlcG9jaC4KICAgKiAqIEEgdGltZSB6b25lLiBFYWNoIGluc3RhbmNlIGlzIGNvbnNpZGVyZWQgaW4gdGhlIGNvbnRleHQgb2YgYSBzcGVjaWZpYyB6b25lIChieSBkZWZhdWx0IHRoZSBsb2NhbCBzeXN0ZW0ncyB6b25lKS4KICAgKiAqIENvbmZpZ3VyYXRpb24gcHJvcGVydGllcyB0aGF0IGVmZmVjdCBob3cgb3V0cHV0IHN0cmluZ3MgYXJlIGZvcm1hdHRlZCwgc3VjaCBhcyBgbG9jYWxlYCwgYG51bWJlcmluZ1N5c3RlbWAsIGFuZCBgb3V0cHV0Q2FsZW5kYXJgLgogICAqCiAgICogSGVyZSBpcyBhIGJyaWVmIG92ZXJ2aWV3IG9mIHRoZSBtb3N0IGNvbW1vbmx5IHVzZWQgZnVuY3Rpb25hbGl0eSBpdCBwcm92aWRlczoKICAgKgogICAqICogKipDcmVhdGlvbioqOiBUbyBjcmVhdGUgYSBEYXRlVGltZSBmcm9tIGl0cyBjb21wb25lbnRzLCB1c2Ugb25lIG9mIGl0cyBmYWN0b3J5IGNsYXNzIG1ldGhvZHM6IHtAbGluayBEYXRlVGltZS5sb2NhbH0sIHtAbGluayBEYXRlVGltZS51dGN9LCBhbmQgKG1vc3QgZmxleGlibHkpIHtAbGluayBEYXRlVGltZS5mcm9tT2JqZWN0fS4gVG8gY3JlYXRlIG9uZSBmcm9tIGEgc3RhbmRhcmQgc3RyaW5nIGZvcm1hdCwgdXNlIHtAbGluayBEYXRlVGltZS5mcm9tSVNPfSwge0BsaW5rIERhdGVUaW1lLmZyb21IVFRQfSwgYW5kIHtAbGluayBEYXRlVGltZS5mcm9tUkZDMjgyMn0uIFRvIGNyZWF0ZSBvbmUgZnJvbSBhIGN1c3RvbSBzdHJpbmcgZm9ybWF0LCB1c2Uge0BsaW5rIERhdGVUaW1lLmZyb21Gb3JtYXR9LiBUbyBjcmVhdGUgb25lIGZyb20gYSBuYXRpdmUgSlMgZGF0ZSwgdXNlIHtAbGluayBEYXRlVGltZS5mcm9tSlNEYXRlfS4KICAgKiAqICoqR3JlZ29yaWFuIGNhbGVuZGFyIGFuZCB0aW1lKio6IFRvIGV4YW1pbmUgdGhlIEdyZWdvcmlhbiBwcm9wZXJ0aWVzIG9mIGEgRGF0ZVRpbWUgaW5kaXZpZHVhbGx5IChpLmUgYXMgb3Bwb3NlZCB0byBjb2xsZWN0aXZlbHkgdGhyb3VnaCB7QGxpbmsgRGF0ZVRpbWUjdG9PYmplY3R9KSwgdXNlIHRoZSB7QGxpbmsgRGF0ZVRpbWUjeWVhcn0sIHtAbGluayBEYXRlVGltZSNtb250aH0sCiAgICoge0BsaW5rIERhdGVUaW1lI2RheX0sIHtAbGluayBEYXRlVGltZSNob3VyfSwge0BsaW5rIERhdGVUaW1lI21pbnV0ZX0sIHtAbGluayBEYXRlVGltZSNzZWNvbmR9LCB7QGxpbmsgRGF0ZVRpbWUjbWlsbGlzZWNvbmR9IGFjY2Vzc29ycy4KICAgKiAqICoqV2VlayBjYWxlbmRhcioqOiBGb3IgSVNPIHdlZWsgY2FsZW5kYXIgYXR0cmlidXRlcywgc2VlIHRoZSB7QGxpbmsgRGF0ZVRpbWUjd2Vla1llYXJ9LCB7QGxpbmsgRGF0ZVRpbWUjd2Vla051bWJlcn0sIGFuZCB7QGxpbmsgRGF0ZVRpbWUjd2Vla2RheX0gYWNjZXNzb3JzLgogICAqICogKipDb25maWd1cmF0aW9uKiogU2VlIHRoZSB7QGxpbmsgRGF0ZVRpbWUjbG9jYWxlfSBhbmQge0BsaW5rIERhdGVUaW1lI251bWJlcmluZ1N5c3RlbX0gYWNjZXNzb3JzLgogICAqICogKipUcmFuc2Zvcm1hdGlvbioqOiBUbyB0cmFuc2Zvcm0gdGhlIERhdGVUaW1lIGludG8gb3RoZXIgRGF0ZVRpbWVzLCB1c2Uge0BsaW5rIERhdGVUaW1lI3NldH0sIHtAbGluayBEYXRlVGltZSNyZWNvbmZpZ3VyZX0sIHtAbGluayBEYXRlVGltZSNzZXRab25lfSwge0BsaW5rIERhdGVUaW1lI3NldExvY2FsZX0sIHtAbGluayBEYXRlVGltZS5wbHVzfSwge0BsaW5rIERhdGVUaW1lI21pbnVzfSwge0BsaW5rIERhdGVUaW1lI2VuZE9mfSwge0BsaW5rIERhdGVUaW1lI3N0YXJ0T2Z9LCB7QGxpbmsgRGF0ZVRpbWUjdG9VVEN9LCBhbmQge0BsaW5rIERhdGVUaW1lI3RvTG9jYWx9LgogICAqICogKipPdXRwdXQqKjogVG8gY29udmVydCB0aGUgRGF0ZVRpbWUgdG8gb3RoZXIgcmVwcmVzZW50YXRpb25zLCB1c2UgdGhlIHtAbGluayBEYXRlVGltZSN0b1JlbGF0aXZlfSwge0BsaW5rIERhdGVUaW1lI3RvUmVsYXRpdmVDYWxlbmRhcn0sIHtAbGluayBEYXRlVGltZSN0b0pTT059LCB7QGxpbmsgRGF0ZVRpbWUjdG9JU099LCB7QGxpbmsgRGF0ZVRpbWUjdG9IVFRQfSwge0BsaW5rIERhdGVUaW1lI3RvT2JqZWN0fSwge0BsaW5rIERhdGVUaW1lI3RvUkZDMjgyMn0sIHtAbGluayBEYXRlVGltZSN0b1N0cmluZ30sIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30sIHtAbGluayBEYXRlVGltZSN0b0Zvcm1hdH0sIHtAbGluayBEYXRlVGltZSN0b01pbGxpc30gYW5kIHtAbGluayBEYXRlVGltZSN0b0pTRGF0ZX0uCiAgICoKICAgKiBUaGVyZSdzIHBsZW50eSBvdGhlcnMgZG9jdW1lbnRlZCBiZWxvdy4gSW4gYWRkaXRpb24sIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHN1YnRsZXIgdG9waWNzIGxpa2UgaW50ZXJuYXRpb25hbGl6YXRpb24sIHRpbWUgem9uZXMsIGFsdGVybmF0aXZlIGNhbGVuZGFycywgdmFsaWRpdHksIGFuZCBzbyBvbiwgc2VlIHRoZSBleHRlcm5hbCBkb2N1bWVudGF0aW9uLgogICAqLwogIGNsYXNzIERhdGVUaW1lIHsKICAgIC8qKgogICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgKi8KICAgIGNvbnN0cnVjdG9yKGNvbmZpZykgewogICAgICBjb25zdCB6b25lID0gY29uZmlnLnpvbmUgfHwgU2V0dGluZ3MuZGVmYXVsdFpvbmU7CgogICAgICBsZXQgaW52YWxpZCA9CiAgICAgICAgY29uZmlnLmludmFsaWQgfHwKICAgICAgICAoTnVtYmVyLmlzTmFOKGNvbmZpZy50cykgPyBuZXcgSW52YWxpZCgiaW52YWxpZCBpbnB1dCIpIDogbnVsbCkgfHwKICAgICAgICAoIXpvbmUuaXNWYWxpZCA/IHVuc3VwcG9ydGVkWm9uZSh6b25lKSA6IG51bGwpOwogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLnRzID0gaXNVbmRlZmluZWQoY29uZmlnLnRzKSA/IFNldHRpbmdzLm5vdygpIDogY29uZmlnLnRzOwoKICAgICAgbGV0IGMgPSBudWxsLAogICAgICAgIG8gPSBudWxsOwogICAgICBpZiAoIWludmFsaWQpIHsKICAgICAgICBjb25zdCB1bmNoYW5nZWQgPSBjb25maWcub2xkICYmIGNvbmZpZy5vbGQudHMgPT09IHRoaXMudHMgJiYgY29uZmlnLm9sZC56b25lLmVxdWFscyh6b25lKTsKCiAgICAgICAgaWYgKHVuY2hhbmdlZCkgewogICAgICAgICAgW2MsIG9dID0gW2NvbmZpZy5vbGQuYywgY29uZmlnLm9sZC5vXTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgY29uc3Qgb3QgPSB6b25lLm9mZnNldCh0aGlzLnRzKTsKICAgICAgICAgIGMgPSB0c1RvT2JqKHRoaXMudHMsIG90KTsKICAgICAgICAgIGludmFsaWQgPSBOdW1iZXIuaXNOYU4oYy55ZWFyKSA/IG5ldyBJbnZhbGlkKCJpbnZhbGlkIGlucHV0IikgOiBudWxsOwogICAgICAgICAgYyA9IGludmFsaWQgPyBudWxsIDogYzsKICAgICAgICAgIG8gPSBpbnZhbGlkID8gbnVsbCA6IG90OwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEBhY2Nlc3MgcHJpdmF0ZQogICAgICAgKi8KICAgICAgdGhpcy5fem9uZSA9IHpvbmU7CiAgICAgIC8qKgogICAgICAgKiBAYWNjZXNzIHByaXZhdGUKICAgICAgICovCiAgICAgIHRoaXMubG9jID0gY29uZmlnLmxvYyB8fCBMb2NhbGUuY3JlYXRlKCk7CiAgICAgIC8qKgogICAgICAgKiBAYWNjZXNzIHByaXZhdGUKICAgICAgICovCiAgICAgIHRoaXMuaW52YWxpZCA9IGludmFsaWQ7CiAgICAgIC8qKgogICAgICAgKiBAYWNjZXNzIHByaXZhdGUKICAgICAgICovCiAgICAgIHRoaXMud2Vla0RhdGEgPSBudWxsOwogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLmMgPSBjOwogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLm8gPSBvOwogICAgICAvKioKICAgICAgICogQGFjY2VzcyBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLmlzTHV4b25EYXRlVGltZSA9IHRydWU7CiAgICB9CgogICAgLy8gQ09OU1RSVUNUCgogICAgLyoqCiAgICAgKiBDcmVhdGUgYSBEYXRlVGltZSBmb3IgdGhlIGN1cnJlbnQgaW5zdGFudCwgaW4gdGhlIHN5c3RlbSdzIHRpbWUgem9uZS4KICAgICAqCiAgICAgKiBVc2UgU2V0dGluZ3MgdG8gb3ZlcnJpZGUgdGhlc2UgZGVmYXVsdCB2YWx1ZXMgaWYgbmVlZGVkLgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkudG9JU08oKSAvL34+IG5vdyBpbiB0aGUgSVNPIGZvcm1hdAogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXRpYyBub3coKSB7CiAgICAgIHJldHVybiBuZXcgRGF0ZVRpbWUoe30pOwogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGEgbG9jYWwgRGF0ZVRpbWUKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbeWVhcl0gLSBUaGUgY2FsZW5kYXIgeWVhci4gSWYgb21pdHRlZCAoYXMgaW4sIGNhbGwgYGxvY2FsKClgIHdpdGggbm8gYXJndW1lbnRzKSwgdGhlIGN1cnJlbnQgdGltZSB3aWxsIGJlIHVzZWQKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbW9udGg9MV0gLSBUaGUgbW9udGgsIDEtaW5kZXhlZAogICAgICogQHBhcmFtIHtudW1iZXJ9IFtkYXk9MV0gLSBUaGUgZGF5IG9mIHRoZSBtb250aCwgMS1pbmRleGVkCiAgICAgKiBAcGFyYW0ge251bWJlcn0gW2hvdXI9MF0gLSBUaGUgaG91ciBvZiB0aGUgZGF5LCBpbiAyNC1ob3VyIHRpbWUKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbWludXRlPTBdIC0gVGhlIG1pbnV0ZSBvZiB0aGUgaG91ciwgbWVhbmluZyBhIG51bWJlciBiZXR3ZWVuIDAgYW5kIDU5CiAgICAgKiBAcGFyYW0ge251bWJlcn0gW3NlY29uZD0wXSAtIFRoZSBzZWNvbmQgb2YgdGhlIG1pbnV0ZSwgbWVhbmluZyBhIG51bWJlciBiZXR3ZWVuIDAgYW5kIDU5CiAgICAgKiBAcGFyYW0ge251bWJlcn0gW21pbGxpc2Vjb25kPTBdIC0gVGhlIG1pbGxpc2Vjb25kIG9mIHRoZSBzZWNvbmQsIG1lYW5pbmcgYSBudW1iZXIgYmV0d2VlbiAwIGFuZCA5OTkKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9+PiBub3cKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKHsgem9uZTogIkFtZXJpY2EvTmV3X1lvcmsiIH0pICAgICAgLy9+PiBub3csIGluIFVTIGVhc3QgY29hc3QgdGltZQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL34+IDIwMTctMDEtMDFUMDA6MDA6MDAKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDMpICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9+PiAyMDE3LTAzLTAxVDAwOjAwOjAwCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE3LCAzLCAxMiwgeyBsb2NhbGU6ICJmciIgfSkgICAgIC8vfj4gMjAxNy0wMy0xMlQwMDowMDowMCwgd2l0aCBhIEZyZW5jaCBsb2NhbGUKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDMsIDEyLCA1KSAgICAgICAgICAgICAgICAgICAgLy9+PiAyMDE3LTAzLTEyVDA1OjAwOjAwCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE3LCAzLCAxMiwgNSwgeyB6b25lOiAidXRjIiB9KSAgIC8vfj4gMjAxNy0wMy0xMlQwNTowMDowMCwgaW4gVVRDCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE3LCAzLCAxMiwgNSwgNDUpICAgICAgICAgICAgICAgIC8vfj4gMjAxNy0wMy0xMlQwNTo0NTowMAogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgMywgMTIsIDUsIDQ1LCAxMCkgICAgICAgICAgICAvL34+IDIwMTctMDMtMTJUMDU6NDU6MTAKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDMsIDEyLCA1LCA0NSwgMTAsIDc2NSkgICAgICAgLy9+PiAyMDE3LTAzLTEyVDA1OjQ1OjEwLjc2NQogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXRpYyBsb2NhbCgpIHsKICAgICAgY29uc3QgW29wdHMsIGFyZ3NdID0gbGFzdE9wdHMoYXJndW1lbnRzKSwKICAgICAgICBbeWVhciwgbW9udGgsIGRheSwgaG91ciwgbWludXRlLCBzZWNvbmQsIG1pbGxpc2Vjb25kXSA9IGFyZ3M7CiAgICAgIHJldHVybiBxdWlja0RUKHsgeWVhciwgbW9udGgsIGRheSwgaG91ciwgbWludXRlLCBzZWNvbmQsIG1pbGxpc2Vjb25kIH0sIG9wdHMpOwogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGEgRGF0ZVRpbWUgaW4gVVRDCiAgICAgKiBAcGFyYW0ge251bWJlcn0gW3llYXJdIC0gVGhlIGNhbGVuZGFyIHllYXIuIElmIG9taXR0ZWQgKGFzIGluLCBjYWxsIGB1dGMoKWAgd2l0aCBubyBhcmd1bWVudHMpLCB0aGUgY3VycmVudCB0aW1lIHdpbGwgYmUgdXNlZAogICAgICogQHBhcmFtIHtudW1iZXJ9IFttb250aD0xXSAtIFRoZSBtb250aCwgMS1pbmRleGVkCiAgICAgKiBAcGFyYW0ge251bWJlcn0gW2RheT0xXSAtIFRoZSBkYXkgb2YgdGhlIG1vbnRoCiAgICAgKiBAcGFyYW0ge251bWJlcn0gW2hvdXI9MF0gLSBUaGUgaG91ciBvZiB0aGUgZGF5LCBpbiAyNC1ob3VyIHRpbWUKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbWludXRlPTBdIC0gVGhlIG1pbnV0ZSBvZiB0aGUgaG91ciwgbWVhbmluZyBhIG51bWJlciBiZXR3ZWVuIDAgYW5kIDU5CiAgICAgKiBAcGFyYW0ge251bWJlcn0gW3NlY29uZD0wXSAtIFRoZSBzZWNvbmQgb2YgdGhlIG1pbnV0ZSwgbWVhbmluZyBhIG51bWJlciBiZXR3ZWVuIDAgYW5kIDU5CiAgICAgKiBAcGFyYW0ge251bWJlcn0gW21pbGxpc2Vjb25kPTBdIC0gVGhlIG1pbGxpc2Vjb25kIG9mIHRoZSBzZWNvbmQsIG1lYW5pbmcgYSBudW1iZXIgYmV0d2VlbiAwIGFuZCA5OTkKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gY29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgRGF0ZVRpbWUKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0aW9ucy5sb2NhbGVdIC0gYSBsb2NhbGUgdG8gc2V0IG9uIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaW5zdGFuY2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0aW9ucy5vdXRwdXRDYWxlbmRhcl0gLSB0aGUgb3V0cHV0IGNhbGVuZGFyIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdGlvbnMubnVtYmVyaW5nU3lzdGVtXSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS51dGMoKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL34+IG5vdwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTcpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9+PiAyMDE3LTAxLTAxVDAwOjAwOjAwWgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTcsIDMpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9+PiAyMDE3LTAzLTAxVDAwOjAwOjAwWgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTcsIDMsIDEyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9+PiAyMDE3LTAzLTEyVDAwOjAwOjAwWgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTcsIDMsIDEyLCA1KSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9+PiAyMDE3LTAzLTEyVDA1OjAwOjAwWgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTcsIDMsIDEyLCA1LCA0NSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9+PiAyMDE3LTAzLTEyVDA1OjQ1OjAwWgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTcsIDMsIDEyLCA1LCA0NSwgeyBsb2NhbGU6ICJmciIgfSkgICAgICAgICAgLy9+PiAyMDE3LTAzLTEyVDA1OjQ1OjAwWiB3aXRoIGEgRnJlbmNoIGxvY2FsZQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTcsIDMsIDEyLCA1LCA0NSwgMTApICAgICAgICAgICAgICAgICAgICAgICAgLy9+PiAyMDE3LTAzLTEyVDA1OjQ1OjEwWgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTcsIDMsIDEyLCA1LCA0NSwgMTAsIDc2NSwgeyBsb2NhbGU6ICJmciIgfSkgLy9+PiAyMDE3LTAzLTEyVDA1OjQ1OjEwLjc2NVogd2l0aCBhIEZyZW5jaCBsb2NhbGUKICAgICAqIEByZXR1cm4ge0RhdGVUaW1lfQogICAgICovCiAgICBzdGF0aWMgdXRjKCkgewogICAgICBjb25zdCBbb3B0cywgYXJnc10gPSBsYXN0T3B0cyhhcmd1bWVudHMpLAogICAgICAgIFt5ZWFyLCBtb250aCwgZGF5LCBob3VyLCBtaW51dGUsIHNlY29uZCwgbWlsbGlzZWNvbmRdID0gYXJnczsKCiAgICAgIG9wdHMuem9uZSA9IEZpeGVkT2Zmc2V0Wm9uZS51dGNJbnN0YW5jZTsKICAgICAgcmV0dXJuIHF1aWNrRFQoeyB5ZWFyLCBtb250aCwgZGF5LCBob3VyLCBtaW51dGUsIHNlY29uZCwgbWlsbGlzZWNvbmQgfSwgb3B0cyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgYSBEYXRlVGltZSBmcm9tIGEgSmF2YVNjcmlwdCBEYXRlIG9iamVjdC4gVXNlcyB0aGUgZGVmYXVsdCB6b25lLgogICAgICogQHBhcmFtIHtEYXRlfSBkYXRlIC0gYSBKYXZhU2NyaXB0IERhdGUgb2JqZWN0CiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIERhdGVUaW1lCiAgICAgKiBAcGFyYW0ge3N0cmluZ3xab25lfSBbb3B0aW9ucy56b25lPSdsb2NhbCddIC0gdGhlIHpvbmUgdG8gcGxhY2UgdGhlIERhdGVUaW1lIGludG8KICAgICAqIEByZXR1cm4ge0RhdGVUaW1lfQogICAgICovCiAgICBzdGF0aWMgZnJvbUpTRGF0ZShkYXRlLCBvcHRpb25zID0ge30pIHsKICAgICAgY29uc3QgdHMgPSBpc0RhdGUoZGF0ZSkgPyBkYXRlLnZhbHVlT2YoKSA6IE5hTjsKICAgICAgaWYgKE51bWJlci5pc05hTih0cykpIHsKICAgICAgICByZXR1cm4gRGF0ZVRpbWUuaW52YWxpZCgiaW52YWxpZCBpbnB1dCIpOwogICAgICB9CgogICAgICBjb25zdCB6b25lVG9Vc2UgPSBub3JtYWxpemVab25lKG9wdGlvbnMuem9uZSwgU2V0dGluZ3MuZGVmYXVsdFpvbmUpOwogICAgICBpZiAoIXpvbmVUb1VzZS5pc1ZhbGlkKSB7CiAgICAgICAgcmV0dXJuIERhdGVUaW1lLmludmFsaWQodW5zdXBwb3J0ZWRab25lKHpvbmVUb1VzZSkpOwogICAgICB9CgogICAgICByZXR1cm4gbmV3IERhdGVUaW1lKHsKICAgICAgICB0czogdHMsCiAgICAgICAgem9uZTogem9uZVRvVXNlLAogICAgICAgIGxvYzogTG9jYWxlLmZyb21PYmplY3Qob3B0aW9ucyksCiAgICAgIH0pOwogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGEgRGF0ZVRpbWUgZnJvbSBhIG51bWJlciBvZiBtaWxsaXNlY29uZHMgc2luY2UgdGhlIGVwb2NoIChtZWFuaW5nIHNpbmNlIDEgSmFudWFyeSAxOTcwIDAwOjAwOjAwIFVUQykuIFVzZXMgdGhlIGRlZmF1bHQgem9uZS4KICAgICAqIEBwYXJhbSB7bnVtYmVyfSBtaWxsaXNlY29uZHMgLSBhIG51bWJlciBvZiBtaWxsaXNlY29uZHMgc2luY2UgMTk3MCBVVEMKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gY29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgRGF0ZVRpbWUKICAgICAqIEBwYXJhbSB7c3RyaW5nfFpvbmV9IFtvcHRpb25zLnpvbmU9J2xvY2FsJ10gLSB0aGUgem9uZSB0byBwbGFjZSB0aGUgRGF0ZVRpbWUgaW50bwogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRpb25zLmxvY2FsZV0gLSBhIGxvY2FsZSB0byBzZXQgb24gdGhlIHJlc3VsdGluZyBEYXRlVGltZSBpbnN0YW5jZQogICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMub3V0cHV0Q2FsZW5kYXIgLSB0aGUgb3V0cHV0IGNhbGVuZGFyIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5udW1iZXJpbmdTeXN0ZW0gLSB0aGUgbnVtYmVyaW5nIHN5c3RlbSB0byBzZXQgb24gdGhlIHJlc3VsdGluZyBEYXRlVGltZSBpbnN0YW5jZQogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXRpYyBmcm9tTWlsbGlzKG1pbGxpc2Vjb25kcywgb3B0aW9ucyA9IHt9KSB7CiAgICAgIGlmICghaXNOdW1iZXIobWlsbGlzZWNvbmRzKSkgewogICAgICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRFcnJvcigKICAgICAgICAgIGBmcm9tTWlsbGlzIHJlcXVpcmVzIGEgbnVtZXJpY2FsIGlucHV0LCBidXQgcmVjZWl2ZWQgYSAke3R5cGVvZiBtaWxsaXNlY29uZHN9IHdpdGggdmFsdWUgJHttaWxsaXNlY29uZHN9YAogICAgICAgICk7CiAgICAgIH0gZWxzZSBpZiAobWlsbGlzZWNvbmRzIDwgLU1BWF9EQVRFIHx8IG1pbGxpc2Vjb25kcyA+IE1BWF9EQVRFKSB7CiAgICAgICAgLy8gdGhpcyBpc24ndCBwZXJmZWN0IGJlY2F1c2UgYmVjYXVzZSB3ZSBjYW4gc3RpbGwgZW5kIHVwIG91dCBvZiByYW5nZSBiZWNhdXNlIG9mIGFkZGl0aW9uYWwgc2hpZnRpbmcsIGJ1dCBpdCdzIGEgc3RhcnQKICAgICAgICByZXR1cm4gRGF0ZVRpbWUuaW52YWxpZCgiVGltZXN0YW1wIG91dCBvZiByYW5nZSIpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBuZXcgRGF0ZVRpbWUoewogICAgICAgICAgdHM6IG1pbGxpc2Vjb25kcywKICAgICAgICAgIHpvbmU6IG5vcm1hbGl6ZVpvbmUob3B0aW9ucy56b25lLCBTZXR0aW5ncy5kZWZhdWx0Wm9uZSksCiAgICAgICAgICBsb2M6IExvY2FsZS5mcm9tT2JqZWN0KG9wdGlvbnMpLAogICAgICAgIH0pOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgYSBEYXRlVGltZSBmcm9tIGEgbnVtYmVyIG9mIHNlY29uZHMgc2luY2UgdGhlIGVwb2NoIChtZWFuaW5nIHNpbmNlIDEgSmFudWFyeSAxOTcwIDAwOjAwOjAwIFVUQykuIFVzZXMgdGhlIGRlZmF1bHQgem9uZS4KICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzZWNvbmRzIC0gYSBudW1iZXIgb2Ygc2Vjb25kcyBzaW5jZSAxOTcwIFVUQwogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBEYXRlVGltZQogICAgICogQHBhcmFtIHtzdHJpbmd8Wm9uZX0gW29wdGlvbnMuem9uZT0nbG9jYWwnXSAtIHRoZSB6b25lIHRvIHBsYWNlIHRoZSBEYXRlVGltZSBpbnRvCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdGlvbnMubG9jYWxlXSAtIGEgbG9jYWxlIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5vdXRwdXRDYWxlbmRhciAtIHRoZSBvdXRwdXQgY2FsZW5kYXIgdG8gc2V0IG9uIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaW5zdGFuY2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRpb25zLm51bWJlcmluZ1N5c3RlbSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAcmV0dXJuIHtEYXRlVGltZX0KICAgICAqLwogICAgc3RhdGljIGZyb21TZWNvbmRzKHNlY29uZHMsIG9wdGlvbnMgPSB7fSkgewogICAgICBpZiAoIWlzTnVtYmVyKHNlY29uZHMpKSB7CiAgICAgICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudEVycm9yKCJmcm9tU2Vjb25kcyByZXF1aXJlcyBhIG51bWVyaWNhbCBpbnB1dCIpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBuZXcgRGF0ZVRpbWUoewogICAgICAgICAgdHM6IHNlY29uZHMgKiAxMDAwLAogICAgICAgICAgem9uZTogbm9ybWFsaXplWm9uZShvcHRpb25zLnpvbmUsIFNldHRpbmdzLmRlZmF1bHRab25lKSwKICAgICAgICAgIGxvYzogTG9jYWxlLmZyb21PYmplY3Qob3B0aW9ucyksCiAgICAgICAgfSk7CiAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIENyZWF0ZSBhIERhdGVUaW1lIGZyb20gYSBKYXZhU2NyaXB0IG9iamVjdCB3aXRoIGtleXMgbGlrZSAneWVhcicgYW5kICdob3VyJyB3aXRoIHJlYXNvbmFibGUgZGVmYXVsdHMuCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqIC0gdGhlIG9iamVjdCB0byBjcmVhdGUgdGhlIERhdGVUaW1lIGZyb20KICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvYmoueWVhciAtIGEgeWVhciwgc3VjaCBhcyAxOTg3CiAgICAgKiBAcGFyYW0ge251bWJlcn0gb2JqLm1vbnRoIC0gYSBtb250aCwgMS0xMgogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai5kYXkgLSBhIGRheSBvZiB0aGUgbW9udGgsIDEtMzEsIGRlcGVuZGluZyBvbiB0aGUgbW9udGgKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvYmoub3JkaW5hbCAtIGRheSBvZiB0aGUgeWVhciwgMS0zNjUgb3IgMzY2CiAgICAgKiBAcGFyYW0ge251bWJlcn0gb2JqLndlZWtZZWFyIC0gYW4gSVNPIHdlZWsgeWVhcgogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai53ZWVrTnVtYmVyIC0gYW4gSVNPIHdlZWsgbnVtYmVyLCBiZXR3ZWVuIDEgYW5kIDUyIG9yIDUzLCBkZXBlbmRpbmcgb24gdGhlIHllYXIKICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvYmoud2Vla2RheSAtIGFuIElTTyB3ZWVrZGF5LCAxLTcsIHdoZXJlIDEgaXMgTW9uZGF5IGFuZCA3IGlzIFN1bmRheQogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai5ob3VyIC0gaG91ciBvZiB0aGUgZGF5LCAwLTIzCiAgICAgKiBAcGFyYW0ge251bWJlcn0gb2JqLm1pbnV0ZSAtIG1pbnV0ZSBvZiB0aGUgaG91ciwgMC01OQogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai5zZWNvbmQgLSBzZWNvbmQgb2YgdGhlIG1pbnV0ZSwgMC01OQogICAgICogQHBhcmFtIHtudW1iZXJ9IG9iai5taWxsaXNlY29uZCAtIG1pbGxpc2Vjb25kIG9mIHRoZSBzZWNvbmQsIDAtOTk5CiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdGlvbnMgZm9yIGNyZWF0aW5nIHRoaXMgRGF0ZVRpbWUKICAgICAqIEBwYXJhbSB7c3RyaW5nfFpvbmV9IFtvcHRzLnpvbmU9J2xvY2FsJ10gLSBpbnRlcnByZXQgdGhlIG51bWJlcnMgaW4gdGhlIGNvbnRleHQgb2YgYSBwYXJ0aWN1bGFyIHpvbmUuIENhbiB0YWtlIGFueSB2YWx1ZSB0YWtlbiBhcyB0aGUgZmlyc3QgYXJndW1lbnQgdG8gc2V0Wm9uZSgpCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jYWxlPSdzeXN0ZW0ncyBsb2NhbGUnXSAtIGEgbG9jYWxlIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0cy5vdXRwdXRDYWxlbmRhciAtIHRoZSBvdXRwdXQgY2FsZW5kYXIgdG8gc2V0IG9uIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaW5zdGFuY2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLm51bWJlcmluZ1N5c3RlbSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tT2JqZWN0KHsgeWVhcjogMTk4MiwgbW9udGg6IDUsIGRheTogMjV9KS50b0lTT0RhdGUoKSAvLz0+ICcxOTgyLTA1LTI1JwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUuZnJvbU9iamVjdCh7IHllYXI6IDE5ODIgfSkudG9JU09EYXRlKCkgLy89PiAnMTk4Mi0wMS0wMScKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmZyb21PYmplY3QoeyBob3VyOiAxMCwgbWludXRlOiAyNiwgc2Vjb25kOiA2IH0pIC8vfj4gdG9kYXkgYXQgMTA6MjY6MDYKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmZyb21PYmplY3QoeyBob3VyOiAxMCwgbWludXRlOiAyNiwgc2Vjb25kOiA2IH0sIHsgem9uZTogJ3V0YycgfSksCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tT2JqZWN0KHsgaG91cjogMTAsIG1pbnV0ZTogMjYsIHNlY29uZDogNiB9LCB7IHpvbmU6ICdsb2NhbCcgfSkKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmZyb21PYmplY3QoeyBob3VyOiAxMCwgbWludXRlOiAyNiwgc2Vjb25kOiA2IH0sIHsgem9uZTogJ0FtZXJpY2EvTmV3X1lvcmsnIH0pCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tT2JqZWN0KHsgd2Vla1llYXI6IDIwMTYsIHdlZWtOdW1iZXI6IDIsIHdlZWtkYXk6IDMgfSkudG9JU09EYXRlKCkgLy89PiAnMjAxNi0wMS0xMycKICAgICAqIEByZXR1cm4ge0RhdGVUaW1lfQogICAgICovCiAgICBzdGF0aWMgZnJvbU9iamVjdChvYmosIG9wdHMgPSB7fSkgewogICAgICBvYmogPSBvYmogfHwge307CiAgICAgIGNvbnN0IHpvbmVUb1VzZSA9IG5vcm1hbGl6ZVpvbmUob3B0cy56b25lLCBTZXR0aW5ncy5kZWZhdWx0Wm9uZSk7CiAgICAgIGlmICghem9uZVRvVXNlLmlzVmFsaWQpIHsKICAgICAgICByZXR1cm4gRGF0ZVRpbWUuaW52YWxpZCh1bnN1cHBvcnRlZFpvbmUoem9uZVRvVXNlKSk7CiAgICAgIH0KCiAgICAgIGNvbnN0IHRzTm93ID0gU2V0dGluZ3Mubm93KCksCiAgICAgICAgb2Zmc2V0UHJvdmlzID0gIWlzVW5kZWZpbmVkKG9wdHMuc3BlY2lmaWNPZmZzZXQpCiAgICAgICAgICA/IG9wdHMuc3BlY2lmaWNPZmZzZXQKICAgICAgICAgIDogem9uZVRvVXNlLm9mZnNldCh0c05vdyksCiAgICAgICAgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZU9iamVjdChvYmosIG5vcm1hbGl6ZVVuaXQpLAogICAgICAgIGNvbnRhaW5zT3JkaW5hbCA9ICFpc1VuZGVmaW5lZChub3JtYWxpemVkLm9yZGluYWwpLAogICAgICAgIGNvbnRhaW5zR3JlZ29yWWVhciA9ICFpc1VuZGVmaW5lZChub3JtYWxpemVkLnllYXIpLAogICAgICAgIGNvbnRhaW5zR3JlZ29yTUQgPSAhaXNVbmRlZmluZWQobm9ybWFsaXplZC5tb250aCkgfHwgIWlzVW5kZWZpbmVkKG5vcm1hbGl6ZWQuZGF5KSwKICAgICAgICBjb250YWluc0dyZWdvciA9IGNvbnRhaW5zR3JlZ29yWWVhciB8fCBjb250YWluc0dyZWdvck1ELAogICAgICAgIGRlZmluaXRlV2Vla0RlZiA9IG5vcm1hbGl6ZWQud2Vla1llYXIgfHwgbm9ybWFsaXplZC53ZWVrTnVtYmVyLAogICAgICAgIGxvYyA9IExvY2FsZS5mcm9tT2JqZWN0KG9wdHMpOwoKICAgICAgLy8gY2FzZXM6CiAgICAgIC8vIGp1c3QgYSB3ZWVrZGF5IC0+IHRoaXMgd2VlaydzIGluc3RhbmNlIG9mIHRoYXQgd2Vla2RheSwgbm8gd29ycmllcwogICAgICAvLyAoZ3JlZ29yaWFuIGRhdGEgb3Igb3JkaW5hbCkgKyAod2Vla1llYXIgb3Igd2Vla051bWJlcikgLT4gZXJyb3IKICAgICAgLy8gKGdyZWdvcmlhbiBtb250aCBvciBkYXkpICsgb3JkaW5hbCAtPiBlcnJvcgogICAgICAvLyBvdGhlcndpc2UganVzdCB1c2Ugd2Vla3Mgb3Igb3JkaW5hbHMgb3IgZ3JlZ29yaWFuLCBkZXBlbmRpbmcgb24gd2hhdCdzIHNwZWNpZmllZAoKICAgICAgaWYgKChjb250YWluc0dyZWdvciB8fCBjb250YWluc09yZGluYWwpICYmIGRlZmluaXRlV2Vla0RlZikgewogICAgICAgIHRocm93IG5ldyBDb25mbGljdGluZ1NwZWNpZmljYXRpb25FcnJvcigKICAgICAgICAgICJDYW4ndCBtaXggd2Vla1llYXIvd2Vla051bWJlciB1bml0cyB3aXRoIHllYXIvbW9udGgvZGF5IG9yIG9yZGluYWxzIgogICAgICAgICk7CiAgICAgIH0KCiAgICAgIGlmIChjb250YWluc0dyZWdvck1EICYmIGNvbnRhaW5zT3JkaW5hbCkgewogICAgICAgIHRocm93IG5ldyBDb25mbGljdGluZ1NwZWNpZmljYXRpb25FcnJvcigiQ2FuJ3QgbWl4IG9yZGluYWwgZGF0ZXMgd2l0aCBtb250aC9kYXkiKTsKICAgICAgfQoKICAgICAgY29uc3QgdXNlV2Vla0RhdGEgPSBkZWZpbml0ZVdlZWtEZWYgfHwgKG5vcm1hbGl6ZWQud2Vla2RheSAmJiAhY29udGFpbnNHcmVnb3IpOwoKICAgICAgLy8gY29uZmlndXJlIG91cnNlbHZlcyB0byBkZWFsIHdpdGggZ3JlZ29yaWFuIGRhdGVzIG9yIHdlZWsgc3R1ZmYKICAgICAgbGV0IHVuaXRzLAogICAgICAgIGRlZmF1bHRWYWx1ZXMsCiAgICAgICAgb2JqTm93ID0gdHNUb09iaih0c05vdywgb2Zmc2V0UHJvdmlzKTsKICAgICAgaWYgKHVzZVdlZWtEYXRhKSB7CiAgICAgICAgdW5pdHMgPSBvcmRlcmVkV2Vla1VuaXRzOwogICAgICAgIGRlZmF1bHRWYWx1ZXMgPSBkZWZhdWx0V2Vla1VuaXRWYWx1ZXM7CiAgICAgICAgb2JqTm93ID0gZ3JlZ29yaWFuVG9XZWVrKG9iak5vdyk7CiAgICAgIH0gZWxzZSBpZiAoY29udGFpbnNPcmRpbmFsKSB7CiAgICAgICAgdW5pdHMgPSBvcmRlcmVkT3JkaW5hbFVuaXRzOwogICAgICAgIGRlZmF1bHRWYWx1ZXMgPSBkZWZhdWx0T3JkaW5hbFVuaXRWYWx1ZXM7CiAgICAgICAgb2JqTm93ID0gZ3JlZ29yaWFuVG9PcmRpbmFsKG9iak5vdyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdW5pdHMgPSBvcmRlcmVkVW5pdHM7CiAgICAgICAgZGVmYXVsdFZhbHVlcyA9IGRlZmF1bHRVbml0VmFsdWVzOwogICAgICB9CgogICAgICAvLyBzZXQgZGVmYXVsdCB2YWx1ZXMgZm9yIG1pc3Npbmcgc3R1ZmYKICAgICAgbGV0IGZvdW5kRmlyc3QgPSBmYWxzZTsKICAgICAgZm9yIChjb25zdCB1IG9mIHVuaXRzKSB7CiAgICAgICAgY29uc3QgdiA9IG5vcm1hbGl6ZWRbdV07CiAgICAgICAgaWYgKCFpc1VuZGVmaW5lZCh2KSkgewogICAgICAgICAgZm91bmRGaXJzdCA9IHRydWU7CiAgICAgICAgfSBlbHNlIGlmIChmb3VuZEZpcnN0KSB7CiAgICAgICAgICBub3JtYWxpemVkW3VdID0gZGVmYXVsdFZhbHVlc1t1XTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgbm9ybWFsaXplZFt1XSA9IG9iak5vd1t1XTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgdmFsdWVzIHdlIGhhdmUgYXJlIGluIHJhbmdlCiAgICAgIGNvbnN0IGhpZ2hlck9yZGVySW52YWxpZCA9IHVzZVdlZWtEYXRhCiAgICAgICAgICA/IGhhc0ludmFsaWRXZWVrRGF0YShub3JtYWxpemVkKQogICAgICAgICAgOiBjb250YWluc09yZGluYWwKICAgICAgICAgID8gaGFzSW52YWxpZE9yZGluYWxEYXRhKG5vcm1hbGl6ZWQpCiAgICAgICAgICA6IGhhc0ludmFsaWRHcmVnb3JpYW5EYXRhKG5vcm1hbGl6ZWQpLAogICAgICAgIGludmFsaWQgPSBoaWdoZXJPcmRlckludmFsaWQgfHwgaGFzSW52YWxpZFRpbWVEYXRhKG5vcm1hbGl6ZWQpOwoKICAgICAgaWYgKGludmFsaWQpIHsKICAgICAgICByZXR1cm4gRGF0ZVRpbWUuaW52YWxpZChpbnZhbGlkKTsKICAgICAgfQoKICAgICAgLy8gY29tcHV0ZSB0aGUgYWN0dWFsIHRpbWUKICAgICAgY29uc3QgZ3JlZ29yaWFuID0gdXNlV2Vla0RhdGEKICAgICAgICAgID8gd2Vla1RvR3JlZ29yaWFuKG5vcm1hbGl6ZWQpCiAgICAgICAgICA6IGNvbnRhaW5zT3JkaW5hbAogICAgICAgICAgPyBvcmRpbmFsVG9HcmVnb3JpYW4obm9ybWFsaXplZCkKICAgICAgICAgIDogbm9ybWFsaXplZCwKICAgICAgICBbdHNGaW5hbCwgb2Zmc2V0RmluYWxdID0gb2JqVG9UUyhncmVnb3JpYW4sIG9mZnNldFByb3Zpcywgem9uZVRvVXNlKSwKICAgICAgICBpbnN0ID0gbmV3IERhdGVUaW1lKHsKICAgICAgICAgIHRzOiB0c0ZpbmFsLAogICAgICAgICAgem9uZTogem9uZVRvVXNlLAogICAgICAgICAgbzogb2Zmc2V0RmluYWwsCiAgICAgICAgICBsb2MsCiAgICAgICAgfSk7CgogICAgICAvLyBncmVnb3JpYW4gZGF0YSArIHdlZWtkYXkgc2VydmVzIG9ubHkgdG8gdmFsaWRhdGUKICAgICAgaWYgKG5vcm1hbGl6ZWQud2Vla2RheSAmJiBjb250YWluc0dyZWdvciAmJiBvYmoud2Vla2RheSAhPT0gaW5zdC53ZWVrZGF5KSB7CiAgICAgICAgcmV0dXJuIERhdGVUaW1lLmludmFsaWQoCiAgICAgICAgICAibWlzbWF0Y2hlZCB3ZWVrZGF5IiwKICAgICAgICAgIGB5b3UgY2FuJ3Qgc3BlY2lmeSBib3RoIGEgd2Vla2RheSBvZiAke25vcm1hbGl6ZWQud2Vla2RheX0gYW5kIGEgZGF0ZSBvZiAke2luc3QudG9JU08oKX1gCiAgICAgICAgKTsKICAgICAgfQoKICAgICAgcmV0dXJuIGluc3Q7CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgYSBEYXRlVGltZSBmcm9tIGFuIElTTyA4NjAxIHN0cmluZwogICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSB0aGUgSVNPIHN0cmluZwogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zIHRvIGFmZmVjdCB0aGUgY3JlYXRpb24KICAgICAqIEBwYXJhbSB7c3RyaW5nfFpvbmV9IFtvcHRzLnpvbmU9J2xvY2FsJ10gLSB1c2UgdGhpcyB6b25lIGlmIG5vIG9mZnNldCBpcyBzcGVjaWZpZWQgaW4gdGhlIGlucHV0IHN0cmluZyBpdHNlbGYuIFdpbGwgYWxzbyBjb252ZXJ0IHRoZSB0aW1lIHRvIHRoaXMgem9uZQogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5zZXRab25lPWZhbHNlXSAtIG92ZXJyaWRlIHRoZSB6b25lIHdpdGggYSBmaXhlZC1vZmZzZXQgem9uZSBzcGVjaWZpZWQgaW4gdGhlIHN0cmluZyBpdHNlbGYsIGlmIGl0IHNwZWNpZmllcyBvbmUKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5sb2NhbGU9J3N5c3RlbSdzIGxvY2FsZSddIC0gYSBsb2NhbGUgdG8gc2V0IG9uIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaW5zdGFuY2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5vdXRwdXRDYWxlbmRhcl0gLSB0aGUgb3V0cHV0IGNhbGVuZGFyIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubnVtYmVyaW5nU3lzdGVtXSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tSVNPKCcyMDE2LTA1LTI1VDA5OjA4OjM0LjEyMycpCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tSVNPKCcyMDE2LTA1LTI1VDA5OjA4OjM0LjEyMyswNjowMCcpCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tSVNPKCcyMDE2LTA1LTI1VDA5OjA4OjM0LjEyMyswNjowMCcsIHtzZXRab25lOiB0cnVlfSkKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmZyb21JU08oJzIwMTYtMDUtMjVUMDk6MDg6MzQuMTIzJywge3pvbmU6ICd1dGMnfSkKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmZyb21JU08oJzIwMTYtVzA1LTQnKQogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXRpYyBmcm9tSVNPKHRleHQsIG9wdHMgPSB7fSkgewogICAgICBjb25zdCBbdmFscywgcGFyc2VkWm9uZV0gPSBwYXJzZUlTT0RhdGUodGV4dCk7CiAgICAgIHJldHVybiBwYXJzZURhdGFUb0RhdGVUaW1lKHZhbHMsIHBhcnNlZFpvbmUsIG9wdHMsICJJU08gODYwMSIsIHRleHQpOwogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGEgRGF0ZVRpbWUgZnJvbSBhbiBSRkMgMjgyMiBzdHJpbmcKICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gdGhlIFJGQyAyODIyIHN0cmluZwogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zIHRvIGFmZmVjdCB0aGUgY3JlYXRpb24KICAgICAqIEBwYXJhbSB7c3RyaW5nfFpvbmV9IFtvcHRzLnpvbmU9J2xvY2FsJ10gLSBjb252ZXJ0IHRoZSB0aW1lIHRvIHRoaXMgem9uZS4gU2luY2UgdGhlIG9mZnNldCBpcyBhbHdheXMgc3BlY2lmaWVkIGluIHRoZSBzdHJpbmcgaXRzZWxmLCB0aGlzIGhhcyBubyBlZmZlY3Qgb24gdGhlIGludGVycHJldGF0aW9uIG9mIHN0cmluZywgbWVyZWx5IHRoZSB6b25lIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaXMgZXhwcmVzc2VkIGluLgogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5zZXRab25lPWZhbHNlXSAtIG92ZXJyaWRlIHRoZSB6b25lIHdpdGggYSBmaXhlZC1vZmZzZXQgem9uZSBzcGVjaWZpZWQgaW4gdGhlIHN0cmluZyBpdHNlbGYsIGlmIGl0IHNwZWNpZmllcyBvbmUKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5sb2NhbGU9J3N5c3RlbSdzIGxvY2FsZSddIC0gYSBsb2NhbGUgdG8gc2V0IG9uIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaW5zdGFuY2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLm91dHB1dENhbGVuZGFyIC0gdGhlIG91dHB1dCBjYWxlbmRhciB0byBzZXQgb24gdGhlIHJlc3VsdGluZyBEYXRlVGltZSBpbnN0YW5jZQogICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdHMubnVtYmVyaW5nU3lzdGVtIC0gdGhlIG51bWJlcmluZyBzeXN0ZW0gdG8gc2V0IG9uIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaW5zdGFuY2UKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmZyb21SRkMyODIyKCcyNSBOb3YgMjAxNiAxMzoyMzoxMiBHTVQnKQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUuZnJvbVJGQzI4MjIoJ0ZyaSwgMjUgTm92IDIwMTYgMTM6MjM6MTIgKzA2MDAnKQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUuZnJvbVJGQzI4MjIoJzI1IE5vdiAyMDE2IDEzOjIzIFonKQogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXRpYyBmcm9tUkZDMjgyMih0ZXh0LCBvcHRzID0ge30pIHsKICAgICAgY29uc3QgW3ZhbHMsIHBhcnNlZFpvbmVdID0gcGFyc2VSRkMyODIyRGF0ZSh0ZXh0KTsKICAgICAgcmV0dXJuIHBhcnNlRGF0YVRvRGF0ZVRpbWUodmFscywgcGFyc2VkWm9uZSwgb3B0cywgIlJGQyAyODIyIiwgdGV4dCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgYSBEYXRlVGltZSBmcm9tIGFuIEhUVFAgaGVhZGVyIGRhdGUKICAgICAqIEBzZWUgaHR0cHM6Ly93d3cudzMub3JnL1Byb3RvY29scy9yZmMyNjE2L3JmYzI2MTYtc2VjMy5odG1sI3NlYzMuMy4xCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIHRoZSBIVFRQIGhlYWRlciBkYXRlCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdGlvbnMgdG8gYWZmZWN0IHRoZSBjcmVhdGlvbgogICAgICogQHBhcmFtIHtzdHJpbmd8Wm9uZX0gW29wdHMuem9uZT0nbG9jYWwnXSAtIGNvbnZlcnQgdGhlIHRpbWUgdG8gdGhpcyB6b25lLiBTaW5jZSBIVFRQIGRhdGVzIGFyZSBhbHdheXMgaW4gVVRDLCB0aGlzIGhhcyBubyBlZmZlY3Qgb24gdGhlIGludGVycHJldGF0aW9uIG9mIHN0cmluZywgbWVyZWx5IHRoZSB6b25lIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaXMgZXhwcmVzc2VkIGluLgogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5zZXRab25lPWZhbHNlXSAtIG92ZXJyaWRlIHRoZSB6b25lIHdpdGggdGhlIGZpeGVkLW9mZnNldCB6b25lIHNwZWNpZmllZCBpbiB0aGUgc3RyaW5nLiBGb3IgSFRUUCBkYXRlcywgdGhpcyBpcyBhbHdheXMgVVRDLCBzbyB0aGlzIG9wdGlvbiBpcyBlcXVpdmFsZW50IHRvIHNldHRpbmcgdGhlIGB6b25lYCBvcHRpb24gdG8gJ3V0YycsIGJ1dCB0aGlzIG9wdGlvbiBpcyBpbmNsdWRlZCBmb3IgY29uc2lzdGVuY3kgd2l0aCBzaW1pbGFyIG1ldGhvZHMuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMubG9jYWxlPSdzeXN0ZW0ncyBsb2NhbGUnXSAtIGEgbG9jYWxlIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0cy5vdXRwdXRDYWxlbmRhciAtIHRoZSBvdXRwdXQgY2FsZW5kYXIgdG8gc2V0IG9uIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUgaW5zdGFuY2UKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLm51bWJlcmluZ1N5c3RlbSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tSFRUUCgnU3VuLCAwNiBOb3YgMTk5NCAwODo0OTozNyBHTVQnKQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUuZnJvbUhUVFAoJ1N1bmRheSwgMDYtTm92LTk0IDA4OjQ5OjM3IEdNVCcpCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tSFRUUCgnU3VuIE5vdiAgNiAwODo0OTozNyAxOTk0JykKICAgICAqIEByZXR1cm4ge0RhdGVUaW1lfQogICAgICovCiAgICBzdGF0aWMgZnJvbUhUVFAodGV4dCwgb3B0cyA9IHt9KSB7CiAgICAgIGNvbnN0IFt2YWxzLCBwYXJzZWRab25lXSA9IHBhcnNlSFRUUERhdGUodGV4dCk7CiAgICAgIHJldHVybiBwYXJzZURhdGFUb0RhdGVUaW1lKHZhbHMsIHBhcnNlZFpvbmUsIG9wdHMsICJIVFRQIiwgb3B0cyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBDcmVhdGUgYSBEYXRlVGltZSBmcm9tIGFuIGlucHV0IHN0cmluZyBhbmQgZm9ybWF0IHN0cmluZy4KICAgICAqIERlZmF1bHRzIHRvIGVuLVVTIGlmIG5vIGxvY2FsZSBoYXMgYmVlbiBzcGVjaWZpZWQsIHJlZ2FyZGxlc3Mgb2YgdGhlIHN5c3RlbSdzIGxvY2FsZS4gRm9yIGEgdGFibGUgb2YgdG9rZW5zIGFuZCB0aGVpciBpbnRlcnByZXRhdGlvbnMsIHNlZSBbaGVyZV0oaHR0cHM6Ly9tb21lbnQuZ2l0aHViLmlvL2x1eG9uLyMvcGFyc2luZz9pZD10YWJsZS1vZi10b2tlbnMpLgogICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSB0aGUgc3RyaW5nIHRvIHBhcnNlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gZm10IC0gdGhlIGZvcm1hdCB0aGUgc3RyaW5nIGlzIGV4cGVjdGVkIHRvIGJlIGluIChzZWUgdGhlIGxpbmsgYmVsb3cgZm9yIHRoZSBmb3JtYXRzKQogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zIHRvIGFmZmVjdCB0aGUgY3JlYXRpb24KICAgICAqIEBwYXJhbSB7c3RyaW5nfFpvbmV9IFtvcHRzLnpvbmU9J2xvY2FsJ10gLSB1c2UgdGhpcyB6b25lIGlmIG5vIG9mZnNldCBpcyBzcGVjaWZpZWQgaW4gdGhlIGlucHV0IHN0cmluZyBpdHNlbGYuIFdpbGwgYWxzbyBjb252ZXJ0IHRoZSBEYXRlVGltZSB0byB0aGlzIHpvbmUKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuc2V0Wm9uZT1mYWxzZV0gLSBvdmVycmlkZSB0aGUgem9uZSB3aXRoIGEgem9uZSBzcGVjaWZpZWQgaW4gdGhlIHN0cmluZyBpdHNlbGYsIGlmIGl0IHNwZWNpZmllcyBvbmUKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5sb2NhbGU9J2VuLVVTJ10gLSBhIGxvY2FsZSBzdHJpbmcgdG8gdXNlIHdoZW4gcGFyc2luZy4gV2lsbCBhbHNvIHNldCB0aGUgRGF0ZVRpbWUgdG8gdGhpcyBsb2NhbGUKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLm51bWJlcmluZ1N5c3RlbSAtIHRoZSBudW1iZXJpbmcgc3lzdGVtIHRvIHVzZSB3aGVuIHBhcnNpbmcuIFdpbGwgYWxzbyBzZXQgdGhlIHJlc3VsdGluZyBEYXRlVGltZSB0byB0aGlzIG51bWJlcmluZyBzeXN0ZW0KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLm91dHB1dENhbGVuZGFyIC0gdGhlIG91dHB1dCBjYWxlbmRhciB0byBzZXQgb24gdGhlIHJlc3VsdGluZyBEYXRlVGltZSBpbnN0YW5jZQogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXRpYyBmcm9tRm9ybWF0KHRleHQsIGZtdCwgb3B0cyA9IHt9KSB7CiAgICAgIGlmIChpc1VuZGVmaW5lZCh0ZXh0KSB8fCBpc1VuZGVmaW5lZChmbXQpKSB7CiAgICAgICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudEVycm9yKCJmcm9tRm9ybWF0IHJlcXVpcmVzIGFuIGlucHV0IHN0cmluZyBhbmQgYSBmb3JtYXQiKTsKICAgICAgfQoKICAgICAgY29uc3QgeyBsb2NhbGUgPSBudWxsLCBudW1iZXJpbmdTeXN0ZW0gPSBudWxsIH0gPSBvcHRzLAogICAgICAgIGxvY2FsZVRvVXNlID0gTG9jYWxlLmZyb21PcHRzKHsKICAgICAgICAgIGxvY2FsZSwKICAgICAgICAgIG51bWJlcmluZ1N5c3RlbSwKICAgICAgICAgIGRlZmF1bHRUb0VOOiB0cnVlLAogICAgICAgIH0pLAogICAgICAgIFt2YWxzLCBwYXJzZWRab25lLCBzcGVjaWZpY09mZnNldCwgaW52YWxpZF0gPSBwYXJzZUZyb21Ub2tlbnMobG9jYWxlVG9Vc2UsIHRleHQsIGZtdCk7CiAgICAgIGlmIChpbnZhbGlkKSB7CiAgICAgICAgcmV0dXJuIERhdGVUaW1lLmludmFsaWQoaW52YWxpZCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHBhcnNlRGF0YVRvRGF0ZVRpbWUodmFscywgcGFyc2VkWm9uZSwgb3B0cywgYGZvcm1hdCAke2ZtdH1gLCB0ZXh0LCBzcGVjaWZpY09mZnNldCk7CiAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEBkZXByZWNhdGVkIHVzZSBmcm9tRm9ybWF0IGluc3RlYWQKICAgICAqLwogICAgc3RhdGljIGZyb21TdHJpbmcodGV4dCwgZm10LCBvcHRzID0ge30pIHsKICAgICAgcmV0dXJuIERhdGVUaW1lLmZyb21Gb3JtYXQodGV4dCwgZm10LCBvcHRzKTsKICAgIH0KCiAgICAvKioKICAgICAqIENyZWF0ZSBhIERhdGVUaW1lIGZyb20gYSBTUUwgZGF0ZSwgdGltZSwgb3IgZGF0ZXRpbWUKICAgICAqIERlZmF1bHRzIHRvIGVuLVVTIGlmIG5vIGxvY2FsZSBoYXMgYmVlbiBzcGVjaWZpZWQsIHJlZ2FyZGxlc3Mgb2YgdGhlIHN5c3RlbSdzIGxvY2FsZQogICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSB0aGUgc3RyaW5nIHRvIHBhcnNlCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdGlvbnMgdG8gYWZmZWN0IHRoZSBjcmVhdGlvbgogICAgICogQHBhcmFtIHtzdHJpbmd8Wm9uZX0gW29wdHMuem9uZT0nbG9jYWwnXSAtIHVzZSB0aGlzIHpvbmUgaWYgbm8gb2Zmc2V0IGlzIHNwZWNpZmllZCBpbiB0aGUgaW5wdXQgc3RyaW5nIGl0c2VsZi4gV2lsbCBhbHNvIGNvbnZlcnQgdGhlIERhdGVUaW1lIHRvIHRoaXMgem9uZQogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5zZXRab25lPWZhbHNlXSAtIG92ZXJyaWRlIHRoZSB6b25lIHdpdGggYSB6b25lIHNwZWNpZmllZCBpbiB0aGUgc3RyaW5nIGl0c2VsZiwgaWYgaXQgc3BlY2lmaWVzIG9uZQogICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRzLmxvY2FsZT0nZW4tVVMnXSAtIGEgbG9jYWxlIHN0cmluZyB0byB1c2Ugd2hlbiBwYXJzaW5nLiBXaWxsIGFsc28gc2V0IHRoZSBEYXRlVGltZSB0byB0aGlzIGxvY2FsZQogICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdHMubnVtYmVyaW5nU3lzdGVtIC0gdGhlIG51bWJlcmluZyBzeXN0ZW0gdG8gdXNlIHdoZW4gcGFyc2luZy4gV2lsbCBhbHNvIHNldCB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIHRvIHRoaXMgbnVtYmVyaW5nIHN5c3RlbQogICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdHMub3V0cHV0Q2FsZW5kYXIgLSB0aGUgb3V0cHV0IGNhbGVuZGFyIHRvIHNldCBvbiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lIGluc3RhbmNlCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tU1FMKCcyMDE3LTA1LTE1JykKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmZyb21TUUwoJzIwMTctMDUtMTUgMDk6MTI6MzQnKQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUuZnJvbVNRTCgnMjAxNy0wNS0xNSAwOToxMjozNC4zNDInKQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUuZnJvbVNRTCgnMjAxNy0wNS0xNSAwOToxMjozNC4zNDIrMDY6MDAnKQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUuZnJvbVNRTCgnMjAxNy0wNS0xNSAwOToxMjozNC4zNDIgQW1lcmljYS9Mb3NfQW5nZWxlcycpCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tU1FMKCcyMDE3LTA1LTE1IDA5OjEyOjM0LjM0MiBBbWVyaWNhL0xvc19BbmdlbGVzJywgeyBzZXRab25lOiB0cnVlIH0pCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tU1FMKCcyMDE3LTA1LTE1IDA5OjEyOjM0LjM0MicsIHsgem9uZTogJ0FtZXJpY2EvTG9zX0FuZ2VsZXMnIH0pCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5mcm9tU1FMKCcwOToxMjozNC4zNDInKQogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXRpYyBmcm9tU1FMKHRleHQsIG9wdHMgPSB7fSkgewogICAgICBjb25zdCBbdmFscywgcGFyc2VkWm9uZV0gPSBwYXJzZVNRTCh0ZXh0KTsKICAgICAgcmV0dXJuIHBhcnNlRGF0YVRvRGF0ZVRpbWUodmFscywgcGFyc2VkWm9uZSwgb3B0cywgIlNRTCIsIHRleHQpOwogICAgfQoKICAgIC8qKgogICAgICogQ3JlYXRlIGFuIGludmFsaWQgRGF0ZVRpbWUuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcmVhc29uIC0gc2ltcGxlIHN0cmluZyBvZiB3aHkgdGhpcyBEYXRlVGltZSBpcyBpbnZhbGlkLiBTaG91bGQgbm90IGNvbnRhaW4gcGFyYW1ldGVycyBvciBhbnl0aGluZyBlbHNlIGRhdGEtZGVwZW5kZW50LgogICAgICogQHBhcmFtIHtzdHJpbmd9IFtleHBsYW5hdGlvbj1udWxsXSAtIGxvbmdlciBleHBsYW5hdGlvbiwgbWF5IGluY2x1ZGUgcGFyYW1ldGVycyBhbmQgb3RoZXIgdXNlZnVsIGRlYnVnZ2luZyBpbmZvcm1hdGlvbgogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXRpYyBpbnZhbGlkKHJlYXNvbiwgZXhwbGFuYXRpb24gPSBudWxsKSB7CiAgICAgIGlmICghcmVhc29uKSB7CiAgICAgICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudEVycm9yKCJuZWVkIHRvIHNwZWNpZnkgYSByZWFzb24gdGhlIERhdGVUaW1lIGlzIGludmFsaWQiKTsKICAgICAgfQoKICAgICAgY29uc3QgaW52YWxpZCA9IHJlYXNvbiBpbnN0YW5jZW9mIEludmFsaWQgPyByZWFzb24gOiBuZXcgSW52YWxpZChyZWFzb24sIGV4cGxhbmF0aW9uKTsKCiAgICAgIGlmIChTZXR0aW5ncy50aHJvd09uSW52YWxpZCkgewogICAgICAgIHRocm93IG5ldyBJbnZhbGlkRGF0ZVRpbWVFcnJvcihpbnZhbGlkKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gbmV3IERhdGVUaW1lKHsgaW52YWxpZCB9KTsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQ2hlY2sgaWYgYW4gb2JqZWN0IGlzIGFuIGluc3RhbmNlIG9mIERhdGVUaW1lLiBXb3JrcyBhY3Jvc3MgY29udGV4dCBib3VuZGFyaWVzCiAgICAgKiBAcGFyYW0ge29iamVjdH0gbwogICAgICogQHJldHVybiB7Ym9vbGVhbn0KICAgICAqLwogICAgc3RhdGljIGlzRGF0ZVRpbWUobykgewogICAgICByZXR1cm4gKG8gJiYgby5pc0x1eG9uRGF0ZVRpbWUpIHx8IGZhbHNlOwogICAgfQoKICAgIC8qKgogICAgICogUHJvZHVjZSB0aGUgZm9ybWF0IHN0cmluZyBmb3IgYSBzZXQgb2Ygb3B0aW9ucwogICAgICogQHBhcmFtIGZvcm1hdE9wdHMKICAgICAqIEBwYXJhbSBsb2NhbGVPcHRzCiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfQogICAgICovCiAgICBzdGF0aWMgcGFyc2VGb3JtYXRGb3JPcHRzKGZvcm1hdE9wdHMsIGxvY2FsZU9wdHMgPSB7fSkgewogICAgICBjb25zdCB0b2tlbkxpc3QgPSBmb3JtYXRPcHRzVG9Ub2tlbnMoZm9ybWF0T3B0cywgTG9jYWxlLmZyb21PYmplY3QobG9jYWxlT3B0cykpOwogICAgICByZXR1cm4gIXRva2VuTGlzdCA/IG51bGwgOiB0b2tlbkxpc3QubWFwKCh0KSA9PiAodCA/IHQudmFsIDogbnVsbCkpLmpvaW4oIiIpOwogICAgfQoKICAgIC8qKgogICAgICogUHJvZHVjZSB0aGUgdGhlIGZ1bGx5IGV4cGFuZGVkIGZvcm1hdCB0b2tlbiBmb3IgdGhlIGxvY2FsZQogICAgICogRG9lcyBOT1QgcXVvdGUgY2hhcmFjdGVycywgc28gcXVvdGVkIHRva2VucyB3aWxsIG5vdCByb3VuZCB0cmlwIGNvcnJlY3RseQogICAgICogQHBhcmFtIGZtdAogICAgICogQHBhcmFtIGxvY2FsZU9wdHMKICAgICAqIEByZXR1cm5zIHtzdHJpbmd9CiAgICAgKi8KICAgIHN0YXRpYyBleHBhbmRGb3JtYXQoZm10LCBsb2NhbGVPcHRzID0ge30pIHsKICAgICAgY29uc3QgZXhwYW5kZWQgPSBleHBhbmRNYWNyb1Rva2VucyhGb3JtYXR0ZXIucGFyc2VGb3JtYXQoZm10KSwgTG9jYWxlLmZyb21PYmplY3QobG9jYWxlT3B0cykpOwogICAgICByZXR1cm4gZXhwYW5kZWQubWFwKCh0KSA9PiB0LnZhbCkuam9pbigiIik7CiAgICB9CgogICAgLy8gSU5GTwoKICAgIC8qKgogICAgICogR2V0IHRoZSB2YWx1ZSBvZiB1bml0LgogICAgICogQHBhcmFtIHtzdHJpbmd9IHVuaXQgLSBhIHVuaXQgc3VjaCBhcyAnbWludXRlJyBvciAnZGF5JwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgNywgNCkuZ2V0KCdtb250aCcpOyAvLz0+IDcKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDcsIDQpLmdldCgnZGF5Jyk7IC8vPT4gNAogICAgICogQHJldHVybiB7bnVtYmVyfQogICAgICovCiAgICBnZXQodW5pdCkgewogICAgICByZXR1cm4gdGhpc1t1bml0XTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgd2hldGhlciB0aGUgRGF0ZVRpbWUgaXMgdmFsaWQuIEludmFsaWQgRGF0ZVRpbWVzIG9jY3VyIHdoZW46CiAgICAgKiAqIFRoZSBEYXRlVGltZSB3YXMgY3JlYXRlZCBmcm9tIGludmFsaWQgY2FsZW5kYXIgaW5mb3JtYXRpb24sIHN1Y2ggYXMgdGhlIDEzdGggbW9udGggb3IgRmVicnVhcnkgMzAKICAgICAqICogVGhlIERhdGVUaW1lIHdhcyBjcmVhdGVkIGJ5IGFuIG9wZXJhdGlvbiBvbiBhbm90aGVyIGludmFsaWQgZGF0ZQogICAgICogQHR5cGUge2Jvb2xlYW59CiAgICAgKi8KICAgIGdldCBpc1ZhbGlkKCkgewogICAgICByZXR1cm4gdGhpcy5pbnZhbGlkID09PSBudWxsOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhbiBlcnJvciBjb2RlIGlmIHRoaXMgRGF0ZVRpbWUgaXMgaW52YWxpZCwgb3IgbnVsbCBpZiB0aGUgRGF0ZVRpbWUgaXMgdmFsaWQKICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIGdldCBpbnZhbGlkUmVhc29uKCkgewogICAgICByZXR1cm4gdGhpcy5pbnZhbGlkID8gdGhpcy5pbnZhbGlkLnJlYXNvbiA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGFuIGV4cGxhbmF0aW9uIG9mIHdoeSB0aGlzIERhdGVUaW1lIGJlY2FtZSBpbnZhbGlkLCBvciBudWxsIGlmIHRoZSBEYXRlVGltZSBpcyB2YWxpZAogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgZ2V0IGludmFsaWRFeHBsYW5hdGlvbigpIHsKICAgICAgcmV0dXJuIHRoaXMuaW52YWxpZCA/IHRoaXMuaW52YWxpZC5leHBsYW5hdGlvbiA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIGxvY2FsZSBvZiBhIERhdGVUaW1lLCBzdWNoICdlbi1HQicuIFRoZSBsb2NhbGUgaXMgdXNlZCB3aGVuIGZvcm1hdHRpbmcgdGhlIERhdGVUaW1lCiAgICAgKgogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgZ2V0IGxvY2FsZSgpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IHRoaXMubG9jLmxvY2FsZSA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIG51bWJlcmluZyBzeXN0ZW0gb2YgYSBEYXRlVGltZSwgc3VjaCAnYmVuZycuIFRoZSBudW1iZXJpbmcgc3lzdGVtIGlzIHVzZWQgd2hlbiBmb3JtYXR0aW5nIHRoZSBEYXRlVGltZQogICAgICoKICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIGdldCBudW1iZXJpbmdTeXN0ZW0oKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLmxvYy5udW1iZXJpbmdTeXN0ZW0gOiBudWxsOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBvdXRwdXQgY2FsZW5kYXIgb2YgYSBEYXRlVGltZSwgc3VjaCAnaXNsYW1pYycuIFRoZSBvdXRwdXQgY2FsZW5kYXIgaXMgdXNlZCB3aGVuIGZvcm1hdHRpbmcgdGhlIERhdGVUaW1lCiAgICAgKgogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgZ2V0IG91dHB1dENhbGVuZGFyKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy5sb2Mub3V0cHV0Q2FsZW5kYXIgOiBudWxsOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSB0aW1lIHpvbmUgYXNzb2NpYXRlZCB3aXRoIHRoaXMgRGF0ZVRpbWUuCiAgICAgKiBAdHlwZSB7Wm9uZX0KICAgICAqLwogICAgZ2V0IHpvbmUoKSB7CiAgICAgIHJldHVybiB0aGlzLl96b25lOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBuYW1lIG9mIHRoZSB0aW1lIHpvbmUuCiAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICovCiAgICBnZXQgem9uZU5hbWUoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLnpvbmUubmFtZSA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIHllYXIKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDUsIDI1KS55ZWFyIC8vPT4gMjAxNwogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IHllYXIoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLmMueWVhciA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgcXVhcnRlcgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgNSwgMjUpLnF1YXJ0ZXIgLy89PiAyCiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICovCiAgICBnZXQgcXVhcnRlcigpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IE1hdGguY2VpbCh0aGlzLmMubW9udGggLyAzKSA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgbW9udGggKDEtMTIpLgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgNSwgMjUpLm1vbnRoIC8vPT4gNQogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IG1vbnRoKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy5jLm1vbnRoIDogTmFOOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBkYXkgb2YgdGhlIG1vbnRoICgxLTMwaXNoKS4KICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDUsIDI1KS5kYXkgLy89PiAyNQogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IGRheSgpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IHRoaXMuYy5kYXkgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIGhvdXIgb2YgdGhlIGRheSAoMC0yMykuCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE3LCA1LCAyNSwgOSkuaG91ciAvLz0+IDkKICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgKi8KICAgIGdldCBob3VyKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy5jLmhvdXIgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIG1pbnV0ZSBvZiB0aGUgaG91ciAoMC01OSkuCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE3LCA1LCAyNSwgOSwgMzApLm1pbnV0ZSAvLz0+IDMwCiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICovCiAgICBnZXQgbWludXRlKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gdGhpcy5jLm1pbnV0ZSA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgc2Vjb25kIG9mIHRoZSBtaW51dGUgKDAtNTkpLgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgNSwgMjUsIDksIDMwLCA1Mikuc2Vjb25kIC8vPT4gNTIKICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgKi8KICAgIGdldCBzZWNvbmQoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLmMuc2Vjb25kIDogTmFOOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBtaWxsaXNlY29uZCBvZiB0aGUgc2Vjb25kICgwLTk5OSkuCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE3LCA1LCAyNSwgOSwgMzAsIDUyLCA2NTQpLm1pbGxpc2Vjb25kIC8vPT4gNjU0CiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICovCiAgICBnZXQgbWlsbGlzZWNvbmQoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLmMubWlsbGlzZWNvbmQgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIHdlZWsgeWVhcgogICAgICogQHNlZSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JU09fd2Vla19kYXRlCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE0LCAxMiwgMzEpLndlZWtZZWFyIC8vPT4gMjAxNQogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IHdlZWtZZWFyKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gcG9zc2libHlDYWNoZWRXZWVrRGF0YSh0aGlzKS53ZWVrWWVhciA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgd2VlayBudW1iZXIgb2YgdGhlIHdlZWsgeWVhciAoMS01MmlzaCkuCiAgICAgKiBAc2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0lTT193ZWVrX2RhdGUKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDUsIDI1KS53ZWVrTnVtYmVyIC8vPT4gMjEKICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgKi8KICAgIGdldCB3ZWVrTnVtYmVyKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gcG9zc2libHlDYWNoZWRXZWVrRGF0YSh0aGlzKS53ZWVrTnVtYmVyIDogTmFOOwogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBkYXkgb2YgdGhlIHdlZWsuCiAgICAgKiAxIGlzIE1vbmRheSBhbmQgNyBpcyBTdW5kYXkKICAgICAqIEBzZWUgaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvSVNPX3dlZWtfZGF0ZQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNCwgMTEsIDMxKS53ZWVrZGF5IC8vPT4gNAogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IHdlZWtkYXkoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyBwb3NzaWJseUNhY2hlZFdlZWtEYXRhKHRoaXMpLndlZWtkYXkgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIG9yZGluYWwgKG1lYW5pbmcgdGhlIGRheSBvZiB0aGUgeWVhcikKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDUsIDI1KS5vcmRpbmFsIC8vPT4gMTQ1CiAgICAgKiBAdHlwZSB7bnVtYmVyfERhdGVUaW1lfQogICAgICovCiAgICBnZXQgb3JkaW5hbCgpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IGdyZWdvcmlhblRvT3JkaW5hbCh0aGlzLmMpLm9yZGluYWwgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIGh1bWFuIHJlYWRhYmxlIHNob3J0IG1vbnRoIG5hbWUsIHN1Y2ggYXMgJ09jdCcuCiAgICAgKiBEZWZhdWx0cyB0byB0aGUgc3lzdGVtJ3MgbG9jYWxlIGlmIG5vIGxvY2FsZSBoYXMgYmVlbiBzcGVjaWZpZWQKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDEwLCAzMCkubW9udGhTaG9ydCAvLz0+IE9jdAogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgZ2V0IG1vbnRoU2hvcnQoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyBJbmZvLm1vbnRocygic2hvcnQiLCB7IGxvY09iajogdGhpcy5sb2MgfSlbdGhpcy5tb250aCAtIDFdIDogbnVsbDsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgaHVtYW4gcmVhZGFibGUgbG9uZyBtb250aCBuYW1lLCBzdWNoIGFzICdPY3RvYmVyJy4KICAgICAqIERlZmF1bHRzIHRvIHRoZSBzeXN0ZW0ncyBsb2NhbGUgaWYgbm8gbG9jYWxlIGhhcyBiZWVuIHNwZWNpZmllZAogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgMTAsIDMwKS5tb250aExvbmcgLy89PiBPY3RvYmVyCiAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICovCiAgICBnZXQgbW9udGhMb25nKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gSW5mby5tb250aHMoImxvbmciLCB7IGxvY09iajogdGhpcy5sb2MgfSlbdGhpcy5tb250aCAtIDFdIDogbnVsbDsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgaHVtYW4gcmVhZGFibGUgc2hvcnQgd2Vla2RheSwgc3VjaCBhcyAnTW9uJy4KICAgICAqIERlZmF1bHRzIHRvIHRoZSBzeXN0ZW0ncyBsb2NhbGUgaWYgbm8gbG9jYWxlIGhhcyBiZWVuIHNwZWNpZmllZAogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgMTAsIDMwKS53ZWVrZGF5U2hvcnQgLy89PiBNb24KICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIGdldCB3ZWVrZGF5U2hvcnQoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyBJbmZvLndlZWtkYXlzKCJzaG9ydCIsIHsgbG9jT2JqOiB0aGlzLmxvYyB9KVt0aGlzLndlZWtkYXkgLSAxXSA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIGh1bWFuIHJlYWRhYmxlIGxvbmcgd2Vla2RheSwgc3VjaCBhcyAnTW9uZGF5Jy4KICAgICAqIERlZmF1bHRzIHRvIHRoZSBzeXN0ZW0ncyBsb2NhbGUgaWYgbm8gbG9jYWxlIGhhcyBiZWVuIHNwZWNpZmllZAogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgMTAsIDMwKS53ZWVrZGF5TG9uZyAvLz0+IE1vbmRheQogICAgICogQHR5cGUge3N0cmluZ30KICAgICAqLwogICAgZ2V0IHdlZWtkYXlMb25nKCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gSW5mby53ZWVrZGF5cygibG9uZyIsIHsgbG9jT2JqOiB0aGlzLmxvYyB9KVt0aGlzLndlZWtkYXkgLSAxXSA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgdGhlIFVUQyBvZmZzZXQgb2YgdGhpcyBEYXRlVGltZSBpbiBtaW51dGVzCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS5vZmZzZXQgLy89PiAtMjQwCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS51dGMoKS5vZmZzZXQgLy89PiAwCiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICovCiAgICBnZXQgb2Zmc2V0KCkgewogICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkID8gK3RoaXMubyA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aGUgc2hvcnQgaHVtYW4gbmFtZSBmb3IgdGhlIHpvbmUncyBjdXJyZW50IG9mZnNldCwgZm9yIGV4YW1wbGUgIkVTVCIgb3IgIkVEVCIuCiAgICAgKiBEZWZhdWx0cyB0byB0aGUgc3lzdGVtJ3MgbG9jYWxlIGlmIG5vIGxvY2FsZSBoYXMgYmVlbiBzcGVjaWZpZWQKICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgKi8KICAgIGdldCBvZmZzZXROYW1lU2hvcnQoKSB7CiAgICAgIGlmICh0aGlzLmlzVmFsaWQpIHsKICAgICAgICByZXR1cm4gdGhpcy56b25lLm9mZnNldE5hbWUodGhpcy50cywgewogICAgICAgICAgZm9ybWF0OiAic2hvcnQiLAogICAgICAgICAgbG9jYWxlOiB0aGlzLmxvY2FsZSwKICAgICAgICB9KTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogR2V0IHRoZSBsb25nIGh1bWFuIG5hbWUgZm9yIHRoZSB6b25lJ3MgY3VycmVudCBvZmZzZXQsIGZvciBleGFtcGxlICJFYXN0ZXJuIFN0YW5kYXJkIFRpbWUiIG9yICJFYXN0ZXJuIERheWxpZ2h0IFRpbWUiLgogICAgICogRGVmYXVsdHMgdG8gdGhlIHN5c3RlbSdzIGxvY2FsZSBpZiBubyBsb2NhbGUgaGFzIGJlZW4gc3BlY2lmaWVkCiAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICovCiAgICBnZXQgb2Zmc2V0TmFtZUxvbmcoKSB7CiAgICAgIGlmICh0aGlzLmlzVmFsaWQpIHsKICAgICAgICByZXR1cm4gdGhpcy56b25lLm9mZnNldE5hbWUodGhpcy50cywgewogICAgICAgICAgZm9ybWF0OiAibG9uZyIsCiAgICAgICAgICBsb2NhbGU6IHRoaXMubG9jYWxlLAogICAgICAgIH0pOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBudWxsOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgd2hldGhlciB0aGlzIHpvbmUncyBvZmZzZXQgZXZlciBjaGFuZ2VzLCBhcyBpbiBhIERTVC4KICAgICAqIEB0eXBlIHtib29sZWFufQogICAgICovCiAgICBnZXQgaXNPZmZzZXRGaXhlZCgpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IHRoaXMuem9uZS5pc1VuaXZlcnNhbCA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBHZXQgd2hldGhlciB0aGUgRGF0ZVRpbWUgaXMgaW4gYSBEU1QuCiAgICAgKiBAdHlwZSB7Ym9vbGVhbn0KICAgICAqLwogICAgZ2V0IGlzSW5EU1QoKSB7CiAgICAgIGlmICh0aGlzLmlzT2Zmc2V0Rml4ZWQpIHsKICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuICgKICAgICAgICAgIHRoaXMub2Zmc2V0ID4gdGhpcy5zZXQoeyBtb250aDogMSwgZGF5OiAxIH0pLm9mZnNldCB8fAogICAgICAgICAgdGhpcy5vZmZzZXQgPiB0aGlzLnNldCh7IG1vbnRoOiA1IH0pLm9mZnNldAogICAgICAgICk7CiAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEdldCB0aG9zZSBEYXRlVGltZXMgd2hpY2ggaGF2ZSB0aGUgc2FtZSBsb2NhbCB0aW1lIGFzIHRoaXMgRGF0ZVRpbWUsIGJ1dCBhIGRpZmZlcmVudCBvZmZzZXQgZnJvbSBVVEMKICAgICAqIGluIHRoaXMgRGF0ZVRpbWUncyB6b25lLiBEdXJpbmcgRFNUIGNoYW5nZXMgbG9jYWwgdGltZSBjYW4gYmUgYW1iaWd1b3VzLCBmb3IgZXhhbXBsZQogICAgICogYDIwMjMtMTAtMjlUMDI6MzA6MDBgIGluIGBFdXJvcGUvQmVybGluYCBjYW4gaGF2ZSBvZmZzZXQgYCswMTowMGAgb3IgYCswMjowMGAuCiAgICAgKiBUaGlzIG1ldGhvZCB3aWxsIHJldHVybiBib3RoIHBvc3NpYmxlIERhdGVUaW1lcyBpZiB0aGlzIERhdGVUaW1lJ3MgbG9jYWwgdGltZSBpcyBhbWJpZ3VvdXMuCiAgICAgKiBAcmV0dXJucyB7RGF0ZVRpbWVbXX0KICAgICAqLwogICAgZ2V0UG9zc2libGVPZmZzZXRzKCkgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCB8fCB0aGlzLmlzT2Zmc2V0Rml4ZWQpIHsKICAgICAgICByZXR1cm4gW3RoaXNdOwogICAgICB9CiAgICAgIGNvbnN0IGRheU1zID0gODY0MDAwMDA7CiAgICAgIGNvbnN0IG1pbnV0ZU1zID0gNjAwMDA7CiAgICAgIGNvbnN0IGxvY2FsVFMgPSBvYmpUb0xvY2FsVFModGhpcy5jKTsKICAgICAgY29uc3Qgb0VhcmxpZXIgPSB0aGlzLnpvbmUub2Zmc2V0KGxvY2FsVFMgLSBkYXlNcyk7CiAgICAgIGNvbnN0IG9MYXRlciA9IHRoaXMuem9uZS5vZmZzZXQobG9jYWxUUyArIGRheU1zKTsKCiAgICAgIGNvbnN0IG8xID0gdGhpcy56b25lLm9mZnNldChsb2NhbFRTIC0gb0VhcmxpZXIgKiBtaW51dGVNcyk7CiAgICAgIGNvbnN0IG8yID0gdGhpcy56b25lLm9mZnNldChsb2NhbFRTIC0gb0xhdGVyICogbWludXRlTXMpOwogICAgICBpZiAobzEgPT09IG8yKSB7CiAgICAgICAgcmV0dXJuIFt0aGlzXTsKICAgICAgfQogICAgICBjb25zdCB0czEgPSBsb2NhbFRTIC0gbzEgKiBtaW51dGVNczsKICAgICAgY29uc3QgdHMyID0gbG9jYWxUUyAtIG8yICogbWludXRlTXM7CiAgICAgIGNvbnN0IGMxID0gdHNUb09iaih0czEsIG8xKTsKICAgICAgY29uc3QgYzIgPSB0c1RvT2JqKHRzMiwgbzIpOwogICAgICBpZiAoCiAgICAgICAgYzEuaG91ciA9PT0gYzIuaG91ciAmJgogICAgICAgIGMxLm1pbnV0ZSA9PT0gYzIubWludXRlICYmCiAgICAgICAgYzEuc2Vjb25kID09PSBjMi5zZWNvbmQgJiYKICAgICAgICBjMS5taWxsaXNlY29uZCA9PT0gYzIubWlsbGlzZWNvbmQKICAgICAgKSB7CiAgICAgICAgcmV0dXJuIFtjbG9uZSh0aGlzLCB7IHRzOiB0czEgfSksIGNsb25lKHRoaXMsIHsgdHM6IHRzMiB9KV07CiAgICAgIH0KICAgICAgcmV0dXJuIFt0aGlzXTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIERhdGVUaW1lIGlzIGluIGEgbGVhcCB5ZWFyLCBmYWxzZSBvdGhlcndpc2UKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTYpLmlzSW5MZWFwWWVhciAvLz0+IHRydWUKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTMpLmlzSW5MZWFwWWVhciAvLz0+IGZhbHNlCiAgICAgKiBAdHlwZSB7Ym9vbGVhbn0KICAgICAqLwogICAgZ2V0IGlzSW5MZWFwWWVhcigpIHsKICAgICAgcmV0dXJuIGlzTGVhcFllYXIodGhpcy55ZWFyKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIG51bWJlciBvZiBkYXlzIGluIHRoaXMgRGF0ZVRpbWUncyBtb250aAogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNiwgMikuZGF5c0luTW9udGggLy89PiAyOQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNiwgMykuZGF5c0luTW9udGggLy89PiAzMQogICAgICogQHR5cGUge251bWJlcn0KICAgICAqLwogICAgZ2V0IGRheXNJbk1vbnRoKCkgewogICAgICByZXR1cm4gZGF5c0luTW9udGgodGhpcy55ZWFyLCB0aGlzLm1vbnRoKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIG51bWJlciBvZiBkYXlzIGluIHRoaXMgRGF0ZVRpbWUncyB5ZWFyCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE2KS5kYXlzSW5ZZWFyIC8vPT4gMzY2CiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDEzKS5kYXlzSW5ZZWFyIC8vPT4gMzY1CiAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICovCiAgICBnZXQgZGF5c0luWWVhcigpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IGRheXNJblllYXIodGhpcy55ZWFyKSA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIG51bWJlciBvZiB3ZWVrcyBpbiB0aGlzIERhdGVUaW1lJ3MgeWVhcgogICAgICogQHNlZSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JU09fd2Vla19kYXRlCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDA0KS53ZWVrc0luV2Vla1llYXIgLy89PiA1MwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxMykud2Vla3NJbldlZWtZZWFyIC8vPT4gNTIKICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgKi8KICAgIGdldCB3ZWVrc0luV2Vla1llYXIoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB3ZWVrc0luV2Vla1llYXIodGhpcy53ZWVrWWVhcikgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSByZXNvbHZlZCBJbnRsIG9wdGlvbnMgZm9yIHRoaXMgRGF0ZVRpbWUuCiAgICAgKiBUaGlzIGlzIHVzZWZ1bCBpbiB1bmRlcnN0YW5kaW5nIHRoZSBiZWhhdmlvciBvZiBmb3JtYXR0aW5nIG1ldGhvZHMKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRzIC0gdGhlIHNhbWUgb3B0aW9ucyBhcyB0b0xvY2FsZVN0cmluZwogICAgICogQHJldHVybiB7T2JqZWN0fQogICAgICovCiAgICByZXNvbHZlZExvY2FsZU9wdGlvbnMob3B0cyA9IHt9KSB7CiAgICAgIGNvbnN0IHsgbG9jYWxlLCBudW1iZXJpbmdTeXN0ZW0sIGNhbGVuZGFyIH0gPSBGb3JtYXR0ZXIuY3JlYXRlKAogICAgICAgIHRoaXMubG9jLmNsb25lKG9wdHMpLAogICAgICAgIG9wdHMKICAgICAgKS5yZXNvbHZlZE9wdGlvbnModGhpcyk7CiAgICAgIHJldHVybiB7IGxvY2FsZSwgbnVtYmVyaW5nU3lzdGVtLCBvdXRwdXRDYWxlbmRhcjogY2FsZW5kYXIgfTsKICAgIH0KCiAgICAvLyBUUkFOU0ZPUk0KCiAgICAvKioKICAgICAqICJTZXQiIHRoZSBEYXRlVGltZSdzIHpvbmUgdG8gVVRDLiBSZXR1cm5zIGEgbmV3bHktY29uc3RydWN0ZWQgRGF0ZVRpbWUuCiAgICAgKgogICAgICogRXF1aXZhbGVudCB0byB7QGxpbmsgRGF0ZVRpbWUjc2V0Wm9uZX0oJ3V0YycpCiAgICAgKiBAcGFyYW0ge251bWJlcn0gW29mZnNldD0wXSAtIG9wdGlvbmFsbHksIGFuIG9mZnNldCBmcm9tIFVUQyBpbiBtaW51dGVzCiAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdHM9e31dIC0gb3B0aW9ucyB0byBwYXNzIHRvIGBzZXRab25lKClgCiAgICAgKiBAcmV0dXJuIHtEYXRlVGltZX0KICAgICAqLwogICAgdG9VVEMob2Zmc2V0ID0gMCwgb3B0cyA9IHt9KSB7CiAgICAgIHJldHVybiB0aGlzLnNldFpvbmUoRml4ZWRPZmZzZXRab25lLmluc3RhbmNlKG9mZnNldCksIG9wdHMpOwogICAgfQoKICAgIC8qKgogICAgICogIlNldCIgdGhlIERhdGVUaW1lJ3Mgem9uZSB0byB0aGUgaG9zdCdzIGxvY2FsIHpvbmUuIFJldHVybnMgYSBuZXdseS1jb25zdHJ1Y3RlZCBEYXRlVGltZS4KICAgICAqCiAgICAgKiBFcXVpdmFsZW50IHRvIGBzZXRab25lKCdsb2NhbCcpYAogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHRvTG9jYWwoKSB7CiAgICAgIHJldHVybiB0aGlzLnNldFpvbmUoU2V0dGluZ3MuZGVmYXVsdFpvbmUpOwogICAgfQoKICAgIC8qKgogICAgICogIlNldCIgdGhlIERhdGVUaW1lJ3Mgem9uZSB0byBzcGVjaWZpZWQgem9uZS4gUmV0dXJucyBhIG5ld2x5LWNvbnN0cnVjdGVkIERhdGVUaW1lLgogICAgICoKICAgICAqIEJ5IGRlZmF1bHQsIHRoZSBzZXR0ZXIga2VlcHMgdGhlIHVuZGVybHlpbmcgdGltZSB0aGUgc2FtZSAoYXMgaW4sIHRoZSBzYW1lIHRpbWVzdGFtcCksIGJ1dCB0aGUgbmV3IGluc3RhbmNlIHdpbGwgcmVwb3J0IGRpZmZlcmVudCBsb2NhbCB0aW1lcyBhbmQgY29uc2lkZXIgRFNUcyB3aGVuIG1ha2luZyBjb21wdXRhdGlvbnMsIGFzIHdpdGgge0BsaW5rIERhdGVUaW1lI3BsdXN9LiBZb3UgbWF5IHdpc2ggdG8gdXNlIHtAbGluayBEYXRlVGltZSN0b0xvY2FsfSBhbmQge0BsaW5rIERhdGVUaW1lI3RvVVRDfSB3aGljaCBwcm92aWRlIHNpbXBsZSBjb252ZW5pZW5jZSB3cmFwcGVycyBmb3IgY29tbW9ubHkgdXNlZCB6b25lcy4KICAgICAqIEBwYXJhbSB7c3RyaW5nfFpvbmV9IFt6b25lPSdsb2NhbCddIC0gYSB6b25lIGlkZW50aWZpZXIuIEFzIGEgc3RyaW5nLCB0aGF0IGNhbiBiZSBhbnkgSUFOQSB6b25lIHN1cHBvcnRlZCBieSB0aGUgaG9zdCBlbnZpcm9ubWVudCwgb3IgYSBmaXhlZC1vZmZzZXQgbmFtZSBvZiB0aGUgZm9ybSAnVVRDKzMnLCBvciB0aGUgc3RyaW5ncyAnbG9jYWwnIG9yICd1dGMnLiBZb3UgbWF5IGFsc28gc3VwcGx5IGFuIGluc3RhbmNlIG9mIGEge0BsaW5rIERhdGVUaW1lI1pvbmV9IGNsYXNzLgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmtlZXBMb2NhbFRpbWU9ZmFsc2VdIC0gSWYgdHJ1ZSwgYWRqdXN0IHRoZSB1bmRlcmx5aW5nIHRpbWUgc28gdGhhdCB0aGUgbG9jYWwgdGltZSBzdGF5cyB0aGUgc2FtZSwgYnV0IGluIHRoZSB0YXJnZXQgem9uZS4gWW91IHNob3VsZCByYXJlbHkgbmVlZCB0aGlzLgogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHNldFpvbmUoem9uZSwgeyBrZWVwTG9jYWxUaW1lID0gZmFsc2UsIGtlZXBDYWxlbmRhclRpbWUgPSBmYWxzZSB9ID0ge30pIHsKICAgICAgem9uZSA9IG5vcm1hbGl6ZVpvbmUoem9uZSwgU2V0dGluZ3MuZGVmYXVsdFpvbmUpOwogICAgICBpZiAoem9uZS5lcXVhbHModGhpcy56b25lKSkgewogICAgICAgIHJldHVybiB0aGlzOwogICAgICB9IGVsc2UgaWYgKCF6b25lLmlzVmFsaWQpIHsKICAgICAgICByZXR1cm4gRGF0ZVRpbWUuaW52YWxpZCh1bnN1cHBvcnRlZFpvbmUoem9uZSkpOwogICAgICB9IGVsc2UgewogICAgICAgIGxldCBuZXdUUyA9IHRoaXMudHM7CiAgICAgICAgaWYgKGtlZXBMb2NhbFRpbWUgfHwga2VlcENhbGVuZGFyVGltZSkgewogICAgICAgICAgY29uc3Qgb2Zmc2V0R3Vlc3MgPSB6b25lLm9mZnNldCh0aGlzLnRzKTsKICAgICAgICAgIGNvbnN0IGFzT2JqID0gdGhpcy50b09iamVjdCgpOwogICAgICAgICAgW25ld1RTXSA9IG9ialRvVFMoYXNPYmosIG9mZnNldEd1ZXNzLCB6b25lKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGNsb25lKHRoaXMsIHsgdHM6IG5ld1RTLCB6b25lIH0pOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiAiU2V0IiB0aGUgbG9jYWxlLCBudW1iZXJpbmdTeXN0ZW0sIG9yIG91dHB1dENhbGVuZGFyLiBSZXR1cm5zIGEgbmV3bHktY29uc3RydWN0ZWQgRGF0ZVRpbWUuCiAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcGVydGllcyAtIHRoZSBwcm9wZXJ0aWVzIHRvIHNldAogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNywgNSwgMjUpLnJlY29uZmlndXJlKHsgbG9jYWxlOiAnZW4tR0InIH0pCiAgICAgKiBAcmV0dXJuIHtEYXRlVGltZX0KICAgICAqLwogICAgcmVjb25maWd1cmUoeyBsb2NhbGUsIG51bWJlcmluZ1N5c3RlbSwgb3V0cHV0Q2FsZW5kYXIgfSA9IHt9KSB7CiAgICAgIGNvbnN0IGxvYyA9IHRoaXMubG9jLmNsb25lKHsgbG9jYWxlLCBudW1iZXJpbmdTeXN0ZW0sIG91dHB1dENhbGVuZGFyIH0pOwogICAgICByZXR1cm4gY2xvbmUodGhpcywgeyBsb2MgfSk7CiAgICB9CgogICAgLyoqCiAgICAgKiAiU2V0IiB0aGUgbG9jYWxlLiBSZXR1cm5zIGEgbmV3bHktY29uc3RydWN0ZWQgRGF0ZVRpbWUuCiAgICAgKiBKdXN0IGEgY29udmVuaWVudCBhbGlhcyBmb3IgcmVjb25maWd1cmUoeyBsb2NhbGUgfSkKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTcsIDUsIDI1KS5zZXRMb2NhbGUoJ2VuLUdCJykKICAgICAqIEByZXR1cm4ge0RhdGVUaW1lfQogICAgICovCiAgICBzZXRMb2NhbGUobG9jYWxlKSB7CiAgICAgIHJldHVybiB0aGlzLnJlY29uZmlndXJlKHsgbG9jYWxlIH0pOwogICAgfQoKICAgIC8qKgogICAgICogIlNldCIgdGhlIHZhbHVlcyBvZiBzcGVjaWZpZWQgdW5pdHMuIFJldHVybnMgYSBuZXdseS1jb25zdHJ1Y3RlZCBEYXRlVGltZS4KICAgICAqIFlvdSBjYW4gb25seSBzZXQgdW5pdHMgd2l0aCB0aGlzIG1ldGhvZDsgZm9yICJzZXR0aW5nIiBtZXRhZGF0YSwgc2VlIHtAbGluayBEYXRlVGltZSNyZWNvbmZpZ3VyZX0gYW5kIHtAbGluayBEYXRlVGltZSNzZXRab25lfS4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSB2YWx1ZXMgLSBhIG1hcHBpbmcgb2YgdW5pdHMgdG8gbnVtYmVycwogICAgICogQGV4YW1wbGUgZHQuc2V0KHsgeWVhcjogMjAxNyB9KQogICAgICogQGV4YW1wbGUgZHQuc2V0KHsgaG91cjogOCwgbWludXRlOiAzMCB9KQogICAgICogQGV4YW1wbGUgZHQuc2V0KHsgd2Vla2RheTogNSB9KQogICAgICogQGV4YW1wbGUgZHQuc2V0KHsgeWVhcjogMjAwNSwgb3JkaW5hbDogMjM0IH0pCiAgICAgKiBAcmV0dXJuIHtEYXRlVGltZX0KICAgICAqLwogICAgc2V0KHZhbHVlcykgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIHRoaXM7CgogICAgICBjb25zdCBub3JtYWxpemVkID0gbm9ybWFsaXplT2JqZWN0KHZhbHVlcywgbm9ybWFsaXplVW5pdCksCiAgICAgICAgc2V0dGluZ1dlZWtTdHVmZiA9CiAgICAgICAgICAhaXNVbmRlZmluZWQobm9ybWFsaXplZC53ZWVrWWVhcikgfHwKICAgICAgICAgICFpc1VuZGVmaW5lZChub3JtYWxpemVkLndlZWtOdW1iZXIpIHx8CiAgICAgICAgICAhaXNVbmRlZmluZWQobm9ybWFsaXplZC53ZWVrZGF5KSwKICAgICAgICBjb250YWluc09yZGluYWwgPSAhaXNVbmRlZmluZWQobm9ybWFsaXplZC5vcmRpbmFsKSwKICAgICAgICBjb250YWluc0dyZWdvclllYXIgPSAhaXNVbmRlZmluZWQobm9ybWFsaXplZC55ZWFyKSwKICAgICAgICBjb250YWluc0dyZWdvck1EID0gIWlzVW5kZWZpbmVkKG5vcm1hbGl6ZWQubW9udGgpIHx8ICFpc1VuZGVmaW5lZChub3JtYWxpemVkLmRheSksCiAgICAgICAgY29udGFpbnNHcmVnb3IgPSBjb250YWluc0dyZWdvclllYXIgfHwgY29udGFpbnNHcmVnb3JNRCwKICAgICAgICBkZWZpbml0ZVdlZWtEZWYgPSBub3JtYWxpemVkLndlZWtZZWFyIHx8IG5vcm1hbGl6ZWQud2Vla051bWJlcjsKCiAgICAgIGlmICgoY29udGFpbnNHcmVnb3IgfHwgY29udGFpbnNPcmRpbmFsKSAmJiBkZWZpbml0ZVdlZWtEZWYpIHsKICAgICAgICB0aHJvdyBuZXcgQ29uZmxpY3RpbmdTcGVjaWZpY2F0aW9uRXJyb3IoCiAgICAgICAgICAiQ2FuJ3QgbWl4IHdlZWtZZWFyL3dlZWtOdW1iZXIgdW5pdHMgd2l0aCB5ZWFyL21vbnRoL2RheSBvciBvcmRpbmFscyIKICAgICAgICApOwogICAgICB9CgogICAgICBpZiAoY29udGFpbnNHcmVnb3JNRCAmJiBjb250YWluc09yZGluYWwpIHsKICAgICAgICB0aHJvdyBuZXcgQ29uZmxpY3RpbmdTcGVjaWZpY2F0aW9uRXJyb3IoIkNhbid0IG1peCBvcmRpbmFsIGRhdGVzIHdpdGggbW9udGgvZGF5Iik7CiAgICAgIH0KCiAgICAgIGxldCBtaXhlZDsKICAgICAgaWYgKHNldHRpbmdXZWVrU3R1ZmYpIHsKICAgICAgICBtaXhlZCA9IHdlZWtUb0dyZWdvcmlhbih7IC4uLmdyZWdvcmlhblRvV2Vlayh0aGlzLmMpLCAuLi5ub3JtYWxpemVkIH0pOwogICAgICB9IGVsc2UgaWYgKCFpc1VuZGVmaW5lZChub3JtYWxpemVkLm9yZGluYWwpKSB7CiAgICAgICAgbWl4ZWQgPSBvcmRpbmFsVG9HcmVnb3JpYW4oeyAuLi5ncmVnb3JpYW5Ub09yZGluYWwodGhpcy5jKSwgLi4ubm9ybWFsaXplZCB9KTsKICAgICAgfSBlbHNlIHsKICAgICAgICBtaXhlZCA9IHsgLi4udGhpcy50b09iamVjdCgpLCAuLi5ub3JtYWxpemVkIH07CgogICAgICAgIC8vIGlmIHdlIGRpZG4ndCBzZXQgdGhlIGRheSBidXQgd2UgZW5kZWQgdXAgb24gYW4gb3ZlcmZsb3cgZGF0ZSwKICAgICAgICAvLyB1c2UgdGhlIGxhc3QgZGF5IG9mIHRoZSByaWdodCBtb250aAogICAgICAgIGlmIChpc1VuZGVmaW5lZChub3JtYWxpemVkLmRheSkpIHsKICAgICAgICAgIG1peGVkLmRheSA9IE1hdGgubWluKGRheXNJbk1vbnRoKG1peGVkLnllYXIsIG1peGVkLm1vbnRoKSwgbWl4ZWQuZGF5KTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIGNvbnN0IFt0cywgb10gPSBvYmpUb1RTKG1peGVkLCB0aGlzLm8sIHRoaXMuem9uZSk7CiAgICAgIHJldHVybiBjbG9uZSh0aGlzLCB7IHRzLCBvIH0pOwogICAgfQoKICAgIC8qKgogICAgICogQWRkIGEgcGVyaW9kIG9mIHRpbWUgdG8gdGhpcyBEYXRlVGltZSBhbmQgcmV0dXJuIHRoZSByZXN1bHRpbmcgRGF0ZVRpbWUKICAgICAqCiAgICAgKiBBZGRpbmcgaG91cnMsIG1pbnV0ZXMsIHNlY29uZHMsIG9yIG1pbGxpc2Vjb25kcyBpbmNyZWFzZXMgdGhlIHRpbWVzdGFtcCBieSB0aGUgcmlnaHQgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcy4gQWRkaW5nIGRheXMsIG1vbnRocywgb3IgeWVhcnMgc2hpZnRzIHRoZSBjYWxlbmRhciwgYWNjb3VudGluZyBmb3IgRFNUcyBhbmQgbGVhcCB5ZWFycyBhbG9uZyB0aGUgd2F5LiBUaHVzLCBgZHQucGx1cyh7IGhvdXJzOiAyNCB9KWAgbWF5IHJlc3VsdCBpbiBhIGRpZmZlcmVudCB0aW1lIHRoYW4gYGR0LnBsdXMoeyBkYXlzOiAxIH0pYCBpZiB0aGVyZSdzIGEgRFNUIHNoaWZ0IGluIGJldHdlZW4uCiAgICAgKiBAcGFyYW0ge0R1cmF0aW9ufE9iamVjdHxudW1iZXJ9IGR1cmF0aW9uIC0gVGhlIGFtb3VudCB0byBhZGQuIEVpdGhlciBhIEx1eG9uIER1cmF0aW9uLCBhIG51bWJlciBvZiBtaWxsaXNlY29uZHMsIHRoZSBvYmplY3QgYXJndW1lbnQgdG8gRHVyYXRpb24uZnJvbU9iamVjdCgpCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS5wbHVzKDEyMykgLy9+PiBpbiAxMjMgbWlsbGlzZWNvbmRzCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS5wbHVzKHsgbWludXRlczogMTUgfSkgLy9+PiBpbiAxNSBtaW51dGVzCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS5wbHVzKHsgZGF5czogMSB9KSAvL34+IHRoaXMgdGltZSB0b21vcnJvdwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkucGx1cyh7IGRheXM6IC0xIH0pIC8vfj4gdGhpcyB0aW1lIHllc3RlcmRheQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkucGx1cyh7IGhvdXJzOiAzLCBtaW51dGVzOiAxMyB9KSAvL34+IGluIDMgaHIsIDEzIG1pbgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkucGx1cyhEdXJhdGlvbi5mcm9tT2JqZWN0KHsgaG91cnM6IDMsIG1pbnV0ZXM6IDEzIH0pKSAvL34+IGluIDMgaHIsIDEzIG1pbgogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHBsdXMoZHVyYXRpb24pIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiB0aGlzOwogICAgICBjb25zdCBkdXIgPSBEdXJhdGlvbi5mcm9tRHVyYXRpb25MaWtlKGR1cmF0aW9uKTsKICAgICAgcmV0dXJuIGNsb25lKHRoaXMsIGFkanVzdFRpbWUodGhpcywgZHVyKSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBTdWJ0cmFjdCBhIHBlcmlvZCBvZiB0aW1lIHRvIHRoaXMgRGF0ZVRpbWUgYW5kIHJldHVybiB0aGUgcmVzdWx0aW5nIERhdGVUaW1lCiAgICAgKiBTZWUge0BsaW5rIERhdGVUaW1lI3BsdXN9CiAgICAgKiBAcGFyYW0ge0R1cmF0aW9ufE9iamVjdHxudW1iZXJ9IGR1cmF0aW9uIC0gVGhlIGFtb3VudCB0byBzdWJ0cmFjdC4gRWl0aGVyIGEgTHV4b24gRHVyYXRpb24sIGEgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcywgdGhlIG9iamVjdCBhcmd1bWVudCB0byBEdXJhdGlvbi5mcm9tT2JqZWN0KCkKICAgICBAcmV0dXJuIHtEYXRlVGltZX0KICAgICAqLwogICAgbWludXMoZHVyYXRpb24pIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiB0aGlzOwogICAgICBjb25zdCBkdXIgPSBEdXJhdGlvbi5mcm9tRHVyYXRpb25MaWtlKGR1cmF0aW9uKS5uZWdhdGUoKTsKICAgICAgcmV0dXJuIGNsb25lKHRoaXMsIGFkanVzdFRpbWUodGhpcywgZHVyKSk7CiAgICB9CgogICAgLyoqCiAgICAgKiAiU2V0IiB0aGlzIERhdGVUaW1lIHRvIHRoZSBiZWdpbm5pbmcgb2YgYSB1bml0IG9mIHRpbWUuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdW5pdCAtIFRoZSB1bml0IHRvIGdvIHRvIHRoZSBiZWdpbm5pbmcgb2YuIENhbiBiZSAneWVhcicsICdxdWFydGVyJywgJ21vbnRoJywgJ3dlZWsnLCAnZGF5JywgJ2hvdXInLCAnbWludXRlJywgJ3NlY29uZCcsIG9yICdtaWxsaXNlY29uZCcuCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE0LCAzLCAzKS5zdGFydE9mKCdtb250aCcpLnRvSVNPRGF0ZSgpOyAvLz0+ICcyMDE0LTAzLTAxJwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNCwgMywgMykuc3RhcnRPZigneWVhcicpLnRvSVNPRGF0ZSgpOyAvLz0+ICcyMDE0LTAxLTAxJwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNCwgMywgMykuc3RhcnRPZignd2VlaycpLnRvSVNPRGF0ZSgpOyAvLz0+ICcyMDE0LTAzLTAzJywgd2Vla3MgYWx3YXlzIHN0YXJ0IG9uIE1vbmRheXMKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTQsIDMsIDMsIDUsIDMwKS5zdGFydE9mKCdkYXknKS50b0lTT1RpbWUoKTsgLy89PiAnMDA6MDAuMDAwLTA1OjAwJwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubG9jYWwoMjAxNCwgMywgMywgNSwgMzApLnN0YXJ0T2YoJ2hvdXInKS50b0lTT1RpbWUoKTsgLy89PiAnMDU6MDA6MDAuMDAwLTA1OjAwJwogICAgICogQHJldHVybiB7RGF0ZVRpbWV9CiAgICAgKi8KICAgIHN0YXJ0T2YodW5pdCkgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuIHRoaXM7CiAgICAgIGNvbnN0IG8gPSB7fSwKICAgICAgICBub3JtYWxpemVkVW5pdCA9IER1cmF0aW9uLm5vcm1hbGl6ZVVuaXQodW5pdCk7CiAgICAgIHN3aXRjaCAobm9ybWFsaXplZFVuaXQpIHsKICAgICAgICBjYXNlICJ5ZWFycyI6CiAgICAgICAgICBvLm1vbnRoID0gMTsKICAgICAgICAvLyBmYWxscyB0aHJvdWdoCiAgICAgICAgY2FzZSAicXVhcnRlcnMiOgogICAgICAgIGNhc2UgIm1vbnRocyI6CiAgICAgICAgICBvLmRheSA9IDE7CiAgICAgICAgLy8gZmFsbHMgdGhyb3VnaAogICAgICAgIGNhc2UgIndlZWtzIjoKICAgICAgICBjYXNlICJkYXlzIjoKICAgICAgICAgIG8uaG91ciA9IDA7CiAgICAgICAgLy8gZmFsbHMgdGhyb3VnaAogICAgICAgIGNhc2UgImhvdXJzIjoKICAgICAgICAgIG8ubWludXRlID0gMDsKICAgICAgICAvLyBmYWxscyB0aHJvdWdoCiAgICAgICAgY2FzZSAibWludXRlcyI6CiAgICAgICAgICBvLnNlY29uZCA9IDA7CiAgICAgICAgLy8gZmFsbHMgdGhyb3VnaAogICAgICAgIGNhc2UgInNlY29uZHMiOgogICAgICAgICAgby5taWxsaXNlY29uZCA9IDA7CiAgICAgICAgICBicmVhazsKICAgICAgICAvLyBubyBkZWZhdWx0LCBpbnZhbGlkIHVuaXRzIHRocm93IGluIG5vcm1hbGl6ZVVuaXQoKQogICAgICB9CgogICAgICBpZiAobm9ybWFsaXplZFVuaXQgPT09ICJ3ZWVrcyIpIHsKICAgICAgICBvLndlZWtkYXkgPSAxOwogICAgICB9CgogICAgICBpZiAobm9ybWFsaXplZFVuaXQgPT09ICJxdWFydGVycyIpIHsKICAgICAgICBjb25zdCBxID0gTWF0aC5jZWlsKHRoaXMubW9udGggLyAzKTsKICAgICAgICBvLm1vbnRoID0gKHEgLSAxKSAqIDMgKyAxOwogICAgICB9CgogICAgICByZXR1cm4gdGhpcy5zZXQobyk7CiAgICB9CgogICAgLyoqCiAgICAgKiAiU2V0IiB0aGlzIERhdGVUaW1lIHRvIHRoZSBlbmQgKG1lYW5pbmcgdGhlIGxhc3QgbWlsbGlzZWNvbmQpIG9mIGEgdW5pdCBvZiB0aW1lCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdW5pdCAtIFRoZSB1bml0IHRvIGdvIHRvIHRoZSBlbmQgb2YuIENhbiBiZSAneWVhcicsICdxdWFydGVyJywgJ21vbnRoJywgJ3dlZWsnLCAnZGF5JywgJ2hvdXInLCAnbWludXRlJywgJ3NlY29uZCcsIG9yICdtaWxsaXNlY29uZCcuCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE0LCAzLCAzKS5lbmRPZignbW9udGgnKS50b0lTTygpOyAvLz0+ICcyMDE0LTAzLTMxVDIzOjU5OjU5Ljk5OS0wNTowMCcKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTQsIDMsIDMpLmVuZE9mKCd5ZWFyJykudG9JU08oKTsgLy89PiAnMjAxNC0xMi0zMVQyMzo1OTo1OS45OTktMDU6MDAnCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE0LCAzLCAzKS5lbmRPZignd2VlaycpLnRvSVNPKCk7IC8vID0+ICcyMDE0LTAzLTA5VDIzOjU5OjU5Ljk5OS0wNTowMCcsIHdlZWtzIHN0YXJ0IG9uIE1vbmRheXMKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTQsIDMsIDMsIDUsIDMwKS5lbmRPZignZGF5JykudG9JU08oKTsgLy89PiAnMjAxNC0wMy0wM1QyMzo1OTo1OS45OTktMDU6MDAnCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE0LCAzLCAzLCA1LCAzMCkuZW5kT2YoJ2hvdXInKS50b0lTTygpOyAvLz0+ICcyMDE0LTAzLTAzVDA1OjU5OjU5Ljk5OS0wNTowMCcKICAgICAqIEByZXR1cm4ge0RhdGVUaW1lfQogICAgICovCiAgICBlbmRPZih1bml0KSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQKICAgICAgICA/IHRoaXMucGx1cyh7IFt1bml0XTogMSB9KQogICAgICAgICAgICAuc3RhcnRPZih1bml0KQogICAgICAgICAgICAubWludXMoMSkKICAgICAgICA6IHRoaXM7CiAgICB9CgogICAgLy8gT1VUUFVUCgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgRGF0ZVRpbWUgZm9ybWF0dGVkIGFjY29yZGluZyB0byB0aGUgc3BlY2lmaWVkIGZvcm1hdCBzdHJpbmcuCiAgICAgKiAqKllvdSBtYXkgbm90IHdhbnQgdGhpcy4qKiBTZWUge0BsaW5rIERhdGVUaW1lI3RvTG9jYWxlU3RyaW5nfSBmb3IgYSBtb3JlIGZsZXhpYmxlIGZvcm1hdHRpbmcgdG9vbC4gRm9yIGEgdGFibGUgb2YgdG9rZW5zIGFuZCB0aGVpciBpbnRlcnByZXRhdGlvbnMsIHNlZSBbaGVyZV0oaHR0cHM6Ly9tb21lbnQuZ2l0aHViLmlvL2x1eG9uLyMvZm9ybWF0dGluZz9pZD10YWJsZS1vZi10b2tlbnMpLgogICAgICogRGVmYXVsdHMgdG8gZW4tVVMgaWYgbm8gbG9jYWxlIGhhcyBiZWVuIHNwZWNpZmllZCwgcmVnYXJkbGVzcyBvZiB0aGUgc3lzdGVtJ3MgbG9jYWxlLgogICAgICogQHBhcmFtIHtzdHJpbmd9IGZtdCAtIHRoZSBmb3JtYXQgc3RyaW5nCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdHMgdG8gb3ZlcnJpZGUgdGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvbiB0aGlzIERhdGVUaW1lCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b0Zvcm1hdCgneXl5eSBMTEwgZGQnKSAvLz0+ICcyMDE3IEFwciAyMicKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnNldExvY2FsZSgnZnInKS50b0Zvcm1hdCgneXl5eSBMTEwgZGQnKSAvLz0+ICcyMDE3IGF2ci4gMjInCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b0Zvcm1hdCgneXl5eSBMTEwgZGQnLCB7IGxvY2FsZTogImZyIiB9KSAvLz0+ICcyMDE3IGF2ci4gMjInCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b0Zvcm1hdCgiSEggJ2hvdXJzIGFuZCcgbW0gJ21pbnV0ZXMnIikgLy89PiAnMjAgaG91cnMgYW5kIDU1IG1pbnV0ZXMnCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9CiAgICAgKi8KICAgIHRvRm9ybWF0KGZtdCwgb3B0cyA9IHt9KSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQKICAgICAgICA/IEZvcm1hdHRlci5jcmVhdGUodGhpcy5sb2MucmVkZWZhdWx0VG9FTihvcHRzKSkuZm9ybWF0RGF0ZVRpbWVGcm9tU3RyaW5nKHRoaXMsIGZtdCkKICAgICAgICA6IElOVkFMSUQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgbG9jYWxpemVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhpcyBkYXRlLiBBY2NlcHRzIHRoZSBzYW1lIG9wdGlvbnMgYXMgdGhlIEludGwuRGF0ZVRpbWVGb3JtYXQgY29uc3RydWN0b3IgYW5kIGFueSBwcmVzZXRzIGRlZmluZWQgYnkgTHV4b24sIHN1Y2ggYXMgYERhdGVUaW1lLkRBVEVfRlVMTGAgb3IgYERhdGVUaW1lLlRJTUVfU0lNUExFYC4KICAgICAqIFRoZSBleGFjdCBiZWhhdmlvciBvZiB0aGlzIG1ldGhvZCBpcyBicm93c2VyLXNwZWNpZmljLCBidXQgaW4gZ2VuZXJhbCBpdCB3aWxsIHJldHVybiBhbiBhcHByb3ByaWF0ZSByZXByZXNlbnRhdGlvbgogICAgICogb2YgdGhlIERhdGVUaW1lIGluIHRoZSBhc3NpZ25lZCBsb2NhbGUuCiAgICAgKiBEZWZhdWx0cyB0byB0aGUgc3lzdGVtJ3MgbG9jYWxlIGlmIG5vIGxvY2FsZSBoYXMgYmVlbiBzcGVjaWZpZWQKICAgICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRGF0ZVRpbWVGb3JtYXQKICAgICAqIEBwYXJhbSBmb3JtYXRPcHRzIHtPYmplY3R9IC0gSW50bC5EYXRlVGltZUZvcm1hdCBjb25zdHJ1Y3RvciBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uIG9wdGlvbnMKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRzIC0gb3B0cyB0byBvdmVycmlkZSB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIG9uIHRoaXMgRGF0ZVRpbWUKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnRvTG9jYWxlU3RyaW5nKCk7IC8vPT4gNC8yMC8yMDE3CiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS5zZXRMb2NhbGUoJ2VuLWdiJykudG9Mb2NhbGVTdHJpbmcoKTsgLy89PiAnMjAvMDQvMjAxNycKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnRvTG9jYWxlU3RyaW5nKERhdGVUaW1lLkRBVEVfRlVMTCk7IC8vPT4gJ0FwcmlsIDIwLCAyMDE3JwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkudG9Mb2NhbGVTdHJpbmcoRGF0ZVRpbWUuREFURV9GVUxMLCB7IGxvY2FsZTogJ2ZyJyB9KTsgLy89PiAnMjggYW/Du3QgMjAyMicKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnRvTG9jYWxlU3RyaW5nKERhdGVUaW1lLlRJTUVfU0lNUExFKTsgLy89PiAnMTE6MzIgQU0nCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b0xvY2FsZVN0cmluZyhEYXRlVGltZS5EQVRFVElNRV9TSE9SVCk7IC8vPT4gJzQvMjAvMjAxNywgMTE6MzIgQU0nCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b0xvY2FsZVN0cmluZyh7IHdlZWtkYXk6ICdsb25nJywgbW9udGg6ICdsb25nJywgZGF5OiAnMi1kaWdpdCcgfSk7IC8vPT4gJ1RodXJzZGF5LCBBcHJpbCAyMCcKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnRvTG9jYWxlU3RyaW5nKHsgd2Vla2RheTogJ3Nob3J0JywgbW9udGg6ICdzaG9ydCcsIGRheTogJzItZGlnaXQnLCBob3VyOiAnMi1kaWdpdCcsIG1pbnV0ZTogJzItZGlnaXQnIH0pOyAvLz0+ICdUaHUsIEFwciAyMCwgMTE6MjcgQU0nCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b0xvY2FsZVN0cmluZyh7IGhvdXI6ICcyLWRpZ2l0JywgbWludXRlOiAnMi1kaWdpdCcsIGhvdXJDeWNsZTogJ2gyMycgfSk7IC8vPT4gJzExOjMyJwogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b0xvY2FsZVN0cmluZyhmb3JtYXRPcHRzID0gREFURV9TSE9SVCwgb3B0cyA9IHt9KSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQKICAgICAgICA/IEZvcm1hdHRlci5jcmVhdGUodGhpcy5sb2MuY2xvbmUob3B0cyksIGZvcm1hdE9wdHMpLmZvcm1hdERhdGVUaW1lKHRoaXMpCiAgICAgICAgOiBJTlZBTElEOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBmb3JtYXQgInBhcnRzIiwgbWVhbmluZyBpbmRpdmlkdWFsIHRva2VucyBhbG9uZyB3aXRoIG1ldGFkYXRhLiBUaGlzIGlzIGFsbG93cyBjYWxsZXJzIHRvIHBvc3QtcHJvY2VzcyBpbmRpdmlkdWFsIHNlY3Rpb25zIG9mIHRoZSBmb3JtYXR0ZWQgb3V0cHV0LgogICAgICogRGVmYXVsdHMgdG8gdGhlIHN5c3RlbSdzIGxvY2FsZSBpZiBubyBsb2NhbGUgaGFzIGJlZW4gc3BlY2lmaWVkCiAgICAgKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0RhdGVUaW1lRm9ybWF0L2Zvcm1hdFRvUGFydHMKICAgICAqIEBwYXJhbSBvcHRzIHtPYmplY3R9IC0gSW50bC5EYXRlVGltZUZvcm1hdCBjb25zdHJ1Y3RvciBvcHRpb25zLCBzYW1lIGFzIGB0b0xvY2FsZVN0cmluZ2AuCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b0xvY2FsZVBhcnRzKCk7IC8vPT4gWwogICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vPT4gICB7IHR5cGU6ICdkYXknLCB2YWx1ZTogJzI1JyB9LAogICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vPT4gICB7IHR5cGU6ICdsaXRlcmFsJywgdmFsdWU6ICcvJyB9LAogICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vPT4gICB7IHR5cGU6ICdtb250aCcsIHZhbHVlOiAnMDUnIH0sCiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy89PiAgIHsgdHlwZTogJ2xpdGVyYWwnLCB2YWx1ZTogJy8nIH0sCiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy89PiAgIHsgdHlwZTogJ3llYXInLCB2YWx1ZTogJzE5ODInIH0KICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLz0+IF0KICAgICAqLwogICAgdG9Mb2NhbGVQYXJ0cyhvcHRzID0ge30pIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZAogICAgICAgID8gRm9ybWF0dGVyLmNyZWF0ZSh0aGlzLmxvYy5jbG9uZShvcHRzKSwgb3B0cykuZm9ybWF0RGF0ZVRpbWVQYXJ0cyh0aGlzKQogICAgICAgIDogW107CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGFuIElTTyA4NjAxLWNvbXBsaWFudCBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhpcyBEYXRlVGltZQogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLnN1cHByZXNzTWlsbGlzZWNvbmRzPWZhbHNlXSAtIGV4Y2x1ZGUgbWlsbGlzZWNvbmRzIGZyb20gdGhlIGZvcm1hdCBpZiB0aGV5J3JlIDAKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuc3VwcHJlc3NTZWNvbmRzPWZhbHNlXSAtIGV4Y2x1ZGUgc2Vjb25kcyBmcm9tIHRoZSBmb3JtYXQgaWYgdGhleSdyZSAwCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmluY2x1ZGVPZmZzZXQ9dHJ1ZV0gLSBpbmNsdWRlIHRoZSBvZmZzZXQsIHN1Y2ggYXMgJ1onIG9yICctMDQ6MDAnCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmV4dGVuZGVkWm9uZT1mYWxzZV0gLSBhZGQgdGhlIHRpbWUgem9uZSBmb3JtYXQgZXh0ZW5zaW9uCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMuZm9ybWF0PSdleHRlbmRlZCddIC0gY2hvb3NlIGJldHdlZW4gdGhlIGJhc2ljIGFuZCBleHRlbmRlZCBmb3JtYXQKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLnV0YygxOTgzLCA1LCAyNSkudG9JU08oKSAvLz0+ICcxOTgyLTA1LTI1VDAwOjAwOjAwLjAwMFonCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b0lTTygpIC8vPT4gJzIwMTctMDQtMjJUMjA6NDc6MDUuMzM1LTA0OjAwJwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkudG9JU08oeyBpbmNsdWRlT2Zmc2V0OiBmYWxzZSB9KSAvLz0+ICcyMDE3LTA0LTIyVDIwOjQ3OjA1LjMzNScKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnRvSVNPKHsgZm9ybWF0OiAnYmFzaWMnIH0pIC8vPT4gJzIwMTcwNDIyVDIwNDcwNS4zMzUtMDQwMCcKICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9JU08oewogICAgICBmb3JtYXQgPSAiZXh0ZW5kZWQiLAogICAgICBzdXBwcmVzc1NlY29uZHMgPSBmYWxzZSwKICAgICAgc3VwcHJlc3NNaWxsaXNlY29uZHMgPSBmYWxzZSwKICAgICAgaW5jbHVkZU9mZnNldCA9IHRydWUsCiAgICAgIGV4dGVuZGVkWm9uZSA9IGZhbHNlLAogICAgfSA9IHt9KSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSB7CiAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgIH0KCiAgICAgIGNvbnN0IGV4dCA9IGZvcm1hdCA9PT0gImV4dGVuZGVkIjsKCiAgICAgIGxldCBjID0gdG9JU09EYXRlKHRoaXMsIGV4dCk7CiAgICAgIGMgKz0gIlQiOwogICAgICBjICs9IHRvSVNPVGltZSh0aGlzLCBleHQsIHN1cHByZXNzU2Vjb25kcywgc3VwcHJlc3NNaWxsaXNlY29uZHMsIGluY2x1ZGVPZmZzZXQsIGV4dGVuZGVkWm9uZSk7CiAgICAgIHJldHVybiBjOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhbiBJU08gODYwMS1jb21wbGlhbnQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgRGF0ZVRpbWUncyBkYXRlIGNvbXBvbmVudAogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdHMuZm9ybWF0PSdleHRlbmRlZCddIC0gY2hvb3NlIGJldHdlZW4gdGhlIGJhc2ljIGFuZCBleHRlbmRlZCBmb3JtYXQKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLnV0YygxOTgyLCA1LCAyNSkudG9JU09EYXRlKCkgLy89PiAnMTk4Mi0wNS0yNScKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLnV0YygxOTgyLCA1LCAyNSkudG9JU09EYXRlKHsgZm9ybWF0OiAnYmFzaWMnIH0pIC8vPT4gJzE5ODIwNTI1JwogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b0lTT0RhdGUoeyBmb3JtYXQgPSAiZXh0ZW5kZWQiIH0gPSB7fSkgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgewogICAgICAgIHJldHVybiBudWxsOwogICAgICB9CgogICAgICByZXR1cm4gdG9JU09EYXRlKHRoaXMsIGZvcm1hdCA9PT0gImV4dGVuZGVkIik7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGFuIElTTyA4NjAxLWNvbXBsaWFudCBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhpcyBEYXRlVGltZSdzIHdlZWsgZGF0ZQogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDE5ODIsIDUsIDI1KS50b0lTT1dlZWtEYXRlKCkgLy89PiAnMTk4Mi1XMjEtMicKICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9JU09XZWVrRGF0ZSgpIHsKICAgICAgcmV0dXJuIHRvVGVjaEZvcm1hdCh0aGlzLCAia2tray0nVydXVy1jIik7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGFuIElTTyA4NjAxLWNvbXBsaWFudCBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhpcyBEYXRlVGltZSdzIHRpbWUgY29tcG9uZW50CiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdGlvbnMKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuc3VwcHJlc3NNaWxsaXNlY29uZHM9ZmFsc2VdIC0gZXhjbHVkZSBtaWxsaXNlY29uZHMgZnJvbSB0aGUgZm9ybWF0IGlmIHRoZXkncmUgMAogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5zdXBwcmVzc1NlY29uZHM9ZmFsc2VdIC0gZXhjbHVkZSBzZWNvbmRzIGZyb20gdGhlIGZvcm1hdCBpZiB0aGV5J3JlIDAKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuaW5jbHVkZU9mZnNldD10cnVlXSAtIGluY2x1ZGUgdGhlIG9mZnNldCwgc3VjaCBhcyAnWicgb3IgJy0wNDowMCcKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuZXh0ZW5kZWRab25lPXRydWVdIC0gYWRkIHRoZSB0aW1lIHpvbmUgZm9ybWF0IGV4dGVuc2lvbgogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5pbmNsdWRlUHJlZml4PWZhbHNlXSAtIGluY2x1ZGUgdGhlIGBUYCBwcmVmaXgKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5mb3JtYXQ9J2V4dGVuZGVkJ10gLSBjaG9vc2UgYmV0d2VlbiB0aGUgYmFzaWMgYW5kIGV4dGVuZGVkIGZvcm1hdAogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKCkuc2V0KHsgaG91cjogNywgbWludXRlOiAzNCB9KS50b0lTT1RpbWUoKSAvLz0+ICcwNzozNDoxOS4zNjFaJwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKCkuc2V0KHsgaG91cjogNywgbWludXRlOiAzNCwgc2Vjb25kczogMCwgbWlsbGlzZWNvbmRzOiAwIH0pLnRvSVNPVGltZSh7IHN1cHByZXNzU2Vjb25kczogdHJ1ZSB9KSAvLz0+ICcwNzozNFonCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS51dGMoKS5zZXQoeyBob3VyOiA3LCBtaW51dGU6IDM0IH0pLnRvSVNPVGltZSh7IGZvcm1hdDogJ2Jhc2ljJyB9KSAvLz0+ICcwNzM0MTkuMzYxWicKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLnV0YygpLnNldCh7IGhvdXI6IDcsIG1pbnV0ZTogMzQgfSkudG9JU09UaW1lKHsgaW5jbHVkZVByZWZpeDogdHJ1ZSB9KSAvLz0+ICdUMDc6MzQ6MTkuMzYxWicKICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9JU09UaW1lKHsKICAgICAgc3VwcHJlc3NNaWxsaXNlY29uZHMgPSBmYWxzZSwKICAgICAgc3VwcHJlc3NTZWNvbmRzID0gZmFsc2UsCiAgICAgIGluY2x1ZGVPZmZzZXQgPSB0cnVlLAogICAgICBpbmNsdWRlUHJlZml4ID0gZmFsc2UsCiAgICAgIGV4dGVuZGVkWm9uZSA9IGZhbHNlLAogICAgICBmb3JtYXQgPSAiZXh0ZW5kZWQiLAogICAgfSA9IHt9KSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSB7CiAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgIH0KCiAgICAgIGxldCBjID0gaW5jbHVkZVByZWZpeCA/ICJUIiA6ICIiOwogICAgICByZXR1cm4gKAogICAgICAgIGMgKwogICAgICAgIHRvSVNPVGltZSgKICAgICAgICAgIHRoaXMsCiAgICAgICAgICBmb3JtYXQgPT09ICJleHRlbmRlZCIsCiAgICAgICAgICBzdXBwcmVzc1NlY29uZHMsCiAgICAgICAgICBzdXBwcmVzc01pbGxpc2Vjb25kcywKICAgICAgICAgIGluY2x1ZGVPZmZzZXQsCiAgICAgICAgICBleHRlbmRlZFpvbmUKICAgICAgICApCiAgICAgICk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGFuIFJGQyAyODIyLWNvbXBhdGlibGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgRGF0ZVRpbWUKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLnV0YygyMDE0LCA3LCAxMykudG9SRkMyODIyKCkgLy89PiAnU3VuLCAxMyBKdWwgMjAxNCAwMDowMDowMCArMDAwMCcKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTQsIDcsIDEzKS50b1JGQzI4MjIoKSAvLz0+ICdTdW4sIDEzIEp1bCAyMDE0IDAwOjAwOjAwIC0wNDAwJwogICAgICogQHJldHVybiB7c3RyaW5nfQogICAgICovCiAgICB0b1JGQzI4MjIoKSB7CiAgICAgIHJldHVybiB0b1RlY2hGb3JtYXQodGhpcywgIkVFRSwgZGQgTExMIHl5eXkgSEg6bW06c3MgWlpaIiwgZmFsc2UpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIERhdGVUaW1lIGFwcHJvcHJpYXRlIGZvciB1c2UgaW4gSFRUUCBoZWFkZXJzLiBUaGUgb3V0cHV0IGlzIGFsd2F5cyBleHByZXNzZWQgaW4gR01ULgogICAgICogU3BlY2lmaWNhbGx5LCB0aGUgc3RyaW5nIGNvbmZvcm1zIHRvIFJGQyAxMTIzLgogICAgICogQHNlZSBodHRwczovL3d3dy53My5vcmcvUHJvdG9jb2xzL3JmYzI2MTYvcmZjMjYxNi1zZWMzLmh0bWwjc2VjMy4zLjEKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLnV0YygyMDE0LCA3LCAxMykudG9IVFRQKCkgLy89PiAnU3VuLCAxMyBKdWwgMjAxNCAwMDowMDowMCBHTVQnCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS51dGMoMjAxNCwgNywgMTMsIDE5KS50b0hUVFAoKSAvLz0+ICdTdW4sIDEzIEp1bCAyMDE0IDE5OjAwOjAwIEdNVCcKICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9IVFRQKCkgewogICAgICByZXR1cm4gdG9UZWNoRm9ybWF0KHRoaXMudG9VVEMoKSwgIkVFRSwgZGQgTExMIHl5eXkgSEg6bW06c3MgJ0dNVCciKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhpcyBEYXRlVGltZSBhcHByb3ByaWF0ZSBmb3IgdXNlIGluIFNRTCBEYXRlCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS51dGMoMjAxNCwgNywgMTMpLnRvU1FMRGF0ZSgpIC8vPT4gJzIwMTQtMDctMTMnCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9CiAgICAgKi8KICAgIHRvU1FMRGF0ZSgpIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHsKICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgfQogICAgICByZXR1cm4gdG9JU09EYXRlKHRoaXMsIHRydWUpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIERhdGVUaW1lIGFwcHJvcHJpYXRlIGZvciB1c2UgaW4gU1FMIFRpbWUKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRzIC0gb3B0aW9ucwogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5pbmNsdWRlWm9uZT1mYWxzZV0gLSBpbmNsdWRlIHRoZSB6b25lLCBzdWNoIGFzICdBbWVyaWNhL05ld19Zb3JrJy4gT3ZlcnJpZGVzIGluY2x1ZGVPZmZzZXQuCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmluY2x1ZGVPZmZzZXQ9dHJ1ZV0gLSBpbmNsdWRlIHRoZSBvZmZzZXQsIHN1Y2ggYXMgJ1onIG9yICctMDQ6MDAnCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmluY2x1ZGVPZmZzZXRTcGFjZT10cnVlXSAtIGluY2x1ZGUgdGhlIHNwYWNlIGJldHdlZW4gdGhlIHRpbWUgYW5kIHRoZSBvZmZzZXQsIHN1Y2ggYXMgJzA1OjE1OjE2LjM0NSAtMDQ6MDAnCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS51dGMoKS50b1NRTCgpIC8vPT4gJzA1OjE1OjE2LjM0NScKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnRvU1FMKCkgLy89PiAnMDU6MTU6MTYuMzQ1IC0wNDowMCcKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnRvU1FMKHsgaW5jbHVkZU9mZnNldDogZmFsc2UgfSkgLy89PiAnMDU6MTU6MTYuMzQ1JwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkudG9TUUwoeyBpbmNsdWRlWm9uZTogZmFsc2UgfSkgLy89PiAnMDU6MTU6MTYuMzQ1IEFtZXJpY2EvTmV3X1lvcmsnCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9CiAgICAgKi8KICAgIHRvU1FMVGltZSh7IGluY2x1ZGVPZmZzZXQgPSB0cnVlLCBpbmNsdWRlWm9uZSA9IGZhbHNlLCBpbmNsdWRlT2Zmc2V0U3BhY2UgPSB0cnVlIH0gPSB7fSkgewogICAgICBsZXQgZm10ID0gIkhIOm1tOnNzLlNTUyI7CgogICAgICBpZiAoaW5jbHVkZVpvbmUgfHwgaW5jbHVkZU9mZnNldCkgewogICAgICAgIGlmIChpbmNsdWRlT2Zmc2V0U3BhY2UpIHsKICAgICAgICAgIGZtdCArPSAiICI7CiAgICAgICAgfQogICAgICAgIGlmIChpbmNsdWRlWm9uZSkgewogICAgICAgICAgZm10ICs9ICJ6IjsKICAgICAgICB9IGVsc2UgaWYgKGluY2x1ZGVPZmZzZXQpIHsKICAgICAgICAgIGZtdCArPSAiWloiOwogICAgICAgIH0KICAgICAgfQoKICAgICAgcmV0dXJuIHRvVGVjaEZvcm1hdCh0aGlzLCBmbXQsIHRydWUpOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIERhdGVUaW1lIGFwcHJvcHJpYXRlIGZvciB1c2UgaW4gU1FMIERhdGVUaW1lCiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIG9wdGlvbnMKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuaW5jbHVkZVpvbmU9ZmFsc2VdIC0gaW5jbHVkZSB0aGUgem9uZSwgc3VjaCBhcyAnQW1lcmljYS9OZXdfWW9yaycuIE92ZXJyaWRlcyBpbmNsdWRlT2Zmc2V0LgogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5pbmNsdWRlT2Zmc2V0PXRydWVdIC0gaW5jbHVkZSB0aGUgb2Zmc2V0LCBzdWNoIGFzICdaJyBvciAnLTA0OjAwJwogICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0cy5pbmNsdWRlT2Zmc2V0U3BhY2U9dHJ1ZV0gLSBpbmNsdWRlIHRoZSBzcGFjZSBiZXR3ZWVuIHRoZSB0aW1lIGFuZCB0aGUgb2Zmc2V0LCBzdWNoIGFzICcwNToxNToxNi4zNDUgLTA0OjAwJwogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUudXRjKDIwMTQsIDcsIDEzKS50b1NRTCgpIC8vPT4gJzIwMTQtMDctMTMgMDA6MDA6MDAuMDAwIFonCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE0LCA3LCAxMykudG9TUUwoKSAvLz0+ICcyMDE0LTA3LTEzIDAwOjAwOjAwLjAwMCAtMDQ6MDAnCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5sb2NhbCgyMDE0LCA3LCAxMykudG9TUUwoeyBpbmNsdWRlT2Zmc2V0OiBmYWxzZSB9KSAvLz0+ICcyMDE0LTA3LTEzIDAwOjAwOjAwLjAwMCcKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLmxvY2FsKDIwMTQsIDcsIDEzKS50b1NRTCh7IGluY2x1ZGVab25lOiB0cnVlIH0pIC8vPT4gJzIwMTQtMDctMTMgMDA6MDA6MDAuMDAwIEFtZXJpY2EvTmV3X1lvcmsnCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9CiAgICAgKi8KICAgIHRvU1FMKG9wdHMgPSB7fSkgewogICAgICBpZiAoIXRoaXMuaXNWYWxpZCkgewogICAgICAgIHJldHVybiBudWxsOwogICAgICB9CgogICAgICByZXR1cm4gYCR7dGhpcy50b1NRTERhdGUoKX0gJHt0aGlzLnRvU1FMVGltZShvcHRzKX1gOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIERhdGVUaW1lIGFwcHJvcHJpYXRlIGZvciBkZWJ1Z2dpbmcKICAgICAqIEByZXR1cm4ge3N0cmluZ30KICAgICAqLwogICAgdG9TdHJpbmcoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyB0aGlzLnRvSVNPKCkgOiBJTlZBTElEOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyB0aGUgZXBvY2ggbWlsbGlzZWNvbmRzIG9mIHRoaXMgRGF0ZVRpbWUuIEFsaWFzIG9mIHtAbGluayBEYXRlVGltZSN0b01pbGxpc30KICAgICAqIEByZXR1cm4ge251bWJlcn0KICAgICAqLwogICAgdmFsdWVPZigpIHsKICAgICAgcmV0dXJuIHRoaXMudG9NaWxsaXMoKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIGVwb2NoIG1pbGxpc2Vjb25kcyBvZiB0aGlzIERhdGVUaW1lLgogICAgICogQHJldHVybiB7bnVtYmVyfQogICAgICovCiAgICB0b01pbGxpcygpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IHRoaXMudHMgOiBOYU47CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBlcG9jaCBzZWNvbmRzIG9mIHRoaXMgRGF0ZVRpbWUuCiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9CiAgICAgKi8KICAgIHRvU2Vjb25kcygpIHsKICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCA/IHRoaXMudHMgLyAxMDAwIDogTmFOOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyB0aGUgZXBvY2ggc2Vjb25kcyAoYXMgYSB3aG9sZSBudW1iZXIpIG9mIHRoaXMgRGF0ZVRpbWUuCiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9CiAgICAgKi8KICAgIHRvVW5peEludGVnZXIoKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyBNYXRoLmZsb29yKHRoaXMudHMgLyAxMDAwKSA6IE5hTjsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYW4gSVNPIDg2MDEgcmVwcmVzZW50YXRpb24gb2YgdGhpcyBEYXRlVGltZSBhcHByb3ByaWF0ZSBmb3IgdXNlIGluIEpTT04uCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9CiAgICAgKi8KICAgIHRvSlNPTigpIHsKICAgICAgcmV0dXJuIHRoaXMudG9JU08oKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYSBCU09OIHNlcmlhbGl6YWJsZSBlcXVpdmFsZW50IHRvIHRoaXMgRGF0ZVRpbWUuCiAgICAgKiBAcmV0dXJuIHtEYXRlfQogICAgICovCiAgICB0b0JTT04oKSB7CiAgICAgIHJldHVybiB0aGlzLnRvSlNEYXRlKCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgSmF2YVNjcmlwdCBvYmplY3Qgd2l0aCB0aGlzIERhdGVUaW1lJ3MgeWVhciwgbW9udGgsIGRheSwgYW5kIHNvIG9uLgogICAgICogQHBhcmFtIG9wdHMgLSBvcHRpb25zIGZvciBnZW5lcmF0aW5nIHRoZSBvYmplY3QKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdHMuaW5jbHVkZUNvbmZpZz1mYWxzZV0gLSBpbmNsdWRlIGNvbmZpZ3VyYXRpb24gYXR0cmlidXRlcyBpbiB0aGUgb3V0cHV0CiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS50b09iamVjdCgpIC8vPT4geyB5ZWFyOiAyMDE3LCBtb250aDogNCwgZGF5OiAyMiwgaG91cjogMjAsIG1pbnV0ZTogNDksIHNlY29uZDogNDIsIG1pbGxpc2Vjb25kOiAyNjggfQogICAgICogQHJldHVybiB7T2JqZWN0fQogICAgICovCiAgICB0b09iamVjdChvcHRzID0ge30pIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiB7fTsKCiAgICAgIGNvbnN0IGJhc2UgPSB7IC4uLnRoaXMuYyB9OwoKICAgICAgaWYgKG9wdHMuaW5jbHVkZUNvbmZpZykgewogICAgICAgIGJhc2Uub3V0cHV0Q2FsZW5kYXIgPSB0aGlzLm91dHB1dENhbGVuZGFyOwogICAgICAgIGJhc2UubnVtYmVyaW5nU3lzdGVtID0gdGhpcy5sb2MubnVtYmVyaW5nU3lzdGVtOwogICAgICAgIGJhc2UubG9jYWxlID0gdGhpcy5sb2MubG9jYWxlOwogICAgICB9CiAgICAgIHJldHVybiBiYXNlOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIEphdmFTY3JpcHQgRGF0ZSBlcXVpdmFsZW50IHRvIHRoaXMgRGF0ZVRpbWUuCiAgICAgKiBAcmV0dXJuIHtEYXRlfQogICAgICovCiAgICB0b0pTRGF0ZSgpIHsKICAgICAgcmV0dXJuIG5ldyBEYXRlKHRoaXMuaXNWYWxpZCA/IHRoaXMudHMgOiBOYU4pOwogICAgfQoKICAgIC8vIENPTVBBUkUKCiAgICAvKioKICAgICAqIFJldHVybiB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHR3byBEYXRlVGltZXMgYXMgYSBEdXJhdGlvbi4KICAgICAqIEBwYXJhbSB7RGF0ZVRpbWV9IG90aGVyRGF0ZVRpbWUgLSB0aGUgRGF0ZVRpbWUgdG8gY29tcGFyZSB0aGlzIG9uZSB0bwogICAgICogQHBhcmFtIHtzdHJpbmd8c3RyaW5nW119IFt1bml0PVsnbWlsbGlzZWNvbmRzJ11dIC0gdGhlIHVuaXQgb3IgYXJyYXkgb2YgdW5pdHMgKHN1Y2ggYXMgJ2hvdXJzJyBvciAnZGF5cycpIHRvIGluY2x1ZGUgaW4gdGhlIGR1cmF0aW9uLgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zIHRoYXQgYWZmZWN0IHRoZSBjcmVhdGlvbiBvZiB0aGUgRHVyYXRpb24KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5jb252ZXJzaW9uQWNjdXJhY3k9J2Nhc3VhbCddIC0gdGhlIGNvbnZlcnNpb24gc3lzdGVtIHRvIHVzZQogICAgICogQGV4YW1wbGUKICAgICAqIHZhciBpMSA9IERhdGVUaW1lLmZyb21JU08oJzE5ODItMDUtMjVUMDk6NDUnKSwKICAgICAqICAgICBpMiA9IERhdGVUaW1lLmZyb21JU08oJzE5ODMtMTAtMTRUMTA6MzAnKTsKICAgICAqIGkyLmRpZmYoaTEpLnRvT2JqZWN0KCkgLy89PiB7IG1pbGxpc2Vjb25kczogNDM4MDc1MDAwMDAgfQogICAgICogaTIuZGlmZihpMSwgJ2hvdXJzJykudG9PYmplY3QoKSAvLz0+IHsgaG91cnM6IDEyMTY4Ljc1IH0KICAgICAqIGkyLmRpZmYoaTEsIFsnbW9udGhzJywgJ2RheXMnXSkudG9PYmplY3QoKSAvLz0+IHsgbW9udGhzOiAxNiwgZGF5czogMTkuMDMxMjUgfQogICAgICogaTIuZGlmZihpMSwgWydtb250aHMnLCAnZGF5cycsICdob3VycyddKS50b09iamVjdCgpIC8vPT4geyBtb250aHM6IDE2LCBkYXlzOiAxOSwgaG91cnM6IDAuNzUgfQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIGRpZmYob3RoZXJEYXRlVGltZSwgdW5pdCA9ICJtaWxsaXNlY29uZHMiLCBvcHRzID0ge30pIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQgfHwgIW90aGVyRGF0ZVRpbWUuaXNWYWxpZCkgewogICAgICAgIHJldHVybiBEdXJhdGlvbi5pbnZhbGlkKCJjcmVhdGVkIGJ5IGRpZmZpbmcgYW4gaW52YWxpZCBEYXRlVGltZSIpOwogICAgICB9CgogICAgICBjb25zdCBkdXJPcHRzID0geyBsb2NhbGU6IHRoaXMubG9jYWxlLCBudW1iZXJpbmdTeXN0ZW06IHRoaXMubnVtYmVyaW5nU3lzdGVtLCAuLi5vcHRzIH07CgogICAgICBjb25zdCB1bml0cyA9IG1heWJlQXJyYXkodW5pdCkubWFwKER1cmF0aW9uLm5vcm1hbGl6ZVVuaXQpLAogICAgICAgIG90aGVySXNMYXRlciA9IG90aGVyRGF0ZVRpbWUudmFsdWVPZigpID4gdGhpcy52YWx1ZU9mKCksCiAgICAgICAgZWFybGllciA9IG90aGVySXNMYXRlciA/IHRoaXMgOiBvdGhlckRhdGVUaW1lLAogICAgICAgIGxhdGVyID0gb3RoZXJJc0xhdGVyID8gb3RoZXJEYXRlVGltZSA6IHRoaXMsCiAgICAgICAgZGlmZmVkID0gZGlmZihlYXJsaWVyLCBsYXRlciwgdW5pdHMsIGR1ck9wdHMpOwoKICAgICAgcmV0dXJuIG90aGVySXNMYXRlciA/IGRpZmZlZC5uZWdhdGUoKSA6IGRpZmZlZDsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoaXMgRGF0ZVRpbWUgYW5kIHJpZ2h0IG5vdy4KICAgICAqIFNlZSB7QGxpbmsgRGF0ZVRpbWUjZGlmZn0KICAgICAqIEBwYXJhbSB7c3RyaW5nfHN0cmluZ1tdfSBbdW5pdD1bJ21pbGxpc2Vjb25kcyddXSAtIHRoZSB1bml0IG9yIHVuaXRzIHVuaXRzIChzdWNoIGFzICdob3Vycycgb3IgJ2RheXMnKSB0byBpbmNsdWRlIGluIHRoZSBkdXJhdGlvbgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHMgLSBvcHRpb25zIHRoYXQgYWZmZWN0IHRoZSBjcmVhdGlvbiBvZiB0aGUgRHVyYXRpb24KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0cy5jb252ZXJzaW9uQWNjdXJhY3k9J2Nhc3VhbCddIC0gdGhlIGNvbnZlcnNpb24gc3lzdGVtIHRvIHVzZQogICAgICogQHJldHVybiB7RHVyYXRpb259CiAgICAgKi8KICAgIGRpZmZOb3codW5pdCA9ICJtaWxsaXNlY29uZHMiLCBvcHRzID0ge30pIHsKICAgICAgcmV0dXJuIHRoaXMuZGlmZihEYXRlVGltZS5ub3coKSwgdW5pdCwgb3B0cyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gYW4gSW50ZXJ2YWwgc3Bhbm5pbmcgYmV0d2VlbiB0aGlzIERhdGVUaW1lIGFuZCBhbm90aGVyIERhdGVUaW1lCiAgICAgKiBAcGFyYW0ge0RhdGVUaW1lfSBvdGhlckRhdGVUaW1lIC0gdGhlIG90aGVyIGVuZCBwb2ludCBvZiB0aGUgSW50ZXJ2YWwKICAgICAqIEByZXR1cm4ge0ludGVydmFsfQogICAgICovCiAgICB1bnRpbChvdGhlckRhdGVUaW1lKSB7CiAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQgPyBJbnRlcnZhbC5mcm9tRGF0ZVRpbWVzKHRoaXMsIG90aGVyRGF0ZVRpbWUpIDogdGhpczsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiB3aGV0aGVyIHRoaXMgRGF0ZVRpbWUgaXMgaW4gdGhlIHNhbWUgdW5pdCBvZiB0aW1lIGFzIGFub3RoZXIgRGF0ZVRpbWUuCiAgICAgKiBIaWdoZXItb3JkZXIgdW5pdHMgbXVzdCBhbHNvIGJlIGlkZW50aWNhbCBmb3IgdGhpcyBmdW5jdGlvbiB0byByZXR1cm4gYHRydWVgLgogICAgICogTm90ZSB0aGF0IHRpbWUgem9uZXMgYXJlICoqaWdub3JlZCoqIGluIHRoaXMgY29tcGFyaXNvbiwgd2hpY2ggY29tcGFyZXMgdGhlICoqbG9jYWwqKiBjYWxlbmRhciB0aW1lLiBVc2Uge0BsaW5rIERhdGVUaW1lI3NldFpvbmV9IHRvIGNvbnZlcnQgb25lIG9mIHRoZSBkYXRlcyBpZiBuZWVkZWQuCiAgICAgKiBAcGFyYW0ge0RhdGVUaW1lfSBvdGhlckRhdGVUaW1lIC0gdGhlIG90aGVyIERhdGVUaW1lCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdW5pdCAtIHRoZSB1bml0IG9mIHRpbWUgdG8gY2hlY2sgc2FtZW5lc3Mgb24KICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLmhhc1NhbWUob3RoZXJEVCwgJ2RheScpOyAvL34+IHRydWUgaWYgb3RoZXJEVCBpcyBpbiB0aGUgc2FtZSBjdXJyZW50IGNhbGVuZGFyIGRheQogICAgICogQHJldHVybiB7Ym9vbGVhbn0KICAgICAqLwogICAgaGFzU2FtZShvdGhlckRhdGVUaW1lLCB1bml0KSB7CiAgICAgIGlmICghdGhpcy5pc1ZhbGlkKSByZXR1cm4gZmFsc2U7CgogICAgICBjb25zdCBpbnB1dE1zID0gb3RoZXJEYXRlVGltZS52YWx1ZU9mKCk7CiAgICAgIGNvbnN0IGFkanVzdGVkVG9ab25lID0gdGhpcy5zZXRab25lKG90aGVyRGF0ZVRpbWUuem9uZSwgeyBrZWVwTG9jYWxUaW1lOiB0cnVlIH0pOwogICAgICByZXR1cm4gYWRqdXN0ZWRUb1pvbmUuc3RhcnRPZih1bml0KSA8PSBpbnB1dE1zICYmIGlucHV0TXMgPD0gYWRqdXN0ZWRUb1pvbmUuZW5kT2YodW5pdCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBFcXVhbGl0eSBjaGVjawogICAgICogVHdvIERhdGVUaW1lcyBhcmUgZXF1YWwgaWYgYW5kIG9ubHkgaWYgdGhleSByZXByZXNlbnQgdGhlIHNhbWUgbWlsbGlzZWNvbmQsIGhhdmUgdGhlIHNhbWUgem9uZSBhbmQgbG9jYXRpb24sIGFuZCBhcmUgYm90aCB2YWxpZC4KICAgICAqIFRvIGNvbXBhcmUganVzdCB0aGUgbWlsbGlzZWNvbmQgdmFsdWVzLCB1c2UgYCtkdDEgPT09ICtkdDJgLgogICAgICogQHBhcmFtIHtEYXRlVGltZX0gb3RoZXIgLSB0aGUgb3RoZXIgRGF0ZVRpbWUKICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIGVxdWFscyhvdGhlcikgewogICAgICByZXR1cm4gKAogICAgICAgIHRoaXMuaXNWYWxpZCAmJgogICAgICAgIG90aGVyLmlzVmFsaWQgJiYKICAgICAgICB0aGlzLnZhbHVlT2YoKSA9PT0gb3RoZXIudmFsdWVPZigpICYmCiAgICAgICAgdGhpcy56b25lLmVxdWFscyhvdGhlci56b25lKSAmJgogICAgICAgIHRoaXMubG9jLmVxdWFscyhvdGhlci5sb2MpCiAgICAgICk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgdGhpcyB0aW1lIHJlbGF0aXZlIHRvIG5vdywgc3VjaCBhcyAiaW4gdHdvIGRheXMiLiBDYW4gb25seSBpbnRlcm5hdGlvbmFsaXplIGlmIHlvdXIKICAgICAqIHBsYXRmb3JtIHN1cHBvcnRzIEludGwuUmVsYXRpdmVUaW1lRm9ybWF0LiBSb3VuZHMgZG93biBieSBkZWZhdWx0LgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBvcHRpb25zIHRoYXQgYWZmZWN0IHRoZSBvdXRwdXQKICAgICAqIEBwYXJhbSB7RGF0ZVRpbWV9IFtvcHRpb25zLmJhc2U9RGF0ZVRpbWUubm93KCldIC0gdGhlIERhdGVUaW1lIHRvIHVzZSBhcyB0aGUgYmFzaXMgdG8gd2hpY2ggdGhpcyB0aW1lIGlzIGNvbXBhcmVkLiBEZWZhdWx0cyB0byBub3cuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gW29wdGlvbnMuc3R5bGU9ImxvbmciXSAtIHRoZSBzdHlsZSBvZiB1bml0cywgbXVzdCBiZSAibG9uZyIsICJzaG9ydCIsIG9yICJuYXJyb3ciCiAgICAgKiBAcGFyYW0ge3N0cmluZ3xzdHJpbmdbXX0gb3B0aW9ucy51bml0IC0gdXNlIGEgc3BlY2lmaWMgdW5pdCBvciBhcnJheSBvZiB1bml0czsgaWYgb21pdHRlZCwgb3IgYW4gYXJyYXksIHRoZSBtZXRob2Qgd2lsbCBwaWNrIHRoZSBiZXN0IHVuaXQuIFVzZSBhbiBhcnJheSBvciBvbmUgb2YgInllYXJzIiwgInF1YXJ0ZXJzIiwgIm1vbnRocyIsICJ3ZWVrcyIsICJkYXlzIiwgImhvdXJzIiwgIm1pbnV0ZXMiLCBvciAic2Vjb25kcyIKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMucm91bmQ9dHJ1ZV0gLSB3aGV0aGVyIHRvIHJvdW5kIHRoZSBudW1iZXJzIGluIHRoZSBvdXRwdXQuCiAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMucGFkZGluZz0wXSAtIHBhZGRpbmcgaW4gbWlsbGlzZWNvbmRzLiBUaGlzIGFsbG93cyB5b3UgdG8gcm91bmQgdXAgdGhlIHJlc3VsdCBpZiBpdCBmaXRzIGluc2lkZSB0aGUgdGhyZXNob2xkLiBEb24ndCB1c2UgaW4gY29tYmluYXRpb24gd2l0aCB7cm91bmQ6IGZhbHNlfSBiZWNhdXNlIHRoZSBkZWNpbWFsIG91dHB1dCB3aWxsIGluY2x1ZGUgdGhlIHBhZGRpbmcuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5sb2NhbGUgLSBvdmVycmlkZSB0aGUgbG9jYWxlIG9mIHRoaXMgRGF0ZVRpbWUKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRpb25zLm51bWJlcmluZ1N5c3RlbSAtIG92ZXJyaWRlIHRoZSBudW1iZXJpbmdTeXN0ZW0gb2YgdGhpcyBEYXRlVGltZS4gVGhlIEludGwgc3lzdGVtIG1heSBjaG9vc2Ugbm90IHRvIGhvbm9yIHRoaXMKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnBsdXMoeyBkYXlzOiAxIH0pLnRvUmVsYXRpdmUoKSAvLz0+ICJpbiAxIGRheSIKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnNldExvY2FsZSgiZXMiKS50b1JlbGF0aXZlKHsgZGF5czogMSB9KSAvLz0+ICJkZW50cm8gZGUgMSBkw61hIgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkucGx1cyh7IGRheXM6IDEgfSkudG9SZWxhdGl2ZSh7IGxvY2FsZTogImZyIiB9KSAvLz0+ICJkYW5zIDIzIGhldXJlcyIKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLm1pbnVzKHsgZGF5czogMiB9KS50b1JlbGF0aXZlKCkgLy89PiAiMiBkYXlzIGFnbyIKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLm1pbnVzKHsgZGF5czogMiB9KS50b1JlbGF0aXZlKHsgdW5pdDogImhvdXJzIiB9KSAvLz0+ICI0OCBob3VycyBhZ28iCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS5taW51cyh7IGhvdXJzOiAzNiB9KS50b1JlbGF0aXZlKHsgcm91bmQ6IGZhbHNlIH0pIC8vPT4gIjEuNSBkYXlzIGFnbyIKICAgICAqLwogICAgdG9SZWxhdGl2ZShvcHRpb25zID0ge30pIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiBudWxsOwogICAgICBjb25zdCBiYXNlID0gb3B0aW9ucy5iYXNlIHx8IERhdGVUaW1lLmZyb21PYmplY3Qoe30sIHsgem9uZTogdGhpcy56b25lIH0pLAogICAgICAgIHBhZGRpbmcgPSBvcHRpb25zLnBhZGRpbmcgPyAodGhpcyA8IGJhc2UgPyAtb3B0aW9ucy5wYWRkaW5nIDogb3B0aW9ucy5wYWRkaW5nKSA6IDA7CiAgICAgIGxldCB1bml0cyA9IFsieWVhcnMiLCAibW9udGhzIiwgImRheXMiLCAiaG91cnMiLCAibWludXRlcyIsICJzZWNvbmRzIl07CiAgICAgIGxldCB1bml0ID0gb3B0aW9ucy51bml0OwogICAgICBpZiAoQXJyYXkuaXNBcnJheShvcHRpb25zLnVuaXQpKSB7CiAgICAgICAgdW5pdHMgPSBvcHRpb25zLnVuaXQ7CiAgICAgICAgdW5pdCA9IHVuZGVmaW5lZDsKICAgICAgfQogICAgICByZXR1cm4gZGlmZlJlbGF0aXZlKGJhc2UsIHRoaXMucGx1cyhwYWRkaW5nKSwgewogICAgICAgIC4uLm9wdGlvbnMsCiAgICAgICAgbnVtZXJpYzogImFsd2F5cyIsCiAgICAgICAgdW5pdHMsCiAgICAgICAgdW5pdCwKICAgICAgfSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgZGF0ZSByZWxhdGl2ZSB0byB0b2RheSwgc3VjaCBhcyAieWVzdGVyZGF5IiBvciAibmV4dCBtb250aCIuCiAgICAgKiBPbmx5IGludGVybmF0aW9uYWxpemVzIG9uIHBsYXRmb3JtcyB0aGF0IHN1cHBvcnRzIEludGwuUmVsYXRpdmVUaW1lRm9ybWF0LgogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBvcHRpb25zIHRoYXQgYWZmZWN0IHRoZSBvdXRwdXQKICAgICAqIEBwYXJhbSB7RGF0ZVRpbWV9IFtvcHRpb25zLmJhc2U9RGF0ZVRpbWUubm93KCldIC0gdGhlIERhdGVUaW1lIHRvIHVzZSBhcyB0aGUgYmFzaXMgdG8gd2hpY2ggdGhpcyB0aW1lIGlzIGNvbXBhcmVkLiBEZWZhdWx0cyB0byBub3cuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5sb2NhbGUgLSBvdmVycmlkZSB0aGUgbG9jYWxlIG9mIHRoaXMgRGF0ZVRpbWUKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRpb25zLnVuaXQgLSB1c2UgYSBzcGVjaWZpYyB1bml0OyBpZiBvbWl0dGVkLCB0aGUgbWV0aG9kIHdpbGwgcGljayB0aGUgdW5pdC4gVXNlIG9uZSBvZiAieWVhcnMiLCAicXVhcnRlcnMiLCAibW9udGhzIiwgIndlZWtzIiwgb3IgImRheXMiCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5udW1iZXJpbmdTeXN0ZW0gLSBvdmVycmlkZSB0aGUgbnVtYmVyaW5nU3lzdGVtIG9mIHRoaXMgRGF0ZVRpbWUuIFRoZSBJbnRsIHN5c3RlbSBtYXkgY2hvb3NlIG5vdCB0byBob25vciB0aGlzCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS5wbHVzKHsgZGF5czogMSB9KS50b1JlbGF0aXZlQ2FsZW5kYXIoKSAvLz0+ICJ0b21vcnJvdyIKICAgICAqIEBleGFtcGxlIERhdGVUaW1lLm5vdygpLnNldExvY2FsZSgiZXMiKS5wbHVzKHsgZGF5czogMSB9KS50b1JlbGF0aXZlKCkgLy89PiAiIm1hw7FhbmEiCiAgICAgKiBAZXhhbXBsZSBEYXRlVGltZS5ub3coKS5wbHVzKHsgZGF5czogMSB9KS50b1JlbGF0aXZlQ2FsZW5kYXIoeyBsb2NhbGU6ICJmciIgfSkgLy89PiAiZGVtYWluIgogICAgICogQGV4YW1wbGUgRGF0ZVRpbWUubm93KCkubWludXMoeyBkYXlzOiAyIH0pLnRvUmVsYXRpdmVDYWxlbmRhcigpIC8vPT4gIjIgZGF5cyBhZ28iCiAgICAgKi8KICAgIHRvUmVsYXRpdmVDYWxlbmRhcihvcHRpb25zID0ge30pIHsKICAgICAgaWYgKCF0aGlzLmlzVmFsaWQpIHJldHVybiBudWxsOwoKICAgICAgcmV0dXJuIGRpZmZSZWxhdGl2ZShvcHRpb25zLmJhc2UgfHwgRGF0ZVRpbWUuZnJvbU9iamVjdCh7fSwgeyB6b25lOiB0aGlzLnpvbmUgfSksIHRoaXMsIHsKICAgICAgICAuLi5vcHRpb25zLAogICAgICAgIG51bWVyaWM6ICJhdXRvIiwKICAgICAgICB1bml0czogWyJ5ZWFycyIsICJtb250aHMiLCAiZGF5cyJdLAogICAgICAgIGNhbGVuZGFyeTogdHJ1ZSwKICAgICAgfSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm4gdGhlIG1pbiBvZiBzZXZlcmFsIGRhdGUgdGltZXMKICAgICAqIEBwYXJhbSB7Li4uRGF0ZVRpbWV9IGRhdGVUaW1lcyAtIHRoZSBEYXRlVGltZXMgZnJvbSB3aGljaCB0byBjaG9vc2UgdGhlIG1pbmltdW0KICAgICAqIEByZXR1cm4ge0RhdGVUaW1lfSB0aGUgbWluIERhdGVUaW1lLCBvciB1bmRlZmluZWQgaWYgY2FsbGVkIHdpdGggbm8gYXJndW1lbnQKICAgICAqLwogICAgc3RhdGljIG1pbiguLi5kYXRlVGltZXMpIHsKICAgICAgaWYgKCFkYXRlVGltZXMuZXZlcnkoRGF0ZVRpbWUuaXNEYXRlVGltZSkpIHsKICAgICAgICB0aHJvdyBuZXcgSW52YWxpZEFyZ3VtZW50RXJyb3IoIm1pbiByZXF1aXJlcyBhbGwgYXJndW1lbnRzIGJlIERhdGVUaW1lcyIpOwogICAgICB9CiAgICAgIHJldHVybiBiZXN0QnkoZGF0ZVRpbWVzLCAoaSkgPT4gaS52YWx1ZU9mKCksIE1hdGgubWluKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybiB0aGUgbWF4IG9mIHNldmVyYWwgZGF0ZSB0aW1lcwogICAgICogQHBhcmFtIHsuLi5EYXRlVGltZX0gZGF0ZVRpbWVzIC0gdGhlIERhdGVUaW1lcyBmcm9tIHdoaWNoIHRvIGNob29zZSB0aGUgbWF4aW11bQogICAgICogQHJldHVybiB7RGF0ZVRpbWV9IHRoZSBtYXggRGF0ZVRpbWUsIG9yIHVuZGVmaW5lZCBpZiBjYWxsZWQgd2l0aCBubyBhcmd1bWVudAogICAgICovCiAgICBzdGF0aWMgbWF4KC4uLmRhdGVUaW1lcykgewogICAgICBpZiAoIWRhdGVUaW1lcy5ldmVyeShEYXRlVGltZS5pc0RhdGVUaW1lKSkgewogICAgICAgIHRocm93IG5ldyBJbnZhbGlkQXJndW1lbnRFcnJvcigibWF4IHJlcXVpcmVzIGFsbCBhcmd1bWVudHMgYmUgRGF0ZVRpbWVzIik7CiAgICAgIH0KICAgICAgcmV0dXJuIGJlc3RCeShkYXRlVGltZXMsIChpKSA9PiBpLnZhbHVlT2YoKSwgTWF0aC5tYXgpOwogICAgfQoKICAgIC8vIE1JU0MKCiAgICAvKioKICAgICAqIEV4cGxhaW4gaG93IGEgc3RyaW5nIHdvdWxkIGJlIHBhcnNlZCBieSBmcm9tRm9ybWF0KCkKICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gdGhlIHN0cmluZyB0byBwYXJzZQogICAgICogQHBhcmFtIHtzdHJpbmd9IGZtdCAtIHRoZSBmb3JtYXQgdGhlIHN0cmluZyBpcyBleHBlY3RlZCB0byBiZSBpbiAoc2VlIGRlc2NyaXB0aW9uKQogICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBvcHRpb25zIHRha2VuIGJ5IGZyb21Gb3JtYXQoKQogICAgICogQHJldHVybiB7T2JqZWN0fQogICAgICovCiAgICBzdGF0aWMgZnJvbUZvcm1hdEV4cGxhaW4odGV4dCwgZm10LCBvcHRpb25zID0ge30pIHsKICAgICAgY29uc3QgeyBsb2NhbGUgPSBudWxsLCBudW1iZXJpbmdTeXN0ZW0gPSBudWxsIH0gPSBvcHRpb25zLAogICAgICAgIGxvY2FsZVRvVXNlID0gTG9jYWxlLmZyb21PcHRzKHsKICAgICAgICAgIGxvY2FsZSwKICAgICAgICAgIG51bWJlcmluZ1N5c3RlbSwKICAgICAgICAgIGRlZmF1bHRUb0VOOiB0cnVlLAogICAgICAgIH0pOwogICAgICByZXR1cm4gZXhwbGFpbkZyb21Ub2tlbnMobG9jYWxlVG9Vc2UsIHRleHQsIGZtdCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGVwcmVjYXRlZCB1c2UgZnJvbUZvcm1hdEV4cGxhaW4gaW5zdGVhZAogICAgICovCiAgICBzdGF0aWMgZnJvbVN0cmluZ0V4cGxhaW4odGV4dCwgZm10LCBvcHRpb25zID0ge30pIHsKICAgICAgcmV0dXJuIERhdGVUaW1lLmZyb21Gb3JtYXRFeHBsYWluKHRleHQsIGZtdCwgb3B0aW9ucyk7CiAgICB9CgogICAgLy8gRk9STUFUIFBSRVNFVFMKCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgMTAvMTQvMTk4MwogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBEQVRFX1NIT1JUKCkgewogICAgICByZXR1cm4gREFURV9TSE9SVDsKICAgIH0KCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgJ09jdCAxNCwgMTk4MycKICAgICAqIEB0eXBlIHtPYmplY3R9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgREFURV9NRUQoKSB7CiAgICAgIHJldHVybiBEQVRFX01FRDsKICAgIH0KCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgJ0ZyaSwgT2N0IDE0LCAxOTgzJwogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBEQVRFX01FRF9XSVRIX1dFRUtEQVkoKSB7CiAgICAgIHJldHVybiBEQVRFX01FRF9XSVRIX1dFRUtEQVk7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICdPY3RvYmVyIDE0LCAxOTgzJwogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBEQVRFX0ZVTEwoKSB7CiAgICAgIHJldHVybiBEQVRFX0ZVTEw7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICdUdWVzZGF5LCBPY3RvYmVyIDE0LCAxOTgzJwogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBEQVRFX0hVR0UoKSB7CiAgICAgIHJldHVybiBEQVRFX0hVR0U7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICcwOTozMCBBTScuIE9ubHkgMTItaG91ciBpZiB0aGUgbG9jYWxlIGlzLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBUSU1FX1NJTVBMRSgpIHsKICAgICAgcmV0dXJuIFRJTUVfU0lNUExFOwogICAgfQoKICAgIC8qKgogICAgICoge0BsaW5rIERhdGVUaW1lI3RvTG9jYWxlU3RyaW5nfSBmb3JtYXQgbGlrZSAnMDk6MzA6MjMgQU0nLiBPbmx5IDEyLWhvdXIgaWYgdGhlIGxvY2FsZSBpcy4KICAgICAqIEB0eXBlIHtPYmplY3R9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgVElNRV9XSVRIX1NFQ09ORFMoKSB7CiAgICAgIHJldHVybiBUSU1FX1dJVEhfU0VDT05EUzsKICAgIH0KCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgJzA5OjMwOjIzIEFNIEVEVCcuIE9ubHkgMTItaG91ciBpZiB0aGUgbG9jYWxlIGlzLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBUSU1FX1dJVEhfU0hPUlRfT0ZGU0VUKCkgewogICAgICByZXR1cm4gVElNRV9XSVRIX1NIT1JUX09GRlNFVDsKICAgIH0KCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgJzA5OjMwOjIzIEFNIEVhc3Rlcm4gRGF5bGlnaHQgVGltZScuIE9ubHkgMTItaG91ciBpZiB0aGUgbG9jYWxlIGlzLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBUSU1FX1dJVEhfTE9OR19PRkZTRVQoKSB7CiAgICAgIHJldHVybiBUSU1FX1dJVEhfTE9OR19PRkZTRVQ7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICcwOTozMCcsIGFsd2F5cyAyNC1ob3VyLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBUSU1FXzI0X1NJTVBMRSgpIHsKICAgICAgcmV0dXJuIFRJTUVfMjRfU0lNUExFOwogICAgfQoKICAgIC8qKgogICAgICoge0BsaW5rIERhdGVUaW1lI3RvTG9jYWxlU3RyaW5nfSBmb3JtYXQgbGlrZSAnMDk6MzA6MjMnLCBhbHdheXMgMjQtaG91ci4KICAgICAqIEB0eXBlIHtPYmplY3R9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgVElNRV8yNF9XSVRIX1NFQ09ORFMoKSB7CiAgICAgIHJldHVybiBUSU1FXzI0X1dJVEhfU0VDT05EUzsKICAgIH0KCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgJzA5OjMwOjIzIEVEVCcsIGFsd2F5cyAyNC1ob3VyLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBUSU1FXzI0X1dJVEhfU0hPUlRfT0ZGU0VUKCkgewogICAgICByZXR1cm4gVElNRV8yNF9XSVRIX1NIT1JUX09GRlNFVDsKICAgIH0KCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgJzA5OjMwOjIzIEVhc3Rlcm4gRGF5bGlnaHQgVGltZScsIGFsd2F5cyAyNC1ob3VyLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBUSU1FXzI0X1dJVEhfTE9OR19PRkZTRVQoKSB7CiAgICAgIHJldHVybiBUSU1FXzI0X1dJVEhfTE9OR19PRkZTRVQ7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICcxMC8xNC8xOTgzLCA5OjMwIEFNJy4gT25seSAxMi1ob3VyIGlmIHRoZSBsb2NhbGUgaXMuCiAgICAgKiBAdHlwZSB7T2JqZWN0fQogICAgICovCiAgICBzdGF0aWMgZ2V0IERBVEVUSU1FX1NIT1JUKCkgewogICAgICByZXR1cm4gREFURVRJTUVfU0hPUlQ7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICcxMC8xNC8xOTgzLCA5OjMwOjMzIEFNJy4gT25seSAxMi1ob3VyIGlmIHRoZSBsb2NhbGUgaXMuCiAgICAgKiBAdHlwZSB7T2JqZWN0fQogICAgICovCiAgICBzdGF0aWMgZ2V0IERBVEVUSU1FX1NIT1JUX1dJVEhfU0VDT05EUygpIHsKICAgICAgcmV0dXJuIERBVEVUSU1FX1NIT1JUX1dJVEhfU0VDT05EUzsKICAgIH0KCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgJ09jdCAxNCwgMTk4MywgOTozMCBBTScuIE9ubHkgMTItaG91ciBpZiB0aGUgbG9jYWxlIGlzLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBEQVRFVElNRV9NRUQoKSB7CiAgICAgIHJldHVybiBEQVRFVElNRV9NRUQ7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICdPY3QgMTQsIDE5ODMsIDk6MzA6MzMgQU0nLiBPbmx5IDEyLWhvdXIgaWYgdGhlIGxvY2FsZSBpcy4KICAgICAqIEB0eXBlIHtPYmplY3R9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgREFURVRJTUVfTUVEX1dJVEhfU0VDT05EUygpIHsKICAgICAgcmV0dXJuIERBVEVUSU1FX01FRF9XSVRIX1NFQ09ORFM7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICdGcmksIDE0IE9jdCAxOTgzLCA5OjMwIEFNJy4gT25seSAxMi1ob3VyIGlmIHRoZSBsb2NhbGUgaXMuCiAgICAgKiBAdHlwZSB7T2JqZWN0fQogICAgICovCiAgICBzdGF0aWMgZ2V0IERBVEVUSU1FX01FRF9XSVRIX1dFRUtEQVkoKSB7CiAgICAgIHJldHVybiBEQVRFVElNRV9NRURfV0lUSF9XRUVLREFZOwogICAgfQoKICAgIC8qKgogICAgICoge0BsaW5rIERhdGVUaW1lI3RvTG9jYWxlU3RyaW5nfSBmb3JtYXQgbGlrZSAnT2N0b2JlciAxNCwgMTk4MywgOTozMCBBTSBFRFQnLiBPbmx5IDEyLWhvdXIgaWYgdGhlIGxvY2FsZSBpcy4KICAgICAqIEB0eXBlIHtPYmplY3R9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgREFURVRJTUVfRlVMTCgpIHsKICAgICAgcmV0dXJuIERBVEVUSU1FX0ZVTEw7CiAgICB9CgogICAgLyoqCiAgICAgKiB7QGxpbmsgRGF0ZVRpbWUjdG9Mb2NhbGVTdHJpbmd9IGZvcm1hdCBsaWtlICdPY3RvYmVyIDE0LCAxOTgzLCA5OjMwOjMzIEFNIEVEVCcuIE9ubHkgMTItaG91ciBpZiB0aGUgbG9jYWxlIGlzLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBEQVRFVElNRV9GVUxMX1dJVEhfU0VDT05EUygpIHsKICAgICAgcmV0dXJuIERBVEVUSU1FX0ZVTExfV0lUSF9TRUNPTkRTOwogICAgfQoKICAgIC8qKgogICAgICoge0BsaW5rIERhdGVUaW1lI3RvTG9jYWxlU3RyaW5nfSBmb3JtYXQgbGlrZSAnRnJpZGF5LCBPY3RvYmVyIDE0LCAxOTgzLCA5OjMwIEFNIEVhc3Rlcm4gRGF5bGlnaHQgVGltZScuIE9ubHkgMTItaG91ciBpZiB0aGUgbG9jYWxlIGlzLgogICAgICogQHR5cGUge09iamVjdH0KICAgICAqLwogICAgc3RhdGljIGdldCBEQVRFVElNRV9IVUdFKCkgewogICAgICByZXR1cm4gREFURVRJTUVfSFVHRTsKICAgIH0KCiAgICAvKioKICAgICAqIHtAbGluayBEYXRlVGltZSN0b0xvY2FsZVN0cmluZ30gZm9ybWF0IGxpa2UgJ0ZyaWRheSwgT2N0b2JlciAxNCwgMTk4MywgOTozMDozMyBBTSBFYXN0ZXJuIERheWxpZ2h0IFRpbWUnLiBPbmx5IDEyLWhvdXIgaWYgdGhlIGxvY2FsZSBpcy4KICAgICAqIEB0eXBlIHtPYmplY3R9CiAgICAgKi8KICAgIHN0YXRpYyBnZXQgREFURVRJTUVfSFVHRV9XSVRIX1NFQ09ORFMoKSB7CiAgICAgIHJldHVybiBEQVRFVElNRV9IVUdFX1dJVEhfU0VDT05EUzsKICAgIH0KICB9CgogIC8qKgogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gZnJpZW5kbHlEYXRlVGltZShkYXRlVGltZWlzaCkgewogICAgaWYgKERhdGVUaW1lLmlzRGF0ZVRpbWUoZGF0ZVRpbWVpc2gpKSB7CiAgICAgIHJldHVybiBkYXRlVGltZWlzaDsKICAgIH0gZWxzZSBpZiAoZGF0ZVRpbWVpc2ggJiYgZGF0ZVRpbWVpc2gudmFsdWVPZiAmJiBpc051bWJlcihkYXRlVGltZWlzaC52YWx1ZU9mKCkpKSB7CiAgICAgIHJldHVybiBEYXRlVGltZS5mcm9tSlNEYXRlKGRhdGVUaW1laXNoKTsKICAgIH0gZWxzZSBpZiAoZGF0ZVRpbWVpc2ggJiYgdHlwZW9mIGRhdGVUaW1laXNoID09PSAib2JqZWN0IikgewogICAgICByZXR1cm4gRGF0ZVRpbWUuZnJvbU9iamVjdChkYXRlVGltZWlzaCk7CiAgICB9IGVsc2UgewogICAgICB0aHJvdyBuZXcgSW52YWxpZEFyZ3VtZW50RXJyb3IoCiAgICAgICAgYFVua25vd24gZGF0ZXRpbWUgYXJndW1lbnQ6ICR7ZGF0ZVRpbWVpc2h9LCBvZiB0eXBlICR7dHlwZW9mIGRhdGVUaW1laXNofWAKICAgICAgKTsKICAgIH0KICB9CgogIC8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgLy8gUXVlcnkgU2V0dGluZ3MgLy8KICAvLy8vLy8vLy8vLy8vLy8vLy8vLwogIGNvbnN0IERFRkFVTFRfUVVFUllfU0VUVElOR1MgPSB7CiAgICAgIHJlbmRlck51bGxBczogIlxcLSIsCiAgICAgIHRhc2tDb21wbGV0aW9uVHJhY2tpbmc6IGZhbHNlLAogICAgICB0YXNrQ29tcGxldGlvblVzZUVtb2ppU2hvcnRoYW5kOiBmYWxzZSwKICAgICAgdGFza0NvbXBsZXRpb25UZXh0OiAiY29tcGxldGlvbiIsCiAgICAgIHRhc2tDb21wbGV0aW9uRGF0ZUZvcm1hdDogInl5eXktTU0tZGQiLAogICAgICByZWN1cnNpdmVTdWJUYXNrQ29tcGxldGlvbjogZmFsc2UsCiAgICAgIHdhcm5PbkVtcHR5UmVzdWx0OiB0cnVlLAogICAgICByZWZyZXNoRW5hYmxlZDogdHJ1ZSwKICAgICAgcmVmcmVzaEludGVydmFsOiAyNTAwLAogICAgICBkZWZhdWx0RGF0ZUZvcm1hdDogIk1NTU0gZGQsIHl5eXkiLAogICAgICBkZWZhdWx0RGF0ZVRpbWVGb3JtYXQ6ICJoOm1tIGEgLSBNTU1NIGRkLCB5eXl5IiwKICAgICAgbWF4UmVjdXJzaXZlUmVuZGVyRGVwdGg6IDQsCiAgICAgIHRhYmxlSWRDb2x1bW5OYW1lOiAiRmlsZSIsCiAgICAgIHRhYmxlR3JvdXBDb2x1bW5OYW1lOiAiR3JvdXAiLAogICAgICBzaG93UmVzdWx0Q291bnQ6IHRydWUsCiAgfTsKICBjb25zdCBERUZBVUxUX0VYUE9SVF9TRVRUSU5HUyA9IHsKICAgICAgYWxsb3dIdG1sOiB0cnVlLAogIH07CiAgLyoqIERlZmF1bHQgc2V0dGluZ3MgZm9yIGRhdGF2aWV3IG9uIGluc3RhbGwuICovCiAgKHsKICAgICAgLi4uREVGQVVMVF9RVUVSWV9TRVRUSU5HUywKICAgICAgLi4uREVGQVVMVF9FWFBPUlRfU0VUVElOR1MsCiAgICAgIC4uLnsKICAgICAgICAgIGlubGluZVF1ZXJ5UHJlZml4OiAiPSIsCiAgICAgICAgICBpbmxpbmVKc1F1ZXJ5UHJlZml4OiAiJD0iLAogICAgICAgICAgaW5saW5lUXVlcmllc0luQ29kZWJsb2NrczogdHJ1ZSwKICAgICAgICAgIGVuYWJsZUlubGluZURhdGF2aWV3OiB0cnVlLAogICAgICAgICAgZW5hYmxlRGF0YXZpZXdKczogZmFsc2UsCiAgICAgICAgICBlbmFibGVJbmxpbmVEYXRhdmlld0pzOiBmYWxzZSwKICAgICAgICAgIHByZXR0eVJlbmRlcklubGluZUZpZWxkczogdHJ1ZSwKICAgICAgICAgIHByZXR0eVJlbmRlcklubGluZUZpZWxkc0luTGl2ZVByZXZpZXc6IHRydWUsCiAgICAgICAgICBkYXRhdmlld0pzS2V5d29yZDogImRhdGF2aWV3anMiLAogICAgICB9LAogIH0pOwoKICAvKiogRnVuY3Rpb25hbCByZXR1cm4gdHlwZSBmb3IgZXJyb3IgaGFuZGxpbmcuICovCiAgY2xhc3MgU3VjY2VzcyB7CiAgICAgIHZhbHVlOwogICAgICBzdWNjZXNzZnVsOwogICAgICBjb25zdHJ1Y3Rvcih2YWx1ZSkgewogICAgICAgICAgdGhpcy52YWx1ZSA9IHZhbHVlOwogICAgICAgICAgdGhpcy5zdWNjZXNzZnVsID0gdHJ1ZTsKICAgICAgfQogICAgICBtYXAoZikgewogICAgICAgICAgcmV0dXJuIG5ldyBTdWNjZXNzKGYodGhpcy52YWx1ZSkpOwogICAgICB9CiAgICAgIGZsYXRNYXAoZikgewogICAgICAgICAgcmV0dXJuIGYodGhpcy52YWx1ZSk7CiAgICAgIH0KICAgICAgbWFwRXJyKGYpIHsKICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICB9CiAgICAgIGJpbWFwKHN1Y2MsIF9mYWlsKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5tYXAoc3VjYyk7CiAgICAgIH0KICAgICAgb3JFbHNlKF92YWx1ZSkgewogICAgICAgICAgcmV0dXJuIHRoaXMudmFsdWU7CiAgICAgIH0KICAgICAgY2FzdCgpIHsKICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICB9CiAgICAgIG9yRWxzZVRocm93KF9tZXNzYWdlKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZTsKICAgICAgfQogIH0KICAvKiogRnVuY3Rpb25hbCByZXR1cm4gdHlwZSBmb3IgZXJyb3IgaGFuZGxpbmcuICovCiAgY2xhc3MgRmFpbHVyZSB7CiAgICAgIGVycm9yOwogICAgICBzdWNjZXNzZnVsOwogICAgICBjb25zdHJ1Y3RvcihlcnJvcikgewogICAgICAgICAgdGhpcy5lcnJvciA9IGVycm9yOwogICAgICAgICAgdGhpcy5zdWNjZXNzZnVsID0gZmFsc2U7CiAgICAgIH0KICAgICAgbWFwKF9mKSB7CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgfQogICAgICBmbGF0TWFwKF9mKSB7CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgfQogICAgICBtYXBFcnIoZikgewogICAgICAgICAgcmV0dXJuIG5ldyBGYWlsdXJlKGYodGhpcy5lcnJvcikpOwogICAgICB9CiAgICAgIGJpbWFwKF9zdWNjLCBmYWlsKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5tYXBFcnIoZmFpbCk7CiAgICAgIH0KICAgICAgb3JFbHNlKHZhbHVlKSB7CiAgICAgICAgICByZXR1cm4gdmFsdWU7CiAgICAgIH0KICAgICAgY2FzdCgpIHsKICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICB9CiAgICAgIG9yRWxzZVRocm93KG1lc3NhZ2UpIHsKICAgICAgICAgIGlmIChtZXNzYWdlKQogICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihtZXNzYWdlKHRoaXMuZXJyb3IpKTsKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIiIgKyB0aGlzLmVycm9yKTsKICAgICAgfQogIH0KICAvKiogTW9uYWRpYyAnUmVzdWx0JyB0eXBlIHdoaWNoIGVuY2Fwc3VsYXRlcyB3aGV0aGVyIGEgcHJvY2VkdXJlIHN1Y2NlZWRlZCBvciBmYWlsZWQsIGFzIHdlbGwgYXMgaXQncyByZXR1cm4gdmFsdWUuICovCiAgdmFyIFJlc3VsdDsKICAoZnVuY3Rpb24gKFJlc3VsdCkgewogICAgICAvKiogQ29uc3RydWN0IGEgbmV3IHN1Y2Nlc3MgcmVzdWx0IHdyYXBwaW5nIHRoZSBnaXZlbiB2YWx1ZS4gKi8KICAgICAgZnVuY3Rpb24gc3VjY2Vzcyh2YWx1ZSkgewogICAgICAgICAgcmV0dXJuIG5ldyBTdWNjZXNzKHZhbHVlKTsKICAgICAgfQogICAgICBSZXN1bHQuc3VjY2VzcyA9IHN1Y2Nlc3M7CiAgICAgIC8qKiBDb25zdHJ1Y3QgYSBuZXcgZmFpbHVyZSB2YWx1ZSB3cmFwcGluZyB0aGUgZ2l2ZW4gZXJyb3IuICovCiAgICAgIGZ1bmN0aW9uIGZhaWx1cmUoZXJyb3IpIHsKICAgICAgICAgIHJldHVybiBuZXcgRmFpbHVyZShlcnJvcik7CiAgICAgIH0KICAgICAgUmVzdWx0LmZhaWx1cmUgPSBmYWlsdXJlOwogICAgICAvKiogSm9pbiB0d28gcmVzdWx0cyB3aXRoIGEgYmktZnVuY3Rpb24gYW5kIHJldHVybiBhIG5ldyByZXN1bHQuICovCiAgICAgIGZ1bmN0aW9uIGZsYXRNYXAyKGZpcnN0LCBzZWNvbmQsIGYpIHsKICAgICAgICAgIGlmIChmaXJzdC5zdWNjZXNzZnVsKSB7CiAgICAgICAgICAgICAgaWYgKHNlY29uZC5zdWNjZXNzZnVsKQogICAgICAgICAgICAgICAgICByZXR1cm4gZihmaXJzdC52YWx1ZSwgc2Vjb25kLnZhbHVlKTsKICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICAgIHJldHVybiBmYWlsdXJlKHNlY29uZC5lcnJvcik7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICByZXR1cm4gZmFpbHVyZShmaXJzdC5lcnJvcik7CiAgICAgICAgICB9CiAgICAgIH0KICAgICAgUmVzdWx0LmZsYXRNYXAyID0gZmxhdE1hcDI7CiAgICAgIC8qKiBKb2luIHR3byByZXN1bHRzIHdpdGggYSBiaS1mdW5jdGlvbiBhbmQgcmV0dXJuIGEgbmV3IHJlc3VsdC4gKi8KICAgICAgZnVuY3Rpb24gbWFwMihmaXJzdCwgc2Vjb25kLCBmKSB7CiAgICAgICAgICByZXR1cm4gZmxhdE1hcDIoZmlyc3QsIHNlY29uZCwgKGEsIGIpID0+IHN1Y2Nlc3MoZihhLCBiKSkpOwogICAgICB9CiAgICAgIFJlc3VsdC5tYXAyID0gbWFwMjsKICB9KShSZXN1bHQgfHwgKFJlc3VsdCA9IHt9KSk7CgogIHZhciBjb21tb25qc0dsb2JhbCA9IHR5cGVvZiBnbG9iYWxUaGlzICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbFRoaXMgOiB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IHdpbmRvdyA6IHR5cGVvZiBnbG9iYWwgIT09ICd1bmRlZmluZWQnID8gZ2xvYmFsIDogdHlwZW9mIHNlbGYgIT09ICd1bmRlZmluZWQnID8gc2VsZiA6IHt9OwoKICB2YXIgcGFyc2ltbW9uX3VtZF9taW4gPSB7ZXhwb3J0czoge319OwoKICBwYXJzaW1tb25fdW1kX21pbi5leHBvcnRzOwoKICAoZnVuY3Rpb24gKG1vZHVsZSwgZXhwb3J0cykgewogIAkhZnVuY3Rpb24obix0KXttb2R1bGUuZXhwb3J0cz10KCk7fSgidW5kZWZpbmVkIiE9dHlwZW9mIHNlbGY/c2VsZjpjb21tb25qc0dsb2JhbCxmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbihuKXt2YXIgdD17fTtmdW5jdGlvbiByKGUpe2lmKHRbZV0pcmV0dXJuIHRbZV0uZXhwb3J0czt2YXIgdT10W2VdPXtpOmUsbDohMSxleHBvcnRzOnt9fTtyZXR1cm4gbltlXS5jYWxsKHUuZXhwb3J0cyx1LHUuZXhwb3J0cyxyKSx1Lmw9ITAsdS5leHBvcnRzfXJldHVybiByLm09bixyLmM9dCxyLmQ9ZnVuY3Rpb24obix0LGUpe3IubyhuLHQpfHxPYmplY3QuZGVmaW5lUHJvcGVydHkobix0LHtjb25maWd1cmFibGU6ITEsZW51bWVyYWJsZTohMCxnZXQ6ZX0pO30sci5yPWZ1bmN0aW9uKG4pe09iamVjdC5kZWZpbmVQcm9wZXJ0eShuLCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt9LHIubj1mdW5jdGlvbihuKXt2YXIgdD1uJiZuLl9fZXNNb2R1bGU/ZnVuY3Rpb24oKXtyZXR1cm4gbi5kZWZhdWx0fTpmdW5jdGlvbigpe3JldHVybiBufTtyZXR1cm4gci5kKHQsImEiLHQpLHR9LHIubz1mdW5jdGlvbihuLHQpe3JldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobix0KX0sci5wPSIiLHIoci5zPTApfShbZnVuY3Rpb24obix0LHIpe2Z1bmN0aW9uIGUobil7aWYoISh0aGlzIGluc3RhbmNlb2YgZSkpcmV0dXJuIG5ldyBlKG4pO3RoaXMuXz1uO312YXIgdT1lLnByb3RvdHlwZTtmdW5jdGlvbiBvKG4sdCl7Zm9yKHZhciByPTA7cjxuO3IrKyl0KHIpO31mdW5jdGlvbiBpKG4sdCxyKXtyZXR1cm4gZnVuY3Rpb24obix0KXtvKHQubGVuZ3RoLGZ1bmN0aW9uKHIpe24odFtyXSxyLHQpO30pO30oZnVuY3Rpb24ocixlLHUpe3Q9bih0LHIsZSx1KTt9LHIpLHR9ZnVuY3Rpb24gYShuLHQpe3JldHVybiBpKGZ1bmN0aW9uKHQscixlLHUpe3JldHVybiB0LmNvbmNhdChbbihyLGUsdSldKX0sW10sdCl9ZnVuY3Rpb24gZihuLHQpe3ZhciByPXt2OjAsYnVmOnR9O3JldHVybiBvKG4sZnVuY3Rpb24oKXt2YXIgbjtyPXt2OnIudjw8MXwobj1yLmJ1ZixuWzBdPj43KSxidWY6ZnVuY3Rpb24obil7dmFyIHQ9aShmdW5jdGlvbihuLHQscixlKXtyZXR1cm4gbi5jb25jYXQocj09PWUubGVuZ3RoLTE/QnVmZmVyLmZyb20oW3QsMF0pLnJlYWRVSW50MTZCRSgwKTplLnJlYWRVSW50MTZCRShyKSl9LFtdLG4pO3JldHVybiBCdWZmZXIuZnJvbShhKGZ1bmN0aW9uKG4pe3JldHVybiAobjw8MSY2NTUzNSk+Pjh9LHQpKX0oci5idWYpfTt9KSxyfWZ1bmN0aW9uIGMoKXtyZXR1cm4gInVuZGVmaW5lZCIhPXR5cGVvZiBCdWZmZXJ9ZnVuY3Rpb24gcygpe2lmKCFjKCkpdGhyb3cgbmV3IEVycm9yKCJCdWZmZXIgZ2xvYmFsIGRvZXMgbm90IGV4aXN0OyBwbGVhc2UgdXNlIHdlYnBhY2sgaWYgeW91IG5lZWQgdG8gcGFyc2UgQnVmZmVycyBpbiB0aGUgYnJvd3Nlci4iKX1mdW5jdGlvbiBsKG4pe3MoKTt2YXIgdD1pKGZ1bmN0aW9uKG4sdCl7cmV0dXJuIG4rdH0sMCxuKTtpZih0JTghPTApdGhyb3cgbmV3IEVycm9yKCJUaGUgYml0cyBbIituLmpvaW4oIiwgIikrIl0gYWRkIHVwIHRvICIrdCsiIHdoaWNoIGlzIG5vdCBhbiBldmVuIG51bWJlciBvZiBieXRlczsgdGhlIHRvdGFsIHNob3VsZCBiZSBkaXZpc2libGUgYnkgOCIpO3ZhciByLHU9dC84LG89KHI9ZnVuY3Rpb24obil7cmV0dXJuIG4+NDh9LGkoZnVuY3Rpb24obix0KXtyZXR1cm4gbnx8KHIodCk/dDpuKX0sbnVsbCxuKSk7aWYobyl0aHJvdyBuZXcgRXJyb3IobysiIGJpdCByYW5nZSByZXF1ZXN0ZWQgZXhjZWVkcyA0OCBiaXQgKDYgYnl0ZSkgTnVtYmVyIG1heC4iKTtyZXR1cm4gbmV3IGUoZnVuY3Rpb24odCxyKXt2YXIgZT11K3I7cmV0dXJuIGU+dC5sZW5ndGg/eChyLHUudG9TdHJpbmcoKSsiIGJ5dGVzIik6YihlLGkoZnVuY3Rpb24obix0KXt2YXIgcj1mKHQsbi5idWYpO3JldHVybiB7Y29sbDpuLmNvbGwuY29uY2F0KHIudiksYnVmOnIuYnVmfX0se2NvbGw6W10sYnVmOnQuc2xpY2UocixlKX0sbikuY29sbCl9KX1mdW5jdGlvbiBoKG4sdCl7cmV0dXJuIG5ldyBlKGZ1bmN0aW9uKHIsZSl7cmV0dXJuIHMoKSxlK3Q+ci5sZW5ndGg/eChlLHQrIiBieXRlcyBmb3IgIituKTpiKGUrdCxyLnNsaWNlKGUsZSt0KSl9KX1mdW5jdGlvbiBwKG4sdCl7aWYoIm51bWJlciIhPXR5cGVvZihyPXQpfHxNYXRoLmZsb29yKHIpIT09cnx8dDwwfHx0PjYpdGhyb3cgbmV3IEVycm9yKG4rIiByZXF1aXJlcyBpbnRlZ2VyIGxlbmd0aCBpbiByYW5nZSBbMCwgNl0uIik7dmFyIHI7fWZ1bmN0aW9uIGQobil7cmV0dXJuIHAoInVpbnRCRSIsbiksaCgidWludEJFKCIrbisiKSIsbikubWFwKGZ1bmN0aW9uKHQpe3JldHVybiB0LnJlYWRVSW50QkUoMCxuKX0pfWZ1bmN0aW9uIHYobil7cmV0dXJuIHAoInVpbnRMRSIsbiksaCgidWludExFKCIrbisiKSIsbikubWFwKGZ1bmN0aW9uKHQpe3JldHVybiB0LnJlYWRVSW50TEUoMCxuKX0pfWZ1bmN0aW9uIGcobil7cmV0dXJuIHAoImludEJFIixuKSxoKCJpbnRCRSgiK24rIikiLG4pLm1hcChmdW5jdGlvbih0KXtyZXR1cm4gdC5yZWFkSW50QkUoMCxuKX0pfWZ1bmN0aW9uIG0obil7cmV0dXJuIHAoImludExFIixuKSxoKCJpbnRMRSgiK24rIikiLG4pLm1hcChmdW5jdGlvbih0KXtyZXR1cm4gdC5yZWFkSW50TEUoMCxuKX0pfWZ1bmN0aW9uIHkobil7cmV0dXJuIG4gaW5zdGFuY2VvZiBlfWZ1bmN0aW9uIEUobil7cmV0dXJuICJbb2JqZWN0IEFycmF5XSI9PT17fS50b1N0cmluZy5jYWxsKG4pfWZ1bmN0aW9uIHcobil7cmV0dXJuIGMoKSYmQnVmZmVyLmlzQnVmZmVyKG4pfWZ1bmN0aW9uIGIobix0KXtyZXR1cm4ge3N0YXR1czohMCxpbmRleDpuLHZhbHVlOnQsZnVydGhlc3Q6LTEsZXhwZWN0ZWQ6W119fWZ1bmN0aW9uIHgobix0KXtyZXR1cm4gRSh0KXx8KHQ9W3RdKSx7c3RhdHVzOiExLGluZGV4Oi0xLHZhbHVlOm51bGwsZnVydGhlc3Q6bixleHBlY3RlZDp0fX1mdW5jdGlvbiBCKG4sdCl7aWYoIXQpcmV0dXJuIG47aWYobi5mdXJ0aGVzdD50LmZ1cnRoZXN0KXJldHVybiBuO3ZhciByPW4uZnVydGhlc3Q9PT10LmZ1cnRoZXN0P2Z1bmN0aW9uKG4sdCl7aWYoZnVuY3Rpb24oKXtpZih2b2lkIDAhPT1lLl9zdXBwb3J0c1NldClyZXR1cm4gZS5fc3VwcG9ydHNTZXQ7dmFyIG49InVuZGVmaW5lZCIhPXR5cGVvZiBTZXQ7cmV0dXJuIGUuX3N1cHBvcnRzU2V0PW4sbn0oKSYmQXJyYXkuZnJvbSl7Zm9yKHZhciByPW5ldyBTZXQobiksdT0wO3U8dC5sZW5ndGg7dSsrKXIuYWRkKHRbdV0pO3ZhciBvPUFycmF5LmZyb20ocik7cmV0dXJuIG8uc29ydCgpLG99Zm9yKHZhciBpPXt9LGE9MDthPG4ubGVuZ3RoO2ErKylpW25bYV1dPSEwO2Zvcih2YXIgZj0wO2Y8dC5sZW5ndGg7ZisrKWlbdFtmXV09ITA7dmFyIGM9W107Zm9yKHZhciBzIGluIGkpKHt9KS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGkscykmJmMucHVzaChzKTtyZXR1cm4gYy5zb3J0KCksY30obi5leHBlY3RlZCx0LmV4cGVjdGVkKTp0LmV4cGVjdGVkO3JldHVybiB7c3RhdHVzOm4uc3RhdHVzLGluZGV4Om4uaW5kZXgsdmFsdWU6bi52YWx1ZSxmdXJ0aGVzdDp0LmZ1cnRoZXN0LGV4cGVjdGVkOnJ9fXZhciBqPXt9O2Z1bmN0aW9uIFMobix0KXtpZih3KG4pKXJldHVybiB7b2Zmc2V0OnQsbGluZTotMSxjb2x1bW46LTF9O24gaW4ganx8KGpbbl09e30pO2Zvcih2YXIgcj1qW25dLGU9MCx1PTAsbz0wLGk9dDtpPj0wOyl7aWYoaSBpbiByKXtlPXJbaV0ubGluZSwwPT09byYmKG89cltpXS5saW5lU3RhcnQpO2JyZWFrfSgiXG4iPT09bi5jaGFyQXQoaSl8fCJcciI9PT1uLmNoYXJBdChpKSYmIlxuIiE9PW4uY2hhckF0KGkrMSkpJiYodSsrLDA9PT1vJiYobz1pKzEpKSxpLS07fXZhciBhPWUrdSxmPXQtbztyZXR1cm4gclt0XT17bGluZTphLGxpbmVTdGFydDpvfSx7b2Zmc2V0OnQsbGluZTphKzEsY29sdW1uOmYrMX19ZnVuY3Rpb24gXyhuKXtpZigheShuKSl0aHJvdyBuZXcgRXJyb3IoIm5vdCBhIHBhcnNlcjogIituKX1mdW5jdGlvbiBMKG4sdCl7cmV0dXJuICJzdHJpbmciPT10eXBlb2Ygbj9uLmNoYXJBdCh0KTpuW3RdfWZ1bmN0aW9uIE8obil7aWYoIm51bWJlciIhPXR5cGVvZiBuKXRocm93IG5ldyBFcnJvcigibm90IGEgbnVtYmVyOiAiK24pfWZ1bmN0aW9uIGsobil7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIG4pdGhyb3cgbmV3IEVycm9yKCJub3QgYSBmdW5jdGlvbjogIituKX1mdW5jdGlvbiBQKG4pe2lmKCJzdHJpbmciIT10eXBlb2Ygbil0aHJvdyBuZXcgRXJyb3IoIm5vdCBhIHN0cmluZzogIituKX12YXIgcT0yLEE9MyxJPTgsRj01KkksTT00Kkksej0iICAiO2Z1bmN0aW9uIFIobix0KXtyZXR1cm4gbmV3IEFycmF5KHQrMSkuam9pbihuKX1mdW5jdGlvbiBVKG4sdCxyKXt2YXIgZT10LW4ubGVuZ3RoO3JldHVybiBlPD0wP246UihyLGUpK259ZnVuY3Rpb24gVyhuLHQscixlKXtyZXR1cm4ge2Zyb206bi10PjA/bi10OjAsdG86bityPmU/ZTpuK3J9fWZ1bmN0aW9uIEQobix0KXt2YXIgcixlLHUsbyxmLGM9dC5pbmRleCxzPWMub2Zmc2V0LGw9MTtpZihzPT09bi5sZW5ndGgpcmV0dXJuICJHb3QgdGhlIGVuZCBvZiB0aGUgaW5wdXQiO2lmKHcobikpe3ZhciBoPXMtcyVJLHA9cy1oLGQ9VyhoLEYsTStJLG4ubGVuZ3RoKSx2PWEoZnVuY3Rpb24obil7cmV0dXJuIGEoZnVuY3Rpb24obil7cmV0dXJuIFUobi50b1N0cmluZygxNiksMiwiMCIpfSxuKX0sZnVuY3Rpb24obix0KXt2YXIgcj1uLmxlbmd0aCxlPVtdLHU9MDtpZihyPD10KXJldHVybiBbbi5zbGljZSgpXTtmb3IodmFyIG89MDtvPHI7bysrKWVbdV18fGUucHVzaChbXSksZVt1XS5wdXNoKG5bb10pLChvKzEpJXQ9PTAmJnUrKztyZXR1cm4gZX0obi5zbGljZShkLmZyb20sZC50bykudG9KU09OKCkuZGF0YSxJKSk7bz1mdW5jdGlvbihuKXtyZXR1cm4gMD09PW4uZnJvbSYmMT09PW4udG8/e2Zyb206bi5mcm9tLHRvOm4udG99Ontmcm9tOm4uZnJvbS9JLHRvOk1hdGguZmxvb3Iobi50by9JKX19KGQpLGU9aC9JLHI9MypwLHA+PTQmJihyKz0xKSxsPTIsdT1hKGZ1bmN0aW9uKG4pe3JldHVybiBuLmxlbmd0aDw9ND9uLmpvaW4oIiAiKTpuLnNsaWNlKDAsNCkuam9pbigiICIpKyIgICIrbi5zbGljZSg0KS5qb2luKCIgIil9LHYpLChmPSg4KihvLnRvPjA/by50by0xOm8udG8pKS50b1N0cmluZygxNikubGVuZ3RoKTwyJiYoZj0yKTt9ZWxzZSB7dmFyIGc9bi5zcGxpdCgvXHJcbnxbXG5cclx1MjAyOFx1MjAyOV0vKTtyPWMuY29sdW1uLTEsZT1jLmxpbmUtMSxvPVcoZSxxLEEsZy5sZW5ndGgpLHU9Zy5zbGljZShvLmZyb20sby50byksZj1vLnRvLnRvU3RyaW5nKCkubGVuZ3RoO312YXIgbT1lLW8uZnJvbTtyZXR1cm4gdyhuKSYmKGY9KDgqKG8udG8+MD9vLnRvLTE6by50bykpLnRvU3RyaW5nKDE2KS5sZW5ndGgpPDImJihmPTIpLGkoZnVuY3Rpb24odCxlLHUpe3ZhciBpLGE9dT09PW0sYz1hPyI+ICI6ejtyZXR1cm4gaT13KG4pP1UoKDgqKG8uZnJvbSt1KSkudG9TdHJpbmcoMTYpLGYsIjAiKTpVKChvLmZyb20rdSsxKS50b1N0cmluZygpLGYsIiAiKSxbXS5jb25jYXQodCxbYytpKyIgfCAiK2VdLGE/W3orUigiICIsZikrIiB8ICIrVSgiIixyLCIgIikrUigiXiIsbCldOltdKX0sW10sdSkuam9pbigiXG4iKX1mdW5jdGlvbiBOKG4sdCl7cmV0dXJuIFsiXG4iLCItLSBQQVJTSU5HIEZBSUxFRCAiK1IoIi0iLDUwKSwiXG5cbiIsRChuLHQpLCJcblxuIiwocj10LmV4cGVjdGVkLDE9PT1yLmxlbmd0aD8iRXhwZWN0ZWQ6XG5cbiIrclswXToiRXhwZWN0ZWQgb25lIG9mIHRoZSBmb2xsb3dpbmc6IFxuXG4iK3Iuam9pbigiLCAiKSksIlxuIl0uam9pbigiIik7dmFyIHI7fWZ1bmN0aW9uIEcobil7cmV0dXJuIHZvaWQgMCE9PW4uZmxhZ3M/bi5mbGFnczpbbi5nbG9iYWw/ImciOiIiLG4uaWdub3JlQ2FzZT8iaSI6IiIsbi5tdWx0aWxpbmU/Im0iOiIiLG4udW5pY29kZT8idSI6IiIsbi5zdGlja3k/InkiOiIiXS5qb2luKCIiKX1mdW5jdGlvbiBDKCl7Zm9yKHZhciBuPVtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSx0PW4ubGVuZ3RoLHI9MDtyPHQ7cis9MSlfKG5bcl0pO3JldHVybiBlKGZ1bmN0aW9uKHIsZSl7Zm9yKHZhciB1LG89bmV3IEFycmF5KHQpLGk9MDtpPHQ7aSs9MSl7aWYoISh1PUIobltpXS5fKHIsZSksdSkpLnN0YXR1cylyZXR1cm4gdTtvW2ldPXUudmFsdWUsZT11LmluZGV4O31yZXR1cm4gQihiKGUsbyksdSl9KX1mdW5jdGlvbiBKKCl7dmFyIG49W10uc2xpY2UuY2FsbChhcmd1bWVudHMpO2lmKDA9PT1uLmxlbmd0aCl0aHJvdyBuZXcgRXJyb3IoInNlcU1hcCBuZWVkcyBhdCBsZWFzdCBvbmUgYXJndW1lbnQiKTt2YXIgdD1uLnBvcCgpO3JldHVybiBrKHQpLEMuYXBwbHkobnVsbCxuKS5tYXAoZnVuY3Rpb24obil7cmV0dXJuIHQuYXBwbHkobnVsbCxuKX0pfWZ1bmN0aW9uIFQoKXt2YXIgbj1bXS5zbGljZS5jYWxsKGFyZ3VtZW50cyksdD1uLmxlbmd0aDtpZigwPT09dClyZXR1cm4gWSgiemVybyBhbHRlcm5hdGVzIik7Zm9yKHZhciByPTA7cjx0O3IrPTEpXyhuW3JdKTtyZXR1cm4gZShmdW5jdGlvbih0LHIpe2Zvcih2YXIgZSx1PTA7dTxuLmxlbmd0aDt1Kz0xKWlmKChlPUIoblt1XS5fKHQsciksZSkpLnN0YXR1cylyZXR1cm4gZTtyZXR1cm4gZX0pfWZ1bmN0aW9uIFYobix0KXtyZXR1cm4gSChuLHQpLm9yKFgoW10pKX1mdW5jdGlvbiBIKG4sdCl7cmV0dXJuIF8obiksXyh0KSxKKG4sdC50aGVuKG4pLm1hbnkoKSxmdW5jdGlvbihuLHQpe3JldHVybiBbbl0uY29uY2F0KHQpfSl9ZnVuY3Rpb24gSyhuKXtQKG4pO3ZhciB0PSInIituKyInIjtyZXR1cm4gZShmdW5jdGlvbihyLGUpe3ZhciB1PWUrbi5sZW5ndGgsbz1yLnNsaWNlKGUsdSk7cmV0dXJuIG89PT1uP2IodSxvKTp4KGUsdCl9KX1mdW5jdGlvbiBRKG4sdCl7IWZ1bmN0aW9uKG4pe2lmKCEobiBpbnN0YW5jZW9mIFJlZ0V4cCkpdGhyb3cgbmV3IEVycm9yKCJub3QgYSByZWdleHA6ICIrbik7Zm9yKHZhciB0PUcobikscj0wO3I8dC5sZW5ndGg7cisrKXt2YXIgZT10LmNoYXJBdChyKTtpZigiaSIhPT1lJiYibSIhPT1lJiYidSIhPT1lJiYicyIhPT1lKXRocm93IG5ldyBFcnJvcigndW5zdXBwb3J0ZWQgcmVnZXhwIGZsYWcgIicrZSsnIjogJytuKX19KG4pLGFyZ3VtZW50cy5sZW5ndGg+PTI/Tyh0KTp0PTA7dmFyIHI9ZnVuY3Rpb24obil7cmV0dXJuIFJlZ0V4cCgiXig/OiIrbi5zb3VyY2UrIikiLEcobikpfShuKSx1PSIiK247cmV0dXJuIGUoZnVuY3Rpb24obixlKXt2YXIgbz1yLmV4ZWMobi5zbGljZShlKSk7aWYobyl7aWYoMDw9dCYmdDw9by5sZW5ndGgpe3ZhciBpPW9bMF0sYT1vW3RdO3JldHVybiBiKGUraS5sZW5ndGgsYSl9cmV0dXJuIHgoZSwidmFsaWQgbWF0Y2ggZ3JvdXAgKDAgdG8gIitvLmxlbmd0aCsiKSBpbiAiK3UpfXJldHVybiB4KGUsdSl9KX1mdW5jdGlvbiBYKG4pe3JldHVybiBlKGZ1bmN0aW9uKHQscil7cmV0dXJuIGIocixuKX0pfWZ1bmN0aW9uIFkobil7cmV0dXJuIGUoZnVuY3Rpb24odCxyKXtyZXR1cm4geChyLG4pfSl9ZnVuY3Rpb24gWihuKXtpZih5KG4pKXJldHVybiBlKGZ1bmN0aW9uKHQscil7dmFyIGU9bi5fKHQscik7cmV0dXJuIGUuaW5kZXg9cixlLnZhbHVlPSIiLGV9KTtpZigic3RyaW5nIj09dHlwZW9mIG4pcmV0dXJuIFooSyhuKSk7aWYobiBpbnN0YW5jZW9mIFJlZ0V4cClyZXR1cm4gWihRKG4pKTt0aHJvdyBuZXcgRXJyb3IoIm5vdCBhIHN0cmluZywgcmVnZXhwLCBvciBwYXJzZXI6ICIrbil9ZnVuY3Rpb24gJChuKXtyZXR1cm4gXyhuKSxlKGZ1bmN0aW9uKHQscil7dmFyIGU9bi5fKHQsciksdT10LnNsaWNlKHIsZS5pbmRleCk7cmV0dXJuIGUuc3RhdHVzP3gociwnbm90ICInK3UrJyInKTpiKHIsbnVsbCl9KX1mdW5jdGlvbiBubihuKXtyZXR1cm4gayhuKSxlKGZ1bmN0aW9uKHQscil7dmFyIGU9TCh0LHIpO3JldHVybiByPHQubGVuZ3RoJiZuKGUpP2IocisxLGUpOngociwiYSBjaGFyYWN0ZXIvYnl0ZSBtYXRjaGluZyAiK24pfSl9ZnVuY3Rpb24gdG4obix0KXthcmd1bWVudHMubGVuZ3RoPDImJih0PW4sbj12b2lkIDApO3ZhciByPWUoZnVuY3Rpb24obixlKXtyZXR1cm4gci5fPXQoKS5fLHIuXyhuLGUpfSk7cmV0dXJuIG4/ci5kZXNjKG4pOnJ9ZnVuY3Rpb24gcm4oKXtyZXR1cm4gWSgiZmFudGFzeS1sYW5kL2VtcHR5Iil9dS5wYXJzZT1mdW5jdGlvbihuKXtpZigic3RyaW5nIiE9dHlwZW9mIG4mJiF3KG4pKXRocm93IG5ldyBFcnJvcigiLnBhcnNlIG11c3QgYmUgY2FsbGVkIHdpdGggYSBzdHJpbmcgb3IgQnVmZmVyIGFzIGl0cyBhcmd1bWVudCIpO3ZhciB0LHI9dGhpcy5za2lwKGFuKS5fKG4sMCk7cmV0dXJuIHQ9ci5zdGF0dXM/e3N0YXR1czohMCx2YWx1ZTpyLnZhbHVlfTp7c3RhdHVzOiExLGluZGV4OlMobixyLmZ1cnRoZXN0KSxleHBlY3RlZDpyLmV4cGVjdGVkfSxkZWxldGUgaltuXSx0fSx1LnRyeVBhcnNlPWZ1bmN0aW9uKG4pe3ZhciB0PXRoaXMucGFyc2Uobik7aWYodC5zdGF0dXMpcmV0dXJuIHQudmFsdWU7dmFyIHI9TihuLHQpLGU9bmV3IEVycm9yKHIpO3Rocm93IGUudHlwZT0iUGFyc2ltbW9uRXJyb3IiLGUucmVzdWx0PXQsZX0sdS5hc3NlcnQ9ZnVuY3Rpb24obix0KXtyZXR1cm4gdGhpcy5jaGFpbihmdW5jdGlvbihyKXtyZXR1cm4gbihyKT9YKHIpOlkodCl9KX0sdS5vcj1mdW5jdGlvbihuKXtyZXR1cm4gVCh0aGlzLG4pfSx1LnRyaW09ZnVuY3Rpb24obil7cmV0dXJuIHRoaXMud3JhcChuLG4pfSx1LndyYXA9ZnVuY3Rpb24obix0KXtyZXR1cm4gSihuLHRoaXMsdCxmdW5jdGlvbihuLHQpe3JldHVybiB0fSl9LHUudGhydT1mdW5jdGlvbihuKXtyZXR1cm4gbih0aGlzKX0sdS50aGVuPWZ1bmN0aW9uKG4pe3JldHVybiBfKG4pLEModGhpcyxuKS5tYXAoZnVuY3Rpb24obil7cmV0dXJuIG5bMV19KX0sdS5tYW55PWZ1bmN0aW9uKCl7dmFyIG49dGhpcztyZXR1cm4gZShmdW5jdGlvbih0LHIpe2Zvcih2YXIgZT1bXSx1PXZvaWQgMDs7KXtpZighKHU9QihuLl8odCxyKSx1KSkuc3RhdHVzKXJldHVybiBCKGIocixlKSx1KTtpZihyPT09dS5pbmRleCl0aHJvdyBuZXcgRXJyb3IoImluZmluaXRlIGxvb3AgZGV0ZWN0ZWQgaW4gLm1hbnkoKSBwYXJzZXIgLS0tIGNhbGxpbmcgLm1hbnkoKSBvbiBhIHBhcnNlciB3aGljaCBjYW4gYWNjZXB0IHplcm8gY2hhcmFjdGVycyBpcyB1c3VhbGx5IHRoZSBjYXVzZSIpO3I9dS5pbmRleCxlLnB1c2godS52YWx1ZSk7fX0pfSx1LnRpZVdpdGg9ZnVuY3Rpb24obil7cmV0dXJuIFAobiksdGhpcy5tYXAoZnVuY3Rpb24odCl7aWYoZnVuY3Rpb24obil7aWYoIUUobikpdGhyb3cgbmV3IEVycm9yKCJub3QgYW4gYXJyYXk6ICIrbil9KHQpLHQubGVuZ3RoKXtQKHRbMF0pO2Zvcih2YXIgcj10WzBdLGU9MTtlPHQubGVuZ3RoO2UrKylQKHRbZV0pLHIrPW4rdFtlXTtyZXR1cm4gcn1yZXR1cm4gIiJ9KX0sdS50aWU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50aWVXaXRoKCIiKX0sdS50aW1lcz1mdW5jdGlvbihuLHQpe3ZhciByPXRoaXM7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg8MiYmKHQ9biksTyhuKSxPKHQpLGUoZnVuY3Rpb24oZSx1KXtmb3IodmFyIG89W10saT12b2lkIDAsYT12b2lkIDAsZj0wO2Y8bjtmKz0xKXtpZihhPUIoaT1yLl8oZSx1KSxhKSwhaS5zdGF0dXMpcmV0dXJuIGE7dT1pLmluZGV4LG8ucHVzaChpLnZhbHVlKTt9Zm9yKDtmPHQmJihhPUIoaT1yLl8oZSx1KSxhKSxpLnN0YXR1cyk7Zis9MSl1PWkuaW5kZXgsby5wdXNoKGkudmFsdWUpO3JldHVybiBCKGIodSxvKSxhKX0pfSx1LnJlc3VsdD1mdW5jdGlvbihuKXtyZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24oKXtyZXR1cm4gbn0pfSx1LmF0TW9zdD1mdW5jdGlvbihuKXtyZXR1cm4gdGhpcy50aW1lcygwLG4pfSx1LmF0TGVhc3Q9ZnVuY3Rpb24obil7cmV0dXJuIEoodGhpcy50aW1lcyhuKSx0aGlzLm1hbnkoKSxmdW5jdGlvbihuLHQpe3JldHVybiBuLmNvbmNhdCh0KX0pfSx1Lm1hcD1mdW5jdGlvbihuKXtrKG4pO3ZhciB0PXRoaXM7cmV0dXJuIGUoZnVuY3Rpb24ocixlKXt2YXIgdT10Ll8ocixlKTtyZXR1cm4gdS5zdGF0dXM/QihiKHUuaW5kZXgsbih1LnZhbHVlKSksdSk6dX0pfSx1LmNvbnRyYW1hcD1mdW5jdGlvbihuKXtrKG4pO3ZhciB0PXRoaXM7cmV0dXJuIGUoZnVuY3Rpb24ocixlKXt2YXIgdT10LnBhcnNlKG4oci5zbGljZShlKSkpO3JldHVybiB1LnN0YXR1cz9iKGUrci5sZW5ndGgsdS52YWx1ZSk6dX0pfSx1LnByb21hcD1mdW5jdGlvbihuLHQpe3JldHVybiBrKG4pLGsodCksdGhpcy5jb250cmFtYXAobikubWFwKHQpfSx1LnNraXA9ZnVuY3Rpb24obil7cmV0dXJuIEModGhpcyxuKS5tYXAoZnVuY3Rpb24obil7cmV0dXJuIG5bMF19KX0sdS5tYXJrPWZ1bmN0aW9uKCl7cmV0dXJuIEooZW4sdGhpcyxlbixmdW5jdGlvbihuLHQscil7cmV0dXJuIHtzdGFydDpuLHZhbHVlOnQsZW5kOnJ9fSl9LHUubm9kZT1mdW5jdGlvbihuKXtyZXR1cm4gSihlbix0aGlzLGVuLGZ1bmN0aW9uKHQscixlKXtyZXR1cm4ge25hbWU6bix2YWx1ZTpyLHN0YXJ0OnQsZW5kOmV9fSl9LHUuc2VwQnk9ZnVuY3Rpb24obil7cmV0dXJuIFYodGhpcyxuKX0sdS5zZXBCeTE9ZnVuY3Rpb24obil7cmV0dXJuIEgodGhpcyxuKX0sdS5sb29rYWhlYWQ9ZnVuY3Rpb24obil7cmV0dXJuIHRoaXMuc2tpcChaKG4pKX0sdS5ub3RGb2xsb3dlZEJ5PWZ1bmN0aW9uKG4pe3JldHVybiB0aGlzLnNraXAoJChuKSl9LHUuZGVzYz1mdW5jdGlvbihuKXtFKG4pfHwobj1bbl0pO3ZhciB0PXRoaXM7cmV0dXJuIGUoZnVuY3Rpb24ocixlKXt2YXIgdT10Ll8ocixlKTtyZXR1cm4gdS5zdGF0dXN8fCh1LmV4cGVjdGVkPW4pLHV9KX0sdS5mYWxsYmFjaz1mdW5jdGlvbihuKXtyZXR1cm4gdGhpcy5vcihYKG4pKX0sdS5hcD1mdW5jdGlvbihuKXtyZXR1cm4gSihuLHRoaXMsZnVuY3Rpb24obix0KXtyZXR1cm4gbih0KX0pfSx1LmNoYWluPWZ1bmN0aW9uKG4pe3ZhciB0PXRoaXM7cmV0dXJuIGUoZnVuY3Rpb24ocixlKXt2YXIgdT10Ll8ocixlKTtyZXR1cm4gdS5zdGF0dXM/QihuKHUudmFsdWUpLl8ocix1LmluZGV4KSx1KTp1fSl9LHUuY29uY2F0PXUub3IsdS5lbXB0eT1ybix1Lm9mPVgsdVsiZmFudGFzeS1sYW5kL2FwIl09dS5hcCx1WyJmYW50YXN5LWxhbmQvY2hhaW4iXT11LmNoYWluLHVbImZhbnRhc3ktbGFuZC9jb25jYXQiXT11LmNvbmNhdCx1WyJmYW50YXN5LWxhbmQvZW1wdHkiXT11LmVtcHR5LHVbImZhbnRhc3ktbGFuZC9vZiJdPXUub2YsdVsiZmFudGFzeS1sYW5kL21hcCJdPXUubWFwO3ZhciBlbj1lKGZ1bmN0aW9uKG4sdCl7cmV0dXJuIGIodCxTKG4sdCkpfSksdW49ZShmdW5jdGlvbihuLHQpe3JldHVybiB0Pj1uLmxlbmd0aD94KHQsImFueSBjaGFyYWN0ZXIvYnl0ZSIpOmIodCsxLEwobix0KSl9KSxvbj1lKGZ1bmN0aW9uKG4sdCl7cmV0dXJuIGIobi5sZW5ndGgsbi5zbGljZSh0KSl9KSxhbj1lKGZ1bmN0aW9uKG4sdCl7cmV0dXJuIHQ8bi5sZW5ndGg/eCh0LCJFT0YiKTpiKHQsbnVsbCl9KSxmbj1RKC9bMC05XS8pLmRlc2MoImEgZGlnaXQiKSxjbj1RKC9bMC05XSovKS5kZXNjKCJvcHRpb25hbCBkaWdpdHMiKSxzbj1RKC9bYS16XS9pKS5kZXNjKCJhIGxldHRlciIpLGxuPVEoL1thLXpdKi9pKS5kZXNjKCJvcHRpb25hbCBsZXR0ZXJzIiksaG49USgvXHMqLykuZGVzYygib3B0aW9uYWwgd2hpdGVzcGFjZSIpLHBuPVEoL1xzKy8pLmRlc2MoIndoaXRlc3BhY2UiKSxkbj1LKCJcciIpLHZuPUsoIlxuIiksZ249SygiXHJcbiIpLG1uPVQoZ24sdm4sZG4pLmRlc2MoIm5ld2xpbmUiKSx5bj1UKG1uLGFuKTtlLmFsbD1vbixlLmFsdD1ULGUuYW55PXVuLGUuY3I9ZG4sZS5jcmVhdGVMYW5ndWFnZT1mdW5jdGlvbihuKXt2YXIgdD17fTtmb3IodmFyIHIgaW4gbikoe30pLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmZnVuY3Rpb24ocil7dFtyXT10bihmdW5jdGlvbigpe3JldHVybiBuW3JdKHQpfSk7fShyKTtyZXR1cm4gdH0sZS5jcmxmPWduLGUuY3VzdG9tPWZ1bmN0aW9uKG4pe3JldHVybiBlKG4oYix4KSl9LGUuZGlnaXQ9Zm4sZS5kaWdpdHM9Y24sZS5lbXB0eT1ybixlLmVuZD15bixlLmVvZj1hbixlLmZhaWw9WSxlLmZvcm1hdEVycm9yPU4sZS5pbmRleD1lbixlLmlzUGFyc2VyPXksZS5sYXp5PXRuLGUubGV0dGVyPXNuLGUubGV0dGVycz1sbixlLmxmPXZuLGUubG9va2FoZWFkPVosZS5tYWtlRmFpbHVyZT14LGUubWFrZVN1Y2Nlc3M9YixlLm5ld2xpbmU9bW4sZS5ub25lT2Y9ZnVuY3Rpb24obil7cmV0dXJuIG5uKGZ1bmN0aW9uKHQpe3JldHVybiBuLmluZGV4T2YodCk8MH0pLmRlc2MoIm5vbmUgb2YgJyIrbisiJyIpfSxlLm5vdEZvbGxvd2VkQnk9JCxlLm9mPVgsZS5vbmVPZj1mdW5jdGlvbihuKXtmb3IodmFyIHQ9bi5zcGxpdCgiIikscj0wO3I8dC5sZW5ndGg7cisrKXRbcl09IiciK3Rbcl0rIiciO3JldHVybiBubihmdW5jdGlvbih0KXtyZXR1cm4gbi5pbmRleE9mKHQpPj0wfSkuZGVzYyh0KX0sZS5vcHRXaGl0ZXNwYWNlPWhuLGUuUGFyc2VyPWUsZS5yYW5nZT1mdW5jdGlvbihuLHQpe3JldHVybiBubihmdW5jdGlvbihyKXtyZXR1cm4gbjw9ciYmcjw9dH0pLmRlc2MobisiLSIrdCl9LGUucmVnZXg9USxlLnJlZ2V4cD1RLGUuc2VwQnk9VixlLnNlcEJ5MT1ILGUuc2VxPUMsZS5zZXFNYXA9SixlLnNlcU9iaj1mdW5jdGlvbigpe2Zvcih2YXIgbix0PXt9LHI9MCx1PShuPWFyZ3VtZW50cyxBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChuKSksbz11Lmxlbmd0aCxpPTA7aTxvO2krPTEpe3ZhciBhPXVbaV07aWYoIXkoYSkpe2lmKEUoYSkmJjI9PT1hLmxlbmd0aCYmInN0cmluZyI9PXR5cGVvZiBhWzBdJiZ5KGFbMV0pKXt2YXIgZj1hWzBdO2lmKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGYpKXRocm93IG5ldyBFcnJvcigic2VxT2JqOiBkdXBsaWNhdGUga2V5ICIrZik7dFtmXT0hMCxyKys7Y29udGludWV9dGhyb3cgbmV3IEVycm9yKCJzZXFPYmogYXJndW1lbnRzIG11c3QgYmUgcGFyc2VycyBvciBbc3RyaW5nLCBwYXJzZXJdIGFycmF5IHBhaXJzLiIpfX1pZigwPT09cil0aHJvdyBuZXcgRXJyb3IoInNlcU9iaiBleHBlY3RzIGF0IGxlYXN0IG9uZSBuYW1lZCBwYXJzZXIsIGZvdW5kIHplcm8iKTtyZXR1cm4gZShmdW5jdGlvbihuLHQpe2Zvcih2YXIgcixlPXt9LGk9MDtpPG87aSs9MSl7dmFyIGEsZjtpZihFKHVbaV0pPyhhPXVbaV1bMF0sZj11W2ldWzFdKTooYT1udWxsLGY9dVtpXSksIShyPUIoZi5fKG4sdCkscikpLnN0YXR1cylyZXR1cm4gcjthJiYoZVthXT1yLnZhbHVlKSx0PXIuaW5kZXg7fXJldHVybiBCKGIodCxlKSxyKX0pfSxlLnN0cmluZz1LLGUuc3VjY2VlZD1YLGUudGFrZVdoaWxlPWZ1bmN0aW9uKG4pe3JldHVybiBrKG4pLGUoZnVuY3Rpb24odCxyKXtmb3IodmFyIGU9cjtlPHQubGVuZ3RoJiZuKEwodCxlKSk7KWUrKztyZXR1cm4gYihlLHQuc2xpY2UocixlKSl9KX0sZS50ZXN0PW5uLGUud2hpdGVzcGFjZT1wbixlWyJmYW50YXN5LWxhbmQvZW1wdHkiXT1ybixlWyJmYW50YXN5LWxhbmQvb2YiXT1YLGUuQmluYXJ5PXtiaXRTZXE6bCxiaXRTZXFPYmo6ZnVuY3Rpb24obil7cygpO3ZhciB0PXt9LHI9MCxlPWEoZnVuY3Rpb24obil7aWYoRShuKSl7dmFyIGU9bjtpZigyIT09ZS5sZW5ndGgpdGhyb3cgbmV3IEVycm9yKCJbIitlLmpvaW4oIiwgIikrIl0gc2hvdWxkIGJlIGxlbmd0aCAyLCBnb3QgbGVuZ3RoICIrZS5sZW5ndGgpO2lmKFAoZVswXSksTyhlWzFdKSxPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxlWzBdKSl0aHJvdyBuZXcgRXJyb3IoImR1cGxpY2F0ZSBrZXkgaW4gYml0U2VxT2JqOiAiK2VbMF0pO3JldHVybiB0W2VbMF1dPSEwLHIrKyxlfXJldHVybiBPKG4pLFtudWxsLG5dfSxuKTtpZihyPDEpdGhyb3cgbmV3IEVycm9yKCJiaXRTZXFPYmogZXhwZWN0cyBhdCBsZWFzdCBvbmUgbmFtZWQgcGFpciwgZ290IFsiK24uam9pbigiLCAiKSsiXSIpO3ZhciB1PWEoZnVuY3Rpb24obil7cmV0dXJuIG5bMF19LGUpO3JldHVybiBsKGEoZnVuY3Rpb24obil7cmV0dXJuIG5bMV19LGUpKS5tYXAoZnVuY3Rpb24obil7cmV0dXJuIGkoZnVuY3Rpb24obix0KXtyZXR1cm4gbnVsbCE9PXRbMF0mJihuW3RbMF1dPXRbMV0pLG59LHt9LGEoZnVuY3Rpb24odCxyKXtyZXR1cm4gW3QsbltyXV19LHUpKX0pfSxieXRlOmZ1bmN0aW9uKG4pe2lmKHMoKSxPKG4pLG4+MjU1KXRocm93IG5ldyBFcnJvcigiVmFsdWUgc3BlY2lmaWVkIHRvIGJ5dGUgY29uc3RydWN0b3IgKCIrbisiPTB4IituLnRvU3RyaW5nKDE2KSsiKSBpcyBsYXJnZXIgaW4gdmFsdWUgdGhhbiBhIHNpbmdsZSBieXRlLiIpO3ZhciB0PShuPjE1PyIweCI6IjB4MCIpK24udG9TdHJpbmcoMTYpO3JldHVybiBlKGZ1bmN0aW9uKHIsZSl7dmFyIHU9TChyLGUpO3JldHVybiB1PT09bj9iKGUrMSx1KTp4KGUsdCl9KX0sYnVmZmVyOmZ1bmN0aW9uKG4pe3JldHVybiBoKCJidWZmZXIiLG4pLm1hcChmdW5jdGlvbihuKXtyZXR1cm4gQnVmZmVyLmZyb20obil9KX0sZW5jb2RlZFN0cmluZzpmdW5jdGlvbihuLHQpe3JldHVybiBoKCJzdHJpbmciLHQpLm1hcChmdW5jdGlvbih0KXtyZXR1cm4gdC50b1N0cmluZyhuKX0pfSx1aW50QkU6ZCx1aW50OEJFOmQoMSksdWludDE2QkU6ZCgyKSx1aW50MzJCRTpkKDQpLHVpbnRMRTp2LHVpbnQ4TEU6digxKSx1aW50MTZMRTp2KDIpLHVpbnQzMkxFOnYoNCksaW50QkU6ZyxpbnQ4QkU6ZygxKSxpbnQxNkJFOmcoMiksaW50MzJCRTpnKDQpLGludExFOm0saW50OExFOm0oMSksaW50MTZMRTptKDIpLGludDMyTEU6bSg0KSxmbG9hdEJFOmgoImZsb2F0QkUiLDQpLm1hcChmdW5jdGlvbihuKXtyZXR1cm4gbi5yZWFkRmxvYXRCRSgwKX0pLGZsb2F0TEU6aCgiZmxvYXRMRSIsNCkubWFwKGZ1bmN0aW9uKG4pe3JldHVybiBuLnJlYWRGbG9hdExFKDApfSksZG91YmxlQkU6aCgiZG91YmxlQkUiLDgpLm1hcChmdW5jdGlvbihuKXtyZXR1cm4gbi5yZWFkRG91YmxlQkUoMCl9KSxkb3VibGVMRTpoKCJkb3VibGVMRSIsOCkubWFwKGZ1bmN0aW9uKG4pe3JldHVybiBuLnJlYWREb3VibGVMRSgwKX0pfSxuLmV4cG9ydHM9ZTt9XSl9KTsgCiAgfSAocGFyc2ltbW9uX3VtZF9taW4sIHBhcnNpbW1vbl91bWRfbWluLmV4cG9ydHMpKTsKCiAgdmFyIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cyA9IHBhcnNpbW1vbl91bWRfbWluLmV4cG9ydHM7CgogIHZhciBlbW9qaVJlZ2V4ID0gKCkgPT4gewogIAkvLyBodHRwczovL210aHMuYmUvZW1vamkKICAJcmV0dXJuIC9bIyowLTldXHVGRTBGP1x1MjBFM3xbXHhBOVx4QUVcdTIwM0NcdTIwNDlcdTIxMjJcdTIxMzlcdTIxOTQtXHUyMTk5XHUyMUE5XHUyMUFBXHUyMzFBXHUyMzFCXHUyMzI4XHUyM0NGXHUyM0VELVx1MjNFRlx1MjNGMVx1MjNGMlx1MjNGOC1cdTIzRkFcdTI0QzJcdTI1QUFcdTI1QUJcdTI1QjZcdTI1QzBcdTI1RkJcdTI1RkNcdTI1RkVcdTI2MDAtXHUyNjA0XHUyNjBFXHUyNjExXHUyNjE0XHUyNjE1XHUyNjE4XHUyNjIwXHUyNjIyXHUyNjIzXHUyNjI2XHUyNjJBXHUyNjJFXHUyNjJGXHUyNjM4LVx1MjYzQVx1MjY0MFx1MjY0Mlx1MjY0OC1cdTI2NTNcdTI2NUZcdTI2NjBcdTI2NjNcdTI2NjVcdTI2NjZcdTI2NjhcdTI2N0JcdTI2N0VcdTI2N0ZcdTI2OTJcdTI2OTQtXHUyNjk3XHUyNjk5XHUyNjlCXHUyNjlDXHUyNkEwXHUyNkE3XHUyNkFBXHUyNkIwXHUyNkIxXHUyNkJEXHUyNkJFXHUyNkM0XHUyNkM4XHUyNkNGXHUyNkQxXHUyNkQzXHUyNkU5XHUyNkYwLVx1MjZGNVx1MjZGN1x1MjZGOFx1MjZGQVx1MjcwMlx1MjcwOFx1MjcwOVx1MjcwRlx1MjcxMlx1MjcxNFx1MjcxNlx1MjcxRFx1MjcyMVx1MjczM1x1MjczNFx1Mjc0NFx1Mjc0N1x1Mjc1N1x1Mjc2M1x1MjdBMVx1MjkzNFx1MjkzNVx1MkIwNS1cdTJCMDdcdTJCMUJcdTJCMUNcdTJCNTVcdTMwMzBcdTMwM0RcdTMyOTdcdTMyOTldXHVGRTBGP3xbXHUyNjFEXHUyNzBDXHUyNzBEXSg/Olx1RkUwRnxcdUQ4M0NbXHVERkZCLVx1REZGRl0pP3xbXHUyNzBBXHUyNzBCXSg/Olx1RDgzQ1tcdURGRkItXHVERkZGXSk/fFtcdTIzRTktXHUyM0VDXHUyM0YwXHUyM0YzXHUyNUZEXHUyNjkzXHUyNkExXHUyNkFCXHUyNkM1XHUyNkNFXHUyNkQ0XHUyNkVBXHUyNkZEXHUyNzA1XHUyNzI4XHUyNzRDXHUyNzRFXHUyNzUzLVx1Mjc1NVx1Mjc5NS1cdTI3OTdcdTI3QjBcdTI3QkZcdTJCNTBdfFx1MjZGOSg/Olx1RkUwRnxcdUQ4M0NbXHVERkZCLVx1REZGRl0pPyg/Olx1MjAwRFtcdTI2NDBcdTI2NDJdXHVGRTBGPyk/fFx1Mjc2NFx1RkUwRj8oPzpcdTIwMEQoPzpcdUQ4M0RcdUREMjV8XHVEODNFXHVERTc5KSk/fFx1RDgzQyg/OltcdURDMDRcdURENzBcdURENzFcdUREN0VcdUREN0ZcdURFMDJcdURFMzdcdURGMjFcdURGMjQtXHVERjJDXHVERjM2XHVERjdEXHVERjk2XHVERjk3XHVERjk5LVx1REY5Qlx1REY5RVx1REY5Rlx1REZDRFx1REZDRVx1REZENC1cdURGREZcdURGRjVcdURGRjddXHVGRTBGP3xbXHVERjg1XHVERkMyXHVERkM3XSg/Olx1RDgzQ1tcdURGRkItXHVERkZGXSk/fFtcdURGQzNcdURGQzRcdURGQ0FdKD86XHVEODNDW1x1REZGQi1cdURGRkZdKT8oPzpcdTIwMERbXHUyNjQwXHUyNjQyXVx1RkUwRj8pP3xbXHVERkNCXHVERkNDXSg/Olx1RkUwRnxcdUQ4M0NbXHVERkZCLVx1REZGRl0pPyg/Olx1MjAwRFtcdTI2NDBcdTI2NDJdXHVGRTBGPyk/fFtcdURDQ0ZcdUREOEVcdUREOTEtXHVERDlBXHVERTAxXHVERTFBXHVERTJGXHVERTMyLVx1REUzNlx1REUzOC1cdURFM0FcdURFNTBcdURFNTFcdURGMDAtXHVERjIwXHVERjJELVx1REYzNVx1REYzNy1cdURGN0NcdURGN0UtXHVERjg0XHVERjg2LVx1REY5M1x1REZBMC1cdURGQzFcdURGQzVcdURGQzZcdURGQzhcdURGQzlcdURGQ0YtXHVERkQzXHVERkUwLVx1REZGMFx1REZGOC1cdURGRkZdfFx1RERFNlx1RDgzQ1tcdURERTgtXHVEREVDXHVEREVFXHVEREYxXHVEREYyXHVEREY0XHVEREY2LVx1RERGQVx1RERGQ1x1RERGRFx1RERGRl18XHVEREU3XHVEODNDW1x1RERFNlx1RERFN1x1RERFOS1cdURERUZcdURERjEtXHVEREY0XHVEREY2LVx1RERGOVx1RERGQlx1RERGQ1x1RERGRVx1RERGRl18XHVEREU4XHVEODNDW1x1RERFNlx1RERFOFx1RERFOVx1RERFQi1cdURERUVcdURERjAtXHVEREY1XHVEREY3XHVEREZBLVx1RERGRl18XHVEREU5XHVEODNDW1x1RERFQVx1RERFQ1x1RERFRlx1RERGMFx1RERGMlx1RERGNFx1RERGRl18XHVEREVBXHVEODNDW1x1RERFNlx1RERFOFx1RERFQVx1RERFQ1x1RERFRFx1RERGNy1cdURERkFdfFx1RERFQlx1RDgzQ1tcdURERUUtXHVEREYwXHVEREYyXHVEREY0XHVEREY3XXxcdURERUNcdUQ4M0NbXHVEREU2XHVEREU3XHVEREU5LVx1RERFRVx1RERGMS1cdURERjNcdURERjUtXHVEREZBXHVEREZDXHVEREZFXXxcdURERURcdUQ4M0NbXHVEREYwXHVEREYyXHVEREYzXHVEREY3XHVEREY5XHVEREZBXXxcdURERUVcdUQ4M0NbXHVEREU4LVx1RERFQVx1RERGMS1cdURERjRcdURERjYtXHVEREY5XXxcdURERUZcdUQ4M0NbXHVEREVBXHVEREYyXHVEREY0XHVEREY1XXxcdURERjBcdUQ4M0NbXHVEREVBXHVEREVDLVx1RERFRVx1RERGMlx1RERGM1x1RERGNVx1RERGN1x1RERGQ1x1RERGRVx1RERGRl18XHVEREYxXHVEODNDW1x1RERFNi1cdURERThcdURERUVcdURERjBcdURERjctXHVEREZCXHVEREZFXXxcdURERjJcdUQ4M0NbXHVEREU2XHVEREU4LVx1RERFRFx1RERGMC1cdURERkZdfFx1RERGM1x1RDgzQ1tcdURERTZcdURERThcdURERUEtXHVEREVDXHVEREVFXHVEREYxXHVEREY0XHVEREY1XHVEREY3XHVEREZBXHVEREZGXXxcdURERjRcdUQ4M0NcdURERjJ8XHVEREY1XHVEODNDW1x1RERFNlx1RERFQS1cdURERURcdURERjAtXHVEREYzXHVEREY3LVx1RERGOVx1RERGQ1x1RERGRV18XHVEREY2XHVEODNDXHVEREU2fFx1RERGN1x1RDgzQ1tcdURERUFcdURERjRcdURERjhcdURERkFcdURERkNdfFx1RERGOFx1RDgzQ1tcdURERTYtXHVEREVBXHVEREVDLVx1RERGNFx1RERGNy1cdURERjlcdURERkJcdURERkQtXHVEREZGXXxcdURERjlcdUQ4M0NbXHVEREU2XHVEREU4XHVEREU5XHVEREVCLVx1RERFRFx1RERFRi1cdURERjRcdURERjdcdURERjlcdURERkJcdURERkNcdURERkZdfFx1RERGQVx1RDgzQ1tcdURERTZcdURERUNcdURERjJcdURERjNcdURERjhcdURERkVcdURERkZdfFx1RERGQlx1RDgzQ1tcdURERTZcdURERThcdURERUFcdURERUNcdURERUVcdURERjNcdURERkFdfFx1RERGQ1x1RDgzQ1tcdURERUJcdURERjhdfFx1RERGRFx1RDgzQ1x1RERGMHxcdURERkVcdUQ4M0NbXHVEREVBXHVEREY5XXxcdURERkZcdUQ4M0NbXHVEREU2XHVEREYyXHVEREZDXXxcdURGRjNcdUZFMEY/KD86XHUyMDBEKD86XHUyNkE3XHVGRTBGP3xcdUQ4M0NcdURGMDgpKT98XHVERkY0KD86XHUyMDBEXHUyNjIwXHVGRTBGP3xcdURCNDBcdURDNjdcdURCNDBcdURDNjJcdURCNDAoPzpcdURDNjVcdURCNDBcdURDNkVcdURCNDBcdURDNjd8XHVEQzczXHVEQjQwXHVEQzYzXHVEQjQwXHVEQzc0fFx1REM3N1x1REI0MFx1REM2Q1x1REI0MFx1REM3MylcdURCNDBcdURDN0YpPyl8XHVEODNEKD86W1x1REMwOFx1REMyNl0oPzpcdTIwMERcdTJCMUIpP3xbXHVEQzNGXHVEQ0ZEXHVERDQ5XHVERDRBXHVERDZGXHVERDcwXHVERDczXHVERDc2LVx1REQ3OVx1REQ4N1x1REQ4QS1cdUREOERcdUREQTVcdUREQThcdUREQjFcdUREQjJcdUREQkNcdUREQzItXHVEREM0XHVEREQxLVx1REREM1x1REREQy1cdUREREVcdURERTFcdURERTNcdURERThcdURERUZcdURERjNcdURERkFcdURFQ0JcdURFQ0QtXHVERUNGXHVERUUwLVx1REVFNVx1REVFOVx1REVGMFx1REVGM11cdUZFMEY/fFtcdURDNDJcdURDNDNcdURDNDYtXHVEQzUwXHVEQzY2XHVEQzY3XHVEQzZCLVx1REM2RFx1REM3Mlx1REM3NC1cdURDNzZcdURDNzhcdURDN0NcdURDODNcdURDODVcdURDOEZcdURDOTFcdURDQUFcdUREN0FcdUREOTVcdUREOTZcdURFNENcdURFNEZcdURFQzBcdURFQ0NdKD86XHVEODNDW1x1REZGQi1cdURGRkZdKT98W1x1REM2RVx1REM3MFx1REM3MVx1REM3M1x1REM3N1x1REM4MVx1REM4Mlx1REM4Nlx1REM4N1x1REU0NS1cdURFNDdcdURFNEJcdURFNERcdURFNEVcdURFQTNcdURFQjQtXHVERUI2XSg/Olx1RDgzQ1tcdURGRkItXHVERkZGXSk/KD86XHUyMDBEW1x1MjY0MFx1MjY0Ml1cdUZFMEY/KT98W1x1REQ3NFx1REQ5MF0oPzpcdUZFMEZ8XHVEODNDW1x1REZGQi1cdURGRkZdKT98W1x1REMwMC1cdURDMDdcdURDMDktXHVEQzE0XHVEQzE2LVx1REMyNVx1REMyNy1cdURDM0FcdURDM0MtXHVEQzNFXHVEQzQwXHVEQzQ0XHVEQzQ1XHVEQzUxLVx1REM2NVx1REM2QVx1REM3OS1cdURDN0JcdURDN0QtXHVEQzgwXHVEQzg0XHVEQzg4LVx1REM4RVx1REM5MFx1REM5Mi1cdURDQTlcdURDQUItXHVEQ0ZDXHVEQ0ZGLVx1REQzRFx1REQ0Qi1cdURENEVcdURENTAtXHVERDY3XHVEREE0XHVEREZCLVx1REUyRFx1REUyRi1cdURFMzRcdURFMzctXHVERTQ0XHVERTQ4LVx1REU0QVx1REU4MC1cdURFQTJcdURFQTQtXHVERUIzXHVERUI3LVx1REVCRlx1REVDMS1cdURFQzVcdURFRDAtXHVERUQyXHVERUQ1LVx1REVEN1x1REVEQy1cdURFREZcdURFRUJcdURFRUNcdURFRjQtXHVERUZDXHVERkUwLVx1REZFQlx1REZGMF18XHVEQzE1KD86XHUyMDBEXHVEODNFXHVEREJBKT98XHVEQzNCKD86XHUyMDBEXHUyNzQ0XHVGRTBGPyk/fFx1REM0MVx1RkUwRj8oPzpcdTIwMERcdUQ4M0RcdURERThcdUZFMEY/KT98XHVEQzY4KD86XHUyMDBEKD86W1x1MjY5NVx1MjY5Nlx1MjcwOF1cdUZFMEY/fFx1Mjc2NFx1RkUwRj9cdTIwMERcdUQ4M0QoPzpcdURDOEJcdTIwMERcdUQ4M0QpP1x1REM2OHxcdUQ4M0NbXHVERjNFXHVERjczXHVERjdDXHVERjkzXHVERkE0XHVERkE4XHVERkVCXHVERkVEXXxcdUQ4M0QoPzpbXHVEQzY4XHVEQzY5XVx1MjAwRFx1RDgzRCg/Olx1REM2Nig/Olx1MjAwRFx1RDgzRFx1REM2Nik/fFx1REM2Nyg/Olx1MjAwRFx1RDgzRFtcdURDNjZcdURDNjddKT8pfFtcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdfFx1REM2Nig/Olx1MjAwRFx1RDgzRFx1REM2Nik/fFx1REM2Nyg/Olx1MjAwRFx1RDgzRFtcdURDNjZcdURDNjddKT8pfFx1RDgzRVtcdUREQUYtXHVEREIzXHVEREJDXHVEREJEXSl8XHVEODNDKD86XHVERkZCKD86XHUyMDBEKD86W1x1MjY5NVx1MjY5Nlx1MjcwOF1cdUZFMEY/fFx1Mjc2NFx1RkUwRj9cdTIwMERcdUQ4M0QoPzpcdURDOEJcdTIwMERcdUQ4M0QpP1x1REM2OFx1RDgzQ1tcdURGRkItXHVERkZGXXxcdUQ4M0NbXHVERjNFXHVERjczXHVERjdDXHVERjkzXHVERkE0XHVERkE4XHVERkVCXHVERkVEXXxcdUQ4M0RbXHVEQ0JCXHVEQ0JDXHVERDI3XHVERDJDXHVERTgwXHVERTkyXXxcdUQ4M0UoPzpbXHVEREFGLVx1RERCM1x1RERCQ1x1RERCRF18XHVERDFEXHUyMDBEXHVEODNEXHVEQzY4XHVEODNDW1x1REZGQy1cdURGRkZdKSkpP3xcdURGRkMoPzpcdTIwMEQoPzpbXHUyNjk1XHUyNjk2XHUyNzA4XVx1RkUwRj98XHUyNzY0XHVGRTBGP1x1MjAwRFx1RDgzRCg/Olx1REM4Qlx1MjAwRFx1RDgzRCk/XHVEQzY4XHVEODNDW1x1REZGQi1cdURGRkZdfFx1RDgzQ1tcdURGM0VcdURGNzNcdURGN0NcdURGOTNcdURGQTRcdURGQThcdURGRUJcdURGRURdfFx1RDgzRFtcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdfFx1RDgzRSg/OltcdUREQUYtXHVEREIzXHVEREJDXHVEREJEXXxcdUREMURcdTIwMERcdUQ4M0RcdURDNjhcdUQ4M0NbXHVERkZCXHVERkZELVx1REZGRl0pKSk/fFx1REZGRCg/Olx1MjAwRCg/OltcdTI2OTVcdTI2OTZcdTI3MDhdXHVGRTBGP3xcdTI3NjRcdUZFMEY/XHUyMDBEXHVEODNEKD86XHVEQzhCXHUyMDBEXHVEODNEKT9cdURDNjhcdUQ4M0NbXHVERkZCLVx1REZGRl18XHVEODNDW1x1REYzRVx1REY3M1x1REY3Q1x1REY5M1x1REZBNFx1REZBOFx1REZFQlx1REZFRF18XHVEODNEW1x1RENCQlx1RENCQ1x1REQyN1x1REQyQ1x1REU4MFx1REU5Ml18XHVEODNFKD86W1x1RERBRi1cdUREQjNcdUREQkNcdUREQkRdfFx1REQxRFx1MjAwRFx1RDgzRFx1REM2OFx1RDgzQ1tcdURGRkJcdURGRkNcdURGRkVcdURGRkZdKSkpP3xcdURGRkUoPzpcdTIwMEQoPzpbXHUyNjk1XHUyNjk2XHUyNzA4XVx1RkUwRj98XHUyNzY0XHVGRTBGP1x1MjAwRFx1RDgzRCg/Olx1REM4Qlx1MjAwRFx1RDgzRCk/XHVEQzY4XHVEODNDW1x1REZGQi1cdURGRkZdfFx1RDgzQ1tcdURGM0VcdURGNzNcdURGN0NcdURGOTNcdURGQTRcdURGQThcdURGRUJcdURGRURdfFx1RDgzRFtcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdfFx1RDgzRSg/OltcdUREQUYtXHVEREIzXHVEREJDXHVEREJEXXxcdUREMURcdTIwMERcdUQ4M0RcdURDNjhcdUQ4M0NbXHVERkZCLVx1REZGRFx1REZGRl0pKSk/fFx1REZGRig/Olx1MjAwRCg/OltcdTI2OTVcdTI2OTZcdTI3MDhdXHVGRTBGP3xcdTI3NjRcdUZFMEY/XHUyMDBEXHVEODNEKD86XHVEQzhCXHUyMDBEXHVEODNEKT9cdURDNjhcdUQ4M0NbXHVERkZCLVx1REZGRl18XHVEODNDW1x1REYzRVx1REY3M1x1REY3Q1x1REY5M1x1REZBNFx1REZBOFx1REZFQlx1REZFRF18XHVEODNEW1x1RENCQlx1RENCQ1x1REQyN1x1REQyQ1x1REU4MFx1REU5Ml18XHVEODNFKD86W1x1RERBRi1cdUREQjNcdUREQkNcdUREQkRdfFx1REQxRFx1MjAwRFx1RDgzRFx1REM2OFx1RDgzQ1tcdURGRkItXHVERkZFXSkpKT8pKT98XHVEQzY5KD86XHUyMDBEKD86W1x1MjY5NVx1MjY5Nlx1MjcwOF1cdUZFMEY/fFx1Mjc2NFx1RkUwRj9cdTIwMERcdUQ4M0QoPzpcdURDOEJcdTIwMERcdUQ4M0QpP1tcdURDNjhcdURDNjldfFx1RDgzQ1tcdURGM0VcdURGNzNcdURGN0NcdURGOTNcdURGQTRcdURGQThcdURGRUJcdURGRURdfFx1RDgzRCg/OltcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdfFx1REM2Nig/Olx1MjAwRFx1RDgzRFx1REM2Nik/fFx1REM2Nyg/Olx1MjAwRFx1RDgzRFtcdURDNjZcdURDNjddKT98XHVEQzY5XHUyMDBEXHVEODNEKD86XHVEQzY2KD86XHUyMDBEXHVEODNEXHVEQzY2KT98XHVEQzY3KD86XHUyMDBEXHVEODNEW1x1REM2Nlx1REM2N10pPykpfFx1RDgzRVtcdUREQUYtXHVEREIzXHVEREJDXHVEREJEXSl8XHVEODNDKD86XHVERkZCKD86XHUyMDBEKD86W1x1MjY5NVx1MjY5Nlx1MjcwOF1cdUZFMEY/fFx1Mjc2NFx1RkUwRj9cdTIwMERcdUQ4M0QoPzpbXHVEQzY4XHVEQzY5XXxcdURDOEJcdTIwMERcdUQ4M0RbXHVEQzY4XHVEQzY5XSlcdUQ4M0NbXHVERkZCLVx1REZGRl18XHVEODNDW1x1REYzRVx1REY3M1x1REY3Q1x1REY5M1x1REZBNFx1REZBOFx1REZFQlx1REZFRF18XHVEODNEW1x1RENCQlx1RENCQ1x1REQyN1x1REQyQ1x1REU4MFx1REU5Ml18XHVEODNFKD86W1x1RERBRi1cdUREQjNcdUREQkNcdUREQkRdfFx1REQxRFx1MjAwRFx1RDgzRFtcdURDNjhcdURDNjldXHVEODNDW1x1REZGQy1cdURGRkZdKSkpP3xcdURGRkMoPzpcdTIwMEQoPzpbXHUyNjk1XHUyNjk2XHUyNzA4XVx1RkUwRj98XHUyNzY0XHVGRTBGP1x1MjAwRFx1RDgzRCg/OltcdURDNjhcdURDNjldfFx1REM4Qlx1MjAwRFx1RDgzRFtcdURDNjhcdURDNjldKVx1RDgzQ1tcdURGRkItXHVERkZGXXxcdUQ4M0NbXHVERjNFXHVERjczXHVERjdDXHVERjkzXHVERkE0XHVERkE4XHVERkVCXHVERkVEXXxcdUQ4M0RbXHVEQ0JCXHVEQ0JDXHVERDI3XHVERDJDXHVERTgwXHVERTkyXXxcdUQ4M0UoPzpbXHVEREFGLVx1RERCM1x1RERCQ1x1RERCRF18XHVERDFEXHUyMDBEXHVEODNEW1x1REM2OFx1REM2OV1cdUQ4M0NbXHVERkZCXHVERkZELVx1REZGRl0pKSk/fFx1REZGRCg/Olx1MjAwRCg/OltcdTI2OTVcdTI2OTZcdTI3MDhdXHVGRTBGP3xcdTI3NjRcdUZFMEY/XHUyMDBEXHVEODNEKD86W1x1REM2OFx1REM2OV18XHVEQzhCXHUyMDBEXHVEODNEW1x1REM2OFx1REM2OV0pXHVEODNDW1x1REZGQi1cdURGRkZdfFx1RDgzQ1tcdURGM0VcdURGNzNcdURGN0NcdURGOTNcdURGQTRcdURGQThcdURGRUJcdURGRURdfFx1RDgzRFtcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdfFx1RDgzRSg/OltcdUREQUYtXHVEREIzXHVEREJDXHVEREJEXXxcdUREMURcdTIwMERcdUQ4M0RbXHVEQzY4XHVEQzY5XVx1RDgzQ1tcdURGRkJcdURGRkNcdURGRkVcdURGRkZdKSkpP3xcdURGRkUoPzpcdTIwMEQoPzpbXHUyNjk1XHUyNjk2XHUyNzA4XVx1RkUwRj98XHUyNzY0XHVGRTBGP1x1MjAwRFx1RDgzRCg/OltcdURDNjhcdURDNjldfFx1REM4Qlx1MjAwRFx1RDgzRFtcdURDNjhcdURDNjldKVx1RDgzQ1tcdURGRkItXHVERkZGXXxcdUQ4M0NbXHVERjNFXHVERjczXHVERjdDXHVERjkzXHVERkE0XHVERkE4XHVERkVCXHVERkVEXXxcdUQ4M0RbXHVEQ0JCXHVEQ0JDXHVERDI3XHVERDJDXHVERTgwXHVERTkyXXxcdUQ4M0UoPzpbXHVEREFGLVx1RERCM1x1RERCQ1x1RERCRF18XHVERDFEXHUyMDBEXHVEODNEW1x1REM2OFx1REM2OV1cdUQ4M0NbXHVERkZCLVx1REZGRFx1REZGRl0pKSk/fFx1REZGRig/Olx1MjAwRCg/OltcdTI2OTVcdTI2OTZcdTI3MDhdXHVGRTBGP3xcdTI3NjRcdUZFMEY/XHUyMDBEXHVEODNEKD86W1x1REM2OFx1REM2OV18XHVEQzhCXHUyMDBEXHVEODNEW1x1REM2OFx1REM2OV0pXHVEODNDW1x1REZGQi1cdURGRkZdfFx1RDgzQ1tcdURGM0VcdURGNzNcdURGN0NcdURGOTNcdURGQTRcdURGQThcdURGRUJcdURGRURdfFx1RDgzRFtcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdfFx1RDgzRSg/OltcdUREQUYtXHVEREIzXHVEREJDXHVEREJEXXxcdUREMURcdTIwMERcdUQ4M0RbXHVEQzY4XHVEQzY5XVx1RDgzQ1tcdURGRkItXHVERkZFXSkpKT8pKT98XHVEQzZGKD86XHUyMDBEW1x1MjY0MFx1MjY0Ml1cdUZFMEY/KT98XHVERDc1KD86XHVGRTBGfFx1RDgzQ1tcdURGRkItXHVERkZGXSk/KD86XHUyMDBEW1x1MjY0MFx1MjY0Ml1cdUZFMEY/KT98XHVERTJFKD86XHUyMDBEXHVEODNEXHVEQ0E4KT98XHVERTM1KD86XHUyMDBEXHVEODNEXHVEQ0FCKT98XHVERTM2KD86XHUyMDBEXHVEODNDXHVERjJCXHVGRTBGPyk/KXxcdUQ4M0UoPzpbXHVERDBDXHVERDBGXHVERDE4LVx1REQxRlx1REQzMC1cdUREMzRcdUREMzZcdURENzdcdUREQjVcdUREQjZcdUREQkJcdURERDJcdURERDNcdURERDVcdURFQzMtXHVERUM1XHVERUYwXHVERUYyLVx1REVGOF0oPzpcdUQ4M0NbXHVERkZCLVx1REZGRl0pP3xbXHVERDI2XHVERDM1XHVERDM3LVx1REQzOVx1REQzRFx1REQzRVx1RERCOFx1RERCOVx1RERDRC1cdUREQ0ZcdURERDRcdURERDYtXHVEREREXSg/Olx1RDgzQ1tcdURGRkItXHVERkZGXSk/KD86XHUyMDBEW1x1MjY0MFx1MjY0Ml1cdUZFMEY/KT98W1x1RERERVx1RERERl0oPzpcdTIwMERbXHUyNjQwXHUyNjQyXVx1RkUwRj8pP3xbXHVERDBEXHVERDBFXHVERDEwLVx1REQxN1x1REQyMC1cdUREMjVcdUREMjctXHVERDJGXHVERDNBXHVERDNGLVx1REQ0NVx1REQ0Ny1cdURENzZcdURENzgtXHVEREI0XHVEREI3XHVEREJBXHVEREJDLVx1RERDQ1x1REREMFx1RERFMC1cdURERkZcdURFNzAtXHVERTdDXHVERTgwLVx1REU4OFx1REU5MC1cdURFQkRcdURFQkYtXHVERUMyXHVERUNFLVx1REVEQlx1REVFMC1cdURFRThdfFx1REQzQyg/Olx1MjAwRFtcdTI2NDBcdTI2NDJdXHVGRTBGP3xcdUQ4M0NbXHVERkZCLVx1REZGRl0pP3xcdURERDEoPzpcdTIwMEQoPzpbXHUyNjk1XHUyNjk2XHUyNzA4XVx1RkUwRj98XHVEODNDW1x1REYzRVx1REY3M1x1REY3Q1x1REY4NFx1REY5M1x1REZBNFx1REZBOFx1REZFQlx1REZFRF18XHVEODNEW1x1RENCQlx1RENCQ1x1REQyN1x1REQyQ1x1REU4MFx1REU5Ml18XHVEODNFKD86W1x1RERBRi1cdUREQjNcdUREQkNcdUREQkRdfFx1REQxRFx1MjAwRFx1RDgzRVx1REREMSkpfFx1RDgzQyg/Olx1REZGQig/Olx1MjAwRCg/OltcdTI2OTVcdTI2OTZcdTI3MDhdXHVGRTBGP3xcdTI3NjRcdUZFMEY/XHUyMDBEKD86XHVEODNEXHVEQzhCXHUyMDBEKT9cdUQ4M0VcdURERDFcdUQ4M0NbXHVERkZDLVx1REZGRl18XHVEODNDW1x1REYzRVx1REY3M1x1REY3Q1x1REY4NFx1REY5M1x1REZBNFx1REZBOFx1REZFQlx1REZFRF18XHVEODNEW1x1RENCQlx1RENCQ1x1REQyN1x1REQyQ1x1REU4MFx1REU5Ml18XHVEODNFKD86W1x1RERBRi1cdUREQjNcdUREQkNcdUREQkRdfFx1REQxRFx1MjAwRFx1RDgzRVx1REREMVx1RDgzQ1tcdURGRkItXHVERkZGXSkpKT98XHVERkZDKD86XHUyMDBEKD86W1x1MjY5NVx1MjY5Nlx1MjcwOF1cdUZFMEY/fFx1Mjc2NFx1RkUwRj9cdTIwMEQoPzpcdUQ4M0RcdURDOEJcdTIwMEQpP1x1RDgzRVx1REREMVx1RDgzQ1tcdURGRkJcdURGRkQtXHVERkZGXXxcdUQ4M0NbXHVERjNFXHVERjczXHVERjdDXHVERjg0XHVERjkzXHVERkE0XHVERkE4XHVERkVCXHVERkVEXXxcdUQ4M0RbXHVEQ0JCXHVEQ0JDXHVERDI3XHVERDJDXHVERTgwXHVERTkyXXxcdUQ4M0UoPzpbXHVEREFGLVx1RERCM1x1RERCQ1x1RERCRF18XHVERDFEXHUyMDBEXHVEODNFXHVEREQxXHVEODNDW1x1REZGQi1cdURGRkZdKSkpP3xcdURGRkQoPzpcdTIwMEQoPzpbXHUyNjk1XHUyNjk2XHUyNzA4XVx1RkUwRj98XHUyNzY0XHVGRTBGP1x1MjAwRCg/Olx1RDgzRFx1REM4Qlx1MjAwRCk/XHVEODNFXHVEREQxXHVEODNDW1x1REZGQlx1REZGQ1x1REZGRVx1REZGRl18XHVEODNDW1x1REYzRVx1REY3M1x1REY3Q1x1REY4NFx1REY5M1x1REZBNFx1REZBOFx1REZFQlx1REZFRF18XHVEODNEW1x1RENCQlx1RENCQ1x1REQyN1x1REQyQ1x1REU4MFx1REU5Ml18XHVEODNFKD86W1x1RERBRi1cdUREQjNcdUREQkNcdUREQkRdfFx1REQxRFx1MjAwRFx1RDgzRVx1REREMVx1RDgzQ1tcdURGRkItXHVERkZGXSkpKT98XHVERkZFKD86XHUyMDBEKD86W1x1MjY5NVx1MjY5Nlx1MjcwOF1cdUZFMEY/fFx1Mjc2NFx1RkUwRj9cdTIwMEQoPzpcdUQ4M0RcdURDOEJcdTIwMEQpP1x1RDgzRVx1REREMVx1RDgzQ1tcdURGRkItXHVERkZEXHVERkZGXXxcdUQ4M0NbXHVERjNFXHVERjczXHVERjdDXHVERjg0XHVERjkzXHVERkE0XHVERkE4XHVERkVCXHVERkVEXXxcdUQ4M0RbXHVEQ0JCXHVEQ0JDXHVERDI3XHVERDJDXHVERTgwXHVERTkyXXxcdUQ4M0UoPzpbXHVEREFGLVx1RERCM1x1RERCQ1x1RERCRF18XHVERDFEXHUyMDBEXHVEODNFXHVEREQxXHVEODNDW1x1REZGQi1cdURGRkZdKSkpP3xcdURGRkYoPzpcdTIwMEQoPzpbXHUyNjk1XHUyNjk2XHUyNzA4XVx1RkUwRj98XHUyNzY0XHVGRTBGP1x1MjAwRCg/Olx1RDgzRFx1REM4Qlx1MjAwRCk/XHVEODNFXHVEREQxXHVEODNDW1x1REZGQi1cdURGRkVdfFx1RDgzQ1tcdURGM0VcdURGNzNcdURGN0NcdURGODRcdURGOTNcdURGQTRcdURGQThcdURGRUJcdURGRURdfFx1RDgzRFtcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdfFx1RDgzRSg/OltcdUREQUYtXHVEREIzXHVEREJDXHVEREJEXXxcdUREMURcdTIwMERcdUQ4M0VcdURERDFcdUQ4M0NbXHVERkZCLVx1REZGRl0pKSk/KSk/fFx1REVGMSg/Olx1RDgzQyg/Olx1REZGQig/Olx1MjAwRFx1RDgzRVx1REVGMlx1RDgzQ1tcdURGRkMtXHVERkZGXSk/fFx1REZGQyg/Olx1MjAwRFx1RDgzRVx1REVGMlx1RDgzQ1tcdURGRkJcdURGRkQtXHVERkZGXSk/fFx1REZGRCg/Olx1MjAwRFx1RDgzRVx1REVGMlx1RDgzQ1tcdURGRkJcdURGRkNcdURGRkVcdURGRkZdKT98XHVERkZFKD86XHUyMDBEXHVEODNFXHVERUYyXHVEODNDW1x1REZGQi1cdURGRkRcdURGRkZdKT98XHVERkZGKD86XHUyMDBEXHVEODNFXHVERUYyXHVEODNDW1x1REZGQi1cdURGRkVdKT8pKT8pL2c7CiAgfTsKCiAgLyoqIE5vcm1hbGl6ZSBhIGR1cmF0aW9uIHRvIGFsbCBvZiB0aGUgcHJvcGVyIHVuaXRzLiAqLwogIGZ1bmN0aW9uIG5vcm1hbGl6ZUR1cmF0aW9uKGR1cikgewogICAgICBpZiAoZHVyID09PSB1bmRlZmluZWQgfHwgZHVyID09PSBudWxsKQogICAgICAgICAgcmV0dXJuIGR1cjsKICAgICAgcmV0dXJuIGR1ci5zaGlmdFRvQWxsKCkubm9ybWFsaXplKCk7CiAgfQogIC8qKiBTdHJpcCB0aGUgdGltZSBjb21wb25lbnRzIG9mIGEgZGF0ZSB0aW1lIG9iamVjdC4gKi8KICBmdW5jdGlvbiBzdHJpcFRpbWUoZHQpIHsKICAgICAgaWYgKGR0ID09PSBudWxsIHx8IGR0ID09PSB1bmRlZmluZWQpCiAgICAgICAgICByZXR1cm4gZHQ7CiAgICAgIHJldHVybiBEYXRlVGltZS5mcm9tT2JqZWN0KHsKICAgICAgICAgIHllYXI6IGR0LnllYXIsCiAgICAgICAgICBtb250aDogZHQubW9udGgsCiAgICAgICAgICBkYXk6IGR0LmRheSwKICAgICAgfSk7CiAgfQogIC8qKiBUcnkgdG8gZXh0cmFjdCBhIFlZWVlNTUREIGRhdGUgZnJvbSBhIHN0cmluZy4gKi8KICBmdW5jdGlvbiBleHRyYWN0RGF0ZShzdHIpIHsKICAgICAgbGV0IGRhdGVNYXRjaCA9IC8oXGR7NH0pLShcZHsyfSktKFxkezJ9KS8uZXhlYyhzdHIpOwogICAgICBpZiAoIWRhdGVNYXRjaCkKICAgICAgICAgIGRhdGVNYXRjaCA9IC8oXGR7NH0pKFxkezJ9KShcZHsyfSkvLmV4ZWMoc3RyKTsKICAgICAgaWYgKGRhdGVNYXRjaCkgewogICAgICAgICAgbGV0IHllYXIgPSBOdW1iZXIucGFyc2VJbnQoZGF0ZU1hdGNoWzFdKTsKICAgICAgICAgIGxldCBtb250aCA9IE51bWJlci5wYXJzZUludChkYXRlTWF0Y2hbMl0pOwogICAgICAgICAgbGV0IGRheSA9IE51bWJlci5wYXJzZUludChkYXRlTWF0Y2hbM10pOwogICAgICAgICAgcmV0dXJuIERhdGVUaW1lLmZyb21PYmplY3QoeyB5ZWFyLCBtb250aCwgZGF5IH0pOwogICAgICB9CiAgICAgIHJldHVybiB1bmRlZmluZWQ7CiAgfQogIC8qKiBHZXQgdGhlIGZvbGRlciBjb250YWluaW5nIHRoZSBnaXZlbiBwYXRoIChpLmUuLCBsaWtlIGNvbXB1dGluZyAncGF0aC8uLicpLiAqLwogIGZ1bmN0aW9uIGdldFBhcmVudEZvbGRlcihwYXRoKSB7CiAgICAgIHJldHVybiBwYXRoLnNwbGl0KCIvIikuc2xpY2UoMCwgLTEpLmpvaW4oIi8iKTsKICB9CiAgLyoqIEdldCB0aGUgInRpdGxlIiBmb3IgYSBmaWxlLCBieSBzdHJpcHBpbmcgb3RoZXIgcGFydHMgb2YgdGhlIHBhdGggYXMgd2VsbCBhcyB0aGUgZXh0ZW5zaW9uLiAqLwogIGZ1bmN0aW9uIGdldEZpbGVUaXRsZShwYXRoKSB7CiAgICAgIGlmIChwYXRoLmluY2x1ZGVzKCIvIikpCiAgICAgICAgICBwYXRoID0gcGF0aC5zdWJzdHJpbmcocGF0aC5sYXN0SW5kZXhPZigiLyIpICsgMSk7CiAgICAgIGlmIChwYXRoLmVuZHNXaXRoKCIubWQiKSkKICAgICAgICAgIHBhdGggPSBwYXRoLnN1YnN0cmluZygwLCBwYXRoLmxlbmd0aCAtIDMpOwogICAgICByZXR1cm4gcGF0aDsKICB9CiAgLyoqIEdldCB0aGUgZXh0ZW5zaW9uIG9mIGEgZmlsZSBmcm9tIHRoZSBmaWxlIHBhdGguICovCiAgZnVuY3Rpb24gZ2V0RXh0ZW5zaW9uKHBhdGgpIHsKICAgICAgaWYgKCFwYXRoLmluY2x1ZGVzKCIuIikpCiAgICAgICAgICByZXR1cm4gIiI7CiAgICAgIHJldHVybiBwYXRoLnN1YnN0cmluZyhwYXRoLmxhc3RJbmRleE9mKCIuIikgKyAxKTsKICB9CiAgLyoqIFBhcnNlIGFsbCBzdWJ0YWdzIG91dCBvZiB0aGUgZ2l2ZW4gdGFnLiBJLmUuLCAjaGVsbG8vaS9hbSB3b3VsZCB5aWVsZCBbI2hlbGxvL2kvYW0sICNoZWxsby9pLCAjaGVsbG9dLiAqLwogIGZ1bmN0aW9uIGV4dHJhY3RTdWJ0YWdzKHRhZykgewogICAgICBsZXQgcmVzdWx0ID0gW3RhZ107CiAgICAgIHdoaWxlICh0YWcuaW5jbHVkZXMoIi8iKSkgewogICAgICAgICAgdGFnID0gdGFnLnN1YnN0cmluZygwLCB0YWcubGFzdEluZGV4T2YoIi8iKSk7CiAgICAgICAgICByZXN1bHQucHVzaCh0YWcpOwogICAgICB9CiAgICAgIHJldHVybiByZXN1bHQ7CiAgfQogIC8qKiBBIHBhcnNpbW1vbiBwYXJzZXIgd2hpY2ggY2Fub25pY2FsaXplcyB2YXJpYWJsZSBuYW1lcyB3aGlsZSBwcm9wZXJseSByZXNwZWN0aW5nIGVtb2ppLiAqLwogIGNvbnN0IFZBUl9OQU1FX0NBTk9OSUNBTElaRVIgPSBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuYWx0KHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleChuZXcgUmVnRXhwKGVtb2ppUmVnZXgoKSwgIiIpKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4KC9bMC05XHB7TGV0dGVyfV8tXSsvdSkubWFwKHN0ciA9PiBzdHIudG9Mb2NhbGVMb3dlckNhc2UoKSksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy53aGl0ZXNwYWNlLm1hcChfID0+ICItIiksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbnkubWFwKF8gPT4gIiIpKQogICAgICAubWFueSgpCiAgICAgIC5tYXAocmVzdWx0ID0+IHJlc3VsdC5qb2luKCIiKSk7CiAgLyoqIENvbnZlcnQgYW4gYXJiaXRyYXJ5IHZhcmlhYmxlIG5hbWUgaW50byBzb21ldGhpbmcgSlMvcXVlcnkgZnJpZW5kbHkuICovCiAgZnVuY3Rpb24gY2Fub25pY2FsaXplVmFyTmFtZShuYW1lKSB7CiAgICAgIHJldHVybiBWQVJfTkFNRV9DQU5PTklDQUxJWkVSLnRyeVBhcnNlKG5hbWUpOwogIH0KICBjb25zdCBIRUFERVJfQ0FOT05JQ0FMSVpFUiA9IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbHQocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4KG5ldyBSZWdFeHAoZW1vamlSZWdleCgpLCAiIikpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMucmVnZXgoL1swLTlccHtMZXR0ZXJ9Xy1dKy91KSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLndoaXRlc3BhY2UubWFwKF8gPT4gIiAiKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLmFueS5tYXAoXyA9PiAiICIpKQogICAgICAubWFueSgpCiAgICAgIC5tYXAocmVzdWx0ID0+IHsKICAgICAgcmV0dXJuIHJlc3VsdC5qb2luKCIiKS5zcGxpdCgvXHMrLykuam9pbigiICIpLnRyaW0oKTsKICB9KTsKICAvKioKICAgKiBOb3JtYWxpemVzIHRoZSB0ZXh0IGluIGEgaGVhZGVyIHRvIGJlIHNvbWV0aGluZyB0aGF0IGlzIGFjdHVhbGx5IGxpbmthYmxlIHRvLiBUaGlzIG1pbWljcwogICAqIGhvdyBPYnNpZGlhbiBkb2VzIGl0J3Mgbm9ybWFsaXphdGlvbiwgY29sbGFwc2luZyByZXBlYXRlZCBzcGFjZXMgYW5kIHN0cmlwcGluZyBvdXQgY29udHJvbCBjaGFyYWN0ZXJzLgogICAqLwogIGZ1bmN0aW9uIG5vcm1hbGl6ZUhlYWRlckZvckxpbmsoaGVhZGVyKSB7CiAgICAgIHJldHVybiBIRUFERVJfQ0FOT05JQ0FMSVpFUi50cnlQYXJzZShoZWFkZXIpOwogIH0KICAvKiogUmVuZGVyIGEgZHVyYXRpb24gaW4gYSBtaW5pbWFsIGZvcm1hdCB0byBzYXZlIHNwYWNlLiAqLwogIGZ1bmN0aW9uIHJlbmRlck1pbmltYWxEdXJhdGlvbihkdXIpIHsKICAgICAgZHVyID0gbm9ybWFsaXplRHVyYXRpb24oZHVyKTsKICAgICAgLy8gdG9IdW1hbiBvdXRwdXRzIHplcm8gcXVhbnRpdGllcyBlLmcuICIwIHNlY29uZHMiCiAgICAgIGR1ciA9IER1cmF0aW9uLmZyb21PYmplY3QoT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKGR1ci50b09iamVjdCgpKS5maWx0ZXIoKFssIHF1YW50aXR5XSkgPT4gcXVhbnRpdHkgIT0gMCkpKTsKICAgICAgcmV0dXJuIGR1ci50b0h1bWFuKCk7CiAgfQoKICB2YXIgVmFsdWVzOwogIChmdW5jdGlvbiAoVmFsdWVzKSB7CiAgICAgIC8qKiBDb252ZXJ0IGFuIGFyYml0cmFyeSB2YWx1ZSBpbnRvIGEgcmVhc29uYWJsZSwgTWFya2Rvd24tZnJpZW5kbHkgc3RyaW5nIGlmIHBvc3NpYmxlLiAqLwogICAgICBmdW5jdGlvbiB0b1N0cmluZyhmaWVsZCwgc2V0dGluZyA9IERFRkFVTFRfUVVFUllfU0VUVElOR1MsIHJlY3Vyc2l2ZSA9IGZhbHNlKSB7CiAgICAgICAgICBsZXQgd3JhcHBlZCA9IHdyYXBWYWx1ZShmaWVsZCk7CiAgICAgICAgICBpZiAoIXdyYXBwZWQpCiAgICAgICAgICAgICAgcmV0dXJuIHNldHRpbmcucmVuZGVyTnVsbEFzOwogICAgICAgICAgc3dpdGNoICh3cmFwcGVkLnR5cGUpIHsKICAgICAgICAgICAgICBjYXNlICJudWxsIjoKICAgICAgICAgICAgICAgICAgcmV0dXJuIHNldHRpbmcucmVuZGVyTnVsbEFzOwogICAgICAgICAgICAgIGNhc2UgInN0cmluZyI6CiAgICAgICAgICAgICAgICAgIHJldHVybiB3cmFwcGVkLnZhbHVlOwogICAgICAgICAgICAgIGNhc2UgIm51bWJlciI6CiAgICAgICAgICAgICAgY2FzZSAiYm9vbGVhbiI6CiAgICAgICAgICAgICAgICAgIHJldHVybiAiIiArIHdyYXBwZWQudmFsdWU7CiAgICAgICAgICAgICAgY2FzZSAiaHRtbCI6CiAgICAgICAgICAgICAgICAgIHJldHVybiB3cmFwcGVkLnZhbHVlLm91dGVySFRNTDsKICAgICAgICAgICAgICBjYXNlICJ3aWRnZXQiOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZS5tYXJrZG93bigpOwogICAgICAgICAgICAgIGNhc2UgImxpbmsiOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZS5tYXJrZG93bigpOwogICAgICAgICAgICAgIGNhc2UgImZ1bmN0aW9uIjoKICAgICAgICAgICAgICAgICAgcmV0dXJuICI8ZnVuY3Rpb24+IjsKICAgICAgICAgICAgICBjYXNlICJhcnJheSI6CiAgICAgICAgICAgICAgICAgIGxldCByZXN1bHQgPSAiIjsKICAgICAgICAgICAgICAgICAgaWYgKHJlY3Vyc2l2ZSkKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSAiWyI7CiAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSB3cmFwcGVkLnZhbHVlLm1hcChmID0+IHRvU3RyaW5nKGYsIHNldHRpbmcsIHRydWUpKS5qb2luKCIsICIpOwogICAgICAgICAgICAgICAgICBpZiAocmVjdXJzaXZlKQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ICs9ICJdIjsKICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgICAgICBjYXNlICJvYmplY3QiOgogICAgICAgICAgICAgICAgICByZXR1cm4gKCJ7ICIgKwogICAgICAgICAgICAgICAgICAgICAgT2JqZWN0LmVudHJpZXMod3JhcHBlZC52YWx1ZSkKICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKGUgPT4gZVswXSArICI6ICIgKyB0b1N0cmluZyhlWzFdLCBzZXR0aW5nLCB0cnVlKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAuam9pbigiLCAiKSArCiAgICAgICAgICAgICAgICAgICAgICAiIH0iKTsKICAgICAgICAgICAgICBjYXNlICJkYXRlIjoKICAgICAgICAgICAgICAgICAgaWYgKHdyYXBwZWQudmFsdWUuc2Vjb25kID09IDAgJiYgd3JhcHBlZC52YWx1ZS5ob3VyID09IDAgJiYgd3JhcHBlZC52YWx1ZS5taW51dGUgPT0gMCkgewogICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHdyYXBwZWQudmFsdWUudG9Gb3JtYXQoc2V0dGluZy5kZWZhdWx0RGF0ZUZvcm1hdCk7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgcmV0dXJuIHdyYXBwZWQudmFsdWUudG9Gb3JtYXQoc2V0dGluZy5kZWZhdWx0RGF0ZVRpbWVGb3JtYXQpOwogICAgICAgICAgICAgIGNhc2UgImR1cmF0aW9uIjoKICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlbmRlck1pbmltYWxEdXJhdGlvbih3cmFwcGVkLnZhbHVlKTsKICAgICAgICAgIH0KICAgICAgfQogICAgICBWYWx1ZXMudG9TdHJpbmcgPSB0b1N0cmluZzsKICAgICAgLyoqIFdyYXAgYSBsaXRlcmFsIHZhbHVlIHNvIHlvdSBjYW4gc3dpdGNoIG9uIGl0IGVhc2lseS4gKi8KICAgICAgZnVuY3Rpb24gd3JhcFZhbHVlKHZhbCkgewogICAgICAgICAgaWYgKGlzTnVsbCh2YWwpKQogICAgICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJudWxsIiwgdmFsdWU6IHZhbCB9OwogICAgICAgICAgZWxzZSBpZiAoaXNOdW1iZXIodmFsKSkKICAgICAgICAgICAgICByZXR1cm4geyB0eXBlOiAibnVtYmVyIiwgdmFsdWU6IHZhbCB9OwogICAgICAgICAgZWxzZSBpZiAoaXNTdHJpbmcodmFsKSkKICAgICAgICAgICAgICByZXR1cm4geyB0eXBlOiAic3RyaW5nIiwgdmFsdWU6IHZhbCB9OwogICAgICAgICAgZWxzZSBpZiAoaXNCb29sZWFuKHZhbCkpCiAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogImJvb2xlYW4iLCB2YWx1ZTogdmFsIH07CiAgICAgICAgICBlbHNlIGlmIChpc0R1cmF0aW9uKHZhbCkpCiAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogImR1cmF0aW9uIiwgdmFsdWU6IHZhbCB9OwogICAgICAgICAgZWxzZSBpZiAoaXNEYXRlKHZhbCkpCiAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogImRhdGUiLCB2YWx1ZTogdmFsIH07CiAgICAgICAgICBlbHNlIGlmIChpc1dpZGdldCh2YWwpKQogICAgICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJ3aWRnZXQiLCB2YWx1ZTogdmFsIH07CiAgICAgICAgICBlbHNlIGlmIChpc0FycmF5KHZhbCkpCiAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogImFycmF5IiwgdmFsdWU6IHZhbCB9OwogICAgICAgICAgZWxzZSBpZiAoaXNMaW5rKHZhbCkpCiAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogImxpbmsiLCB2YWx1ZTogdmFsIH07CiAgICAgICAgICBlbHNlIGlmIChpc0Z1bmN0aW9uKHZhbCkpCiAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogImZ1bmN0aW9uIiwgdmFsdWU6IHZhbCB9OwogICAgICAgICAgZWxzZSBpZiAoaXNIdG1sKHZhbCkpCiAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogImh0bWwiLCB2YWx1ZTogdmFsIH07CiAgICAgICAgICBlbHNlIGlmIChpc09iamVjdCh2YWwpKQogICAgICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJvYmplY3QiLCB2YWx1ZTogdmFsIH07CiAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgICAgfQogICAgICBWYWx1ZXMud3JhcFZhbHVlID0gd3JhcFZhbHVlOwogICAgICAvKiogUmVjdXJzaXZlbHkgbWFwIGNvbXBsZXggb2JqZWN0cyBhdCB0aGUgbGVhdmVzLiAqLwogICAgICBmdW5jdGlvbiBtYXBMZWF2ZXModmFsLCBmdW5jKSB7CiAgICAgICAgICBpZiAoaXNPYmplY3QodmFsKSkgewogICAgICAgICAgICAgIGxldCByZXN1bHQgPSB7fTsKICAgICAgICAgICAgICBmb3IgKGxldCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXModmFsKSkKICAgICAgICAgICAgICAgICAgcmVzdWx0W2tleV0gPSBtYXBMZWF2ZXModmFsdWUsIGZ1bmMpOwogICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIGlmIChpc0FycmF5KHZhbCkpIHsKICAgICAgICAgICAgICBsZXQgcmVzdWx0ID0gW107CiAgICAgICAgICAgICAgZm9yIChsZXQgdmFsdWUgb2YgdmFsKQogICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChtYXBMZWF2ZXModmFsdWUsIGZ1bmMpKTsKICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgcmV0dXJuIGZ1bmModmFsKTsKICAgICAgICAgIH0KICAgICAgfQogICAgICBWYWx1ZXMubWFwTGVhdmVzID0gbWFwTGVhdmVzOwogICAgICAvKiogQ29tcGFyZSB0d28gYXJiaXRyYXJ5IEphdmFTY3JpcHQgdmFsdWVzLiBQcm9kdWNlcyBhIHRvdGFsIG9yZGVyaW5nIG92ZXIgQU5ZIHBvc3NpYmxlIGRhdGF2aWV3IHZhbHVlLiAqLwogICAgICBmdW5jdGlvbiBjb21wYXJlVmFsdWUodmFsMSwgdmFsMiwgbGlua05vcm1hbGl6ZXIpIHsKICAgICAgICAgIC8vIEhhbmRsZSB1bmRlZmluZWQvbnVsbHMgZmlyc3QuCiAgICAgICAgICBpZiAodmFsMSA9PT0gdW5kZWZpbmVkKQogICAgICAgICAgICAgIHZhbDEgPSBudWxsOwogICAgICAgICAgaWYgKHZhbDIgPT09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICB2YWwyID0gbnVsbDsKICAgICAgICAgIGlmICh2YWwxID09PSBudWxsICYmIHZhbDIgPT09IG51bGwpCiAgICAgICAgICAgICAgcmV0dXJuIDA7CiAgICAgICAgICBlbHNlIGlmICh2YWwxID09PSBudWxsKQogICAgICAgICAgICAgIHJldHVybiAtMTsKICAgICAgICAgIGVsc2UgaWYgKHZhbDIgPT09IG51bGwpCiAgICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgICAvLyBBIG5vbi1udWxsIHZhbHVlIG5vdyB3aGljaCB3ZSBjYW4gd3JhcCAmIGNvbXBhcmUgb24uCiAgICAgICAgICBsZXQgd3JhcDEgPSB3cmFwVmFsdWUodmFsMSk7CiAgICAgICAgICBsZXQgd3JhcDIgPSB3cmFwVmFsdWUodmFsMik7CiAgICAgICAgICBpZiAod3JhcDEgPT09IHVuZGVmaW5lZCAmJiB3cmFwMiA9PT0gdW5kZWZpbmVkKQogICAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgZWxzZSBpZiAod3JhcDEgPT09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICByZXR1cm4gLTE7CiAgICAgICAgICBlbHNlIGlmICh3cmFwMiA9PT0gdW5kZWZpbmVkKQogICAgICAgICAgICAgIHJldHVybiAxOwogICAgICAgICAgLy8gU2hvcnQtY2lyY3VpdCBvbiBkaWZmZXJlbnQgdHlwZXMgb3Igb24gcmVmZXJlbmNlIGVxdWFsaXR5LgogICAgICAgICAgaWYgKHdyYXAxLnR5cGUgIT0gd3JhcDIudHlwZSkKICAgICAgICAgICAgICByZXR1cm4gd3JhcDEudHlwZS5sb2NhbGVDb21wYXJlKHdyYXAyLnR5cGUpOwogICAgICAgICAgaWYgKHdyYXAxLnZhbHVlID09PSB3cmFwMi52YWx1ZSkKICAgICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICAgIHN3aXRjaCAod3JhcDEudHlwZSkgewogICAgICAgICAgICAgIGNhc2UgInN0cmluZyI6CiAgICAgICAgICAgICAgICAgIHJldHVybiB3cmFwMS52YWx1ZS5sb2NhbGVDb21wYXJlKHdyYXAyLnZhbHVlKTsKICAgICAgICAgICAgICBjYXNlICJudW1iZXIiOgogICAgICAgICAgICAgICAgICBpZiAod3JhcDEudmFsdWUgPCB3cmFwMi52YWx1ZSkKICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAtMTsKICAgICAgICAgICAgICAgICAgZWxzZSBpZiAod3JhcDEudmFsdWUgPT0gd3JhcDIudmFsdWUpCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgICAgICAgY2FzZSAibnVsbCI6CiAgICAgICAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgICAgIGNhc2UgImJvb2xlYW4iOgogICAgICAgICAgICAgICAgICBpZiAod3JhcDEudmFsdWUgPT0gd3JhcDIudmFsdWUpCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHdyYXAxLnZhbHVlID8gMSA6IC0xOwogICAgICAgICAgICAgIGNhc2UgImxpbmsiOgogICAgICAgICAgICAgICAgICBsZXQgbGluazEgPSB3cmFwMS52YWx1ZTsKICAgICAgICAgICAgICAgICAgbGV0IGxpbmsyID0gd3JhcDIudmFsdWU7CiAgICAgICAgICAgICAgICAgIGxldCBub3JtYWxpemUgPSBsaW5rTm9ybWFsaXplciA/PyAoKHgpID0+IHgpOwogICAgICAgICAgICAgICAgICAvLyBXZSBjYW4ndCBjb21wYXJlIGJ5IGZpbGUgbmFtZSBvciBkaXNwbGF5LCBzaW5jZSB0aGF0IHdvdWxkIGJyZWFrIGxpbmsgZXF1YWxpdHkuIENvbXBhcmUgYnkgcGF0aC4KICAgICAgICAgICAgICAgICAgbGV0IHBhdGhDb21wYXJlID0gbm9ybWFsaXplKGxpbmsxLnBhdGgpLmxvY2FsZUNvbXBhcmUobm9ybWFsaXplKGxpbmsyLnBhdGgpKTsKICAgICAgICAgICAgICAgICAgaWYgKHBhdGhDb21wYXJlICE9IDApCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcGF0aENvbXBhcmU7CiAgICAgICAgICAgICAgICAgIC8vIFRoZW4gY29tcGFyZSBieSB0eXBlLgogICAgICAgICAgICAgICAgICBsZXQgdHlwZUNvbXBhcmUgPSBsaW5rMS50eXBlLmxvY2FsZUNvbXBhcmUobGluazIudHlwZSk7CiAgICAgICAgICAgICAgICAgIGlmICh0eXBlQ29tcGFyZSAhPSAwKQogICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHR5cGVDb21wYXJlOwogICAgICAgICAgICAgICAgICAvLyBUaGVuIGNvbXBhcmUgYnkgc3VicGF0aCBleGlzdGVuY2UuCiAgICAgICAgICAgICAgICAgIGlmIChsaW5rMS5zdWJwYXRoICYmICFsaW5rMi5zdWJwYXRoKQogICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgICAgICAgICAgIGlmICghbGluazEuc3VicGF0aCAmJiBsaW5rMi5zdWJwYXRoKQogICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIC0xOwogICAgICAgICAgICAgICAgICBpZiAoIWxpbmsxLnN1YnBhdGggJiYgIWxpbmsyLnN1YnBhdGgpCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICAgICAgICAgICAgLy8gU2luY2UgYm90aCBoYXZlIGEgc3VicGF0aCwgY29tcGFyZSBieSBzdWJwYXRoLgogICAgICAgICAgICAgICAgICByZXR1cm4gKGxpbmsxLnN1YnBhdGggPz8gIiIpLmxvY2FsZUNvbXBhcmUobGluazIuc3VicGF0aCA/PyAiIik7CiAgICAgICAgICAgICAgY2FzZSAiZGF0ZSI6CiAgICAgICAgICAgICAgICAgIHJldHVybiB3cmFwMS52YWx1ZSA8IHdyYXAyLnZhbHVlCiAgICAgICAgICAgICAgICAgICAgICA/IC0xCiAgICAgICAgICAgICAgICAgICAgICA6IHdyYXAxLnZhbHVlLmVxdWFscyh3cmFwMi52YWx1ZSkKICAgICAgICAgICAgICAgICAgICAgICAgICA/IDAKICAgICAgICAgICAgICAgICAgICAgICAgICA6IDE7CiAgICAgICAgICAgICAgY2FzZSAiZHVyYXRpb24iOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcDEudmFsdWUgPCB3cmFwMi52YWx1ZQogICAgICAgICAgICAgICAgICAgICAgPyAtMQogICAgICAgICAgICAgICAgICAgICAgOiB3cmFwMS52YWx1ZS5lcXVhbHMod3JhcDIudmFsdWUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgPyAwCiAgICAgICAgICAgICAgICAgICAgICAgICAgOiAxOwogICAgICAgICAgICAgIGNhc2UgImFycmF5IjoKICAgICAgICAgICAgICAgICAgbGV0IGYxID0gd3JhcDEudmFsdWU7CiAgICAgICAgICAgICAgICAgIGxldCBmMiA9IHdyYXAyLnZhbHVlOwogICAgICAgICAgICAgICAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgTWF0aC5taW4oZjEubGVuZ3RoLCBmMi5sZW5ndGgpOyBpbmRleCsrKSB7CiAgICAgICAgICAgICAgICAgICAgICBsZXQgY29tcCA9IGNvbXBhcmVWYWx1ZShmMVtpbmRleF0sIGYyW2luZGV4XSk7CiAgICAgICAgICAgICAgICAgICAgICBpZiAoY29tcCAhPSAwKQogICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjb21wOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIHJldHVybiBmMS5sZW5ndGggLSBmMi5sZW5ndGg7CiAgICAgICAgICAgICAgY2FzZSAib2JqZWN0IjoKICAgICAgICAgICAgICAgICAgbGV0IG8xID0gd3JhcDEudmFsdWU7CiAgICAgICAgICAgICAgICAgIGxldCBvMiA9IHdyYXAyLnZhbHVlOwogICAgICAgICAgICAgICAgICBsZXQgazEgPSBBcnJheS5mcm9tKE9iamVjdC5rZXlzKG8xKSk7CiAgICAgICAgICAgICAgICAgIGxldCBrMiA9IEFycmF5LmZyb20oT2JqZWN0LmtleXMobzIpKTsKICAgICAgICAgICAgICAgICAgazEuc29ydCgpOwogICAgICAgICAgICAgICAgICBrMi5zb3J0KCk7CiAgICAgICAgICAgICAgICAgIGxldCBrZXlDb21wYXJlID0gY29tcGFyZVZhbHVlKGsxLCBrMik7CiAgICAgICAgICAgICAgICAgIGlmIChrZXlDb21wYXJlICE9IDApCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ga2V5Q29tcGFyZTsKICAgICAgICAgICAgICAgICAgZm9yIChsZXQga2V5IG9mIGsxKSB7CiAgICAgICAgICAgICAgICAgICAgICBsZXQgY29tcCA9IGNvbXBhcmVWYWx1ZShvMVtrZXldLCBvMltrZXldKTsKICAgICAgICAgICAgICAgICAgICAgIGlmIChjb21wICE9IDApCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbXA7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgcmV0dXJuIDA7CiAgICAgICAgICAgICAgY2FzZSAid2lkZ2V0IjoKICAgICAgICAgICAgICBjYXNlICJodG1sIjoKICAgICAgICAgICAgICBjYXNlICJmdW5jdGlvbiI6CiAgICAgICAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgfQogICAgICB9CiAgICAgIFZhbHVlcy5jb21wYXJlVmFsdWUgPSBjb21wYXJlVmFsdWU7CiAgICAgIC8qKiBGaW5kIHRoZSBjb3JyZXNwb25kaW5nIERhdGF2ZWl3IHR5cGUgZm9yIGFuIGFyYml0cmFyeSB2YWx1ZS4gKi8KICAgICAgZnVuY3Rpb24gdHlwZU9mKHZhbCkgewogICAgICAgICAgcmV0dXJuIHdyYXBWYWx1ZSh2YWwpPy50eXBlOwogICAgICB9CiAgICAgIFZhbHVlcy50eXBlT2YgPSB0eXBlT2Y7CiAgICAgIC8qKiBEZXRlcm1pbmUgaWYgdGhlIGdpdmVuIHZhbHVlIGlzICJ0cnV0aHkiIChpLmUuLCBpcyBub24tbnVsbCBhbmQgaGFzIGRhdGEgaW4gaXQpLiAqLwogICAgICBmdW5jdGlvbiBpc1RydXRoeShmaWVsZCkgewogICAgICAgICAgbGV0IHdyYXBwZWQgPSB3cmFwVmFsdWUoZmllbGQpOwogICAgICAgICAgaWYgKCF3cmFwcGVkKQogICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgIHN3aXRjaCAod3JhcHBlZC50eXBlKSB7CiAgICAgICAgICAgICAgY2FzZSAibnVtYmVyIjoKICAgICAgICAgICAgICAgICAgcmV0dXJuIHdyYXBwZWQudmFsdWUgIT0gMDsKICAgICAgICAgICAgICBjYXNlICJzdHJpbmciOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZS5sZW5ndGggPiAwOwogICAgICAgICAgICAgIGNhc2UgImJvb2xlYW4iOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZTsKICAgICAgICAgICAgICBjYXNlICJsaW5rIjoKICAgICAgICAgICAgICAgICAgcmV0dXJuICEhd3JhcHBlZC52YWx1ZS5wYXRoOwogICAgICAgICAgICAgIGNhc2UgImRhdGUiOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZS50b01pbGxpcygpICE9IDA7CiAgICAgICAgICAgICAgY2FzZSAiZHVyYXRpb24iOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZS5hcygic2Vjb25kcyIpICE9IDA7CiAgICAgICAgICAgICAgY2FzZSAib2JqZWN0IjoKICAgICAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHdyYXBwZWQudmFsdWUpLmxlbmd0aCA+IDA7CiAgICAgICAgICAgICAgY2FzZSAiYXJyYXkiOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZS5sZW5ndGggPiAwOwogICAgICAgICAgICAgIGNhc2UgIm51bGwiOgogICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgY2FzZSAiaHRtbCI6CiAgICAgICAgICAgICAgY2FzZSAid2lkZ2V0IjoKICAgICAgICAgICAgICBjYXNlICJmdW5jdGlvbiI6CiAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgfQogICAgICB9CiAgICAgIFZhbHVlcy5pc1RydXRoeSA9IGlzVHJ1dGh5OwogICAgICAvKiogRGVlcCBjb3B5IGEgZmllbGQuICovCiAgICAgIGZ1bmN0aW9uIGRlZXBDb3B5KGZpZWxkKSB7CiAgICAgICAgICBpZiAoZmllbGQgPT09IG51bGwgfHwgZmllbGQgPT09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICByZXR1cm4gZmllbGQ7CiAgICAgICAgICBpZiAoVmFsdWVzLmlzQXJyYXkoZmllbGQpKSB7CiAgICAgICAgICAgICAgcmV0dXJuIFtdLmNvbmNhdChmaWVsZC5tYXAodiA9PiBkZWVwQ29weSh2KSkpOwogICAgICAgICAgfQogICAgICAgICAgZWxzZSBpZiAoVmFsdWVzLmlzT2JqZWN0KGZpZWxkKSkgewogICAgICAgICAgICAgIGxldCByZXN1bHQgPSB7fTsKICAgICAgICAgICAgICBmb3IgKGxldCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoZmllbGQpKQogICAgICAgICAgICAgICAgICByZXN1bHRba2V5XSA9IGRlZXBDb3B5KHZhbHVlKTsKICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgcmV0dXJuIGZpZWxkOwogICAgICAgICAgfQogICAgICB9CiAgICAgIFZhbHVlcy5kZWVwQ29weSA9IGRlZXBDb3B5OwogICAgICBmdW5jdGlvbiBpc1N0cmluZyh2YWwpIHsKICAgICAgICAgIHJldHVybiB0eXBlb2YgdmFsID09ICJzdHJpbmciOwogICAgICB9CiAgICAgIFZhbHVlcy5pc1N0cmluZyA9IGlzU3RyaW5nOwogICAgICBmdW5jdGlvbiBpc051bWJlcih2YWwpIHsKICAgICAgICAgIHJldHVybiB0eXBlb2YgdmFsID09ICJudW1iZXIiOwogICAgICB9CiAgICAgIFZhbHVlcy5pc051bWJlciA9IGlzTnVtYmVyOwogICAgICBmdW5jdGlvbiBpc0RhdGUodmFsKSB7CiAgICAgICAgICByZXR1cm4gdmFsIGluc3RhbmNlb2YgRGF0ZVRpbWU7CiAgICAgIH0KICAgICAgVmFsdWVzLmlzRGF0ZSA9IGlzRGF0ZTsKICAgICAgZnVuY3Rpb24gaXNEdXJhdGlvbih2YWwpIHsKICAgICAgICAgIHJldHVybiB2YWwgaW5zdGFuY2VvZiBEdXJhdGlvbjsKICAgICAgfQogICAgICBWYWx1ZXMuaXNEdXJhdGlvbiA9IGlzRHVyYXRpb247CiAgICAgIGZ1bmN0aW9uIGlzTnVsbCh2YWwpIHsKICAgICAgICAgIHJldHVybiB2YWwgPT09IG51bGwgfHwgdmFsID09PSB1bmRlZmluZWQ7CiAgICAgIH0KICAgICAgVmFsdWVzLmlzTnVsbCA9IGlzTnVsbDsKICAgICAgZnVuY3Rpb24gaXNBcnJheSh2YWwpIHsKICAgICAgICAgIHJldHVybiBBcnJheS5pc0FycmF5KHZhbCk7CiAgICAgIH0KICAgICAgVmFsdWVzLmlzQXJyYXkgPSBpc0FycmF5OwogICAgICBmdW5jdGlvbiBpc0Jvb2xlYW4odmFsKSB7CiAgICAgICAgICByZXR1cm4gdHlwZW9mIHZhbCA9PT0gImJvb2xlYW4iOwogICAgICB9CiAgICAgIFZhbHVlcy5pc0Jvb2xlYW4gPSBpc0Jvb2xlYW47CiAgICAgIGZ1bmN0aW9uIGlzTGluayh2YWwpIHsKICAgICAgICAgIHJldHVybiB2YWwgaW5zdGFuY2VvZiBMaW5rOwogICAgICB9CiAgICAgIFZhbHVlcy5pc0xpbmsgPSBpc0xpbms7CiAgICAgIGZ1bmN0aW9uIGlzV2lkZ2V0KHZhbCkgewogICAgICAgICAgcmV0dXJuIHZhbCBpbnN0YW5jZW9mIFdpZGdldDsKICAgICAgfQogICAgICBWYWx1ZXMuaXNXaWRnZXQgPSBpc1dpZGdldDsKICAgICAgZnVuY3Rpb24gaXNIdG1sKHZhbCkgewogICAgICAgICAgaWYgKHR5cGVvZiBIVE1MRWxlbWVudCAhPT0gInVuZGVmaW5lZCIpIHsKICAgICAgICAgICAgICByZXR1cm4gdmFsIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQ7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICB9CiAgICAgIH0KICAgICAgVmFsdWVzLmlzSHRtbCA9IGlzSHRtbDsKICAgICAgLyoqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gdmFsdWUgaXMgYW4gb2JqZWN0IChhbmQgbm90IGFueSBvdGhlciBkYXRhdmlldy1yZWNvZ25pemVkIG9iamVjdC1saWtlIHR5cGUpLiAqLwogICAgICBmdW5jdGlvbiBpc09iamVjdCh2YWwpIHsKICAgICAgICAgIHJldHVybiAodHlwZW9mIHZhbCA9PSAib2JqZWN0IiAmJgogICAgICAgICAgICAgICFpc0h0bWwodmFsKSAmJgogICAgICAgICAgICAgICFpc1dpZGdldCh2YWwpICYmCiAgICAgICAgICAgICAgIWlzQXJyYXkodmFsKSAmJgogICAgICAgICAgICAgICFpc0R1cmF0aW9uKHZhbCkgJiYKICAgICAgICAgICAgICAhaXNEYXRlKHZhbCkgJiYKICAgICAgICAgICAgICAhaXNMaW5rKHZhbCkgJiYKICAgICAgICAgICAgICB2YWwgIT09IHVuZGVmaW5lZCAmJgogICAgICAgICAgICAgICFpc051bGwodmFsKSk7CiAgICAgIH0KICAgICAgVmFsdWVzLmlzT2JqZWN0ID0gaXNPYmplY3Q7CiAgICAgIGZ1bmN0aW9uIGlzRnVuY3Rpb24odmFsKSB7CiAgICAgICAgICByZXR1cm4gdHlwZW9mIHZhbCA9PSAiZnVuY3Rpb24iOwogICAgICB9CiAgICAgIFZhbHVlcy5pc0Z1bmN0aW9uID0gaXNGdW5jdGlvbjsKICB9KShWYWx1ZXMgfHwgKFZhbHVlcyA9IHt9KSk7CiAgLy8vLy8vLy8vLy8vLy8vCiAgLy8gR3JvdXBpbmdzIC8vCiAgLy8vLy8vLy8vLy8vLy8vCiAgdmFyIEdyb3VwaW5nczsKICAoZnVuY3Rpb24gKEdyb3VwaW5ncykgewogICAgICAvKiogRGV0ZXJtaW5lcyBpZiB0aGUgZ2l2ZW4gZ3JvdXAgZW50cnkgaXMgYSBzdGFuZGFsb25lIHZhbHVlLCBvciBhIGdyb3VwaW5nIG9mIHN1Yi1lbnRyaWVzLiAqLwogICAgICBmdW5jdGlvbiBpc0VsZW1lbnRHcm91cChlbnRyeSkgewogICAgICAgICAgcmV0dXJuIFZhbHVlcy5pc09iamVjdChlbnRyeSkgJiYgT2JqZWN0LmtleXMoZW50cnkpLmxlbmd0aCA9PSAyICYmICJrZXkiIGluIGVudHJ5ICYmICJyb3dzIiBpbiBlbnRyeTsKICAgICAgfQogICAgICBHcm91cGluZ3MuaXNFbGVtZW50R3JvdXAgPSBpc0VsZW1lbnRHcm91cDsKICAgICAgLyoqIERldGVybWluZXMgaWYgdGhlIGdpdmVuIGFycmF5IGlzIGEgZ3JvdXBpbmcgYXJyYXkuICovCiAgICAgIGZ1bmN0aW9uIGlzR3JvdXBpbmcoZW50cnkpIHsKICAgICAgICAgIGZvciAobGV0IGVsZW1lbnQgb2YgZW50cnkpCiAgICAgICAgICAgICAgaWYgKCFpc0VsZW1lbnRHcm91cChlbGVtZW50KSkKICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgIH0KICAgICAgR3JvdXBpbmdzLmlzR3JvdXBpbmcgPSBpc0dyb3VwaW5nOwogICAgICAvKiogQ291bnQgdGhlIHRvdGFsIG51bWJlciBvZiBlbGVtZW50cyBpbiBhIHJlY3Vyc2l2ZSBncm91cGluZy4gKi8KICAgICAgZnVuY3Rpb24gY291bnQoZWxlbWVudHMpIHsKICAgICAgICAgIGlmIChpc0dyb3VwaW5nKGVsZW1lbnRzKSkgewogICAgICAgICAgICAgIGxldCByZXN1bHQgPSAwOwogICAgICAgICAgICAgIGZvciAobGV0IHN1Ymdyb3VwIG9mIGVsZW1lbnRzKQogICAgICAgICAgICAgICAgICByZXN1bHQgKz0gY291bnQoc3ViZ3JvdXAucm93cyk7CiAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0KICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgIHJldHVybiBlbGVtZW50cy5sZW5ndGg7CiAgICAgICAgICB9CiAgICAgIH0KICAgICAgR3JvdXBpbmdzLmNvdW50ID0gY291bnQ7CiAgfSkoR3JvdXBpbmdzIHx8IChHcm91cGluZ3MgPSB7fSkpOwogIC8vLy8vLy8vLy8KICAvLyBMSU5LIC8vCiAgLy8vLy8vLy8vLwogIC8qKiBUaGUgT2JzaWRpYW4gJ2xpbmsnLCB1c2VkIGZvciB1bmlxdWVseSBkZXNjcmliaW5nIGEgZmlsZSwgaGVhZGVyLCBvciBibG9jay4gKi8KICBjbGFzcyBMaW5rIHsKICAgICAgLyoqIFRoZSBmaWxlIHBhdGggdGhpcyBsaW5rIHBvaW50cyB0by4gKi8KICAgICAgcGF0aDsKICAgICAgLyoqIFRoZSBkaXNwbGF5IG5hbWUgYXNzb2NpYXRlZCB3aXRoIHRoZSBsaW5rLiAqLwogICAgICBkaXNwbGF5OwogICAgICAvKiogVGhlIGJsb2NrIElEIG9yIGhlYWRlciB0aGlzIGxpbmsgcG9pbnRzIHRvIHdpdGhpbiBhIGZpbGUsIGlmIHJlbGV2YW50LiAqLwogICAgICBzdWJwYXRoOwogICAgICAvKiogSXMgdGhpcyBsaW5rIGFuIGVtYmVkZGVkIGxpbmsgKCEpPyAqLwogICAgICBlbWJlZDsKICAgICAgLyoqIFRoZSB0eXBlIG9mIHRoaXMgbGluaywgd2hpY2ggZGV0ZXJtaW5lcyB3aGF0ICdzdWJwYXRoJyByZWZlcnMgdG8sIGlmIGFueXRoaW5nLiAqLwogICAgICB0eXBlOwogICAgICAvKiogQ3JlYXRlIGEgbGluayB0byBhIHNwZWNpZmljIGZpbGUuICovCiAgICAgIHN0YXRpYyBmaWxlKHBhdGgsIGVtYmVkID0gZmFsc2UsIGRpc3BsYXkpIHsKICAgICAgICAgIHJldHVybiBuZXcgTGluayh7CiAgICAgICAgICAgICAgcGF0aCwKICAgICAgICAgICAgICBlbWJlZCwKICAgICAgICAgICAgICBkaXNwbGF5LAogICAgICAgICAgICAgIHN1YnBhdGg6IHVuZGVmaW5lZCwKICAgICAgICAgICAgICB0eXBlOiAiZmlsZSIsCiAgICAgICAgICB9KTsKICAgICAgfQogICAgICBzdGF0aWMgaW5mZXIobGlua3BhdGgsIGVtYmVkID0gZmFsc2UsIGRpc3BsYXkpIHsKICAgICAgICAgIGlmIChsaW5rcGF0aC5pbmNsdWRlcygiI14iKSkgewogICAgICAgICAgICAgIGxldCBzcGxpdCA9IGxpbmtwYXRoLnNwbGl0KCIjXiIpOwogICAgICAgICAgICAgIHJldHVybiBMaW5rLmJsb2NrKHNwbGl0WzBdLCBzcGxpdFsxXSwgZW1iZWQsIGRpc3BsYXkpOwogICAgICAgICAgfQogICAgICAgICAgZWxzZSBpZiAobGlua3BhdGguaW5jbHVkZXMoIiMiKSkgewogICAgICAgICAgICAgIGxldCBzcGxpdCA9IGxpbmtwYXRoLnNwbGl0KCIjIik7CiAgICAgICAgICAgICAgcmV0dXJuIExpbmsuaGVhZGVyKHNwbGl0WzBdLCBzcGxpdFsxXSwgZW1iZWQsIGRpc3BsYXkpOwogICAgICAgICAgfQogICAgICAgICAgZWxzZQogICAgICAgICAgICAgIHJldHVybiBMaW5rLmZpbGUobGlua3BhdGgsIGVtYmVkLCBkaXNwbGF5KTsKICAgICAgfQogICAgICAvKiogQ3JlYXRlIGEgbGluayB0byBhIHNwZWNpZmljIGZpbGUgYW5kIGhlYWRlciBpbiB0aGF0IGZpbGUuICovCiAgICAgIHN0YXRpYyBoZWFkZXIocGF0aCwgaGVhZGVyLCBlbWJlZCwgZGlzcGxheSkgewogICAgICAgICAgLy8gSGVhZGVycyBuZWVkIHRvIGJlIG5vcm1hbGl6ZWQgdG8gYWxwaGEtbnVtZXJpYyAmIHdpdGggZXh0cmEgc3BhY2luZyByZW1vdmVkLgogICAgICAgICAgcmV0dXJuIG5ldyBMaW5rKHsKICAgICAgICAgICAgICBwYXRoLAogICAgICAgICAgICAgIGVtYmVkLAogICAgICAgICAgICAgIGRpc3BsYXksCiAgICAgICAgICAgICAgc3VicGF0aDogbm9ybWFsaXplSGVhZGVyRm9yTGluayhoZWFkZXIpLAogICAgICAgICAgICAgIHR5cGU6ICJoZWFkZXIiLAogICAgICAgICAgfSk7CiAgICAgIH0KICAgICAgLyoqIENyZWF0ZSBhIGxpbmsgdG8gYSBzcGVjaWZpYyBmaWxlIGFuZCBibG9jayBpbiB0aGF0IGZpbGUuICovCiAgICAgIHN0YXRpYyBibG9jayhwYXRoLCBibG9ja0lkLCBlbWJlZCwgZGlzcGxheSkgewogICAgICAgICAgcmV0dXJuIG5ldyBMaW5rKHsKICAgICAgICAgICAgICBwYXRoLAogICAgICAgICAgICAgIGVtYmVkLAogICAgICAgICAgICAgIGRpc3BsYXksCiAgICAgICAgICAgICAgc3VicGF0aDogYmxvY2tJZCwKICAgICAgICAgICAgICB0eXBlOiAiYmxvY2siLAogICAgICAgICAgfSk7CiAgICAgIH0KICAgICAgc3RhdGljIGZyb21PYmplY3Qob2JqZWN0KSB7CiAgICAgICAgICByZXR1cm4gbmV3IExpbmsob2JqZWN0KTsKICAgICAgfQogICAgICBjb25zdHJ1Y3RvcihmaWVsZHMpIHsKICAgICAgICAgIE9iamVjdC5hc3NpZ24odGhpcywgZmllbGRzKTsKICAgICAgfQogICAgICAvKiogQ2hlY2tzIGZvciBsaW5rIGVxdWFsaXR5IChpLmUuLCB0aGF0IHRoZSBsaW5rcyBhcmUgcG9pbnRpbmcgdG8gdGhlIHNhbWUgZXhhY3QgbG9jYXRpb24pLiAqLwogICAgICBlcXVhbHMob3RoZXIpIHsKICAgICAgICAgIGlmIChvdGhlciA9PSB1bmRlZmluZWQgfHwgb3RoZXIgPT0gbnVsbCkKICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICByZXR1cm4gdGhpcy5wYXRoID09IG90aGVyLnBhdGggJiYgdGhpcy50eXBlID09IG90aGVyLnR5cGUgJiYgdGhpcy5zdWJwYXRoID09IG90aGVyLnN1YnBhdGg7CiAgICAgIH0KICAgICAgLyoqIENvbnZlcnQgdGhpcyBsaW5rIHRvIGl0J3MgbWFya2Rvd24gcmVwcmVzZW50YXRpb24uICovCiAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgcmV0dXJuIHRoaXMubWFya2Rvd24oKTsKICAgICAgfQogICAgICAvKiogQ29udmVydCB0aGlzIGxpbmsgdG8gYSByYXcgb2JqZWN0IHdoaWNoIGlzIHNlcmlhbGl6YXRpb24tZnJpZW5kbHkuICovCiAgICAgIHRvT2JqZWN0KCkgewogICAgICAgICAgcmV0dXJuIHsgcGF0aDogdGhpcy5wYXRoLCB0eXBlOiB0aGlzLnR5cGUsIHN1YnBhdGg6IHRoaXMuc3VicGF0aCwgZGlzcGxheTogdGhpcy5kaXNwbGF5LCBlbWJlZDogdGhpcy5lbWJlZCB9OwogICAgICB9CiAgICAgIC8qKiBVcGRhdGUgdGhpcyBsaW5rIHdpdGggYSBuZXcgcGF0aC4gKi8KICAgICAgLy9AdHMtaWdub3JlOyBlcnJvciBhcHBlYXJlZCBhZnRlciB1cGRhdGluZyBPYnNpZGlhbiB0byAwLjE1LjQ7IGl0IGFsc28gdXBkYXRlZCBvdGhlciBwYWNrYWdlcyBidXQgZGlkbid0IHNheSB3aGljaAogICAgICB3aXRoUGF0aChwYXRoKSB7CiAgICAgICAgICByZXR1cm4gbmV3IExpbmsoT2JqZWN0LmFzc2lnbih7fSwgdGhpcywgeyBwYXRoIH0pKTsKICAgICAgfQogICAgICAvKiogUmV0dXJuIGEgbmV3IGxpbmsgd2hpY2ggcG9pbnRzIHRvIHRoZSBzYW1lIGxvY2F0aW9uIGJ1dCB3aXRoIGEgbmV3IGRpc3BsYXkgdmFsdWUuICovCiAgICAgIHdpdGhEaXNwbGF5KGRpc3BsYXkpIHsKICAgICAgICAgIHJldHVybiBuZXcgTGluayhPYmplY3QuYXNzaWduKHt9LCB0aGlzLCB7IGRpc3BsYXkgfSkpOwogICAgICB9CiAgICAgIC8qKiBDb252ZXJ0IGEgZmlsZSBsaW5rIGludG8gYSBsaW5rIHRvIGEgc3BlY2lmaWMgaGVhZGVyLiAqLwogICAgICB3aXRoSGVhZGVyKGhlYWRlcikgewogICAgICAgICAgcmV0dXJuIExpbmsuaGVhZGVyKHRoaXMucGF0aCwgaGVhZGVyLCB0aGlzLmVtYmVkLCB0aGlzLmRpc3BsYXkpOwogICAgICB9CiAgICAgIC8qKiBDb252ZXJ0IGFueSBsaW5rIGludG8gYSBsaW5rIHRvIGl0cyBmaWxlLiAqLwogICAgICB0b0ZpbGUoKSB7CiAgICAgICAgICByZXR1cm4gTGluay5maWxlKHRoaXMucGF0aCwgdGhpcy5lbWJlZCwgdGhpcy5kaXNwbGF5KTsKICAgICAgfQogICAgICAvKiogQ29udmVydCB0aGlzIGxpbmsgaW50byBhbiBlbWJlZGRlZCBsaW5rLiAqLwogICAgICB0b0VtYmVkKCkgewogICAgICAgICAgaWYgKHRoaXMuZW1iZWQpIHsKICAgICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgIGxldCBsaW5rID0gbmV3IExpbmsodGhpcyk7CiAgICAgICAgICAgICAgbGluay5lbWJlZCA9IHRydWU7CiAgICAgICAgICAgICAgcmV0dXJuIGxpbms7CiAgICAgICAgICB9CiAgICAgIH0KICAgICAgLyoqIENvbnZlcnQgdGhpcyBsaW5rIGludG8gYSBub24tZW1iZWRkZWQgbGluay4gKi8KICAgICAgZnJvbUVtYmVkKCkgewogICAgICAgICAgaWYgKCF0aGlzLmVtYmVkKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICBsZXQgbGluayA9IG5ldyBMaW5rKHRoaXMpOwogICAgICAgICAgICAgIGxpbmsuZW1iZWQgPSBmYWxzZTsKICAgICAgICAgICAgICByZXR1cm4gbGluazsKICAgICAgICAgIH0KICAgICAgfQogICAgICAvKiogQ29udmVydCB0aGlzIGxpbmsgdG8gbWFya2Rvd24gc28gaXQgY2FuIGJlIHJlbmRlcmVkLiAqLwogICAgICBtYXJrZG93bigpIHsKICAgICAgICAgIGxldCByZXN1bHQgPSAodGhpcy5lbWJlZCA/ICIhIiA6ICIiKSArICJbWyIgKyB0aGlzLm9ic2lkaWFuTGluaygpOwogICAgICAgICAgaWYgKHRoaXMuZGlzcGxheSkgewogICAgICAgICAgICAgIHJlc3VsdCArPSAifCIgKyB0aGlzLmRpc3BsYXk7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICByZXN1bHQgKz0gInwiICsgZ2V0RmlsZVRpdGxlKHRoaXMucGF0aCk7CiAgICAgICAgICAgICAgaWYgKHRoaXMudHlwZSA9PSAiaGVhZGVyIiB8fCB0aGlzLnR5cGUgPT0gImJsb2NrIikKICAgICAgICAgICAgICAgICAgcmVzdWx0ICs9ICIgPiAiICsgdGhpcy5zdWJwYXRoOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0ICs9ICJdXSI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9CiAgICAgIC8qKiBDb252ZXJ0IHRoZSBpbm5lciBwYXJ0IG9mIHRoZSBsaW5rIHRvIHNvbWV0aGluZyB0aGF0IE9ic2lkaWFuIGNhbiBvcGVuIC8gdW5kZXJzdGFuZC4gKi8KICAgICAgb2JzaWRpYW5MaW5rKCkgewogICAgICAgICAgY29uc3QgZXNjYXBlZCA9IHRoaXMucGF0aC5yZXBsYWNlQWxsKCJ8IiwgIlxcfCIpOwogICAgICAgICAgaWYgKHRoaXMudHlwZSA9PSAiaGVhZGVyIikKICAgICAgICAgICAgICByZXR1cm4gZXNjYXBlZCArICIjIiArIHRoaXMuc3VicGF0aD8ucmVwbGFjZUFsbCgifCIsICJcXHwiKTsKICAgICAgICAgIGlmICh0aGlzLnR5cGUgPT0gImJsb2NrIikKICAgICAgICAgICAgICByZXR1cm4gZXNjYXBlZCArICIjXiIgKyB0aGlzLnN1YnBhdGg/LnJlcGxhY2VBbGwoInwiLCAiXFx8Iik7CiAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgcmV0dXJuIGVzY2FwZWQ7CiAgICAgIH0KICAgICAgLyoqIFRoZSBzdHJpcHBlZCBuYW1lIG9mIHRoZSBmaWxlIHRoaXMgbGluayBwb2ludHMgdG8uICovCiAgICAgIGZpbGVOYW1lKCkgewogICAgICAgICAgcmV0dXJuIGdldEZpbGVUaXRsZSh0aGlzLnBhdGgpLnJlcGxhY2UoIi5tZCIsICIiKTsKICAgICAgfQogIH0KICAvLy8vLy8vLy8vLy8vLy8vLwogIC8vIFdJREdFVCBCQVNFIC8vCiAgLy8vLy8vLy8vLy8vLy8vLy8KICAvKioKICAgKiBBIHRyaXZpYWwgYmFzZSBjbGFzcyB3aGljaCBqdXN0IGRlZmluZXMgdGhlICckd2lkZ2V0JyBpZGVudGlmaWVyIHR5cGUuIFN1YnR5cGVzIG9mCiAgICogd2lkZ2V0IGFyZSByZXNwb25zaWJsZSBmb3IgYWRkaW5nIHdoYXRldmVyIG1ldGFkYXRhIGlzIHJlbGV2YW50LiBJZiB5b3Ugd2FudCB5b3VyIHdpZGdldAogICAqIHRvIGhhdmUgcmVuZGVyaW5nIGZ1bmN0aW9uYWxpdHkgKHdoaWNoIHlvdSBwcm9iYWJseSBkbyksIHlvdSBzaG91bGQgZXh0ZW5kIGBSZW5kZXJXaWRnZXRgLgogICAqLwogIGNsYXNzIFdpZGdldCB7CiAgICAgICR3aWRnZXQ7CiAgICAgIGNvbnN0cnVjdG9yKCR3aWRnZXQpIHsKICAgICAgICAgIHRoaXMuJHdpZGdldCA9ICR3aWRnZXQ7CiAgICAgIH0KICB9CiAgLyoqIEEgdHJpdmlhbCB3aWRnZXQgd2hpY2ggcmVuZGVycyBhIChrZXksIHZhbHVlKSBwYWlyLCBhbmQgYWxsb3dzIGFjY2Vzc2luZyB0aGUga2V5IGFuZCB2YWx1ZS4gKi8KICBjbGFzcyBMaXN0UGFpcldpZGdldCBleHRlbmRzIFdpZGdldCB7CiAgICAgIGtleTsKICAgICAgdmFsdWU7CiAgICAgIGNvbnN0cnVjdG9yKGtleSwgdmFsdWUpIHsKICAgICAgICAgIHN1cGVyKCJkYXRhdmlldzpsaXN0LXBhaXIiKTsKICAgICAgICAgIHRoaXMua2V5ID0ga2V5OwogICAgICAgICAgdGhpcy52YWx1ZSA9IHZhbHVlOwogICAgICB9CiAgICAgIG1hcmtkb3duKCkgewogICAgICAgICAgcmV0dXJuIGAke1ZhbHVlcy50b1N0cmluZyh0aGlzLmtleSl9OiAke1ZhbHVlcy50b1N0cmluZyh0aGlzLnZhbHVlKX1gOwogICAgICB9CiAgfQogIC8qKiBBIHNpbXBsZSB3aWRnZXQgd2hpY2ggcmVuZGVycyBhbiBleHRlcm5hbCBsaW5rLiAqLwogIGNsYXNzIEV4dGVybmFsTGlua1dpZGdldCBleHRlbmRzIFdpZGdldCB7CiAgICAgIHVybDsKICAgICAgZGlzcGxheTsKICAgICAgY29uc3RydWN0b3IodXJsLCBkaXNwbGF5KSB7CiAgICAgICAgICBzdXBlcigiZGF0YXZpZXc6ZXh0ZXJuYWwtbGluayIpOwogICAgICAgICAgdGhpcy51cmwgPSB1cmw7CiAgICAgICAgICB0aGlzLmRpc3BsYXkgPSBkaXNwbGF5OwogICAgICB9CiAgICAgIG1hcmtkb3duKCkgewogICAgICAgICAgcmV0dXJuIGBbJHt0aGlzLmRpc3BsYXkgPz8gdGhpcy51cmx9XSgke3RoaXMudXJsfSlgOwogICAgICB9CiAgfQogIHZhciBXaWRnZXRzOwogIChmdW5jdGlvbiAoV2lkZ2V0cykgewogICAgICAvKiogQ3JlYXRlIGEgbGlzdCBwYWlyIHdpZGdldCBtYXRjaGluZyB0aGUgZ2l2ZW4ga2V5IGFuZCB2YWx1ZS4gKi8KICAgICAgZnVuY3Rpb24gbGlzdFBhaXIoa2V5LCB2YWx1ZSkgewogICAgICAgICAgcmV0dXJuIG5ldyBMaXN0UGFpcldpZGdldChrZXksIHZhbHVlKTsKICAgICAgfQogICAgICBXaWRnZXRzLmxpc3RQYWlyID0gbGlzdFBhaXI7CiAgICAgIC8qKiBDcmVhdGUgYW4gZXh0ZXJuYWwgbGluayB3aWRnZXQgd2hpY2ggcmVuZGVycyBhbiBleHRlcm5hbCBPYnNpZGlhbiBsaW5rLiAqLwogICAgICBmdW5jdGlvbiBleHRlcm5hbExpbmsodXJsLCBkaXNwbGF5KSB7CiAgICAgICAgICByZXR1cm4gbmV3IEV4dGVybmFsTGlua1dpZGdldCh1cmwsIGRpc3BsYXkpOwogICAgICB9CiAgICAgIFdpZGdldHMuZXh0ZXJuYWxMaW5rID0gZXh0ZXJuYWxMaW5rOwogICAgICAvKiogQ2hlY2tzIGlmIHRoZSBnaXZlbiB3aWRnZXQgaXMgYSBsaXN0IHBhaXIgd2lkZ2V0LiAqLwogICAgICBmdW5jdGlvbiBpc0xpc3RQYWlyKHdpZGdldCkgewogICAgICAgICAgcmV0dXJuIHdpZGdldC4kd2lkZ2V0ID09PSAiZGF0YXZpZXc6bGlzdC1wYWlyIjsKICAgICAgfQogICAgICBXaWRnZXRzLmlzTGlzdFBhaXIgPSBpc0xpc3RQYWlyOwogICAgICBmdW5jdGlvbiBpc0V4dGVybmFsTGluayh3aWRnZXQpIHsKICAgICAgICAgIHJldHVybiB3aWRnZXQuJHdpZGdldCA9PT0gImRhdGF2aWV3OmV4dGVybmFsLWxpbmsiOwogICAgICB9CiAgICAgIFdpZGdldHMuaXNFeHRlcm5hbExpbmsgPSBpc0V4dGVybmFsTGluazsKICAgICAgLyoqIERldGVybWluZXMgaWYgdGhlIGdpdmVuIHdpZGdldCBpcyBhbnkga2luZCBvZiBidWlsdC1pbiB3aWRnZXQgd2l0aCBzcGVjaWFsIHJlbmRlcmluZyBoYW5kbGluZy4gKi8KICAgICAgZnVuY3Rpb24gaXNCdWlsdGluKHdpZGdldCkgewogICAgICAgICAgcmV0dXJuIGlzTGlzdFBhaXIod2lkZ2V0KSB8fCBpc0V4dGVybmFsTGluayh3aWRnZXQpOwogICAgICB9CiAgICAgIFdpZGdldHMuaXNCdWlsdGluID0gaXNCdWlsdGluOwogIH0pKFdpZGdldHMgfHwgKFdpZGdldHMgPSB7fSkpOwoKICAvKiogVXRpbGl0eSBtZXRob2RzIGZvciBjcmVhdGluZyAmIGNvbXBhcmluZyBmaWVsZHMuICovCiAgdmFyIEZpZWxkczsKICAoZnVuY3Rpb24gKEZpZWxkcykgewogICAgICBmdW5jdGlvbiB2YXJpYWJsZShuYW1lKSB7CiAgICAgICAgICByZXR1cm4geyB0eXBlOiAidmFyaWFibGUiLCBuYW1lIH07CiAgICAgIH0KICAgICAgRmllbGRzLnZhcmlhYmxlID0gdmFyaWFibGU7CiAgICAgIGZ1bmN0aW9uIGxpdGVyYWwodmFsdWUpIHsKICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJsaXRlcmFsIiwgdmFsdWUgfTsKICAgICAgfQogICAgICBGaWVsZHMubGl0ZXJhbCA9IGxpdGVyYWw7CiAgICAgIGZ1bmN0aW9uIGJpbmFyeU9wKGxlZnQsIG9wLCByaWdodCkgewogICAgICAgICAgcmV0dXJuIHsgdHlwZTogImJpbmFyeW9wIiwgbGVmdCwgb3AsIHJpZ2h0IH07CiAgICAgIH0KICAgICAgRmllbGRzLmJpbmFyeU9wID0gYmluYXJ5T3A7CiAgICAgIGZ1bmN0aW9uIGluZGV4KG9iaiwgaW5kZXgpIHsKICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJpbmRleCIsIG9iamVjdDogb2JqLCBpbmRleCB9OwogICAgICB9CiAgICAgIEZpZWxkcy5pbmRleCA9IGluZGV4OwogICAgICAvKiogQ29udmVydHMgYSBzdHJpbmcgaW4gZG90LW5vdGF0aW9uLWZvcm1hdCBpbnRvIGEgdmFyaWFibGUgd2hpY2ggaW5kZXhlcy4gKi8KICAgICAgZnVuY3Rpb24gaW5kZXhWYXJpYWJsZShuYW1lKSB7CiAgICAgICAgICBsZXQgcGFydHMgPSBuYW1lLnNwbGl0KCIuIik7CiAgICAgICAgICBsZXQgcmVzdWx0ID0gRmllbGRzLnZhcmlhYmxlKHBhcnRzWzBdKTsKICAgICAgICAgIGZvciAobGV0IGluZGV4ID0gMTsgaW5kZXggPCBwYXJ0cy5sZW5ndGg7IGluZGV4KyspIHsKICAgICAgICAgICAgICByZXN1bHQgPSBGaWVsZHMuaW5kZXgocmVzdWx0LCBGaWVsZHMubGl0ZXJhbChwYXJ0c1tpbmRleF0pKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH0KICAgICAgRmllbGRzLmluZGV4VmFyaWFibGUgPSBpbmRleFZhcmlhYmxlOwogICAgICBmdW5jdGlvbiBsYW1iZGEoYXJncywgdmFsdWUpIHsKICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJsYW1iZGEiLCBhcmd1bWVudHM6IGFyZ3MsIHZhbHVlIH07CiAgICAgIH0KICAgICAgRmllbGRzLmxhbWJkYSA9IGxhbWJkYTsKICAgICAgZnVuY3Rpb24gZnVuYyhmdW5jLCBhcmdzKSB7CiAgICAgICAgICByZXR1cm4geyB0eXBlOiAiZnVuY3Rpb24iLCBmdW5jLCBhcmd1bWVudHM6IGFyZ3MgfTsKICAgICAgfQogICAgICBGaWVsZHMuZnVuYyA9IGZ1bmM7CiAgICAgIGZ1bmN0aW9uIGxpc3QodmFsdWVzKSB7CiAgICAgICAgICByZXR1cm4geyB0eXBlOiAibGlzdCIsIHZhbHVlcyB9OwogICAgICB9CiAgICAgIEZpZWxkcy5saXN0ID0gbGlzdDsKICAgICAgZnVuY3Rpb24gb2JqZWN0KHZhbHVlcykgewogICAgICAgICAgcmV0dXJuIHsgdHlwZTogIm9iamVjdCIsIHZhbHVlcyB9OwogICAgICB9CiAgICAgIEZpZWxkcy5vYmplY3QgPSBvYmplY3Q7CiAgICAgIGZ1bmN0aW9uIG5lZ2F0ZShjaGlsZCkgewogICAgICAgICAgcmV0dXJuIHsgdHlwZTogIm5lZ2F0ZWQiLCBjaGlsZCB9OwogICAgICB9CiAgICAgIEZpZWxkcy5uZWdhdGUgPSBuZWdhdGU7CiAgICAgIGZ1bmN0aW9uIGlzQ29tcGFyZU9wKG9wKSB7CiAgICAgICAgICByZXR1cm4gb3AgPT0gIjw9IiB8fCBvcCA9PSAiPCIgfHwgb3AgPT0gIj4iIHx8IG9wID09ICI+PSIgfHwgb3AgPT0gIiE9IiB8fCBvcCA9PSAiPSI7CiAgICAgIH0KICAgICAgRmllbGRzLmlzQ29tcGFyZU9wID0gaXNDb21wYXJlT3A7CiAgICAgIEZpZWxkcy5OVUxMID0gRmllbGRzLmxpdGVyYWwobnVsbCk7CiAgfSkoRmllbGRzIHx8IChGaWVsZHMgPSB7fSkpOwoKICAvKiogQVNUIGltcGxlbWVudGF0aW9uIGZvciBxdWVyaWVzIG92ZXIgZGF0YSBzb3VyY2VzLiAqLwogIC8qKiBVdGlsaXR5IGZ1bmN0aW9ucyBmb3IgY3JlYXRpbmcgYW5kIG1hbmlwdWxhdGluZyBzb3VyY2VzLiAqLwogIHZhciBTb3VyY2VzOwogIChmdW5jdGlvbiAoU291cmNlcykgewogICAgICAvKiogQ3JlYXRlIGEgc291cmNlIHdoaWNoIHNlYXJjaGVzIGZyb20gYSB0YWcuICovCiAgICAgIGZ1bmN0aW9uIHRhZyh0YWcpIHsKICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJ0YWciLCB0YWcgfTsKICAgICAgfQogICAgICBTb3VyY2VzLnRhZyA9IHRhZzsKICAgICAgLyoqIENyZWF0ZSBhIHNvdXJjZSB3aGljaCBmZXRjaGVzIGZyb20gYSBDU1YgZmlsZS4gKi8KICAgICAgZnVuY3Rpb24gY3N2KHBhdGgpIHsKICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJjc3YiLCBwYXRoIH07CiAgICAgIH0KICAgICAgU291cmNlcy5jc3YgPSBjc3Y7CiAgICAgIC8qKiBDcmVhdGUgYSBzb3VyY2Ugd2hpY2ggc2VhcmNoZXMgZm9yIGZpbGVzIHVuZGVyIGEgZm9sZGVyIHByZWZpeC4gKi8KICAgICAgZnVuY3Rpb24gZm9sZGVyKHByZWZpeCkgewogICAgICAgICAgcmV0dXJuIHsgdHlwZTogImZvbGRlciIsIGZvbGRlcjogcHJlZml4IH07CiAgICAgIH0KICAgICAgU291cmNlcy5mb2xkZXIgPSBmb2xkZXI7CiAgICAgIC8qKiBDcmVhdGUgYSBzb3VyY2Ugd2hpY2ggc2VhcmNoZXMgZm9yIGZpbGVzIHdoaWNoIGxpbmsgdG8vZnJvbSBhIGdpdmVuIGZpbGUuICovCiAgICAgIGZ1bmN0aW9uIGxpbmsoZmlsZSwgaW5jb21pbmcpIHsKICAgICAgICAgIHJldHVybiB7IHR5cGU6ICJsaW5rIiwgZmlsZSwgZGlyZWN0aW9uOiBpbmNvbWluZyA/ICJpbmNvbWluZyIgOiAib3V0Z29pbmciIH07CiAgICAgIH0KICAgICAgU291cmNlcy5saW5rID0gbGluazsKICAgICAgLyoqIENyZWF0ZSBhIHNvdXJjZSB3aGljaCBqb2lucyB0d28gc291cmNlcyBieSBhIGxvZ2ljYWwgb3BlcmF0b3IgKGFuZC9vcikuICovCiAgICAgIGZ1bmN0aW9uIGJpbmFyeU9wKGxlZnQsIG9wLCByaWdodCkgewogICAgICAgICAgcmV0dXJuIHsgdHlwZTogImJpbmFyeW9wIiwgbGVmdCwgb3AsIHJpZ2h0IH07CiAgICAgIH0KICAgICAgU291cmNlcy5iaW5hcnlPcCA9IGJpbmFyeU9wOwogICAgICAvKiogQ3JlYXRlIGEgc291cmNlIHdoaWNoIHRha2VzIHRoZSBpbnRlcnNlY3Rpb24gb2YgdHdvIHNvdXJjZXMuICovCiAgICAgIGZ1bmN0aW9uIGFuZChsZWZ0LCByaWdodCkgewogICAgICAgICAgcmV0dXJuIHsgdHlwZTogImJpbmFyeW9wIiwgbGVmdCwgb3A6ICImIiwgcmlnaHQgfTsKICAgICAgfQogICAgICBTb3VyY2VzLmFuZCA9IGFuZDsKICAgICAgLyoqIENyZWF0ZSBhIHNvdXJjZSB3aGljaCB0YWtlcyB0aGUgdW5pb24gb2YgdHdvIHNvdXJjZXMuICovCiAgICAgIGZ1bmN0aW9uIG9yKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4geyB0eXBlOiAiYmluYXJ5b3AiLCBsZWZ0LCBvcDogInwiLCByaWdodCB9OwogICAgICB9CiAgICAgIFNvdXJjZXMub3IgPSBvcjsKICAgICAgLyoqIENyZWF0ZSBhIHNvdXJjZSB3aGljaCBuZWdhdGVzIHRoZSB1bmRlcmx5aW5nIHNvdXJjZS4gKi8KICAgICAgZnVuY3Rpb24gbmVnYXRlKGNoaWxkKSB7CiAgICAgICAgICByZXR1cm4geyB0eXBlOiAibmVnYXRlIiwgY2hpbGQgfTsKICAgICAgfQogICAgICBTb3VyY2VzLm5lZ2F0ZSA9IG5lZ2F0ZTsKICAgICAgZnVuY3Rpb24gZW1wdHkoKSB7CiAgICAgICAgICByZXR1cm4geyB0eXBlOiAiZW1wdHkiIH07CiAgICAgIH0KICAgICAgU291cmNlcy5lbXB0eSA9IGVtcHR5OwogIH0pKFNvdXJjZXMgfHwgKFNvdXJjZXMgPSB7fSkpOwoKICAvKiogRW1vamkgcmVnZXggd2l0aG91dCBhbnkgYWRkaXRpb25hbCBmbGFncy4gKi8KICBjb25zdCBFTU9KSV9SRUdFWCA9IG5ldyBSZWdFeHAoZW1vamlSZWdleCgpLCAiIik7CiAgLyoqIFByb3ZpZGVzIGEgbG9va3VwIHRhYmxlIGZvciB1bml0IGR1cmF0aW9ucyBvZiB0aGUgZ2l2ZW4gdHlwZS4gKi8KICBjb25zdCBEVVJBVElPTl9UWVBFUyA9IHsKICAgICAgeWVhcjogRHVyYXRpb24uZnJvbU9iamVjdCh7IHllYXJzOiAxIH0pLAogICAgICB5ZWFyczogRHVyYXRpb24uZnJvbU9iamVjdCh7IHllYXJzOiAxIH0pLAogICAgICB5cjogRHVyYXRpb24uZnJvbU9iamVjdCh7IHllYXJzOiAxIH0pLAogICAgICB5cnM6IER1cmF0aW9uLmZyb21PYmplY3QoeyB5ZWFyczogMSB9KSwKICAgICAgbW9udGg6IER1cmF0aW9uLmZyb21PYmplY3QoeyBtb250aHM6IDEgfSksCiAgICAgIG1vbnRoczogRHVyYXRpb24uZnJvbU9iamVjdCh7IG1vbnRoczogMSB9KSwKICAgICAgbW86IER1cmF0aW9uLmZyb21PYmplY3QoeyBtb250aHM6IDEgfSksCiAgICAgIG1vczogRHVyYXRpb24uZnJvbU9iamVjdCh7IG1vbnRoczogMSB9KSwKICAgICAgd2VlazogRHVyYXRpb24uZnJvbU9iamVjdCh7IHdlZWtzOiAxIH0pLAogICAgICB3ZWVrczogRHVyYXRpb24uZnJvbU9iamVjdCh7IHdlZWtzOiAxIH0pLAogICAgICB3azogRHVyYXRpb24uZnJvbU9iamVjdCh7IHdlZWtzOiAxIH0pLAogICAgICB3a3M6IER1cmF0aW9uLmZyb21PYmplY3QoeyB3ZWVrczogMSB9KSwKICAgICAgdzogRHVyYXRpb24uZnJvbU9iamVjdCh7IHdlZWtzOiAxIH0pLAogICAgICBkYXk6IER1cmF0aW9uLmZyb21PYmplY3QoeyBkYXlzOiAxIH0pLAogICAgICBkYXlzOiBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgZGF5czogMSB9KSwKICAgICAgZDogRHVyYXRpb24uZnJvbU9iamVjdCh7IGRheXM6IDEgfSksCiAgICAgIGhvdXI6IER1cmF0aW9uLmZyb21PYmplY3QoeyBob3VyczogMSB9KSwKICAgICAgaG91cnM6IER1cmF0aW9uLmZyb21PYmplY3QoeyBob3VyczogMSB9KSwKICAgICAgaHI6IER1cmF0aW9uLmZyb21PYmplY3QoeyBob3VyczogMSB9KSwKICAgICAgaHJzOiBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgaG91cnM6IDEgfSksCiAgICAgIGg6IER1cmF0aW9uLmZyb21PYmplY3QoeyBob3VyczogMSB9KSwKICAgICAgbWludXRlOiBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgbWludXRlczogMSB9KSwKICAgICAgbWludXRlczogRHVyYXRpb24uZnJvbU9iamVjdCh7IG1pbnV0ZXM6IDEgfSksCiAgICAgIG1pbjogRHVyYXRpb24uZnJvbU9iamVjdCh7IG1pbnV0ZXM6IDEgfSksCiAgICAgIG1pbnM6IER1cmF0aW9uLmZyb21PYmplY3QoeyBtaW51dGVzOiAxIH0pLAogICAgICBtOiBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgbWludXRlczogMSB9KSwKICAgICAgc2Vjb25kOiBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgc2Vjb25kczogMSB9KSwKICAgICAgc2Vjb25kczogRHVyYXRpb24uZnJvbU9iamVjdCh7IHNlY29uZHM6IDEgfSksCiAgICAgIHNlYzogRHVyYXRpb24uZnJvbU9iamVjdCh7IHNlY29uZHM6IDEgfSksCiAgICAgIHNlY3M6IER1cmF0aW9uLmZyb21PYmplY3QoeyBzZWNvbmRzOiAxIH0pLAogICAgICBzOiBEdXJhdGlvbi5mcm9tT2JqZWN0KHsgc2Vjb25kczogMSB9KSwKICB9OwogIC8qKiBTaG9ydGhhbmQgZm9yIGNvbW1vbiBkYXRlcyAocmVsYXRpdmUgdG8gcmlnaHQgbm93KS4gKi8KICBjb25zdCBEQVRFX1NIT1JUSEFORFMgPSB7CiAgICAgIG5vdzogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKSwKICAgICAgdG9kYXk6ICgpID0+IERhdGVUaW1lLmxvY2FsKCkuc3RhcnRPZigiZGF5IiksCiAgICAgIHllc3RlcmRheTogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKQogICAgICAgICAgLnN0YXJ0T2YoImRheSIpCiAgICAgICAgICAubWludXMoRHVyYXRpb24uZnJvbU9iamVjdCh7IGRheXM6IDEgfSkpLAogICAgICB0b21vcnJvdzogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKQogICAgICAgICAgLnN0YXJ0T2YoImRheSIpCiAgICAgICAgICAucGx1cyhEdXJhdGlvbi5mcm9tT2JqZWN0KHsgZGF5czogMSB9KSksCiAgICAgIHNvdzogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKS5zdGFydE9mKCJ3ZWVrIiksCiAgICAgICJzdGFydC1vZi13ZWVrIjogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKS5zdGFydE9mKCJ3ZWVrIiksCiAgICAgIGVvdzogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKS5lbmRPZigid2VlayIpLAogICAgICAiZW5kLW9mLXdlZWsiOiAoKSA9PiBEYXRlVGltZS5sb2NhbCgpLmVuZE9mKCJ3ZWVrIiksCiAgICAgIHNveTogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKS5zdGFydE9mKCJ5ZWFyIiksCiAgICAgICJzdGFydC1vZi15ZWFyIjogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKS5zdGFydE9mKCJ5ZWFyIiksCiAgICAgIGVveTogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKS5lbmRPZigieWVhciIpLAogICAgICAiZW5kLW9mLXllYXIiOiAoKSA9PiBEYXRlVGltZS5sb2NhbCgpLmVuZE9mKCJ5ZWFyIiksCiAgICAgIHNvbTogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKS5zdGFydE9mKCJtb250aCIpLAogICAgICAic3RhcnQtb2YtbW9udGgiOiAoKSA9PiBEYXRlVGltZS5sb2NhbCgpLnN0YXJ0T2YoIm1vbnRoIiksCiAgICAgIGVvbTogKCkgPT4gRGF0ZVRpbWUubG9jYWwoKS5lbmRPZigibW9udGgiKSwKICAgICAgImVuZC1vZi1tb250aCI6ICgpID0+IERhdGVUaW1lLmxvY2FsKCkuZW5kT2YoIm1vbnRoIiksCiAgfTsKICAvKioKICAgKiBLZXl3b3JkcyB3aGljaCBjYW5ub3QgYmUgdXNlZCBhcyB2YXJpYWJsZXMgZGlyZWN0bHkuIFVzZSBgcm93Ljx0aGluZz5gIGlmIGl0IGlzIGEgdmFyaWFibGUgeW91IGhhdmUgZGVmaW5lZCBhbmQgd2FudAogICAqIHRvIGFjY2Vzcy4KICAgKi8KICBjb25zdCBLRVlXT1JEUyA9IFsiRlJPTSIsICJXSEVSRSIsICJMSU1JVCIsICJHUk9VUCIsICJGTEFUVEVOIl07CiAgLy8vLy8vLy8vLy8vLy8vCiAgLy8gVXRpbGl0aWVzIC8vCiAgLy8vLy8vLy8vLy8vLy8vCiAgLyoqIFNwbGl0IG9uIHVuZXNjYXBlZCBwaXBlcyBpbiBhbiBpbm5lciBsaW5rLiAqLwogIGZ1bmN0aW9uIHNwbGl0T25VbmVzY2FwZWRQaXBlKGxpbmspIHsKICAgICAgbGV0IHBpcGUgPSAtMTsKICAgICAgd2hpbGUgKChwaXBlID0gbGluay5pbmRleE9mKCJ8IiwgcGlwZSArIDEpKSA+PSAwKSB7CiAgICAgICAgICBpZiAocGlwZSA+IDAgJiYgbGlua1twaXBlIC0gMV0gPT0gIlxcIikKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIHJldHVybiBbbGluay5zdWJzdHJpbmcoMCwgcGlwZSkucmVwbGFjZSgvXFxcfC9nLCAifCIpLCBsaW5rLnN1YnN0cmluZyhwaXBlICsgMSldOwogICAgICB9CiAgICAgIHJldHVybiBbbGluay5yZXBsYWNlKC9cXFx8L2csICJ8IiksIHVuZGVmaW5lZF07CiAgfQogIC8qKiBBdHRlbXB0IHRvIHBhcnNlIHRoZSBpbnNpZGUgb2YgYSBsaW5rIHRvIHB1bGwgb3V0IGRpc3BsYXkgbmFtZSwgc3VicGF0aCwgZXRjLiAqLwogIGZ1bmN0aW9uIHBhcnNlSW5uZXJMaW5rKHJhd2xpbmspIHsKICAgICAgbGV0IFtsaW5rLCBkaXNwbGF5XSA9IHNwbGl0T25VbmVzY2FwZWRQaXBlKHJhd2xpbmspOwogICAgICByZXR1cm4gTGluay5pbmZlcihsaW5rLCBmYWxzZSwgZGlzcGxheSk7CiAgfQogIC8qKiBDcmVhdGUgYSBsZWZ0LWFzc29jaWF0aXZlIGJpbmFyeSBwYXJzZXIgd2hpY2ggcGFyc2VzIHRoZSBnaXZlbiBzdWItZWxlbWVudCBhbmQgc2VwYXJhdG9yLiBIYW5kbGVzIHdoaXRlc3BhY2UuICovCiAgZnVuY3Rpb24gY3JlYXRlQmluYXJ5UGFyc2VyKGNoaWxkLCBzZXAsIGNvbWJpbmUpIHsKICAgICAgcmV0dXJuIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAoY2hpbGQsIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXEocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UsIHNlcCwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UsIGNoaWxkKS5tYW55KCksIChmaXJzdCwgcmVzdCkgPT4gewogICAgICAgICAgaWYgKHJlc3QubGVuZ3RoID09IDApCiAgICAgICAgICAgICAgcmV0dXJuIGZpcnN0OwogICAgICAgICAgbGV0IG5vZGUgPSBjb21iaW5lKGZpcnN0LCByZXN0WzBdWzFdLCByZXN0WzBdWzNdKTsKICAgICAgICAgIGZvciAobGV0IGluZGV4ID0gMTsgaW5kZXggPCByZXN0Lmxlbmd0aDsgaW5kZXgrKykgewogICAgICAgICAgICAgIG5vZGUgPSBjb21iaW5lKG5vZGUsIHJlc3RbaW5kZXhdWzFdLCByZXN0W2luZGV4XVszXSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gbm9kZTsKICAgICAgfSk7CiAgfQogIGZ1bmN0aW9uIGNoYWluT3B0KGJhc2UsIC4uLmZ1bmNzKSB7CiAgICAgIHJldHVybiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuY3VzdG9tKChzdWNjZXNzLCBmYWlsdXJlKSA9PiB7CiAgICAgICAgICByZXR1cm4gKGlucHV0LCBpKSA9PiB7CiAgICAgICAgICAgICAgbGV0IHJlc3VsdCA9IGJhc2UuXyhpbnB1dCwgaSk7CiAgICAgICAgICAgICAgaWYgKCFyZXN1bHQuc3RhdHVzKQogICAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgICAgIGZvciAobGV0IGZ1bmMgb2YgZnVuY3MpIHsKICAgICAgICAgICAgICAgICAgbGV0IG5leHQgPSBmdW5jKHJlc3VsdC52YWx1ZSkuXyhpbnB1dCwgcmVzdWx0LmluZGV4KTsKICAgICAgICAgICAgICAgICAgaWYgKCFuZXh0LnN0YXR1cykKICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IG5leHQ7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9OwogICAgICB9KTsKICB9CiAgY29uc3QgRVhQUkVTU0lPTiA9IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5jcmVhdGVMYW5ndWFnZSh7CiAgICAgIC8vIEEgZmxvYXRpbmcgcG9pbnQgbnVtYmVyOyB0aGUgZGVjaW1hbCBwb2ludCBpcyBvcHRpb25hbC4KICAgICAgbnVtYmVyOiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoLy0/WzAtOV0rKFwuWzAtOV0rKT8vKQogICAgICAgICAgLm1hcChzdHIgPT4gTnVtYmVyLnBhcnNlRmxvYXQoc3RyKSkKICAgICAgICAgIC5kZXNjKCJudW1iZXIiKSwKICAgICAgLy8gQSBxdW90ZS1zdXJyb3VuZGVkIHN0cmluZyB3aGljaCBzdXBwb3J0cyBlc2NhcGUgY2hhcmFjdGVycyAoJ1wnKS4KICAgICAgc3RyaW5nOiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoJyInKQogICAgICAgICAgLnRoZW4ocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLmFsdChxLmVzY2FwZUNoYXJhY3RlciwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm5vbmVPZignIlxcJykpCiAgICAgICAgICAuYXRMZWFzdCgwKQogICAgICAgICAgLm1hcChjaGFycyA9PiBjaGFycy5qb2luKCIiKSkpCiAgICAgICAgICAuc2tpcChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCciJykpCiAgICAgICAgICAuZGVzYygic3RyaW5nIiksCiAgICAgIGVzY2FwZUNoYXJhY3RlcjogXyA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCJcXCIpCiAgICAgICAgICAudGhlbihwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuYW55KQogICAgICAgICAgLm1hcChlc2NhcGVkID0+IHsKICAgICAgICAgIC8vIElmIHdlIGFyZSBlc2NhcGluZyBhIGJhY2tzbGFzaCBvciBhIHF1b3RlLCBwYXNzIGluIG9uIGluIGVzY2FwZWQgZm9ybQogICAgICAgICAgaWYgKGVzY2FwZWQgPT09ICciJykKICAgICAgICAgICAgICByZXR1cm4gJyInOwogICAgICAgICAgaWYgKGVzY2FwZWQgPT09ICJcXCIpCiAgICAgICAgICAgICAgcmV0dXJuICJcXCI7CiAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgcmV0dXJuICJcXCIgKyBlc2NhcGVkOwogICAgICB9KSwKICAgICAgLy8gQSBib29sZWFuIHRydWUvZmFsc2UgdmFsdWUuCiAgICAgIGJvb2w6IF8gPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvdHJ1ZXxmYWxzZXxUcnVlfEZhbHNlLykKICAgICAgICAgIC5tYXAoc3RyID0+IHN0ci50b0xvd2VyQ2FzZSgpID09ICJ0cnVlIikKICAgICAgICAgIC5kZXNjKCJib29sZWFuICgndHJ1ZScgb3IgJ2ZhbHNlJykiKSwKICAgICAgLy8gQSB0YWcgb2YgdGhlIGZvcm0gJyNzdHVmZi9oZWxsby10aGVyZScuCiAgICAgIHRhZzogXyA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIiMiKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLmFsdChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMucmVnZXhwKC9bXlx1MjAwMC1cdTIwNkZcdTJFMDAtXHUyRTdGJyEiIyQlJigpKissLjo7PD0+P0BeYHt8fX5cW1xdXFxcc10vKS5kZXNjKCJ0ZXh0IikpLm1hbnkoKSwgKHN0YXJ0LCByZXN0KSA9PiBzdGFydCArIHJlc3Quam9pbigiIikpLmRlc2MoInRhZyAoJyNoZWxsby9zdHVmZicpIiksCiAgICAgIC8vIEEgdmFyaWFibGUgaWRlbnRpZmllciwgd2hpY2ggaXMgYWxwaGFudW1lcmljIGFuZCBtdXN0IHN0YXJ0IHdpdGggYSBsZXR0ZXIgb3IuLi4gZW1vamkuCiAgICAgIGlkZW50aWZpZXI6IF8gPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnNlcU1hcChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuYWx0KHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoL1xwe0xldHRlcn0vdSksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoRU1PSklfUkVHRVgpLmRlc2MoInRleHQiKSksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbHQocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvWzAtOVxwe0xldHRlcn1fLV0vdSksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoRU1PSklfUkVHRVgpLmRlc2MoInRleHQiKSkubWFueSgpLCAoZmlyc3QsIHJlc3QpID0+IGZpcnN0ICsgcmVzdC5qb2luKCIiKSkuZGVzYygidmFyaWFibGUgaWRlbnRpZmllciIpLAogICAgICAvLyBBbiBPYnNpZGlhbiBsaW5rIG9mIHRoZSBmb3JtIFtbPGxpbms+XV0uCiAgICAgIGxpbms6IF8gPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvXFtcWyhbXlxbXF1dKj8pXF1cXS91LCAxKQogICAgICAgICAgLm1hcChsaW5rSW5uZXIgPT4gcGFyc2VJbm5lckxpbmsobGlua0lubmVyKSkKICAgICAgICAgIC5kZXNjKCJmaWxlIGxpbmsiKSwKICAgICAgLy8gQW4gZW1iZWRkYWJsZSBsaW5rIHdoaWNoIGNhbiBzdGFydCB3aXRoICchJy4gVGhpcyBvdmVybGFwcyB3aXRoIHRoZSBub3JtYWwgbmVnYXRpb24gb3BlcmF0b3IsIHNvIGl0IGlzIG9ubHkKICAgICAgLy8gcHJvdmlkZWQgZm9yIG1ldGFkYXRhIHBhcnNpbmcuCiAgICAgIGVtYmVkTGluazogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIiEiKS5hdE1vc3QoMSksIHEubGluaywgKHAsIGwpID0+IHsKICAgICAgICAgIGlmIChwLmxlbmd0aCA+IDApCiAgICAgICAgICAgICAgbC5lbWJlZCA9IHRydWU7CiAgICAgICAgICByZXR1cm4gbDsKICAgICAgfSkuZGVzYygiZmlsZSBsaW5rIiksCiAgICAgIC8vIEJpbmFyeSBwbHVzIG9yIG1pbnVzIG9wZXJhdG9yLgogICAgICBiaW5hcnlQbHVzTWludXM6IF8gPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvXCt8LS8pCiAgICAgICAgICAubWFwKHN0ciA9PiBzdHIpCiAgICAgICAgICAuZGVzYygiJysnIG9yICctJyIpLAogICAgICAvLyBCaW5hcnkgdGltZXMgb3IgZGl2aWRlIG9wZXJhdG9yLgogICAgICBiaW5hcnlNdWxEaXY6IF8gPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvXCp8XC98JS8pCiAgICAgICAgICAubWFwKHN0ciA9PiBzdHIpCiAgICAgICAgICAuZGVzYygiJyonIG9yICcvJyBvciAnJSciKSwKICAgICAgLy8gQmluYXJ5IGNvbXBhcmlzb24gb3BlcmF0b3IuCiAgICAgIGJpbmFyeUNvbXBhcmVPcDogXyA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMucmVnZXhwKC8+PXw8PXwhPXw+fDx8PS8pCiAgICAgICAgICAubWFwKHN0ciA9PiBzdHIpCiAgICAgICAgICAuZGVzYygiJz49JyBvciAnPD0nIG9yICchPScgb3IgJz0nIG9yICc+JyBvciAnPCciKSwKICAgICAgLy8gQmluYXJ5IGJvb2xlYW4gY29tYmluYXRpb24gb3BlcmF0b3IuCiAgICAgIGJpbmFyeUJvb2xlYW5PcDogXyA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMucmVnZXhwKC9hbmR8b3J8JnxcfC9pKQogICAgICAgICAgLm1hcChzdHIgPT4gewogICAgICAgICAgaWYgKHN0ci50b0xvd2VyQ2FzZSgpID09ICJhbmQiKQogICAgICAgICAgICAgIHJldHVybiAiJiI7CiAgICAgICAgICBlbHNlIGlmIChzdHIudG9Mb3dlckNhc2UoKSA9PSAib3IiKQogICAgICAgICAgICAgIHJldHVybiAifCI7CiAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgcmV0dXJuIHN0cjsKICAgICAgfSkKICAgICAgICAgIC5kZXNjKCInYW5kJyBvciAnb3InIiksCiAgICAgIC8vIEEgZGF0ZSB3aGljaCBjYW4gYmUgWVlZWS1NTVstRERUSEg6bW06c3NdLgogICAgICByb290RGF0ZTogXyA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoL1xkezR9LyksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIi0iKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvXGR7Mn0vKSwgKHllYXIsIF8sIG1vbnRoKSA9PiB7CiAgICAgICAgICByZXR1cm4gRGF0ZVRpbWUuZnJvbU9iamVjdCh7IHllYXI6IE51bWJlci5wYXJzZUludCh5ZWFyKSwgbW9udGg6IE51bWJlci5wYXJzZUludChtb250aCkgfSk7CiAgICAgIH0pLmRlc2MoImRhdGUgaW4gZm9ybWF0IFlZWVktTU1bLUREVEhILU1NLVNTLk1TXSIpLAogICAgICBkYXRlU2hvcnRoYW5kOiBfID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbHQoLi4uT2JqZWN0LmtleXMoREFURV9TSE9SVEhBTkRTKQogICAgICAgICAgLnNvcnQoKGEsIGIpID0+IGIubGVuZ3RoIC0gYS5sZW5ndGgpCiAgICAgICAgICAubWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcpKSwKICAgICAgZGF0ZTogcSA9PiBjaGFpbk9wdChxLnJvb3REYXRlLCAoeW0pID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiLSIpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMucmVnZXhwKC9cZHsyfS8pLCAoXywgZGF5KSA9PiB5bS5zZXQoeyBkYXk6IE51bWJlci5wYXJzZUludChkYXkpIH0pKSwgKHltZCkgPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnNlcU1hcChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCJUIiksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoL1xkezJ9LyksIChfLCBob3VyKSA9PiB5bWQuc2V0KHsgaG91cjogTnVtYmVyLnBhcnNlSW50KGhvdXIpIH0pKSwgKHltZGgpID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiOiIpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMucmVnZXhwKC9cZHsyfS8pLCAoXywgbWludXRlKSA9PiB5bWRoLnNldCh7IG1pbnV0ZTogTnVtYmVyLnBhcnNlSW50KG1pbnV0ZSkgfSkpLCAoeW1kaG0pID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiOiIpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMucmVnZXhwKC9cZHsyfS8pLCAoXywgc2Vjb25kKSA9PiB5bWRobS5zZXQoeyBzZWNvbmQ6IE51bWJlci5wYXJzZUludChzZWNvbmQpIH0pKSwgKHltZGhtcykgPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLmFsdChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIi4iKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvXGR7M30vKSwgKF8sIG1pbGxpc2Vjb25kKSA9PiB5bWRobXMuc2V0KHsgbWlsbGlzZWNvbmQ6IE51bWJlci5wYXJzZUludChtaWxsaXNlY29uZCkgfSkpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3VjY2VlZCh5bWRobXMpIC8vIHBhc3MKICAgICAgKSwgKGR0KSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuYWx0KHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiKyIpLm9yKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIi0iKSksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoL1xkezEsMn0oOlxkezJ9KT8vKSwgKHBtLCBocikgPT4gZHQuc2V0Wm9uZSgiVVRDIiArIHBtICsgaHIsIHsga2VlcExvY2FsVGltZTogdHJ1ZSB9KSksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiWiIpLCAoKSA9PiBkdC5zZXRab25lKCJ1dGMiLCB7IGtlZXBMb2NhbFRpbWU6IHRydWUgfSkpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIlsiKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvWzAtOUEtWmEteistXC9dKy91KSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiXSIpLCAoX2EsIHpvbmUsIF9iKSA9PiBkdC5zZXRab25lKHpvbmUsIHsga2VlcExvY2FsVGltZTogdHJ1ZSB9KSkpKQogICAgICAgICAgLmFzc2VydCgoZHQpID0+IGR0LmlzVmFsaWQsICJ2YWxpZCBkYXRlIikKICAgICAgICAgIC5kZXNjKCJkYXRlIGluIGZvcm1hdCBZWVlZLU1NWy1ERFRISC1NTS1TUy5NU10iKSwKICAgICAgLy8gQSBkYXRlLCBwbHVzIHZhcmlvdXMgc2hvcnRoYW5kIHRpbWVzIG9mIGRheSBpdCBjb3VsZCBiZS4KICAgICAgZGF0ZVBsdXM6IHEgPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLmFsdChxLmRhdGVTaG9ydGhhbmQubWFwKGQgPT4gREFURV9TSE9SVEhBTkRTW2RdKCkpLCBxLmRhdGUpLmRlc2MoImRhdGUgaW4gZm9ybWF0IFlZWVktTU1bLUREVEhILU1NLVNTLk1TXSBvciBpbiBzaG9ydGhhbmQiKSwKICAgICAgLy8gQSBkdXJhdGlvbiBvZiB0aW1lLgogICAgICBkdXJhdGlvblR5cGU6IF8gPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLmFsdCguLi5PYmplY3Qua2V5cyhEVVJBVElPTl9UWVBFUykKICAgICAgICAgIC5zb3J0KChhLCBiKSA9PiBiLmxlbmd0aCAtIGEubGVuZ3RoKQogICAgICAgICAgLm1hcChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKSksCiAgICAgIGR1cmF0aW9uOiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocS5udW1iZXIsIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlLCBxLmR1cmF0aW9uVHlwZSwgKGNvdW50LCBfLCB0KSA9PiBEVVJBVElPTl9UWVBFU1t0XS5tYXBVbml0cyh4ID0+IHggKiBjb3VudCkpCiAgICAgICAgICAuc2VwQnkxKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIiwiKS50cmltKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKS5vcihwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSkpCiAgICAgICAgICAubWFwKGR1cmF0aW9ucyA9PiBkdXJhdGlvbnMucmVkdWNlKChwLCBjKSA9PiBwLnBsdXMoYykpKQogICAgICAgICAgLmRlc2MoImR1cmF0aW9uIGxpa2UgNGhyMm1pbiIpLAogICAgICAvLyBBIHJhdyBudWxsIHZhbHVlLgogICAgICByYXdOdWxsOiBfID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIm51bGwiKSwKICAgICAgLy8gU291cmNlIHBhcnNpbmcuCiAgICAgIHRhZ1NvdXJjZTogcSA9PiBxLnRhZy5tYXAodGFnID0+IFNvdXJjZXMudGFnKHRhZykpLAogICAgICBjc3ZTb3VyY2U6IHEgPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnNlcU1hcChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCJjc3YoIikuc2tpcChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSksIHEuc3RyaW5nLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCIpIiksIChfMSwgcGF0aCwgXzIpID0+IFNvdXJjZXMuY3N2KHBhdGgpKSwKICAgICAgbGlua0luY29taW5nU291cmNlOiBxID0+IHEubGluay5tYXAobGluayA9PiBTb3VyY2VzLmxpbmsobGluay5wYXRoLCB0cnVlKSksCiAgICAgIGxpbmtPdXRnb2luZ1NvdXJjZTogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIm91dGdvaW5nKCIpLnNraXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UpLCBxLmxpbmssIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIikiKSwgKF8xLCBsaW5rLCBfMikgPT4gU291cmNlcy5saW5rKGxpbmsucGF0aCwgZmFsc2UpKSwKICAgICAgZm9sZGVyU291cmNlOiBxID0+IHEuc3RyaW5nLm1hcChzdHIgPT4gU291cmNlcy5mb2xkZXIoc3RyKSksCiAgICAgIHBhcmVuc1NvdXJjZTogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIigiKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UsIHEuc291cmNlLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiKSIpLCAoXzEsIF8yLCBmaWVsZCwgXzMsIF80KSA9PiBmaWVsZCksCiAgICAgIG5lZ2F0ZVNvdXJjZTogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbHQocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiLSIpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCIhIikpLCBxLmF0b21Tb3VyY2UsIChfLCBzb3VyY2UpID0+IFNvdXJjZXMubmVnYXRlKHNvdXJjZSkpLAogICAgICBhdG9tU291cmNlOiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbHQocS5wYXJlbnNTb3VyY2UsIHEubmVnYXRlU291cmNlLCBxLmxpbmtPdXRnb2luZ1NvdXJjZSwgcS5saW5rSW5jb21pbmdTb3VyY2UsIHEuZm9sZGVyU291cmNlLCBxLnRhZ1NvdXJjZSwgcS5jc3ZTb3VyY2UpLAogICAgICBiaW5hcnlPcFNvdXJjZTogcSA9PiBjcmVhdGVCaW5hcnlQYXJzZXIocS5hdG9tU291cmNlLCBxLmJpbmFyeUJvb2xlYW5PcC5tYXAocyA9PiBzKSwgU291cmNlcy5iaW5hcnlPcCksCiAgICAgIHNvdXJjZTogcSA9PiBxLmJpbmFyeU9wU291cmNlLAogICAgICAvLyBGaWVsZCBwYXJzaW5nLgogICAgICB2YXJpYWJsZUZpZWxkOiBxID0+IHEuaWRlbnRpZmllcgogICAgICAgICAgLmNoYWluKHIgPT4gewogICAgICAgICAgaWYgKEtFWVdPUkRTLmluY2x1ZGVzKHIudG9VcHBlckNhc2UoKSkpIHsKICAgICAgICAgICAgICByZXR1cm4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLmZhaWwoIlZhcmlhYmxlIGZpZWxkcyBjYW5ub3QgYmUgYSBrZXl3b3JkICgiICsgS0VZV09SRFMuam9pbigiIG9yICIpICsgIikiKTsKICAgICAgICAgIH0KICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgIHJldHVybiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3VjY2VlZChGaWVsZHMudmFyaWFibGUocikpOwogICAgICAgICAgfQogICAgICB9KQogICAgICAgICAgLmRlc2MoInZhcmlhYmxlIiksCiAgICAgIG51bWJlckZpZWxkOiBxID0+IHEubnVtYmVyLm1hcCh2YWwgPT4gRmllbGRzLmxpdGVyYWwodmFsKSkuZGVzYygibnVtYmVyIiksCiAgICAgIHN0cmluZ0ZpZWxkOiBxID0+IHEuc3RyaW5nLm1hcCh2YWwgPT4gRmllbGRzLmxpdGVyYWwodmFsKSkuZGVzYygic3RyaW5nIiksCiAgICAgIGJvb2xGaWVsZDogcSA9PiBxLmJvb2wubWFwKHZhbCA9PiBGaWVsZHMubGl0ZXJhbCh2YWwpKS5kZXNjKCJib29sZWFuIiksCiAgICAgIGRhdGVGaWVsZDogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoImRhdGUoIiksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlLCBxLmRhdGVQbHVzLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiKSIpLCAocHJlZml4LCBfMSwgZGF0ZSwgXzIsIHBvc3RmaXgpID0+IEZpZWxkcy5saXRlcmFsKGRhdGUpKS5kZXNjKCJkYXRlIiksCiAgICAgIGR1cmF0aW9uRmllbGQ6IHEgPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnNlcU1hcChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCJkdXIoIiksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlLCBxLmR1cmF0aW9uLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiKSIpLCAocHJlZml4LCBfMSwgZHVyLCBfMiwgcG9zdGZpeCkgPT4gRmllbGRzLmxpdGVyYWwoZHVyKSkuZGVzYygiZHVyYXRpb24iKSwKICAgICAgbnVsbEZpZWxkOiBxID0+IHEucmF3TnVsbC5tYXAoXyA9PiBGaWVsZHMuTlVMTCksCiAgICAgIGxpbmtGaWVsZDogcSA9PiBxLmxpbmsubWFwKGYgPT4gRmllbGRzLmxpdGVyYWwoZikpLAogICAgICBsaXN0RmllbGQ6IHEgPT4gcS5maWVsZAogICAgICAgICAgLnNlcEJ5KHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIiwiKS50cmltKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKSkKICAgICAgICAgIC53cmFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIlsiKS5za2lwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UudGhlbihwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCJdIikpKQogICAgICAgICAgLm1hcChsID0+IEZpZWxkcy5saXN0KGwpKQogICAgICAgICAgLmRlc2MoImxpc3QgKCdbMSwgMiwgM10nKSIpLAogICAgICBvYmplY3RGaWVsZDogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHEuaWRlbnRpZmllci5vcihxLnN0cmluZyksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIjoiKS50cmltKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKSwgcS5maWVsZCwgKG5hbWUsIF9zZXAsIHZhbHVlKSA9PiB7CiAgICAgICAgICByZXR1cm4geyBuYW1lLCB2YWx1ZSB9OwogICAgICB9KQogICAgICAgICAgLnNlcEJ5KHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIiwiKS50cmltKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKSkKICAgICAgICAgIC53cmFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoInsiKS5za2lwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UudGhlbihwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCJ9IikpKQogICAgICAgICAgLm1hcCh2YWxzID0+IHsKICAgICAgICAgIGxldCByZXMgPSB7fTsKICAgICAgICAgIGZvciAobGV0IGVudHJ5IG9mIHZhbHMpCiAgICAgICAgICAgICAgcmVzW2VudHJ5Lm5hbWVdID0gZW50cnkudmFsdWU7CiAgICAgICAgICByZXR1cm4gRmllbGRzLm9iamVjdChyZXMpOwogICAgICB9KQogICAgICAgICAgLmRlc2MoIm9iamVjdCAoJ3sgYTogMSwgYjogMiB9JykiKSwKICAgICAgYXRvbUlubGluZUZpZWxkOiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbHQocS5kYXRlLCBxLmR1cmF0aW9uLm1hcChkID0+IG5vcm1hbGl6ZUR1cmF0aW9uKGQpKSwgcS5zdHJpbmcsIHEudGFnLCBxLmVtYmVkTGluaywgcS5ib29sLCBxLm51bWJlciwgcS5yYXdOdWxsKSwKICAgICAgaW5saW5lRmllbGRMaXN0OiBxID0+IHEuYXRvbUlubGluZUZpZWxkLnNlcEJ5KHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIiwiKS50cmltKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKS5sb29rYWhlYWQocS5hdG9tSW5saW5lRmllbGQpKSwKICAgICAgaW5saW5lRmllbGQ6IHEgPT4gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLmFsdChwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHEuYXRvbUlubGluZUZpZWxkLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCIsIikudHJpbShwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSksIHEuaW5saW5lRmllbGRMaXN0LCAoZiwgX3MsIGwpID0+IFtmXS5jb25jYXQobCkpLCBxLmF0b21JbmxpbmVGaWVsZCksCiAgICAgIGF0b21GaWVsZDogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuYWx0KAogICAgICAvLyBQbGFjZSBlbWJlZCBsaW5rcyBhYm92ZSBuZWdhdGVkIGZpZWxkcyBhcyB0aGV5IGFyZSB0aGUgc3BlY2lhbCBwYXJzZXIgY2FzZSAnIVtbdGhpbmddXScgYW5kIGFyZSBnZW5lcmFsbHkgdW5hbWJpZ2lvdXMuCiAgICAgIHEuZW1iZWRMaW5rLm1hcChsID0+IEZpZWxkcy5saXRlcmFsKGwpKSwgcS5uZWdhdGVkRmllbGQsIHEubGlua0ZpZWxkLCBxLmxpc3RGaWVsZCwgcS5vYmplY3RGaWVsZCwgcS5sYW1iZGFGaWVsZCwgcS5wYXJlbnNGaWVsZCwgcS5ib29sRmllbGQsIHEubnVtYmVyRmllbGQsIHEuc3RyaW5nRmllbGQsIHEuZGF0ZUZpZWxkLCBxLmR1cmF0aW9uRmllbGQsIHEubnVsbEZpZWxkLCBxLnZhcmlhYmxlRmllbGQpLAogICAgICBpbmRleEZpZWxkOiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocS5hdG9tRmllbGQsIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbHQocS5kb3RQb3N0Zml4LCBxLmluZGV4UG9zdGZpeCwgcS5mdW5jdGlvblBvc3RmaXgpLm1hbnkoKSwgKG9iaiwgcG9zdGZpeGVzKSA9PiB7CiAgICAgICAgICBsZXQgcmVzdWx0ID0gb2JqOwogICAgICAgICAgZm9yIChsZXQgcG9zdCBvZiBwb3N0Zml4ZXMpIHsKICAgICAgICAgICAgICBzd2l0Y2ggKHBvc3QudHlwZSkgewogICAgICAgICAgICAgICAgICBjYXNlICJkb3QiOgogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gRmllbGRzLmluZGV4KHJlc3VsdCwgRmllbGRzLmxpdGVyYWwocG9zdC5maWVsZCkpOwogICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgIGNhc2UgImluZGV4IjoKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IEZpZWxkcy5pbmRleChyZXN1bHQsIHBvc3QuZmllbGQpOwogICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgIGNhc2UgImZ1bmN0aW9uIjoKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IEZpZWxkcy5mdW5jKHJlc3VsdCwgcG9zdC5maWVsZHMpOwogICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfSksCiAgICAgIG5lZ2F0ZWRGaWVsZDogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIiEiKSwgcS5pbmRleEZpZWxkLCAoXywgZmllbGQpID0+IEZpZWxkcy5uZWdhdGUoZmllbGQpKS5kZXNjKCJuZWdhdGVkIGZpZWxkIiksCiAgICAgIHBhcmVuc0ZpZWxkOiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiKCIpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSwgcS5maWVsZCwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UsIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIikiKSwgKF8xLCBfMiwgZmllbGQsIF8zLCBfNCkgPT4gZmllbGQpLAogICAgICBsYW1iZGFGaWVsZDogcSA9PiBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc2VxTWFwKHEuaWRlbnRpZmllcgogICAgICAgICAgLnNlcEJ5KHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIiwiKS50cmltKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKSkKICAgICAgICAgIC53cmFwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIigiKS50cmltKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiKSIpLnRyaW0ocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UpKSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiPT4iKS50cmltKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5vcHRXaGl0ZXNwYWNlKSwgcS5maWVsZCwgKGlkZW50LCBfaWdub3JlLCB2YWx1ZSkgPT4gewogICAgICAgICAgcmV0dXJuIHsgdHlwZTogImxhbWJkYSIsIGFyZ3VtZW50czogaWRlbnQsIHZhbHVlIH07CiAgICAgIH0pLAogICAgICBkb3RQb3N0Zml4OiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiLiIpLCBxLmlkZW50aWZpZXIsIChfLCBmaWVsZCkgPT4gewogICAgICAgICAgcmV0dXJuIHsgdHlwZTogImRvdCIsIGZpZWxkOiBmaWVsZCB9OwogICAgICB9KSwKICAgICAgaW5kZXhQb3N0Zml4OiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiWyIpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSwgcS5maWVsZCwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLm9wdFdoaXRlc3BhY2UsIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zdHJpbmcoIl0iKSwgKF8sIF8yLCBmaWVsZCwgXzMsIF80KSA9PiB7CiAgICAgICAgICByZXR1cm4geyB0eXBlOiAiaW5kZXgiLCBmaWVsZCB9OwogICAgICB9KSwKICAgICAgZnVuY3Rpb25Qb3N0Zml4OiBxID0+IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5zZXFNYXAocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiKCIpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSwgcS5maWVsZC5zZXBCeShwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMuc3RyaW5nKCIsIikudHJpbShwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSkpLCBwYXJzaW1tb25fdW1kX21pbkV4cG9ydHMub3B0V2hpdGVzcGFjZSwgcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnN0cmluZygiKSIpLCAoXywgXzEsIGZpZWxkcywgXzIsIF8zKSA9PiB7CiAgICAgICAgICByZXR1cm4geyB0eXBlOiAiZnVuY3Rpb24iLCBmaWVsZHMgfTsKICAgICAgfSksCiAgICAgIC8vIFRoZSBwcmVjZWRlbmNlIGhpZXJhcmNoeSBvZiBvcGVyYXRvcnMgLSBtdWx0aXBseS9kaXZpZGUsIGFkZC9zdWJ0cmFjdCwgY29tcGFyZSwgYW5kIHRoZW4gYm9vbGVhbiBvcGVyYXRpb25zLgogICAgICBiaW5hcnlNdWxEaXZGaWVsZDogcSA9PiBjcmVhdGVCaW5hcnlQYXJzZXIocS5pbmRleEZpZWxkLCBxLmJpbmFyeU11bERpdiwgRmllbGRzLmJpbmFyeU9wKSwKICAgICAgYmluYXJ5UGx1c01pbnVzRmllbGQ6IHEgPT4gY3JlYXRlQmluYXJ5UGFyc2VyKHEuYmluYXJ5TXVsRGl2RmllbGQsIHEuYmluYXJ5UGx1c01pbnVzLCBGaWVsZHMuYmluYXJ5T3ApLAogICAgICBiaW5hcnlDb21wYXJlRmllbGQ6IHEgPT4gY3JlYXRlQmluYXJ5UGFyc2VyKHEuYmluYXJ5UGx1c01pbnVzRmllbGQsIHEuYmluYXJ5Q29tcGFyZU9wLCBGaWVsZHMuYmluYXJ5T3ApLAogICAgICBiaW5hcnlCb29sZWFuRmllbGQ6IHEgPT4gY3JlYXRlQmluYXJ5UGFyc2VyKHEuYmluYXJ5Q29tcGFyZUZpZWxkLCBxLmJpbmFyeUJvb2xlYW5PcCwgRmllbGRzLmJpbmFyeU9wKSwKICAgICAgYmluYXJ5T3BGaWVsZDogcSA9PiBxLmJpbmFyeUJvb2xlYW5GaWVsZCwKICAgICAgZmllbGQ6IHEgPT4gcS5iaW5hcnlPcEZpZWxkLAogIH0pOwoKICAvKiogUGFyc2UgaW5saW5lIGZpZWxkcyBhbmQgb3RoZXIgZW1iZWRkZWQgbWV0YWRhdGEgaW4gYSBsaW5lLiAqLwogIC8qKiBUaGUgd3JhcHBlciBjaGFyYWN0ZXJzIHRoYXQgY2FuIGJlIHVzZWQgdG8gZGVmaW5lIGFuIGlubGluZSBmaWVsZC4gKi8KICBjb25zdCBJTkxJTkVfRklFTERfV1JBUFBFUlMgPSBPYmplY3QuZnJlZXplKHsKICAgICAgIlsiOiAiXSIsCiAgICAgICIoIjogIikiLAogIH0pOwogIC8qKgogICAqIEZpbmQgYSBtYXRjaGluZyBjbG9zaW5nIGJyYWNrZXQgdGhhdCBvY2N1cnMgYXQgb3IgYWZ0ZXIgYHN0YXJ0YCwgcmVzcGVjdGluZyBuZXN0aW5nIGFuZCBlc2NhcGVzLiBJZiBmb3VuZCwKICAgKiByZXR1cm5zIHRoZSB2YWx1ZSBjb250YWluZWQgd2l0aGluIGFuZCB0aGUgc3RyaW5nIGluZGV4IGFmdGVyIHRoZSBlbmQgb2YgdGhlIHZhbHVlLgogICAqLwogIGZ1bmN0aW9uIGZpbmRDbG9zaW5nKGxpbmUsIHN0YXJ0LCBvcGVuLCBjbG9zZSkgewogICAgICBsZXQgbmVzdGluZyA9IDA7CiAgICAgIGxldCBlc2NhcGVkID0gZmFsc2U7CiAgICAgIGZvciAobGV0IGluZGV4ID0gc3RhcnQ7IGluZGV4IDwgbGluZS5sZW5ndGg7IGluZGV4KyspIHsKICAgICAgICAgIGxldCBjaGFyID0gbGluZS5jaGFyQXQoaW5kZXgpOwogICAgICAgICAgLy8gQWxsb3dzIGZvciBkb3VibGUgZXNjYXBlcyBsaWtlICdcXCcgdG8gYmUgcmVuZGVyZWQgbm9ybWFsbHkuCiAgICAgICAgICBpZiAoY2hhciA9PSAiXFwiKSB7CiAgICAgICAgICAgICAgZXNjYXBlZCA9ICFlc2NhcGVkOwogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgfQogICAgICAgICAgLy8gSWYgZXNjYXBlZCwgaWdub3JlIHRoZSBuZXh0IGNoYXJhY3RlciBmb3IgY29tcHV0aW5nIG5lc3RpbmcsIHJlZ2FyZGxlc3Mgb2Ygd2hhdCBpdCBpcy4KICAgICAgICAgIGlmIChlc2NhcGVkKSB7CiAgICAgICAgICAgICAgZXNjYXBlZCA9IGZhbHNlOwogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGNoYXIgPT0gb3BlbikKICAgICAgICAgICAgICBuZXN0aW5nKys7CiAgICAgICAgICBlbHNlIGlmIChjaGFyID09IGNsb3NlKQogICAgICAgICAgICAgIG5lc3RpbmctLTsKICAgICAgICAgIC8vIE9ubHkgb2NjdXJzIGlmIHdlIGFyZSBvbiBhIGNsb3NlIGNoYXJhY3RlciBhbmQgdHJoZXJlIGlzIG5vIG1vcmUgbmVzdGluZy4KICAgICAgICAgIGlmIChuZXN0aW5nIDwgMCkKICAgICAgICAgICAgICByZXR1cm4geyB2YWx1ZTogbGluZS5zdWJzdHJpbmcoc3RhcnQsIGluZGV4KS50cmltKCksIGVuZEluZGV4OiBpbmRleCArIDEgfTsKICAgICAgICAgIGVzY2FwZWQgPSBmYWxzZTsKICAgICAgfQogICAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KICAvKiogRmluZCB0aGUgJzo6JyBzZXBhcmF0b3IgaW4gYW4gaW5saW5lIGZpZWxkLiAqLwogIGZ1bmN0aW9uIGZpbmRTZXBhcmF0b3IobGluZSwgc3RhcnQpIHsKICAgICAgbGV0IHNlcCA9IGxpbmUuaW5kZXhPZigiOjoiLCBzdGFydCk7CiAgICAgIGlmIChzZXAgPCAwKQogICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgICAgcmV0dXJuIHsga2V5OiBsaW5lLnN1YnN0cmluZyhzdGFydCwgc2VwKS50cmltKCksIHZhbHVlSW5kZXg6IHNlcCArIDIgfTsKICB9CiAgLyoqIFRyeSB0byBjb21wbGV0ZWx5IHBhcnNlIGFuIGlubGluZSBmaWVsZCBzdGFydGluZyBhdCB0aGUgZ2l2ZW4gcG9zaXRpb24uIEFzc3VlbXMgYHN0YXJ0YCBpcyBvbiBhIHdyYXBwaW5nIGNoYXJhY3Rlci4gKi8KICBmdW5jdGlvbiBmaW5kU3BlY2lmaWNJbmxpbmVGaWVsZChsaW5lLCBzdGFydCkgewogICAgICBsZXQgb3BlbiA9IGxpbmUuY2hhckF0KHN0YXJ0KTsKICAgICAgbGV0IGtleSA9IGZpbmRTZXBhcmF0b3IobGluZSwgc3RhcnQgKyAxKTsKICAgICAgaWYgKGtleSA9PT0gdW5kZWZpbmVkKQogICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgICAgLy8gRmFpbCB0aGUgbWF0Y2ggaWYgd2UgZmluZCBhbnkgc2VwYXJhdG9yIGNoYXJhY3RlcnMgKG5vdCBhbGxvd2VkIGluIGtleXMpLgogICAgICBmb3IgKGxldCBzZXAgb2YgT2JqZWN0LmtleXMoSU5MSU5FX0ZJRUxEX1dSQVBQRVJTKS5jb25jYXQoT2JqZWN0LnZhbHVlcyhJTkxJTkVfRklFTERfV1JBUFBFUlMpKSkgewogICAgICAgICAgaWYgKGtleS5rZXkuaW5jbHVkZXMoc2VwKSkKICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkOwogICAgICB9CiAgICAgIGxldCB2YWx1ZSA9IGZpbmRDbG9zaW5nKGxpbmUsIGtleS52YWx1ZUluZGV4LCBvcGVuLCBJTkxJTkVfRklFTERfV1JBUFBFUlNbb3Blbl0pOwogICAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkKICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7CiAgICAgIHJldHVybiB7CiAgICAgICAgICBrZXk6IGtleS5rZXksCiAgICAgICAgICB2YWx1ZTogdmFsdWUudmFsdWUsCiAgICAgICAgICBzdGFydDogc3RhcnQsCiAgICAgICAgICBzdGFydFZhbHVlOiBrZXkudmFsdWVJbmRleCwKICAgICAgICAgIGVuZDogdmFsdWUuZW5kSW5kZXgsCiAgICAgICAgICB3cmFwcGluZzogb3BlbiwKICAgICAgfTsKICB9CiAgLyoqIFBhcnNlIGEgdGV4dHVhbCBpbmxpbmUgZmllbGQgdmFsdWUgaW50byBzb21ldGhpbmcgd2UgY2FuIHdvcmsgd2l0aC4gKi8KICBmdW5jdGlvbiBwYXJzZUlubGluZVZhbHVlKHZhbHVlKSB7CiAgICAgIC8vIEVtcHR5IGlubGluZSB2YWx1ZXMgKGkuZS4sIG5vIHRleHQpIHNob3VsZCBtYXAgdG8gbnVsbCB0byBtYXRjaCBsb25nLXRlcm0gRGF0YXZpZXcgc2VtYW50aWNzLgogICAgICAvLyBOdWxsIGlzIGFsc28gYSBtb3JlIHVuaXZlcnNhbCB0eXBlIHRvIGRlYWwgd2l0aCB0aGFuIHN0cmluZ3MsIHNpbmNlIGFsbCBmdW5jdGlvbnMgYWNjZXB0IG51bGxzLgogICAgICBpZiAodmFsdWUudHJpbSgpID09ICIiKQogICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgIC8vIFRoZSBzdHJpcHBlZCBsaXRlcmFsIGZpZWxkIHBhcnNlciB1bmRlcnN0YW5kcyBhbGwgb2YgdGhlIG5vbi1hcnJheS9ub24tb2JqZWN0IGZpZWxkcyBhbmQgY2FuIHBhcnNlIHRoZW0gZm9yIHVzLgogICAgICAvLyBJbmxpbmUgZmllbGQgb2JqZWN0cyBhcmUgbm90IGN1cnJlbnRseSBzdXBwb3J0ZWQ7IGlubGluZSBhcnJheSBvYmplY3RzIGhhdmUgdG8gYmUgaGFuZGxlZCBieSB0aGUgcGFyc2VyCiAgICAgIC8vIHNlcGFyYXRlbHkuCiAgICAgIGxldCBpbmxpbmUgPSBFWFBSRVNTSU9OLmlubGluZUZpZWxkLnBhcnNlKHZhbHVlKTsKICAgICAgaWYgKGlubGluZS5zdGF0dXMpCiAgICAgICAgICByZXR1cm4gaW5saW5lLnZhbHVlOwogICAgICBlbHNlCiAgICAgICAgICByZXR1cm4gdmFsdWU7CiAgfQogIC8qKiBFeHRyYWN0cyBpbmxpbmUgZmllbGRzIG9mIHRoZSBmb3JtICdba2V5OjogdmFsdWVdJyBmcm9tIGEgbGluZSBvZiB0ZXh0LiBUaGlzIGlzIGRvbmUgaW4gYSByZWxhdGl2ZWx5CiAgICogInJvYnVzdCIgd2F5IHRvIGF2b2lkIGZhaWxpbmcgZHVlIHRvIGJhZCBuZXN0aW5nIG9yIG90aGVyIGludGVyZmVyaW5nIE1hcmtkb3duIHN5bWJvbHM6CiAgICoKICAgKiAtIExvb2sgZm9yIGFueSB3cmFwcGVycyAoJ1snIGFuZCAnKCcpIGluIHRoZSBsaW5lLCB0cnlpbmcgdG8gcGFyc2Ugd2hhdGV2ZXIgY29tZXMgYWZ0ZXIgaXQgYXMgYW4gaW5saW5lIGtleTo6LgogICAqIC0gSWYgc3VjY2Vzc2Z1bCwgc2NhbiB1bnRpbCB5b3UgZmluZCBhIG1hdGNoaW5nIGVuZCBicmFja2V0LCBhbmQgcGFyc2Ugd2hhdGV2ZXIgcmVtYWlucyBhcyBhbiBpbmxpbmUgdmFsdWUuCiAgICovCiAgZnVuY3Rpb24gZXh0cmFjdElubGluZUZpZWxkcyhsaW5lLCBpbmNsdWRlVGFza0ZpZWxkcyA9IGZhbHNlKSB7CiAgICAgIGxldCBmaWVsZHMgPSBbXTsKICAgICAgZm9yIChsZXQgd3JhcHBlciBvZiBPYmplY3Qua2V5cyhJTkxJTkVfRklFTERfV1JBUFBFUlMpKSB7CiAgICAgICAgICBsZXQgZm91bmRJbmRleCA9IGxpbmUuaW5kZXhPZih3cmFwcGVyKTsKICAgICAgICAgIHdoaWxlIChmb3VuZEluZGV4ID49IDApIHsKICAgICAgICAgICAgICBsZXQgcGFyc2VkRmllbGQgPSBmaW5kU3BlY2lmaWNJbmxpbmVGaWVsZChsaW5lLCBmb3VuZEluZGV4KTsKICAgICAgICAgICAgICBpZiAoIXBhcnNlZEZpZWxkKSB7CiAgICAgICAgICAgICAgICAgIGZvdW5kSW5kZXggPSBsaW5lLmluZGV4T2Yod3JhcHBlciwgZm91bmRJbmRleCArIDEpOwogICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZmllbGRzLnB1c2gocGFyc2VkRmllbGQpOwogICAgICAgICAgICAgIGZvdW5kSW5kZXggPSBsaW5lLmluZGV4T2Yod3JhcHBlciwgcGFyc2VkRmllbGQuZW5kKTsKICAgICAgICAgIH0KICAgICAgfQogICAgICBpZiAoaW5jbHVkZVRhc2tGaWVsZHMpCiAgICAgICAgICBmaWVsZHMgPSBmaWVsZHMuY29uY2F0KGV4dHJhY3RTcGVjaWFsVGFza0ZpZWxkcyhsaW5lKSk7CiAgICAgIGZpZWxkcy5zb3J0KChhLCBiKSA9PiBhLnN0YXJ0IC0gYi5zdGFydCk7CiAgICAgIGxldCBmaWx0ZXJlZEZpZWxkcyA9IFtdOwogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGZpZWxkcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgaWYgKGkgPT0gMCB8fCBmaWx0ZXJlZEZpZWxkc1tmaWx0ZXJlZEZpZWxkcy5sZW5ndGggLSAxXS5lbmQgPCBmaWVsZHNbaV0uc3RhcnQpIHsKICAgICAgICAgICAgICBmaWx0ZXJlZEZpZWxkcy5wdXNoKGZpZWxkc1tpXSk7CiAgICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIGZpbHRlcmVkRmllbGRzOwogIH0KICAvKiogVmFsaWRhdGVzIHRoYXQgYSByYXcgZmllbGQgbmFtZSBoYXMgYSB2YWxpZCBmb3JtLiAqLwogIGNvbnN0IEZVTExfTElORV9LRVlfUEFSVCA9IHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5hbHQocGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cChuZXcgUmVnRXhwKGVtb2ppUmVnZXgoKSwgInUiKSksIHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoL1swLTlccHtMZXR0ZXJ9XHdcc18vLV0rL3UpKQogICAgICAubWFueSgpCiAgICAgIC5tYXAocGFydHMgPT4gcGFydHMuam9pbigiIikpOwogIGNvbnN0IEZVTExfTElORV9LRVlfUEFSU0VSID0gcGFyc2ltbW9uX3VtZF9taW5FeHBvcnRzLnJlZ2V4cCgvW14wLTlcd1xwe0xldHRlcn1dKi91KQogICAgICAudGhlbihGVUxMX0xJTkVfS0VZX1BBUlQpCiAgICAgIC5za2lwKHBhcnNpbW1vbl91bWRfbWluRXhwb3J0cy5yZWdleHAoL1tfXCp+YF0qL3UpKTsKICAvKiogQXR0ZW1wdCB0byBleHRyYWN0IGEgZnVsbC1saW5lIGZpZWxkIChLZXk6OiBWYWx1ZSBjb25zdW1pbmcgdGhlIGVudGlyZSBjb250ZW50IGxpbmUpLiAqLwogIGZ1bmN0aW9uIGV4dHJhY3RGdWxsTGluZUZpZWxkKHRleHQpIHsKICAgICAgbGV0IHNlcCA9IGZpbmRTZXBhcmF0b3IodGV4dCwgMCk7CiAgICAgIGlmICghc2VwKQogICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgICAgLy8gV2UgbmVlZCB0byBwb3N0LXByb2Nlc3MgdGhlIGtleSB0byBkcm9wIHVubmVjZXNzYXJ5IG9wZW5pbmcgYW5ub3RhdGlvbnMgYXMgd2VsbCBhcwogICAgICAvLyBkcm9wIHN1cnJvdW5kaW5nIE1hcmtkb3duLgogICAgICBsZXQgcmVhbEtleSA9IEZVTExfTElORV9LRVlfUEFSU0VSLnBhcnNlKHNlcC5rZXkpOwogICAgICBpZiAoIXJlYWxLZXkuc3RhdHVzKQogICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgICAgcmV0dXJuIHsKICAgICAgICAgIGtleTogcmVhbEtleS52YWx1ZSwKICAgICAgICAgIHZhbHVlOiB0ZXh0LnN1YnN0cmluZyhzZXAudmFsdWVJbmRleCkudHJpbSgpLAogICAgICAgICAgc3RhcnQ6IDAsCiAgICAgICAgICBzdGFydFZhbHVlOiBzZXAudmFsdWVJbmRleCwKICAgICAgICAgIGVuZDogdGV4dC5sZW5ndGgsCiAgICAgIH07CiAgfQogIGNvbnN0IENSRUFURURfREFURV9SRUdFWCA9IC9cdXsyNzk1fVxzKihcZHs0fS1cZHsyfS1cZHsyfSkvdTsKICBjb25zdCBEVUVfREFURV9SRUdFWCA9IC8oPzpcdXsxRjRDNX18XHV7MUY0QzZ9fFx1ezFGNUQzfVx1e0ZFMEZ9PylccyooXGR7NH0tXGR7Mn0tXGR7Mn0pL3U7CiAgY29uc3QgRE9ORV9EQVRFX1JFR0VYID0gL1x1ezI3MDV9XHMqKFxkezR9LVxkezJ9LVxkezJ9KS91OwogIGNvbnN0IFNDSEVEVUxFRF9EQVRFX1JFR0VYID0gL1tcdXsyM0YzfVx1ezIzMUJ9XVxzKihcZHs0fS1cZHsyfS1cZHsyfSkvdTsKICBjb25zdCBTVEFSVF9EQVRFX1JFR0VYID0gL1x1ezFGNkVCfVxzKihcZHs0fS1cZHsyfS1cZHsyfSkvdTsKICBjb25zdCBFTU9KSV9SRUdFWEVTID0gWwogICAgICB7IHJlZ2V4OiBDUkVBVEVEX0RBVEVfUkVHRVgsIGtleTogImNyZWF0ZWQiIH0sCiAgICAgIHsgcmVnZXg6IFNUQVJUX0RBVEVfUkVHRVgsIGtleTogInN0YXJ0IiB9LAogICAgICB7IHJlZ2V4OiBTQ0hFRFVMRURfREFURV9SRUdFWCwga2V5OiAic2NoZWR1bGVkIiB9LAogICAgICB7IHJlZ2V4OiBEVUVfREFURV9SRUdFWCwga2V5OiAiZHVlIiB9LAogICAgICB7IHJlZ2V4OiBET05FX0RBVEVfUkVHRVgsIGtleTogImNvbXBsZXRpb24iIH0sCiAgXTsKICAvKiogUGFyc2Ugc3BlY2lhbCBjb21wbGV0ZWQvZHVlL2RvbmUgdGFzayBmaWVsZHMgd2hpY2ggYXJlIG1hcmtlZCB2aWEgZW1vamkuICovCiAgZnVuY3Rpb24gZXh0cmFjdFNwZWNpYWxUYXNrRmllbGRzKGxpbmUpIHsKICAgICAgbGV0IHJlc3VsdHMgPSBbXTsKICAgICAgZm9yIChsZXQgeyByZWdleCwga2V5IH0gb2YgRU1PSklfUkVHRVhFUykgewogICAgICAgICAgY29uc3QgbWF0Y2ggPSByZWdleC5leGVjKGxpbmUpOwogICAgICAgICAgaWYgKCFtYXRjaCkKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIHJlc3VsdHMucHVzaCh7CiAgICAgICAgICAgICAga2V5LAogICAgICAgICAgICAgIHZhbHVlOiBtYXRjaFsxXSwKICAgICAgICAgICAgICBzdGFydDogbWF0Y2guaW5kZXgsCiAgICAgICAgICAgICAgc3RhcnRWYWx1ZTogbWF0Y2guaW5kZXggKyAxLAogICAgICAgICAgICAgIGVuZDogbWF0Y2guaW5kZXggKyBtYXRjaFswXS5sZW5ndGgsCiAgICAgICAgICAgICAgd3JhcHBpbmc6ICJlbW9qaS1zaG9ydGhhbmQiLAogICAgICAgICAgfSk7CiAgICAgIH0KICAgICAgcmV0dXJuIHJlc3VsdHM7CiAgfQoKICAvKiogQWxsIGV4dHJhY3RlZCBtYXJrZG93biBmaWxlIG1ldGFkYXRhIG9idGFpbmVkIGZyb20gYSBmaWxlLiAqLwogIGNsYXNzIFBhZ2VNZXRhZGF0YSB7CiAgICAgIC8qKiBUaGUgcGF0aCB0aGlzIGZpbGUgZXhpc3RzIGF0LiAqLwogICAgICBwYXRoOwogICAgICAvKiogT2JzaWRpYW4tcHJvdmlkZWQgZGF0ZSB0aGlzIHBhZ2Ugd2FzIGNyZWF0ZWQuICovCiAgICAgIGN0aW1lOwogICAgICAvKiogT2JzaWRpYW4tcHJvdmlkZWQgZGF0ZSB0aGlzIHBhZ2Ugd2FzIG1vZGlmaWVkLiAqLwogICAgICBtdGltZTsKICAgICAgLyoqIE9ic2lkaWFuLXByb3ZpZGVkIHNpemUgb2YgdGhpcyBwYWdlIGluIGJ5dGVzLiAqLwogICAgICBzaXplOwogICAgICAvKiogVGhlIGRheSBhc3NvY2lhdGVkIHdpdGggdGhpcyBwYWdlLCBpZiByZWxldmFudC4gKi8KICAgICAgZGF5OwogICAgICAvKiogVGhlIGZpcnN0IEgxL0gyIGhlYWRlciBpbiB0aGUgZmlsZS4gTWF5IG5vdCBleGlzdC4gKi8KICAgICAgdGl0bGU7CiAgICAgIC8qKiBBbGwgb2YgdGhlIGZpZWxkcyBjb250YWluZWQgaW4gdGhpcyBtYXJrZG93biBmaWxlIC0gYm90aCBmcm9udG1hdHRlciBBTkQgaW4tZmlsZSBsaW5rcy4gKi8KICAgICAgZmllbGRzOwogICAgICAvKiogQWxsIG9mIHRoZSBleGFjdCB0YWdzIChwcmVmaXhlZCB3aXRoICcjJykgaW4gdGhpcyBmaWxlIG92ZXJhbGwuICovCiAgICAgIHRhZ3M7CiAgICAgIC8qKiBBbGwgb2YgdGhlIGFsaWFzZXMgZGVmaW5lZCBmb3IgdGhpcyBmaWxlLiAqLwogICAgICBhbGlhc2VzOwogICAgICAvKiogQWxsIE9VVEdPSU5HIGxpbmtzIChpbmNsdWRpbmcgZW1iZWRzLCBoZWFkZXIgKyBibG9jayBsaW5rcykgaW4gdGhpcyBmaWxlLiAqLwogICAgICBsaW5rczsKICAgICAgLyoqIEFsbCBsaXN0IGl0ZW1zIGNvbnRhaW5lZCB3aXRoaW4gdGhpcyBwYWdlLiBGaWx0ZXIgZm9yIHRhc2tzIHRvIGdldCBqdXN0IHRhc2tzLiAqLwogICAgICBsaXN0czsKICAgICAgLyoqIFRoZSByYXcgZnJvbnRtYXR0ZXIgZm9yIHRoaXMgZG9jdW1lbnQuICovCiAgICAgIGZyb250bWF0dGVyOwogICAgICBjb25zdHJ1Y3RvcihwYXRoLCBpbml0KSB7CiAgICAgICAgICB0aGlzLnBhdGggPSBwYXRoOwogICAgICAgICAgdGhpcy5maWVsZHMgPSBuZXcgTWFwKCk7CiAgICAgICAgICB0aGlzLmZyb250bWF0dGVyID0ge307CiAgICAgICAgICB0aGlzLnRhZ3MgPSBuZXcgU2V0KCk7CiAgICAgICAgICB0aGlzLmFsaWFzZXMgPSBuZXcgU2V0KCk7CiAgICAgICAgICB0aGlzLmxpbmtzID0gW107CiAgICAgICAgICBPYmplY3QuYXNzaWduKHRoaXMsIGluaXQpOwogICAgICAgICAgdGhpcy5saXN0cyA9ICh0aGlzLmxpc3RzIHx8IFtdKS5tYXAobCA9PiBuZXcgTGlzdEl0ZW0obCkpOwogICAgICB9CiAgICAgIC8qKiBDYW5vbmljYWxpemUgcmF3IGxpbmtzIGFuZCBvdGhlciBkYXRhIGluIHBhcnRpYWwgZGF0YSB3aXRoIG5vcm1hbGl6ZXJzLCByZXR1cm5pbmcgYSBjb21wbGV0ZWQgb2JqZWN0LiAqLwogICAgICBzdGF0aWMgY2Fub25pY2FsaXplKGRhdGEsIGxpbmtOb3JtYWxpemVyKSB7CiAgICAgICAgICAvLyBNdXRhdGUgdGhlIGRhdGEgZm9yIG5vdywgd2hpY2ggaXMgcHJvYmFibHkgYSBiYWQgaWRlYSBidXQuLi4gYWxsIHdlbGwuCiAgICAgICAgICBpZiAoZGF0YS5mcm9udG1hdHRlcikgewogICAgICAgICAgICAgIGRhdGEuZnJvbnRtYXR0ZXIgPSBWYWx1ZXMubWFwTGVhdmVzKGRhdGEuZnJvbnRtYXR0ZXIsIHQgPT4gVmFsdWVzLmlzTGluayh0KSA/IGxpbmtOb3JtYWxpemVyKHQpIDogdCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoZGF0YS5maWVsZHMpIHsKICAgICAgICAgICAgICBmb3IgKGxldCBba2V5LCB2YWx1ZV0gb2YgZGF0YS5maWVsZHMuZW50cmllcygpKSB7CiAgICAgICAgICAgICAgICAgIGRhdGEuZmllbGRzLnNldChrZXksIFZhbHVlcy5tYXBMZWF2ZXModmFsdWUsIHQgPT4gKFZhbHVlcy5pc0xpbmsodCkgPyBsaW5rTm9ybWFsaXplcih0KSA6IHQpKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKGRhdGEubGlzdHMpIHsKICAgICAgICAgICAgICBmb3IgKGxldCBpdGVtIG9mIGRhdGEubGlzdHMpIHsKICAgICAgICAgICAgICAgICAgZm9yIChsZXQgW2tleSwgdmFsdWVdIG9mIGl0ZW0uZmllbGRzLmVudHJpZXMoKSkgewogICAgICAgICAgICAgICAgICAgICAgaXRlbS5maWVsZHMuc2V0KGtleSwgdmFsdWUubWFwKHggPT4gVmFsdWVzLm1hcExlYXZlcyh4LCB0ID0+IChWYWx1ZXMuaXNMaW5rKHQpID8gbGlua05vcm1hbGl6ZXIodCkgOiB0KSkpKTsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChkYXRhLmxpbmtzKSB7CiAgICAgICAgICAgICAgZGF0YS5saW5rcyA9IGRhdGEubGlua3MubWFwKGwgPT4gbGlua05vcm1hbGl6ZXIobCkpOwogICAgICAgICAgfQogICAgICAgICAgLy8gVGhpcyBpcyBwcmV0dHkgdWdseSwgYnV0IGl0J3Mgbm90IHBvc3NpYmxlIHRvIG5vcm1hbGl6ZSBvbiB0aGUgd29ya2VyIHRocmVhZCB0aGF0IGRvZXMgcGFyc2luZy4KICAgICAgICAgIC8vIFRoZSBiZXN0IHdheSB0byBpbXByb3ZlIHRoaXMgaXMgdG8gaW5zdGVhZCBqdXN0IGNhbm9uaWNhbGl6ZSB0aGUgZW50aXJlIGRhdGEgb2JqZWN0OyBJIGNhbiB0cnkgdG8KICAgICAgICAgIC8vIG9wdGltaXplIGBWYWx1ZXMubWFwTGVhdmVzYCB0byBvbmx5IG11dGF0ZSBpZiBpdCBhY3R1YWxseSBjaGFuZ2VzIHRoaW5ncy4KICAgICAgICAgIHJldHVybiBuZXcgUGFnZU1ldGFkYXRhKGRhdGEucGF0aCwgZGF0YSk7CiAgICAgIH0KICAgICAgLyoqIFRoZSBuYW1lIChiYXNlZCBvbiBwYXRoKSBvZiB0aGlzIGZpbGUuICovCiAgICAgIG5hbWUoKSB7CiAgICAgICAgICByZXR1cm4gZ2V0RmlsZVRpdGxlKHRoaXMucGF0aCk7CiAgICAgIH0KICAgICAgLyoqIFRoZSBjb250YWluaW5nIGZvbGRlciAoYmFzZWQgb24gcGF0aCkgb2YgdGhpcyBmaWxlLiAqLwogICAgICBmb2xkZXIoKSB7CiAgICAgICAgICByZXR1cm4gZ2V0UGFyZW50Rm9sZGVyKHRoaXMucGF0aCk7CiAgICAgIH0KICAgICAgLyoqIFRoZSBleHRlbnNpb24gb2YgdGhpcyBmaWxlIChsaWtlbHkgJ21kJykuICovCiAgICAgIGV4dGVuc2lvbigpIHsKICAgICAgICAgIHJldHVybiBnZXRFeHRlbnNpb24odGhpcy5wYXRoKTsKICAgICAgfQogICAgICAvKiogUmV0dXJuIGEgc2V0IG9mIHRhZ3MgQU5EIGFsbCBvZiB0aGVpciBwYXJlbnQgdGFncyAoc28gI2hlbGxvL3llcyB3b3VsZCBiZWNvbWUgI2hlbGxvLCAjaGVsbG8veWVzKS4gKi8KICAgICAgZnVsbFRhZ3MoKSB7CiAgICAgICAgICBsZXQgcmVzdWx0ID0gbmV3IFNldCgpOwogICAgICAgICAgZm9yIChsZXQgdGFnIG9mIHRoaXMudGFncykgewogICAgICAgICAgICAgIGZvciAobGV0IHN1YnRhZyBvZiBleHRyYWN0U3VidGFncyh0YWcpKQogICAgICAgICAgICAgICAgICByZXN1bHQuYWRkKHN1YnRhZyk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9CiAgICAgIC8qKiBDb252ZXJ0IGFsbCBsaW5rcyBpbiB0aGlzIGZpbGUgdG8gZmlsZSBsaW5rcy4gKi8KICAgICAgZmlsZUxpbmtzKCkgewogICAgICAgICAgLy8gV2Ugd2FudCB0byBtYWtlIHRoZW0gZGlzdGluY3QsIGJ1dCB3aGVyZSBsaW5rcyBhcmUgbm90IHJhdyBsaW5rcyB3ZQogICAgICAgICAgLy8gbm93IGtlZXAgdGhlIGFkZGl0aW9uYWwgbWV0YWRhdGEuCiAgICAgICAgICBsZXQgZGlzdGluY3RMaW5rcyA9IG5ldyBTZXQodGhpcy5saW5rcyk7CiAgICAgICAgICByZXR1cm4gQXJyYXkuZnJvbShkaXN0aW5jdExpbmtzKTsKICAgICAgfQogICAgICAvKiogTWFwIHRoaXMgbWV0YWRhdGEgdG8gYSBmdWxsIG9iamVjdDsgdXNlcyB0aGUgaW5kZXggZm9yIGFkZGl0aW9uYWwgZGF0YSBsb29rdXBzLiAgKi8KICAgICAgc2VyaWFsaXplKGluZGV4LCBjYWNoZSkgewogICAgICAgICAgLy8gQ29udmVydCBsaXN0IGl0ZW1zIHZpYSB0aGUgY2Fub25pY2FsaXphdGlvbiBjYWNoZS4KICAgICAgICAgIGxldCByZWFsQ2FjaGUgPSBjYWNoZSA/PyBuZXcgTGlzdFNlcmlhbGl6YXRpb25DYWNoZSh0aGlzLmxpc3RzKTsKICAgICAgICAgIGxldCByZXN1bHQgPSB7CiAgICAgICAgICAgICAgZmlsZTogewogICAgICAgICAgICAgICAgICBwYXRoOiB0aGlzLnBhdGgsCiAgICAgICAgICAgICAgICAgIGZvbGRlcjogdGhpcy5mb2xkZXIoKSwKICAgICAgICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lKCksCiAgICAgICAgICAgICAgICAgIGxpbms6IExpbmsuZmlsZSh0aGlzLnBhdGgpLAogICAgICAgICAgICAgICAgICBvdXRsaW5rczogdGhpcy5maWxlTGlua3MoKSwKICAgICAgICAgICAgICAgICAgaW5saW5rczogQXJyYXkuZnJvbShpbmRleC5saW5rcy5nZXRJbnZlcnNlKHRoaXMucGF0aCkpLm1hcChsID0+IExpbmsuZmlsZShsKSksCiAgICAgICAgICAgICAgICAgIGV0YWdzOiBBcnJheS5mcm9tKHRoaXMudGFncyksCiAgICAgICAgICAgICAgICAgIHRhZ3M6IEFycmF5LmZyb20odGhpcy5mdWxsVGFncygpKSwKICAgICAgICAgICAgICAgICAgYWxpYXNlczogQXJyYXkuZnJvbSh0aGlzLmFsaWFzZXMpLAogICAgICAgICAgICAgICAgICBsaXN0czogdGhpcy5saXN0cy5tYXAobCA9PiByZWFsQ2FjaGUuZ2V0KGwubGluZSkpLAogICAgICAgICAgICAgICAgICB0YXNrczogdGhpcy5saXN0cy5maWx0ZXIobCA9PiAhIWwudGFzaykubWFwKGwgPT4gcmVhbENhY2hlLmdldChsLmxpbmUpKSwKICAgICAgICAgICAgICAgICAgY3RpbWU6IHRoaXMuY3RpbWUsCiAgICAgICAgICAgICAgICAgIGNkYXk6IHN0cmlwVGltZSh0aGlzLmN0aW1lKSwKICAgICAgICAgICAgICAgICAgbXRpbWU6IHRoaXMubXRpbWUsCiAgICAgICAgICAgICAgICAgIG1kYXk6IHN0cmlwVGltZSh0aGlzLm10aW1lKSwKICAgICAgICAgICAgICAgICAgc2l6ZTogdGhpcy5zaXplLAogICAgICAgICAgICAgICAgICBzdGFycmVkOiBpbmRleC5zdGFycmVkLnN0YXJyZWQodGhpcy5wYXRoKSwKICAgICAgICAgICAgICAgICAgZnJvbnRtYXR0ZXI6IFZhbHVlcy5kZWVwQ29weSh0aGlzLmZyb250bWF0dGVyKSwKICAgICAgICAgICAgICAgICAgZXh0OiB0aGlzLmV4dGVuc2lvbigpLAogICAgICAgICAgICAgIH0sCiAgICAgICAgICB9OwogICAgICAgICAgLy8gQWRkIHRoZSBjdXJyZW50IGRheSBpZiBwcmVzZW50LgogICAgICAgICAgaWYgKHRoaXMuZGF5KQogICAgICAgICAgICAgIHJlc3VsdC5maWxlLmRheSA9IHRoaXMuZGF5OwogICAgICAgICAgLy8gVGhlbiBhcHBlbmQgdGhlIGNvbXB1dGVkIGZpZWxkcy4KICAgICAgICAgIGZvciAobGV0IFtrZXksIHZhbHVlXSBvZiB0aGlzLmZpZWxkcy5lbnRyaWVzKCkpIHsKICAgICAgICAgICAgICBpZiAoa2V5IGluIHJlc3VsdCkKICAgICAgICAgICAgICAgICAgY29udGludWU7IC8vIERvbid0IGFsbG93IGZpZWxkcyB0byBvdmVycmlkZSBleGlzdGluZyBrZXlzLgogICAgICAgICAgICAgIHJlc3VsdFtrZXldID0gdmFsdWU7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9CiAgfQogIC8qKiBBIGxpc3QgaXRlbSBpbnNpZGUgb2YgYSBsaXN0LiAqLwogIGNsYXNzIExpc3RJdGVtIHsKICAgICAgLyoqIFRoZSBzeW1ib2wgKCcqJywgJy0nLCAnMS4nKSB1c2VkIHRvIGRlZmluZSB0aGlzIGxpc3QgaXRlbS4gKi8KICAgICAgc3ltYm9sOwogICAgICAvKiogQSBsaW5rIHdoaWNoIHBvaW50cyB0byB0aGlzIHRhc2ssIG9yIHRvIHRoZSBjbG9zZXN0IGJsb2NrIHRoYXQgdGhpcyB0YXNrIGlzIGNvbnRhaW5lZCBpbi4gKi8KICAgICAgbGluazsKICAgICAgLyoqIEEgbGluayB0byB0aGUgc2VjdGlvbiB0aGF0IGNvbnRhaW5zIHRoaXMgbGlzdCBlbGVtZW50OyBjb3VsZCBiZSBhIGZpbGUgaWYgdGhpcyBpcyBub3QgaW4gYSBzZWN0aW9uLiAqLwogICAgICBzZWN0aW9uOwogICAgICAvKiogVGhlIHRleHQgb2YgdGhpcyBsaXN0IGl0ZW0uIFRoaXMgbWF5IGJlIG11bHRpcGxlIGxpbmVzIG9mIG1hcmtkb3duLiAqLwogICAgICB0ZXh0OwogICAgICAvKiogVGhlIGxpbmUgdGhhdCB0aGlzIGxpc3QgaXRlbSBzdGFydHMgb24gaW4gdGhlIGZpbGUuICovCiAgICAgIGxpbmU7CiAgICAgIC8qKiBUaGUgbnVtYmVyIG9mIGxpbmVzIHRoYXQgZGVmaW5lIHRoaXMgbGlzdCBpdGVtLiAqLwogICAgICBsaW5lQ291bnQ7CiAgICAgIC8qKiBUaGUgbGluZSBudW1iZXIgZm9yIHRoZSBmaXJzdCBsaXN0IGl0ZW0gaW4gdGhlIGxpc3QgdGhpcyBpdGVtIGJlbG9uZ3MgdG8uICovCiAgICAgIGxpc3Q7CiAgICAgIC8qKiBBbnkgbGlua3MgY29udGFpbmVkIHdpdGhpbiB0aGlzIGxpc3QgaXRlbS4gKi8KICAgICAgbGlua3M7CiAgICAgIC8qKiBUaGUgdGFncyBjb250YWluZWQgd2l0aGluIHRoaXMgbGlzdCBpdGVtLiAqLwogICAgICB0YWdzOwogICAgICAvKiogVGhlIHJhdyBPYnNpZGlhbi1wcm92aWRlZCBwb3NpdGlvbiBmb3Igd2hlcmUgdGhpcyB0YXNrIGlzLiAqLwogICAgICBwb3NpdGlvbjsKICAgICAgLyoqIFRoZSBsaW5lIG51bWJlciBvZiB0aGUgcGFyZW50IGxpc3QgaXRlbSwgaWYgcHJlc2VudDsgaWYgdGhpcyBpcyB1bmRlZmluZWQsIHRoaXMgaXMgYSByb290IGl0ZW0uICovCiAgICAgIHBhcmVudDsKICAgICAgLyoqIFRoZSBsaW5lIG51bWJlcnMgb2YgY2hpbGRyZW4gb2YgdGhpcyBsaXN0IGl0ZW0uICovCiAgICAgIGNoaWxkcmVuOwogICAgICAvKiogVGhlIGJsb2NrIElEIGZvciB0aGlzIGl0ZW0sIGlmIG9uZSBpcyBwcmVzZW50LiAqLwogICAgICBibG9ja0lkOwogICAgICAvKiogQW55IGZpZWxkcyBkZWZpbmVkIGluIHRoaXMgbGlzdCBpdGVtLiBGb3IgdGFza3MsIHRoaXMgaW5jbHVkZXMgZmllbGRzIHVuZGVybmVhdGggdGhlIHRhc2suICovCiAgICAgIGZpZWxkczsKICAgICAgdGFzazsKICAgICAgY29uc3RydWN0b3IoaW5pdCkgewogICAgICAgICAgT2JqZWN0LmFzc2lnbih0aGlzLCBpbml0KTsKICAgICAgICAgIHRoaXMuZmllbGRzID0gdGhpcy5maWVsZHMgfHwgbmV3IE1hcCgpOwogICAgICAgICAgdGhpcy50YWdzID0gdGhpcy50YWdzIHx8IG5ldyBTZXQoKTsKICAgICAgICAgIHRoaXMuY2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuIHx8IFtdOwogICAgICAgICAgdGhpcy5saW5rcyA9IHRoaXMubGlua3MgfHwgW107CiAgICAgIH0KICAgICAgaWQoKSB7CiAgICAgICAgICByZXR1cm4gYCR7dGhpcy5maWxlKCkucGF0aH0tJHt0aGlzLmxpbmV9YDsKICAgICAgfQogICAgICBmaWxlKCkgewogICAgICAgICAgcmV0dXJuIHRoaXMubGluay50b0ZpbGUoKTsKICAgICAgfQogICAgICBtYXJrZG93bigpIHsKICAgICAgICAgIGlmICh0aGlzLnRhc2spCiAgICAgICAgICAgICAgcmV0dXJuIGAke3RoaXMuc3ltYm9sfSBbJHt0aGlzLnRhc2suY29tcGxldGVkID8gIngiIDogIiAifV0gJHt0aGlzLnRleHR9YDsKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICByZXR1cm4gYCR7dGhpcy5zeW1ib2x9ICR7dGhpcy50ZXh0fWA7CiAgICAgIH0KICAgICAgY3JlYXRlZCgpIHsKICAgICAgICAgIHJldHVybiAodGhpcy5maWVsZHMuZ2V0KCJjcmVhdGVkIikgPz8gdGhpcy5maWVsZHMuZ2V0KCJjdGltZSIpID8/IHRoaXMuZmllbGRzLmdldCgiY2RheSIpKT8uWzBdOwogICAgICB9CiAgICAgIGR1ZSgpIHsKICAgICAgICAgIHJldHVybiAodGhpcy5maWVsZHMuZ2V0KCJkdWUiKSA/PyB0aGlzLmZpZWxkcy5nZXQoImR1ZXRpbWUiKSA/PyB0aGlzLmZpZWxkcy5nZXQoImR1ZWRheSIpKT8uWzBdOwogICAgICB9CiAgICAgIGNvbXBsZXRlZCgpIHsKICAgICAgICAgIHJldHVybiAodGhpcy5maWVsZHMuZ2V0KCJjb21wbGV0ZWQiKSA/PwogICAgICAgICAgICAgIHRoaXMuZmllbGRzLmdldCgiY29tcGxldGlvbiIpID8/CiAgICAgICAgICAgICAgdGhpcy5maWVsZHMuZ2V0KCJjb21wdGltZSIpID8/CiAgICAgICAgICAgICAgdGhpcy5maWVsZHMuZ2V0KCJjb21wZGF5IikpPy5bMF07CiAgICAgIH0KICAgICAgc3RhcnQoKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5maWVsZHMuZ2V0KCJzdGFydCIpPy5bMF07CiAgICAgIH0KICAgICAgc2NoZWR1bGVkKCkgewogICAgICAgICAgcmV0dXJuIHRoaXMuZmllbGRzLmdldCgic2NoZWR1bGVkIik/LlswXTsKICAgICAgfQogICAgICAvKiogQ3JlYXRlIGFuIEFQSS1mcmllbmRseSBjb3B5IG9mIHRoaXMgbGlzdCBpdGVtLiBEZS1kdXBsaWNhdGlvbiBpcyBkb25lIHZpYSB0aGUgcHJvdmlkZWQgY2FjaGUuICovCiAgICAgIHNlcmlhbGl6ZShjYWNoZSkgewogICAgICAgICAgLy8gTWFwIGNoaWxkcmVuIHRvIHRoZWlyIHNlcmlhbGl6ZWQvZGUtZHVwbGljYXRlZCBlcXVpdmFsZW50cyByaWdodCBhd2F5LgogICAgICAgICAgbGV0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbi5tYXAobCA9PiBjYWNoZS5nZXQobCkpLmZpbHRlcigobCkgPT4gbCAhPT0gdW5kZWZpbmVkKTsKICAgICAgICAgIGxldCByZXN1bHQgPSB7CiAgICAgICAgICAgICAgc3ltYm9sOiB0aGlzLnN5bWJvbCwKICAgICAgICAgICAgICBsaW5rOiB0aGlzLmxpbmssCiAgICAgICAgICAgICAgc2VjdGlvbjogdGhpcy5zZWN0aW9uLAogICAgICAgICAgICAgIHRleHQ6IHRoaXMudGV4dCwKICAgICAgICAgICAgICB0YWdzOiBBcnJheS5mcm9tKHRoaXMudGFncyksCiAgICAgICAgICAgICAgbGluZTogdGhpcy5saW5lLAogICAgICAgICAgICAgIGxpbmVDb3VudDogdGhpcy5saW5lQ291bnQsCiAgICAgICAgICAgICAgbGlzdDogdGhpcy5saXN0LAogICAgICAgICAgICAgIG91dGxpbmtzOiBBcnJheS5mcm9tKHRoaXMubGlua3MpLAogICAgICAgICAgICAgIHBhdGg6IHRoaXMubGluay5wYXRoLAogICAgICAgICAgICAgIGNoaWxkcmVuOiBjaGlsZHJlbiwKICAgICAgICAgICAgICB0YXNrOiAhIXRoaXMudGFzaywKICAgICAgICAgICAgICBhbm5vdGF0ZWQ6IHRoaXMuZmllbGRzLnNpemUgPiAwLAogICAgICAgICAgICAgIHBvc2l0aW9uOiBWYWx1ZXMuZGVlcENvcHkodGhpcy5wb3NpdGlvbiksCiAgICAgICAgICAgICAgc3VidGFza3M6IGNoaWxkcmVuLAogICAgICAgICAgICAgIHJlYWw6ICEhdGhpcy50YXNrLAogICAgICAgICAgICAgIGhlYWRlcjogdGhpcy5zZWN0aW9uLCAvLyBAZGVwcmVjYXRlZCwgdXNlICdpdGVtLnNlY3Rpb24nIGluc3RlYWQuCiAgICAgICAgICB9OwogICAgICAgICAgaWYgKHRoaXMucGFyZW50IHx8IHRoaXMucGFyZW50ID09PSAwKQogICAgICAgICAgICAgIHJlc3VsdC5wYXJlbnQgPSB0aGlzLnBhcmVudDsKICAgICAgICAgIGlmICh0aGlzLmJsb2NrSWQpCiAgICAgICAgICAgICAgcmVzdWx0LmJsb2NrSWQgPSB0aGlzLmJsb2NrSWQ7CiAgICAgICAgICBhZGRGaWVsZHModGhpcy5maWVsZHMsIHJlc3VsdCk7CiAgICAgICAgICBpZiAodGhpcy50YXNrKSB7CiAgICAgICAgICAgICAgcmVzdWx0LnN0YXR1cyA9IHRoaXMudGFzay5zdGF0dXM7CiAgICAgICAgICAgICAgcmVzdWx0LmNoZWNrZWQgPSB0aGlzLnRhc2suY2hlY2tlZDsKICAgICAgICAgICAgICByZXN1bHQuY29tcGxldGVkID0gdGhpcy50YXNrLmNvbXBsZXRlZDsKICAgICAgICAgICAgICByZXN1bHQuZnVsbHlDb21wbGV0ZWQgPSB0aGlzLnRhc2suZnVsbHlDb21wbGV0ZWQ7CiAgICAgICAgICAgICAgbGV0IGNyZWF0ZWQgPSB0aGlzLmNyZWF0ZWQoKSwgZHVlID0gdGhpcy5kdWUoKSwgY29tcGxldGVkID0gdGhpcy5jb21wbGV0ZWQoKSwgc3RhcnQgPSB0aGlzLnN0YXJ0KCksIHNjaGVkdWxlZCA9IHRoaXMuc2NoZWR1bGVkKCk7CiAgICAgICAgICAgICAgaWYgKGNyZWF0ZWQpCiAgICAgICAgICAgICAgICAgIHJlc3VsdC5jcmVhdGVkID0gVmFsdWVzLmRlZXBDb3B5KGNyZWF0ZWQpOwogICAgICAgICAgICAgIGlmIChkdWUpCiAgICAgICAgICAgICAgICAgIHJlc3VsdC5kdWUgPSBWYWx1ZXMuZGVlcENvcHkoZHVlKTsKICAgICAgICAgICAgICBpZiAoY29tcGxldGVkKQogICAgICAgICAgICAgICAgICByZXN1bHQuY29tcGxldGlvbiA9IFZhbHVlcy5kZWVwQ29weShjb21wbGV0ZWQpOwogICAgICAgICAgICAgIGlmIChzdGFydCkKICAgICAgICAgICAgICAgICAgcmVzdWx0LnN0YXJ0ID0gVmFsdWVzLmRlZXBDb3B5KHN0YXJ0KTsKICAgICAgICAgICAgICBpZiAoc2NoZWR1bGVkKQogICAgICAgICAgICAgICAgICByZXN1bHQuc2NoZWR1bGVkID0gVmFsdWVzLmRlZXBDb3B5KHNjaGVkdWxlZCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9CiAgfQogIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogIC8vIENvbnZlcnNpb24gLyBTZXJpYWxpemF0aW9uIFV0aWxpdGllcyAvLwogIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogIC8qKiBEZS1kdXBsaWNhdGVzIGxpc3QgaXRlbXMgYWNyb3NzIHNlY3Rpb24gbWV0YWRhdGEgYW5kIHBhZ2UgbWV0YWRhdGEuICovCiAgY2xhc3MgTGlzdFNlcmlhbGl6YXRpb25DYWNoZSB7CiAgICAgIGxpc3RJdGVtczsKICAgICAgY2FjaGU7CiAgICAgIHNlZW47CiAgICAgIGNvbnN0cnVjdG9yKGxpc3RJdGVtcykgewogICAgICAgICAgdGhpcy5saXN0SXRlbXMgPSB7fTsKICAgICAgICAgIHRoaXMuY2FjaGUgPSB7fTsKICAgICAgICAgIHRoaXMuc2VlbiA9IG5ldyBTZXQoKTsKICAgICAgICAgIGZvciAobGV0IGl0ZW0gb2YgbGlzdEl0ZW1zKQogICAgICAgICAgICAgIHRoaXMubGlzdEl0ZW1zW2l0ZW0ubGluZV0gPSBpdGVtOwogICAgICB9CiAgICAgIGdldChsaW5lbm8pIHsKICAgICAgICAgIGlmIChsaW5lbm8gaW4gdGhpcy5jYWNoZSkKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5jYWNoZVtsaW5lbm9dOwogICAgICAgICAgZWxzZSBpZiAodGhpcy5zZWVuLmhhcyhsaW5lbm8pKSB7CiAgICAgICAgICAgICAgY29uc29sZS5sb2coYERhdGF2aWV3OiBFbmNvdW50ZXJlZCBhIGNpcmN1bGFyIGxpc3QgKGxpbmUgbnVtYmVyICR7bGluZW5vfTsgY2hpbGRyZW4gJHt0aGlzLmxpc3RJdGVtc1tsaW5lbm9dLmNoaWxkcmVuLmpvaW4oIiwgIil9KWApOwogICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7CiAgICAgICAgICB9CiAgICAgICAgICB0aGlzLnNlZW4uYWRkKGxpbmVubyk7CiAgICAgICAgICBsZXQgcmVzdWx0ID0gdGhpcy5saXN0SXRlbXNbbGluZW5vXS5zZXJpYWxpemUodGhpcyk7CiAgICAgICAgICB0aGlzLmNhY2hlW2xpbmVub10gPSByZXN1bHQ7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9CiAgfQogIGZ1bmN0aW9uIGFkZEZpZWxkcyhmaWVsZHMsIHRhcmdldCkgewogICAgICBmb3IgKGxldCBba2V5LCB2YWx1ZXNdIG9mIGZpZWxkcy5lbnRyaWVzKCkpIHsKICAgICAgICAgIGlmIChrZXkgaW4gdGFyZ2V0KQogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgdGFyZ2V0W2tleV0gPSB2YWx1ZXMubGVuZ3RoID09IDEgPyB2YWx1ZXNbMF0gOiB2YWx1ZXM7CiAgICAgIH0KICAgICAgcmV0dXJuIHRhcmdldDsKICB9CgogIC8qKiBDb21tb24gdXRpbGl0aWVzIGZvciBleHRyYWN0aW5nIHRhZ3MsIGxpbmtzLCBhbmQgb3RoZXIgYnVzaW5lc3MgZnJvbSBtZXRhZGF0YS4gKi8KICBjb25zdCBQT1RFTlRJQUxfVEFHX01BVENIRVIgPSAvI1teXHMsO1wuOiFcPyciYCgpXFtcXVx7XH1dKy9naXU7CiAgLyoqIEV4dHJhY3QgYWxsIHRhZ3MgZnJvbSB0aGUgZ2l2ZW4gc291cmNlIHN0cmluZy4gKi8KICBmdW5jdGlvbiBleHRyYWN0VGFncyQxKHNvdXJjZSkgewogICAgICBsZXQgcmVzdWx0ID0gbmV3IFNldCgpOwogICAgICBsZXQgbWF0Y2hlcyA9IHNvdXJjZS5tYXRjaEFsbChQT1RFTlRJQUxfVEFHX01BVENIRVIpOwogICAgICBmb3IgKGxldCBtYXRjaCBvZiBtYXRjaGVzKSB7CiAgICAgICAgICBsZXQgcGFyc2VkID0gRVhQUkVTU0lPTi50YWcucGFyc2UobWF0Y2hbMF0pOwogICAgICAgICAgaWYgKHBhcnNlZC5zdGF0dXMpCiAgICAgICAgICAgICAgcmVzdWx0LmFkZChwYXJzZWQudmFsdWUpOwogICAgICB9CiAgICAgIHJldHVybiByZXN1bHQ7CiAgfQoKICAvKiogSW1wb3J0ZXIgZm9yIG1hcmtkb3duIGRvY3VtZW50cy4gKi8KICAvKiogRXh0cmFjdCBtYXJrZG93biBtZXRhZGF0YSBmcm9tIHRoZSBnaXZlbiBPYnNpZGlhbiBtYXJrZG93biBmaWxlLiAqLwogIGZ1bmN0aW9uIHBhcnNlUGFnZShwYXRoLCBjb250ZW50cywgc3RhdCwgbWV0YWRhdGEpIHsKICAgICAgbGV0IHRhZ3MgPSBuZXcgU2V0KCk7CiAgICAgIGxldCBhbGlhc2VzID0gbmV3IFNldCgpOwogICAgICBsZXQgZmllbGRzID0gbmV3IE1hcCgpOwogICAgICBsZXQgbGlua3MgPSBbXTsKICAgICAgLy8gRmlsZSB0YWdzLCBpbmNsdWRpbmcgZnJvbnQtbWF0dGVyIGFuZCBpbi1maWxlIHRhZ3MuCiAgICAgIChtZXRhZGF0YS50YWdzIHx8IFtdKS5mb3JFYWNoKHQgPT4gdGFncy5hZGQodC50YWcuc3RhcnRzV2l0aCgiIyIpID8gdC50YWcgOiAiIyIgKyB0LnRhZykpOwogICAgICAvLyBGcm9udC1tYXR0ZXIgZmlsZSB0YWdzLCBhbGlhc2VzLCBBTkQgZnJvbnRtYXR0ZXIgcHJvcGVydGllcy4KICAgICAgaWYgKG1ldGFkYXRhLmZyb250bWF0dGVyKSB7CiAgICAgICAgICBmb3IgKGxldCB0YWcgb2YgZXh0cmFjdFRhZ3MobWV0YWRhdGEuZnJvbnRtYXR0ZXIpKSB7CiAgICAgICAgICAgICAgaWYgKCF0YWcuc3RhcnRzV2l0aCgiIyIpKQogICAgICAgICAgICAgICAgICB0YWcgPSAiIyIgKyB0YWc7CiAgICAgICAgICAgICAgdGFncy5hZGQodGFnKTsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGFsaWFzIG9mIGV4dHJhY3RBbGlhc2VzKG1ldGFkYXRhLmZyb250bWF0dGVyKSB8fCBbXSkKICAgICAgICAgICAgICBhbGlhc2VzLmFkZChhbGlhcyk7CiAgICAgICAgICBsZXQgZnJvbnRGaWVsZHMgPSBwYXJzZUZyb250bWF0dGVyKG1ldGFkYXRhLmZyb250bWF0dGVyKTsKICAgICAgICAgIGZvciAobGV0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhmcm9udEZpZWxkcykpIHsKICAgICAgICAgICAgICBpZiAoa2V5ID09ICJwb3NpdGlvbiIpCiAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgIGFkZElubGluZUZpZWxkKGtleSwgdmFsdWUsIGZpZWxkcyk7CiAgICAgICAgICB9CiAgICAgIH0KICAgICAgLy8gQWRkIGZyb250bWF0dGVyIGxpbmtzIHRvIGxpbmtzLgogICAgICBpZiAobWV0YWRhdGEuZnJvbnRtYXR0ZXJMaW5rcykgewogICAgICAgICAgZm9yIChsZXQgcmF3TGluayBvZiBtZXRhZGF0YS5mcm9udG1hdHRlckxpbmtzIHx8IFtdKSB7CiAgICAgICAgICAgICAgY29uc3QgbGluayA9IExpbmsuaW5mZXIocmF3TGluay5saW5rLCBmYWxzZSwgcmF3TGluay5kaXNwbGF5VGV4dCk7CiAgICAgICAgICAgICAgbGlua3MucHVzaChsaW5rKTsKICAgICAgICAgIH0KICAgICAgfQogICAgICAvLyBMaW5rcyBpbiBtZXRhZGF0YS4KICAgICAgY29uc3QgbGlua3NCeUxpbmUgPSB7fTsKICAgICAgZm9yIChsZXQgcmF3TGluayBvZiBtZXRhZGF0YS5saW5rcyB8fCBbXSkgewogICAgICAgICAgY29uc3QgbGluayA9IExpbmsuaW5mZXIocmF3TGluay5saW5rLCBmYWxzZSwgcmF3TGluay5kaXNwbGF5VGV4dCk7CiAgICAgICAgICBjb25zdCBsaW5lID0gcmF3TGluay5wb3NpdGlvbi5zdGFydC5saW5lOwogICAgICAgICAgbGlua3MucHVzaChsaW5rKTsKICAgICAgICAgIGlmICghKGxpbmUgaW4gbGlua3NCeUxpbmUpKQogICAgICAgICAgICAgIGxpbmtzQnlMaW5lW2xpbmVdID0gW2xpbmtdOwogICAgICAgICAgZWxzZQogICAgICAgICAgICAgIGxpbmtzQnlMaW5lW2xpbmVdLnB1c2gobGluayk7CiAgICAgIH0KICAgICAgLy8gRW1iZWQgTGlua3MgaW4gbWV0YWRhdGEuCiAgICAgIGZvciAobGV0IHJhd0VtYmVkIG9mIG1ldGFkYXRhLmVtYmVkcyB8fCBbXSkgewogICAgICAgICAgY29uc3QgbGluayA9IExpbmsuaW5mZXIocmF3RW1iZWQubGluaywgdHJ1ZSwgcmF3RW1iZWQuZGlzcGxheVRleHQpOwogICAgICAgICAgY29uc3QgbGluZSA9IHJhd0VtYmVkLnBvc2l0aW9uLnN0YXJ0LmxpbmU7CiAgICAgICAgICBsaW5rcy5wdXNoKGxpbmspOwogICAgICAgICAgaWYgKCEobGluZSBpbiBsaW5rc0J5TGluZSkpCiAgICAgICAgICAgICAgbGlua3NCeUxpbmVbbGluZV0gPSBbbGlua107CiAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgbGlua3NCeUxpbmVbbGluZV0ucHVzaChsaW5rKTsKICAgICAgfQogICAgICAvLyBNZXJnZSBmcm9udG1hdHRlciBmaWVsZHMgd2l0aCBwYXJzZWQgZmllbGRzLgogICAgICBsZXQgbWFya2Rvd25EYXRhID0gcGFyc2VNYXJrZG93bihwYXRoLCBjb250ZW50cy5zcGxpdCgiXG4iKSwgbWV0YWRhdGEsIGxpbmtzQnlMaW5lKTsKICAgICAgbWVyZ2VGaWVsZEdyb3VwcyhmaWVsZHMsIG1hcmtkb3duRGF0YS5maWVsZHMpOwogICAgICAvLyBTdHJpcCAicG9zaXRpb24iIGZyb20gZnJvbnRtYXR0ZXIgc2luY2UgaXQgaXMgT2JzaWRpYW4gZGV0ZXJtaW5lZC4KICAgICAgY29uc3QgZnJvbnRtYXR0ZXIgPSBtZXRhZGF0YS5mcm9udG1hdHRlciB8fCB7fTsKICAgICAgaWYgKGZyb250bWF0dGVyICYmICJwb3NpdGlvbiIgaW4gZnJvbnRtYXR0ZXIpCiAgICAgICAgICBkZWxldGUgZnJvbnRtYXR0ZXJbInBvc2l0aW9uIl07CiAgICAgIHJldHVybiBuZXcgUGFnZU1ldGFkYXRhKHBhdGgsIHsKICAgICAgICAgIHRhZ3MsCiAgICAgICAgICBhbGlhc2VzLAogICAgICAgICAgbGlua3MsCiAgICAgICAgICBsaXN0czogbWFya2Rvd25EYXRhLmxpc3RzLAogICAgICAgICAgZmllbGRzOiBmaW5hbGl6ZUlubGluZUZpZWxkcyhmaWVsZHMpLAogICAgICAgICAgZnJvbnRtYXR0ZXI6IGZyb250bWF0dGVyLAogICAgICAgICAgY3RpbWU6IERhdGVUaW1lLmZyb21NaWxsaXMoc3RhdC5jdGltZSksCiAgICAgICAgICBtdGltZTogRGF0ZVRpbWUuZnJvbU1pbGxpcyhzdGF0Lm10aW1lKSwKICAgICAgICAgIHNpemU6IHN0YXQuc2l6ZSwKICAgICAgICAgIGRheTogZmluZERhdGUocGF0aCwgZmllbGRzKSwKICAgICAgfSk7CiAgfQogIC8qKiBFeHRyYWN0IHRhZ3MgaW50ZWxsaWdlbnRseSBmcm9tIGZyb250bWF0dGVyLiBIYW5kbGVzIGFycmF5cywgbnVtYmVycywgYW5kIHN0cmluZ3MuICovCiAgZnVuY3Rpb24gZXh0cmFjdFRhZ3MobWV0YWRhdGEpIHsKICAgICAgbGV0IHRhZ0tleXMgPSBPYmplY3Qua2V5cyhtZXRhZGF0YSkuZmlsdGVyKHQgPT4gdC50b0xvd2VyQ2FzZSgpID09ICJ0YWdzIiB8fCB0LnRvTG93ZXJDYXNlKCkgPT0gInRhZyIpOwogICAgICByZXR1cm4gdGFnS2V5cwogICAgICAgICAgLm1hcChrID0+IHNwbGl0RnJvbnRtYXR0ZXJUYWdPckFsaWFzKG1ldGFkYXRhW2tdLCAvWyxcc10rLykpCiAgICAgICAgICAucmVkdWNlKChwLCBjKSA9PiBwLmNvbmNhdChjKSwgW10pCiAgICAgICAgICAubWFwKHN0ciA9PiAoc3RyLnN0YXJ0c1dpdGgoIiMiKSA/IHN0ciA6ICIjIiArIHN0cikpOwogIH0KICAvKiogRXh0cmFjdCBhbGlhc2VzIGludGVsbGlnZW50bHkgZnJvbSBmcm9udG1hdHRlci4gSGFuZGxlcyBhcnJheXMsIG51bWJlcnMsIGFuZCBzdHJpbmdzLiAgKi8KICBmdW5jdGlvbiBleHRyYWN0QWxpYXNlcyhtZXRhZGF0YSkgewogICAgICBsZXQgYWxpYXNLZXlzID0gT2JqZWN0LmtleXMobWV0YWRhdGEpLmZpbHRlcih0ID0+IHQudG9Mb3dlckNhc2UoKSA9PSAiYWxpYXMiIHx8IHQudG9Mb3dlckNhc2UoKSA9PSAiYWxpYXNlcyIpOwogICAgICBjb25zdCByZXN1bHQgPSBbXTsKICAgICAgZm9yIChsZXQga2V5IG9mIGFsaWFzS2V5cykgewogICAgICAgICAgY29uc3QgdmFsdWUgPSBtZXRhZGF0YVtrZXldOwogICAgICAgICAgaWYgKCF2YWx1ZSkKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkKICAgICAgICAgICAgICByZXN1bHQucHVzaCguLi52YWx1ZS5tYXAodiA9PiAoIiIgKyB2KS50cmltKCkpKTsKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICByZXN1bHQucHVzaCguLi5zcGxpdEZyb250bWF0dGVyVGFnT3JBbGlhcyh2YWx1ZSwgLywvKSk7CiAgICAgIH0KICAgICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgLyoqIFNwbGl0IGEgZnJvbnRtYXR0ZXIgbGlzdCBpbnRvIHNlcGFyYXRlIGVsZW1lbnRzOyBoYW5kbGVzIGFjdHVhbCBsaXN0cywgY29tbWEgc2VwYXJhdGVkIGxpc3RzLCBhbmQgc2luZ2xlIGVsZW1lbnRzLiAqLwogIGZ1bmN0aW9uIHNwbGl0RnJvbnRtYXR0ZXJUYWdPckFsaWFzKGRhdGEsIG9uKSB7CiAgICAgIGlmIChkYXRhID09IG51bGwgfHwgZGF0YSA9PSB1bmRlZmluZWQpCiAgICAgICAgICByZXR1cm4gW107CiAgICAgIGlmIChBcnJheS5pc0FycmF5KGRhdGEpKSB7CiAgICAgICAgICByZXR1cm4gZGF0YQogICAgICAgICAgICAgIC5maWx0ZXIocyA9PiAhIXMpCiAgICAgICAgICAgICAgLm1hcChzID0+IHNwbGl0RnJvbnRtYXR0ZXJUYWdPckFsaWFzKHMsIG9uKSkKICAgICAgICAgICAgICAucmVkdWNlKChwLCBjKSA9PiBwLmNvbmNhdChjKSwgW10pOwogICAgICB9CiAgICAgIC8vIEZvcmNlIHRvIGEgc3RyaW5nIHRvIGhhbmRsZSBudW1iZXJzIGFuZCBzbyBvbi4KICAgICAgcmV0dXJuICgiIiArIGRhdGEpCiAgICAgICAgICAuc3BsaXQob24pCiAgICAgICAgICAuZmlsdGVyKHQgPT4gISF0KQogICAgICAgICAgLm1hcCh0ID0+IHQudHJpbSgpKQogICAgICAgICAgLmZpbHRlcih0ID0+IHQubGVuZ3RoID4gMCk7CiAgfQogIC8qKiBQYXJzZSByYXcgKG5ld2xpbmUtZGVsaW1pdGVkKSBtYXJrZG93biwgcmV0dXJuaW5nIGlubGluZSBmaWVsZHMsIGxpc3QgaXRlbXMsIGFuZCBvdGhlciBtZXRhZGF0YS4gKi8KICBmdW5jdGlvbiBwYXJzZU1hcmtkb3duKHBhdGgsIGNvbnRlbnRzLCBtZXRhZGF0YSwgbGlua3NCeUxpbmUpIHsKICAgICAgbGV0IGZpZWxkcyA9IG5ldyBNYXAoKTsKICAgICAgLy8gRXh0cmFjdCB0YXNrIGRhdGEgYW5kIGFwcGVuZCB0aGUgZ2xvYmFsIGRhdGEgZXh0cmFjdGVkIGZyb20gdGhlbSB0byBvdXIgZmllbGRzLgogICAgICBsZXQgW2xpc3RzLCBleHRyYURhdGFdID0gcGFyc2VMaXN0cyhwYXRoLCBjb250ZW50cywgbWV0YWRhdGEsIGxpbmtzQnlMaW5lKTsKICAgICAgZm9yIChsZXQgW2tleSwgdmFsdWVzXSBvZiBleHRyYURhdGEuZW50cmllcygpKSB7CiAgICAgICAgICBpZiAoIWZpZWxkcy5oYXMoa2V5KSkKICAgICAgICAgICAgICBmaWVsZHMuc2V0KGtleSwgdmFsdWVzKTsKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICBmaWVsZHMuc2V0KGtleSwgZmllbGRzLmdldChrZXkpLmNvbmNhdCh2YWx1ZXMpKTsKICAgICAgfQogICAgICAvLyBUaGUgT2JzaWRpYW4gbWV0YWRhdGEgY2FjaGUgd2lsbCB0cmFjayBsaXN0IGVsZW1lbnRzIGluc2lkZSBvZiBvdGhlciBlbGVtZW50IGdyb3VwcyAobGlrZSBhbm5vdGF0aW9ucyBhbmQKICAgICAgLy8gY2FsbG91dHMpLi4uIHRoaXMgbWVhbnMgd2UgbWlnaHQgc2VlIG1ldGFkYXRhIHR3aWNlLCBzbyBza2lwIHRoZW0gbm93LiBWZXJ5IGFubm95aW5nLgogICAgICBjb25zdCBsaXN0TGluZXNUb1NraXAgPSBuZXcgU2V0KCk7CiAgICAgIGZvciAoY29uc3QgbGluZSBvZiBsaXN0cykgewogICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lLmxpbmVDb3VudDsgaSsrKQogICAgICAgICAgICAgIGxpc3RMaW5lc1RvU2tpcC5hZGQobGluZS5saW5lICsgaSk7CiAgICAgIH0KICAgICAgLy8gT25seSBwYXJzZSBoZWFkaW5nIGFuZCBwYXJhZ3JhcGggZWxlbWVudHMgZm9yIGlubGluZSBmaWVsZHM7IHdlIHdpbGwgcGFyc2UgbGlzdCBtZXRhZGF0YSBzZXBhcmF0ZWx5LgogICAgICBmb3IgKGxldCBzZWN0aW9uIG9mIG1ldGFkYXRhLnNlY3Rpb25zIHx8IFtdKSB7CiAgICAgICAgICBpZiAoc2VjdGlvbi50eXBlID09ICJsaXN0IiB8fCBzZWN0aW9uLnR5cGUgPT0gInJ1bGluZyIpCiAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICBmb3IgKGxldCBsaW5lbm8gPSBzZWN0aW9uLnBvc2l0aW9uLnN0YXJ0LmxpbmU7IGxpbmVubyA8PSBzZWN0aW9uLnBvc2l0aW9uLmVuZC5saW5lOyBsaW5lbm8rKykgewogICAgICAgICAgICAgIGxldCBsaW5lID0gY29udGVudHNbbGluZW5vXTsKICAgICAgICAgICAgICBpZiAobGluZSA9PSB1bmRlZmluZWQgfHwgbGluZSA9PSBudWxsKQogICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICBpZiAobGlzdExpbmVzVG9Ta2lwLmhhcyhsaW5lbm8pKQogICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAvLyBGYXN0IGJhaWwtb3V0IGZvciBsaW5lcyB0aGF0IGFyZSB0b28gbG9uZyBvciBkbyBub3QgY29udGFpbiAnOjonLgogICAgICAgICAgICAgIGlmIChsaW5lLmxlbmd0aCA+IDMyNzY4IHx8ICFsaW5lLmluY2x1ZGVzKCI6OiIpKQogICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICBsaW5lID0gbGluZS50cmltKCk7CiAgICAgICAgICAgICAgbGV0IGlubGluZUZpZWxkcyA9IGV4dHJhY3RJbmxpbmVGaWVsZHMobGluZSk7CiAgICAgICAgICAgICAgaWYgKGlubGluZUZpZWxkcy5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgICAgICAgIGZvciAobGV0IGlmaWVsZCBvZiBpbmxpbmVGaWVsZHMpCiAgICAgICAgICAgICAgICAgICAgICBhZGRSYXdJbmxpbmVGaWVsZChpZmllbGQsIGZpZWxkcyk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgICBsZXQgZnVsbExpbmUgPSBleHRyYWN0RnVsbExpbmVGaWVsZChsaW5lKTsKICAgICAgICAgICAgICAgICAgaWYgKGZ1bGxMaW5lKQogICAgICAgICAgICAgICAgICAgICAgYWRkUmF3SW5saW5lRmllbGQoZnVsbExpbmUsIGZpZWxkcyk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICB9CiAgICAgIHJldHVybiB7IGZpZWxkcywgbGlzdHMgfTsKICB9CiAgLy8gVE9ETzogQ29uc2lkZXIgdXNpbmcgYW4gYWN0dWFsIHBhcnNlciBpbiBsZWl1IG9mIGEgbW9yZSBleHBlbnNpdmUgcmVnZXguCiAgY29uc3QgTElTVF9JVEVNX1JFR0VYID0gL15bXHM+XSooXGQrXC58XGQrXCl8XCp8LXxcKylccyooXFsuezAsMX1cXSk/XHMqKC4qKSQvbXU7CiAgLyoqCiAgICogUGFyc2UgbGlzdCBpdGVtcyBmcm9tIHRoZSBwYWdlICsgbWV0YWRhdGEuIFRoaXMgcmVxdWlyZXMgc29tZSBhZGRpdGlvbmFsIHBhcnNpbmcgYWJvdmUgd2hhdGV2ZXIgT2JzaWRpYW4gcHJvdmlkZXMsCiAgICogc2luY2UgT2JzaWRpYW4gb25seSBnaXZlcyBsaW5lIG51bWJlcnMuCiAgICovCiAgZnVuY3Rpb24gcGFyc2VMaXN0cyhwYXRoLCBjb250ZW50LCBtZXRhZGF0YSwgbGlua3NCeUxpbmUpIHsKICAgICAgbGV0IGNhY2hlID0ge307CiAgICAgIC8vIFBsYWNlIGFsbCBvZiB0aGUgdmFsdWVzIGluIHRoZSBjYWNoZSBiZWZvcmUgcmVzb2x2aW5nIGNoaWxkcmVuICYgbWV0YWRhdGEgcmVsYXRpb25zaGlwcy4KICAgICAgZm9yIChsZXQgcmF3RWxlbWVudCBvZiBtZXRhZGF0YS5saXN0SXRlbXMgfHwgW10pIHsKICAgICAgICAgIC8vIE1hdGNoIG9uIHRoZSBmaXJzdCBsaW5lIHRvIGdldCB0aGUgc3ltYm9sIGFuZCBmaXJzdCBsaW5lIG9mIHRleHQuCiAgICAgICAgICBsZXQgcmF3TWF0Y2ggPSBMSVNUX0lURU1fUkVHRVguZXhlYyhjb250ZW50W3Jhd0VsZW1lbnQucG9zaXRpb24uc3RhcnQubGluZV0pOwogICAgICAgICAgaWYgKCFyYXdNYXRjaCkKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIC8vIEFuZCB0aGVuIHN0cmlwIHVubmVjZXNzYXJ5IHNwYWNpbmcgZnJvbSB0aGUgcmVtYWluaW5nIGxpbmVzLgogICAgICAgICAgbGV0IHRleHRQYXJ0cyA9IFtyYXdNYXRjaFszXV0KICAgICAgICAgICAgICAuY29uY2F0KGNvbnRlbnQuc2xpY2UocmF3RWxlbWVudC5wb3NpdGlvbi5zdGFydC5saW5lICsgMSwgcmF3RWxlbWVudC5wb3NpdGlvbi5lbmQubGluZSArIDEpKQogICAgICAgICAgICAgIC5tYXAodCA9PiB0LnRyaW0oKSk7CiAgICAgICAgICBsZXQgdGV4dFdpdGhOZXdsaW5lID0gdGV4dFBhcnRzLmpvaW4oIlxuIik7CiAgICAgICAgICBsZXQgdGV4dE5vTmV3bGluZSA9IHRleHRQYXJ0cy5qb2luKCIgIik7CiAgICAgICAgICAvLyBGaW5kIHRoZSBsaXN0IHRoYXQgd2UgYXJlIGEgcGFydCBvZiBieSBsaW5lLgogICAgICAgICAgbGV0IGNvbnRhaW5pbmdMaXN0SWQgPSAobWV0YWRhdGEuc2VjdGlvbnMgfHwgW10pLmZpbmRJbmRleChzID0+IHMudHlwZSA9PSAibGlzdCIgJiYKICAgICAgICAgICAgICBzLnBvc2l0aW9uLnN0YXJ0LmxpbmUgPD0gcmF3RWxlbWVudC5wb3NpdGlvbi5zdGFydC5saW5lICYmCiAgICAgICAgICAgICAgcy5wb3NpdGlvbi5lbmQubGluZSA+PSByYXdFbGVtZW50LnBvc2l0aW9uLnN0YXJ0LmxpbmUpOwogICAgICAgICAgLy8gRmluZCB0aGUgc2VjdGlvbiB3ZSBiZWxvbmcgdG8gYXMgd2VsbC4KICAgICAgICAgIGxldCBzZWN0aW9uTmFtZSA9IGZpbmRQcmV2aW91c0hlYWRlcihyYXdFbGVtZW50LnBvc2l0aW9uLnN0YXJ0LmxpbmUsIG1ldGFkYXRhLmhlYWRpbmdzIHx8IFtdKTsKICAgICAgICAgIGxldCBzZWN0aW9uTGluayA9IHNlY3Rpb25OYW1lID09PSB1bmRlZmluZWQgPyBMaW5rLmZpbGUocGF0aCkgOiBMaW5rLmhlYWRlcihwYXRoLCBzZWN0aW9uTmFtZSk7CiAgICAgICAgICBsZXQgY2xvc2VzdExpbmsgPSByYXdFbGVtZW50LmlkID09PSB1bmRlZmluZWQgPyBzZWN0aW9uTGluayA6IExpbmsuYmxvY2socGF0aCwgcmF3RWxlbWVudC5pZCk7CiAgICAgICAgICAvLyBHYXRoZXIgYW55IGxpbmtzIHRoYXQgb2NjdXIgb24gdGhlIHNhbWUgbGluZXMgYXMgdGhlIHRhc2suCiAgICAgICAgICBjb25zdCBsaW5rcyA9IFtdOwogICAgICAgICAgZm9yIChsZXQgbGluZSA9IHJhd0VsZW1lbnQucG9zaXRpb24uc3RhcnQubGluZTsgbGluZSA8PSByYXdFbGVtZW50LnBvc2l0aW9uLmVuZC5saW5lOyBsaW5lKyspIHsKICAgICAgICAgICAgICBpZiAobGlua3NCeUxpbmVbbGluZV0pCiAgICAgICAgICAgICAgICAgIGxpbmtzLnB1c2goLi4ubGlua3NCeUxpbmVbbGluZV0pOwogICAgICAgICAgfQogICAgICAgICAgLy8gQ29uc3RydWN0IHVuaXZlcnNhbCBpbmZvcm1hdGlvbiBhYm91dCB0aGlzIGVsZW1lbnQgKGJlZm9yZSB0YXNrcykuCiAgICAgICAgICBsZXQgaXRlbSA9IG5ldyBMaXN0SXRlbSh7CiAgICAgICAgICAgICAgc3ltYm9sOiByYXdNYXRjaFsxXSwKICAgICAgICAgICAgICBsaW5rOiBjbG9zZXN0TGluaywKICAgICAgICAgICAgICBsaW5rczogbGlua3MsCiAgICAgICAgICAgICAgc2VjdGlvbjogc2VjdGlvbkxpbmssCiAgICAgICAgICAgICAgdGV4dDogdGV4dFdpdGhOZXdsaW5lLAogICAgICAgICAgICAgIHRhZ3M6IGV4dHJhY3RUYWdzJDEodGV4dE5vTmV3bGluZSksCiAgICAgICAgICAgICAgbGluZTogcmF3RWxlbWVudC5wb3NpdGlvbi5zdGFydC5saW5lLAogICAgICAgICAgICAgIGxpbmVDb3VudDogcmF3RWxlbWVudC5wb3NpdGlvbi5lbmQubGluZSAtIHJhd0VsZW1lbnQucG9zaXRpb24uc3RhcnQubGluZSArIDEsCiAgICAgICAgICAgICAgbGlzdDogY29udGFpbmluZ0xpc3RJZCA9PSAtMSA/IC0xIDogKG1ldGFkYXRhLnNlY3Rpb25zIHx8IFtdKVtjb250YWluaW5nTGlzdElkXS5wb3NpdGlvbi5zdGFydC5saW5lLAogICAgICAgICAgICAgIHBvc2l0aW9uOiByYXdFbGVtZW50LnBvc2l0aW9uLAogICAgICAgICAgICAgIGNoaWxkcmVuOiBbXSwKICAgICAgICAgICAgICBibG9ja0lkOiByYXdFbGVtZW50LmlkLAogICAgICAgICAgfSk7CiAgICAgICAgICBpZiAocmF3RWxlbWVudC5wYXJlbnQgPj0gMCAmJiByYXdFbGVtZW50LnBhcmVudCAhPSBpdGVtLmxpbmUpCiAgICAgICAgICAgICAgaXRlbS5wYXJlbnQgPSByYXdFbGVtZW50LnBhcmVudDsKICAgICAgICAgIC8vIFNldCB1cCB0aGUgYmFzaWMgdGFzayBpbmZvcm1hdGlvbiBmb3Igbm93LCB0aG91Z2ggd2UgaGF2ZSB0byByZWNvbXB1dGUgYGZ1bGx5Q29tcHV0ZWRgIGxhdGVyLgogICAgICAgICAgaWYgKHJhd0VsZW1lbnQudGFzaykgewogICAgICAgICAgICAgIGl0ZW0udGFzayA9IHsKICAgICAgICAgICAgICAgICAgc3RhdHVzOiByYXdFbGVtZW50LnRhc2ssCiAgICAgICAgICAgICAgICAgIGNoZWNrZWQ6IHJhd0VsZW1lbnQudGFzayAhPSAiIiAmJiByYXdFbGVtZW50LnRhc2sgIT0gIiAiLAogICAgICAgICAgICAgICAgICBjb21wbGV0ZWQ6IHJhd0VsZW1lbnQudGFzayA9PSAiWCIgfHwgcmF3RWxlbWVudC50YXNrID09ICJ4IiwKICAgICAgICAgICAgICAgICAgZnVsbHlDb21wbGV0ZWQ6IHJhd0VsZW1lbnQudGFzayA9PSAiWCIgfHwgcmF3RWxlbWVudC50YXNrID09ICJ4IiwKICAgICAgICAgICAgICB9OwogICAgICAgICAgfQogICAgICAgICAgLy8gRXh0cmFjdCBpbmxpbmUgZmllbGRzOyBleHRyYWN0IGZ1bGwtbGluZSBmaWVsZHMgb25seSBpZiB3ZSBhcmUgTk9UIGEgdGFzay4KICAgICAgICAgIGl0ZW0uZmllbGRzID0gbmV3IE1hcCgpOwogICAgICAgICAgZm9yIChsZXQgZWxlbWVudCBvZiBleHRyYWN0SW5saW5lRmllbGRzKHRleHROb05ld2xpbmUsIHRydWUpKQogICAgICAgICAgICAgIGFkZFJhd0lubGluZUZpZWxkKGVsZW1lbnQsIGl0ZW0uZmllbGRzKTsKICAgICAgICAgIGlmICghcmF3RWxlbWVudC50YXNrICYmIGl0ZW0uZmllbGRzLnNpemUgPT0gMCkgewogICAgICAgICAgICAgIGxldCBmdWxsTGluZSA9IGV4dHJhY3RGdWxsTGluZUZpZWxkKHRleHROb05ld2xpbmUpOwogICAgICAgICAgICAgIGlmIChmdWxsTGluZSkKICAgICAgICAgICAgICAgICAgYWRkUmF3SW5saW5lRmllbGQoZnVsbExpbmUsIGl0ZW0uZmllbGRzKTsKICAgICAgICAgIH0KICAgICAgICAgIGNhY2hlW2l0ZW0ubGluZV0gPSBpdGVtOwogICAgICB9CiAgICAgIC8vIFRyZWUgdXBkYXRpbmcgcGFzc2VzLiBVcGRhdGUgY2hpbGQgbGlzdHMuIFByb3BvZ2F0ZSBtZXRhZGF0YSB1cCB0byBwYXJlbnQgdGFza3MuIFVwZGF0ZSB0YXNrIGBmdWxseUNvbXBsZXRlZGAuCiAgICAgIGxldCBsaXRlcmFscyA9IG5ldyBNYXAoKTsKICAgICAgZm9yIChsZXQgbGlzdEl0ZW0gb2YgT2JqZWN0LnZhbHVlcyhjYWNoZSkpIHsKICAgICAgICAgIC8vIFBhc3MgMTogVXBkYXRlIGNoaWxkIGxpc3RzLgogICAgICAgICAgaWYgKGxpc3RJdGVtLnBhcmVudCAhPT0gdW5kZWZpbmVkICYmIGxpc3RJdGVtLnBhcmVudCBpbiBjYWNoZSkgewogICAgICAgICAgICAgIGxldCBwYXJlbnQgPSBjYWNoZVtsaXN0SXRlbS5wYXJlbnRdOwogICAgICAgICAgICAgIHBhcmVudC5jaGlsZHJlbi5wdXNoKGxpc3RJdGVtLmxpbmUpOwogICAgICAgICAgfQogICAgICAgICAgLy8gUGFzcyAyOiBQcm9wb2dhdGUgbWV0YWRhdGEgdXAgdG8gdGhlIHBhcmVudCB0YXNrIG9yIHJvb3QgZWxlbWVudC4KICAgICAgICAgIGlmICghbGlzdEl0ZW0udGFzaykgewogICAgICAgICAgICAgIG1lcmdlRmllbGRHcm91cHMobGl0ZXJhbHMsIGxpc3RJdGVtLmZpZWxkcyk7CiAgICAgICAgICAgICAgLy8gVE9ETyAoYmxhY2tzbWl0aGd1KTogVGhlIGJlbG93IGNvZGUgcHJvcGVybHkgcHJvcG9nYXRlcyBtZXRhZGF0YSB1cCB0byB0aGUgbmVhcmVzdCB0YXNrLCB3aGljaCBpcyB0aGUKICAgICAgICAgICAgICAvLyBtb3JlIGludHVpdGl2ZSBiZWhhdmlvci4gRm9yIG5vdywgdGhvdWdoLCB3ZSB3aWxsIGtlZXAgdGhlIGV4aXN0aW5nIGxvZ2ljLgogICAgICAgICAgICAgIC8qCiAgICAgICAgICAgICAgbGV0IHJvb3Q6IExpc3RJdGVtIHwgdW5kZWZpbmVkID0gbGlzdEl0ZW07CiAgICAgICAgICAgICAgd2hpbGUgKCEhcm9vdCAmJiAhcm9vdC50YXNrKSByb290ID0gY2FjaGVbcm9vdC5wYXJlbnQgPz8gLTFdOwoKICAgICAgICAgICAgICAvLyBJZiB0aGUgcm9vdCBpcyBudWxsLCBhcHBlbmQgdGhpcyBtZXRhZGF0YSB0byB0aGUgcm9vdDsgb3RoZXJ3aXNlLCBhcHBlbmQgdG8gdGhlIHRhc2suCiAgICAgICAgICAgICAgbWVyZ2VGaWVsZEdyb3Vwcyhyb290ID09PSB1bmRlZmluZWQgfHwgcm9vdCA9PSBudWxsID8gbGl0ZXJhbHMgOiByb290LmZpZWxkcywgbGlzdEl0ZW0uZmllbGRzKTsKICAgICAgICAgICAgICAqLwogICAgICAgICAgfQogICAgICAgICAgLy8gUGFzcyAzOiBQcm9wb2dhdGUgYGZ1bGx5Q29tcGxldGVkYCB1cCB0aGUgdGFzayB0cmVlLiBUaGlzIGlzIGEgbGl0dGxlIGxlc3MgZWZmaWNpZW50IHRoYW4ganVzdCBkb2luZyBhIHNpbXBsZQogICAgICAgICAgLy8gREZTIHVzaW5nIHRoZSBjaGlsZHJlbiBJRHMsIGJ1dCBpdCdzIHByb2JhYmx5IGZpbmUuCiAgICAgICAgICBpZiAobGlzdEl0ZW0udGFzaykgewogICAgICAgICAgICAgIGxldCBjdXJyID0gbGlzdEl0ZW07CiAgICAgICAgICAgICAgd2hpbGUgKCEhY3VycikgewogICAgICAgICAgICAgICAgICBpZiAoY3Vyci50YXNrKQogICAgICAgICAgICAgICAgICAgICAgY3Vyci50YXNrLmZ1bGx5Q29tcGxldGVkID0gY3Vyci50YXNrLmZ1bGx5Q29tcGxldGVkICYmIGxpc3RJdGVtLnRhc2suY29tcGxldGVkOwogICAgICAgICAgICAgICAgICBjdXJyID0gY2FjaGVbY3Vyci5wYXJlbnQgPz8gLTFdOwogICAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gW09iamVjdC52YWx1ZXMoY2FjaGUpLCBsaXRlcmFsc107CiAgfQogIC8qKiBBdHRlbXB0IHRvIGZpbmQgYSBkYXRlIGFzc29jaWF0ZWQgd2l0aCB0aGUgZ2l2ZW4gcGFnZSBmcm9tIG1ldGFkYXRhIG9yIGZpbGVuYW1lcy4gKi8KICBmdW5jdGlvbiBmaW5kRGF0ZShmaWxlLCBmaWVsZHMpIHsKICAgICAgZm9yIChsZXQga2V5IG9mIGZpZWxkcy5rZXlzKCkpIHsKICAgICAgICAgIGlmICghKGtleS50b0xvY2FsZUxvd2VyQ2FzZSgpID09ICJkYXRlIiB8fCBrZXkudG9Mb2NhbGVMb3dlckNhc2UoKSA9PSAiZGF5IikpCiAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICBsZXQgdmFsdWUgPSBmaWVsZHMuZ2V0KGtleSk7CiAgICAgICAgICBpZiAoVmFsdWVzLmlzRGF0ZSh2YWx1ZSkpIHsKICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIGlmIChWYWx1ZXMuaXNBcnJheSh2YWx1ZSkgJiYgdmFsdWUubGVuZ3RoID4gMCAmJiBWYWx1ZXMuaXNEYXRlKHZhbHVlWzBdKSkgewogICAgICAgICAgICAgIHJldHVybiB2YWx1ZVswXTsKICAgICAgICAgIH0KICAgICAgICAgIGVsc2UgaWYgKFZhbHVlcy5pc0xpbmsodmFsdWUpKSB7CiAgICAgICAgICAgICAgbGV0IGRhdGUgPSBleHRyYWN0RGF0ZSh2YWx1ZS5wYXRoKSA/PyBleHRyYWN0RGF0ZSh2YWx1ZS5zdWJwYXRoID8/ICIiKSA/PyBleHRyYWN0RGF0ZSh2YWx1ZS5kaXNwbGF5ID8/ICIiKTsKICAgICAgICAgICAgICBpZiAoZGF0ZSkKICAgICAgICAgICAgICAgICAgcmV0dXJuIGRhdGU7CiAgICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIGV4dHJhY3REYXRlKGdldEZpbGVUaXRsZShmaWxlKSk7CiAgfQogIC8qKiBSZWN1cnNpdmVseSBjb252ZXJ0IGZyb250bWF0dGVyIGludG8gZmllbGRzLiBXZSBoYXZlIHRvIGRhbmNlIGFyb3VuZCBZQU1MIHN0cnVjdHVyZS4gKi8KICBmdW5jdGlvbiBwYXJzZUZyb250bWF0dGVyKHZhbHVlKSB7CiAgICAgIGlmICh2YWx1ZSA9PSBudWxsKSB7CiAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgfQogICAgICBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICJvYmplY3QiKSB7CiAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHsKICAgICAgICAgICAgICBsZXQgcmVzdWx0ID0gW107CiAgICAgICAgICAgICAgZm9yIChsZXQgY2hpbGQgb2YgdmFsdWUpIHsKICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2gocGFyc2VGcm9udG1hdHRlcihjaGlsZCkpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgZWxzZSBpZiAodmFsdWUgaW5zdGFuY2VvZiBEYXRlKSB7CiAgICAgICAgICAgICAgbGV0IGRhdGVQYXJzZSA9IERhdGVUaW1lLmZyb21KU0RhdGUodmFsdWUpOwogICAgICAgICAgICAgIHJldHVybiBkYXRlUGFyc2U7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICBsZXQgb2JqZWN0ID0gdmFsdWU7CiAgICAgICAgICAgICAgbGV0IHJlc3VsdCA9IHt9OwogICAgICAgICAgICAgIGZvciAobGV0IGtleSBpbiBvYmplY3QpIHsKICAgICAgICAgICAgICAgICAgcmVzdWx0W2tleV0gPSBwYXJzZUZyb250bWF0dGVyKG9iamVjdFtrZXldKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0KICAgICAgfQogICAgICBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICJudW1iZXIiKSB7CiAgICAgICAgICByZXR1cm4gdmFsdWU7CiAgICAgIH0KICAgICAgZWxzZSBpZiAodHlwZW9mIHZhbHVlID09PSAiYm9vbGVhbiIpIHsKICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgfQogICAgICBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICJzdHJpbmciKSB7CiAgICAgICAgICBsZXQgZGF0ZVBhcnNlID0gRVhQUkVTU0lPTi5kYXRlLnBhcnNlKHZhbHVlKTsKICAgICAgICAgIGlmIChkYXRlUGFyc2Uuc3RhdHVzKQogICAgICAgICAgICAgIHJldHVybiBkYXRlUGFyc2UudmFsdWU7CiAgICAgICAgICBsZXQgZHVyYXRpb25QYXJzZSA9IEVYUFJFU1NJT04uZHVyYXRpb24ucGFyc2UodmFsdWUpOwogICAgICAgICAgaWYgKGR1cmF0aW9uUGFyc2Uuc3RhdHVzKQogICAgICAgICAgICAgIHJldHVybiBkdXJhdGlvblBhcnNlLnZhbHVlOwogICAgICAgICAgbGV0IGxpbmtQYXJzZSA9IEVYUFJFU1NJT04uZW1iZWRMaW5rLnBhcnNlKHZhbHVlKTsKICAgICAgICAgIGlmIChsaW5rUGFyc2Uuc3RhdHVzKQogICAgICAgICAgICAgIHJldHVybiBsaW5rUGFyc2UudmFsdWU7CiAgICAgICAgICByZXR1cm4gdmFsdWU7CiAgICAgIH0KICAgICAgLy8gQmFja3VwIGlmIHdlIGRvbid0IHVuZGVyc3RhbmQgdGhlIHR5cGUuCiAgICAgIHJldHVybiBudWxsOwogIH0KICAvKiogQWRkIGEgcGFyc2VkIGlubGluZSBmaWVsZCB0byB0aGUgb3V0cHV0IG1hcC4gKi8KICBmdW5jdGlvbiBhZGRSYXdJbmxpbmVGaWVsZChmaWVsZCwgb3V0cHV0KSB7CiAgICAgIGFkZElubGluZUZpZWxkKGZpZWxkLmtleSwgcGFyc2VJbmxpbmVWYWx1ZShmaWVsZC52YWx1ZSksIG91dHB1dCk7CiAgfQogIC8qKiBBZGQgYSByYXcgaW5saW5lIGZpZWxkIHRvIGFuIG91dHB1dCBtYXAsIGNhbm9uaWNhbGl6aW5nIGFzIG5lZWRlZC4gKi8KICBmdW5jdGlvbiBhZGRJbmxpbmVGaWVsZChrZXksIHZhbHVlLCBvdXRwdXQpIHsKICAgICAgaWYgKCFvdXRwdXQuaGFzKGtleSkpCiAgICAgICAgICBvdXRwdXQuc2V0KGtleSwgW3ZhbHVlXSk7CiAgICAgIGVsc2UKICAgICAgICAgIG91dHB1dC5nZXQoa2V5KT8ucHVzaCh2YWx1ZSk7CiAgfQogIC8qKiBHaXZlbiBhIHJhdyBsaXN0IG9mIGlubGluZSBmaWVsZCB2YWx1ZXMsIGFkZCBub3JtYWxpemVkIGtleXMgYW5kIHNxdWFzaCB0aGVtLiAqLwogIGZ1bmN0aW9uIGZpbmFsaXplSW5saW5lRmllbGRzKGZpZWxkcykgewogICAgICAvLyBDb21wdXRlIHVuaXF1ZSBub3JtYWxpemVkIGtleXMgKHRoYXQgZG8gbm90IG92ZXJsYXAgdy8gdGhlIGZpZWxkcykuCiAgICAgIGxldCBub3JtYWxpemVkID0gbmV3IE1hcCgpOwogICAgICBmb3IgKGxldCBba2V5LCB2YWx1ZXNdIG9mIGZpZWxkcy5lbnRyaWVzKCkpIHsKICAgICAgICAgIGxldCBub3JtS2V5ID0gY2Fub25pY2FsaXplVmFyTmFtZShrZXkpOwogICAgICAgICAgaWYgKG5vcm1LZXkgPT0gIiIgfHwgZmllbGRzLmhhcyhub3JtS2V5KSkKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIGlmICghbm9ybWFsaXplZC5oYXMobm9ybUtleSkpCiAgICAgICAgICAgICAgbm9ybWFsaXplZC5zZXQobm9ybUtleSwgdmFsdWVzKTsKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICBub3JtYWxpemVkLnNldChub3JtS2V5LCBub3JtYWxpemVkLmdldChub3JtS2V5KS5jb25jYXQodmFsdWVzKSk7CiAgICAgIH0KICAgICAgLy8gQ29tYmluZSBub3JtYWxpemVkICsgbm9ybWFsIGtleXMuCiAgICAgIGxldCBpbnRlcmltID0gbmV3IE1hcCgpOwogICAgICBtZXJnZUZpZWxkR3JvdXBzKGludGVyaW0sIGZpZWxkcyk7CiAgICAgIG1lcmdlRmllbGRHcm91cHMoaW50ZXJpbSwgbm9ybWFsaXplZCk7CiAgICAgIC8vIEFuZCB0aGVuIGZsYXR0ZW4gdGhlbS4KICAgICAgbGV0IHJlc3VsdCA9IG5ldyBNYXAoKTsKICAgICAgZm9yIChsZXQgW2tleSwgdmFsdWVdIG9mIGludGVyaW0uZW50cmllcygpKSB7CiAgICAgICAgICBpZiAodmFsdWUubGVuZ3RoID09IDEpCiAgICAgICAgICAgICAgcmVzdWx0LnNldChrZXksIHZhbHVlWzBdKTsKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICByZXN1bHQuc2V0KGtleSwgdmFsdWUpOwogICAgICB9CiAgICAgIHJldHVybiByZXN1bHQ7CiAgfQogIC8qKiBDb3B5IGFsbCBmaWVsZHMgb2YgJ3NvdXJjZScgaW50byAndGFyZ2V0Jy4gKi8KICBmdW5jdGlvbiBtZXJnZUZpZWxkR3JvdXBzKHRhcmdldCwgc291cmNlKSB7CiAgICAgIGZvciAobGV0IGtleSBvZiBzb3VyY2Uua2V5cygpKSB7CiAgICAgICAgICBpZiAoIXRhcmdldC5oYXMoa2V5KSkKICAgICAgICAgICAgICB0YXJnZXQuc2V0KGtleSwgc291cmNlLmdldChrZXkpKTsKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICB0YXJnZXQuc2V0KGtleSwgdGFyZ2V0LmdldChrZXkpLmNvbmNhdChzb3VyY2UuZ2V0KGtleSkpKTsKICAgICAgfQogIH0KICAvKiogRmluZCB0aGUgaGVhZGVyIHRoYXQgaXMgbW9zdCBpbW1lZGlhdGVseSBhYm92ZSB0aGUgZ2l2ZW4gbGluZSBudW1iZXIuICovCiAgZnVuY3Rpb24gZmluZFByZXZpb3VzSGVhZGVyKGxpbmUsIGhlYWRlcnMpIHsKICAgICAgaWYgKGhlYWRlcnMubGVuZ3RoID09IDApCiAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkOwogICAgICBpZiAoaGVhZGVyc1swXS5wb3NpdGlvbi5zdGFydC5saW5lID4gbGluZSkKICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7CiAgICAgIGxldCBpbmRleCA9IGhlYWRlcnMubGVuZ3RoIC0gMTsKICAgICAgd2hpbGUgKGluZGV4ID49IDAgJiYgaGVhZGVyc1tpbmRleF0ucG9zaXRpb24uc3RhcnQubGluZSA+IGxpbmUpCiAgICAgICAgICBpbmRleC0tOwogICAgICByZXR1cm4gaGVhZGVyc1tpbmRleF0uaGVhZGluZzsKICB9CgogIC8qKiBBY3R1YWwgaW1wb3J0IGltcGxlbWVudGF0aW9uIGJhY2tlbmQuIFRoaXMgbXVzdCByZW1haW4gc2VwYXJhdGUgZnJvbSBgaW1wb3J0LWVudHJ5YCBzaW5jZSBpdCBpcyB1c2VkIHdpdGhvdXQgd2ViIHdvcmtlcnMuICovCiAgZnVuY3Rpb24gcnVuSW1wb3J0KHBhdGgsIGNvbnRlbnRzLCBzdGF0cywgbWV0YWRhdGEpIHsKICAgICAgcmV0dXJuIHBhcnNlUGFnZShwYXRoLCBjb250ZW50cywgc3RhdHMsIG1ldGFkYXRhKTsKICB9CgogIC8qKiBTaW1wbGlmaWVzIHBhc3NpbmcgZGF0YXZpZXcgdmFsdWVzIGFjcm9zcyB0aGUgSlMgd2ViIHdvcmtlciBiYXJyaWVyLiAqLwogIHZhciBUcmFuc2ZlcmFibGU7CiAgKGZ1bmN0aW9uIChUcmFuc2ZlcmFibGUpIHsKICAgICAgLyoqIENvbnZlcnQgYSBsaXRlcmFsIHZhbHVlIHRvIGEgc2VyaWFsaXplci1mcmllbmRseSB0cmFuc2ZlcmFibGUgdmFsdWUuICovCiAgICAgIGZ1bmN0aW9uIHRyYW5zZmVyYWJsZSh2YWx1ZSkgewogICAgICAgICAgLy8gSGFuZGxlIHNpbXBsZSB1bml2ZXJzYWwgdHlwZXMgZmlyc3QuCiAgICAgICAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBNYXApIHsKICAgICAgICAgICAgICBsZXQgY29waWVkID0gbmV3IE1hcCgpOwogICAgICAgICAgICAgIGZvciAobGV0IFtrZXksIHZhbF0gb2YgdmFsdWUuZW50cmllcygpKQogICAgICAgICAgICAgICAgICBjb3BpZWQuc2V0KHRyYW5zZmVyYWJsZShrZXkpLCB0cmFuc2ZlcmFibGUodmFsKSk7CiAgICAgICAgICAgICAgcmV0dXJuIGNvcGllZDsKICAgICAgICAgIH0KICAgICAgICAgIGVsc2UgaWYgKHZhbHVlIGluc3RhbmNlb2YgU2V0KSB7CiAgICAgICAgICAgICAgbGV0IGNvcGllZCA9IG5ldyBTZXQoKTsKICAgICAgICAgICAgICBmb3IgKGxldCB2YWwgb2YgdmFsdWUpCiAgICAgICAgICAgICAgICAgIGNvcGllZC5hZGQodHJhbnNmZXJhYmxlKHZhbCkpOwogICAgICAgICAgICAgIHJldHVybiBjb3BpZWQ7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgd3JhcHBlZCA9IFZhbHVlcy53cmFwVmFsdWUodmFsdWUpOwogICAgICAgICAgaWYgKHdyYXBwZWQgPT09IHVuZGVmaW5lZCkKICAgICAgICAgICAgICB0aHJvdyBFcnJvcigiVW5yZWNvZ25pemVkIHRyYW5zZmVyYWJsZSB2YWx1ZTogIiArIHZhbHVlKTsKICAgICAgICAgIHN3aXRjaCAod3JhcHBlZC50eXBlKSB7CiAgICAgICAgICAgICAgY2FzZSAibnVsbCI6CiAgICAgICAgICAgICAgY2FzZSAibnVtYmVyIjoKICAgICAgICAgICAgICBjYXNlICJzdHJpbmciOgogICAgICAgICAgICAgIGNhc2UgImJvb2xlYW4iOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZTsKICAgICAgICAgICAgICBjYXNlICJkYXRlIjoKICAgICAgICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgICAgICAgICJfX190cmFuc2Zlci10eXBlIjogImRhdGUiLAogICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHRyYW5zZmVyYWJsZSh3cmFwcGVkLnZhbHVlLnRvT2JqZWN0KCkpLAogICAgICAgICAgICAgICAgICAgICAgb3B0aW9uczogewogICAgICAgICAgICAgICAgICAgICAgICAgIHpvbmU6IHdyYXBwZWQudmFsdWUuem9uZS5lcXVhbHMoU3lzdGVtWm9uZS5pbnN0YW5jZSkgPyB1bmRlZmluZWQgOiB3cmFwcGVkLnZhbHVlLnpvbmVOYW1lLAogICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICBjYXNlICJkdXJhdGlvbiI6CiAgICAgICAgICAgICAgICAgIHJldHVybiB7ICJfX190cmFuc2Zlci10eXBlIjogImR1cmF0aW9uIiwgdmFsdWU6IHRyYW5zZmVyYWJsZSh3cmFwcGVkLnZhbHVlLnRvT2JqZWN0KCkpIH07CiAgICAgICAgICAgICAgY2FzZSAiYXJyYXkiOgogICAgICAgICAgICAgICAgICByZXR1cm4gd3JhcHBlZC52YWx1ZS5tYXAodiA9PiB0cmFuc2ZlcmFibGUodikpOwogICAgICAgICAgICAgIGNhc2UgImxpbmsiOgogICAgICAgICAgICAgICAgICByZXR1cm4geyAiX19fdHJhbnNmZXItdHlwZSI6ICJsaW5rIiwgdmFsdWU6IHRyYW5zZmVyYWJsZSh3cmFwcGVkLnZhbHVlLnRvT2JqZWN0KCkpIH07CiAgICAgICAgICAgICAgY2FzZSAib2JqZWN0IjoKICAgICAgICAgICAgICAgICAgbGV0IHJlc3VsdCA9IHt9OwogICAgICAgICAgICAgICAgICBmb3IgKGxldCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMod3JhcHBlZC52YWx1ZSkpCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRba2V5XSA9IHRyYW5zZmVyYWJsZSh2YWx1ZSk7CiAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgIH0KICAgICAgVHJhbnNmZXJhYmxlLnRyYW5zZmVyYWJsZSA9IHRyYW5zZmVyYWJsZTsKICAgICAgLyoqIENvbnZlcnQgYSB0cmFuc2ZlcmFibGUgdmFsdWUgYmFjayB0byBhIGxpdGVyYWwgdmFsdWUgd2UgY2FuIHdvcmsgd2l0aC4gKi8KICAgICAgZnVuY3Rpb24gdmFsdWUodHJhbnNmZXJhYmxlKSB7CiAgICAgICAgICBpZiAodHJhbnNmZXJhYmxlID09PSBudWxsKSB7CiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIGlmICh0cmFuc2ZlcmFibGUgPT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIGlmICh0cmFuc2ZlcmFibGUgaW5zdGFuY2VvZiBNYXApIHsKICAgICAgICAgICAgICBsZXQgcmVhbCA9IG5ldyBNYXAoKTsKICAgICAgICAgICAgICBmb3IgKGxldCBba2V5LCB2YWxdIG9mIHRyYW5zZmVyYWJsZS5lbnRyaWVzKCkpCiAgICAgICAgICAgICAgICAgIHJlYWwuc2V0KHZhbHVlKGtleSksIHZhbHVlKHZhbCkpOwogICAgICAgICAgICAgIHJldHVybiByZWFsOwogICAgICAgICAgfQogICAgICAgICAgZWxzZSBpZiAodHJhbnNmZXJhYmxlIGluc3RhbmNlb2YgU2V0KSB7CiAgICAgICAgICAgICAgbGV0IHJlYWwgPSBuZXcgU2V0KCk7CiAgICAgICAgICAgICAgZm9yIChsZXQgdmFsIG9mIHRyYW5zZmVyYWJsZSkKICAgICAgICAgICAgICAgICAgcmVhbC5hZGQodmFsdWUodmFsKSk7CiAgICAgICAgICAgICAgcmV0dXJuIHJlYWw7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlIGlmIChBcnJheS5pc0FycmF5KHRyYW5zZmVyYWJsZSkpIHsKICAgICAgICAgICAgICByZXR1cm4gdHJhbnNmZXJhYmxlLm1hcCh2ID0+IHZhbHVlKHYpKTsKICAgICAgICAgIH0KICAgICAgICAgIGVsc2UgaWYgKHR5cGVvZiB0cmFuc2ZlcmFibGUgPT09ICJvYmplY3QiKSB7CiAgICAgICAgICAgICAgaWYgKCJfX190cmFuc2Zlci10eXBlIiBpbiB0cmFuc2ZlcmFibGUpIHsKICAgICAgICAgICAgICAgICAgc3dpdGNoICh0cmFuc2ZlcmFibGVbIl9fX3RyYW5zZmVyLXR5cGUiXSkgewogICAgICAgICAgICAgICAgICAgICAgY2FzZSAiZGF0ZSI6CiAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGRhdGVPcHRzID0gdmFsdWUodHJhbnNmZXJhYmxlLm9wdGlvbnMpOwogICAgICAgICAgICAgICAgICAgICAgICAgIGxldCBkYXRlRGF0YSA9IHZhbHVlKHRyYW5zZmVyYWJsZS52YWx1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIERhdGVUaW1lLmZyb21PYmplY3QoZGF0ZURhdGEsIHsgem9uZTogZGF0ZU9wdHMuem9uZSB9KTsKICAgICAgICAgICAgICAgICAgICAgIGNhc2UgImR1cmF0aW9uIjoKICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gRHVyYXRpb24uZnJvbU9iamVjdCh2YWx1ZSh0cmFuc2ZlcmFibGUudmFsdWUpKTsKICAgICAgICAgICAgICAgICAgICAgIGNhc2UgImxpbmsiOgogICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBMaW5rLmZyb21PYmplY3QodmFsdWUodHJhbnNmZXJhYmxlLnZhbHVlKSk7CiAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGBVbnJlY29nbml6ZWQgdHJhbnNmZXIgdHlwZSAnJHt0cmFuc2ZlcmFibGVbIl9fX3RyYW5zZmVyLXR5cGUiXX0nYCk7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgbGV0IHJlc3VsdCA9IHt9OwogICAgICAgICAgICAgIGZvciAobGV0IFtrZXksIHZhbF0gb2YgT2JqZWN0LmVudHJpZXModHJhbnNmZXJhYmxlKSkKICAgICAgICAgICAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZSh2YWwpOwogICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdHJhbnNmZXJhYmxlOwogICAgICB9CiAgICAgIFRyYW5zZmVyYWJsZS52YWx1ZSA9IHZhbHVlOwogIH0pKFRyYW5zZmVyYWJsZSB8fCAoVHJhbnNmZXJhYmxlID0ge30pKTsKCiAgLyoqIEVudHJ5LXBvaW50IHNjcmlwdCB1c2VkIGJ5IHRoZSBpbmRleCBhcyBhIHdlYiB3b3JrZXIuICovCiAgLyoqIEFuIGltcG9ydCB3aGljaCBjYW4gZmFpbCBhbmQgcmFpc2UgYW4gZXhjZXB0aW9uLCB3aGljaCB3aWxsIGJlIGNhdWdodCBieSB0aGUgaGFuZGxlci4gKi8KICBmdW5jdGlvbiBmYWlsYWJsZUltcG9ydChwYXRoLCBjb250ZW50cywgc3RhdCwgbWV0YWRhdGEpIHsKICAgICAgaWYgKG1ldGFkYXRhID09PSB1bmRlZmluZWQgfHwgbWV0YWRhdGEgPT09IG51bGwpIHsKICAgICAgICAgIHRocm93IEVycm9yKGBDYW5ub3QgaW5kZXggZmlsZSwgc2luY2UgaXQgaGFzIG5vIE9ic2lkaWFuIGZpbGUgbWV0YWRhdGEuYCk7CiAgICAgIH0KICAgICAgcmV0dXJuIHJ1bkltcG9ydChwYXRoLCBjb250ZW50cywgc3RhdCwgbWV0YWRhdGEpOwogIH0KICBvbm1lc3NhZ2UgPSBhc3luYyAoZXZ0KSA9PiB7CiAgICAgIHRyeSB7CiAgICAgICAgICBsZXQgeyBwYXRoLCBjb250ZW50cywgc3RhdCwgbWV0YWRhdGEgfSA9IGV2dC5kYXRhOwogICAgICAgICAgbGV0IHJlc3VsdCA9IGZhaWxhYmxlSW1wb3J0KHBhdGgsIGNvbnRlbnRzLCBzdGF0LCBtZXRhZGF0YSk7CiAgICAgICAgICBwb3N0TWVzc2FnZSh7IHBhdGg6IGV2dC5kYXRhLnBhdGgsIHJlc3VsdDogVHJhbnNmZXJhYmxlLnRyYW5zZmVyYWJsZShyZXN1bHQpIH0pOwogICAgICB9CiAgICAgIGNhdGNoIChlcnJvcikgewogICAgICAgICAgY29uc29sZS5sb2coZXJyb3IpOwogICAgICAgICAgcG9zdE1lc3NhZ2UoewogICAgICAgICAgICAgIHBhdGg6IGV2dC5kYXRhLnBhdGgsCiAgICAgICAgICAgICAgcmVzdWx0OiB7CiAgICAgICAgICAgICAgICAgICRlcnJvcjogYEZhaWxlZCB0byBpbmRleCBmaWxlOiAke2V2dC5kYXRhLnBhdGh9OiAke2Vycm9yfWAsCiAgICAgICAgICAgICAgfSwKICAgICAgICAgIH0pOwogICAgICB9CiAgfTsKCn0pKCk7Cgo=', null, false);
- class FileImporter extends obsidian.Component {
- numWorkers;
- vault;
- metadataCache;
-
- workers;
-
- busy;
-
- reloadQueue;
-
- reloadSet;
-
- callbacks;
- constructor(numWorkers, vault, metadataCache) {
- super();
- this.numWorkers = numWorkers;
- this.vault = vault;
- this.metadataCache = metadataCache;
- this.workers = [];
- this.busy = [];
- this.reloadQueue = [];
- this.reloadSet = new Set();
- this.callbacks = new Map();
- for (let index = 0; index < numWorkers; index++) {
- let worker = new WorkerFactory({ name: "Dataview Indexer " + (index + 1) });
- worker.onmessage = evt => this.finish(evt.data.path, Transferable.value(evt.data.result), index);
- this.workers.push(worker);
- this.register(() => worker.terminate());
- this.busy.push(false);
- }
- }
-
- reload(file) {
- let promise = new Promise((resolve, reject) => {
- if (this.callbacks.has(file.path))
- this.callbacks.get(file.path)?.push([resolve, reject]);
- else
- this.callbacks.set(file.path, [[resolve, reject]]);
- });
-
- if (this.reloadSet.has(file.path))
- return promise;
- this.reloadSet.add(file.path);
-
- let workerId = this.nextAvailableWorker();
- if (workerId !== undefined) {
- this.send(file, workerId);
- }
- else {
- this.reloadQueue.push(file);
- }
- return promise;
- }
-
- finish(path, data, index) {
-
- let calls = [].concat(this.callbacks.get(path) ?? []);
-
- this.reloadSet.delete(path);
- this.callbacks.delete(path);
-
- this.busy[index] = false;
-
- let job = this.reloadQueue.shift();
- if (job !== undefined)
- this.send(job, index);
-
- if ("$error" in data) {
- for (let [_, reject] of calls)
- reject(data["$error"]);
- }
- else {
- for (let [callback, _] of calls)
- callback(data);
- }
- }
-
- send(file, workerId) {
- this.busy[workerId] = true;
- this.vault.cachedRead(file).then(c => this.workers[workerId].postMessage({
- path: file.path,
- contents: c,
- stat: file.stat,
- metadata: this.metadataCache.getFileCache(file),
- }));
- }
-
- nextAvailableWorker() {
- let index = this.busy.indexOf(false);
- return index == -1 ? undefined : index;
- }
- }
- class FullIndex extends obsidian.Component {
- app;
- indexVersion;
- onChange;
-
- static create(app, indexVersion, onChange) {
- return new FullIndex(app, indexVersion, onChange);
- }
-
- initialized;
-
- vault;
-
- metadataCache;
-
- persister;
-
- pages;
-
- tags;
-
- etags;
-
- links;
-
- prefix;
-
- starred;
-
-
- csv;
-
- revision;
-
- importer;
-
- constructor(app, indexVersion, onChange) {
- super();
- this.app = app;
- this.indexVersion = indexVersion;
- this.onChange = onChange;
- this.initialized = false;
- this.vault = app.vault;
- this.metadataCache = app.metadataCache;
- this.pages = new Map();
- this.tags = new ValueCaseInsensitiveIndexMap();
- this.etags = new ValueCaseInsensitiveIndexMap();
- this.links = new IndexMap();
- this.revision = 0;
-
- this.persister = new LocalStorageCache(app.appId || "shared", indexVersion);
-
- this.addChild((this.importer = new FileImporter(2, this.vault, this.metadataCache)));
-
- this.addChild((this.prefix = PrefixIndex.create(this.vault, () => this.touch())));
-
- this.addChild((this.csv = new CsvCache(this.vault)));
-
- this.addChild((this.starred = new StarredCache(this.app, () => this.touch())));
- }
-
- trigger(...args) {
- this.metadataCache.trigger("dataview:metadata-change", ...args);
- }
-
- touch() {
- this.revision += 1;
- this.onChange();
- }
-
- initialize() {
-
- this.registerEvent(this.metadataCache.on("resolve", file => this.reload(file)));
-
- this.registerEvent(this.vault.on("rename", this.rename, this));
-
- this.registerEvent(this.vault.on("delete", af => {
- if (!(af instanceof obsidian.TFile) || !PathFilters.markdown(af.path))
- return;
- let file = af;
- this.pages.delete(file.path);
- this.tags.delete(file.path);
- this.etags.delete(file.path);
- this.links.delete(file.path);
- this.touch();
- this.trigger("delete", file);
- }));
-
- this._initialize(this.vault.getMarkdownFiles());
- }
-
- async reinitialize() {
- await this.persister.recreate();
- const files = this.vault.getMarkdownFiles();
- const start = Date.now();
- let promises = files.map(file => this.reload(file));
- await Promise.all(promises);
- console.log(`Dataview: re-initialized index with ${files.length} files (${(Date.now() - start) / 1000.0}s)`);
- }
- /** Internal asynchronous initializer. */
- async _initialize(files) {
- let reloadStart = Date.now();
- let promises = files.map(l => this.reload(l));
- let results = await Promise.all(promises);
- let cached = 0, skipped = 0;
- for (let item of results) {
- if (item.skipped) {
- skipped += 1;
- continue;
- }
- if (item.cached)
- cached += 1;
- }
- this.initialized = true;
- this.metadataCache.trigger("dataview:index-ready");
- console.log(`Dataview: all ${files.length} files have been indexed in ${(Date.now() - reloadStart) / 1000.0}s (${cached} cached, ${skipped} skipped).`);
-
- let remaining = await this.persister.synchronize(files.map(l => l.path));
- if (remaining.size > 0) {
- console.log(`Dataview: Dropped cache entries for ${remaining.size} deleted files.`);
- }
- }
- rename(file, oldPath) {
- if (!(file instanceof obsidian.TFile) || !PathFilters.markdown(file.path))
- return;
- if (this.pages.has(oldPath)) {
- const oldMeta = this.pages.get(oldPath);
- this.pages.delete(oldPath);
- if (oldMeta) {
- oldMeta.path = file.path;
- this.pages.set(file.path, oldMeta);
- }
- }
- this.tags.rename(oldPath, file.path);
- this.links.rename(oldPath, file.path);
- this.etags.rename(oldPath, file.path);
- this.touch();
- this.trigger("rename", file, oldPath);
- }
-
- async reload(file) {
- if (!PathFilters.markdown(file.path))
- return { cached: false, skipped: true };
-
- if (this.pages.has(file.path) || this.initialized) {
- await this.import(file);
- return { cached: false, skipped: false };
- }
- else {
-
- return this.persister.loadFile(file.path).then(async (cached) => {
- if (!cached || cached.time < file.stat.mtime || cached.version != this.indexVersion) {
-
-
-
- let fileCache = this.metadataCache.getFileCache(file);
- if (fileCache === undefined || fileCache === null)
- return { cached: false, skipped: true };
- await this.import(file);
- return { cached: false, skipped: false };
- }
- else {
-
- this.finish(file, cached.data);
- return { cached: true, skipped: false };
- }
- });
- }
- }
-
- async import(file) {
- return this.importer.reload(file).then(r => {
- this.finish(file, r);
- this.persister.storeFile(file.path, r);
- });
- }
-
- finish(file, parsed) {
- let meta = PageMetadata.canonicalize(parsed, link => {
- let realPath = this.metadataCache.getFirstLinkpathDest(link.path, file.path);
- if (realPath)
- return link.withPath(realPath.path);
- else
- return link;
- });
- this.pages.set(file.path, meta);
- this.tags.set(file.path, meta.fullTags());
- this.etags.set(file.path, meta.tags);
- this.links.set(file.path, new Set(meta.links.map(l => l.path)));
- this.touch();
- this.trigger("update", file);
- }
- }
- class PrefixIndex extends obsidian.Component {
- vault;
- updateRevision;
- static create(vault, updateRevision) {
- return new PrefixIndex(vault, updateRevision);
- }
- constructor(vault, updateRevision) {
- super();
- this.vault = vault;
- this.updateRevision = updateRevision;
- }
- *walk(folder, filter) {
- for (const file of folder.children) {
- if (file instanceof obsidian.TFolder) {
- yield* this.walk(file, filter);
- }
- else if (filter ? filter(file.path) : true) {
- yield file.path;
- }
- }
- }
-
- get(prefix, filter) {
- let folder = this.vault.getAbstractFileByPath(prefix || "/");
- return new Set(folder instanceof obsidian.TFolder ? this.walk(folder, filter) : []);
- }
-
- pathExists(path) {
- return this.vault.getAbstractFileByPath(path || "/") != null;
- }
-
- nodeExists(prefix) {
- return this.vault.getAbstractFileByPath(prefix || "/") instanceof obsidian.TFolder;
- }
-
- resolveRelative(path, origin) {
- if (!origin)
- return path;
- else if (path.startsWith("/"))
- return path.substring(1);
- let relativePath = getParentFolder(origin) + "/" + path;
- if (this.pathExists(relativePath))
- return relativePath;
- else
- return path;
- }
- }
- var PathFilters;
- (function (PathFilters) {
- function csv(path) {
- return path.toLowerCase().endsWith(".csv");
- }
- PathFilters.csv = csv;
- function markdown(path) {
- let lcPath = path.toLowerCase();
- return lcPath.endsWith(".md") || lcPath.endsWith(".markdown");
- }
- PathFilters.markdown = markdown;
- })(PathFilters || (PathFilters = {}));
- class CsvCache extends obsidian.Component {
- vault;
- static CACHE_EXPIRY_SECONDS = 5 * 60;
-
- cache;
-
- cacheClearInterval;
- constructor(vault) {
- super();
- this.vault = vault;
- this.cache = new Map();
-
- this.registerEvent(this.vault.on("modify", file => {
- if (file instanceof obsidian.TFile && PathFilters.csv(file.path))
- this.cache.delete(file.path);
- }));
- this.registerEvent(this.vault.on("delete", file => {
- if (file instanceof obsidian.TFile && PathFilters.csv(file.path))
- this.cache.delete(file.path);
- }));
- }
-
- async get(path) {
-
- this.clearOldEntries();
- let existing = this.cache.get(path);
- if (existing)
- return Result.success(existing.data);
- else {
- let value = await this.loadInternal(path);
- if (value.successful)
- this.cache.set(path, { data: value.value, loadTime: DateTime.now() });
- return value;
- }
- }
-
- async loadInternal(path) {
-
- if (path.startsWith("http://") || path.startsWith("https://") || path.startsWith("file://")) {
- try {
- let result = await fetch(path, {
- method: "GET",
- mode: "no-cors",
- redirect: "follow",
- });
- return Result.success(parseCsv(await result.text()));
- }
- catch (ex) {
- return Result.failure("" + ex + "\n\n" + ex.stack);
- }
- }
-
- try {
- let fileData = await this.vault.adapter.read(path);
- return Result.success(parseCsv(fileData));
- }
- catch (ex) {
- return Result.failure(`Failed to load data from path '${path}'.`);
- }
- }
-
- clearOldEntries() {
- let currentTime = DateTime.now();
- let keysToRemove = new Set();
- for (let [key, value] of this.cache.entries()) {
- let entryAge = Math.abs(currentTime.diff(value.loadTime, "seconds").seconds);
- if (entryAge > CsvCache.CACHE_EXPIRY_SECONDS)
- keysToRemove.add(key);
- }
- keysToRemove.forEach(key => this.cache.delete(key));
- }
- }
- class StarredCache extends obsidian.Component {
- app;
- onUpdate;
-
- static INITIAL_DELAY = 4 * 1000;
-
- static REFRESH_INTERVAL = 30 * 1000;
-
- stars;
- constructor(app, onUpdate) {
- super();
- this.app = app;
- this.onUpdate = onUpdate;
- this.stars = StarredCache.fetch(this.app);
- this.registerInterval(window.setInterval(() => this.reload(), StarredCache.REFRESH_INTERVAL));
- const initialHandler = window.setTimeout(() => this.reload(), StarredCache.INITIAL_DELAY);
- this.register(() => window.clearTimeout(initialHandler));
- }
-
- starred(path) {
- return this.stars.has(path);
- }
- reload() {
- let newStars = StarredCache.fetch(this.app);
- if (!setsEqual(this.stars, newStars)) {
- this.stars = newStars;
- this.onUpdate();
- }
- }
-
- static fetch(app) {
- let items = app?.internalPlugins?.plugins?.bookmarks?.instance?.items;
- if (items == undefined)
- return new Set();
-
- const flattenItems = (items) => {
- let children = [];
- return items
- .map(i => {
- if (i.type == "group" && i.items && i.items.length) {
- children = [...children, ...i.items];
- }
- return i;
- })
- .concat(children.length ? flattenItems(children) : children);
- };
- items = flattenItems(items);
- return new Set(items.filter((l) => l.type === "file").map(l => l.path));
- }
- }
- class IndexMap {
-
- map;
-
- invMap;
-
- constructor() {
- this.map = new Map();
- this.invMap = new Map();
- }
-
- get(key) {
- let result = this.map.get(key);
- if (result) {
- return new Set(result);
- }
- else {
- return new Set();
- }
- }
-
- getInverse(value) {
- return this.invMap.get(value) || IndexMap.EMPTY_SET;
- }
-
- set(key, values) {
- if (!values.size) {
-
- this.delete(key);
- return this;
- }
- let oldValues = this.map.get(key);
- if (oldValues) {
- for (let value of oldValues) {
-
- if (!values.has(key))
- this.invMap.get(value)?.delete(key);
- }
- }
- this.map.set(key, values);
- for (let value of values) {
- if (!this.invMap.has(value))
- this.invMap.set(value, new Set([key]));
- else
- this.invMap.get(value)?.add(key);
- }
- return this;
- }
-
- delete(key) {
- let oldValues = this.map.get(key);
- if (!oldValues)
- return false;
- this.map.delete(key);
- for (let value of oldValues) {
- this.invMap.get(value)?.delete(key);
- }
- return true;
- }
-
- rename(oldKey, newKey) {
- let oldValues = this.map.get(oldKey);
- if (!oldValues)
- return false;
- this.delete(oldKey);
- this.set(newKey, oldValues);
- return true;
- }
-
- clear() {
- this.map.clear();
- this.invMap.clear();
- }
- static EMPTY_SET = Object.freeze(new Set());
- }
- class ValueCaseInsensitiveIndexMap {
- delegate;
-
- constructor(delegate = new IndexMap()) {
- this.delegate = delegate;
- }
-
- get(key) {
- return this.delegate.get(key);
- }
-
- getInverse(value) {
- return this.delegate.getInverse(value.toLocaleLowerCase());
- }
-
- set(key, values) {
- this.delegate.set(key, new Set(Array.from(values).map(v => v.toLocaleLowerCase())));
- return this;
- }
-
- delete(key) {
- return this.delegate.delete(key);
- }
-
- rename(oldKey, newKey) {
- return this.delegate.rename(oldKey, newKey);
- }
-
- clear() {
- this.delegate.clear();
- }
- }
- function matchingSourcePaths(source, index, originFile = "") {
- switch (source.type) {
- case "empty":
- return Result.success(new Set());
- case "tag":
- return Result.success(index.tags.getInverse(source.tag));
- case "csv":
- return Result.success(new Set([index.prefix.resolveRelative(source.path, originFile)]));
- case "folder":
-
- if (index.prefix.nodeExists(source.folder))
- return Result.success(index.prefix.get(source.folder, PathFilters.markdown));
-
- if (index.prefix.pathExists(source.folder))
- return Result.success(new Set([source.folder]));
- else if (index.prefix.pathExists(source.folder + ".md"))
- return Result.success(new Set([source.folder + ".md"]));
-
- return Result.success(new Set());
- case "link":
- let fullPath = index.metadataCache.getFirstLinkpathDest(source.file, originFile)?.path;
- if (!fullPath) {
-
- return Result.success(index.links.getInverse(source.file));
- }
- if (source.direction === "incoming") {
-
-
- let resolved = index.metadataCache.resolvedLinks;
- let incoming = new Set();
- for (let [key, value] of Object.entries(resolved)) {
- if (fullPath in value)
- incoming.add(key);
- }
- return Result.success(incoming);
- }
- else {
- let resolved = index.metadataCache.resolvedLinks;
- if (!(fullPath in resolved))
- return Result.failure(`Could not find file "${source.file}" during link lookup - does it exist?`);
- return Result.success(new Set(Object.keys(index.metadataCache.resolvedLinks[fullPath])));
- }
- case "binaryop":
- return Result.flatMap2(matchingSourcePaths(source.left, index, originFile), matchingSourcePaths(source.right, index, originFile), (left, right) => {
- if (source.op == "&") {
- let result = new Set();
- for (let elem of right) {
- if (left.has(elem))
- result.add(elem);
- }
- return Result.success(result);
- }
- else if (source.op == "|") {
- let result = new Set(left);
- for (let elem of right)
- result.add(elem);
- return Result.success(result);
- }
- else {
- return Result.failure(`Unrecognized operator '${source.op}'.`);
- }
- });
- case "negate":
- return matchingSourcePaths(source.child, index, originFile).map(child => {
-
-
- let allFiles = new Set(index.vault.getMarkdownFiles().map(f => f.path));
- child.forEach(f => allFiles.delete(f));
- return allFiles;
- });
- }
- }
- async function resolvePathData(path, index) {
- if (PathFilters.csv(path))
- return resolveCsvData(path, index);
- else
- return resolveMarkdownData(path, index);
- }
- async function resolveCsvData(path, index) {
- let rawData = await index.csv.get(path);
- return rawData.map(rows => {
- return rows.map((row, index) => {
- return {
- id: `${path}#${index}`,
- data: row,
- };
- });
- });
- }
- function resolveMarkdownData(path, index) {
- let page = index.pages.get(path);
- if (!page)
- return Result.success([]);
- return Result.success([
- {
- id: Link.file(path),
- data: page.serialize(index),
- },
- ]);
- }
- async function resolveSource(source, index, originFile = "") {
- let paths = matchingSourcePaths(source, index, originFile);
- if (!paths.successful)
- return Result.failure(paths.error);
- let result = [];
- for (let path of paths.value) {
- let resolved = await resolvePathData(path, index);
- if (!resolved.successful)
- return resolved;
- for (let val of resolved.value)
- result.push(val);
- }
- return Result.success(result);
- }
- function cyrb53(str, seed = 0) {
- let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
- for (let i = 0, ch; i < str.length; i++) {
- ch = str.charCodeAt(i);
- h1 = Math.imul(h1 ^ ch, 2654435761);
- h2 = Math.imul(h2 ^ ch, 1597334677);
- }
- h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
- h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
- h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
- h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
-
-
- return 4294967296 * (2097151 & h2) + (h1 >>> 0);
- }
- class FunctionBuilder {
- name;
- variants;
- vectorized;
- constructor(name) {
- this.name = name;
- this.variants = [];
- this.vectorized = {};
- }
-
- vararg(impl) {
- this.variants.push({ args: [], varargs: true, impl });
- return this;
- }
-
- add1(argType, impl) {
- this.variants.push({
- args: [argType],
- varargs: false,
- impl: (c, ...rest) => impl(rest[0], c),
- });
- return this;
- }
-
- add2(arg1, arg2, impl) {
- this.variants.push({
- args: [arg1, arg2],
- varargs: false,
- impl: (c, ...rest) => impl(rest[0], rest[1], c),
- });
- return this;
- }
-
- add3(arg1, arg2, arg3, impl) {
- this.variants.push({
- args: [arg1, arg2, arg3],
- varargs: false,
- impl: (c, ...rest) => impl(rest[0], rest[1], rest[2], c),
- });
- return this;
- }
-
- vectorize(numArgs, positions) {
- this.vectorized[numArgs] = positions;
- return this;
- }
-
- build() {
- let self = (context, ...args) => {
- let types = [];
- for (let arg of args) {
- let argType = Values.typeOf(arg);
- if (!argType)
- throw Error(`Unrecognized argument type for argument '${arg}'`);
- types.push(argType);
- }
-
- if (this.vectorized[types.length]) {
- let vectorizedPositions = this.vectorized[types.length].filter(k => types[k] == "array");
- if (vectorizedPositions.length > 0) {
- let minLength = vectorizedPositions
- .map(p => args[p].length)
- .reduce((p, c) => Math.min(p, c));
-
-
-
- let result = [];
- for (let vpos = 0; vpos < minLength; vpos++) {
- let subargs = [];
- for (let index = 0; index < args.length; index++) {
- if (vectorizedPositions.includes(index)) {
- let arr = args[index];
- subargs.push(arr[vpos]);
- }
- else {
- subargs.push(args[index]);
- }
- }
- result.push(self(context, ...subargs));
- }
- return result;
- }
- }
- outer: for (let variant of this.variants) {
- if (variant.varargs)
- return variant.impl(context, ...args);
- if (variant.args.length != types.length)
- continue;
- for (let index = 0; index < variant.args.length; index++) {
- if (variant.args[index] != "*" && variant.args[index] != types[index])
- continue outer;
- }
- return variant.impl(context, ...args);
- }
- throw Error(`No implementation of '${this.name}' found for arguments: ${types.join(", ")}`);
- };
- return self;
- }
- }
- var Functions;
- (function (Functions) {
-
- function bind(func, context) {
- return (...args) => func(context, ...args);
- }
- Functions.bind = bind;
-
- function bindAll(funcs, context) {
- let result = {};
- for (let [key, func] of Object.entries(funcs)) {
- result[key] = Functions.bind(func, context);
- }
- return result;
- }
- Functions.bindAll = bindAll;
- })(Functions || (Functions = {}));
- var DefaultFunctions;
- (function (DefaultFunctions) {
- DefaultFunctions.typeOf = new FunctionBuilder("type")
- .add1("array", _ => "array")
- .add1("boolean", _ => "boolean")
- .add1("date", _ => "date")
- .add1("duration", _ => "duration")
- .add1("function", _ => "function")
- .add1("widget", _ => "widget")
- .add1("link", _ => "link")
- .add1("null", _ => "null")
- .add1("number", _ => "number")
- .add1("object", _ => "object")
- .add1("string", _ => "string")
- .add1("*", _ => "unknown")
- .build();
-
- DefaultFunctions.length = new FunctionBuilder("length")
- .add1("array", a => a.length)
- .add1("object", a => Object.keys(a).length)
- .add1("string", a => a.length)
- .add1("null", _a => 0)
- .build();
-
- DefaultFunctions.list = (_context, ...args) => args;
-
- DefaultFunctions.object = (_context, ...args) => {
- if (args.length % 2 != 0)
- throw Error("object() requires an even number of arguments");
- let result = {};
- for (let index = 0; index < args.length; index += 2) {
- let key = args[index];
- if (!Values.isString(key))
- throw Error("keys should be of type string for object(key1, value1, ...)");
- result[key] = args[index + 1];
- }
- return result;
- };
-
- DefaultFunctions.link = new FunctionBuilder("link")
- .add1("string", (a, c) => Link.file(c.linkHandler.normalize(a), false))
- .add1("link", a => a)
- .add1("null", _a => null)
- .vectorize(1, [0])
- .add2("string", "string", (t, d, c) => Link.file(c.linkHandler.normalize(t), false, d))
- .add3("string", "string", "boolean", (t, d, e, c) => Link.file(c.linkHandler.normalize(t), e, d))
- .add2("link", "string", (t, d) => t.withDisplay(d))
- .add2("null", "*", () => null)
- .add2("*", "null", (t, _n, c) => DefaultFunctions.link(c, t))
- .vectorize(2, [0, 1])
- .build();
-
- DefaultFunctions.embed = new FunctionBuilder("embed")
- .add1("link", l => l.toEmbed())
- .vectorize(1, [0])
- .add2("link", "boolean", (l, e, c) => (e ? l.toEmbed() : l.fromEmbed()))
- .add1("null", () => null)
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .vectorize(2, [0, 1])
- .build();
-
- DefaultFunctions.elink = new FunctionBuilder("elink")
- .add2("string", "string", (a, d) => Widgets.externalLink(a, d))
- .add2("string", "null", (s, _n, c) => DefaultFunctions.elink(c, s, s))
- .add2("null", "*", () => null)
- .vectorize(2, [0])
- .add1("string", (a, c) => DefaultFunctions.elink(c, a, a))
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
-
- DefaultFunctions.date = new FunctionBuilder("date")
- .add1("string", str => {
- let parsedDate = EXPRESSION.datePlus.parse(str);
- if (parsedDate.status)
- return parsedDate.value;
- else
- return null;
- })
- .add1("date", d => d)
- .add1("link", (link, c) => {
-
- if (link.display) {
- let parsedDate = EXPRESSION.date.parse(link.display);
- if (parsedDate.status)
- return parsedDate.value;
- }
-
- let parsedDate = EXPRESSION.date.parse(link.path);
- if (parsedDate.status)
- return parsedDate.value;
-
- let resolved = c.linkHandler.resolve(link.path);
- if (resolved && resolved?.file?.day) {
- return resolved?.file?.day;
- }
- return null;
- })
- .add2("string", "string", (d, f) => {
- if (f === "x" || f === "X") {
- let match = NUMBER_REGEX.exec(d);
- if (match)
- return DateTime.fromMillis(Number.parseInt(match[0]) * (f === "X" ? 1000 : 1));
- else {
- throw Error("Not a number for format( (${ f }): ${ d }");
- }
- }
- else {
- let parsedDate = DateTime.fromFormat(d, f);
- if (parsedDate.isValid)
- return parsedDate;
- else {
- throw Error(`Can't handle format (${f}) on date string (${d})`);
- }
- }
- })
- .add2("null", "string", () => null)
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
-
- DefaultFunctions.dur = new FunctionBuilder("dur")
- .add1("string", str => {
- let parsedDur = EXPRESSION.duration.parse(str.trim());
- if (parsedDur.status)
- return parsedDur.value;
- else
- return null;
- })
- .add1("duration", d => d)
- .add1("null", d => d)
- .vectorize(1, [0])
- .build();
-
- DefaultFunctions.dateformat = new FunctionBuilder("dateformat")
- .add2("date", "string", (date, format) => date.toFormat(format, { locale: currentLocale() }))
- .add2("null", "string", (_nul, _format) => null)
- .vectorize(2, [0])
- .build();
- DefaultFunctions.durationformat = new FunctionBuilder("durationformat")
- .add2("duration", "string", (dur, format) => dur.toFormat(format))
- .add2("null", "string", (_nul, _format) => null)
- .vectorize(2, [0])
- .build();
- DefaultFunctions.localtime = new FunctionBuilder("localtime")
- .add1("date", d => d.toLocal())
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
- const NUMBER_REGEX = /-?[0-9]+(\.[0-9]+)?/;
-
- DefaultFunctions.number = new FunctionBuilder("number")
- .add1("number", a => a)
- .add1("string", str => {
- let match = NUMBER_REGEX.exec(str);
- if (match)
- return Number.parseFloat(match[0]);
- else
- return null;
- })
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
-
- DefaultFunctions.currencyformat = new FunctionBuilder("currencyformat")
- .add2("number", "string", (num, format) => Intl.NumberFormat(currentLocale(), { style: "currency", currency: format }).format(num))
- .add2("null", "string", (_nul, _format) => null)
- .add1("number", num => Intl.NumberFormat(currentLocale(), { style: "currency", currency: "USD" }).format(num))
- .add1("null", () => null)
- .vectorize(2, [0])
- .build();
-
- DefaultFunctions.string = new FunctionBuilder("string").add1("*", (a, ctx) => Values.toString(a, ctx.settings)).build();
- DefaultFunctions.round = new FunctionBuilder("round")
- .add1("number", n => Math.round(n))
- .add1("null", () => null)
- .vectorize(1, [0])
- .add2("number", "number", (n, p) => {
- if (p <= 0)
- return Math.round(n);
- return parseFloat(n.toFixed(p));
- })
- .add2("number", "null", n => Math.round(n))
- .add2("null", "*", () => null)
- .vectorize(2, [0])
- .build();
- DefaultFunctions.trunc = new FunctionBuilder("trunc")
- .add1("number", n => Math.trunc(n))
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
- DefaultFunctions.floor = new FunctionBuilder("floor")
- .add1("number", n => Math.floor(n))
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
- DefaultFunctions.ceil = new FunctionBuilder("ceil")
- .add1("number", n => Math.ceil(n))
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
- DefaultFunctions.min = new FunctionBuilder("min")
- .add2("*", "null", (a, _n) => a)
- .add2("null", "*", (_n, a) => a)
- .add2("*", "*", (a, b, ctx) => (Values.compareValue(a, b, ctx.linkHandler.normalize) <= 0 ? a : b))
- .add1("array", (a, ctx) => DefaultFunctions.min(ctx, ...a))
- .vararg((ctx, ...args) => (args.length == 0 ? null : args.reduce((p, c) => DefaultFunctions.min(ctx, p, c))))
- .build();
- DefaultFunctions.max = new FunctionBuilder("max")
- .add2("*", "null", (a, _n) => a)
- .add2("null", "*", (_n, a) => a)
- .add2("*", "*", (a, b, ctx) => (Values.compareValue(a, b, ctx.linkHandler.normalize) > 0 ? a : b))
- .add1("array", (a, ctx) => DefaultFunctions.max(ctx, ...a))
- .vararg((ctx, ...args) => (args.length == 0 ? null : args.reduce((p, c) => DefaultFunctions.max(ctx, p, c))))
- .build();
- DefaultFunctions.minby = new FunctionBuilder("minby")
- .add2("array", "function", (arr, func, ctx) => {
- if (arr.length == 0)
- return null;
- let values = arr.map(v => {
- return { value: v, mapped: func(ctx, v) };
- });
- let filtered = values.filter(v => !Values.isNull(v.mapped));
- if (filtered.length == 0)
- return arr[0];
- return filtered.reduce((p, c) => {
- if (Values.compareValue(p.mapped, c.mapped, ctx.linkHandler.normalize) <= 0)
- return p;
- else
- return c;
- }).value;
- })
- .add2("null", "function", (_arr, _func, _ctx) => null)
- .build();
- DefaultFunctions.maxby = new FunctionBuilder("maxby")
- .add2("array", "function", (arr, func, ctx) => {
- if (arr.length == 0)
- return null;
- let values = arr.map(v => {
- return { value: v, mapped: func(ctx, v) };
- });
- let filtered = values.filter(v => !Values.isNull(v.mapped));
- if (filtered.length == 0)
- return arr[0];
- return filtered.reduce((p, c) => {
- if (Values.compareValue(p.mapped, c.mapped, ctx.linkHandler.normalize) > 0)
- return p;
- else
- return c;
- }).value;
- })
- .add2("null", "function", (_arr, _func, _ctx) => null)
- .build();
- DefaultFunctions.striptime = new FunctionBuilder("striptime")
- .add1("date", d => DateTime.fromObject({ year: d.year, month: d.month, day: d.day }))
- .add1("null", _n => null)
- .vectorize(1, [0])
- .build();
-
- DefaultFunctions.contains = new FunctionBuilder("contains")
- .add2("array", "*", (l, elem, context) => l.some(e => DefaultFunctions.contains(context, e, elem)))
- .add2("string", "string", (haystack, needle) => haystack.includes(needle))
- .add2("object", "string", (obj, key) => key in obj)
- .add2("*", "*", (elem1, elem2, context) => context.evaluate(Fields.binaryOp(Fields.literal(elem1), "=", Fields.literal(elem2))).orElseThrow())
- .vectorize(2, [1])
- .build();
-
- DefaultFunctions.icontains = new FunctionBuilder("icontains")
- .add2("array", "*", (l, elem, context) => l.some(e => DefaultFunctions.icontains(context, e, elem)))
- .add2("string", "string", (haystack, needle) => haystack.toLocaleLowerCase().includes(needle.toLocaleLowerCase()))
- .add2("object", "string", (obj, key) => key in obj)
- .add2("*", "*", (elem1, elem2, context) => context.evaluate(Fields.binaryOp(Fields.literal(elem1), "=", Fields.literal(elem2))).orElseThrow())
- .vectorize(2, [1])
- .build();
-
- DefaultFunctions.econtains = new FunctionBuilder("econtains")
- .add2("array", "*", (l, elem, context) => l.some(e => context.evaluate(Fields.binaryOp(Fields.literal(elem), "=", Fields.literal(e))).orElseThrow()))
- .add2("string", "string", (haystack, needle) => haystack.includes(needle))
- .add2("object", "string", (obj, key) => key in obj)
- .add2("*", "*", (elem1, elem2, context) => context.evaluate(Fields.binaryOp(Fields.literal(elem1), "=", Fields.literal(elem2))).orElseThrow())
- .vectorize(2, [1])
- .build();
-
- DefaultFunctions.containsword = new FunctionBuilder("containsword")
- .add2("string", "string", (hay, needle) => !!hay.match(new RegExp(".*\\b" + escapeRegex(needle) + "\\b.*", "i")))
- .add2("null", "*", (_a, _b) => null)
- .add2("*", "null", (_a, _b) => null)
- .vectorize(2, [0, 1])
- .build();
-
- DefaultFunctions.extract = (context, ...args) => {
- if (args.length == 0)
- return "extract(object, key1, ...) requires at least 1 argument";
-
- let object = args[0];
- if (Values.isArray(object))
- return object.map(v => DefaultFunctions.extract(context, v, ...args.slice(1)));
- let result = {};
- for (let index = 1; index < args.length; index++) {
- let key = args[index];
- if (!Values.isString(key))
- throw Error("extract(object, key1, ...) must be called with string keys");
- result[key] = context.evaluate(Fields.index(Fields.literal(object), Fields.literal(key))).orElseThrow();
- }
- return result;
- };
-
- DefaultFunctions.reverse = new FunctionBuilder("reverse")
- .add1("array", l => {
- let result = [];
- for (let index = l.length - 1; index >= 0; index--)
- result.push(l[index]);
- return result;
- })
- .add1("string", l => {
- let result = "";
- for (let c = 0; c < l.length; c++)
- result += l[l.length - c - 1];
- return result;
- })
- .add1("*", e => e)
- .build();
-
- DefaultFunctions.sort = new FunctionBuilder("sort")
- .add1("array", (list, context) => DefaultFunctions.sort(context, list, (_ctx, a) => a))
- .add2("array", "function", (list, key, context) => {
- let result = [].concat(list);
- result.sort((a, b) => {
- let akey = key(context, a);
- let bkey = key(context, b);
- let le = context
- .evaluate(Fields.binaryOp(Fields.literal(akey), "<", Fields.literal(bkey)))
- .orElseThrow();
- if (Values.isTruthy(le))
- return -1;
- let eq = context
- .evaluate(Fields.binaryOp(Fields.literal(akey), "=", Fields.literal(bkey)))
- .orElseThrow();
- if (Values.isTruthy(eq))
- return 0;
- return 1;
- });
- return result;
- })
- .add1("*", e => e)
- .build();
- DefaultFunctions.regextest = new FunctionBuilder("regextest")
- .add2("string", "string", (pattern, field) => RegExp(pattern).test(field))
- .add2("null", "*", (_n, _a) => false)
- .add2("*", "null", (_a, _n) => false)
- .vectorize(2, [0, 1])
- .build();
- DefaultFunctions.regexmatch = new FunctionBuilder("regexmatch")
- .add2("string", "string", (pattern, field) => {
- if (!pattern.startsWith("^") && !pattern.endsWith("$"))
- pattern = "^" + pattern + "$";
- return !!field.match(pattern);
- })
- .add2("null", "*", (_n, _a) => false)
- .add2("*", "null", (_a, _n) => false)
- .vectorize(2, [0, 1])
- .build();
- DefaultFunctions.regexreplace = new FunctionBuilder("regexreplace")
- .add3("string", "string", "string", (field, pat, rep) => {
- try {
- let reg = new RegExp(pat, "g");
- return field.replace(reg, rep);
- }
- catch (ex) {
- throw Error(`Invalid regexp '${pat}' in regexreplace`);
- }
- })
- .add3("null", "*", "*", () => null)
- .add3("*", "null", "*", () => null)
- .add3("*", "*", "null", () => null)
- .vectorize(3, [0, 1, 2])
- .build();
- DefaultFunctions.lower = new FunctionBuilder("lower")
- .add1("string", s => s.toLocaleLowerCase())
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
- DefaultFunctions.upper = new FunctionBuilder("upper")
- .add1("string", s => s.toLocaleUpperCase())
- .add1("null", () => null)
- .vectorize(1, [0])
- .build();
- DefaultFunctions.replace = new FunctionBuilder("replace")
- .add3("string", "string", "string", (str, pat, repr) => str.split(pat).join(repr))
- .add3("null", "*", "*", () => null)
- .add3("*", "null", "*", () => null)
- .add3("*", "*", "null", () => null)
- .vectorize(3, [0, 1, 2])
- .build();
-
- const splitImpl = (str, delim, limit) => str.split(new RegExp(delim), limit).map(str => str || "");
-
- DefaultFunctions.split = new FunctionBuilder("split")
- .add2("string", "string", (string, splitter) => splitImpl(string, splitter))
- .add3("string", "string", "number", (string, splitter, limit) => splitImpl(string, splitter, limit))
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .add3("*", "*", "null", () => null)
- .add3("*", "null", "*", () => null)
- .add3("null", "*", "*", () => null)
- .build();
- DefaultFunctions.startswith = new FunctionBuilder("startswith")
- .add2("string", "string", (str, starting) => str.startsWith(starting))
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .vectorize(2, [0, 1])
- .build();
- DefaultFunctions.endswith = new FunctionBuilder("endswith")
- .add2("string", "string", (str, ending) => str.endsWith(ending))
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .vectorize(2, [0, 1])
- .build();
- DefaultFunctions.padleft = new FunctionBuilder("padleft")
- .add2("string", "number", (str, len) => str.padStart(len, " "))
- .add3("string", "number", "string", (str, len, padding) => str.padStart(len, padding))
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .add3("null", "*", "*", () => null)
- .add3("*", "null", "*", () => null)
- .add3("*", "*", "null", () => null)
- .vectorize(2, [0, 1])
- .vectorize(3, [0, 1, 2])
- .build();
- DefaultFunctions.padright = new FunctionBuilder("padright")
- .add2("string", "number", (str, len) => str.padEnd(len, " "))
- .add3("string", "number", "string", (str, len, padding) => str.padEnd(len, padding))
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .add3("null", "*", "*", () => null)
- .add3("*", "null", "*", () => null)
- .add3("*", "*", "null", () => null)
- .vectorize(2, [0, 1])
- .vectorize(3, [0, 1, 2])
- .build();
- DefaultFunctions.substring = new FunctionBuilder("substring")
- .add2("string", "number", (str, start) => str.substring(start))
- .add3("string", "number", "number", (str, start, end) => str.substring(start, end))
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .add3("null", "*", "*", () => null)
- .add3("*", "null", "*", () => null)
- .add3("*", "*", "null", () => null)
- .vectorize(2, [0, 1])
- .vectorize(3, [0, 1, 2])
- .build();
- DefaultFunctions.truncate = new FunctionBuilder("truncate")
- .add3("string", "number", "string", (str, length, suffix) => {
- if (str.length > length - suffix.length) {
- return str.substring(0, Math.max(0, length - suffix.length)) + suffix;
- }
- else {
- return str;
- }
- })
- .add2("string", "number", (str, length, ctx) => DefaultFunctions.truncate(ctx, str, length, "..."))
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .add3("null", "*", "*", () => null)
- .add3("*", "null", "*", () => null)
- .add3("*", "*", "null", () => null)
- .vectorize(2, [0, 1])
- .vectorize(3, [0, 1, 2])
- .build();
- DefaultFunctions.fdefault = new FunctionBuilder("default")
- .add2("*", "*", (v, bk) => (Values.isNull(v) ? bk : v))
- .vectorize(2, [0, 1])
- .build();
- DefaultFunctions.ldefault = new FunctionBuilder("ldefault")
- .add2("*", "*", (v, bk) => (Values.isNull(v) ? bk : v))
- .build();
- DefaultFunctions.choice = new FunctionBuilder("choice")
- .add3("*", "*", "*", (b, left, right) => (Values.isTruthy(b) ? left : right))
- .vectorize(3, [0])
- .build();
- DefaultFunctions.hash = new FunctionBuilder("hash")
- .add2("string", "number", (seed, variant) => {
- return cyrb53(seed, variant);
- })
- .add2("string", "string", (seed, text) => {
- return cyrb53(seed + text);
- })
- .add3("string", "string", "number", (seed, text, variant) => {
- return cyrb53(seed + text, variant);
- })
- .build();
- DefaultFunctions.reduce = new FunctionBuilder("reduce")
- .add2("array", "string", (lis, op, context) => {
- if (lis.length == 0)
- return null;
- if (op != "+" && op != "-" && op != "*" && op != "/" && op != "&" && op != "|")
- throw Error("reduce(array, op) supports '+', '-', '/', '*', '&', and '|'");
- let value = lis[0];
- for (let index = 1; index < lis.length; index++) {
- value = context
- .evaluate(Fields.binaryOp(Fields.literal(value), op, Fields.literal(lis[index])))
- .orElseThrow();
- }
- return value;
- })
- .add2("array", "function", (lis, op, context) => {
- if (lis.length == 0)
- return null;
- let value = lis[0];
- for (let index = 1; index < lis.length; index++) {
-
- if (Values.isNull(lis[index]))
- continue;
- value = op(context, value, lis[index]);
- }
- return value;
- })
- .add2("null", "*", () => null)
- .add2("*", "null", () => null)
- .vectorize(2, [1])
- .build();
- DefaultFunctions.sum = new FunctionBuilder("sum")
- .add1("array", (arr, c) => DefaultFunctions.reduce(c, arr, "+"))
- .add1("*", e => e)
- .build();
- DefaultFunctions.average = new FunctionBuilder("average")
- .add1("array", (array, context) => {
- if (array.length == 0)
- return null;
- const add = DefaultFunctions.sum(context, array);
- if (add == null || add == undefined)
- return null;
- return context
- .evaluate(Fields.binaryOp(Fields.literal(add), "/", Fields.literal(array.length)))
- .orElseThrow();
- })
- .add1("*", e => e)
- .build();
- DefaultFunctions.product = new FunctionBuilder("product")
- .add1("array", (arr, c) => DefaultFunctions.reduce(c, arr, "*"))
- .add1("*", e => e)
- .build();
- DefaultFunctions.join = new FunctionBuilder("join")
- .add2("array", "string", (arr, sep, ctx) => arr.map(e => Values.toString(e, ctx.settings)).join(sep))
- .add2("array", "null", (arr, _s, context) => DefaultFunctions.join(context, arr, ", "))
- .add2("*", "string", (elem, sep, ctx) => Values.toString(elem, ctx.settings))
- .add1("array", (arr, context) => DefaultFunctions.join(context, arr, ", "))
- .add1("*", (e, ctx) => Values.toString(e, ctx.settings))
- .vectorize(2, [1])
- .build();
- DefaultFunctions.any = new FunctionBuilder("any")
- .add1("array", arr => arr.some(v => Values.isTruthy(v)))
- .add2("array", "function", (arr, f, ctx) => arr.some(v => Values.isTruthy(f(ctx, v))))
- .vararg((_ctx, ...args) => args.some(v => Values.isTruthy(v)))
- .build();
- DefaultFunctions.all = new FunctionBuilder("all")
- .add1("array", arr => arr.every(v => Values.isTruthy(v)))
- .add2("array", "function", (arr, f, ctx) => arr.every(v => Values.isTruthy(f(ctx, v))))
- .vararg((_ctx, ...args) => args.every(v => Values.isTruthy(v)))
- .build();
- DefaultFunctions.none = new FunctionBuilder("all")
- .add1("array", arr => !arr.some(v => Values.isTruthy(v)))
- .add2("array", "function", (arr, f, ctx) => !arr.some(v => Values.isTruthy(f(ctx, v))))
- .vararg((_ctx, ...args) => !args.some(v => Values.isTruthy(v)))
- .build();
- DefaultFunctions.filter = new FunctionBuilder("filter")
- .add2("array", "function", (arr, f, ctx) => arr.filter(v => Values.isTruthy(f(ctx, v))))
- .add2("null", "*", () => null)
- .build();
- DefaultFunctions.unique = new FunctionBuilder("unique")
- .add1("array", (arr, ctx) => DataArray.wrap(arr, ctx.settings).distinct().array())
- .add1("null", () => null)
- .build();
- DefaultFunctions.map = new FunctionBuilder("map")
- .add2("array", "function", (arr, f, ctx) => arr.map(v => f(ctx, v)))
- .add2("null", "*", () => null)
- .build();
- DefaultFunctions.nonnull = new FunctionBuilder("nonnull")
- .add1("array", arr => arr.filter(v => Values.typeOf(v) != "null"))
- .vararg((_ctx, ...args) => args.filter(v => Values.typeOf(v) != "null"))
- .build();
-
- DefaultFunctions.meta = new FunctionBuilder("meta")
- .add1("link", link => ({
- display: link.display ?? null,
- embed: link.embed,
- path: link.path,
- subpath: link.subpath ?? null,
- type: link.type,
- }))
- .build();
-
- DefaultFunctions.flat = new FunctionBuilder("flat")
- .add1("array", a => {
- return a.flat();
- })
- .add2("array", "number", (a, n) => {
-
- return a.flat(n);
- })
- .add1("null", () => null)
- .build();
-
- DefaultFunctions.slice = new FunctionBuilder("slice")
- .add1("array", a => {
- return a.slice();
- })
- .add2("array", "number", (a, start) => {
- return a.slice(start);
- })
- .add3("array", "number", "number", (a, start, end) => {
- return a.slice(start, end);
- })
- .add1("null", () => null)
- .build();
- })(DefaultFunctions || (DefaultFunctions = {}));
- const DEFAULT_FUNCTIONS = {
-
- object: DefaultFunctions.object,
- list: DefaultFunctions.list,
- array: DefaultFunctions.list,
- date: DefaultFunctions.date,
- dur: DefaultFunctions.dur,
- number: DefaultFunctions.number,
- string: DefaultFunctions.string,
- link: DefaultFunctions.link,
- embed: DefaultFunctions.embed,
- elink: DefaultFunctions.elink,
- typeof: DefaultFunctions.typeOf,
-
- round: DefaultFunctions.round,
- trunc: DefaultFunctions.trunc,
- floor: DefaultFunctions.floor,
- ceil: DefaultFunctions.ceil,
- min: DefaultFunctions.min,
- max: DefaultFunctions.max,
- sum: DefaultFunctions.sum,
- product: DefaultFunctions.product,
- average: DefaultFunctions.average,
- minby: DefaultFunctions.minby,
- maxby: DefaultFunctions.maxby,
-
- contains: DefaultFunctions.contains,
- icontains: DefaultFunctions.icontains,
- econtains: DefaultFunctions.econtains,
- containsword: DefaultFunctions.containsword,
- extract: DefaultFunctions.extract,
- sort: DefaultFunctions.sort,
- reverse: DefaultFunctions.reverse,
- length: DefaultFunctions.length,
- nonnull: DefaultFunctions.nonnull,
- all: DefaultFunctions.all,
- any: DefaultFunctions.any,
- none: DefaultFunctions.none,
- join: DefaultFunctions.join,
- filter: DefaultFunctions.filter,
- map: DefaultFunctions.map,
- flat: DefaultFunctions.flat,
- slice: DefaultFunctions.slice,
- unique: DefaultFunctions.unique,
- reduce: DefaultFunctions.reduce,
-
- regextest: DefaultFunctions.regextest,
- regexmatch: DefaultFunctions.regexmatch,
- regexreplace: DefaultFunctions.regexreplace,
- replace: DefaultFunctions.replace,
- lower: DefaultFunctions.lower,
- upper: DefaultFunctions.upper,
- split: DefaultFunctions.split,
- startswith: DefaultFunctions.startswith,
- endswith: DefaultFunctions.endswith,
- padleft: DefaultFunctions.padleft,
- padright: DefaultFunctions.padright,
- substring: DefaultFunctions.substring,
- truncate: DefaultFunctions.truncate,
-
- default: DefaultFunctions.fdefault,
- ldefault: DefaultFunctions.ldefault,
- choice: DefaultFunctions.choice,
- striptime: DefaultFunctions.striptime,
- dateformat: DefaultFunctions.dateformat,
- durationformat: DefaultFunctions.durationformat,
- currencyformat: DefaultFunctions.currencyformat,
- localtime: DefaultFunctions.localtime,
- hash: DefaultFunctions.hash,
- meta: DefaultFunctions.meta,
- };
- class BinaryOpHandler {
- map;
- static create() {
- return new BinaryOpHandler();
- }
- constructor() {
- this.map = new Map();
- }
- register(left, op, right, func) {
- this.map.set(BinaryOpHandler.repr(op, left, right), func);
- return this;
- }
- registerComm(left, op, right, func) {
- return this.register(left, op, right, func).register(right, op, left, (a, b, ctx) => func(b, a, ctx));
- }
-
- compare(type, compare) {
- return this.register(type, "<", type, (a, b, ctx) => compare(a, b, ctx) < 0)
- .register(type, "<=", type, (a, b, ctx) => compare(a, b, ctx) <= 0)
- .register(type, ">", type, (a, b, ctx) => compare(a, b, ctx) > 0)
- .register(type, ">=", type, (a, b, ctx) => compare(a, b, ctx) >= 0)
- .register(type, "=", type, (a, b, ctx) => compare(a, b, ctx) == 0)
- .register(type, "!=", type, (a, b, ctx) => compare(a, b, ctx) != 0);
- }
-
- evaluate(op, left, right, ctx) {
- let leftType = Values.typeOf(left);
- let rightType = Values.typeOf(right);
- if (!leftType)
- return Result.failure(`Unrecognized value '${left}'`);
- else if (!rightType)
- return Result.failure(`Unrecognized value '${right}'`);
- let handler = this.map.get(BinaryOpHandler.repr(op, leftType, rightType));
- if (handler)
- return Result.success(handler(left, right, ctx));
-
- let handler2 = this.map.get(BinaryOpHandler.repr(op, leftType, "*"));
- if (handler2)
- return Result.success(handler2(left, right, ctx));
-
- let handler3 = this.map.get(BinaryOpHandler.repr(op, "*", rightType));
- if (handler3)
- return Result.success(handler3(left, right, ctx));
-
- let handler4 = this.map.get(BinaryOpHandler.repr(op, "*", "*"));
- if (handler4)
- return Result.success(handler4(left, right, ctx));
- return Result.failure(`No implementation found for '${leftType} ${op} ${rightType}'`);
- }
-
- static repr(op, left, right) {
- return `${left},${op},${right}`;
- }
- }
- function createBinaryOps(linkNormalizer) {
- return (BinaryOpHandler.create()
-
- .compare("*", (a, b) => Values.compareValue(a, b, linkNormalizer))
-
- .register("*", "&", "*", (a, b) => Values.isTruthy(a) && Values.isTruthy(b))
- .register("*", "|", "*", (a, b) => Values.isTruthy(a) || Values.isTruthy(b))
-
- .register("number", "+", "number", (a, b) => a + b)
- .register("number", "-", "number", (a, b) => a - b)
- .register("number", "*", "number", (a, b) => a * b)
- .register("number", "/", "number", (a, b) => a / b)
- .register("number", "%", "number", (a, b) => a % b)
-
- .register("string", "+", "*", (a, b, ctx) => a + Values.toString(b, ctx.settings))
- .register("*", "+", "string", (a, b, ctx) => Values.toString(a, ctx.settings) + b)
- .registerComm("string", "*", "number", (a, b) => (b < 0 ? "" : a.repeat(b)))
-
- .register("date", "-", "date", (a, b) => {
- return normalizeDuration(a.diff(b, ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"]));
- })
- .register("date", "-", "duration", (a, b) => a.minus(b))
- .registerComm("date", "+", "duration", (a, b) => a.plus(b))
-
- .register("duration", "+", "duration", (a, b) => normalizeDuration(a.plus(b)))
- .register("duration", "-", "duration", (a, b) => normalizeDuration(a.minus(b)))
- .register("duration", "/", "number", (a, b) => normalizeDuration(a.mapUnits(x => x / b)))
- .registerComm("duration", "*", "number", (a, b) => normalizeDuration(a.mapUnits(x => x * b)))
-
- .register("array", "+", "array", (a, b) => [].concat(a).concat(b))
-
- .register("object", "+", "object", (a, b) => Object.assign({}, a, b))
-
- .register("null", "+", "null", (_a, _b) => null)
- .register("null", "-", "null", (_a, _b) => null)
- .register("null", "*", "null", (_a, _b) => null)
- .register("null", "/", "null", (_a, _b) => null)
- .register("null", "%", "null", (_a, _b) => null)
- .register("date", "+", "null", (_a, _b) => null)
- .register("null", "+", "date", (_a, _b) => null)
- .register("date", "-", "null", (_a, _b) => null)
- .register("null", "-", "date", (_a, _b) => null));
- }
- class Context {
- linkHandler;
- settings;
- globals;
- binaryOps;
- functions;
-
- constructor(linkHandler, settings, globals = {}, binaryOps = createBinaryOps(linkHandler.normalize), functions = DEFAULT_FUNCTIONS) {
- this.linkHandler = linkHandler;
- this.settings = settings;
- this.globals = globals;
- this.binaryOps = binaryOps;
- this.functions = functions;
- }
-
- set(name, value) {
- this.globals[name] = value;
- return this;
- }
-
- get(name) {
- return this.globals[name] ?? null;
- }
-
- tryEvaluate(field, data = {}) {
- return this.evaluate(field, data).orElseThrow();
- }
-
- evaluate(field, data = {}) {
- switch (field.type) {
- case "literal":
- return Result.success(field.value);
- case "variable":
- if (field.name in data)
- return Result.success(data[field.name]);
- else if (field.name in this.globals)
- return Result.success(this.globals[field.name]);
- else
- return Result.success(null);
- case "negated":
- return this.evaluate(field.child, data).map(s => !Values.isTruthy(s));
- case "binaryop":
- return Result.flatMap2(this.evaluate(field.left, data), this.evaluate(field.right, data), (a, b) => this.binaryOps.evaluate(field.op, a, b, this));
- case "list":
- let result = [];
- for (let child of field.values) {
- let subeval = this.evaluate(child, data);
- if (!subeval.successful)
- return subeval;
- result.push(subeval.value);
- }
- return Result.success(result);
- case "object":
- let objResult = {};
- for (let [key, child] of Object.entries(field.values)) {
- let subeval = this.evaluate(child, data);
- if (!subeval.successful)
- return subeval;
- objResult[key] = subeval.value;
- }
- return Result.success(objResult);
- case "lambda":
-
-
- return Result.success((ctx, ...args) => {
- let copy = Object.assign({}, data);
- for (let arg = 0; arg < Math.min(args.length, field.arguments.length); arg++) {
- copy[field.arguments[arg]] = args[arg];
- }
- return ctx.evaluate(field.value, copy).orElseThrow();
- });
- case "function":
- let rawFunc = field.func.type == "variable"
- ? Result.success(field.func.name)
- : this.evaluate(field.func, data);
- if (!rawFunc.successful)
- return rawFunc;
- let func = rawFunc.value;
- let args = [];
- for (let arg of field.arguments) {
- let resolved = this.evaluate(arg, data);
- if (!resolved.successful)
- return resolved;
- args.push(resolved.value);
- }
- let call;
- if (Values.isFunction(func))
- call = func;
- else if (Values.isString(func) && func in this.functions)
- call = this.functions[func];
- else if (Values.isString(func))
- return Result.failure(`Unrecognized function name '${func}'`);
- else
- return Result.failure(`Cannot call type '${Values.typeOf(func)}' as a function`);
- try {
- return Result.success(call(this, ...args));
- }
- catch (e) {
- return Result.failure(e.message);
- }
- case "index":
-
- let literalIndex = this.evaluate(field.index, data);
- let checkedIndex = literalIndex.flatMap(s => Values.isString(s) || Values.isNumber(s) || Values.isNull(s)
- ? Result.success(s)
- : Result.failure("Can only index with a string or number"));
- if (!checkedIndex.successful)
- return checkedIndex;
- let index = checkedIndex.value;
- if (Values.isNull(index))
- return Result.success(null);
- let checkedObject = field.object.type == "variable" && field.object.name == "row"
- ? Result.success(Object.assign({}, this.globals, data))
- : this.evaluate(field.object, data);
- if (!checkedObject.successful)
- return checkedObject;
- let object = Values.wrapValue(checkedObject.value);
- if (!object)
- return Result.failure("Unrecognized object to index into: " + object);
- switch (object.type) {
- case "object":
- if (!Values.isString(index))
- return Result.failure('can only index into objects with strings (a.b or a["b"])');
- return Result.success(object.value[index] ?? null);
- case "link":
- if (!Values.isString(index))
- return Result.failure('can only index into links with strings (a.b or a["b"])');
- let linkValue = this.linkHandler.resolve(object.value.path);
- if (Values.isNull(linkValue))
- return Result.success(null);
- return Result.success(linkValue[index] ?? null);
- case "array":
- if (Values.isNumber(index)) {
- if (index >= object.value.length || index < 0)
- return Result.success(null);
- else
- return Result.success(object.value[index]);
- }
- else if (Values.isString(index)) {
- let result = [];
- for (let value of object.value) {
- let next = this.evaluate(Fields.index(Fields.literal(value), Fields.literal(index)));
- if (!next.successful)
- continue;
- result.push(next.value);
- }
- return Result.success(result);
- }
- else {
- return Result.failure("Array indexing requires either a number (to get a specific element), or a string (to map all elements inside the array)");
- }
- case "string":
- if (!Values.isNumber(index))
- return Result.failure("string indexing requires a numeric index (string[index])");
- if (index >= object.value.length || index < 0)
- return Result.success(null);
- return Result.success(object.value[index]);
- case "date":
- if (!Values.isString(index))
- return Result.failure("date indexing requires a string representing the unit");
- switch (index) {
- case "year":
- return Result.success(object.value.year);
- case "month":
- return Result.success(object.value.month);
- case "weekyear":
- return Result.success(object.value.weekNumber);
- case "week":
- return Result.success(Math.floor(object.value.day / 7) + 1);
- case "weekday":
- return Result.success(object.value.weekday);
- case "day":
- return Result.success(object.value.day);
- case "hour":
- return Result.success(object.value.hour);
- case "minute":
- return Result.success(object.value.minute);
- case "second":
- return Result.success(object.value.second);
- case "millisecond":
- return Result.success(object.value.millisecond);
- default:
- return Result.success(null);
- }
- case "duration":
- if (!Values.isString(index))
- return Result.failure("duration indexing requires a string representing the unit");
- switch (index) {
- case "year":
- case "years":
- return Result.success(object.value.shiftTo("years").years);
- case "month":
- case "months":
- return Result.success(object.value.shiftTo("months").months);
- case "weeks":
- return Result.success(object.value.shiftTo("weeks").weeks);
- case "day":
- case "days":
- return Result.success(object.value.shiftTo("days").days);
- case "hour":
- case "hours":
- return Result.success(object.value.shiftTo("hours").hours);
- case "minute":
- case "minutes":
- return Result.success(object.value.shiftTo("minutes").minutes);
- case "second":
- case "seconds":
- return Result.success(object.value.shiftTo("seconds").seconds);
- case "millisecond":
- case "milliseconds":
- return Result.success(object.value.shiftTo("milliseconds").milliseconds);
- default:
- return Result.success(null);
- }
- default:
- return Result.success(null);
- }
- }
- }
- }
- function iden(x) {
- return x;
- }
- function executeCore(rows, context, ops) {
- let diagnostics = [];
- let identMeaning = { type: "path" };
- let startTime = Date.now();
- for (let op of ops) {
- let opStartTime = Date.now();
- let incomingRows = rows.length;
- let errors = [];
- switch (op.type) {
- case "where":
- let whereResult = [];
- for (let index = 0; index < rows.length; index++) {
- let row = rows[index];
- let value = context.evaluate(op.clause, row.data);
- if (!value.successful)
- errors.push({ index, message: value.error });
- else if (Values.isTruthy(value.value))
- whereResult.push(row);
- }
- rows = whereResult;
- break;
- case "sort":
- let sortFields = op.fields;
- let taggedData = [];
- outer: for (let index = 0; index < rows.length; index++) {
- let row = rows[index];
- let rowSorts = [];
- for (let sIndex = 0; sIndex < sortFields.length; sIndex++) {
- let value = context.evaluate(sortFields[sIndex].field, row.data);
- if (!value.successful) {
- errors.push({ index, message: value.error });
- continue outer;
- }
- rowSorts.push(value.value);
- }
- taggedData.push({ data: row, fields: rowSorts });
- }
-
- taggedData.sort((a, b) => {
- for (let index = 0; index < sortFields.length; index++) {
- let factor = sortFields[index].direction === "ascending" ? 1 : -1;
- let le = context.binaryOps
- .evaluate("<", a.fields[index], b.fields[index], context)
- .orElse(false);
- if (Values.isTruthy(le))
- return factor * -1;
- let ge = context.binaryOps
- .evaluate(">", a.fields[index], b.fields[index], context)
- .orElse(false);
- if (Values.isTruthy(ge))
- return factor * 1;
- }
- return 0;
- });
- rows = taggedData.map(v => v.data);
- break;
- case "limit":
- let limiting = context.evaluate(op.amount);
- if (!limiting.successful)
- return Result.failure("Failed to execute 'limit' statement: " + limiting.error);
- if (!Values.isNumber(limiting.value))
- return Result.failure(`Failed to execute 'limit' statement: limit should be a number, but got '${Values.typeOf(limiting.value)}' (${limiting.value})`);
- rows = rows.slice(0, limiting.value);
- break;
- case "group":
- let groupData = [];
- for (let index = 0; index < rows.length; index++) {
- let value = context.evaluate(op.field.field, rows[index].data);
- if (!value.successful) {
- errors.push({ index, message: value.error });
- continue;
- }
- groupData.push({ data: rows[index], key: value.value });
- }
-
- groupData.sort((a, b) => {
- let le = context.binaryOps.evaluate("<", a.key, b.key, context).orElse(false);
- if (Values.isTruthy(le))
- return -1;
- let ge = context.binaryOps.evaluate(">", a.key, b.key, context).orElse(false);
- if (Values.isTruthy(ge))
- return 1;
- return 0;
- });
-
- let finalGroupData = [];
- if (groupData.length > 0)
- finalGroupData.push({
- key: groupData[0].key,
- rows: [groupData[0].data.data],
- [op.field.name]: groupData[0].key,
- });
- for (let index = 1; index < groupData.length; index++) {
- let curr = groupData[index], prev = groupData[index - 1];
- if (context.binaryOps.evaluate("=", curr.key, prev.key, context).orElse(false)) {
- finalGroupData[finalGroupData.length - 1].rows.push(curr.data.data);
- }
- else {
- finalGroupData.push({
- key: curr.key,
- rows: [curr.data.data],
- [op.field.name]: curr.key,
- });
- }
- }
- rows = finalGroupData.map(d => {
- return { id: d.key, data: d };
- });
- identMeaning = { type: "group", name: op.field.name, on: identMeaning };
- break;
- case "flatten":
- let flattenResult = [];
- for (let index = 0; index < rows.length; index++) {
- let row = rows[index];
- let value = context.evaluate(op.field.field, row.data);
- if (!value.successful) {
- errors.push({ index, message: value.error });
- continue;
- }
- let datapoints = Values.isArray(value.value) ? value.value : [value.value];
- for (let v of datapoints) {
- let copy = Values.deepCopy(row);
- copy.data[op.field.name] = v;
- flattenResult.push(copy);
- }
- }
- rows = flattenResult;
- if (identMeaning.type == "group" && identMeaning.name == op.field.name)
- identMeaning = identMeaning.on;
- break;
- default:
- return Result.failure("Unrecognized query operation '" + op.type + "'");
- }
- if (errors.length >= incomingRows && incomingRows > 0) {
- return Result.failure(`Every row during operation '${op.type}' failed with an error; first ${Math.min(3, errors.length)}:\n
- ${errors
- .slice(0, 3)
- .map(d => "- " + d.message)
- .join("\n")}`);
- }
- diagnostics.push({
- incomingRows,
- errors,
- outgoingRows: rows.length,
- timeMs: Date.now() - opStartTime,
- });
- }
- return Result.success({
- data: rows,
- idMeaning: identMeaning,
- ops,
- diagnostics,
- timeMs: Date.now() - startTime,
- });
- }
- function executeCoreExtract(rows, context, ops, fields) {
- let internal = executeCore(rows, context, ops);
- if (!internal.successful)
- return internal;
- let core = internal.value;
- let startTime = Date.now();
- let errors = [];
- let res = [];
- outer: for (let index = 0; index < core.data.length; index++) {
- let page = { id: core.data[index].id, data: {} };
- for (let [name, field] of Object.entries(fields)) {
- let value = context.evaluate(field, core.data[index].data);
- if (!value.successful) {
- errors.push({ index: index, message: value.error });
- continue outer;
- }
- page.data[name] = value.value;
- }
- res.push(page);
- }
- if (errors.length >= core.data.length && core.data.length > 0) {
- return Result.failure(`Every row during final data extraction failed with an error; first ${Math.max(errors.length, 3)}:\n
- ${errors
- .slice(0, 3)
- .map(d => "- " + d.message)
- .join("\n")}`);
- }
- let execTime = Date.now() - startTime;
- return Result.success({
- data: res,
- idMeaning: core.idMeaning,
- diagnostics: core.diagnostics.concat([
- {
- timeMs: execTime,
- incomingRows: core.data.length,
- outgoingRows: res.length,
- errors,
- },
- ]),
- ops: core.ops.concat([{ type: "extract", fields }]),
- timeMs: core.timeMs + execTime,
- });
- }
- async function executeList(query, index, origin, settings) {
-
- let fileset = await resolveSource(query.source, index, origin);
- if (!fileset.successful)
- return Result.failure(fileset.error);
-
- let rootContext = new Context(defaultLinkHandler(index, origin), settings, {
- this: index.pages.get(origin)?.serialize(index) ?? {},
- });
- let targetField = query.header.format;
- let showId = query.header.showId;
- let fields = targetField ? { target: targetField } : {};
- return executeCoreExtract(fileset.value, rootContext, query.operations, fields).map(core => {
- let data;
- if (showId && targetField) {
- data = core.data.map(p => Widgets.listPair(p.id, p.data["target"] ?? null));
- }
- else if (targetField) {
- data = core.data.map(p => p.data["target"] ?? null);
- }
- else {
- data = core.data.map(p => p.id);
- }
- return { primaryMeaning: core.idMeaning, core, data };
- });
- }
- async function executeTable(query, index, origin, settings) {
-
- let fileset = await resolveSource(query.source, index, origin);
- if (!fileset.successful)
- return Result.failure(fileset.error);
-
- let rootContext = new Context(defaultLinkHandler(index, origin), settings, {
- this: index.pages.get(origin)?.serialize(index) ?? {},
- });
- let targetFields = query.header.fields;
- let showId = query.header.showId;
- let fields = {};
- for (let field of targetFields)
- fields[field.name] = field.field;
- return executeCoreExtract(fileset.value, rootContext, query.operations, fields).map(core => {
- if (showId) {
- const idName = core.idMeaning.type === "group" ? core.idMeaning.name : settings.tableIdColumnName;
- let names = [idName].concat(targetFields.map(f => f.name));
- let data = core.data.map(p => [p.id].concat(targetFields.map(f => p.data[f.name])));
- return { core, names, data, idMeaning: core.idMeaning };
- }
- else {
- let names = targetFields.map(f => f.name);
- let data = core.data.map(p => targetFields.map(f => p.data[f.name]));
- return { core, names, data, idMeaning: core.idMeaning };
- }
- });
- }
- function extractTaskGroupings(id, rows) {
- switch (id.type) {
- case "path":
- return rows;
- case "group":
- let key = id.name;
- return rows.map(r => iden({
- key: r[key],
- rows: extractTaskGroupings(id.on, r.rows),
- }));
- }
- }
- async function executeTask(query, origin, index, settings) {
- let fileset = matchingSourcePaths(query.source, index, origin);
- if (!fileset.successful)
- return Result.failure(fileset.error);
-
- let incomingTasks = [];
- for (let path of fileset.value) {
- let page = index.pages.get(path);
- if (!page)
- continue;
- let pageData = page.serialize(index);
- let pageTasks = pageData.file.tasks.map(t => {
- const tcopy = Values.deepCopy(t);
-
- for (let [key, value] of Object.entries(pageData)) {
- if (key in tcopy)
- continue;
- tcopy[key] = value;
- }
- return { id: `${pageData.path}#${t.line}`, data: tcopy };
- });
- for (let task of pageTasks)
- incomingTasks.push(task);
- }
-
- let rootContext = new Context(defaultLinkHandler(index, origin), settings, {
- this: index.pages.get(origin)?.serialize(index) ?? {},
- });
- return executeCore(incomingTasks, rootContext, query.operations).map(core => {
- return {
- core,
- tasks: extractTaskGroupings(core.idMeaning, core.data.map(r => r.data)),
- };
- });
- }
- function executeInline(field, origin, index, settings) {
- return new Context(defaultLinkHandler(index, origin), settings, {
- this: index.pages.get(origin)?.serialize(index) ?? {},
- }).evaluate(field);
- }
- function defaultLinkHandler(index, origin) {
- return {
- resolve: link => {
- let realFile = index.metadataCache.getFirstLinkpathDest(link, origin);
- if (!realFile)
- return null;
- let realPage = index.pages.get(realFile.path);
- if (!realPage)
- return null;
- return realPage.serialize(index);
- },
- normalize: link => {
- let realFile = index.metadataCache.getFirstLinkpathDest(link, origin);
- return realFile?.path ?? link;
- },
- exists: link => {
- let realFile = index.metadataCache.getFirstLinkpathDest(link, origin);
- return !!realFile;
- },
- };
- }
- async function executeCalendar(query, index, origin, settings) {
-
- let fileset = await resolveSource(query.source, index, origin);
- if (!fileset.successful)
- return Result.failure(fileset.error);
-
- let rootContext = new Context(defaultLinkHandler(index, origin), settings, {
- this: index.pages.get(origin)?.serialize(index) ?? {},
- });
- let targetField = query.header.field.field;
- let fields = {
- target: targetField,
- link: Fields.indexVariable("file.link"),
- };
- return executeCoreExtract(fileset.value, rootContext, query.operations, fields).map(core => {
- let data = core.data.map(p => iden({
- date: p.data["target"],
- link: p.data["link"],
- }));
- return { core, data };
- });
- }
- function compareVersions(v1, v2) {
-
- const n1 = validateAndParse(v1);
- const n2 = validateAndParse(v2);
-
- const p1 = n1.pop();
- const p2 = n2.pop();
-
- const r = compareSegments(n1, n2);
- if (r !== 0) return r;
-
- if (p1 && p2) {
- return compareSegments(p1.split('.'), p2.split('.'));
- } else if (p1 || p2) {
- return p1 ? -1 : 1;
- }
- return 0;
- }
- const validate = (v) =>
- typeof v === 'string' && /^[v\d]/.test(v) && semver.test(v);
- const compare = (v1, v2, operator) => {
-
- assertValidOperator(operator);
-
-
- const res = compareVersions(v1, v2);
- return operatorResMap[operator].includes(res);
- };
- const satisfies = (v, r) => {
-
- const m = r.match(/^([<>=~^]+)/);
- const op = m ? m[1] : '=';
-
- if (op !== '^' && op !== '~') return compare(v, r, op);
-
- const [v1, v2, v3] = validateAndParse(v);
- const [r1, r2, r3] = validateAndParse(r);
- if (compareStrings(v1, r1) !== 0) return false;
- if (op === '^') {
- return compareSegments([v2, v3], [r2, r3]) >= 0;
- }
- if (compareStrings(v2, r2) !== 0) return false;
- return compareStrings(v3, r3) >= 0;
- };
- compareVersions.validate = validate;
- compareVersions.compare = compare;
- compareVersions.satisfies = satisfies;
- const semver =
- /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
- const validateAndParse = (v) => {
- if (typeof v !== 'string') {
- throw new TypeError('Invalid argument expected string');
- }
- const match = v.match(semver);
- if (!match) {
- throw new Error(`Invalid argument not valid semver ('${v}' received)`);
- }
- match.shift();
- return match;
- };
- const isWildcard = (s) => s === '*' || s === 'x' || s === 'X';
- const tryParse = (v) => {
- const n = parseInt(v, 10);
- return isNaN(n) ? v : n;
- };
- const forceType = (a, b) =>
- typeof a !== typeof b ? [String(a), String(b)] : [a, b];
- const compareStrings = (a, b) => {
- if (isWildcard(a) || isWildcard(b)) return 0;
- const [ap, bp] = forceType(tryParse(a), tryParse(b));
- if (ap > bp) return 1;
- if (ap < bp) return -1;
- return 0;
- };
- const compareSegments = (a, b) => {
- for (let i = 0; i < Math.max(a.length, b.length); i++) {
- const r = compareStrings(a[i] || 0, b[i] || 0);
- if (r !== 0) return r;
- }
- return 0;
- };
- const operatorResMap = {
- '>': [1],
- '>=': [0, 1],
- '=': [0],
- '<=': [-1, 0],
- '<': [-1],
- };
- const allowedOperators = Object.keys(operatorResMap);
- const assertValidOperator = (op) => {
- if (typeof op !== 'string') {
- throw new TypeError(
- `Invalid operator type, expected string but got ${typeof op}`
- );
- }
- if (allowedOperators.indexOf(op) === -1) {
- throw new Error(
- `Invalid operator, expected one of ${allowedOperators.join('|')}`
- );
- }
- };
- var n,l$1,u$1,i$1,o$1,r$1,f$1,e$1,c$1={},s$1=[],a$1=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,h$1=Array.isArray;function v$1(n,l){for(var u in l)n[u]=l[u];return n}function p$1(n){var l=n.parentNode;l&&l.removeChild(n);}function y$1(l,u,t){var i,o,r,f={};for(r in u)"key"==r?i=u[r]:"ref"==r?o=u[r]:f[r]=u[r];if(arguments.length>2&&(f.children=arguments.length>3?n.call(arguments,2):t),"function"==typeof l&&null!=l.defaultProps)for(r in l.defaultProps)void 0===f[r]&&(f[r]=l.defaultProps[r]);return d$1(l,f,i,o,null)}function d$1(n,t,i,o,r){var f={type:n,props:t,key:i,ref:o,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==r?++u$1:r};return null==r&&null!=l$1.vnode&&l$1.vnode(f),f}function _$1(){return {current:null}}function k$2(n){return n.children}function b$1(n,l){this.props=n,this.context=l;}function g$2(n,l){if(null==l)return n.__?g$2(n.__,n.__.__k.indexOf(n)+1):null;for(var u;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e)return u.__e;return "function"==typeof n.type?g$2(n):null}function m$1(n){var l,u;if(null!=(n=n.__)&&null!=n.__c){for(n.__e=n.__c.base=null,l=0;l<n.__k.length;l++)if(null!=(u=n.__k[l])&&null!=u.__e){n.__e=n.__c.base=u.__e;break}return m$1(n)}}function w$2(n){(!n.__d&&(n.__d=!0)&&i$1.push(n)&&!x$2.__r++||o$1!==l$1.debounceRendering)&&((o$1=l$1.debounceRendering)||r$1)(x$2);}function x$2(){var n,l,u,t,o,r,e,c,s;for(i$1.sort(f$1);n=i$1.shift();)n.__d&&(l=i$1.length,t=void 0,o=void 0,r=void 0,c=(e=(u=n).__v).__e,(s=u.__P)&&(t=[],o=[],(r=v$1({},e)).__v=e.__v+1,L$1(s,e,r,u.__n,void 0!==s.ownerSVGElement,null!=e.__h?[c]:null,t,null==c?g$2(e):c,e.__h,o),M$1(t,e,o),e.__e!=c&&m$1(e)),i$1.length>l&&i$1.sort(f$1));x$2.__r=0;}function P$1(n,l,u,t,i,o,r,f,e,a,v){var p,y,_,b,m,w,x,P,C,H=0,I=t&&t.__k||s$1,T=I.length,j=T,z=l.length;for(u.__k=[],p=0;p<z;p++)null!=(b=u.__k[p]=null==(b=l[p])||"boolean"==typeof b||"function"==typeof b?null:"string"==typeof b||"number"==typeof b||"bigint"==typeof b?d$1(null,b,null,null,b):h$1(b)?d$1(k$2,{children:b},null,null,null):b.__b>0?d$1(b.type,b.props,b.key,b.ref?b.ref:null,b.__v):b)?(b.__=u,b.__b=u.__b+1,-1===(P=A$2(b,I,x=p+H,j))?_=c$1:(_=I[P]||c$1,I[P]=void 0,j--),L$1(n,b,_,i,o,r,f,e,a,v),m=b.__e,(y=b.ref)&&_.ref!=y&&(_.ref&&O$1(_.ref,null,b),v.push(y,b.__c||m,b)),null!=m&&(null==w&&(w=m),(C=_===c$1||null===_.__v)?-1==P&&H--:P!==x&&(P===x+1?H++:P>x?j>z-x?H+=P-x:H--:H=P<x&&P==x-1?P-x:0),x=p+H,"function"!=typeof b.type||P===x&&_.__k!==b.__k?"function"==typeof b.type||P===x&&!C?void 0!==b.__d?(e=b.__d,b.__d=void 0):e=m.nextSibling:e=S(n,m,e):e=$$1(b,e,n),"function"==typeof u.type&&(u.__d=e))):(_=I[p])&&null==_.key&&_.__e&&(_.__e==e&&(e=g$2(_)),q$2(_,_,!1),I[p]=null);for(u.__e=w,p=T;p--;)null!=I[p]&&("function"==typeof u.type&&null!=I[p].__e&&I[p].__e==u.__d&&(u.__d=I[p].__e.nextSibling),q$2(I[p],I[p]));}function $$1(n,l,u){for(var t,i=n.__k,o=0;i&&o<i.length;o++)(t=i[o])&&(t.__=n,l="function"==typeof t.type?$$1(t,l,u):S(u,t.__e,l));return l}function C$1(n,l){return l=l||[],null==n||"boolean"==typeof n||(h$1(n)?n.some(function(n){C$1(n,l);}):l.push(n)),l}function S(n,l,u){return null==u||u.parentNode!==n?n.insertBefore(l,null):l==u&&null!=l.parentNode||n.insertBefore(l,u),l.nextSibling}function A$2(n,l,u,t){var i=n.key,o=n.type,r=u-1,f=u+1,e=l[u];if(null===e||e&&i==e.key&&o===e.type)return u;if(t>(null!=e?1:0))for(;r>=0||f<l.length;){if(r>=0){if((e=l[r])&&i==e.key&&o===e.type)return r;r--;}if(f<l.length){if((e=l[f])&&i==e.key&&o===e.type)return f;f++;}}return -1}function H$1(n,l,u,t,i){var o;for(o in u)"children"===o||"key"===o||o in l||T$2(n,o,null,u[o],t);for(o in l)i&&"function"!=typeof l[o]||"children"===o||"key"===o||"value"===o||"checked"===o||u[o]===l[o]||T$2(n,o,l[o],u[o],t);}function I$1(n,l,u){"-"===l[0]?n.setProperty(l,null==u?"":u):n[l]=null==u?"":"number"!=typeof u||a$1.test(l)?u:u+"px";}function T$2(n,l,u,t,i){var o;n:if("style"===l)if("string"==typeof u)n.style.cssText=u;else {if("string"==typeof t&&(n.style.cssText=t=""),t)for(l in t)u&&l in u||I$1(n.style,l,"");if(u)for(l in u)t&&u[l]===t[l]||I$1(n.style,l,u[l]);}else if("o"===l[0]&&"n"===l[1])o=l!==(l=l.replace(/(PointerCapture)$|Capture$/,"$1")),l=l.toLowerCase()in n?l.toLowerCase().slice(2):l.slice(2),n.l||(n.l={}),n.l[l+o]=u,u?t||n.addEventListener(l,o?z$2:j$2,o):n.removeEventListener(l,o?z$2:j$2,o);else if("dangerouslySetInnerHTML"!==l){if(i)l=l.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!==l&&"height"!==l&&"href"!==l&&"list"!==l&&"form"!==l&&"tabIndex"!==l&&"download"!==l&&"rowSpan"!==l&&"colSpan"!==l&&l in n)try{n[l]=null==u?"":u;break n}catch(n){}"function"==typeof u||(null==u||!1===u&&"-"!==l[4]?n.removeAttribute(l):n.setAttribute(l,u));}}function j$2(n){return this.l[n.type+!1](l$1.event?l$1.event(n):n)}function z$2(n){return this.l[n.type+!0](l$1.event?l$1.event(n):n)}function L$1(n,u,t,i,o,r,f,e,c,s){var a,p,y,d,_,g,m,w,x,$,C,S,A,H,I,T=u.type;if(void 0!==u.constructor)return null;null!=t.__h&&(c=t.__h,e=u.__e=t.__e,u.__h=null,r=[e]),(a=l$1.__b)&&a(u);n:if("function"==typeof T)try{if(w=u.props,x=(a=T.contextType)&&i[a.__c],$=a?x?x.props.value:a.__:i,t.__c?m=(p=u.__c=t.__c).__=p.__E:("prototype"in T&&T.prototype.render?u.__c=p=new T(w,$):(u.__c=p=new b$1(w,$),p.constructor=T,p.render=B$2),x&&x.sub(p),p.props=w,p.state||(p.state={}),p.context=$,p.__n=i,y=p.__d=!0,p.__h=[],p._sb=[]),null==p.__s&&(p.__s=p.state),null!=T.getDerivedStateFromProps&&(p.__s==p.state&&(p.__s=v$1({},p.__s)),v$1(p.__s,T.getDerivedStateFromProps(w,p.__s))),d=p.props,_=p.state,p.__v=u,y)null==T.getDerivedStateFromProps&&null!=p.componentWillMount&&p.componentWillMount(),null!=p.componentDidMount&&p.__h.push(p.componentDidMount);else {if(null==T.getDerivedStateFromProps&&w!==d&&null!=p.componentWillReceiveProps&&p.componentWillReceiveProps(w,$),!p.__e&&(null!=p.shouldComponentUpdate&&!1===p.shouldComponentUpdate(w,p.__s,$)||u.__v===t.__v)){for(u.__v!==t.__v&&(p.props=w,p.state=p.__s,p.__d=!1),u.__e=t.__e,u.__k=t.__k,u.__k.forEach(function(n){n&&(n.__=u);}),C=0;C<p._sb.length;C++)p.__h.push(p._sb[C]);p._sb=[],p.__h.length&&f.push(p);break n}null!=p.componentWillUpdate&&p.componentWillUpdate(w,p.__s,$),null!=p.componentDidUpdate&&p.__h.push(function(){p.componentDidUpdate(d,_,g);});}if(p.context=$,p.props=w,p.__P=n,p.__e=!1,S=l$1.__r,A=0,"prototype"in T&&T.prototype.render){for(p.state=p.__s,p.__d=!1,S&&S(u),a=p.render(p.props,p.state,p.context),H=0;H<p._sb.length;H++)p.__h.push(p._sb[H]);p._sb=[];}else do{p.__d=!1,S&&S(u),a=p.render(p.props,p.state,p.context),p.state=p.__s;}while(p.__d&&++A<25);p.state=p.__s,null!=p.getChildContext&&(i=v$1(v$1({},i),p.getChildContext())),y||null==p.getSnapshotBeforeUpdate||(g=p.getSnapshotBeforeUpdate(d,_)),P$1(n,h$1(I=null!=a&&a.type===k$2&&null==a.key?a.props.children:a)?I:[I],u,t,i,o,r,f,e,c,s),p.base=u.__e,u.__h=null,p.__h.length&&f.push(p),m&&(p.__E=p.__=null);}catch(n){u.__v=null,(c||null!=r)&&(u.__e=e,u.__h=!!c,r[r.indexOf(e)]=null),l$1.__e(n,u,t);}else null==r&&u.__v===t.__v?(u.__k=t.__k,u.__e=t.__e):u.__e=N$1(t.__e,u,t,i,o,r,f,c,s);(a=l$1.diffed)&&a(u);}function M$1(n,u,t){for(var i=0;i<t.length;i++)O$1(t[i],t[++i],t[++i]);l$1.__c&&l$1.__c(u,n),n.some(function(u){try{n=u.__h,u.__h=[],n.some(function(n){n.call(u);});}catch(n){l$1.__e(n,u.__v);}});}function N$1(l,u,t,i,o,r,f,e,s){var a,v,y,d=t.props,_=u.props,k=u.type,b=0;if("svg"===k&&(o=!0),null!=r)for(;b<r.length;b++)if((a=r[b])&&"setAttribute"in a==!!k&&(k?a.localName===k:3===a.nodeType)){l=a,r[b]=null;break}if(null==l){if(null===k)return document.createTextNode(_);l=o?document.createElementNS("http://www.w3.org/2000/svg",k):document.createElement(k,_.is&&_),r=null,e=!1;}if(null===k)d===_||e&&l.data===_||(l.data=_);else {if(r=r&&n.call(l.childNodes),v=(d=t.props||c$1).dangerouslySetInnerHTML,y=_.dangerouslySetInnerHTML,!e){if(null!=r)for(d={},b=0;b<l.attributes.length;b++)d[l.attributes[b].name]=l.attributes[b].value;(y||v)&&(y&&(v&&y.__html==v.__html||y.__html===l.innerHTML)||(l.innerHTML=y&&y.__html||""));}if(H$1(l,_,d,o,e),y)u.__k=[];else if(P$1(l,h$1(b=u.props.children)?b:[b],u,t,i,o&&"foreignObject"!==k,r,f,r?r[0]:t.__k&&g$2(t,0),e,s),null!=r)for(b=r.length;b--;)null!=r[b]&&p$1(r[b]);e||("value"in _&&void 0!==(b=_.value)&&(b!==l.value||"progress"===k&&!b||"option"===k&&b!==d.value)&&T$2(l,"value",b,d.value,!1),"checked"in _&&void 0!==(b=_.checked)&&b!==l.checked&&T$2(l,"checked",b,d.checked,!1));}return l}function O$1(n,u,t){try{"function"==typeof n?n(u):n.current=u;}catch(n){l$1.__e(n,t);}}function q$2(n,u,t){var i,o;if(l$1.unmount&&l$1.unmount(n),(i=n.ref)&&(i.current&&i.current!==n.__e||O$1(i,null,u)),null!=(i=n.__c)){if(i.componentWillUnmount)try{i.componentWillUnmount();}catch(n){l$1.__e(n,u);}i.base=i.__P=null,n.__c=void 0;}if(i=n.__k)for(o=0;o<i.length;o++)i[o]&&q$2(i[o],u,t||"function"!=typeof n.type);t||null==n.__e||p$1(n.__e),n.__=n.__e=n.__d=void 0;}function B$2(n,l,u){return this.constructor(n,u)}function D$1(u,t,i){var o,r,f,e;l$1.__&&l$1.__(u,t),r=(o="function"==typeof i)?null:i&&i.__k||t.__k,f=[],e=[],L$1(t,u=(!o&&i||t).__k=y$1(k$2,null,[u]),r||c$1,c$1,void 0!==t.ownerSVGElement,!o&&i?[i]:r?null:t.firstChild?n.call(t.childNodes):null,f,!o&&i?i:r?r.__e:t.firstChild,o,e),M$1(f,u,e);}function E$1(n,l){D$1(n,l,E$1);}function F$2(l,u,t){var i,o,r,f,e=v$1({},l.props);for(r in l.type&&l.type.defaultProps&&(f=l.type.defaultProps),u)"key"==r?i=u[r]:"ref"==r?o=u[r]:e[r]=void 0===u[r]&&void 0!==f?f[r]:u[r];return arguments.length>2&&(e.children=arguments.length>3?n.call(arguments,2):t),d$1(l.type,e,i||l.key,o||l.ref,null)}function G$1(n,l){var u={__c:l="__cC"+e$1++,__:n,Consumer:function(n,l){return n.children(l)},Provider:function(n){var u,t;return this.getChildContext||(u=[],(t={})[l]=this,this.getChildContext=function(){return t},this.shouldComponentUpdate=function(n){this.props.value!==n.value&&u.some(function(n){n.__e=!0,w$2(n);});},this.sub=function(n){u.push(n);var l=n.componentWillUnmount;n.componentWillUnmount=function(){u.splice(u.indexOf(n),1),l&&l.call(n);};}),n.children}};return u.Provider.__=u.Consumer.contextType=u}n=s$1.slice,l$1={__e:function(n,l,u,t){for(var i,o,r;l=l.__;)if((i=l.__c)&&!i.__)try{if((o=i.constructor)&&null!=o.getDerivedStateFromError&&(i.setState(o.getDerivedStateFromError(n)),r=i.__d),null!=i.componentDidCatch&&(i.componentDidCatch(n,t||{}),r=i.__d),r)return i.__E=i}catch(l){n=l;}throw n}},u$1=0,b$1.prototype.setState=function(n,l){var u;u=null!=this.__s&&this.__s!==this.state?this.__s:this.__s=v$1({},this.state),"function"==typeof n&&(n=n(v$1({},u),this.props)),n&&v$1(u,n),null!=n&&this.__v&&(l&&this._sb.push(l),w$2(this));},b$1.prototype.forceUpdate=function(n){this.__v&&(this.__e=!0,n&&this.__h.push(n),w$2(this));},b$1.prototype.render=k$2,i$1=[],r$1="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,f$1=function(n,l){return n.__v.__b-l.__v.__b},x$2.__r=0,e$1=0;
- var t,r,u,i,o=0,f=[],c=[],e=l$1.__b,a=l$1.__r,v=l$1.diffed,l=l$1.__c,m=l$1.unmount;function d(t,u){l$1.__h&&l$1.__h(r,t,o||u),o=0;var i=r.__H||(r.__H={__:[],__h:[]});return t>=i.__.length&&i.__.push({__V:c}),i.__[t]}function h(n){return o=1,s(B$1,n)}function s(n,u,i){var o=d(t++,2);if(o.t=n,!o.__c&&(o.__=[i?i(u):B$1(void 0,u),function(n){var t=o.__N?o.__N[0]:o.__[0],r=o.t(t,n);t!==r&&(o.__N=[r,o.__[1]],o.__c.setState({}));}],o.__c=r,!r.u)){var f=function(n,t,r){if(!o.__c.__H)return !0;var u=o.__c.__H.__.filter(function(n){return n.__c});if(u.every(function(n){return !n.__N}))return !c||c.call(this,n,t,r);var i=!1;return u.forEach(function(n){if(n.__N){var t=n.__[0];n.__=n.__N,n.__N=void 0,t!==n.__[0]&&(i=!0);}}),!(!i&&o.__c.props===n)&&(!c||c.call(this,n,t,r))};r.u=!0;var c=r.shouldComponentUpdate,e=r.componentWillUpdate;r.componentWillUpdate=function(n,t,r){if(this.__e){var u=c;c=void 0,f(n,t,r),c=u;}e&&e.call(this,n,t,r);},r.shouldComponentUpdate=f;}return o.__N||o.__}function p(u,i){var o=d(t++,3);!l$1.__s&&z$1(o.__H,i)&&(o.__=u,o.i=i,r.__H.__h.push(o));}function y(u,i){var o=d(t++,4);!l$1.__s&&z$1(o.__H,i)&&(o.__=u,o.i=i,r.__h.push(o));}function _(n){return o=5,F$1(function(){return {current:n}},[])}function A$1(n,t,r){o=6,y(function(){return "function"==typeof n?(n(t()),function(){return n(null)}):n?(n.current=t(),function(){return n.current=null}):void 0},null==r?r:r.concat(n));}function F$1(n,r){var u=d(t++,7);return z$1(u.__H,r)?(u.__V=n(),u.i=r,u.__h=n,u.__V):u.__}function T$1(n,t){return o=8,F$1(function(){return n},t)}function q$1(n){var u=r.context[n.__c],i=d(t++,9);return i.c=n,u?(null==i.__&&(i.__=!0,u.sub(r)),u.props.value):n.__}function x$1(t,r){l$1.useDebugValue&&l$1.useDebugValue(r?r(t):t);}function V$1(){var n=d(t++,11);if(!n.__){for(var u=r.__v;null!==u&&!u.__m&&null!==u.__;)u=u.__;var i=u.__m||(u.__m=[0,0]);n.__="P"+i[0]+"-"+i[1]++;}return n.__}function b(){for(var t;t=f.shift();)if(t.__P&&t.__H)try{t.__H.__h.forEach(k$1),t.__H.__h.forEach(w$1),t.__H.__h=[];}catch(r){t.__H.__h=[],l$1.__e(r,t.__v);}}l$1.__b=function(n){r=null,e&&e(n);},l$1.__r=function(n){a&&a(n),t=0;var i=(r=n.__c).__H;i&&(u===r?(i.__h=[],r.__h=[],i.__.forEach(function(n){n.__N&&(n.__=n.__N),n.__V=c,n.__N=n.i=void 0;})):(i.__h.forEach(k$1),i.__h.forEach(w$1),i.__h=[],t=0)),u=r;},l$1.diffed=function(t){v&&v(t);var o=t.__c;o&&o.__H&&(o.__H.__h.length&&(1!==f.push(o)&&i===l$1.requestAnimationFrame||((i=l$1.requestAnimationFrame)||j$1)(b)),o.__H.__.forEach(function(n){n.i&&(n.__H=n.i),n.__V!==c&&(n.__=n.__V),n.i=void 0,n.__V=c;})),u=r=null;},l$1.__c=function(t,r){r.some(function(t){try{t.__h.forEach(k$1),t.__h=t.__h.filter(function(n){return !n.__||w$1(n)});}catch(u){r.some(function(n){n.__h&&(n.__h=[]);}),r=[],l$1.__e(u,t.__v);}}),l&&l(t,r);},l$1.unmount=function(t){m&&m(t);var r,u=t.__c;u&&u.__H&&(u.__H.__.forEach(function(n){try{k$1(n);}catch(n){r=n;}}),u.__H=void 0,r&&l$1.__e(r,u.__v));};var g$1="function"==typeof requestAnimationFrame;function j$1(n){var t,r=function(){clearTimeout(u),g$1&&cancelAnimationFrame(t),setTimeout(n);},u=setTimeout(r,100);g$1&&(t=requestAnimationFrame(r));}function k$1(n){var t=r,u=n.__c;"function"==typeof u&&(n.__c=void 0,u()),r=t;}function w$1(n){var t=r;n.__c=n.__(),r=t;}function z$1(n,t){return !n||n.length!==t.length||t.some(function(t,r){return t!==n[r]})}function B$1(n,t){return "function"==typeof t?t(n):t}
- function g(n,t){for(var e in t)n[e]=t[e];return n}function C(n,t){for(var e in n)if("__source"!==e&&!(e in t))return !0;for(var r in t)if("__source"!==r&&n[r]!==t[r])return !0;return !1}function E(n,t){return n===t&&(0!==n||1/n==1/t)||n!=n&&t!=t}function w(n){this.props=n;}function x(n,e){function r(n){var t=this.props.ref,r=t==n.ref;return !r&&t&&(t.call?t(null):t.current=null),e?!e(this.props,n)||!r:C(this.props,n)}function u(e){return this.shouldComponentUpdate=r,y$1(n,e)}return u.displayName="Memo("+(n.displayName||n.name)+")",u.prototype.isReactComponent=!0,u.__f=!0,u}(w.prototype=new b$1).isPureReactComponent=!0,w.prototype.shouldComponentUpdate=function(n,t){return C(this.props,n)||C(this.state,t)};var R=l$1.__b;l$1.__b=function(n){n.type&&n.type.__f&&n.ref&&(n.props.ref=n.ref,n.ref=null),R&&R(n);};var N="undefined"!=typeof Symbol&&Symbol.for&&Symbol.for("react.forward_ref")||3911;function k(n){function t(t){var e=g({},t);return delete e.ref,n(e,t.ref||null)}return t.$$typeof=N,t.render=t,t.prototype.isReactComponent=t.__f=!0,t.displayName="ForwardRef("+(n.displayName||n.name)+")",t}var A=function(n,t){return null==n?null:C$1(C$1(n).map(t))},O={map:A,forEach:A,count:function(n){return n?C$1(n).length:0},only:function(n){var t=C$1(n);if(1!==t.length)throw "Children.only";return t[0]},toArray:C$1},T=l$1.__e;l$1.__e=function(n,t,e,r){if(n.then)for(var u,o=t;o=o.__;)if((u=o.__c)&&u.__c)return null==t.__e&&(t.__e=e.__e,t.__k=e.__k),u.__c(n,t);T(n,t,e,r);};var F=l$1.unmount;function I(n,t,e){return n&&(n.__c&&n.__c.__H&&(n.__c.__H.__.forEach(function(n){"function"==typeof n.__c&&n.__c();}),n.__c.__H=null),null!=(n=g({},n)).__c&&(n.__c.__P===e&&(n.__c.__P=t),n.__c=null),n.__k=n.__k&&n.__k.map(function(n){return I(n,t,e)})),n}function L(n,t,e){return n&&(n.__v=null,n.__k=n.__k&&n.__k.map(function(n){return L(n,t,e)}),n.__c&&n.__c.__P===t&&(n.__e&&e.insertBefore(n.__e,n.__d),n.__c.__e=!0,n.__c.__P=e)),n}function U(){this.__u=0,this.t=null,this.__b=null;}function D(n){var t=n.__.__c;return t&&t.__a&&t.__a(n)}function M(n){var e,r,u;function o(o){if(e||(e=n()).then(function(n){r=n.default||n;},function(n){u=n;}),u)throw u;if(!r)throw e;return y$1(r,o)}return o.displayName="Lazy",o.__f=!0,o}function V(){this.u=null,this.o=null;}l$1.unmount=function(n){var t=n.__c;t&&t.__R&&t.__R(),t&&!0===n.__h&&(n.type=null),F&&F(n);},(U.prototype=new b$1).__c=function(n,t){var e=t.__c,r=this;null==r.t&&(r.t=[]),r.t.push(e);var u=D(r.__v),o=!1,i=function(){o||(o=!0,e.__R=null,u?u(l):l());};e.__R=i;var l=function(){if(!--r.__u){if(r.state.__a){var n=r.state.__a;r.__v.__k[0]=L(n,n.__c.__P,n.__c.__O);}var t;for(r.setState({__a:r.__b=null});t=r.t.pop();)t.forceUpdate();}},c=!0===t.__h;r.__u++||c||r.setState({__a:r.__b=r.__v.__k[0]}),n.then(i,i);},U.prototype.componentWillUnmount=function(){this.t=[];},U.prototype.render=function(n,e){if(this.__b){if(this.__v.__k){var r=document.createElement("div"),o=this.__v.__k[0].__c;this.__v.__k[0]=I(this.__b,r,o.__O=o.__P);}this.__b=null;}var i=e.__a&&y$1(k$2,null,n.fallback);return i&&(i.__h=null),[y$1(k$2,null,e.__a?null:n.children),i]};var W=function(n,t,e){if(++e[1]===e[0]&&n.o.delete(t),n.props.revealOrder&&("t"!==n.props.revealOrder[0]||!n.o.size))for(e=n.u;e;){for(;e.length>3;)e.pop()();if(e[1]<e[0])break;n.u=e=e[2];}};function P(n){return this.getChildContext=function(){return n.context},n.children}function j(n){var e=this,r=n.i;e.componentWillUnmount=function(){D$1(null,e.l),e.l=null,e.i=null;},e.i&&e.i!==r&&e.componentWillUnmount(),e.l||(e.i=r,e.l={nodeType:1,parentNode:r,childNodes:[],appendChild:function(n){this.childNodes.push(n),e.i.appendChild(n);},insertBefore:function(n,t){this.childNodes.push(n),e.i.appendChild(n);},removeChild:function(n){this.childNodes.splice(this.childNodes.indexOf(n)>>>1,1),e.i.removeChild(n);}}),D$1(y$1(P,{context:e.context},n.__v),e.l);}function z(n,e){var r=y$1(j,{__v:n,i:e});return r.containerInfo=e,r}(V.prototype=new b$1).__a=function(n){var t=this,e=D(t.__v),r=t.o.get(n);return r[0]++,function(u){var o=function(){t.props.revealOrder?(r.push(u),W(t,n,r)):u();};e?e(o):o();}},V.prototype.render=function(n){this.u=null,this.o=new Map;var t=C$1(n.children);n.revealOrder&&"b"===n.revealOrder[0]&&t.reverse();for(var e=t.length;e--;)this.o.set(t[e],this.u=[1,0,this.u]);return n.children},V.prototype.componentDidUpdate=V.prototype.componentDidMount=function(){var n=this;this.o.forEach(function(t,e){W(n,e,t);});};var B="undefined"!=typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103,H=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,Z=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,Y=/[A-Z0-9]/g,$="undefined"!=typeof document,q=function(n){return ("undefined"!=typeof Symbol&&"symbol"==typeof Symbol()?/fil|che|rad/:/fil|che|ra/).test(n)};function G(n,t,e){return null==t.__k&&(t.textContent=""),D$1(n,t),"function"==typeof e&&e(),n?n.__c:null}function J(n,t,e){return E$1(n,t),"function"==typeof e&&e(),n?n.__c:null}b$1.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(t){Object.defineProperty(b$1.prototype,t,{configurable:!0,get:function(){return this["UNSAFE_"+t]},set:function(n){Object.defineProperty(this,t,{configurable:!0,writable:!0,value:n});}});});var K=l$1.event;function Q(){}function X(){return this.cancelBubble}function nn(){return this.defaultPrevented}l$1.event=function(n){return K&&(n=K(n)),n.persist=Q,n.isPropagationStopped=X,n.isDefaultPrevented=nn,n.nativeEvent=n};var tn,en={enumerable:!1,configurable:!0,get:function(){return this.class}},rn=l$1.vnode;l$1.vnode=function(n){"string"==typeof n.type&&function(n){var t=n.props,e=n.type,u={};for(var o in t){var i=t[o];if(!("value"===o&&"defaultValue"in t&&null==i||$&&"children"===o&&"noscript"===e||"class"===o||"className"===o)){var l=o.toLowerCase();"defaultValue"===o&&"value"in t&&null==t.value?o="value":"download"===o&&!0===i?i="":"ondoubleclick"===l?o="ondblclick":"onchange"!==l||"input"!==e&&"textarea"!==e||q(t.type)?"onfocus"===l?o="onfocusin":"onblur"===l?o="onfocusout":Z.test(o)?o=l:-1===e.indexOf("-")&&H.test(o)?o=o.replace(Y,"-$&").toLowerCase():null===i&&(i=void 0):l=o="oninput","oninput"===l&&u[o=l]&&(o="oninputCapture"),u[o]=i;}}"select"==e&&u.multiple&&Array.isArray(u.value)&&(u.value=C$1(t.children).forEach(function(n){n.props.selected=-1!=u.value.indexOf(n.props.value);})),"select"==e&&null!=u.defaultValue&&(u.value=C$1(t.children).forEach(function(n){n.props.selected=u.multiple?-1!=u.defaultValue.indexOf(n.props.value):u.defaultValue==n.props.value;})),t.class&&!t.className?(u.class=t.class,Object.defineProperty(u,"className",en)):(t.className&&!t.class||t.class&&t.className)&&(u.class=u.className=t.className),n.props=u;}(n),n.$$typeof=B,rn&&rn(n);};var un=l$1.__r;l$1.__r=function(n){un&&un(n),tn=n.__c;};var on=l$1.diffed;l$1.diffed=function(n){on&&on(n);var t=n.props,e=n.__e;null!=e&&"textarea"===n.type&&"value"in t&&t.value!==e.value&&(e.value=null==t.value?"":t.value),tn=null;};var ln={ReactCurrentDispatcher:{current:{readContext:function(n){return tn.__n[n.__c].props.value}}}};function fn(n){return y$1.bind(null,n)}function an(n){return !!n&&n.$$typeof===B}function sn(n){return an(n)&&n.type===k$2}function hn(n){return an(n)?F$2.apply(null,arguments):n}function vn(n){return !!n.__k&&(D$1(null,n),!0)}function dn(n){return n&&(n.base||1===n.nodeType&&n)||null}var pn=function(n,t){return n(t)},mn=function(n,t){return n(t)},yn=k$2;function _n(n){n();}function bn(n){return n}function Sn(){return [!1,_n]}var gn=y,Cn=an;function En(n,t){var e=t(),r=h({h:{__:e,v:t}}),u=r[0].h,o=r[1];return y(function(){u.__=e,u.v=t,E(u.__,t())||o({h:u});},[n,e,t]),p(function(){return E(u.__,u.v())||o({h:u}),n(function(){E(u.__,u.v())||o({h:u});})},[n]),e}var wn={useState:h,useId:V$1,useReducer:s,useEffect:p,useLayoutEffect:y,useInsertionEffect:gn,useTransition:Sn,useDeferredValue:bn,useSyncExternalStore:En,startTransition:_n,useRef:_,useImperativeHandle:A$1,useMemo:F$1,useCallback:T$1,useContext:q$1,useDebugValue:x$1,version:"17.0.2",Children:O,render:G,hydrate:J,unmountComponentAtNode:vn,createPortal:z,createElement:y$1,createContext:G$1,createFactory:fn,cloneElement:hn,createRef:_$1,Fragment:k$2,isValidElement:an,isElement:Cn,isFragment:sn,findDOMNode:dn,Component:b$1,PureComponent:w,memo:x,forwardRef:k,flushSync:mn,unstable_batchedUpdates:pn,StrictMode:yn,Suspense:U,SuspenseList:V,lazy:M,__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:ln};
- const IMAGE_EXTENSIONS = Object.freeze(new Set([
- ".tif",
- ".tiff",
- ".gif",
- ".png",
- ".apng",
- ".avif",
- ".jpg",
- ".jpeg",
- ".jfif",
- ".pjepg",
- ".pjp",
- ".svg",
- ".webp",
- ".bmp",
- ".ico",
- ".cur",
- ]));
- function isImageEmbed(link) {
- if (!link.path.contains("."))
- return false;
- let extension = link.path.substring(link.path.lastIndexOf("."));
- return link.type == "file" && link.embed && IMAGE_EXTENSIONS.has(extension);
- }
- function extractImageDimensions(link) {
- if (!link.display)
- return undefined;
- let match = /^(\d+)x(\d+)$/iu.exec(link.display);
- if (match)
- return [parseInt(match[1]), parseInt(match[2])];
- let match2 = /^(\d+)/.exec(link.display);
- if (match2)
- return [parseInt(match2[1])];
-
- return undefined;
- }
- const DataviewContext = G$1(undefined);
- function RawMarkdown({ content, sourcePath, inline = true, style, cls, onClick, }) {
- const container = _(null);
- const component = q$1(DataviewContext).component;
- p(() => {
- if (!container.current)
- return;
- container.current.innerHTML = "";
- obsidian.MarkdownRenderer.renderMarkdown(content, container.current, sourcePath, component).then(() => {
- if (!container.current || !inline)
- return;
-
- let paragraph = container.current.querySelector("p");
- while (paragraph) {
- let children = paragraph.childNodes;
- paragraph.replaceWith(...Array.from(children));
- paragraph = container.current.querySelector("p");
- }
- });
- }, [content, sourcePath, container.current]);
- return y$1("span", { ref: container, style: style, class: cls, onClick: onClick });
- }
- const Markdown = wn.memo(RawMarkdown);
- function RawEmbedHtml({ element }) {
- const container = _(null);
- p(() => {
- if (!container.current)
- return;
- container.current.innerHTML = "";
- container.current.appendChild(element);
- }, [container.current, element]);
- return y$1("span", { ref: container });
- }
- const EmbedHtml = wn.memo(RawEmbedHtml);
- function RawLit({ value, sourcePath, inline = false, depth = 0, }) {
- const context = q$1(DataviewContext);
-
- if (depth >= context.settings.maxRecursiveRenderDepth)
- return y$1(k$2, null, "...");
- if (Values.isNull(value) || value === undefined) {
- return y$1(Markdown, { content: context.settings.renderNullAs, sourcePath: sourcePath });
- }
- else if (Values.isString(value)) {
- return y$1(Markdown, { content: value, sourcePath: sourcePath });
- }
- else if (Values.isNumber(value)) {
- return y$1(k$2, null, "" + value);
- }
- else if (Values.isBoolean(value)) {
- return y$1(k$2, null, "" + value);
- }
- else if (Values.isDate(value)) {
- return y$1(k$2, null, renderMinimalDate(value, context.settings, currentLocale()));
- }
- else if (Values.isDuration(value)) {
- return y$1(k$2, null, renderMinimalDuration(value));
- }
- else if (Values.isLink(value)) {
-
- if (isImageEmbed(value)) {
- let realFile = context.app.metadataCache.getFirstLinkpathDest(value.path, sourcePath);
- if (!realFile)
- return y$1(Markdown, { content: value.markdown(), sourcePath: sourcePath });
- let dimensions = extractImageDimensions(value);
- let resourcePath = context.app.vault.getResourcePath(realFile);
- if (dimensions && dimensions.length == 2)
- return y$1("img", { alt: value.path, src: resourcePath, width: dimensions[0], height: dimensions[1] });
- else if (dimensions && dimensions.length == 1)
- return y$1("img", { alt: value.path, src: resourcePath, width: dimensions[0] });
- else
- return y$1("img", { alt: value.path, src: resourcePath });
- }
- return y$1(Markdown, { content: value.markdown(), sourcePath: sourcePath });
- }
- else if (Values.isHtml(value)) {
- return y$1(EmbedHtml, { element: value });
- }
- else if (Values.isWidget(value)) {
- if (Widgets.isListPair(value)) {
- return (y$1(k$2, null,
- y$1(Lit, { value: value.key, sourcePath: sourcePath }),
- ":",
- " ",
- y$1(Lit, { value: value.value, sourcePath: sourcePath })));
- }
- else if (Widgets.isExternalLink(value)) {
- return (y$1("a", { href: value.url, rel: "noopener", target: "_blank", class: "external-link" }, value.display ?? value.url));
- }
- else {
- return y$1("b", null,
- "<unknown widget '",
- value.$widget,
- "'>");
- }
- }
- else if (Values.isFunction(value)) {
- return y$1(k$2, null, "<function>");
- }
- else if (Values.isArray(value) || DataArray.isDataArray(value)) {
- if (!inline) {
- return (y$1("ul", { class: "dataview dataview-ul dataview-result-list-ul" }, value.map(subvalue => (y$1("li", { class: "dataview-result-list-li" },
- y$1(Lit, { value: subvalue, sourcePath: sourcePath, inline: inline, depth: depth + 1 }))))));
- }
- else {
- if (value.length == 0)
- return y$1(k$2, null, "<Empty List>");
- return (y$1("span", { class: "dataview dataview-result-list-span" }, value.map((subvalue, index) => (y$1(k$2, null,
- index == 0 ? "" : ", ",
- y$1(Lit, { value: subvalue, sourcePath: sourcePath, inline: inline, depth: depth + 1 }))))));
- }
- }
- else if (Values.isObject(value)) {
-
- if (value?.constructor?.name && value?.constructor?.name != "Object") {
- return y$1(k$2, null,
- "<",
- value.constructor.name,
- ">");
- }
- if (!inline) {
- return (y$1("ul", { class: "dataview dataview-ul dataview-result-object-ul" }, Object.entries(value).map(([key, value]) => (y$1("li", { class: "dataview dataview-li dataview-result-object-li" },
- key,
- ": ",
- y$1(Lit, { value: value, sourcePath: sourcePath, inline: inline, depth: depth + 1 }))))));
- }
- else {
- if (Object.keys(value).length == 0)
- return y$1(k$2, null, "<Empty Object>");
- return (y$1("span", { class: "dataview dataview-result-object-span" }, Object.entries(value).map(([key, value], index) => (y$1(k$2, null,
- index == 0 ? "" : ", ",
- key,
- ": ",
- y$1(Lit, { value: value, sourcePath: sourcePath, inline: inline, depth: depth + 1 }))))));
- }
- }
- return y$1(k$2, null,
- "<Unrecognized: ",
- JSON.stringify(value),
- ">");
- }
- const Lit = wn.memo(RawLit);
- function ErrorPre(props, {}) {
- return y$1("pre", { class: "dataview dataview-error" }, props.children);
- }
- function ErrorMessage({ message }) {
- return (y$1("div", { class: "dataview dataview-error-box" },
- y$1("p", { class: "dataview dataview-error-message" }, message)));
- }
- function useIndexBackedState(container, app, settings, index, initial, compute) {
- let [initialized, setInitialized] = h(false);
- let [state, updateState] = h(initial);
- let [lastReload, setLastReload] = h(index.revision);
-
- if (!initialized) {
- setLastReload(index.revision);
- setInitialized(true);
- compute().then(updateState);
- }
-
- p(() => {
- const refreshOperation = () => {
- if (lastReload != index.revision && container.isShown() && settings.refreshEnabled) {
- compute().then(updateState);
- setLastReload(index.revision);
- }
- };
-
- let workEvent = app.workspace.on("dataview:refresh-views", refreshOperation);
-
- let nodeEvent = container.onNodeInserted(refreshOperation);
- return () => {
- app.workspace.offref(workEvent);
- nodeEvent();
- };
- }, [container, lastReload]);
- return state;
- }
- class ReactRenderer extends obsidian.MarkdownRenderChild {
- init;
- element;
- constructor(init, element) {
- super(init.container);
- this.init = init;
- this.element = element;
- }
- onload() {
- const context = Object.assign({}, { component: this }, this.init);
- D$1(y$1(DataviewContext.Provider, { value: context }, this.element), this.containerEl);
- }
- onunload() {
- vn(this.containerEl);
- }
- }
- function wasLinkPressed(evt) {
- return evt.target != null && evt.target != undefined && evt.target.tagName == "A";
- }
- function TaskItem({ item }) {
- let context = q$1(DataviewContext);
-
- const onClicked = (evt) => {
- if (wasLinkPressed(evt)) {
- return;
- }
- evt.stopPropagation();
- const selectionState = {
- eState: {
- cursor: {
- from: { line: item.line, ch: item.position.start.col },
- to: { line: item.line + item.lineCount - 1, ch: item.position.end.col },
- },
- line: item.line,
- },
- };
-
- context.app.workspace.openLinkText(item.link.toFile().obsidianLink(), item.path, evt.ctrlKey || (evt.metaKey && obsidian.Platform.isMacOS), selectionState);
- };
-
- const onChecked = (evt) => {
- evt.stopPropagation();
- const completed = evt.currentTarget.checked;
- const status = completed ? "x" : " ";
-
- const parent = evt.currentTarget.parentElement;
- parent?.setAttribute("data-task", status);
- let flatted = [item];
- if (context.settings.recursiveSubTaskCompletion) {
- function flatter(iitem) {
- flatted.push(iitem);
- iitem.children.forEach(flatter);
- }
- item.children.forEach(flatter);
- flatted = flatted.flat(Infinity);
- }
- async function effectFn() {
- for (let i = 0; i < flatted.length; i++) {
- const _item = flatted[i];
- let updatedText = _item.text;
- if (context.settings.taskCompletionTracking) {
- updatedText = setTaskCompletion(_item.text, context.settings.taskCompletionUseEmojiShorthand, context.settings.taskCompletionText, context.settings.taskCompletionDateFormat, completed);
- }
- await rewriteTask(context.app.vault, _item, status, updatedText);
- }
- context.app.workspace.trigger("dataview:refresh-views");
- }
- effectFn();
- };
- const checked = item.status !== " ";
- return (y$1("li", { class: "dataview task-list-item" + (checked ? " is-checked" : ""), onClick: onClicked, "data-task": item.status },
- y$1("input", { class: "dataview task-list-item-checkbox", type: "checkbox", checked: checked, onClick: onChecked }),
- y$1(Markdown, { inline: true, content: item.visual ?? item.text, sourcePath: item.path }),
- item.children.length > 0 && y$1(TaskList, { items: item.children })));
- }
- function ListItem({ item }) {
- let context = q$1(DataviewContext);
-
- const onClicked = (evt) => {
- if (wasLinkPressed(evt)) {
- return;
- }
- evt.stopPropagation();
- const selectionState = {
- eState: {
- cursor: {
- from: { line: item.line, ch: item.position.start.col },
- to: { line: item.line + item.lineCount - 1, ch: item.position.end.col },
- },
- line: item.line,
- },
- };
-
- context.app.workspace.openLinkText(item.link.toFile().obsidianLink(), item.path, evt.ctrlKey || (evt.metaKey && obsidian.Platform.isMacOS), selectionState);
- };
- return (y$1("li", { class: "dataview task-list-basic-item", onClick: onClicked },
- y$1(Markdown, { inline: true, content: item.visual ?? item.text, sourcePath: item.path }),
- item.children.length > 0 && y$1(TaskList, { items: item.children })));
- }
- function TaskList({ items }) {
- const settings = q$1(DataviewContext).settings;
- if (items.length == 0 && settings.warnOnEmptyResult)
- return y$1(ErrorMessage, { message: "Dataview: No results to show for task query." });
- let [nest, _mask] = nestItems(items);
- return (y$1("ul", { class: "contains-task-list" }, nest.map(item => item.task ? y$1(TaskItem, { key: listId(item), item: item }) : y$1(ListItem, { key: listId(item), item: item }))));
- }
- function ResultCount$1(props) {
- const { settings } = q$1(DataviewContext);
- return settings.showResultCount ? (y$1("span", { class: "dataview small-text" }, Groupings.count(props.item.rows))) : (y$1(k$2, null));
- }
- function TaskGrouping({ items, sourcePath }) {
- const isGrouping = items.length > 0 && Groupings.isGrouping(items);
- return (y$1(k$2, null,
- isGrouping &&
- items.map(item => (y$1(k$2, { key: item.key },
- y$1("h4", null,
- y$1(Lit, { value: item.key, sourcePath: sourcePath }),
- y$1(ResultCount$1, { item: item })),
- y$1("div", { class: "dataview result-group" },
- y$1(TaskGrouping, { items: item.rows, sourcePath: sourcePath }))))),
- !isGrouping && y$1(TaskList, { items: items })));
- }
- function TaskView({ query, sourcePath }) {
- let context = q$1(DataviewContext);
- let items = useIndexBackedState(context.container, context.app, context.settings, context.index, { state: "loading" }, async () => {
- let result = await asyncTryOrPropogate(() => executeTask(query, sourcePath, context.index, context.settings));
- if (!result.successful)
- return { state: "error", error: result.error, sourcePath };
- else
- return { state: "ready", items: result.value.tasks };
- });
- if (items.state == "loading")
- return (y$1(k$2, null,
- y$1(ErrorPre, null, "Loading")));
- else if (items.state == "error")
- return (y$1(k$2, null,
- y$1(ErrorPre, null,
- "Dataview: ",
- items.error)));
- return (y$1("div", { class: "dataview dataview-container" },
- y$1(TaskGrouping, { items: items.items, sourcePath: sourcePath })));
- }
- function createTaskView(init, query, sourcePath) {
- return new ReactRenderer(init, y$1(TaskView, { query: query, sourcePath: sourcePath }));
- }
- function createFixedTaskView(init, items, sourcePath) {
- return new ReactRenderer(init, y$1(TaskGrouping, { items: items, sourcePath: sourcePath }));
- }
- function listId(item) {
- return item.path + ":" + item.line;
- }
- function parentListId(item) {
- return item.path + ":" + item.parent;
- }
- function enumerateChildren(item, output) {
- if (!output.has(listId(item)))
- output.set(listId(item), item);
- for (let child of item.children)
- enumerateChildren(child, output);
- return output;
- }
- function replaceChildren(elements, lookup) {
- return elements.map(element => {
- element.children = replaceChildren(element.children, lookup);
- const id = listId(element);
- const map = lookup.get(id);
- if (map)
- return map;
- else
- return element;
- });
- }
- function nestItems(raw) {
- let elements = new Map();
- let mask = new Set();
- for (let elem of raw) {
- let id = listId(elem);
- elements.set(id, elem);
- mask.add(id);
- }
-
- for (let elem of raw)
- enumerateChildren(elem, elements);
- let roots = raw.filter(elem => elem.parent == undefined || elem.parent == null || !elements.has(parentListId(elem)));
- return [replaceChildren(roots, elements), mask];
- }
- function nestGroups(raw) {
- if (Groupings.isGrouping(raw)) {
- return raw.map(g => {
- return { key: g.key, rows: nestGroups(g.rows) };
- });
- }
- else {
- return nestItems(raw)[0];
- }
- }
- function trimEndingLines(text) {
- let parts = text.split(/\r?\n/u);
- let trim = parts.length - 1;
- while (trim > 0 && parts[trim].trim() == "")
- trim--;
- return parts.join("\n");
- }
- function setTaskCompletion(originalText, useEmojiShorthand, completionKey, completionDateFormat, complete) {
- const blockIdRegex = /\^[a-z0-9\-]+/i;
- if (!complete && !useEmojiShorthand)
- return trimEndingLines(setInlineField(originalText.trimEnd(), completionKey)).trimEnd();
- let parts = originalText.split(/\r?\n/u);
- const matches = blockIdRegex.exec(parts[parts.length - 1]);
- console.debug("matchreg", matches);
- let processedPart = parts[parts.length - 1].split(blockIdRegex).join("");
- if (useEmojiShorthand) {
- processedPart = setEmojiShorthandCompletionField(processedPart, complete ? DateTime.now().toFormat("yyyy-MM-dd") : "");
- }
- else {
- processedPart = setInlineField(processedPart, completionKey, DateTime.now().toFormat(completionDateFormat));
- }
- processedPart = `${processedPart.trimEnd()}${matches?.length ? " " + matches[0].trim() : ""}`.trimEnd();
- parts[parts.length - 1] = processedPart;
- return parts.join("\n");
- }
- async function rewriteTask(vault, task, desiredStatus, desiredText) {
- if (desiredStatus == task.status && (desiredText == undefined || desiredText == task.text))
- return;
- desiredStatus = desiredStatus == "" ? " " : desiredStatus;
- let rawFiletext = await vault.adapter.read(task.path);
- let hasRN = rawFiletext.contains("\r");
- let filetext = rawFiletext.split(/\r?\n/u);
- if (filetext.length < task.line)
- return;
- let match = LIST_ITEM_REGEX.exec(filetext[task.line]);
- if (!match || match[2].length == 0)
- return;
- let taskTextParts = task.text.split("\n");
- if (taskTextParts[0].trim() != match[3].trim())
- return;
-
- let initialSpacing = /^[\s>]*/u.exec(filetext[task.line])[0];
- if (desiredText) {
- let desiredParts = desiredText.split("\n");
- let newTextLines = [`${initialSpacing}${task.symbol} [${desiredStatus}] ${desiredParts[0]}`].concat(desiredParts.slice(1).map(l => initialSpacing + "\t" + l));
- filetext.splice(task.line, task.lineCount, ...newTextLines);
- }
- else {
- filetext[task.line] = `${initialSpacing}${task.symbol} [${desiredStatus}] ${taskTextParts[0].trim()}`;
- }
- let newText = filetext.join(hasRN ? "\r\n" : "\n");
- await vault.adapter.write(task.path, newText);
- }
- function ListGrouping({ items, sourcePath }) {
- return (y$1("ul", { class: "dataview list-view-ul" }, items.map(item => (y$1("li", null,
- y$1(Lit, { value: item, sourcePath: sourcePath }))))));
- }
- function ListView({ query, sourcePath }) {
- let context = q$1(DataviewContext);
- let items = useIndexBackedState(context.container, context.app, context.settings, context.index, { state: "loading" }, async () => {
- let result = await asyncTryOrPropogate(() => executeList(query, context.index, sourcePath, context.settings));
- if (!result.successful)
- return { state: "error", error: result.error, sourcePath };
- return { state: "ready", items: result.value.data };
- });
- if (items.state == "loading")
- return (y$1(k$2, null,
- y$1(ErrorPre, null, "Loading...")));
- else if (items.state == "error")
- return (y$1(k$2, null,
- " ",
- y$1(ErrorPre, null,
- "Dataview: ",
- items.error),
- " "));
- if (items.items.length == 0 && context.settings.warnOnEmptyResult)
- return y$1(ErrorMessage, { message: "Dataview: No results to show for list query." });
- return y$1(ListGrouping, { items: items.items, sourcePath: sourcePath });
- }
- function createListView(init, query, sourcePath) {
- return new ReactRenderer(init, y$1(ListView, { query: query, sourcePath: sourcePath }));
- }
- function createFixedListView(init, elements, sourcePath) {
- return new ReactRenderer(init, y$1(ListGrouping, { items: elements, sourcePath: sourcePath }));
- }
- function ResultCount(props) {
- const { settings } = q$1(DataviewContext);
- return settings.showResultCount ? y$1("span", { class: "dataview small-text" }, props.length) : y$1(k$2, null);
- }
- function TableGrouping({ headings, values, sourcePath, }) {
- let settings = q$1(DataviewContext).settings;
- return (y$1(k$2, null,
- y$1("table", { class: "dataview table-view-table" },
- y$1("thead", { class: "table-view-thead" },
- y$1("tr", { class: "table-view-tr-header" }, headings.map((heading, index) => (y$1("th", { class: "table-view-th" },
- y$1(Markdown, { sourcePath: sourcePath, content: heading }),
- index == 0 && y$1(ResultCount, { length: values.length })))))),
- y$1("tbody", { class: "table-view-tbody" }, values.map(row => (y$1("tr", null, row.map(element => (y$1("td", null,
- y$1(Lit, { value: element, sourcePath: sourcePath }))))))))),
- settings.warnOnEmptyResult && values.length == 0 && (y$1(ErrorMessage, { message: "Dataview: No results to show for table query." }))));
- }
- function TableView({ query, sourcePath }) {
- let context = q$1(DataviewContext);
- let items = useIndexBackedState(context.container, context.app, context.settings, context.index, { state: "loading" }, async () => {
- let result = await asyncTryOrPropogate(() => executeTable(query, context.index, sourcePath, context.settings));
- if (!result.successful)
- return { state: "error", error: result.error };
- return { state: "ready", headings: result.value.names, values: result.value.data };
- });
- if (items.state == "loading")
- return (y$1(k$2, null,
- y$1(ErrorPre, null, "Loading...")));
- else if (items.state == "error")
- return (y$1(k$2, null,
- " ",
- y$1(ErrorPre, null,
- "Dataview: ",
- items.error),
- " "));
- return y$1(TableGrouping, { headings: items.headings, values: items.values, sourcePath: sourcePath });
- }
- function createTableView(init, query, sourcePath) {
- return new ReactRenderer(init, y$1(TableView, { query: query, sourcePath: sourcePath }));
- }
- function createFixedTableView(init, headings, values, sourcePath) {
- return new ReactRenderer(init, y$1(TableGrouping, { values: values, headings: headings, sourcePath: sourcePath }));
- }
- var QueryFields;
- (function (QueryFields) {
- function named(name, field) {
- return { name, field };
- }
- QueryFields.named = named;
- function sortBy(field, dir) {
- return { field, direction: dir };
- }
- QueryFields.sortBy = sortBy;
- })(QueryFields || (QueryFields = {}));
- function captureRaw(base) {
- return parsimmon_umd_minExports.custom((success, failure) => {
- return (input, i) => {
- let result = base._(input, i);
- if (!result.status)
- return result;
- return Object.assign({}, result, { value: [result.value, input.substring(i, result.index)] });
- };
- });
- }
- function stripNewlines(text) {
- return text
- .split(/[\r\n]+/)
- .map(t => t.trim())
- .join("");
- }
- function precededByWhitespaceIfNotEof(if_eof, parser) {
- return parsimmon_umd_minExports.eof.map(if_eof).or(parsimmon_umd_minExports.whitespace.then(parser));
- }
- const QUERY_LANGUAGE = parsimmon_umd_minExports.createLanguage({
-
- queryType: q => parsimmon_umd_minExports.alt(parsimmon_umd_minExports.regexp(/TABLE|LIST|TASK|CALENDAR/i))
- .map(str => str.toLowerCase())
- .desc("query type ('TABLE', 'LIST', 'TASK', or 'CALENDAR')"),
- explicitNamedField: q => parsimmon_umd_minExports.seqMap(EXPRESSION.field.skip(parsimmon_umd_minExports.whitespace), parsimmon_umd_minExports.regexp(/AS/i).skip(parsimmon_umd_minExports.whitespace), EXPRESSION.identifier.or(EXPRESSION.string), (field, _as, ident) => QueryFields.named(ident, field)),
- comment: () => parsimmon_umd_minExports.Parser((input, i) => {
-
- let line = input.substring(i);
- if (!line.startsWith("//"))
- return parsimmon_umd_minExports.makeFailure(i, "Not a comment");
-
- line = line.split("\n")[0];
- let comment = line.substring(2).trim();
- return parsimmon_umd_minExports.makeSuccess(i + line.length, comment);
- }),
- namedField: q => parsimmon_umd_minExports.alt(q.explicitNamedField, captureRaw(EXPRESSION.field).map(([value, text]) => QueryFields.named(stripNewlines(text), value))),
- sortField: q => parsimmon_umd_minExports.seqMap(EXPRESSION.field.skip(parsimmon_umd_minExports.optWhitespace), parsimmon_umd_minExports.regexp(/ASCENDING|DESCENDING|ASC|DESC/i).atMost(1), (field, dir) => {
- let direction = dir.length == 0 ? "ascending" : dir[0].toLowerCase();
- if (direction == "desc")
- direction = "descending";
- if (direction == "asc")
- direction = "ascending";
- return {
- field: field,
- direction: direction,
- };
- }),
- headerClause: q => q.queryType
- .chain(type => {
- switch (type) {
- case "table": {
- return precededByWhitespaceIfNotEof(() => ({ type, fields: [], showId: true }), parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/WITHOUT\s+ID/i)
- .skip(parsimmon_umd_minExports.optWhitespace)
- .atMost(1), parsimmon_umd_minExports.sepBy(q.namedField, parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace)), (withoutId, fields) => {
- return { type, fields, showId: withoutId.length == 0 };
- }));
- }
- case "list":
- return precededByWhitespaceIfNotEof(() => ({ type, format: undefined, showId: true }), parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/WITHOUT\s+ID/i)
- .skip(parsimmon_umd_minExports.optWhitespace)
- .atMost(1), EXPRESSION.field.atMost(1), (withoutId, format) => {
- return {
- type,
- format: format.length == 1 ? format[0] : undefined,
- showId: withoutId.length == 0,
- };
- }));
- case "task":
- return parsimmon_umd_minExports.succeed({ type });
- case "calendar":
- return parsimmon_umd_minExports.whitespace.then(parsimmon_umd_minExports.seqMap(q.namedField, field => {
- return {
- type,
- showId: true,
- field,
- };
- }));
- default:
- return parsimmon_umd_minExports.fail(`Unrecognized query type '${type}'`);
- }
- })
- .desc("TABLE or LIST or TASK or CALENDAR"),
- fromClause: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/FROM/i), parsimmon_umd_minExports.whitespace, EXPRESSION.source, (_1, _2, source) => source),
- whereClause: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/WHERE/i), parsimmon_umd_minExports.whitespace, EXPRESSION.field, (where, _, field) => {
- return { type: "where", clause: field };
- }).desc("WHERE <expression>"),
- sortByClause: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/SORT/i), parsimmon_umd_minExports.whitespace, q.sortField.sepBy1(parsimmon_umd_minExports.string(",").trim(parsimmon_umd_minExports.optWhitespace)), (sort, _1, fields) => {
- return { type: "sort", fields };
- }).desc("SORT field [ASC/DESC]"),
- limitClause: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/LIMIT/i), parsimmon_umd_minExports.whitespace, EXPRESSION.field, (limit, _1, field) => {
- return { type: "limit", amount: field };
- }).desc("LIMIT <value>"),
- flattenClause: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/FLATTEN/i).skip(parsimmon_umd_minExports.whitespace), q.namedField, (_, field) => {
- return { type: "flatten", field };
- }).desc("FLATTEN <value> [AS <name>]"),
- groupByClause: q => parsimmon_umd_minExports.seqMap(parsimmon_umd_minExports.regexp(/GROUP BY/i).skip(parsimmon_umd_minExports.whitespace), q.namedField, (_, field) => {
- return { type: "group", field };
- }).desc("GROUP BY <value> [AS <name>]"),
-
- clause: q => parsimmon_umd_minExports.alt(q.fromClause, q.whereClause, q.sortByClause, q.limitClause, q.groupByClause, q.flattenClause),
- query: q => parsimmon_umd_minExports.seqMap(q.headerClause.trim(optionalWhitespaceOrComment), q.fromClause.trim(optionalWhitespaceOrComment).atMost(1), q.clause.trim(optionalWhitespaceOrComment).many(), (header, from, clauses) => {
- return {
- header,
- source: from.length == 0 ? Sources.folder("") : from[0],
- operations: clauses,
- settings: DEFAULT_QUERY_SETTINGS,
- };
- }),
- });
- const optionalWhitespaceOrComment = parsimmon_umd_minExports.alt(parsimmon_umd_minExports.whitespace, QUERY_LANGUAGE.comment)
- .many()
-
- .map(arr => arr.join(""));
- function parseQuery(text) {
- try {
- let query = QUERY_LANGUAGE.query.tryParse(text);
- return Result.success(query);
- }
- catch (error) {
- return Result.failure("" + error);
- }
- }
- function noop() { }
- function assign(tar, src) {
-
- for (const k in src)
- tar[k] = src[k];
- return tar;
- }
- function is_promise(value) {
- return value && typeof value === 'object' && typeof value.then === 'function';
- }
- function run(fn) {
- return fn();
- }
- function blank_object() {
- return Object.create(null);
- }
- function run_all(fns) {
- fns.forEach(run);
- }
- function is_function(thing) {
- return typeof thing === 'function';
- }
- function safe_not_equal(a, b) {
- return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
- }
- function not_equal(a, b) {
- return a != a ? b == b : a !== b;
- }
- function is_empty(obj) {
- return Object.keys(obj).length === 0;
- }
- function create_slot(definition, ctx, $$scope, fn) {
- if (definition) {
- const slot_ctx = get_slot_context(definition, ctx, $$scope, fn);
- return definition[0](slot_ctx);
- }
- }
- function get_slot_context(definition, ctx, $$scope, fn) {
- return definition[1] && fn
- ? assign($$scope.ctx.slice(), definition[1](fn(ctx)))
- : $$scope.ctx;
- }
- function get_slot_changes(definition, $$scope, dirty, fn) {
- if (definition[2] && fn) {
- const lets = definition[2](fn(dirty));
- if ($$scope.dirty === undefined) {
- return lets;
- }
- if (typeof lets === 'object') {
- const merged = [];
- const len = Math.max($$scope.dirty.length, lets.length);
- for (let i = 0; i < len; i += 1) {
- merged[i] = $$scope.dirty[i] | lets[i];
- }
- return merged;
- }
- return $$scope.dirty | lets;
- }
- return $$scope.dirty;
- }
- function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) {
- const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);
- if (slot_changes) {
- const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);
- slot.p(slot_context, slot_changes);
- }
- }
- function null_to_empty(value) {
- return value == null ? '' : value;
- }
- function append(target, node) {
- target.appendChild(node);
- }
- function insert(target, node, anchor) {
- target.insertBefore(node, anchor || null);
- }
- function detach(node) {
- node.parentNode.removeChild(node);
- }
- function destroy_each(iterations, detaching) {
- for (let i = 0; i < iterations.length; i += 1) {
- if (iterations[i])
- iterations[i].d(detaching);
- }
- }
- function element(name) {
- return document.createElement(name);
- }
- function svg_element(name) {
- return document.createElementNS('http://www.w3.org/2000/svg', name);
- }
- function text(data) {
- return document.createTextNode(data);
- }
- function space() {
- return text(' ');
- }
- function empty() {
- return text('');
- }
- function listen(node, event, handler, options) {
- node.addEventListener(event, handler, options);
- return () => node.removeEventListener(event, handler, options);
- }
- function attr(node, attribute, value) {
- if (value == null)
- node.removeAttribute(attribute);
- else if (node.getAttribute(attribute) !== value)
- node.setAttribute(attribute, value);
- }
- function set_attributes(node, attributes) {
-
- const descriptors = Object.getOwnPropertyDescriptors(node.__proto__);
- for (const key in attributes) {
- if (attributes[key] == null) {
- node.removeAttribute(key);
- }
- else if (key === 'style') {
- node.style.cssText = attributes[key];
- }
- else if (key === '__value') {
- node.value = node[key] = attributes[key];
- }
- else if (descriptors[key] && descriptors[key].set) {
- node[key] = attributes[key];
- }
- else {
- attr(node, key, attributes[key]);
- }
- }
- }
- function children(element) {
- return Array.from(element.childNodes);
- }
- function set_data(text, data) {
- data = '' + data;
- if (text.wholeText !== data)
- text.data = data;
- }
- function toggle_class(element, name, toggle) {
- element.classList[toggle ? 'add' : 'remove'](name);
- }
- let current_component;
- function set_current_component(component) {
- current_component = component;
- }
- function get_current_component() {
- if (!current_component)
- throw new Error('Function called outside component initialization');
- return current_component;
- }
- const dirty_components = [];
- const binding_callbacks = [];
- const render_callbacks = [];
- const flush_callbacks = [];
- const resolved_promise = Promise.resolve();
- let update_scheduled = false;
- function schedule_update() {
- if (!update_scheduled) {
- update_scheduled = true;
- resolved_promise.then(flush);
- }
- }
- function add_render_callback(fn) {
- render_callbacks.push(fn);
- }
- let flushing = false;
- const seen_callbacks = new Set();
- function flush() {
- if (flushing)
- return;
- flushing = true;
- do {
-
-
- for (let i = 0; i < dirty_components.length; i += 1) {
- const component = dirty_components[i];
- set_current_component(component);
- update(component.$$);
- }
- set_current_component(null);
- dirty_components.length = 0;
- while (binding_callbacks.length)
- binding_callbacks.pop()();
-
-
-
- for (let i = 0; i < render_callbacks.length; i += 1) {
- const callback = render_callbacks[i];
- if (!seen_callbacks.has(callback)) {
-
- seen_callbacks.add(callback);
- callback();
- }
- }
- render_callbacks.length = 0;
- } while (dirty_components.length);
- while (flush_callbacks.length) {
- flush_callbacks.pop()();
- }
- update_scheduled = false;
- flushing = false;
- seen_callbacks.clear();
- }
- function update($$) {
- if ($$.fragment !== null) {
- $$.update();
- run_all($$.before_update);
- const dirty = $$.dirty;
- $$.dirty = [-1];
- $$.fragment && $$.fragment.p($$.ctx, dirty);
- $$.after_update.forEach(add_render_callback);
- }
- }
- const outroing = new Set();
- let outros;
- function group_outros() {
- outros = {
- r: 0,
- c: [],
- p: outros
- };
- }
- function check_outros() {
- if (!outros.r) {
- run_all(outros.c);
- }
- outros = outros.p;
- }
- function transition_in(block, local) {
- if (block && block.i) {
- outroing.delete(block);
- block.i(local);
- }
- }
- function transition_out(block, local, detach, callback) {
- if (block && block.o) {
- if (outroing.has(block))
- return;
- outroing.add(block);
- outros.c.push(() => {
- outroing.delete(block);
- if (callback) {
- if (detach)
- block.d(1);
- callback();
- }
- });
- block.o(local);
- }
- }
- function handle_promise(promise, info) {
- const token = info.token = {};
- function update(type, index, key, value) {
- if (info.token !== token)
- return;
- info.resolved = value;
- let child_ctx = info.ctx;
- if (key !== undefined) {
- child_ctx = child_ctx.slice();
- child_ctx[key] = value;
- }
- const block = type && (info.current = type)(child_ctx);
- let needs_flush = false;
- if (info.block) {
- if (info.blocks) {
- info.blocks.forEach((block, i) => {
- if (i !== index && block) {
- group_outros();
- transition_out(block, 1, 1, () => {
- if (info.blocks[i] === block) {
- info.blocks[i] = null;
- }
- });
- check_outros();
- }
- });
- }
- else {
- info.block.d(1);
- }
- block.c();
- transition_in(block, 1);
- block.m(info.mount(), info.anchor);
- needs_flush = true;
- }
- info.block = block;
- if (info.blocks)
- info.blocks[index] = block;
- if (needs_flush) {
- flush();
- }
- }
- if (is_promise(promise)) {
- const current_component = get_current_component();
- promise.then(value => {
- set_current_component(current_component);
- update(info.then, 1, info.value, value);
- set_current_component(null);
- }, error => {
- set_current_component(current_component);
- update(info.catch, 2, info.error, error);
- set_current_component(null);
- if (!info.hasCatch) {
- throw error;
- }
- });
-
- if (info.current !== info.pending) {
- update(info.pending, 0);
- return true;
- }
- }
- else {
- if (info.current !== info.then) {
- update(info.then, 1, info.value, promise);
- return true;
- }
- info.resolved = promise;
- }
- }
- function outro_and_destroy_block(block, lookup) {
- transition_out(block, 1, 1, () => {
- lookup.delete(block.key);
- });
- }
- function update_keyed_each(old_blocks, dirty, get_key, dynamic, ctx, list, lookup, node, destroy, create_each_block, next, get_context) {
- let o = old_blocks.length;
- let n = list.length;
- let i = o;
- const old_indexes = {};
- while (i--)
- old_indexes[old_blocks[i].key] = i;
- const new_blocks = [];
- const new_lookup = new Map();
- const deltas = new Map();
- i = n;
- while (i--) {
- const child_ctx = get_context(ctx, list, i);
- const key = get_key(child_ctx);
- let block = lookup.get(key);
- if (!block) {
- block = create_each_block(key, child_ctx);
- block.c();
- }
- else if (dynamic) {
- block.p(child_ctx, dirty);
- }
- new_lookup.set(key, new_blocks[i] = block);
- if (key in old_indexes)
- deltas.set(key, Math.abs(i - old_indexes[key]));
- }
- const will_move = new Set();
- const did_move = new Set();
- function insert(block) {
- transition_in(block, 1);
- block.m(node, next);
- lookup.set(block.key, block);
- next = block.first;
- n--;
- }
- while (o && n) {
- const new_block = new_blocks[n - 1];
- const old_block = old_blocks[o - 1];
- const new_key = new_block.key;
- const old_key = old_block.key;
- if (new_block === old_block) {
-
- next = new_block.first;
- o--;
- n--;
- }
- else if (!new_lookup.has(old_key)) {
-
- destroy(old_block, lookup);
- o--;
- }
- else if (!lookup.has(new_key) || will_move.has(new_key)) {
- insert(new_block);
- }
- else if (did_move.has(old_key)) {
- o--;
- }
- else if (deltas.get(new_key) > deltas.get(old_key)) {
- did_move.add(new_key);
- insert(new_block);
- }
- else {
- will_move.add(old_key);
- o--;
- }
- }
- while (o--) {
- const old_block = old_blocks[o];
- if (!new_lookup.has(old_block.key))
- destroy(old_block, lookup);
- }
- while (n)
- insert(new_blocks[n - 1]);
- return new_blocks;
- }
- function get_spread_update(levels, updates) {
- const update = {};
- const to_null_out = {};
- const accounted_for = { $$scope: 1 };
- let i = levels.length;
- while (i--) {
- const o = levels[i];
- const n = updates[i];
- if (n) {
- for (const key in o) {
- if (!(key in n))
- to_null_out[key] = 1;
- }
- for (const key in n) {
- if (!accounted_for[key]) {
- update[key] = n[key];
- accounted_for[key] = 1;
- }
- }
- levels[i] = n;
- }
- else {
- for (const key in o) {
- accounted_for[key] = 1;
- }
- }
- }
- for (const key in to_null_out) {
- if (!(key in update))
- update[key] = undefined;
- }
- return update;
- }
- function get_spread_object(spread_props) {
- return typeof spread_props === 'object' && spread_props !== null ? spread_props : {};
- }
- function create_component(block) {
- block && block.c();
- }
- function mount_component(component, target, anchor, customElement) {
- const { fragment, on_mount, on_destroy, after_update } = component.$$;
- fragment && fragment.m(target, anchor);
- if (!customElement) {
-
- add_render_callback(() => {
- const new_on_destroy = on_mount.map(run).filter(is_function);
- if (on_destroy) {
- on_destroy.push(...new_on_destroy);
- }
- else {
-
-
- run_all(new_on_destroy);
- }
- component.$$.on_mount = [];
- });
- }
- after_update.forEach(add_render_callback);
- }
- function destroy_component(component, detaching) {
- const $$ = component.$$;
- if ($$.fragment !== null) {
- run_all($$.on_destroy);
- $$.fragment && $$.fragment.d(detaching);
-
-
- $$.on_destroy = $$.fragment = null;
- $$.ctx = [];
- }
- }
- function make_dirty(component, i) {
- if (component.$$.dirty[0] === -1) {
- dirty_components.push(component);
- schedule_update();
- component.$$.dirty.fill(0);
- }
- component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));
- }
- function init(component, options, instance, create_fragment, not_equal, props, dirty = [-1]) {
- const parent_component = current_component;
- set_current_component(component);
- const $$ = component.$$ = {
- fragment: null,
- ctx: null,
-
- props,
- update: noop,
- not_equal,
- bound: blank_object(),
-
- on_mount: [],
- on_destroy: [],
- on_disconnect: [],
- before_update: [],
- after_update: [],
- context: new Map(parent_component ? parent_component.$$.context : []),
-
- callbacks: blank_object(),
- dirty,
- skip_bound: false
- };
- let ready = false;
- $$.ctx = instance
- ? instance(component, options.props || {}, (i, ret, ...rest) => {
- const value = rest.length ? rest[0] : ret;
- if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
- if (!$$.skip_bound && $$.bound[i])
- $$.bound[i](value);
- if (ready)
- make_dirty(component, i);
- }
- return ret;
- })
- : [];
- $$.update();
- ready = true;
- run_all($$.before_update);
-
- $$.fragment = create_fragment ? create_fragment($$.ctx) : false;
- if (options.target) {
- if (options.hydrate) {
- const nodes = children(options.target);
-
- $$.fragment && $$.fragment.l(nodes);
- nodes.forEach(detach);
- }
- else {
-
- $$.fragment && $$.fragment.c();
- }
- if (options.intro)
- transition_in(component.$$.fragment);
- mount_component(component, options.target, options.anchor, options.customElement);
- flush();
- }
- set_current_component(parent_component);
- }
- class SvelteComponent {
- $destroy() {
- destroy_component(this, 1);
- this.$destroy = noop;
- }
- $on(type, callback) {
- const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
- callbacks.push(callback);
- return () => {
- const index = callbacks.indexOf(callback);
- if (index !== -1)
- callbacks.splice(index, 1);
- };
- }
- $set($$props) {
- if (this.$$set && !is_empty($$props)) {
- this.$$.skip_bound = true;
- this.$$set($$props);
- this.$$.skip_bound = false;
- }
- }
- }
- /**
- * dateUID is a way of weekly identifying daily/weekly/monthly notes.
- * They are prefixed with the granularity to avoid ambiguity.
- */
- function getDateUID(date, granularity = "day") {
- const ts = date.clone().startOf(granularity).format();
- return `${granularity}-${ts}`;
- }
- var getDateUID_1 = getDateUID;
- function add_css$5() {
- var style = element("style");
- style.id = "svelte-1widvzq-style";
- style.textContent = ".dot.svelte-1widvzq,.hollow.svelte-1widvzq{display:inline-block;height:6px;width:6px;margin:0 1px}.filled.svelte-1widvzq{fill:var(--color-dot)}.active.filled.svelte-1widvzq{fill:var(--text-on-accent)}.hollow.svelte-1widvzq{fill:none;stroke:var(--color-dot)}.active.hollow.svelte-1widvzq{fill:none;stroke:var(--text-on-accent)}";
- append(document.head, style);
- }
- function create_else_block$1(ctx) {
- let svg;
- let circle;
- let svg_class_value;
- return {
- c() {
- svg = svg_element("svg");
- circle = svg_element("circle");
- attr(circle, "cx", "3");
- attr(circle, "cy", "3");
- attr(circle, "r", "2");
- attr(svg, "class", svg_class_value = "" + (null_to_empty(`hollow ${/*className*/ ctx[0]}`) + " svelte-1widvzq"));
- attr(svg, "viewBox", "0 0 6 6");
- attr(svg, "xmlns", "http://www.w3.org/2000/svg");
- toggle_class(svg, "active", ctx[2]);
- },
- m(target, anchor) {
- insert(target, svg, anchor);
- append(svg, circle);
- },
- p(ctx, dirty) {
- if (dirty & 1 && svg_class_value !== (svg_class_value = "" + (null_to_empty(`hollow ${/*className*/ ctx[0]}`) + " svelte-1widvzq"))) {
- attr(svg, "class", svg_class_value);
- }
- if (dirty & 5) {
- toggle_class(svg, "active", ctx[2]);
- }
- },
- d(detaching) {
- if (detaching) detach(svg);
- }
- };
- }
- function create_if_block$2(ctx) {
- let svg;
- let circle;
- let svg_class_value;
- return {
- c() {
- svg = svg_element("svg");
- circle = svg_element("circle");
- attr(circle, "cx", "3");
- attr(circle, "cy", "3");
- attr(circle, "r", "2");
- attr(svg, "class", svg_class_value = "" + (null_to_empty(`dot filled ${/*className*/ ctx[0]}`) + " svelte-1widvzq"));
- attr(svg, "viewBox", "0 0 6 6");
- attr(svg, "xmlns", "http://www.w3.org/2000/svg");
- toggle_class(svg, "active", ctx[2]);
- },
- m(target, anchor) {
- insert(target, svg, anchor);
- append(svg, circle);
- },
- p(ctx, dirty) {
- if (dirty & 1 && svg_class_value !== (svg_class_value = "" + (null_to_empty(`dot filled ${/*className*/ ctx[0]}`) + " svelte-1widvzq"))) {
- attr(svg, "class", svg_class_value);
- }
- if (dirty & 5) {
- toggle_class(svg, "active", ctx[2]);
- }
- },
- d(detaching) {
- if (detaching) detach(svg);
- }
- };
- }
- function create_fragment$6(ctx) {
- let if_block_anchor;
- function select_block_type(ctx, dirty) {
- if ( ctx[1]) return create_if_block$2;
- return create_else_block$1;
- }
- let current_block_type = select_block_type(ctx);
- let if_block = current_block_type(ctx);
- return {
- c() {
- if_block.c();
- if_block_anchor = empty();
- },
- m(target, anchor) {
- if_block.m(target, anchor);
- insert(target, if_block_anchor, anchor);
- },
- p(ctx, [dirty]) {
- if (current_block_type === (current_block_type = select_block_type(ctx)) && if_block) {
- if_block.p(ctx, dirty);
- } else {
- if_block.d(1);
- if_block = current_block_type(ctx);
- if (if_block) {
- if_block.c();
- if_block.m(if_block_anchor.parentNode, if_block_anchor);
- }
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if_block.d(detaching);
- if (detaching) detach(if_block_anchor);
- }
- };
- }
- function instance$6($$self, $$props, $$invalidate) {
- let { className = "" } = $$props;
- let { isFilled } = $$props;
- let { isActive } = $$props;
- $$self.$$set = $$props => {
- if ("className" in $$props) $$invalidate(0, className = $$props.className);
- if ("isFilled" in $$props) $$invalidate(1, isFilled = $$props.isFilled);
- if ("isActive" in $$props) $$invalidate(2, isActive = $$props.isActive);
- };
- return [className, isFilled, isActive];
- }
- class Dot extends SvelteComponent {
- constructor(options) {
- super();
- if (!document.getElementById("svelte-1widvzq-style")) add_css$5();
- init(this, options, instance$6, create_fragment$6, safe_not_equal, { className: 0, isFilled: 1, isActive: 2 });
- }
- }
- const get_default_slot_changes_1 = dirty => ({});
- const get_default_slot_context_1 = ctx => ({ metadata: null });
- const get_default_slot_changes = dirty => ({ metadata: dirty & 1 });
- const get_default_slot_context = ctx => ({ metadata: ctx[3] });
- function create_else_block(ctx) {
- let current;
- const default_slot_template = ctx[2].default;
- const default_slot = create_slot(default_slot_template, ctx, ctx[1], get_default_slot_context_1);
- return {
- c() {
- if (default_slot) default_slot.c();
- },
- m(target, anchor) {
- if (default_slot) {
- default_slot.m(target, anchor);
- }
- current = true;
- },
- p(ctx, dirty) {
- if (default_slot) {
- if (default_slot.p && dirty & 2) {
- update_slot(default_slot, default_slot_template, ctx, ctx[1], dirty, get_default_slot_changes_1, get_default_slot_context_1);
- }
- }
- },
- i(local) {
- if (current) return;
- transition_in(default_slot, local);
- current = true;
- },
- o(local) {
- transition_out(default_slot, local);
- current = false;
- },
- d(detaching) {
- if (default_slot) default_slot.d(detaching);
- }
- };
- }
- function create_if_block$1(ctx) {
- let await_block_anchor;
- let promise;
- let current;
- let info = {
- ctx,
- current: null,
- token: null,
- hasCatch: false,
- pending: create_pending_block,
- then: create_then_block,
- catch: create_catch_block,
- value: 3,
- blocks: [,,,]
- };
- handle_promise(promise = ctx[0], info);
- return {
- c() {
- await_block_anchor = empty();
- info.block.c();
- },
- m(target, anchor) {
- insert(target, await_block_anchor, anchor);
- info.block.m(target, info.anchor = anchor);
- info.mount = () => await_block_anchor.parentNode;
- info.anchor = await_block_anchor;
- current = true;
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- info.ctx = ctx;
- if (dirty & 1 && promise !== (promise = ctx[0]) && handle_promise(promise, info)) ; else {
- const child_ctx = ctx.slice();
- child_ctx[3] = info.resolved;
- info.block.p(child_ctx, dirty);
- }
- },
- i(local) {
- if (current) return;
- transition_in(info.block);
- current = true;
- },
- o(local) {
- for (let i = 0; i < 3; i += 1) {
- const block = info.blocks[i];
- transition_out(block);
- }
- current = false;
- },
- d(detaching) {
- if (detaching) detach(await_block_anchor);
- info.block.d(detaching);
- info.token = null;
- info = null;
- }
- };
- }
- function create_catch_block(ctx) {
- return {
- c: noop,
- m: noop,
- p: noop,
- i: noop,
- o: noop,
- d: noop
- };
- }
- function create_then_block(ctx) {
- let current;
- const default_slot_template = ctx[2].default;
- const default_slot = create_slot(default_slot_template, ctx, ctx[1], get_default_slot_context);
- return {
- c() {
- if (default_slot) default_slot.c();
- },
- m(target, anchor) {
- if (default_slot) {
- default_slot.m(target, anchor);
- }
- current = true;
- },
- p(ctx, dirty) {
- if (default_slot) {
- if (default_slot.p && dirty & 3) {
- update_slot(default_slot, default_slot_template, ctx, ctx[1], dirty, get_default_slot_changes, get_default_slot_context);
- }
- }
- },
- i(local) {
- if (current) return;
- transition_in(default_slot, local);
- current = true;
- },
- o(local) {
- transition_out(default_slot, local);
- current = false;
- },
- d(detaching) {
- if (default_slot) default_slot.d(detaching);
- }
- };
- }
- function create_pending_block(ctx) {
- return {
- c: noop,
- m: noop,
- p: noop,
- i: noop,
- o: noop,
- d: noop
- };
- }
- function create_fragment$5(ctx) {
- let current_block_type_index;
- let if_block;
- let if_block_anchor;
- let current;
- const if_block_creators = [create_if_block$1, create_else_block];
- const if_blocks = [];
- function select_block_type(ctx, dirty) {
- if ( ctx[0]) return 0;
- return 1;
- }
- current_block_type_index = select_block_type(ctx);
- if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
- return {
- c() {
- if_block.c();
- if_block_anchor = empty();
- },
- m(target, anchor) {
- if_blocks[current_block_type_index].m(target, anchor);
- insert(target, if_block_anchor, anchor);
- current = true;
- },
- p(ctx, [dirty]) {
- let previous_block_index = current_block_type_index;
- current_block_type_index = select_block_type(ctx);
- if (current_block_type_index === previous_block_index) {
- if_blocks[current_block_type_index].p(ctx, dirty);
- } else {
- group_outros();
- transition_out(if_blocks[previous_block_index], 1, 1, () => {
- if_blocks[previous_block_index] = null;
- });
- check_outros();
- if_block = if_blocks[current_block_type_index];
- if (!if_block) {
- if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
- if_block.c();
- } else {
- if_block.p(ctx, dirty);
- }
- transition_in(if_block, 1);
- if_block.m(if_block_anchor.parentNode, if_block_anchor);
- }
- },
- i(local) {
- if (current) return;
- transition_in(if_block);
- current = true;
- },
- o(local) {
- transition_out(if_block);
- current = false;
- },
- d(detaching) {
- if_blocks[current_block_type_index].d(detaching);
- if (detaching) detach(if_block_anchor);
- }
- };
- }
- function instance$5($$self, $$props, $$invalidate) {
- let { $$slots: slots = {}, $$scope } = $$props;
-
- let { metadata } = $$props;
- $$self.$$set = $$props => {
- if ("metadata" in $$props) $$invalidate(0, metadata = $$props.metadata);
- if ("$$scope" in $$props) $$invalidate(1, $$scope = $$props.$$scope);
- };
- return [metadata, $$scope, slots];
- }
- class MetadataResolver extends SvelteComponent {
- constructor(options) {
- super();
- init(this, options, instance$5, create_fragment$5, not_equal, { metadata: 0 });
- }
- }
- function isMacOS() {
- return navigator.appVersion.indexOf("Mac") !== -1;
- }
- function isMetaPressed(e) {
- return isMacOS() ? e.metaKey : e.ctrlKey;
- }
- function getDaysOfWeek(..._args) {
- return window.moment.weekdaysShort(true);
- }
- function isWeekend(date) {
- return date.isoWeekday() === 6 || date.isoWeekday() === 7;
- }
- function getStartOfWeek(days) {
- return days[0].weekday(0);
- }
- function getMonth(displayedMonth, ..._args) {
- const locale = window.moment().locale();
- const month = [];
- let week;
- const startOfMonth = displayedMonth.clone().locale(locale).date(1);
- const startOffset = startOfMonth.weekday();
- let date = startOfMonth.clone().subtract(startOffset, "days");
- for (let _day = 0; _day < 42; _day++) {
- if (_day % 7 === 0) {
- week = {
- days: [],
- weekNum: date.week(),
- };
- month.push(week);
- }
- week.days.push(date);
- date = date.clone().add(1, "days");
- }
- return month;
- }
- function add_css$4() {
- var style = element("style");
- style.id = "svelte-q3wqg9-style";
- style.textContent = ".day.svelte-q3wqg9{background-color:var(--color-background-day);border-radius:4px;color:var(--color-text-day);cursor:pointer;font-size:0.8em;height:100%;padding:4px;position:relative;text-align:center;transition:background-color 0.1s ease-in, color 0.1s ease-in;vertical-align:baseline}.day.svelte-q3wqg9:hover{background-color:var(--interactive-hover)}.day.active.svelte-q3wqg9:hover{background-color:var(--interactive-accent-hover)}.adjacent-month.svelte-q3wqg9{opacity:0.25}.today.svelte-q3wqg9{color:var(--color-text-today)}.day.svelte-q3wqg9:active,.active.svelte-q3wqg9,.active.today.svelte-q3wqg9{color:var(--text-on-accent);background-color:var(--interactive-accent)}.dot-container.svelte-q3wqg9{display:flex;flex-wrap:wrap;justify-content:center;line-height:6px;min-height:6px}";
- append(document.head, style);
- }
- function get_each_context$2(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[11] = list[i];
- return child_ctx;
- }
- function create_each_block$2(ctx) {
- let dot;
- let current;
- const dot_spread_levels = [ ctx[11]];
- let dot_props = {};
- for (let i = 0; i < dot_spread_levels.length; i += 1) {
- dot_props = assign(dot_props, dot_spread_levels[i]);
- }
- dot = new Dot({ props: dot_props });
- return {
- c() {
- create_component(dot.$$.fragment);
- },
- m(target, anchor) {
- mount_component(dot, target, anchor);
- current = true;
- },
- p(ctx, dirty) {
- const dot_changes = (dirty & 128)
- ? get_spread_update(dot_spread_levels, [get_spread_object( ctx[11])])
- : {};
- dot.$set(dot_changes);
- },
- i(local) {
- if (current) return;
- transition_in(dot.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(dot.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(dot, detaching);
- }
- };
- }
- function create_default_slot$1(ctx) {
- let div1;
- let t0_value = ctx[0].format("D") + "";
- let t0;
- let t1;
- let div0;
- let div1_class_value;
- let current;
- let mounted;
- let dispose;
- let each_value = ctx[7].dots;
- let each_blocks = [];
- for (let i = 0; i < each_value.length; i += 1) {
- each_blocks[i] = create_each_block$2(get_each_context$2(ctx, each_value, i));
- }
- const out = i => transition_out(each_blocks[i], 1, 1, () => {
- each_blocks[i] = null;
- });
- let div1_levels = [
- {
- class: div1_class_value = `day ${/*metadata*/ ctx[7].classes.join(" ")}`
- },
- ctx[7].dataAttributes || {}
- ];
- let div1_data = {};
- for (let i = 0; i < div1_levels.length; i += 1) {
- div1_data = assign(div1_data, div1_levels[i]);
- }
- return {
- c() {
- div1 = element("div");
- t0 = text(t0_value);
- t1 = space();
- div0 = element("div");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- attr(div0, "class", "dot-container svelte-q3wqg9");
- set_attributes(div1, div1_data);
- toggle_class(div1, "active", ctx[6] === getDateUID_1( ctx[0], "day"));
- toggle_class(div1, "adjacent-month", ! ctx[0].isSame( ctx[5], "month"));
- toggle_class(div1, "today", ctx[0].isSame( ctx[4], "day"));
- toggle_class(div1, "svelte-q3wqg9", true);
- },
- m(target, anchor) {
- insert(target, div1, anchor);
- append(div1, t0);
- append(div1, t1);
- append(div1, div0);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(div0, null);
- }
- current = true;
- if (!mounted) {
- dispose = [
- listen(div1, "click", function () {
- if (is_function( ctx[2] && ctx[8])) ( ctx[2] && ctx[8]).apply(this, arguments);
- }),
- listen(div1, "contextmenu", function () {
- if (is_function( ctx[3] && ctx[9])) ( ctx[3] && ctx[9]).apply(this, arguments);
- }),
- listen(div1, "pointerover", function () {
- if (is_function( ctx[1] && ctx[10])) ( ctx[1] && ctx[10]).apply(this, arguments);
- })
- ];
- mounted = true;
- }
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- if ((!current || dirty & 1) && t0_value !== (t0_value = ctx[0].format("D") + "")) set_data(t0, t0_value);
- if (dirty & 128) {
- each_value = ctx[7].dots;
- let i;
- for (i = 0; i < each_value.length; i += 1) {
- const child_ctx = get_each_context$2(ctx, each_value, i);
- if (each_blocks[i]) {
- each_blocks[i].p(child_ctx, dirty);
- transition_in(each_blocks[i], 1);
- } else {
- each_blocks[i] = create_each_block$2(child_ctx);
- each_blocks[i].c();
- transition_in(each_blocks[i], 1);
- each_blocks[i].m(div0, null);
- }
- }
- group_outros();
- for (i = each_value.length; i < each_blocks.length; i += 1) {
- out(i);
- }
- check_outros();
- }
- set_attributes(div1, div1_data = get_spread_update(div1_levels, [
- (!current || dirty & 128 && div1_class_value !== (div1_class_value = `day ${/*metadata*/ ctx[7].classes.join(" ")}`)) && { class: div1_class_value },
- dirty & 128 && ( ctx[7].dataAttributes || {})
- ]));
- toggle_class(div1, "active", ctx[6] === getDateUID_1( ctx[0], "day"));
- toggle_class(div1, "adjacent-month", ! ctx[0].isSame( ctx[5], "month"));
- toggle_class(div1, "today", ctx[0].isSame( ctx[4], "day"));
- toggle_class(div1, "svelte-q3wqg9", true);
- },
- i(local) {
- if (current) return;
- for (let i = 0; i < each_value.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- each_blocks = each_blocks.filter(Boolean);
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching) detach(div1);
- destroy_each(each_blocks, detaching);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function create_fragment$4(ctx) {
- let td;
- let metadataresolver;
- let current;
- metadataresolver = new MetadataResolver({
- props: {
- metadata: ctx[7],
- $$slots: {
- default: [
- create_default_slot$1,
- ({ metadata }) => ({ 7: metadata }),
- ({ metadata }) => metadata ? 128 : 0
- ]
- },
- $$scope: { ctx }
- }
- });
- return {
- c() {
- td = element("td");
- create_component(metadataresolver.$$.fragment);
- },
- m(target, anchor) {
- insert(target, td, anchor);
- mount_component(metadataresolver, td, null);
- current = true;
- },
- p(ctx, [dirty]) {
- const metadataresolver_changes = {};
- if (dirty & 128) metadataresolver_changes.metadata = ctx[7];
- if (dirty & 16639) {
- metadataresolver_changes.$$scope = { dirty, ctx };
- }
- metadataresolver.$set(metadataresolver_changes);
- },
- i(local) {
- if (current) return;
- transition_in(metadataresolver.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(metadataresolver.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching) detach(td);
- destroy_component(metadataresolver);
- }
- };
- }
- function instance$4($$self, $$props, $$invalidate) {
-
-
- let { date } = $$props;
- let { metadata } = $$props;
- let { onHover } = $$props;
- let { onClick } = $$props;
- let { onContextMenu } = $$props;
- let { today } = $$props;
- let { displayedMonth = null } = $$props;
- let { selectedId = null } = $$props;
- const click_handler = e => onClick(date, isMetaPressed(e));
- const contextmenu_handler = e => onContextMenu(date, e);
- const pointerover_handler = e => onHover(date, e.target, isMetaPressed(e));
- $$self.$$set = $$props => {
- if ("date" in $$props) $$invalidate(0, date = $$props.date);
- if ("metadata" in $$props) $$invalidate(7, metadata = $$props.metadata);
- if ("onHover" in $$props) $$invalidate(1, onHover = $$props.onHover);
- if ("onClick" in $$props) $$invalidate(2, onClick = $$props.onClick);
- if ("onContextMenu" in $$props) $$invalidate(3, onContextMenu = $$props.onContextMenu);
- if ("today" in $$props) $$invalidate(4, today = $$props.today);
- if ("displayedMonth" in $$props) $$invalidate(5, displayedMonth = $$props.displayedMonth);
- if ("selectedId" in $$props) $$invalidate(6, selectedId = $$props.selectedId);
- };
- return [
- date,
- onHover,
- onClick,
- onContextMenu,
- today,
- displayedMonth,
- selectedId,
- metadata,
- click_handler,
- contextmenu_handler,
- pointerover_handler
- ];
- }
- class Day extends SvelteComponent {
- constructor(options) {
- super();
- if (!document.getElementById("svelte-q3wqg9-style")) add_css$4();
- init(this, options, instance$4, create_fragment$4, not_equal, {
- date: 0,
- metadata: 7,
- onHover: 1,
- onClick: 2,
- onContextMenu: 3,
- today: 4,
- displayedMonth: 5,
- selectedId: 6
- });
- }
- }
- function add_css$3() {
- var style = element("style");
- style.id = "svelte-156w7na-style";
- style.textContent = ".arrow.svelte-156w7na.svelte-156w7na{align-items:center;cursor:pointer;display:flex;justify-content:center;width:24px}.arrow.is-mobile.svelte-156w7na.svelte-156w7na{width:32px}.right.svelte-156w7na.svelte-156w7na{transform:rotate(180deg)}.arrow.svelte-156w7na svg.svelte-156w7na{color:var(--color-arrow);height:16px;width:16px}";
- append(document.head, style);
- }
- function create_fragment$3(ctx) {
- let div;
- let svg;
- let path;
- let mounted;
- let dispose;
- return {
- c() {
- div = element("div");
- svg = svg_element("svg");
- path = svg_element("path");
- attr(path, "fill", "currentColor");
- attr(path, "d", "M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z");
- attr(svg, "focusable", "false");
- attr(svg, "role", "img");
- attr(svg, "xmlns", "http://www.w3.org/2000/svg");
- attr(svg, "viewBox", "0 0 320 512");
- attr(svg, "class", "svelte-156w7na");
- attr(div, "class", "arrow svelte-156w7na");
- attr(div, "aria-label", ctx[1]);
- toggle_class(div, "is-mobile", ctx[3]);
- toggle_class(div, "right", ctx[2] === "right");
- },
- m(target, anchor) {
- insert(target, div, anchor);
- append(div, svg);
- append(svg, path);
- if (!mounted) {
- dispose = listen(div, "click", function () {
- if (is_function( ctx[0])) ctx[0].apply(this, arguments);
- });
- mounted = true;
- }
- },
- p(new_ctx, [dirty]) {
- ctx = new_ctx;
- if (dirty & 2) {
- attr(div, "aria-label", ctx[1]);
- }
- if (dirty & 4) {
- toggle_class(div, "right", ctx[2] === "right");
- }
- },
- i: noop,
- o: noop,
- d(detaching) {
- if (detaching) detach(div);
- mounted = false;
- dispose();
- }
- };
- }
- function instance$3($$self, $$props, $$invalidate) {
- let { onClick } = $$props;
- let { tooltip } = $$props;
- let { direction } = $$props;
-
- let isMobile = window.app.isMobile;
- $$self.$$set = $$props => {
- if ("onClick" in $$props) $$invalidate(0, onClick = $$props.onClick);
- if ("tooltip" in $$props) $$invalidate(1, tooltip = $$props.tooltip);
- if ("direction" in $$props) $$invalidate(2, direction = $$props.direction);
- };
- return [onClick, tooltip, direction, isMobile];
- }
- class Arrow extends SvelteComponent {
- constructor(options) {
- super();
- if (!document.getElementById("svelte-156w7na-style")) add_css$3();
- init(this, options, instance$3, create_fragment$3, safe_not_equal, { onClick: 0, tooltip: 1, direction: 2 });
- }
- }
- function add_css$2() {
- var style = element("style");
- style.id = "svelte-1vwr9dd-style";
- style.textContent = ".nav.svelte-1vwr9dd.svelte-1vwr9dd{align-items:center;display:flex;margin:0.6em 0 1em;padding:0 8px;width:100%}.nav.is-mobile.svelte-1vwr9dd.svelte-1vwr9dd{padding:0}.title.svelte-1vwr9dd.svelte-1vwr9dd{color:var(--color-text-title);font-size:1.5em;margin:0}.is-mobile.svelte-1vwr9dd .title.svelte-1vwr9dd{font-size:1.3em}.month.svelte-1vwr9dd.svelte-1vwr9dd{font-weight:500;text-transform:capitalize}.year.svelte-1vwr9dd.svelte-1vwr9dd{color:var(--interactive-accent)}.right-nav.svelte-1vwr9dd.svelte-1vwr9dd{display:flex;justify-content:center;margin-left:auto}.reset-button.svelte-1vwr9dd.svelte-1vwr9dd{cursor:pointer;border-radius:4px;color:var(--text-muted);font-size:0.7em;font-weight:600;letter-spacing:1px;margin:0 4px;padding:0px 4px;text-transform:uppercase}.is-mobile.svelte-1vwr9dd .reset-button.svelte-1vwr9dd{display:none}";
- append(document.head, style);
- }
- function create_fragment$2(ctx) {
- let div2;
- let h3;
- let span0;
- let t0_value = ctx[0].format("MMM") + "";
- let t0;
- let t1;
- let span1;
- let t2_value = ctx[0].format("YYYY") + "";
- let t2;
- let t3;
- let div1;
- let arrow0;
- let t4;
- let div0;
- let t6;
- let arrow1;
- let current;
- let mounted;
- let dispose;
- arrow0 = new Arrow({
- props: {
- direction: "left",
- onClick: ctx[3],
- tooltip: "Previous Month"
- }
- });
- arrow1 = new Arrow({
- props: {
- direction: "right",
- onClick: ctx[2],
- tooltip: "Next Month"
- }
- });
- return {
- c() {
- div2 = element("div");
- h3 = element("h3");
- span0 = element("span");
- t0 = text(t0_value);
- t1 = space();
- span1 = element("span");
- t2 = text(t2_value);
- t3 = space();
- div1 = element("div");
- create_component(arrow0.$$.fragment);
- t4 = space();
- div0 = element("div");
- div0.textContent = `${/*todayDisplayStr*/ ctx[4]}`;
- t6 = space();
- create_component(arrow1.$$.fragment);
- attr(span0, "class", "month svelte-1vwr9dd");
- attr(span1, "class", "year svelte-1vwr9dd");
- attr(h3, "class", "title svelte-1vwr9dd");
- attr(div0, "class", "reset-button svelte-1vwr9dd");
- attr(div1, "class", "right-nav svelte-1vwr9dd");
- attr(div2, "class", "nav svelte-1vwr9dd");
- toggle_class(div2, "is-mobile", ctx[5]);
- },
- m(target, anchor) {
- insert(target, div2, anchor);
- append(div2, h3);
- append(h3, span0);
- append(span0, t0);
- append(h3, t1);
- append(h3, span1);
- append(span1, t2);
- append(div2, t3);
- append(div2, div1);
- mount_component(arrow0, div1, null);
- append(div1, t4);
- append(div1, div0);
- append(div1, t6);
- mount_component(arrow1, div1, null);
- current = true;
- if (!mounted) {
- dispose = [
- listen(h3, "click", function () {
- if (is_function( ctx[1])) ctx[1].apply(this, arguments);
- }),
- listen(div0, "click", function () {
- if (is_function( ctx[1])) ctx[1].apply(this, arguments);
- })
- ];
- mounted = true;
- }
- },
- p(new_ctx, [dirty]) {
- ctx = new_ctx;
- if ((!current || dirty & 1) && t0_value !== (t0_value = ctx[0].format("MMM") + "")) set_data(t0, t0_value);
- if ((!current || dirty & 1) && t2_value !== (t2_value = ctx[0].format("YYYY") + "")) set_data(t2, t2_value);
- const arrow0_changes = {};
- if (dirty & 8) arrow0_changes.onClick = ctx[3];
- arrow0.$set(arrow0_changes);
- const arrow1_changes = {};
- if (dirty & 4) arrow1_changes.onClick = ctx[2];
- arrow1.$set(arrow1_changes);
- },
- i(local) {
- if (current) return;
- transition_in(arrow0.$$.fragment, local);
- transition_in(arrow1.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(arrow0.$$.fragment, local);
- transition_out(arrow1.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching) detach(div2);
- destroy_component(arrow0);
- destroy_component(arrow1);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function instance$2($$self, $$props, $$invalidate) {
-
- let { displayedMonth } = $$props;
- let { today } = $$props;
- let { resetDisplayedMonth } = $$props;
- let { incrementDisplayedMonth } = $$props;
- let { decrementDisplayedMonth } = $$props;
-
- const todayDisplayStr = today.calendar().split(/\d|\s/)[0];
-
- let isMobile = window.app.isMobile;
- $$self.$$set = $$props => {
- if ("displayedMonth" in $$props) $$invalidate(0, displayedMonth = $$props.displayedMonth);
- if ("today" in $$props) $$invalidate(6, today = $$props.today);
- if ("resetDisplayedMonth" in $$props) $$invalidate(1, resetDisplayedMonth = $$props.resetDisplayedMonth);
- if ("incrementDisplayedMonth" in $$props) $$invalidate(2, incrementDisplayedMonth = $$props.incrementDisplayedMonth);
- if ("decrementDisplayedMonth" in $$props) $$invalidate(3, decrementDisplayedMonth = $$props.decrementDisplayedMonth);
- };
- return [
- displayedMonth,
- resetDisplayedMonth,
- incrementDisplayedMonth,
- decrementDisplayedMonth,
- todayDisplayStr,
- isMobile,
- today
- ];
- }
- class Nav extends SvelteComponent {
- constructor(options) {
- super();
- if (!document.getElementById("svelte-1vwr9dd-style")) add_css$2();
- init(this, options, instance$2, create_fragment$2, safe_not_equal, {
- displayedMonth: 0,
- today: 6,
- resetDisplayedMonth: 1,
- incrementDisplayedMonth: 2,
- decrementDisplayedMonth: 3
- });
- }
- }
- function add_css$1() {
- var style = element("style");
- style.id = "svelte-egt0yd-style";
- style.textContent = "td.svelte-egt0yd{border-right:1px solid var(--background-modifier-border)}.week-num.svelte-egt0yd{background-color:var(--color-background-weeknum);border-radius:4px;color:var(--color-text-weeknum);cursor:pointer;font-size:0.65em;height:100%;padding:4px;text-align:center;transition:background-color 0.1s ease-in, color 0.1s ease-in;vertical-align:baseline}.week-num.svelte-egt0yd:hover{background-color:var(--interactive-hover)}.week-num.active.svelte-egt0yd:hover{background-color:var(--interactive-accent-hover)}.active.svelte-egt0yd{color:var(--text-on-accent);background-color:var(--interactive-accent)}.dot-container.svelte-egt0yd{display:flex;flex-wrap:wrap;justify-content:center;line-height:6px;min-height:6px}";
- append(document.head, style);
- }
- function get_each_context$1(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[11] = list[i];
- return child_ctx;
- }
- function create_each_block$1(ctx) {
- let dot;
- let current;
- const dot_spread_levels = [ ctx[11]];
- let dot_props = {};
- for (let i = 0; i < dot_spread_levels.length; i += 1) {
- dot_props = assign(dot_props, dot_spread_levels[i]);
- }
- dot = new Dot({ props: dot_props });
- return {
- c() {
- create_component(dot.$$.fragment);
- },
- m(target, anchor) {
- mount_component(dot, target, anchor);
- current = true;
- },
- p(ctx, dirty) {
- const dot_changes = (dirty & 64)
- ? get_spread_update(dot_spread_levels, [get_spread_object( ctx[11])])
- : {};
- dot.$set(dot_changes);
- },
- i(local) {
- if (current) return;
- transition_in(dot.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(dot.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(dot, detaching);
- }
- };
- }
- function create_default_slot(ctx) {
- let div1;
- let t0;
- let t1;
- let div0;
- let div1_class_value;
- let current;
- let mounted;
- let dispose;
- let each_value = ctx[6].dots;
- let each_blocks = [];
- for (let i = 0; i < each_value.length; i += 1) {
- each_blocks[i] = create_each_block$1(get_each_context$1(ctx, each_value, i));
- }
- const out = i => transition_out(each_blocks[i], 1, 1, () => {
- each_blocks[i] = null;
- });
- return {
- c() {
- div1 = element("div");
- t0 = text( ctx[0]);
- t1 = space();
- div0 = element("div");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- attr(div0, "class", "dot-container svelte-egt0yd");
- attr(div1, "class", div1_class_value = "" + (null_to_empty(`week-num ${/*metadata*/ ctx[6].classes.join(" ")}`) + " svelte-egt0yd"));
- toggle_class(div1, "active", ctx[5] === getDateUID_1( ctx[1][0], "week"));
- },
- m(target, anchor) {
- insert(target, div1, anchor);
- append(div1, t0);
- append(div1, t1);
- append(div1, div0);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(div0, null);
- }
- current = true;
- if (!mounted) {
- dispose = [
- listen(div1, "click", function () {
- if (is_function( ctx[3] && ctx[8])) ( ctx[3] && ctx[8]).apply(this, arguments);
- }),
- listen(div1, "contextmenu", function () {
- if (is_function( ctx[4] && ctx[9])) ( ctx[4] && ctx[9]).apply(this, arguments);
- }),
- listen(div1, "pointerover", function () {
- if (is_function( ctx[2] && ctx[10])) ( ctx[2] && ctx[10]).apply(this, arguments);
- })
- ];
- mounted = true;
- }
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- if (!current || dirty & 1) set_data(t0, ctx[0]);
- if (dirty & 64) {
- each_value = ctx[6].dots;
- let i;
- for (i = 0; i < each_value.length; i += 1) {
- const child_ctx = get_each_context$1(ctx, each_value, i);
- if (each_blocks[i]) {
- each_blocks[i].p(child_ctx, dirty);
- transition_in(each_blocks[i], 1);
- } else {
- each_blocks[i] = create_each_block$1(child_ctx);
- each_blocks[i].c();
- transition_in(each_blocks[i], 1);
- each_blocks[i].m(div0, null);
- }
- }
- group_outros();
- for (i = each_value.length; i < each_blocks.length; i += 1) {
- out(i);
- }
- check_outros();
- }
- if (!current || dirty & 64 && div1_class_value !== (div1_class_value = "" + (null_to_empty(`week-num ${/*metadata*/ ctx[6].classes.join(" ")}`) + " svelte-egt0yd"))) {
- attr(div1, "class", div1_class_value);
- }
- if (dirty & 98) {
- toggle_class(div1, "active", ctx[5] === getDateUID_1( ctx[1][0], "week"));
- }
- },
- i(local) {
- if (current) return;
- for (let i = 0; i < each_value.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- each_blocks = each_blocks.filter(Boolean);
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching) detach(div1);
- destroy_each(each_blocks, detaching);
- mounted = false;
- run_all(dispose);
- }
- };
- }
- function create_fragment$1(ctx) {
- let td;
- let metadataresolver;
- let current;
- metadataresolver = new MetadataResolver({
- props: {
- metadata: ctx[6],
- $$slots: {
- default: [
- create_default_slot,
- ({ metadata }) => ({ 6: metadata }),
- ({ metadata }) => metadata ? 64 : 0
- ]
- },
- $$scope: { ctx }
- }
- });
- return {
- c() {
- td = element("td");
- create_component(metadataresolver.$$.fragment);
- attr(td, "class", "svelte-egt0yd");
- },
- m(target, anchor) {
- insert(target, td, anchor);
- mount_component(metadataresolver, td, null);
- current = true;
- },
- p(ctx, [dirty]) {
- const metadataresolver_changes = {};
- if (dirty & 64) metadataresolver_changes.metadata = ctx[6];
- if (dirty & 16639) {
- metadataresolver_changes.$$scope = { dirty, ctx };
- }
- metadataresolver.$set(metadataresolver_changes);
- },
- i(local) {
- if (current) return;
- transition_in(metadataresolver.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(metadataresolver.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching) detach(td);
- destroy_component(metadataresolver);
- }
- };
- }
- function instance$1($$self, $$props, $$invalidate) {
-
-
- let { weekNum } = $$props;
- let { days } = $$props;
- let { metadata } = $$props;
- let { onHover } = $$props;
- let { onClick } = $$props;
- let { onContextMenu } = $$props;
- let { selectedId = null } = $$props;
- let startOfWeek;
- const click_handler = e => onClick(startOfWeek, isMetaPressed(e));
- const contextmenu_handler = e => onContextMenu(days[0], e);
- const pointerover_handler = e => onHover(startOfWeek, e.target, isMetaPressed(e));
- $$self.$$set = $$props => {
- if ("weekNum" in $$props) $$invalidate(0, weekNum = $$props.weekNum);
- if ("days" in $$props) $$invalidate(1, days = $$props.days);
- if ("metadata" in $$props) $$invalidate(6, metadata = $$props.metadata);
- if ("onHover" in $$props) $$invalidate(2, onHover = $$props.onHover);
- if ("onClick" in $$props) $$invalidate(3, onClick = $$props.onClick);
- if ("onContextMenu" in $$props) $$invalidate(4, onContextMenu = $$props.onContextMenu);
- if ("selectedId" in $$props) $$invalidate(5, selectedId = $$props.selectedId);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & 2) {
- $$invalidate(7, startOfWeek = getStartOfWeek(days));
- }
- };
- return [
- weekNum,
- days,
- onHover,
- onClick,
- onContextMenu,
- selectedId,
- metadata,
- startOfWeek,
- click_handler,
- contextmenu_handler,
- pointerover_handler
- ];
- }
- class WeekNum extends SvelteComponent {
- constructor(options) {
- super();
- if (!document.getElementById("svelte-egt0yd-style")) add_css$1();
- init(this, options, instance$1, create_fragment$1, not_equal, {
- weekNum: 0,
- days: 1,
- metadata: 6,
- onHover: 2,
- onClick: 3,
- onContextMenu: 4,
- selectedId: 5
- });
- }
- }
- async function metadataReducer(promisedMetadata) {
- const meta = {
- dots: [],
- classes: [],
- dataAttributes: {},
- };
- const metas = await Promise.all(promisedMetadata);
- return metas.reduce((acc, meta) => ({
- classes: [...acc.classes, ...(meta.classes || [])],
- dataAttributes: Object.assign(acc.dataAttributes, meta.dataAttributes),
- dots: [...acc.dots, ...(meta.dots || [])],
- }), meta);
- }
- function getDailyMetadata(sources, date, ..._args) {
- return metadataReducer(sources.map((source) => source.getDailyMetadata(date)));
- }
- function getWeeklyMetadata(sources, date, ..._args) {
- return metadataReducer(sources.map((source) => source.getWeeklyMetadata(date)));
- }
- function add_css() {
- var style = element("style");
- style.id = "svelte-pcimu8-style";
- style.textContent = ".container.svelte-pcimu8{--color-background-heading:transparent;--color-background-day:transparent;--color-background-weeknum:transparent;--color-background-weekend:transparent;--color-dot:var(--text-muted);--color-arrow:var(--text-muted);--color-button:var(--text-muted);--color-text-title:var(--text-normal);--color-text-heading:var(--text-muted);--color-text-day:var(--text-normal);--color-text-today:var(--interactive-accent);--color-text-weeknum:var(--text-muted)}.container.svelte-pcimu8{padding:0 8px}.container.is-mobile.svelte-pcimu8{padding:0}th.svelte-pcimu8{text-align:center}.weekend.svelte-pcimu8{background-color:var(--color-background-weekend)}.calendar.svelte-pcimu8{border-collapse:collapse;width:100%}th.svelte-pcimu8{background-color:var(--color-background-heading);color:var(--color-text-heading);font-size:0.6em;letter-spacing:1px;padding:4px;text-transform:uppercase}";
- append(document.head, style);
- }
- function get_each_context(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[18] = list[i];
- return child_ctx;
- }
- function get_each_context_1(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[21] = list[i];
- return child_ctx;
- }
- function get_each_context_2(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[24] = list[i];
- return child_ctx;
- }
- function get_each_context_3(ctx, list, i) {
- const child_ctx = ctx.slice();
- child_ctx[27] = list[i];
- return child_ctx;
- }
- function create_if_block_2(ctx) {
- let col;
- return {
- c() {
- col = element("col");
- },
- m(target, anchor) {
- insert(target, col, anchor);
- },
- d(detaching) {
- if (detaching) detach(col);
- }
- };
- }
- function create_each_block_3(ctx) {
- let col;
- return {
- c() {
- col = element("col");
- attr(col, "class", "svelte-pcimu8");
- toggle_class(col, "weekend", isWeekend( ctx[27]));
- },
- m(target, anchor) {
- insert(target, col, anchor);
- },
- p(ctx, dirty) {
- if (dirty & 16384) {
- toggle_class(col, "weekend", isWeekend( ctx[27]));
- }
- },
- d(detaching) {
- if (detaching) detach(col);
- }
- };
- }
- function create_if_block_1(ctx) {
- let th;
- return {
- c() {
- th = element("th");
- th.textContent = "W";
- attr(th, "class", "svelte-pcimu8");
- },
- m(target, anchor) {
- insert(target, th, anchor);
- },
- d(detaching) {
- if (detaching) detach(th);
- }
- };
- }
- function create_each_block_2(ctx) {
- let th;
- let t_value = ctx[24] + "";
- let t;
- return {
- c() {
- th = element("th");
- t = text(t_value);
- attr(th, "class", "svelte-pcimu8");
- },
- m(target, anchor) {
- insert(target, th, anchor);
- append(th, t);
- },
- p(ctx, dirty) {
- if (dirty & 32768 && t_value !== (t_value = ctx[24] + "")) set_data(t, t_value);
- },
- d(detaching) {
- if (detaching) detach(th);
- }
- };
- }
- function create_if_block(ctx) {
- let weeknum;
- let current;
- const weeknum_spread_levels = [
- ctx[18],
- {
- metadata: getWeeklyMetadata( ctx[8], ctx[18].days[0], ctx[10])
- },
- { onClick: ctx[7] },
- {
- onContextMenu: ctx[5]
- },
- { onHover: ctx[3] },
- { selectedId: ctx[9] }
- ];
- let weeknum_props = {};
- for (let i = 0; i < weeknum_spread_levels.length; i += 1) {
- weeknum_props = assign(weeknum_props, weeknum_spread_levels[i]);
- }
- weeknum = new WeekNum({ props: weeknum_props });
- return {
- c() {
- create_component(weeknum.$$.fragment);
- },
- m(target, anchor) {
- mount_component(weeknum, target, anchor);
- current = true;
- },
- p(ctx, dirty) {
- const weeknum_changes = (dirty & 18344)
- ? get_spread_update(weeknum_spread_levels, [
- dirty & 16384 && get_spread_object( ctx[18]),
- dirty & 17664 && {
- metadata: getWeeklyMetadata( ctx[8], ctx[18].days[0], ctx[10])
- },
- dirty & 128 && { onClick: ctx[7] },
- dirty & 32 && {
- onContextMenu: ctx[5]
- },
- dirty & 8 && { onHover: ctx[3] },
- dirty & 512 && { selectedId: ctx[9] }
- ])
- : {};
- weeknum.$set(weeknum_changes);
- },
- i(local) {
- if (current) return;
- transition_in(weeknum.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(weeknum.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- destroy_component(weeknum, detaching);
- }
- };
- }
- function create_each_block_1(key_1, ctx) {
- let first;
- let day;
- let current;
- day = new Day({
- props: {
- date: ctx[21],
- today: ctx[10],
- displayedMonth: ctx[0],
- onClick: ctx[6],
- onContextMenu: ctx[4],
- onHover: ctx[2],
- metadata: getDailyMetadata( ctx[8], ctx[21], ctx[10]),
- selectedId: ctx[9]
- }
- });
- return {
- key: key_1,
- first: null,
- c() {
- first = empty();
- create_component(day.$$.fragment);
- this.first = first;
- },
- m(target, anchor) {
- insert(target, first, anchor);
- mount_component(day, target, anchor);
- current = true;
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- const day_changes = {};
- if (dirty & 16384) day_changes.date = ctx[21];
- if (dirty & 1024) day_changes.today = ctx[10];
- if (dirty & 1) day_changes.displayedMonth = ctx[0];
- if (dirty & 64) day_changes.onClick = ctx[6];
- if (dirty & 16) day_changes.onContextMenu = ctx[4];
- if (dirty & 4) day_changes.onHover = ctx[2];
- if (dirty & 17664) day_changes.metadata = getDailyMetadata( ctx[8], ctx[21], ctx[10]);
- if (dirty & 512) day_changes.selectedId = ctx[9];
- day.$set(day_changes);
- },
- i(local) {
- if (current) return;
- transition_in(day.$$.fragment, local);
- current = true;
- },
- o(local) {
- transition_out(day.$$.fragment, local);
- current = false;
- },
- d(detaching) {
- if (detaching) detach(first);
- destroy_component(day, detaching);
- }
- };
- }
- function create_each_block(key_1, ctx) {
- let tr;
- let t0;
- let each_blocks = [];
- let each_1_lookup = new Map();
- let t1;
- let current;
- let if_block = ctx[1] && create_if_block(ctx);
- let each_value_1 = ctx[18].days;
- const get_key = ctx => ctx[21].format();
- for (let i = 0; i < each_value_1.length; i += 1) {
- let child_ctx = get_each_context_1(ctx, each_value_1, i);
- let key = get_key(child_ctx);
- each_1_lookup.set(key, each_blocks[i] = create_each_block_1(key, child_ctx));
- }
- return {
- key: key_1,
- first: null,
- c() {
- tr = element("tr");
- if (if_block) if_block.c();
- t0 = space();
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- t1 = space();
- this.first = tr;
- },
- m(target, anchor) {
- insert(target, tr, anchor);
- if (if_block) if_block.m(tr, null);
- append(tr, t0);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(tr, null);
- }
- append(tr, t1);
- current = true;
- },
- p(new_ctx, dirty) {
- ctx = new_ctx;
- if ( ctx[1]) {
- if (if_block) {
- if_block.p(ctx, dirty);
- if (dirty & 2) {
- transition_in(if_block, 1);
- }
- } else {
- if_block = create_if_block(ctx);
- if_block.c();
- transition_in(if_block, 1);
- if_block.m(tr, t0);
- }
- } else if (if_block) {
- group_outros();
- transition_out(if_block, 1, 1, () => {
- if_block = null;
- });
- check_outros();
- }
- if (dirty & 18261) {
- each_value_1 = ctx[18].days;
- group_outros();
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value_1, each_1_lookup, tr, outro_and_destroy_block, create_each_block_1, t1, get_each_context_1);
- check_outros();
- }
- },
- i(local) {
- if (current) return;
- transition_in(if_block);
- for (let i = 0; i < each_value_1.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- transition_out(if_block);
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching) detach(tr);
- if (if_block) if_block.d();
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
- }
- };
- }
- function create_fragment(ctx) {
- let div;
- let nav;
- let t0;
- let table;
- let colgroup;
- let t1;
- let t2;
- let thead;
- let tr;
- let t3;
- let t4;
- let tbody;
- let each_blocks = [];
- let each2_lookup = new Map();
- let current;
- nav = new Nav({
- props: {
- today: ctx[10],
- displayedMonth: ctx[0],
- incrementDisplayedMonth: ctx[11],
- decrementDisplayedMonth: ctx[12],
- resetDisplayedMonth: ctx[13]
- }
- });
- let if_block0 = ctx[1] && create_if_block_2();
- let each_value_3 = ctx[14][1].days;
- let each_blocks_2 = [];
- for (let i = 0; i < each_value_3.length; i += 1) {
- each_blocks_2[i] = create_each_block_3(get_each_context_3(ctx, each_value_3, i));
- }
- let if_block1 = ctx[1] && create_if_block_1();
- let each_value_2 = ctx[15];
- let each_blocks_1 = [];
- for (let i = 0; i < each_value_2.length; i += 1) {
- each_blocks_1[i] = create_each_block_2(get_each_context_2(ctx, each_value_2, i));
- }
- let each_value = ctx[14];
- const get_key = ctx => ctx[18].weekNum;
- for (let i = 0; i < each_value.length; i += 1) {
- let child_ctx = get_each_context(ctx, each_value, i);
- let key = get_key(child_ctx);
- each2_lookup.set(key, each_blocks[i] = create_each_block(key, child_ctx));
- }
- return {
- c() {
- div = element("div");
- create_component(nav.$$.fragment);
- t0 = space();
- table = element("table");
- colgroup = element("colgroup");
- if (if_block0) if_block0.c();
- t1 = space();
- for (let i = 0; i < each_blocks_2.length; i += 1) {
- each_blocks_2[i].c();
- }
- t2 = space();
- thead = element("thead");
- tr = element("tr");
- if (if_block1) if_block1.c();
- t3 = space();
- for (let i = 0; i < each_blocks_1.length; i += 1) {
- each_blocks_1[i].c();
- }
- t4 = space();
- tbody = element("tbody");
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].c();
- }
- attr(table, "class", "calendar svelte-pcimu8");
- attr(div, "id", "calendar-container");
- attr(div, "class", "container svelte-pcimu8");
- toggle_class(div, "is-mobile", ctx[16]);
- },
- m(target, anchor) {
- insert(target, div, anchor);
- mount_component(nav, div, null);
- append(div, t0);
- append(div, table);
- append(table, colgroup);
- if (if_block0) if_block0.m(colgroup, null);
- append(colgroup, t1);
- for (let i = 0; i < each_blocks_2.length; i += 1) {
- each_blocks_2[i].m(colgroup, null);
- }
- append(table, t2);
- append(table, thead);
- append(thead, tr);
- if (if_block1) if_block1.m(tr, null);
- append(tr, t3);
- for (let i = 0; i < each_blocks_1.length; i += 1) {
- each_blocks_1[i].m(tr, null);
- }
- append(table, t4);
- append(table, tbody);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].m(tbody, null);
- }
- current = true;
- },
- p(ctx, [dirty]) {
- const nav_changes = {};
- if (dirty & 1024) nav_changes.today = ctx[10];
- if (dirty & 1) nav_changes.displayedMonth = ctx[0];
- nav.$set(nav_changes);
- if (/*showWeekNums*/ ctx[1]) {
- if (if_block0) ; else {
- if_block0 = create_if_block_2();
- if_block0.c();
- if_block0.m(colgroup, t1);
- }
- } else if (if_block0) {
- if_block0.d(1);
- if_block0 = null;
- }
- if (dirty & 16384) {
- each_value_3 = ctx[14][1].days;
- let i;
- for (i = 0; i < each_value_3.length; i += 1) {
- const child_ctx = get_each_context_3(ctx, each_value_3, i);
- if (each_blocks_2[i]) {
- each_blocks_2[i].p(child_ctx, dirty);
- } else {
- each_blocks_2[i] = create_each_block_3(child_ctx);
- each_blocks_2[i].c();
- each_blocks_2[i].m(colgroup, null);
- }
- }
- for (; i < each_blocks_2.length; i += 1) {
- each_blocks_2[i].d(1);
- }
- each_blocks_2.length = each_value_3.length;
- }
- if ( ctx[1]) {
- if (if_block1) ; else {
- if_block1 = create_if_block_1();
- if_block1.c();
- if_block1.m(tr, t3);
- }
- } else if (if_block1) {
- if_block1.d(1);
- if_block1 = null;
- }
- if (dirty & 32768) {
- each_value_2 = ctx[15];
- let i;
- for (i = 0; i < each_value_2.length; i += 1) {
- const child_ctx = get_each_context_2(ctx, each_value_2, i);
- if (each_blocks_1[i]) {
- each_blocks_1[i].p(child_ctx, dirty);
- } else {
- each_blocks_1[i] = create_each_block_2(child_ctx);
- each_blocks_1[i].c();
- each_blocks_1[i].m(tr, null);
- }
- }
- for (; i < each_blocks_1.length; i += 1) {
- each_blocks_1[i].d(1);
- }
- each_blocks_1.length = each_value_2.length;
- }
- if (dirty & 18431) {
- each_value = ctx[14];
- group_outros();
- each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each2_lookup, tbody, outro_and_destroy_block, create_each_block, null, get_each_context);
- check_outros();
- }
- },
- i(local) {
- if (current) return;
- transition_in(nav.$$.fragment, local);
- for (let i = 0; i < each_value.length; i += 1) {
- transition_in(each_blocks[i]);
- }
- current = true;
- },
- o(local) {
- transition_out(nav.$$.fragment, local);
- for (let i = 0; i < each_blocks.length; i += 1) {
- transition_out(each_blocks[i]);
- }
- current = false;
- },
- d(detaching) {
- if (detaching) detach(div);
- destroy_component(nav);
- if (if_block0) if_block0.d();
- destroy_each(each_blocks_2, detaching);
- if (if_block1) if_block1.d();
- destroy_each(each_blocks_1, detaching);
- for (let i = 0; i < each_blocks.length; i += 1) {
- each_blocks[i].d();
- }
- }
- };
- }
- function instance($$self, $$props, $$invalidate) {
-
-
- let { localeData } = $$props;
- let { showWeekNums = false } = $$props;
- let { onHoverDay } = $$props;
- let { onHoverWeek } = $$props;
- let { onContextMenuDay } = $$props;
- let { onContextMenuWeek } = $$props;
- let { onClickDay } = $$props;
- let { onClickWeek } = $$props;
- let { sources = [] } = $$props;
- let { selectedId } = $$props;
- let { today = window.moment() } = $$props;
- let { displayedMonth = today } = $$props;
- let month;
- let daysOfWeek;
-
- let isMobile = window.app.isMobile;
- function incrementDisplayedMonth() {
- $$invalidate(0, displayedMonth = displayedMonth.clone().add(1, "month"));
- }
- function decrementDisplayedMonth() {
- $$invalidate(0, displayedMonth = displayedMonth.clone().subtract(1, "month"));
- }
- function resetDisplayedMonth() {
- $$invalidate(0, displayedMonth = today.clone());
- }
- $$self.$$set = $$props => {
- if ("localeData" in $$props) $$invalidate(17, localeData = $$props.localeData);
- if ("showWeekNums" in $$props) $$invalidate(1, showWeekNums = $$props.showWeekNums);
- if ("onHoverDay" in $$props) $$invalidate(2, onHoverDay = $$props.onHoverDay);
- if ("onHoverWeek" in $$props) $$invalidate(3, onHoverWeek = $$props.onHoverWeek);
- if ("onContextMenuDay" in $$props) $$invalidate(4, onContextMenuDay = $$props.onContextMenuDay);
- if ("onContextMenuWeek" in $$props) $$invalidate(5, onContextMenuWeek = $$props.onContextMenuWeek);
- if ("onClickDay" in $$props) $$invalidate(6, onClickDay = $$props.onClickDay);
- if ("onClickWeek" in $$props) $$invalidate(7, onClickWeek = $$props.onClickWeek);
- if ("sources" in $$props) $$invalidate(8, sources = $$props.sources);
- if ("selectedId" in $$props) $$invalidate(9, selectedId = $$props.selectedId);
- if ("today" in $$props) $$invalidate(10, today = $$props.today);
- if ("displayedMonth" in $$props) $$invalidate(0, displayedMonth = $$props.displayedMonth);
- };
- $$self.$$.update = () => {
- if ($$self.$$.dirty & 131073) {
- $$invalidate(14, month = getMonth(displayedMonth, localeData));
- }
- if ($$self.$$.dirty & 132096) {
- $$invalidate(15, daysOfWeek = getDaysOfWeek(today, localeData));
- }
- };
- return [
- displayedMonth,
- showWeekNums,
- onHoverDay,
- onHoverWeek,
- onContextMenuDay,
- onContextMenuWeek,
- onClickDay,
- onClickWeek,
- sources,
- selectedId,
- today,
- incrementDisplayedMonth,
- decrementDisplayedMonth,
- resetDisplayedMonth,
- month,
- daysOfWeek,
- isMobile,
- localeData
- ];
- }
- class Calendar extends SvelteComponent {
- constructor(options) {
- super();
- if (!document.getElementById("svelte-pcimu8-style")) add_css();
- init(this, options, instance, create_fragment, not_equal, {
- localeData: 17,
- showWeekNums: 1,
- onHoverDay: 2,
- onHoverWeek: 3,
- onContextMenuDay: 4,
- onContextMenuWeek: 5,
- onClickDay: 6,
- onClickWeek: 7,
- sources: 8,
- selectedId: 9,
- today: 10,
- displayedMonth: 0,
- incrementDisplayedMonth: 11,
- decrementDisplayedMonth: 12,
- resetDisplayedMonth: 13
- });
- }
- get incrementDisplayedMonth() {
- return this.$$.ctx[11];
- }
- get decrementDisplayedMonth() {
- return this.$$.ctx[12];
- }
- get resetDisplayedMonth() {
- return this.$$.ctx[13];
- }
- }
- class DataviewRefreshableRenderer extends obsidian.MarkdownRenderChild {
- container;
- index;
- app;
- settings;
- lastReload;
- constructor(container, index, app, settings) {
- super(container);
- this.container = container;
- this.index = index;
- this.app = app;
- this.settings = settings;
- this.lastReload = 0;
- }
- onload() {
- this.render();
- this.lastReload = this.index.revision;
-
- this.registerEvent(this.app.workspace.on("dataview:refresh-views", this.maybeRefresh));
-
- this.register(this.container.onNodeInserted(this.maybeRefresh));
- }
- maybeRefresh = () => {
-
-
- if (this.lastReload != this.index.revision && this.container.isShown() && this.settings.refreshEnabled) {
- this.lastReload = this.index.revision;
- this.render();
- }
- };
- }
- class DataviewCalendarRenderer extends DataviewRefreshableRenderer {
- query;
- container;
- index;
- origin;
- settings;
- app;
- calendar;
- constructor(query, container, index, origin, settings, app) {
- super(container, index, app, settings);
- this.query = query;
- this.container = container;
- this.index = index;
- this.origin = origin;
- this.settings = settings;
- this.app = app;
- }
- async render() {
- this.container.innerHTML = "";
- let maybeResult = await asyncTryOrPropogate(() => executeCalendar(this.query, this.index, this.origin, this.settings));
- if (!maybeResult.successful) {
- renderErrorPre(this.container, "Dataview: " + maybeResult.error);
- return;
- }
- else if (maybeResult.value.data.length == 0 && this.settings.warnOnEmptyResult) {
- renderErrorPre(this.container, "Dataview: Query returned 0 results.");
- return;
- }
- let dateMap = new Map();
- for (let data of maybeResult.value.data) {
- const dot = {
- color: "default",
- className: "note",
- isFilled: true,
- link: data.link,
- };
- const d = data.date.toFormat("yyyyLLdd");
- if (!dateMap.has(d)) {
- dateMap.set(d, [dot]);
- }
- else {
- dateMap.get(d)?.push(dot);
- }
- }
- const querySource = {
- getDailyMetadata: async (date) => {
- return {
- dots: dateMap.get(date.format("YYYYMMDD")) || [],
- };
- },
- };
- const sources = [querySource];
- const renderer = this;
- this.calendar = new Calendar({
-
- target: this.container,
- props: {
- onHoverDay(date, targetEl) {
- const vals = dateMap.get(date.format("YYYYMMDD"));
- if (!vals || vals.length == 0) {
- return;
- }
- if (vals?.length == 0) {
- return;
- }
- renderer.app.workspace.trigger("link-hover", {}, targetEl, vals[0].link.path, vals[0].link.path);
- },
- onClickDay: async (date) => {
- const vals = dateMap.get(date.format("YYYYMMDD"));
- if (!vals || vals.length == 0) {
- return;
- }
- if (vals?.length == 0) {
- return;
- }
- const file = renderer.app.metadataCache.getFirstLinkpathDest(vals[0].link.path, "");
- if (file == null) {
- return;
- }
- const leaf = renderer.app.workspace.getUnpinnedLeaf();
- await leaf.openFile(file, { active: true });
- },
- showWeekNums: false,
- sources,
- },
- });
- }
- onClose() {
- if (this.calendar) {
- this.calendar.$destroy();
- }
- return Promise.resolve();
- }
- }
- class DataviewInlineIOApi {
- api;
- currentFile;
- constructor(api, currentFile) {
- this.api = api;
- this.currentFile = currentFile;
- }
-
- async csv(path, originFile) {
- return this.api.csv(path, originFile || this.currentFile);
- }
-
- async load(path, originFile) {
- return this.api.load(path, originFile || this.currentFile);
- }
-
- normalize(path, originFile) {
- return this.api.normalize(path, originFile || this.currentFile);
- }
- }
- class DataviewInlineApi {
-
- index;
-
- component;
-
- currentFilePath;
-
- container;
-
- app;
-
- api;
-
- settings;
-
- evaluationContext;
-
- value = Values;
-
- widget = Widgets;
-
- io;
-
- luxon = Luxon;
-
- func;
- constructor(api, component, container, currentFilePath) {
- this.index = api.index;
- this.app = api.app;
- this.settings = api.settings;
- this.component = component;
- this.container = container;
- this.currentFilePath = currentFilePath;
- this.api = api;
- this.io = new DataviewInlineIOApi(this.api.io, this.currentFilePath);
-
- let fileMeta = this.index.pages.get(this.currentFilePath)?.serialize(this.index) ?? {};
- this.evaluationContext = new Context(defaultLinkHandler(this.index, this.currentFilePath), this.settings, {
- this: fileMeta,
- });
- this.func = Functions.bindAll(DEFAULT_FUNCTIONS, this.evaluationContext);
- }
-
-
-
-
- pagePaths(query) {
- return this.api.pagePaths(query, this.currentFilePath);
- }
-
- page(path) {
- return this.api.page(path, this.currentFilePath);
- }
-
- pages(query) {
- return this.api.pages(query, this.currentFilePath);
- }
-
- current() {
- return this.page(this.currentFilePath);
- }
-
-
-
-
- async query(source, originFile, settings) {
- return this.api.query(source, originFile ?? this.currentFilePath, settings);
- }
-
- async tryQuery(source, originFile, settings) {
- return this.api.tryQuery(source, originFile ?? this.currentFilePath, settings);
- }
-
- async queryMarkdown(source, originFile, settings) {
- return this.api.queryMarkdown(source, originFile ?? this.currentFilePath, settings);
- }
-
- async tryQueryMarkdown(source, originFile, settings) {
- return this.api.tryQueryMarkdown(source, originFile ?? this.currentFilePath, settings);
- }
-
- evaluate(expression, context) {
- let field = EXPRESSION.field.parse(expression);
- if (!field.status)
- return Result.failure(`Failed to parse expression "${expression}"`);
- return this.evaluationContext.evaluate(field.value, context);
- }
-
- tryEvaluate(expression, context) {
- return this.evaluate(expression, context).orElseThrow();
- }
-
- async execute(source) {
- this.api.execute(source, this.container, this.component, this.currentFilePath);
- }
-
- async executeJs(code) {
- this.api.executeJs(code, this.container, this.component, this.currentFilePath);
- }
-
-
-
-
- array(raw) {
- return this.api.array(raw);
- }
-
- isArray(raw) {
- return this.api.isArray(raw);
- }
-
- isDataArray(raw) {
- return DataArray.isDataArray(raw);
- }
-
- fileLink(path, embed = false, display) {
- return Link.file(path, embed, display);
- }
-
- sectionLink(path, section, embed = false, display) {
- return Link.header(path, section, embed, display);
- }
-
- blockLink(path, blockId, embed = false, display) {
- return Link.block(path, blockId, embed, display);
- }
-
- date(pathlike) {
- return this.api.date(pathlike);
- }
-
- duration(dur) {
- return this.api.duration(dur);
- }
-
- parse(value) {
- return this.api.parse(value);
- }
-
- literal(value) {
- return this.api.literal(value);
- }
-
- clone(value) {
- return Values.deepCopy(value);
- }
-
- compare(a, b) {
- return Values.compareValue(a, b);
- }
-
- equal(a, b) {
- return this.compare(a, b) == 0;
- }
-
-
-
-
- el(el, text, { container = this.container, ...options } = {}) {
- let wrapped = Values.wrapValue(text);
- if (wrapped === null || wrapped === undefined) {
- return container.createEl(el, Object.assign({ text }, options));
- }
- let _el = container.createEl(el, options);
- renderValue(this.app, wrapped.value, _el, this.currentFilePath, this.component, this.settings, true);
- return _el;
- }
-
- header(level, text, options) {
- let header = { 1: "h1", 2: "h2", 3: "h3", 4: "h4", 5: "h5", 6: "h6" }[level];
- if (!header)
- throw Error(`Unrecognized level '${level}' (expected 1, 2, 3, 4, 5, or 6)`);
- return this.el(header, text, options);
- }
-
- paragraph(text, options) {
- return this.el("p", text, options);
- }
-
- span(text, options) {
- return this.el("span", text, options);
- }
-
- async view(viewName, input) {
-
- const simpleViewPath = `${viewName}.js`;
- const complexViewPath = `${viewName}/view.js`;
- let checkForCss = false;
- let cssElement = undefined;
- let viewFile = this.app.metadataCache.getFirstLinkpathDest(simpleViewPath, this.currentFilePath);
- if (!viewFile) {
- viewFile = this.app.metadataCache.getFirstLinkpathDest(complexViewPath, this.currentFilePath);
- checkForCss = true;
- }
- if (!viewFile) {
- renderErrorPre(this.container, `Dataview: custom view not found for '${simpleViewPath}' or '${complexViewPath}'.`);
- return;
- }
- if (checkForCss) {
-
- let cssFile = this.app.metadataCache.getFirstLinkpathDest(`${viewName}/view.css`, this.currentFilePath);
- if (cssFile) {
- let cssContents = await this.app.vault.read(cssFile);
- cssContents += `\n/*# sourceURL=${location.origin}/${cssFile.path} */`;
- cssElement = this.container.createEl("style", { text: cssContents, attr: { scope: " " } });
- }
- }
- let contents = await this.app.vault.read(viewFile);
- if (contents.contains("await"))
- contents = "(async () => { " + contents + " })()";
- contents += `\n//# sourceURL=${viewFile.path}`;
- let func = new Function("dv", "input", contents);
- try {
-
- let result = await Promise.resolve(func(this, input));
- if (result)
- await renderValue(this.app, result, this.container, this.currentFilePath, this.component, this.settings, true);
- }
- catch (ex) {
- if (cssElement)
- this.container.removeChild(cssElement);
- renderErrorPre(this.container, `Dataview: Failed to execute view '${viewFile.path}'.\n\n${ex}`);
- }
- }
-
- list(values) {
- return this.api.list(values, this.container, this.component, this.currentFilePath);
- }
-
- table(headers, values) {
- return this.api.table(headers, values, this.container, this.component, this.currentFilePath);
- }
-
- taskList(tasks, groupByFile = true) {
- return this.api.taskList(tasks, groupByFile, this.container, this.component, this.currentFilePath);
- }
-
-
-
-
- markdownTable(headers, values, settings) {
- return this.api.markdownTable(headers, values, settings);
- }
-
- markdownList(values, settings) {
- return this.api.markdownList(values, settings);
- }
-
- markdownTaskList(values, settings) {
- return this.api.markdownTaskList(values, settings);
- }
- }
- function evalInContext(script, context) {
- return function () {
- return eval(script);
- }.call(context);
- }
- async function asyncEvalInContext(script, context) {
- if (script.includes("await")) {
- return evalInContext("(async () => { " + script + " })()", context);
- }
- else {
- return Promise.resolve(evalInContext(script, context));
- }
- }
- class DataviewJSRenderer extends DataviewRefreshableRenderer {
- api;
- script;
- container;
- origin;
- static PREAMBLE = "const dataview = this;const dv = this;";
- constructor(api, script, container, origin) {
- super(container, api.index, api.app, api.settings);
- this.api = api;
- this.script = script;
- this.container = container;
- this.origin = origin;
- }
- async render() {
- this.container.innerHTML = "";
- if (!this.settings.enableDataviewJs) {
- this.containerEl.innerHTML = "";
- renderErrorPre(this.container, "Dataview JS queries are disabled. You can enable them in the Dataview settings.");
- return;
- }
-
- try {
- await asyncEvalInContext(DataviewJSRenderer.PREAMBLE + this.script, new DataviewInlineApi(this.api, this, this.container, this.origin));
- }
- catch (e) {
- this.containerEl.innerHTML = "";
- renderErrorPre(this.container, "Evaluation Error: " + e.stack);
- }
- }
- }
- class DataviewInlineJSRenderer extends DataviewRefreshableRenderer {
- api;
- script;
- container;
- target;
- origin;
- static PREAMBLE = "const dataview = this;const dv=this;";
-
- errorbox;
- constructor(api, script, container, target, origin) {
- super(container, api.index, api.app, api.settings);
- this.api = api;
- this.script = script;
- this.container = container;
- this.target = target;
- this.origin = origin;
- }
- async render() {
- this.errorbox?.remove();
- if (!this.settings.enableDataviewJs || !this.settings.enableInlineDataviewJs) {
- let temp = document.createElement("span");
- temp.innerText = "(disabled; enable in settings)";
- this.target.replaceWith(temp);
- this.target = temp;
- return;
- }
-
- try {
- let temp = document.createElement("span");
- let result = await asyncEvalInContext(DataviewInlineJSRenderer.PREAMBLE + this.script, new DataviewInlineApi(this.api, this, temp, this.origin));
- this.target.replaceWith(temp);
- this.target = temp;
- if (result === undefined)
- return;
- renderValue(this.api.app, result, temp, this.origin, this, this.settings, false);
- }
- catch (e) {
- this.errorbox = this.container.createEl("div");
- renderErrorPre(this.errorbox, "Dataview (for inline JS query '" + this.script + "'): " + e);
- }
- }
- }
- function markdownTable(headers, values, settings) {
- if (values.length > 0 && headers.length != values[0].length)
- throw new Error(`The number of headers (${headers.length}) must match the number of columns (${values[0].length})`);
- settings = settings ?? DEFAULT_SETTINGS;
- const mvalues = [];
- const maxLengths = Array.from(headers, v => escapeTable(v).length);
-
- for (let row = 0; row < values.length; row++) {
- const current = [];
- for (let col = 0; col < values[row].length; col++) {
- const text = tableLiteral(values[row][col], settings.allowHtml, settings);
- current.push(text);
- maxLengths[col] = Math.max(maxLengths[col], text.length);
- }
- mvalues.push(current);
- }
-
-
- let table = `| ${headers.map((v, i) => padright(escapeTable(v), " ", maxLengths[i])).join(" | ")} |\n`;
-
- table += `| ${maxLengths.map(i => padright("", "-", i)).join(" | ")} |\n`;
-
- for (let row = 0; row < values.length; row++) {
- table += `| ${mvalues[row].map((v, i) => padright(v, " ", maxLengths[i])).join(" | ")} |\n`;
- }
- return table;
- }
- function tableLiteral(value, allowHtml = true, settings) {
- return escapeTable(rawTableLiteral(value, allowHtml, settings));
- }
- function rawTableLiteral(value, allowHtml = true, settings) {
- if (!allowHtml)
- return Values.toString(value, settings);
- if (Values.isArray(value)) {
- return `<ul>${value.map(v => "<li>" + tableLiteral(v, allowHtml, settings) + "</li>").join("")}</ul>`;
- }
- else if (Values.isObject(value)) {
- const inner = Object.entries(value)
- .map(([k, v]) => {
- return `<li><b>${tableLiteral(k, allowHtml, settings)}</b>: ${tableLiteral(v, allowHtml, settings)}</li>`;
- })
- .join("");
- return `<ul>${inner}</ul>`;
- }
- else {
- return Values.toString(value, settings);
- }
- }
- function padright(text, padding, length) {
- if (text.length >= length)
- return text;
- return text + padding.repeat(length - text.length);
- }
- function escapeTable(text) {
- return text.split(/(?!\\)\|/i).join("\\|");
- }
- function markdownList(values, settings) {
- return markdownListRec(values, settings, 0);
- }
- function markdownListRec(input, settings, depth = 0) {
- if (Values.isArray(input)) {
- let result = depth == 0 ? "" : "\n";
- for (let value of input) {
- result += " ".repeat(depth) + "- ";
- result += markdownListRec(value, settings, depth);
- result += "\n";
- }
- return result;
- }
- else if (Values.isObject(input)) {
- let result = depth == 0 ? "" : "\n";
- for (let [key, value] of Object.entries(input)) {
- result += " ".repeat(depth) + "- ";
- result += Values.toString(key) + ": ";
- result += markdownListRec(value, settings, depth);
- result += "\n";
- }
- return result;
- }
- else if (Values.isWidget(input) && Widgets.isListPair(input)) {
- return `${Values.toString(input.key)}: ${markdownListRec(input.value, settings, depth + 1)}`;
- }
- return Values.toString(input);
- }
- function markdownTaskList(tasks, settings, depth = 0) {
- if (Groupings.isGrouping(tasks)) {
- let result = "";
- for (let element of tasks) {
- result += "#".repeat(depth + 1) + " " + Values.toString(element.key) + "\n\n";
- result += markdownTaskList(element.rows, settings, depth + 1);
- }
- return result;
- }
- else {
-
- const [dedupTasks, _] = nestItems(tasks);
- let result = "";
- for (let element of dedupTasks) {
- result += " ".repeat(depth) + "- ";
- if (element.task) {
- result += `[${element.status}] ${(element.visual ?? element.text).split("\n").join(" ")}\n`;
- }
- else {
- result += `${(element.visual ?? element.text).split("\n").join(" ")}\n`;
- }
- result += markdownTaskList(element.children, settings, depth + 1);
- }
- return result;
- }
- }
- class DataviewIOApi {
- api;
- constructor(api) {
- this.api = api;
- }
-
- async csv(path, originFile) {
- if (!Values.isLink(path) && !Values.isString(path)) {
- throw Error(`dv.io.csv only handles string or link paths; was provided type '${typeof path}'.`);
- }
- let data = await this.api.index.csv.get(this.normalize(path, originFile));
- if (data.successful)
- return DataArray.from(data.value, this.api.settings);
- else
- throw Error(`Could not find CSV for path '${path}' (relative to origin '${originFile ?? "/"}')`);
- }
-
- async load(path, originFile) {
- if (!Values.isLink(path) && !Values.isString(path)) {
- throw Error(`dv.io.load only handles string or link paths; was provided type '${typeof path}'.`);
- }
- let existingFile = this.api.index.vault.getAbstractFileByPath(this.normalize(path, originFile));
- if (!existingFile || !(existingFile instanceof obsidian.TFile))
- return undefined;
- return this.api.index.vault.cachedRead(existingFile);
- }
-
- normalize(path, originFile) {
- let realPath;
- if (Values.isLink(path))
- realPath = path.path;
- else
- realPath = path;
- return this.api.index.prefix.resolveRelative(realPath, originFile);
- }
- }
- class DataviewApi {
- app;
- index;
- settings;
- verNum;
-
- evaluationContext;
-
- io;
-
- func;
-
- value = Values;
-
- widget = Widgets;
-
- luxon = Luxon;
- constructor(app, index, settings, verNum) {
- this.app = app;
- this.index = index;
- this.settings = settings;
- this.verNum = verNum;
- this.evaluationContext = new Context(defaultLinkHandler(index, ""), settings);
- this.func = Functions.bindAll(DEFAULT_FUNCTIONS, this.evaluationContext);
- this.io = new DataviewIOApi(this);
- }
-
- version = (() => {
- const self = this;
- return {
- get current() {
- return self.verNum;
- },
- compare: (op, ver) => compare(this.verNum, ver, op),
- satisfies: (range) => satisfies(this.verNum, range),
- };
- })();
-
-
-
-
- pagePaths(query, originFile) {
- let source;
- try {
- if (!query || query.trim() === "")
- source = Sources.folder("");
- else
- source = EXPRESSION.source.tryParse(query);
- }
- catch (ex) {
- throw new Error(`Failed to parse query in 'pagePaths': ${ex}`);
- }
- return matchingSourcePaths(source, this.index, originFile)
- .map(s => DataArray.from(s, this.settings))
- .orElseThrow();
- }
-
- page(path, originFile) {
- if (!(typeof path === "string") && !Values.isLink(path)) {
- throw Error("dv.page only handles string and link paths; was provided type '" + typeof path + "'");
- }
- let rawPath = path instanceof Link ? path.path : path;
- let normPath = this.app.metadataCache.getFirstLinkpathDest(rawPath, originFile ?? "");
- if (!normPath)
- return undefined;
- let pageObject = this.index.pages.get(normPath.path);
- if (!pageObject)
- return undefined;
- return this._addDataArrays(pageObject.serialize(this.index));
- }
-
- pages(query, originFile) {
- return this.pagePaths(query, originFile).flatMap(p => {
- let res = this.page(p, originFile);
- return res ? [res] : [];
- });
- }
-
- _addDataArrays(pageObject) {
-
- for (let [key, value] of Object.entries(pageObject.file)) {
- if (Array.isArray(value))
- pageObject.file[key] = DataArray.wrap(value, this.settings);
- }
- return pageObject;
- }
-
-
-
-
- array(raw) {
- if (DataArray.isDataArray(raw))
- return raw;
- if (Array.isArray(raw))
- return DataArray.wrap(raw, this.settings);
- return DataArray.wrap([raw], this.settings);
- }
-
- isArray(raw) {
- return DataArray.isDataArray(raw) || Array.isArray(raw);
- }
-
- isDataArray(raw) {
- return DataArray.isDataArray(raw);
- }
-
- fileLink(path, embed = false, display) {
- return Link.file(path, embed, display);
- }
-
- sectionLink(path, section, embed = false, display) {
- return Link.header(path, section, embed, display);
- }
-
- blockLink(path, blockId, embed = false, display) {
- return Link.block(path, blockId, embed, display);
- }
-
- date(pathlike) {
- return this.func.date(pathlike);
- }
-
- duration(str) {
- return this.func.dur(str);
- }
-
- parse(value) {
- let raw = EXPRESSION.inlineField.parse(value);
- if (raw.status)
- return raw.value;
- else
- return value;
- }
-
- literal(value) {
- return parseFrontmatter(value);
- }
-
- clone(value) {
- return Values.deepCopy(value);
- }
-
- compare(a, b) {
- return Values.compareValue(a, b, this.evaluationContext.linkHandler.normalize);
- }
-
- equal(a, b) {
- return this.compare(a, b) == 0;
- }
-
-
-
-
- async query(source, originFile, settings) {
- const query = typeof source === "string" ? parseQuery(source) : Result.success(source);
- if (!query.successful)
- return query.cast();
- const header = query.value.header;
- switch (header.type) {
- case "calendar":
- const cres = await executeCalendar(query.value, this.index, originFile ?? "", this.settings);
- if (!cres.successful)
- return cres.cast();
- return Result.success({ type: "calendar", values: cres.value.data });
- case "task":
- const tasks = await executeTask(query.value, originFile ?? "", this.index, this.settings);
- if (!tasks.successful)
- return tasks.cast();
- return Result.success({ type: "task", values: tasks.value.tasks });
- case "list":
- if (settings?.forceId !== undefined)
- header.showId = settings.forceId;
- const lres = await executeList(query.value, this.index, originFile ?? "", this.settings);
- if (!lres.successful)
- return lres.cast();
-
-
- return Result.success({
- type: "list",
- values: lres.value.data,
- primaryMeaning: lres.value.primaryMeaning,
- });
- case "table":
- if (settings?.forceId !== undefined)
- header.showId = settings.forceId;
- const tres = await executeTable(query.value, this.index, originFile ?? "", this.settings);
- if (!tres.successful)
- return tres.cast();
- return Result.success({
- type: "table",
- values: tres.value.data,
- headers: tres.value.names,
- idMeaning: tres.value.idMeaning,
- });
- }
- }
-
- async tryQuery(source, originFile, settings) {
- return (await this.query(source, originFile, settings)).orElseThrow();
- }
-
- async queryMarkdown(source, originFile, settings) {
- const result = await this.query(source, originFile, settings);
- if (!result.successful)
- return result.cast();
- switch (result.value.type) {
- case "list":
- return Result.success(this.markdownList(result.value.values, settings));
- case "table":
- return Result.success(this.markdownTable(result.value.headers, result.value.values, settings));
- case "task":
- return Result.success(this.markdownTaskList(result.value.values, settings));
- case "calendar":
- return Result.failure("Cannot render calendar queries to markdown.");
- }
- }
-
- async tryQueryMarkdown(source, originFile, settings) {
- return (await this.queryMarkdown(source, originFile, settings)).orElseThrow();
- }
-
- evaluate(expression, context, originFile) {
- let field = EXPRESSION.field.parse(expression);
- if (!field.status)
- return Result.failure(`Failed to parse expression "${expression}"`);
- let evaluationContext = originFile
- ? new Context(defaultLinkHandler(this.index, originFile), this.settings)
- : this.evaluationContext;
- return evaluationContext.evaluate(field.value, context);
- }
-
- tryEvaluate(expression, context, originFile) {
- return this.evaluate(expression, context, originFile).orElseThrow();
- }
-
- evaluateInline(expression, origin) {
- let field = EXPRESSION.field.parse(expression);
- if (!field.status)
- return Result.failure(`Failed to parse expression "${expression}"`);
- return executeInline(field.value, origin, this.index, this.settings);
- }
-
-
-
-
- async execute(source, container, component, filePath) {
- if (isDataviewDisabled(filePath)) {
- renderCodeBlock(container, source);
- return;
- }
- let maybeQuery = tryOrPropogate(() => parseQuery(source));
-
- if (!maybeQuery.successful) {
- renderErrorPre(container, "Dataview: " + maybeQuery.error);
- return;
- }
- let query = maybeQuery.value;
- let init = { app: this.app, settings: this.settings, index: this.index, container };
- let childComponent;
- switch (query.header.type) {
- case "task":
- childComponent = createTaskView(init, query, filePath);
- component.addChild(childComponent);
- break;
- case "list":
- childComponent = createListView(init, query, filePath);
- component.addChild(childComponent);
- break;
- case "table":
- childComponent = createTableView(init, query, filePath);
- component.addChild(childComponent);
- break;
- case "calendar":
- childComponent = new DataviewCalendarRenderer(query, container, this.index, filePath, this.settings, this.app);
- component.addChild(childComponent);
- break;
- }
- childComponent.load();
- }
-
- async executeJs(code, container, component, filePath) {
- if (isDataviewDisabled(filePath)) {
- renderCodeBlock(container, code, "javascript");
- return;
- }
- const renderer = new DataviewJSRenderer(this, code, container, filePath);
- renderer.load();
- component.addChild(renderer);
- }
-
- async list(values, container, component, filePath) {
- if (!values)
- return;
- if (values !== undefined && values !== null && !Array.isArray(values) && !DataArray.isDataArray(values))
- values = Array.from(values);
-
- let subcontainer = container.createEl("div");
- component.addChild(createFixedListView({ app: this.app, settings: this.settings, index: this.index, container: subcontainer }, values, filePath));
- }
-
- async table(headers, values, container, component, filePath) {
- if (!headers)
- headers = [];
- if (!values)
- values = [];
- if (!Array.isArray(headers) && !DataArray.isDataArray(headers))
- headers = Array.from(headers);
-
- let subcontainer = container.createEl("div");
- component.addChild(createFixedTableView({ app: this.app, settings: this.settings, index: this.index, container: subcontainer }, headers, values, filePath));
- }
-
- async taskList(tasks, groupByFile = true, container, component, filePath = "") {
- let groupedTasks = !Groupings.isGrouping(tasks) && groupByFile ? this.array(tasks).groupBy(t => Link.file(t.path)) : tasks;
-
- let taskContainer = container.createEl("div");
- component.addChild(createFixedTaskView({ app: this.app, settings: this.settings, index: this.index, container: taskContainer }, groupedTasks, filePath));
- }
-
- async renderValue(value, container, component, filePath, inline = false) {
- return renderValue(this.app, value, container, filePath, component, this.settings, inline);
- }
-
-
-
-
- markdownTable(headers, values, settings) {
- if (!headers)
- headers = [];
- if (!values)
- values = [];
- const combined = Object.assign({}, this.settings, settings);
- return markdownTable(headers, values, combined);
- }
-
- markdownList(values, settings) {
- if (!values)
- values = [];
- const combined = Object.assign({}, this.settings, settings);
- return markdownList(values, combined);
- }
-
- markdownTaskList(values, settings) {
- if (!values)
- values = [];
- const sparse = nestGroups(values);
- const combined = Object.assign({}, this.settings, settings);
- return markdownTaskList(sparse, combined);
- }
- }
- function isDataviewDisabled(sourcePath) {
- if (!sourcePath)
- return false;
- let questionLocation = sourcePath.lastIndexOf("?");
- if (questionLocation == -1)
- return false;
- return sourcePath.substring(questionLocation).contains("no-dataview");
- }
- class DataviewInlineRenderer extends DataviewRefreshableRenderer {
- field;
- fieldText;
- container;
- target;
- index;
- origin;
- settings;
- app;
-
- errorbox;
- constructor(field, fieldText, container, target, index, origin, settings, app) {
- super(container, index, app, settings);
- this.field = field;
- this.fieldText = fieldText;
- this.container = container;
- this.target = target;
- this.index = index;
- this.origin = origin;
- this.settings = settings;
- this.app = app;
- }
- async render() {
- this.errorbox?.remove();
- let result = tryOrPropogate(() => executeInline(this.field, this.origin, this.index, this.settings));
- if (!result.successful) {
- this.errorbox = this.container.createEl("div");
- renderErrorPre(this.errorbox, "Dataview (for inline query '" + this.fieldText + "'): " + result.error);
- }
- else {
- let temp = document.createElement("span");
- temp.addClasses(["dataview", "dataview-inline-query"]);
- await renderValue(this.app, result.value, temp, this.origin, this, this.settings, false);
- this.target.replaceWith(temp);
- }
- }
- }
- async function replaceInlineFields(ctx, init) {
- const inlineFields = extractInlineFields(init.container.innerHTML);
- if (inlineFields.length == 0)
- return;
- const component = new obsidian.MarkdownRenderChild(init.container);
- ctx.addChild(component);
-
- let result = init.container.innerHTML;
- for (let x = inlineFields.length - 1; x >= 0; x--) {
- let field = inlineFields[x];
- let renderContainer = document.createElement("span");
- renderContainer.addClasses(["dataview", "inline-field"]);
-
- if (field.wrapping == "[") {
- const key = renderContainer.createSpan({
- cls: ["dataview", "inline-field-key"],
- attr: {
- "data-dv-key": field.key,
- "data-dv-norm-key": canonicalizeVarName(field.key),
- },
- });
-
- key.innerHTML = field.key;
- renderContainer.createSpan({
- cls: ["dataview", "inline-field-value"],
- attr: { id: "dataview-inline-field-" + x },
- });
- }
- else {
- renderContainer.createSpan({
- cls: ["dataview", "inline-field-standalone-value"],
- attr: { id: "dataview-inline-field-" + x },
- });
- }
- result = result.slice(0, field.start) + renderContainer.outerHTML + result.slice(field.end);
- }
-
- const template = document.createElement("template");
- template.innerHTML = result;
-
-
- init.container.replaceChildren(...template.content.childNodes);
- let inlineFieldsFromText;
- let hasRetrievedText = false;
- for (let index = 0; index < inlineFields.length; index++) {
- const box = init.container.querySelector("#dataview-inline-field-" + index);
- if (!box)
- continue;
- const context = Object.assign({}, init, { container: box, component: component });
- const parseInlineValueWrapper = (fieldVal) => {
- if (fieldVal.startsWith('<span class="math"')) {
-
- if (!hasRetrievedText) {
- hasRetrievedText = true;
- let text = ctx.getSectionInfo(init.container)?.text;
- if (text) {
- inlineFieldsFromText = extractInlineFields(text);
- }
- }
- if (!inlineFieldsFromText)
- return parseInlineValue(fieldVal);
- return parseInlineValue(inlineFieldsFromText[index].value);
- }
- else {
- return parseInlineValue(fieldVal);
- }
- };
- D$1(y$1(DataviewContext.Provider, { value: context },
- y$1(Lit, { value: parseInlineValueWrapper(inlineFields[index].value), inline: true, sourcePath: ctx.sourcePath })), box);
- }
- }
- function selectionAndRangeOverlap(selection, rangeFrom, rangeTo) {
- for (const range of selection.ranges) {
- if (range.from <= rangeTo && range.to >= rangeFrom) {
- return true;
- }
- }
- return false;
- }
- class InlineWidget extends view.WidgetType {
- cssClasses;
- rawQuery;
- el;
- view;
- constructor(cssClasses, rawQuery, el, view) {
- super();
- this.cssClasses = cssClasses;
- this.rawQuery = rawQuery;
- this.el = el;
- this.view = view;
- }
-
-
- eq(other) {
- if (other.rawQuery === this.rawQuery) {
-
- for (let value of other.cssClasses) {
- if (!this.cssClasses.includes(value)) {
- this.el.removeClass(value);
- }
- else {
- this.el.addClass(value);
- }
- }
- return true;
- }
- return false;
- }
-
-
- toDOM(view) {
- this.el.addClasses(this.cssClasses);
- return this.el;
- }
-
- ignoreEvent(event) {
-
- if (event.type === "mousedown") {
- const currentPos = this.view.posAtCoords({ x: event.x, y: event.y });
- if (event.shiftKey) {
-
- if (currentPos) {
- const { editor } = this.view.state.field(obsidian.editorInfoField);
- if (editor) {
- editor.setCursor(editor.offsetToPos(currentPos));
- }
- }
- return false;
- }
- }
- return true;
- }
- }
- function getCssClasses(props) {
- const classes = [];
- if (props.has("strong")) {
- classes.push("cm-strong");
- }
- if (props.has("em")) {
- classes.push("cm-em");
- }
- if (props.has("highlight")) {
- classes.push("cm-highlight");
- }
- if (props.has("strikethrough")) {
- classes.push("cm-strikethrough");
- }
- if (props.has("comment")) {
- classes.push("cm-comment");
- }
- return classes;
- }
- function inlinePlugin(app, index, settings, api) {
- return view.ViewPlugin.fromClass(class {
- decorations;
- component;
- constructor(view$1) {
- this.component = new obsidian.Component();
- this.component.load();
- this.decorations = this.inlineRender(view$1) ?? view.Decoration.none;
- }
- update(update) {
-
- if (!update.state.field(obsidian.editorLivePreviewField)) {
- this.decorations = view.Decoration.none;
- return;
- }
- if (update.docChanged) {
- this.decorations = this.decorations.map(update.changes);
- this.updateTree(update.view);
- }
- else if (update.selectionSet) {
- this.updateTree(update.view);
- }
- else if (update.viewportChanged ) {
- this.decorations = this.inlineRender(update.view) ?? view.Decoration.none;
- }
- }
- updateTree(view) {
- for (const { from, to } of view.visibleRanges) {
- language.syntaxTree(view.state).iterate({
- from,
- to,
- enter: ({ node }) => {
- const { render, isQuery } = this.renderNode(view, node);
- if (!render && isQuery) {
- this.removeDeco(node);
- return;
- }
- else if (!render) {
- return;
- }
- else if (render) {
- this.addDeco(node, view);
- }
- },
- });
- }
- }
- removeDeco(node) {
- this.decorations.between(node.from - 1, node.to + 1, (from, to, value) => {
- this.decorations = this.decorations.update({
- filterFrom: from,
- filterTo: to,
- filter: (from, to, value) => false,
- });
- });
- }
- addDeco(node, view) {
- const from = node.from - 1;
- const to = node.to + 1;
- let exists = false;
- this.decorations.between(from, to, (from, to, value) => {
- exists = true;
- });
- if (!exists) {
-
- const currentFile = view.state.field(obsidian.editorInfoField).file;
- if (!currentFile)
- return;
- const newDeco = this.renderWidget(node, view, currentFile)?.value;
- if (newDeco) {
- this.decorations = this.decorations.update({
- add: [{ from: from, to: to, value: newDeco }],
- });
- }
- }
- }
-
- renderNode(view, node) {
- const type = node.type;
-
- const tokenProps = type.prop(language.tokenClassNodeProp);
- const props = new Set(tokenProps?.split(" "));
- if (props.has("inline-code") && !props.has("formatting")) {
-
- const start = node.from;
- const end = node.to;
-
-
- const selection = view.state.selection;
- if (selectionAndRangeOverlap(selection, start - 1, end + 1)) {
- if (this.isInlineQuery(view, start, end)) {
- return { render: false, isQuery: true };
- }
- else {
- return { render: false, isQuery: false };
- }
- }
- else if (this.isInlineQuery(view, start, end)) {
- return { render: true, isQuery: true };
- }
- }
- return { render: false, isQuery: false };
- }
- isInlineQuery(view, start, end) {
- const text = view.state.doc.sliceString(start, end);
- const isInlineQuery = text.startsWith(settings.inlineQueryPrefix) || text.startsWith(settings.inlineJsQueryPrefix);
- return isInlineQuery;
- }
- inlineRender(view$1) {
-
- if (!index.initialized)
- return;
- const currentFile = view$1.state.field(obsidian.editorInfoField).file;
- if (!currentFile)
- return;
- const widgets = [];
-
- for (const { from, to } of view$1.visibleRanges) {
- language.syntaxTree(view$1.state).iterate({
- from,
- to,
- enter: ({ node }) => {
- if (!this.renderNode(view$1, node).render)
- return;
- const widget = this.renderWidget(node, view$1, currentFile);
- if (widget) {
- widgets.push(widget);
- }
- },
- });
- }
- return view.Decoration.set(widgets, true);
- }
- renderWidget(node, view$1, currentFile) {
- const type = node.type;
-
- const start = node.from;
- const end = node.to;
-
- if (view$1.state.doc.sliceString(end, end + 1) === "\n") {
- return;
- }
- const text = view$1.state.doc.sliceString(start, end);
- let code = "";
- let result = "";
- const PREAMBLE = "const dataview=this;const dv=this;";
- const el = createSpan({
- cls: ["dataview", "dataview-inline"],
- });
-
- if (text.startsWith(settings.inlineQueryPrefix)) {
- if (settings.enableInlineDataview) {
- code = text.substring(settings.inlineQueryPrefix.length).trim();
- const field = tryOrPropogate(() => parseField(code));
- if (!field.successful) {
- result = `Dataview (inline field '${code}'): ${field.error}`;
- el.innerText = result;
- }
- else {
- const fieldValue = field.value;
- const intermediateResult = tryOrPropogate(() => executeInline(fieldValue, currentFile.path, index, settings));
- if (!intermediateResult.successful) {
- result = `Dataview (for inline query '${fieldValue}'): ${intermediateResult.error}`;
- el.innerText = result;
- }
- else {
- const { value } = intermediateResult;
- result = value;
- renderValue(app, result, el, currentFile.path, this.component, settings);
- }
- }
- }
- else {
- result = "(disabled; enable in settings)";
- el.innerText = result;
- }
- }
- else if (text.startsWith(settings.inlineJsQueryPrefix)) {
- if (settings.enableInlineDataviewJs) {
- code = text.substring(settings.inlineJsQueryPrefix.length).trim();
- try {
-
- const myEl = createDiv();
- const dvInlineApi = new DataviewInlineApi(api, this.component, myEl, currentFile.path);
- if (code.includes("await")) {
- evalInContext("(async () => { " + PREAMBLE + code + " })()").then((result) => {
- renderValue(app, result, el, currentFile.path, this.component, settings);
- });
- }
- else {
- result = evalInContext(PREAMBLE + code);
- renderValue(app, result, el, currentFile.path, this.component, settings);
- }
- function evalInContext(script) {
- return function () {
- return eval(script);
- }.call(dvInlineApi);
- }
- }
- catch (e) {
- result = `Dataview (for inline JS query '${code}'): ${e}`;
- el.innerText = result;
- }
- }
- else {
- result = "(disabled; enable in settings)";
- el.innerText = result;
- }
- }
- else {
- return;
- }
- const tokenProps = type.prop(language.tokenClassNodeProp);
- const props = new Set(tokenProps?.split(" "));
- const classes = getCssClasses(props);
- return view.Decoration.replace({
- widget: new InlineWidget(classes, code, el, view$1),
- inclusive: false,
- block: false,
- }).range(start - 1, end + 1);
- }
- destroy() {
- this.component.unload();
- }
- }, { decorations: v => v.decorations });
- }
- class InlineFieldValue extends state.RangeValue {
- field;
- constructor(field) {
- super();
- this.field = field;
- }
- eq(other) {
- return this.field.key == other.field.key && this.field.value == other.field.value;
- }
- }
- function buildInlineFields(state$1) {
- const builder = new state.RangeSetBuilder();
- const tree = language.syntaxTree(state$1);
- for (let lineNumber = 1; lineNumber <= state$1.doc.lines; lineNumber++) {
- const line = state$1.doc.line(lineNumber);
- let isInsideCodeBlock = false;
- tree.iterate({
- from: line.from,
- to: line.to,
- enter: node => {
-
- if (node.name.startsWith("HyperMD-codeblock")) {
- isInsideCodeBlock = true;
- }
- return node.name == "Document";
- },
- });
- if (!isInsideCodeBlock) {
- const inlineFields = extractInlineFields(line.text);
- for (const field of inlineFields) {
- builder.add(line.from + field.start, line.from + field.end, new InlineFieldValue(field));
- }
- }
- }
- return builder.finish();
- }
- const inlineFieldsField = state.StateField.define({
- create: buildInlineFields,
- update(oldFields, tr) {
- return tr.docChanged ? buildInlineFields(tr.state) : oldFields;
- },
- });
- const replaceInlineFieldsInLivePreview = (app, settings) => view.ViewPlugin.fromClass(class {
- decorations;
- component;
- constructor(view) {
- this.component = new obsidian.Component();
- this.component.load();
- this.decorations = this.buildDecorations(view);
- }
- destroy() {
- this.component.unload();
- }
- buildDecorations(view$1) {
-
- if (!view$1.state.field(obsidian.editorLivePreviewField))
- return view.Decoration.none;
- const file = view$1.state.field(obsidian.editorInfoField).file;
- if (!file)
- return view.Decoration.none;
- const info = view$1.state.field(inlineFieldsField);
- const builder = new state.RangeSetBuilder();
- const selection = view$1.state.selection;
- for (const { from, to } of view$1.visibleRanges) {
- info.between(from, to, (start, end, { field }) => {
-
- if (!selectionAndRangeOverlap(selection, start, end)) {
- builder.add(start, end, view.Decoration.replace({
- widget: new InlineFieldWidget(app, field, file.path, this.component, settings, view$1),
- }));
- }
- });
- }
- return builder.finish();
- }
- update(update) {
-
- if (!update.state.field(obsidian.editorLivePreviewField)) {
- this.decorations = view.Decoration.none;
- return;
- }
- const layoutChanged = update.transactions.some(transaction => transaction.effects.some(effect => effect.is(workspaceLayoutChangeEffect)));
- if (update.docChanged) {
- this.decorations = this.decorations.map(update.changes);
- this.updateDecorations(update.view);
- }
- else if (update.selectionSet) {
- this.updateDecorations(update.view);
- }
- else if (update.viewportChanged || layoutChanged) {
- this.decorations = this.buildDecorations(update.view);
- }
- }
- updateDecorations(view$1) {
- const file = view$1.state.field(obsidian.editorInfoField).file;
- if (!file) {
- this.decorations = view.Decoration.none;
- return;
- }
- const inlineFields = view$1.state.field(inlineFieldsField);
- const selection = view$1.state.selection;
- for (const { from, to } of view$1.visibleRanges) {
- inlineFields.between(from, to, (start, end, { field }) => {
- const overlap = selectionAndRangeOverlap(selection, start, end);
- if (overlap) {
- this.removeDeco(start, end);
- return;
- }
- else {
- this.addDeco(start, end, field, file, view$1);
- }
- });
- }
- }
- removeDeco(start, end) {
- this.decorations.between(start, end, (from, to) => {
- this.decorations = this.decorations.update({
- filterFrom: from,
- filterTo: to,
- filter: () => false,
- });
- });
- }
- addDeco(start, end, field, file, view$1) {
- let exists = false;
- this.decorations.between(start, end, () => {
- exists = true;
- });
- if (!exists) {
- this.decorations = this.decorations.update({
- add: [
- {
- from: start,
- to: end,
- value: view.Decoration.replace({
- widget: new InlineFieldWidget(app, field, file.path, this.component, settings, view$1),
- }),
- },
- ],
- });
- }
- }
- }, {
- decorations: instance => instance.decorations,
- });
- class InlineFieldWidget extends view.WidgetType {
- app;
- field;
- sourcePath;
- component;
- settings;
- view;
- constructor(app, field, sourcePath, component, settings, view) {
- super();
- this.app = app;
- this.field = field;
- this.sourcePath = sourcePath;
- this.component = component;
- this.settings = settings;
- this.view = view;
- }
- eq(other) {
- return this.field.key == other.field.key && this.field.value == other.field.value;
- }
- toDOM() {
-
-
- const renderContainer = createSpan({
- cls: ["dataview", "inline-field"],
- });
-
- if (this.field.wrapping == "[") {
- const key = renderContainer.createSpan({
- cls: ["dataview", "inline-field-key"],
- attr: {
- "data-dv-key": this.field.key,
- "data-dv-norm-key": canonicalizeVarName(this.field.key),
- },
- });
- renderCompactMarkdown(this.app, this.field.key, key, this.sourcePath, this.component, true);
- const value = renderContainer.createSpan({
- cls: ["dataview", "inline-field-value"],
- });
- renderValue(this.app, parseInlineValue(this.field.value), value, this.sourcePath, this.component, this.settings, false, undefined, undefined, true);
- this.addKeyClickHandler(key, renderContainer);
- this.addValueClickHandler(value, renderContainer);
- }
- else {
- const value = renderContainer.createSpan({
- cls: ["dataview", "inline-field-standalone-value"],
- });
- renderValue(this.app, parseInlineValue(this.field.value), value, this.sourcePath, this.component, this.settings, false, undefined, undefined, true);
- this.addValueClickHandler(value, renderContainer);
- }
- return renderContainer;
- }
-
-
- addKeyClickHandler(key, renderContainer) {
- key.addEventListener("click", event => {
- if (event instanceof MouseEvent) {
- const rect = key.getBoundingClientRect();
- const relativePos = (event.x - rect.x) / rect.width;
- const startPos = this.view.posAtCoords(renderContainer.getBoundingClientRect(), false);
- const clickedPos = Math.round(startPos + (this.field.startValue - 2 - this.field.start) * relativePos);
- this.view.dispatch({ selection: { anchor: clickedPos } });
- }
- });
- }
- addValueClickHandler(value, renderContainer) {
- value.addEventListener("click", event => {
- if (event instanceof MouseEvent) {
- const rect = value.getBoundingClientRect();
- const relativePos = (event.x - rect.x) / rect.width;
- const startPos = this.view.posAtCoords(renderContainer.getBoundingClientRect(), false);
- const clickedPos = Math.round(startPos +
- (this.field.startValue - this.field.start) +
- (this.field.end - this.field.startValue) * relativePos);
- this.view.dispatch({ selection: { anchor: clickedPos } });
- }
- });
- }
- }
- const workspaceLayoutChangeEffect = state.StateEffect.define();
- class DataviewPlugin extends obsidian.Plugin {
-
- settings;
-
- index;
-
- api;
-
- cmExtension;
- async onload() {
-
- this.settings = Object.assign(DEFAULT_SETTINGS, (await this.loadData()) ?? {});
- this.addSettingTab(new GeneralSettingsTab(this.app, this));
- this.index = this.addChild(FullIndex.create(this.app, this.manifest.version, () => {
- if (this.settings.refreshEnabled)
- this.debouncedRefresh();
- }));
-
- this.updateRefreshSettings();
-
- this.api = new DataviewApi(this.app, this.index, this.settings, this.manifest.version);
-
- (window["DataviewAPI"] = this.api) && this.register(() => delete window["DataviewAPI"]);
-
- this.registerPriorityCodeblockPostProcessor("dataview", -100, async (source, el, ctx) => this.dataview(source, el, ctx, ctx.sourcePath));
-
- this.registerPriorityCodeblockPostProcessor(this.settings.dataviewJsKeyword, -100, async (source, el, ctx) => this.dataviewjs(source, el, ctx, ctx.sourcePath));
-
- this.registerPriorityMarkdownPostProcessor(-100, async (el, ctx) => {
-
- if (!this.settings.enableInlineDataview || isDataviewDisabled(ctx.sourcePath))
- return;
- this.dataviewInline(el, ctx, ctx.sourcePath);
- });
-
- this.registerPriorityMarkdownPostProcessor(100, async (el, ctx) => {
-
- if (!this.settings.prettyRenderInlineFields || isDataviewDisabled(ctx.sourcePath))
- return;
-
- for (let p of el.findAllSelf("p,h1,h2,h3,h4,h5,h6,li,span,th,td")) {
- const init = {
- app: this.app,
- index: this.index,
- settings: this.settings,
- container: p,
- };
- await replaceInlineFields(ctx, init);
- }
- });
-
- this.cmExtension = [];
- this.registerEditorExtension(this.cmExtension);
- this.updateEditorExtensions();
-
- this.addCommand({
- id: "dataview-force-refresh-views",
- name: "Force refresh all views and blocks",
- callback: () => {
- this.index.revision += 1;
- this.app.workspace.trigger("dataview:refresh-views");
- },
- });
- this.addCommand({
- id: "dataview-drop-cache",
- name: "Drop all cached file metadata",
- callback: () => {
- this.index.reinitialize();
- },
- });
- this.addCommand({
- id: "dataview-rebuild-current-view",
- name: "Rebuild current view",
- callback: () => {
- const activeView = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
- if (activeView) {
- activeView.leaf.rebuildView();
- }
- },
- });
-
- if (!this.app.workspace.layoutReady) {
- this.app.workspace.onLayoutReady(async () => this.index.initialize());
- }
- else {
- this.index.initialize();
- }
-
- this.app.metadataCache.trigger("dataview:api-ready", this.api);
- console.log(`Dataview: version ${this.manifest.version} (requires obsidian ${this.manifest.minAppVersion})`);
-
- this.registerEvent(this.app.workspace.on("layout-change", () => {
- this.app.workspace.iterateAllLeaves(leaf => {
- if (leaf.view instanceof obsidian.MarkdownView && leaf.view.editor.cm) {
- leaf.view.editor.cm.dispatch({
- effects: workspaceLayoutChangeEffect.of(null),
- });
- }
- });
- }));
- this.registerDataviewjsCodeHighlighting();
- this.register(() => this.unregisterDataviewjsCodeHighlighting());
- }
- registerDataviewjsCodeHighlighting() {
- window.CodeMirror.defineMode(this.settings.dataviewJsKeyword, config => window.CodeMirror.getMode(config, "javascript"));
- }
- unregisterDataviewjsCodeHighlighting() {
- window.CodeMirror.defineMode(this.settings.dataviewJsKeyword, config => window.CodeMirror.getMode(config, "null"));
- }
- debouncedRefresh = () => null;
- updateRefreshSettings() {
- this.debouncedRefresh = obsidian.debounce(() => this.app.workspace.trigger("dataview:refresh-views"), this.settings.refreshInterval, true);
- }
- onunload() {
- console.log(`Dataview: version ${this.manifest.version} unloaded.`);
- }
-
- registerPriorityMarkdownPostProcessor(priority, processor) {
- let registered = this.registerMarkdownPostProcessor(processor);
- registered.sortOrder = priority;
- }
-
- registerPriorityCodeblockPostProcessor(language, priority, processor) {
- let registered = this.registerMarkdownCodeBlockProcessor(language, processor);
- registered.sortOrder = priority;
- }
- updateEditorExtensions() {
-
- this.cmExtension.length = 0;
-
- this.cmExtension.push(inlinePlugin(this.app, this.index, this.settings, this.api));
-
- if (this.settings.prettyRenderInlineFieldsInLivePreview) {
- this.cmExtension.push(inlineFieldsField, replaceInlineFieldsInLivePreview(this.app, this.settings));
- }
- this.app.workspace.updateOptions();
- }
-
- async dataview(source, el, component, sourcePath) {
- el.style.overflowX = "auto";
- this.api.execute(source, el, component, sourcePath);
- }
-
- async dataviewjs(source, el, component, sourcePath) {
- el.style.overflowX = "auto";
- this.api.executeJs(source, el, component, sourcePath);
- }
-
- async dataviewInline(el, component, sourcePath) {
- if (isDataviewDisabled(sourcePath))
- return;
-
- let codeblocks = el.querySelectorAll("code");
- for (let index = 0; index < codeblocks.length; index++) {
- let codeblock = codeblocks.item(index);
-
- if (codeblock.parentElement &&
- codeblock.parentElement.nodeName.toLowerCase() == "pre" &&
- !this.settings.inlineQueriesInCodeblocks)
- continue;
- let text = codeblock.innerText.trim();
- if (this.settings.inlineJsQueryPrefix.length > 0 && text.startsWith(this.settings.inlineJsQueryPrefix)) {
- let code = text.substring(this.settings.inlineJsQueryPrefix.length).trim();
- if (code.length == 0)
- continue;
- component.addChild(new DataviewInlineJSRenderer(this.api, code, el, codeblock, sourcePath));
- }
- else if (this.settings.inlineQueryPrefix.length > 0 && text.startsWith(this.settings.inlineQueryPrefix)) {
- let potentialField = text.substring(this.settings.inlineQueryPrefix.length).trim();
- if (potentialField.length == 0)
- continue;
- let field = tryOrPropogate(() => parseField(potentialField));
- if (!field.successful) {
- let errorBlock = el.createEl("div");
- renderErrorPre(errorBlock, `Dataview (inline field '${potentialField}'): ${field.error}`);
- }
- else {
- let fieldValue = field.value;
- component.addChild(new DataviewInlineRenderer(fieldValue, text, el, codeblock, this.index, sourcePath, this.settings, this.app));
- }
- }
- }
- }
-
- async updateSettings(settings) {
- Object.assign(this.settings, settings);
- this.updateRefreshSettings();
- await this.saveData(this.settings);
- }
-
- withApi(callback) {
- callback(this.api);
- }
-
- localApi(path, component, el) {
- return new DataviewInlineApi(this.api, component, el, path);
- }
- }
- class GeneralSettingsTab extends obsidian.PluginSettingTab {
- plugin;
- constructor(app, plugin) {
- super(app, plugin);
- this.plugin = plugin;
- }
- display() {
- this.containerEl.empty();
- new obsidian.Setting(this.containerEl)
- .setName("Enable inline queries")
- .setDesc("Enable or disable executing regular inline Dataview queries.")
- .addToggle(toggle => toggle
- .setValue(this.plugin.settings.enableInlineDataview)
- .onChange(async (value) => await this.plugin.updateSettings({ enableInlineDataview: value })));
- new obsidian.Setting(this.containerEl)
- .setName("Enable JavaScript queries")
- .setDesc("Enable or disable executing DataviewJS queries.")
- .addToggle(toggle => toggle
- .setValue(this.plugin.settings.enableDataviewJs)
- .onChange(async (value) => await this.plugin.updateSettings({ enableDataviewJs: value })));
- new obsidian.Setting(this.containerEl)
- .setName("Enable inline JavaScript queries")
- .setDesc("Enable or disable executing inline DataviewJS queries. Requires that DataviewJS queries are enabled.")
- .addToggle(toggle => toggle
- .setValue(this.plugin.settings.enableInlineDataviewJs)
- .onChange(async (value) => await this.plugin.updateSettings({ enableInlineDataviewJs: value })));
- new obsidian.Setting(this.containerEl)
- .setName("Enable inline field highlighting in reading view")
- .setDesc("Enables or disables visual highlighting / pretty rendering for inline fields in reading view.")
- .addToggle(toggle => toggle
- .setValue(this.plugin.settings.prettyRenderInlineFields)
- .onChange(async (value) => await this.plugin.updateSettings({ prettyRenderInlineFields: value })));
- new obsidian.Setting(this.containerEl)
- .setName("Enable inline field highlighting in Live Preview")
- .setDesc("Enables or disables visual highlighting / pretty rendering for inline fields in Live Preview.")
- .addToggle(toggle => toggle.setValue(this.plugin.settings.prettyRenderInlineFieldsInLivePreview).onChange(async (value) => {
- await this.plugin.updateSettings({ prettyRenderInlineFieldsInLivePreview: value });
- this.plugin.updateEditorExtensions();
- }));
- new obsidian.Setting(this.containerEl).setName("Codeblocks").setHeading();
- new obsidian.Setting(this.containerEl)
- .setName("DataviewJS keyword")
- .setDesc("Keyword for DataviewJS blocks. Defaults to 'dataviewjs'. Reload required for changes to take effect.")
- .addText(text => text
- .setPlaceholder("dataviewjs")
- .setValue(this.plugin.settings.dataviewJsKeyword)
- .onChange(async (value) => {
- if (value.length == 0)
- return;
- this.plugin.unregisterDataviewjsCodeHighlighting();
- await this.plugin.updateSettings({ dataviewJsKeyword: value });
- this.plugin.registerDataviewjsCodeHighlighting();
- }));
- new obsidian.Setting(this.containerEl)
- .setName("Inline query prefix")
- .setDesc("The prefix to inline queries (to mark them as Dataview queries). Defaults to '='.")
- .addText(text => text
- .setPlaceholder("=")
- .setValue(this.plugin.settings.inlineQueryPrefix)
- .onChange(async (value) => {
- if (value.length == 0)
- return;
- await this.plugin.updateSettings({ inlineQueryPrefix: value });
- }));
- new obsidian.Setting(this.containerEl)
- .setName("JavaScript inline query prefix")
- .setDesc("The prefix to JavaScript inline queries (to mark them as DataviewJS queries). Defaults to '$='.")
- .addText(text => text
- .setPlaceholder("$=")
- .setValue(this.plugin.settings.inlineJsQueryPrefix)
- .onChange(async (value) => {
- if (value.length == 0)
- return;
- await this.plugin.updateSettings({ inlineJsQueryPrefix: value });
- }));
- new obsidian.Setting(this.containerEl)
- .setName("Code block inline queries")
- .setDesc("If enabled, inline queries will also be evaluated inside full code blocks.")
- .addToggle(toggle => toggle
- .setValue(this.plugin.settings.inlineQueriesInCodeblocks)
- .onChange(async (value) => await this.plugin.updateSettings({ inlineQueriesInCodeblocks: value })));
- new obsidian.Setting(this.containerEl).setName("View").setHeading();
- new obsidian.Setting(this.containerEl)
- .setName("Display result count")
- .setDesc("If toggled off, the small number in the result header of TASK and TABLE queries will be hidden.")
- .addToggle(toggle => toggle.setValue(this.plugin.settings.showResultCount).onChange(async (value) => {
- await this.plugin.updateSettings({ showResultCount: value });
- this.plugin.index.touch();
- }));
- new obsidian.Setting(this.containerEl)
- .setName("Warn on empty result")
- .setDesc("If set, queries which return 0 results will render a warning message.")
- .addToggle(toggle => toggle.setValue(this.plugin.settings.warnOnEmptyResult).onChange(async (value) => {
- await this.plugin.updateSettings({ warnOnEmptyResult: value });
- this.plugin.index.touch();
- }));
- new obsidian.Setting(this.containerEl)
- .setName("Render null as")
- .setDesc("What null/non-existent should show up as in tables, by default. This supports Markdown notation.")
- .addText(text => text
- .setPlaceholder("-")
- .setValue(this.plugin.settings.renderNullAs)
- .onChange(async (value) => {
- await this.plugin.updateSettings({ renderNullAs: value });
- this.plugin.index.touch();
- }));
- new obsidian.Setting(this.containerEl)
- .setName("Automatic view refreshing")
- .setDesc("If enabled, views will automatically refresh when files in your vault change; this can negatively affect" +
- " some functionality like embeds in views, so turn it off if such functionality is not working.")
- .addToggle(toggle => toggle.setValue(this.plugin.settings.refreshEnabled).onChange(async (value) => {
- await this.plugin.updateSettings({ refreshEnabled: value });
- this.plugin.index.touch();
- }));
- new obsidian.Setting(this.containerEl)
- .setName("Refresh interval")
- .setDesc("How long to wait (in milliseconds) for files to stop changing before updating views.")
- .addText(text => text
- .setPlaceholder("500")
- .setValue("" + this.plugin.settings.refreshInterval)
- .onChange(async (value) => {
- let parsed = parseInt(value);
- if (isNaN(parsed))
- return;
- parsed = parsed < 100 ? 100 : parsed;
- await this.plugin.updateSettings({ refreshInterval: parsed });
- }));
- let dformat = new obsidian.Setting(this.containerEl)
- .setName("Date format")
- .setDesc("The default date format (see Luxon date format options)." +
- " Currently: " +
- DateTime.now().toFormat(this.plugin.settings.defaultDateFormat, { locale: currentLocale() }))
- .addText(text => text
- .setPlaceholder(DEFAULT_QUERY_SETTINGS.defaultDateFormat)
- .setValue(this.plugin.settings.defaultDateFormat)
- .onChange(async (value) => {
- dformat.setDesc("The default date format (see Luxon date format options)." +
- " Currently: " +
- DateTime.now().toFormat(value, { locale: currentLocale() }));
- await this.plugin.updateSettings({ defaultDateFormat: value });
- this.plugin.index.touch();
- }));
- let dtformat = new obsidian.Setting(this.containerEl)
- .setName("Date + time format")
- .setDesc("The default date and time format (see Luxon date format options)." +
- " Currently: " +
- DateTime.now().toFormat(this.plugin.settings.defaultDateTimeFormat, { locale: currentLocale() }))
- .addText(text => text
- .setPlaceholder(DEFAULT_QUERY_SETTINGS.defaultDateTimeFormat)
- .setValue(this.plugin.settings.defaultDateTimeFormat)
- .onChange(async (value) => {
- dtformat.setDesc("The default date and time format (see Luxon date format options)." +
- " Currently: " +
- DateTime.now().toFormat(value, { locale: currentLocale() }));
- await this.plugin.updateSettings({ defaultDateTimeFormat: value });
- this.plugin.index.touch();
- }));
- new obsidian.Setting(this.containerEl).setName("Tables").setHeading();
- new obsidian.Setting(this.containerEl)
- .setName("Primary column name")
- .setDesc("The name of the default ID column in tables; this is the auto-generated first column that links to the source file.")
- .addText(text => text
- .setPlaceholder("File")
- .setValue(this.plugin.settings.tableIdColumnName)
- .onChange(async (value) => {
- await this.plugin.updateSettings({ tableIdColumnName: value });
- this.plugin.index.touch();
- }));
- new obsidian.Setting(this.containerEl)
- .setName("Grouped column name")
- .setDesc("The name of the default ID column in tables, when the table is on grouped data; this is the auto-generated first column" +
- "that links to the source file/group.")
- .addText(text => text
- .setPlaceholder("Group")
- .setValue(this.plugin.settings.tableGroupColumnName)
- .onChange(async (value) => {
- await this.plugin.updateSettings({ tableGroupColumnName: value });
- this.plugin.index.touch();
- }));
- new obsidian.Setting(this.containerEl).setName("Tasks").setHeading();
- let taskCompletionSubsettingsEnabled = this.plugin.settings.taskCompletionTracking;
- let taskCompletionInlineSubsettingsEnabled = taskCompletionSubsettingsEnabled && !this.plugin.settings.taskCompletionUseEmojiShorthand;
- new obsidian.Setting(this.containerEl)
- .setName("Automatic task completion tracking")
- .setDesc(createFragment(el => {
- el.appendText("If enabled, Dataview will automatically append tasks with their completion date when they are checked in Dataview views.");
- el.createEl("br");
- el.appendText("Example with default field name and date format: - [x] my task [completion:: 2022-01-01]");
- }))
- .addToggle(toggle => toggle.setValue(this.plugin.settings.taskCompletionTracking).onChange(async (value) => {
- await this.plugin.updateSettings({ taskCompletionTracking: value });
- taskCompletionSubsettingsEnabled = value;
- this.display();
- }));
- let taskEmojiShorthand = new obsidian.Setting(this.containerEl)
- .setName("Use emoji shorthand for completion")
- .setDisabled(!taskCompletionSubsettingsEnabled);
- if (taskCompletionSubsettingsEnabled)
- taskEmojiShorthand
- .setDesc(createFragment(el => {
- el.appendText('If enabled, will use emoji shorthand instead of inline field formatting to fill out implicit task field "completion".');
- el.createEl("br");
- el.appendText("Example: - [x] my task ✅ 2022-01-01");
- el.createEl("br");
- el.appendText("Disable this to customize the completion date format or field name, or to use Dataview inline field formatting.");
- el.createEl("br");
- el.appendText('Only available when "automatic task completion tracking" is enabled.');
- }))
- .addToggle(toggle => toggle.setValue(this.plugin.settings.taskCompletionUseEmojiShorthand).onChange(async (value) => {
- await this.plugin.updateSettings({ taskCompletionUseEmojiShorthand: value });
- taskCompletionInlineSubsettingsEnabled = taskCompletionSubsettingsEnabled && !value;
- this.display();
- }));
- else
- taskEmojiShorthand.setDesc('Only available when "automatic task completion tracking" is enabled.');
- let taskFieldName = new obsidian.Setting(this.containerEl)
- .setName("Completion field name")
- .setDisabled(!taskCompletionInlineSubsettingsEnabled);
- if (taskCompletionInlineSubsettingsEnabled)
- taskFieldName
- .setDesc(createFragment(el => {
- el.appendText("Text used as inline field key for task completion date when toggling a task's checkbox in a Dataview view.");
- el.createEl("br");
- el.appendText('Only available when "automatic task completion tracking" is enabled and "use emoji shorthand for completion" is disabled.');
- }))
- .addText(text => text.setValue(this.plugin.settings.taskCompletionText).onChange(async (value) => {
- await this.plugin.updateSettings({ taskCompletionText: value.trim() });
- }));
- else
- taskFieldName.setDesc('Only available when "automatic task completion tracking" is enabled and "use emoji shorthand for completion" is disabled.');
- let taskDtFormat = new obsidian.Setting(this.containerEl)
- .setName("Completion date format")
- .setDisabled(!taskCompletionInlineSubsettingsEnabled);
- if (taskCompletionInlineSubsettingsEnabled) {
- let descTextLines = [
- "Date-time format for task completion date when toggling a task's checkbox in a Dataview view (see Luxon date format options).",
- 'Only available when "automatic task completion tracking" is enabled and "use emoji shorthand for completion" is disabled.',
- "Currently: ",
- ];
- taskDtFormat
- .setDesc(createFragment(el => {
- el.appendText(descTextLines[0]);
- el.createEl("br");
- el.appendText(descTextLines[1]);
- el.createEl("br");
- el.appendText(descTextLines[2] +
- DateTime.now().toFormat(this.plugin.settings.taskCompletionDateFormat, {
- locale: currentLocale(),
- }));
- }))
- .addText(text => text
- .setPlaceholder(DEFAULT_SETTINGS.taskCompletionDateFormat)
- .setValue(this.plugin.settings.taskCompletionDateFormat)
- .onChange(async (value) => {
- taskDtFormat.setDesc(createFragment(el => {
- el.appendText(descTextLines[0]);
- el.createEl("br");
- el.appendText(descTextLines[1]);
- el.createEl("br");
- el.appendText(descTextLines[2] +
- DateTime.now().toFormat(value.trim(), { locale: currentLocale() }));
- }));
- await this.plugin.updateSettings({ taskCompletionDateFormat: value.trim() });
- this.plugin.index.touch();
- }));
- }
- else {
- taskDtFormat.setDesc('Only available when "automatic task completion tracking" is enabled and "use emoji shorthand for completion" is disabled.');
- }
- new obsidian.Setting(this.containerEl)
- .setName("Recursive sub-task completion")
-
- .setDesc("If enabled, completing a task in a Dataview will automatically complete its subtasks too.")
- .addToggle(toggle => toggle
- .setValue(this.plugin.settings.recursiveSubTaskCompletion)
- .onChange(async (value) => await this.plugin.updateSettings({ recursiveSubTaskCompletion: value })));
- }
- }
- module.exports = DataviewPlugin;
|