| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269 | /*! * Chart.js v3.7.1 * https://www.chartjs.org * (c) 2022 Chart.js Contributors * Released under the MIT License */(function (global, factory) {typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :typeof define === 'function' && define.amd ? define(factory) :(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chart = factory());})(this, (function () { 'use strict';function fontString(pixelSize, fontStyle, fontFamily) {  return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;}const requestAnimFrame = (function() {  if (typeof window === 'undefined') {    return function(callback) {      return callback();    };  }  return window.requestAnimationFrame;}());function throttled(fn, thisArg, updateFn) {  const updateArgs = updateFn || ((args) => Array.prototype.slice.call(args));  let ticking = false;  let args = [];  return function(...rest) {    args = updateArgs(rest);    if (!ticking) {      ticking = true;      requestAnimFrame.call(window, () => {        ticking = false;        fn.apply(thisArg, args);      });    }  };}function debounce(fn, delay) {  let timeout;  return function(...args) {    if (delay) {      clearTimeout(timeout);      timeout = setTimeout(fn, delay, args);    } else {      fn.apply(this, args);    }    return delay;  };}const _toLeftRightCenter = (align) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';const _alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2;const _textX = (align, left, right, rtl) => {  const check = rtl ? 'left' : 'right';  return align === check ? right : align === 'center' ? (left + right) / 2 : left;};class Animator {  constructor() {    this._request = null;    this._charts = new Map();    this._running = false;    this._lastDate = undefined;  }  _notify(chart, anims, date, type) {    const callbacks = anims.listeners[type];    const numSteps = anims.duration;    callbacks.forEach(fn => fn({      chart,      initial: anims.initial,      numSteps,      currentStep: Math.min(date - anims.start, numSteps)    }));  }  _refresh() {    if (this._request) {      return;    }    this._running = true;    this._request = requestAnimFrame.call(window, () => {      this._update();      this._request = null;      if (this._running) {        this._refresh();      }    });  }  _update(date = Date.now()) {    let remaining = 0;    this._charts.forEach((anims, chart) => {      if (!anims.running || !anims.items.length) {        return;      }      const items = anims.items;      let i = items.length - 1;      let draw = false;      let item;      for (; i >= 0; --i) {        item = items[i];        if (item._active) {          if (item._total > anims.duration) {            anims.duration = item._total;          }          item.tick(date);          draw = true;        } else {          items[i] = items[items.length - 1];          items.pop();        }      }      if (draw) {        chart.draw();        this._notify(chart, anims, date, 'progress');      }      if (!items.length) {        anims.running = false;        this._notify(chart, anims, date, 'complete');        anims.initial = false;      }      remaining += items.length;    });    this._lastDate = date;    if (remaining === 0) {      this._running = false;    }  }  _getAnims(chart) {    const charts = this._charts;    let anims = charts.get(chart);    if (!anims) {      anims = {        running: false,        initial: true,        items: [],        listeners: {          complete: [],          progress: []        }      };      charts.set(chart, anims);    }    return anims;  }  listen(chart, event, cb) {    this._getAnims(chart).listeners[event].push(cb);  }  add(chart, items) {    if (!items || !items.length) {      return;    }    this._getAnims(chart).items.push(...items);  }  has(chart) {    return this._getAnims(chart).items.length > 0;  }  start(chart) {    const anims = this._charts.get(chart);    if (!anims) {      return;    }    anims.running = true;    anims.start = Date.now();    anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0);    this._refresh();  }  running(chart) {    if (!this._running) {      return false;    }    const anims = this._charts.get(chart);    if (!anims || !anims.running || !anims.items.length) {      return false;    }    return true;  }  stop(chart) {    const anims = this._charts.get(chart);    if (!anims || !anims.items.length) {      return;    }    const items = anims.items;    let i = items.length - 1;    for (; i >= 0; --i) {      items[i].cancel();    }    anims.items = [];    this._notify(chart, anims, Date.now(), 'complete');  }  remove(chart) {    return this._charts.delete(chart);  }}var animator = new Animator();/*! * @kurkle/color v0.1.9 * https://github.com/kurkle/color#readme * (c) 2020 Jukka Kurkela * Released under the MIT License */const map$1 = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15};const hex = '0123456789ABCDEF';const h1 = (b) => hex[b & 0xF];const h2 = (b) => hex[(b & 0xF0) >> 4] + hex[b & 0xF];const eq = (b) => (((b & 0xF0) >> 4) === (b & 0xF));function isShort(v) {	return eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a);}function hexParse(str) {	var len = str.length;	var ret;	if (str[0] === '#') {		if (len === 4 || len === 5) {			ret = {				r: 255 & map$1[str[1]] * 17,				g: 255 & map$1[str[2]] * 17,				b: 255 & map$1[str[3]] * 17,				a: len === 5 ? map$1[str[4]] * 17 : 255			};		} else if (len === 7 || len === 9) {			ret = {				r: map$1[str[1]] << 4 | map$1[str[2]],				g: map$1[str[3]] << 4 | map$1[str[4]],				b: map$1[str[5]] << 4 | map$1[str[6]],				a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255			};		}	}	return ret;}function hexString(v) {	var f = isShort(v) ? h1 : h2;	return v		? '#' + f(v.r) + f(v.g) + f(v.b) + (v.a < 255 ? f(v.a) : '')		: v;}function round(v) {	return v + 0.5 | 0;}const lim = (v, l, h) => Math.max(Math.min(v, h), l);function p2b(v) {	return lim(round(v * 2.55), 0, 255);}function n2b(v) {	return lim(round(v * 255), 0, 255);}function b2n(v) {	return lim(round(v / 2.55) / 100, 0, 1);}function n2p(v) {	return lim(round(v * 100), 0, 100);}const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;function rgbParse(str) {	const m = RGB_RE.exec(str);	let a = 255;	let r, g, b;	if (!m) {		return;	}	if (m[7] !== r) {		const v = +m[7];		a = 255 & (m[8] ? p2b(v) : v * 255);	}	r = +m[1];	g = +m[3];	b = +m[5];	r = 255 & (m[2] ? p2b(r) : r);	g = 255 & (m[4] ? p2b(g) : g);	b = 255 & (m[6] ? p2b(b) : b);	return {		r: r,		g: g,		b: b,		a: a	};}function rgbString(v) {	return v && (		v.a < 255			? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})`			: `rgb(${v.r}, ${v.g}, ${v.b})`	);}const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function hsl2rgbn(h, s, l) {	const a = s * Math.min(l, 1 - l);	const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);	return [f(0), f(8), f(4)];}function hsv2rgbn(h, s, v) {	const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);	return [f(5), f(3), f(1)];}function hwb2rgbn(h, w, b) {	const rgb = hsl2rgbn(h, 1, 0.5);	let i;	if (w + b > 1) {		i = 1 / (w + b);		w *= i;		b *= i;	}	for (i = 0; i < 3; i++) {		rgb[i] *= 1 - w - b;		rgb[i] += w;	}	return rgb;}function rgb2hsl(v) {	const range = 255;	const r = v.r / range;	const g = v.g / range;	const b = v.b / range;	const max = Math.max(r, g, b);	const min = Math.min(r, g, b);	const l = (max + min) / 2;	let h, s, d;	if (max !== min) {		d = max - min;		s = l > 0.5 ? d / (2 - max - min) : d / (max + min);		h = max === r			? ((g - b) / d) + (g < b ? 6 : 0)			: max === g				? (b - r) / d + 2				: (r - g) / d + 4;		h = h * 60 + 0.5;	}	return [h | 0, s || 0, l];}function calln(f, a, b, c) {	return (		Array.isArray(a)			? f(a[0], a[1], a[2])			: f(a, b, c)	).map(n2b);}function hsl2rgb(h, s, l) {	return calln(hsl2rgbn, h, s, l);}function hwb2rgb(h, w, b) {	return calln(hwb2rgbn, h, w, b);}function hsv2rgb(h, s, v) {	return calln(hsv2rgbn, h, s, v);}function hue(h) {	return (h % 360 + 360) % 360;}function hueParse(str) {	const m = HUE_RE.exec(str);	let a = 255;	let v;	if (!m) {		return;	}	if (m[5] !== v) {		a = m[6] ? p2b(+m[5]) : n2b(+m[5]);	}	const h = hue(+m[2]);	const p1 = +m[3] / 100;	const p2 = +m[4] / 100;	if (m[1] === 'hwb') {		v = hwb2rgb(h, p1, p2);	} else if (m[1] === 'hsv') {		v = hsv2rgb(h, p1, p2);	} else {		v = hsl2rgb(h, p1, p2);	}	return {		r: v[0],		g: v[1],		b: v[2],		a: a	};}function rotate(v, deg) {	var h = rgb2hsl(v);	h[0] = hue(h[0] + deg);	h = hsl2rgb(h);	v.r = h[0];	v.g = h[1];	v.b = h[2];}function hslString(v) {	if (!v) {		return;	}	const a = rgb2hsl(v);	const h = a[0];	const s = n2p(a[1]);	const l = n2p(a[2]);	return v.a < 255		? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})`		: `hsl(${h}, ${s}%, ${l}%)`;}const map$1$1 = {	x: 'dark',	Z: 'light',	Y: 're',	X: 'blu',	W: 'gr',	V: 'medium',	U: 'slate',	A: 'ee',	T: 'ol',	S: 'or',	B: 'ra',	C: 'lateg',	D: 'ights',	R: 'in',	Q: 'turquois',	E: 'hi',	P: 'ro',	O: 'al',	N: 'le',	M: 'de',	L: 'yello',	F: 'en',	K: 'ch',	G: 'arks',	H: 'ea',	I: 'ightg',	J: 'wh'};const names = {	OiceXe: 'f0f8ff',	antiquewEte: 'faebd7',	aqua: 'ffff',	aquamarRe: '7fffd4',	azuY: 'f0ffff',	beige: 'f5f5dc',	bisque: 'ffe4c4',	black: '0',	blanKedOmond: 'ffebcd',	Xe: 'ff',	XeviTet: '8a2be2',	bPwn: 'a52a2a',	burlywood: 'deb887',	caMtXe: '5f9ea0',	KartYuse: '7fff00',	KocTate: 'd2691e',	cSO: 'ff7f50',	cSnflowerXe: '6495ed',	cSnsilk: 'fff8dc',	crimson: 'dc143c',	cyan: 'ffff',	xXe: '8b',	xcyan: '8b8b',	xgTMnPd: 'b8860b',	xWay: 'a9a9a9',	xgYF: '6400',	xgYy: 'a9a9a9',	xkhaki: 'bdb76b',	xmagFta: '8b008b',	xTivegYF: '556b2f',	xSange: 'ff8c00',	xScEd: '9932cc',	xYd: '8b0000',	xsOmon: 'e9967a',	xsHgYF: '8fbc8f',	xUXe: '483d8b',	xUWay: '2f4f4f',	xUgYy: '2f4f4f',	xQe: 'ced1',	xviTet: '9400d3',	dAppRk: 'ff1493',	dApskyXe: 'bfff',	dimWay: '696969',	dimgYy: '696969',	dodgerXe: '1e90ff',	fiYbrick: 'b22222',	flSOwEte: 'fffaf0',	foYstWAn: '228b22',	fuKsia: 'ff00ff',	gaRsbSo: 'dcdcdc',	ghostwEte: 'f8f8ff',	gTd: 'ffd700',	gTMnPd: 'daa520',	Way: '808080',	gYF: '8000',	gYFLw: 'adff2f',	gYy: '808080',	honeyMw: 'f0fff0',	hotpRk: 'ff69b4',	RdianYd: 'cd5c5c',	Rdigo: '4b0082',	ivSy: 'fffff0',	khaki: 'f0e68c',	lavFMr: 'e6e6fa',	lavFMrXsh: 'fff0f5',	lawngYF: '7cfc00',	NmoncEffon: 'fffacd',	ZXe: 'add8e6',	ZcSO: 'f08080',	Zcyan: 'e0ffff',	ZgTMnPdLw: 'fafad2',	ZWay: 'd3d3d3',	ZgYF: '90ee90',	ZgYy: 'd3d3d3',	ZpRk: 'ffb6c1',	ZsOmon: 'ffa07a',	ZsHgYF: '20b2aa',	ZskyXe: '87cefa',	ZUWay: '778899',	ZUgYy: '778899',	ZstAlXe: 'b0c4de',	ZLw: 'ffffe0',	lime: 'ff00',	limegYF: '32cd32',	lRF: 'faf0e6',	magFta: 'ff00ff',	maPon: '800000',	VaquamarRe: '66cdaa',	VXe: 'cd',	VScEd: 'ba55d3',	VpurpN: '9370db',	VsHgYF: '3cb371',	VUXe: '7b68ee',	VsprRggYF: 'fa9a',	VQe: '48d1cc',	VviTetYd: 'c71585',	midnightXe: '191970',	mRtcYam: 'f5fffa',	mistyPse: 'ffe4e1',	moccasR: 'ffe4b5',	navajowEte: 'ffdead',	navy: '80',	Tdlace: 'fdf5e6',	Tive: '808000',	TivedBb: '6b8e23',	Sange: 'ffa500',	SangeYd: 'ff4500',	ScEd: 'da70d6',	pOegTMnPd: 'eee8aa',	pOegYF: '98fb98',	pOeQe: 'afeeee',	pOeviTetYd: 'db7093',	papayawEp: 'ffefd5',	pHKpuff: 'ffdab9',	peru: 'cd853f',	pRk: 'ffc0cb',	plum: 'dda0dd',	powMrXe: 'b0e0e6',	purpN: '800080',	YbeccapurpN: '663399',	Yd: 'ff0000',	Psybrown: 'bc8f8f',	PyOXe: '4169e1',	saddNbPwn: '8b4513',	sOmon: 'fa8072',	sandybPwn: 'f4a460',	sHgYF: '2e8b57',	sHshell: 'fff5ee',	siFna: 'a0522d',	silver: 'c0c0c0',	skyXe: '87ceeb',	UXe: '6a5acd',	UWay: '708090',	UgYy: '708090',	snow: 'fffafa',	sprRggYF: 'ff7f',	stAlXe: '4682b4',	tan: 'd2b48c',	teO: '8080',	tEstN: 'd8bfd8',	tomato: 'ff6347',	Qe: '40e0d0',	viTet: 'ee82ee',	JHt: 'f5deb3',	wEte: 'ffffff',	wEtesmoke: 'f5f5f5',	Lw: 'ffff00',	LwgYF: '9acd32'};function unpack() {	const unpacked = {};	const keys = Object.keys(names);	const tkeys = Object.keys(map$1$1);	let i, j, k, ok, nk;	for (i = 0; i < keys.length; i++) {		ok = nk = keys[i];		for (j = 0; j < tkeys.length; j++) {			k = tkeys[j];			nk = nk.replace(k, map$1$1[k]);		}		k = parseInt(names[ok], 16);		unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF];	}	return unpacked;}let names$1;function nameParse(str) {	if (!names$1) {		names$1 = unpack();		names$1.transparent = [0, 0, 0, 0];	}	const a = names$1[str.toLowerCase()];	return a && {		r: a[0],		g: a[1],		b: a[2],		a: a.length === 4 ? a[3] : 255	};}function modHSL(v, i, ratio) {	if (v) {		let tmp = rgb2hsl(v);		tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1));		tmp = hsl2rgb(tmp);		v.r = tmp[0];		v.g = tmp[1];		v.b = tmp[2];	}}function clone$1(v, proto) {	return v ? Object.assign(proto || {}, v) : v;}function fromObject(input) {	var v = {r: 0, g: 0, b: 0, a: 255};	if (Array.isArray(input)) {		if (input.length >= 3) {			v = {r: input[0], g: input[1], b: input[2], a: 255};			if (input.length > 3) {				v.a = n2b(input[3]);			}		}	} else {		v = clone$1(input, {r: 0, g: 0, b: 0, a: 1});		v.a = n2b(v.a);	}	return v;}function functionParse(str) {	if (str.charAt(0) === 'r') {		return rgbParse(str);	}	return hueParse(str);}class Color {	constructor(input) {		if (input instanceof Color) {			return input;		}		const type = typeof input;		let v;		if (type === 'object') {			v = fromObject(input);		} else if (type === 'string') {			v = hexParse(input) || nameParse(input) || functionParse(input);		}		this._rgb = v;		this._valid = !!v;	}	get valid() {		return this._valid;	}	get rgb() {		var v = clone$1(this._rgb);		if (v) {			v.a = b2n(v.a);		}		return v;	}	set rgb(obj) {		this._rgb = fromObject(obj);	}	rgbString() {		return this._valid ? rgbString(this._rgb) : this._rgb;	}	hexString() {		return this._valid ? hexString(this._rgb) : this._rgb;	}	hslString() {		return this._valid ? hslString(this._rgb) : this._rgb;	}	mix(color, weight) {		const me = this;		if (color) {			const c1 = me.rgb;			const c2 = color.rgb;			let w2;			const p = weight === w2 ? 0.5 : weight;			const w = 2 * p - 1;			const a = c1.a - c2.a;			const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0;			w2 = 1 - w1;			c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5;			c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5;			c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5;			c1.a = p * c1.a + (1 - p) * c2.a;			me.rgb = c1;		}		return me;	}	clone() {		return new Color(this.rgb);	}	alpha(a) {		this._rgb.a = n2b(a);		return this;	}	clearer(ratio) {		const rgb = this._rgb;		rgb.a *= 1 - ratio;		return this;	}	greyscale() {		const rgb = this._rgb;		const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11);		rgb.r = rgb.g = rgb.b = val;		return this;	}	opaquer(ratio) {		const rgb = this._rgb;		rgb.a *= 1 + ratio;		return this;	}	negate() {		const v = this._rgb;		v.r = 255 - v.r;		v.g = 255 - v.g;		v.b = 255 - v.b;		return this;	}	lighten(ratio) {		modHSL(this._rgb, 2, ratio);		return this;	}	darken(ratio) {		modHSL(this._rgb, 2, -ratio);		return this;	}	saturate(ratio) {		modHSL(this._rgb, 1, ratio);		return this;	}	desaturate(ratio) {		modHSL(this._rgb, 1, -ratio);		return this;	}	rotate(deg) {		rotate(this._rgb, deg);		return this;	}}function index_esm(input) {	return new Color(input);}const isPatternOrGradient = (value) => value instanceof CanvasGradient || value instanceof CanvasPattern;function color(value) {  return isPatternOrGradient(value) ? value : index_esm(value);}function getHoverColor(value) {  return isPatternOrGradient(value)    ? value    : index_esm(value).saturate(0.5).darken(0.1).hexString();}function noop() {}const uid = (function() {  let id = 0;  return function() {    return id++;  };}());function isNullOrUndef(value) {  return value === null || typeof value === 'undefined';}function isArray(value) {  if (Array.isArray && Array.isArray(value)) {    return true;  }  const type = Object.prototype.toString.call(value);  if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {    return true;  }  return false;}function isObject(value) {  return value !== null && Object.prototype.toString.call(value) === '[object Object]';}const isNumberFinite = (value) => (typeof value === 'number' || value instanceof Number) && isFinite(+value);function finiteOrDefault(value, defaultValue) {  return isNumberFinite(value) ? value : defaultValue;}function valueOrDefault(value, defaultValue) {  return typeof value === 'undefined' ? defaultValue : value;}const toPercentage = (value, dimension) =>  typeof value === 'string' && value.endsWith('%') ?    parseFloat(value) / 100    : value / dimension;const toDimension = (value, dimension) =>  typeof value === 'string' && value.endsWith('%') ?    parseFloat(value) / 100 * dimension    : +value;function callback(fn, args, thisArg) {  if (fn && typeof fn.call === 'function') {    return fn.apply(thisArg, args);  }}function each(loopable, fn, thisArg, reverse) {  let i, len, keys;  if (isArray(loopable)) {    len = loopable.length;    if (reverse) {      for (i = len - 1; i >= 0; i--) {        fn.call(thisArg, loopable[i], i);      }    } else {      for (i = 0; i < len; i++) {        fn.call(thisArg, loopable[i], i);      }    }  } else if (isObject(loopable)) {    keys = Object.keys(loopable);    len = keys.length;    for (i = 0; i < len; i++) {      fn.call(thisArg, loopable[keys[i]], keys[i]);    }  }}function _elementsEqual(a0, a1) {  let i, ilen, v0, v1;  if (!a0 || !a1 || a0.length !== a1.length) {    return false;  }  for (i = 0, ilen = a0.length; i < ilen; ++i) {    v0 = a0[i];    v1 = a1[i];    if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {      return false;    }  }  return true;}function clone(source) {  if (isArray(source)) {    return source.map(clone);  }  if (isObject(source)) {    const target = Object.create(null);    const keys = Object.keys(source);    const klen = keys.length;    let k = 0;    for (; k < klen; ++k) {      target[keys[k]] = clone(source[keys[k]]);    }    return target;  }  return source;}function isValidKey(key) {  return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1;}function _merger(key, target, source, options) {  if (!isValidKey(key)) {    return;  }  const tval = target[key];  const sval = source[key];  if (isObject(tval) && isObject(sval)) {    merge(tval, sval, options);  } else {    target[key] = clone(sval);  }}function merge(target, source, options) {  const sources = isArray(source) ? source : [source];  const ilen = sources.length;  if (!isObject(target)) {    return target;  }  options = options || {};  const merger = options.merger || _merger;  for (let i = 0; i < ilen; ++i) {    source = sources[i];    if (!isObject(source)) {      continue;    }    const keys = Object.keys(source);    for (let k = 0, klen = keys.length; k < klen; ++k) {      merger(keys[k], target, source, options);    }  }  return target;}function mergeIf(target, source) {  return merge(target, source, {merger: _mergerIf});}function _mergerIf(key, target, source) {  if (!isValidKey(key)) {    return;  }  const tval = target[key];  const sval = source[key];  if (isObject(tval) && isObject(sval)) {    mergeIf(tval, sval);  } else if (!Object.prototype.hasOwnProperty.call(target, key)) {    target[key] = clone(sval);  }}function _deprecated(scope, value, previous, current) {  if (value !== undefined) {    console.warn(scope + ': "' + previous +			'" is deprecated. Please use "' + current + '" instead');  }}const emptyString = '';const dot = '.';function indexOfDotOrLength(key, start) {  const idx = key.indexOf(dot, start);  return idx === -1 ? key.length : idx;}function resolveObjectKey(obj, key) {  if (key === emptyString) {    return obj;  }  let pos = 0;  let idx = indexOfDotOrLength(key, pos);  while (obj && idx > pos) {    obj = obj[key.substr(pos, idx - pos)];    pos = idx + 1;    idx = indexOfDotOrLength(key, pos);  }  return obj;}function _capitalize(str) {  return str.charAt(0).toUpperCase() + str.slice(1);}const defined = (value) => typeof value !== 'undefined';const isFunction = (value) => typeof value === 'function';const setsEqual = (a, b) => {  if (a.size !== b.size) {    return false;  }  for (const item of a) {    if (!b.has(item)) {      return false;    }  }  return true;};function _isClickEvent(e) {  return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';}const overrides = Object.create(null);const descriptors = Object.create(null);function getScope$1(node, key) {  if (!key) {    return node;  }  const keys = key.split('.');  for (let i = 0, n = keys.length; i < n; ++i) {    const k = keys[i];    node = node[k] || (node[k] = Object.create(null));  }  return node;}function set(root, scope, values) {  if (typeof scope === 'string') {    return merge(getScope$1(root, scope), values);  }  return merge(getScope$1(root, ''), scope);}class Defaults {  constructor(_descriptors) {    this.animation = undefined;    this.backgroundColor = 'rgba(0,0,0,0.1)';    this.borderColor = 'rgba(0,0,0,0.1)';    this.color = '#666';    this.datasets = {};    this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio();    this.elements = {};    this.events = [      'mousemove',      'mouseout',      'click',      'touchstart',      'touchmove'    ];    this.font = {      family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",      size: 12,      style: 'normal',      lineHeight: 1.2,      weight: null    };    this.hover = {};    this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor);    this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor);    this.hoverColor = (ctx, options) => getHoverColor(options.color);    this.indexAxis = 'x';    this.interaction = {      mode: 'nearest',      intersect: true    };    this.maintainAspectRatio = true;    this.onHover = null;    this.onClick = null;    this.parsing = true;    this.plugins = {};    this.responsive = true;    this.scale = undefined;    this.scales = {};    this.showLine = true;    this.drawActiveElementsOnTop = true;    this.describe(_descriptors);  }  set(scope, values) {    return set(this, scope, values);  }  get(scope) {    return getScope$1(this, scope);  }  describe(scope, values) {    return set(descriptors, scope, values);  }  override(scope, values) {    return set(overrides, scope, values);  }  route(scope, name, targetScope, targetName) {    const scopeObject = getScope$1(this, scope);    const targetScopeObject = getScope$1(this, targetScope);    const privateName = '_' + name;    Object.defineProperties(scopeObject, {      [privateName]: {        value: scopeObject[name],        writable: true      },      [name]: {        enumerable: true,        get() {          const local = this[privateName];          const target = targetScopeObject[targetName];          if (isObject(local)) {            return Object.assign({}, target, local);          }          return valueOrDefault(local, target);        },        set(value) {          this[privateName] = value;        }      }    });  }}var defaults = new Defaults({  _scriptable: (name) => !name.startsWith('on'),  _indexable: (name) => name !== 'events',  hover: {    _fallback: 'interaction'  },  interaction: {    _scriptable: false,    _indexable: false,  }});const PI = Math.PI;const TAU = 2 * PI;const PITAU = TAU + PI;const INFINITY = Number.POSITIVE_INFINITY;const RAD_PER_DEG = PI / 180;const HALF_PI = PI / 2;const QUARTER_PI = PI / 4;const TWO_THIRDS_PI = PI * 2 / 3;const log10 = Math.log10;const sign = Math.sign;function niceNum(range) {  const roundedRange = Math.round(range);  range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range;  const niceRange = Math.pow(10, Math.floor(log10(range)));  const fraction = range / niceRange;  const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;  return niceFraction * niceRange;}function _factorize(value) {  const result = [];  const sqrt = Math.sqrt(value);  let i;  for (i = 1; i < sqrt; i++) {    if (value % i === 0) {      result.push(i);      result.push(value / i);    }  }  if (sqrt === (sqrt | 0)) {    result.push(sqrt);  }  result.sort((a, b) => a - b).pop();  return result;}function isNumber(n) {  return !isNaN(parseFloat(n)) && isFinite(n);}function almostEquals(x, y, epsilon) {  return Math.abs(x - y) < epsilon;}function almostWhole(x, epsilon) {  const rounded = Math.round(x);  return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x);}function _setMinAndMaxByKey(array, target, property) {  let i, ilen, value;  for (i = 0, ilen = array.length; i < ilen; i++) {    value = array[i][property];    if (!isNaN(value)) {      target.min = Math.min(target.min, value);      target.max = Math.max(target.max, value);    }  }}function toRadians(degrees) {  return degrees * (PI / 180);}function toDegrees(radians) {  return radians * (180 / PI);}function _decimalPlaces(x) {  if (!isNumberFinite(x)) {    return;  }  let e = 1;  let p = 0;  while (Math.round(x * e) / e !== x) {    e *= 10;    p++;  }  return p;}function getAngleFromPoint(centrePoint, anglePoint) {  const distanceFromXCenter = anglePoint.x - centrePoint.x;  const distanceFromYCenter = anglePoint.y - centrePoint.y;  const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);  let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);  if (angle < (-0.5 * PI)) {    angle += TAU;  }  return {    angle,    distance: radialDistanceFromCenter  };}function distanceBetweenPoints(pt1, pt2) {  return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));}function _angleDiff(a, b) {  return (a - b + PITAU) % TAU - PI;}function _normalizeAngle(a) {  return (a % TAU + TAU) % TAU;}function _angleBetween(angle, start, end, sameAngleIsFullCircle) {  const a = _normalizeAngle(angle);  const s = _normalizeAngle(start);  const e = _normalizeAngle(end);  const angleToStart = _normalizeAngle(s - a);  const angleToEnd = _normalizeAngle(e - a);  const startToAngle = _normalizeAngle(a - s);  const endToAngle = _normalizeAngle(a - e);  return a === s || a === e || (sameAngleIsFullCircle && s === e)    || (angleToStart > angleToEnd && startToAngle < endToAngle);}function _limitValue(value, min, max) {  return Math.max(min, Math.min(max, value));}function _int16Range(value) {  return _limitValue(value, -32768, 32767);}function _isBetween(value, start, end, epsilon = 1e-6) {  return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;}function toFontString(font) {  if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {    return null;  }  return (font.style ? font.style + ' ' : '')		+ (font.weight ? font.weight + ' ' : '')		+ font.size + 'px '		+ font.family;}function _measureText(ctx, data, gc, longest, string) {  let textWidth = data[string];  if (!textWidth) {    textWidth = data[string] = ctx.measureText(string).width;    gc.push(string);  }  if (textWidth > longest) {    longest = textWidth;  }  return longest;}function _longestText(ctx, font, arrayOfThings, cache) {  cache = cache || {};  let data = cache.data = cache.data || {};  let gc = cache.garbageCollect = cache.garbageCollect || [];  if (cache.font !== font) {    data = cache.data = {};    gc = cache.garbageCollect = [];    cache.font = font;  }  ctx.save();  ctx.font = font;  let longest = 0;  const ilen = arrayOfThings.length;  let i, j, jlen, thing, nestedThing;  for (i = 0; i < ilen; i++) {    thing = arrayOfThings[i];    if (thing !== undefined && thing !== null && isArray(thing) !== true) {      longest = _measureText(ctx, data, gc, longest, thing);    } else if (isArray(thing)) {      for (j = 0, jlen = thing.length; j < jlen; j++) {        nestedThing = thing[j];        if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {          longest = _measureText(ctx, data, gc, longest, nestedThing);        }      }    }  }  ctx.restore();  const gcLen = gc.length / 2;  if (gcLen > arrayOfThings.length) {    for (i = 0; i < gcLen; i++) {      delete data[gc[i]];    }    gc.splice(0, gcLen);  }  return longest;}function _alignPixel(chart, pixel, width) {  const devicePixelRatio = chart.currentDevicePixelRatio;  const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0;  return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;}function clearCanvas(canvas, ctx) {  ctx = ctx || canvas.getContext('2d');  ctx.save();  ctx.resetTransform();  ctx.clearRect(0, 0, canvas.width, canvas.height);  ctx.restore();}function drawPoint(ctx, options, x, y) {  let type, xOffset, yOffset, size, cornerRadius;  const style = options.pointStyle;  const rotation = options.rotation;  const radius = options.radius;  let rad = (rotation || 0) * RAD_PER_DEG;  if (style && typeof style === 'object') {    type = style.toString();    if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {      ctx.save();      ctx.translate(x, y);      ctx.rotate(rad);      ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);      ctx.restore();      return;    }  }  if (isNaN(radius) || radius <= 0) {    return;  }  ctx.beginPath();  switch (style) {  default:    ctx.arc(x, y, radius, 0, TAU);    ctx.closePath();    break;  case 'triangle':    ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);    rad += TWO_THIRDS_PI;    ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);    rad += TWO_THIRDS_PI;    ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);    ctx.closePath();    break;  case 'rectRounded':    cornerRadius = radius * 0.516;    size = radius - cornerRadius;    xOffset = Math.cos(rad + QUARTER_PI) * size;    yOffset = Math.sin(rad + QUARTER_PI) * size;    ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);    ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad);    ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI);    ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);    ctx.closePath();    break;  case 'rect':    if (!rotation) {      size = Math.SQRT1_2 * radius;      ctx.rect(x - size, y - size, 2 * size, 2 * size);      break;    }    rad += QUARTER_PI;  case 'rectRot':    xOffset = Math.cos(rad) * radius;    yOffset = Math.sin(rad) * radius;    ctx.moveTo(x - xOffset, y - yOffset);    ctx.lineTo(x + yOffset, y - xOffset);    ctx.lineTo(x + xOffset, y + yOffset);    ctx.lineTo(x - yOffset, y + xOffset);    ctx.closePath();    break;  case 'crossRot':    rad += QUARTER_PI;  case 'cross':    xOffset = Math.cos(rad) * radius;    yOffset = Math.sin(rad) * radius;    ctx.moveTo(x - xOffset, y - yOffset);    ctx.lineTo(x + xOffset, y + yOffset);    ctx.moveTo(x + yOffset, y - xOffset);    ctx.lineTo(x - yOffset, y + xOffset);    break;  case 'star':    xOffset = Math.cos(rad) * radius;    yOffset = Math.sin(rad) * radius;    ctx.moveTo(x - xOffset, y - yOffset);    ctx.lineTo(x + xOffset, y + yOffset);    ctx.moveTo(x + yOffset, y - xOffset);    ctx.lineTo(x - yOffset, y + xOffset);    rad += QUARTER_PI;    xOffset = Math.cos(rad) * radius;    yOffset = Math.sin(rad) * radius;    ctx.moveTo(x - xOffset, y - yOffset);    ctx.lineTo(x + xOffset, y + yOffset);    ctx.moveTo(x + yOffset, y - xOffset);    ctx.lineTo(x - yOffset, y + xOffset);    break;  case 'line':    xOffset = Math.cos(rad) * radius;    yOffset = Math.sin(rad) * radius;    ctx.moveTo(x - xOffset, y - yOffset);    ctx.lineTo(x + xOffset, y + yOffset);    break;  case 'dash':    ctx.moveTo(x, y);    ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius);    break;  }  ctx.fill();  if (options.borderWidth > 0) {    ctx.stroke();  }}function _isPointInArea(point, area, margin) {  margin = margin || 0.5;  return !area || (point && point.x > area.left - margin && point.x < area.right + margin &&		point.y > area.top - margin && point.y < area.bottom + margin);}function clipArea(ctx, area) {  ctx.save();  ctx.beginPath();  ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);  ctx.clip();}function unclipArea(ctx) {  ctx.restore();}function _steppedLineTo(ctx, previous, target, flip, mode) {  if (!previous) {    return ctx.lineTo(target.x, target.y);  }  if (mode === 'middle') {    const midpoint = (previous.x + target.x) / 2.0;    ctx.lineTo(midpoint, previous.y);    ctx.lineTo(midpoint, target.y);  } else if (mode === 'after' !== !!flip) {    ctx.lineTo(previous.x, target.y);  } else {    ctx.lineTo(target.x, previous.y);  }  ctx.lineTo(target.x, target.y);}function _bezierCurveTo(ctx, previous, target, flip) {  if (!previous) {    return ctx.lineTo(target.x, target.y);  }  ctx.bezierCurveTo(    flip ? previous.cp1x : previous.cp2x,    flip ? previous.cp1y : previous.cp2y,    flip ? target.cp2x : target.cp1x,    flip ? target.cp2y : target.cp1y,    target.x,    target.y);}function renderText(ctx, text, x, y, font, opts = {}) {  const lines = isArray(text) ? text : [text];  const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';  let i, line;  ctx.save();  ctx.font = font.string;  setRenderOpts(ctx, opts);  for (i = 0; i < lines.length; ++i) {    line = lines[i];    if (stroke) {      if (opts.strokeColor) {        ctx.strokeStyle = opts.strokeColor;      }      if (!isNullOrUndef(opts.strokeWidth)) {        ctx.lineWidth = opts.strokeWidth;      }      ctx.strokeText(line, x, y, opts.maxWidth);    }    ctx.fillText(line, x, y, opts.maxWidth);    decorateText(ctx, x, y, line, opts);    y += font.lineHeight;  }  ctx.restore();}function setRenderOpts(ctx, opts) {  if (opts.translation) {    ctx.translate(opts.translation[0], opts.translation[1]);  }  if (!isNullOrUndef(opts.rotation)) {    ctx.rotate(opts.rotation);  }  if (opts.color) {    ctx.fillStyle = opts.color;  }  if (opts.textAlign) {    ctx.textAlign = opts.textAlign;  }  if (opts.textBaseline) {    ctx.textBaseline = opts.textBaseline;  }}function decorateText(ctx, x, y, line, opts) {  if (opts.strikethrough || opts.underline) {    const metrics = ctx.measureText(line);    const left = x - metrics.actualBoundingBoxLeft;    const right = x + metrics.actualBoundingBoxRight;    const top = y - metrics.actualBoundingBoxAscent;    const bottom = y + metrics.actualBoundingBoxDescent;    const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;    ctx.strokeStyle = ctx.fillStyle;    ctx.beginPath();    ctx.lineWidth = opts.decorationWidth || 2;    ctx.moveTo(left, yDecoration);    ctx.lineTo(right, yDecoration);    ctx.stroke();  }}function addRoundedRectPath(ctx, rect) {  const {x, y, w, h, radius} = rect;  ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true);  ctx.lineTo(x, y + h - radius.bottomLeft);  ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);  ctx.lineTo(x + w - radius.bottomRight, y + h);  ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);  ctx.lineTo(x + w, y + radius.topRight);  ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);  ctx.lineTo(x + radius.topLeft, y);}function _lookup(table, value, cmp) {  cmp = cmp || ((index) => table[index] < value);  let hi = table.length - 1;  let lo = 0;  let mid;  while (hi - lo > 1) {    mid = (lo + hi) >> 1;    if (cmp(mid)) {      lo = mid;    } else {      hi = mid;    }  }  return {lo, hi};}const _lookupByKey = (table, key, value) =>  _lookup(table, value, index => table[index][key] < value);const _rlookupByKey = (table, key, value) =>  _lookup(table, value, index => table[index][key] >= value);function _filterBetween(values, min, max) {  let start = 0;  let end = values.length;  while (start < end && values[start] < min) {    start++;  }  while (end > start && values[end - 1] > max) {    end--;  }  return start > 0 || end < values.length    ? values.slice(start, end)    : values;}const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];function listenArrayEvents(array, listener) {  if (array._chartjs) {    array._chartjs.listeners.push(listener);    return;  }  Object.defineProperty(array, '_chartjs', {    configurable: true,    enumerable: false,    value: {      listeners: [listener]    }  });  arrayEvents.forEach((key) => {    const method = '_onData' + _capitalize(key);    const base = array[key];    Object.defineProperty(array, key, {      configurable: true,      enumerable: false,      value(...args) {        const res = base.apply(this, args);        array._chartjs.listeners.forEach((object) => {          if (typeof object[method] === 'function') {            object[method](...args);          }        });        return res;      }    });  });}function unlistenArrayEvents(array, listener) {  const stub = array._chartjs;  if (!stub) {    return;  }  const listeners = stub.listeners;  const index = listeners.indexOf(listener);  if (index !== -1) {    listeners.splice(index, 1);  }  if (listeners.length > 0) {    return;  }  arrayEvents.forEach((key) => {    delete array[key];  });  delete array._chartjs;}function _arrayUnique(items) {  const set = new Set();  let i, ilen;  for (i = 0, ilen = items.length; i < ilen; ++i) {    set.add(items[i]);  }  if (set.size === ilen) {    return items;  }  return Array.from(set);}function _isDomSupported() {  return typeof window !== 'undefined' && typeof document !== 'undefined';}function _getParentNode(domNode) {  let parent = domNode.parentNode;  if (parent && parent.toString() === '[object ShadowRoot]') {    parent = parent.host;  }  return parent;}function parseMaxStyle(styleValue, node, parentProperty) {  let valueInPixels;  if (typeof styleValue === 'string') {    valueInPixels = parseInt(styleValue, 10);    if (styleValue.indexOf('%') !== -1) {      valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];    }  } else {    valueInPixels = styleValue;  }  return valueInPixels;}const getComputedStyle = (element) => window.getComputedStyle(element, null);function getStyle(el, property) {  return getComputedStyle(el).getPropertyValue(property);}const positions = ['top', 'right', 'bottom', 'left'];function getPositionedStyle(styles, style, suffix) {  const result = {};  suffix = suffix ? '-' + suffix : '';  for (let i = 0; i < 4; i++) {    const pos = positions[i];    result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;  }  result.width = result.left + result.right;  result.height = result.top + result.bottom;  return result;}const useOffsetPos = (x, y, target) => (x > 0 || y > 0) && (!target || !target.shadowRoot);function getCanvasPosition(evt, canvas) {  const e = evt.native || evt;  const touches = e.touches;  const source = touches && touches.length ? touches[0] : e;  const {offsetX, offsetY} = source;  let box = false;  let x, y;  if (useOffsetPos(offsetX, offsetY, e.target)) {    x = offsetX;    y = offsetY;  } else {    const rect = canvas.getBoundingClientRect();    x = source.clientX - rect.left;    y = source.clientY - rect.top;    box = true;  }  return {x, y, box};}function getRelativePosition$1(evt, chart) {  const {canvas, currentDevicePixelRatio} = chart;  const style = getComputedStyle(canvas);  const borderBox = style.boxSizing === 'border-box';  const paddings = getPositionedStyle(style, 'padding');  const borders = getPositionedStyle(style, 'border', 'width');  const {x, y, box} = getCanvasPosition(evt, canvas);  const xOffset = paddings.left + (box && borders.left);  const yOffset = paddings.top + (box && borders.top);  let {width, height} = chart;  if (borderBox) {    width -= paddings.width + borders.width;    height -= paddings.height + borders.height;  }  return {    x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),    y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)  };}function getContainerSize(canvas, width, height) {  let maxWidth, maxHeight;  if (width === undefined || height === undefined) {    const container = _getParentNode(canvas);    if (!container) {      width = canvas.clientWidth;      height = canvas.clientHeight;    } else {      const rect = container.getBoundingClientRect();      const containerStyle = getComputedStyle(container);      const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');      const containerPadding = getPositionedStyle(containerStyle, 'padding');      width = rect.width - containerPadding.width - containerBorder.width;      height = rect.height - containerPadding.height - containerBorder.height;      maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');      maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');    }  }  return {    width,    height,    maxWidth: maxWidth || INFINITY,    maxHeight: maxHeight || INFINITY  };}const round1 = v => Math.round(v * 10) / 10;function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {  const style = getComputedStyle(canvas);  const margins = getPositionedStyle(style, 'margin');  const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;  const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;  const containerSize = getContainerSize(canvas, bbWidth, bbHeight);  let {width, height} = containerSize;  if (style.boxSizing === 'content-box') {    const borders = getPositionedStyle(style, 'border', 'width');    const paddings = getPositionedStyle(style, 'padding');    width -= paddings.width + borders.width;    height -= paddings.height + borders.height;  }  width = Math.max(0, width - margins.width);  height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height);  width = round1(Math.min(width, maxWidth, containerSize.maxWidth));  height = round1(Math.min(height, maxHeight, containerSize.maxHeight));  if (width && !height) {    height = round1(width / 2);  }  return {    width,    height  };}function retinaScale(chart, forceRatio, forceStyle) {  const pixelRatio = forceRatio || 1;  const deviceHeight = Math.floor(chart.height * pixelRatio);  const deviceWidth = Math.floor(chart.width * pixelRatio);  chart.height = deviceHeight / pixelRatio;  chart.width = deviceWidth / pixelRatio;  const canvas = chart.canvas;  if (canvas.style && (forceStyle || (!canvas.style.height && !canvas.style.width))) {    canvas.style.height = `${chart.height}px`;    canvas.style.width = `${chart.width}px`;  }  if (chart.currentDevicePixelRatio !== pixelRatio      || canvas.height !== deviceHeight      || canvas.width !== deviceWidth) {    chart.currentDevicePixelRatio = pixelRatio;    canvas.height = deviceHeight;    canvas.width = deviceWidth;    chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);    return true;  }  return false;}const supportsEventListenerOptions = (function() {  let passiveSupported = false;  try {    const options = {      get passive() {        passiveSupported = true;        return false;      }    };    window.addEventListener('test', null, options);    window.removeEventListener('test', null, options);  } catch (e) {  }  return passiveSupported;}());function readUsedSize(element, property) {  const value = getStyle(element, property);  const matches = value && value.match(/^(\d+)(\.\d+)?px$/);  return matches ? +matches[1] : undefined;}function getRelativePosition(e, chart) {  if ('native' in e) {    return {      x: e.x,      y: e.y    };  }  return getRelativePosition$1(e, chart);}function evaluateAllVisibleItems(chart, handler) {  const metasets = chart.getSortedVisibleDatasetMetas();  let index, data, element;  for (let i = 0, ilen = metasets.length; i < ilen; ++i) {    ({index, data} = metasets[i]);    for (let j = 0, jlen = data.length; j < jlen; ++j) {      element = data[j];      if (!element.skip) {        handler(element, index, j);      }    }  }}function binarySearch(metaset, axis, value, intersect) {  const {controller, data, _sorted} = metaset;  const iScale = controller._cachedMeta.iScale;  if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) {    const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey;    if (!intersect) {      return lookupMethod(data, axis, value);    } else if (controller._sharedOptions) {      const el = data[0];      const range = typeof el.getRange === 'function' && el.getRange(axis);      if (range) {        const start = lookupMethod(data, axis, value - range);        const end = lookupMethod(data, axis, value + range);        return {lo: start.lo, hi: end.hi};      }    }  }  return {lo: 0, hi: data.length - 1};}function optimizedEvaluateItems(chart, axis, position, handler, intersect) {  const metasets = chart.getSortedVisibleDatasetMetas();  const value = position[axis];  for (let i = 0, ilen = metasets.length; i < ilen; ++i) {    const {index, data} = metasets[i];    const {lo, hi} = binarySearch(metasets[i], axis, value, intersect);    for (let j = lo; j <= hi; ++j) {      const element = data[j];      if (!element.skip) {        handler(element, index, j);      }    }  }}function getDistanceMetricForAxis(axis) {  const useX = axis.indexOf('x') !== -1;  const useY = axis.indexOf('y') !== -1;  return function(pt1, pt2) {    const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;    const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;    return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));  };}function getIntersectItems(chart, position, axis, useFinalPosition) {  const items = [];  if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) {    return items;  }  const evaluationFunc = function(element, datasetIndex, index) {    if (element.inRange(position.x, position.y, useFinalPosition)) {      items.push({element, datasetIndex, index});    }  };  optimizedEvaluateItems(chart, axis, position, evaluationFunc, true);  return items;}function getNearestRadialItems(chart, position, axis, useFinalPosition) {  let items = [];  function evaluationFunc(element, datasetIndex, index) {    const {startAngle, endAngle} = element.getProps(['startAngle', 'endAngle'], useFinalPosition);    const {angle} = getAngleFromPoint(element, {x: position.x, y: position.y});    if (_angleBetween(angle, startAngle, endAngle)) {      items.push({element, datasetIndex, index});    }  }  optimizedEvaluateItems(chart, axis, position, evaluationFunc);  return items;}function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition) {  let items = [];  const distanceMetric = getDistanceMetricForAxis(axis);  let minDistance = Number.POSITIVE_INFINITY;  function evaluationFunc(element, datasetIndex, index) {    const inRange = element.inRange(position.x, position.y, useFinalPosition);    if (intersect && !inRange) {      return;    }    const center = element.getCenterPoint(useFinalPosition);    const pointInArea = _isPointInArea(center, chart.chartArea, chart._minPadding);    if (!pointInArea && !inRange) {      return;    }    const distance = distanceMetric(position, center);    if (distance < minDistance) {      items = [{element, datasetIndex, index}];      minDistance = distance;    } else if (distance === minDistance) {      items.push({element, datasetIndex, index});    }  }  optimizedEvaluateItems(chart, axis, position, evaluationFunc);  return items;}function getNearestItems(chart, position, axis, intersect, useFinalPosition) {  if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) {    return [];  }  return axis === 'r' && !intersect    ? getNearestRadialItems(chart, position, axis, useFinalPosition)    : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition);}function getAxisItems(chart, e, options, useFinalPosition) {  const position = getRelativePosition(e, chart);  const items = [];  const axis = options.axis;  const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';  let intersectsItem = false;  evaluateAllVisibleItems(chart, (element, datasetIndex, index) => {    if (element[rangeMethod](position[axis], useFinalPosition)) {      items.push({element, datasetIndex, index});    }    if (element.inRange(position.x, position.y, useFinalPosition)) {      intersectsItem = true;    }  });  if (options.intersect && !intersectsItem) {    return [];  }  return items;}var Interaction = {  modes: {    index(chart, e, options, useFinalPosition) {      const position = getRelativePosition(e, chart);      const axis = options.axis || 'x';      const items = options.intersect        ? getIntersectItems(chart, position, axis, useFinalPosition)        : getNearestItems(chart, position, axis, false, useFinalPosition);      const elements = [];      if (!items.length) {        return [];      }      chart.getSortedVisibleDatasetMetas().forEach((meta) => {        const index = items[0].index;        const element = meta.data[index];        if (element && !element.skip) {          elements.push({element, datasetIndex: meta.index, index});        }      });      return elements;    },    dataset(chart, e, options, useFinalPosition) {      const position = getRelativePosition(e, chart);      const axis = options.axis || 'xy';      let items = options.intersect        ? getIntersectItems(chart, position, axis, useFinalPosition) :        getNearestItems(chart, position, axis, false, useFinalPosition);      if (items.length > 0) {        const datasetIndex = items[0].datasetIndex;        const data = chart.getDatasetMeta(datasetIndex).data;        items = [];        for (let i = 0; i < data.length; ++i) {          items.push({element: data[i], datasetIndex, index: i});        }      }      return items;    },    point(chart, e, options, useFinalPosition) {      const position = getRelativePosition(e, chart);      const axis = options.axis || 'xy';      return getIntersectItems(chart, position, axis, useFinalPosition);    },    nearest(chart, e, options, useFinalPosition) {      const position = getRelativePosition(e, chart);      const axis = options.axis || 'xy';      return getNearestItems(chart, position, axis, options.intersect, useFinalPosition);    },    x(chart, e, options, useFinalPosition) {      return getAxisItems(chart, e, {axis: 'x', intersect: options.intersect}, useFinalPosition);    },    y(chart, e, options, useFinalPosition) {      return getAxisItems(chart, e, {axis: 'y', intersect: options.intersect}, useFinalPosition);    }  }};const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);const FONT_STYLE = new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/);function toLineHeight(value, size) {  const matches = ('' + value).match(LINE_HEIGHT);  if (!matches || matches[1] === 'normal') {    return size * 1.2;  }  value = +matches[2];  switch (matches[3]) {  case 'px':    return value;  case '%':    value /= 100;    break;  }  return size * value;}const numberOrZero = v => +v || 0;function _readValueToProps(value, props) {  const ret = {};  const objProps = isObject(props);  const keys = objProps ? Object.keys(props) : props;  const read = isObject(value)    ? objProps      ? prop => valueOrDefault(value[prop], value[props[prop]])      : prop => value[prop]    : () => value;  for (const prop of keys) {    ret[prop] = numberOrZero(read(prop));  }  return ret;}function toTRBL(value) {  return _readValueToProps(value, {top: 'y', right: 'x', bottom: 'y', left: 'x'});}function toTRBLCorners(value) {  return _readValueToProps(value, ['topLeft', 'topRight', 'bottomLeft', 'bottomRight']);}function toPadding(value) {  const obj = toTRBL(value);  obj.width = obj.left + obj.right;  obj.height = obj.top + obj.bottom;  return obj;}function toFont(options, fallback) {  options = options || {};  fallback = fallback || defaults.font;  let size = valueOrDefault(options.size, fallback.size);  if (typeof size === 'string') {    size = parseInt(size, 10);  }  let style = valueOrDefault(options.style, fallback.style);  if (style && !('' + style).match(FONT_STYLE)) {    console.warn('Invalid font style specified: "' + style + '"');    style = '';  }  const font = {    family: valueOrDefault(options.family, fallback.family),    lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),    size,    style,    weight: valueOrDefault(options.weight, fallback.weight),    string: ''  };  font.string = toFontString(font);  return font;}function resolve(inputs, context, index, info) {  let cacheable = true;  let i, ilen, value;  for (i = 0, ilen = inputs.length; i < ilen; ++i) {    value = inputs[i];    if (value === undefined) {      continue;    }    if (context !== undefined && typeof value === 'function') {      value = value(context);      cacheable = false;    }    if (index !== undefined && isArray(value)) {      value = value[index % value.length];      cacheable = false;    }    if (value !== undefined) {      if (info && !cacheable) {        info.cacheable = false;      }      return value;    }  }}function _addGrace(minmax, grace, beginAtZero) {  const {min, max} = minmax;  const change = toDimension(grace, (max - min) / 2);  const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add;  return {    min: keepZero(min, -Math.abs(change)),    max: keepZero(max, change)  };}function createContext(parentContext, context) {  return Object.assign(Object.create(parentContext), context);}const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom'];function filterByPosition(array, position) {  return array.filter(v => v.pos === position);}function filterDynamicPositionByAxis(array, axis) {  return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);}function sortByWeight(array, reverse) {  return array.sort((a, b) => {    const v0 = reverse ? b : a;    const v1 = reverse ? a : b;    return v0.weight === v1.weight ?      v0.index - v1.index :      v0.weight - v1.weight;  });}function wrapBoxes(boxes) {  const layoutBoxes = [];  let i, ilen, box, pos, stack, stackWeight;  for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) {    box = boxes[i];    ({position: pos, options: {stack, stackWeight = 1}} = box);    layoutBoxes.push({      index: i,      box,      pos,      horizontal: box.isHorizontal(),      weight: box.weight,      stack: stack && (pos + stack),      stackWeight    });  }  return layoutBoxes;}function buildStacks(layouts) {  const stacks = {};  for (const wrap of layouts) {    const {stack, pos, stackWeight} = wrap;    if (!stack || !STATIC_POSITIONS.includes(pos)) {      continue;    }    const _stack = stacks[stack] || (stacks[stack] = {count: 0, placed: 0, weight: 0, size: 0});    _stack.count++;    _stack.weight += stackWeight;  }  return stacks;}function setLayoutDims(layouts, params) {  const stacks = buildStacks(layouts);  const {vBoxMaxWidth, hBoxMaxHeight} = params;  let i, ilen, layout;  for (i = 0, ilen = layouts.length; i < ilen; ++i) {    layout = layouts[i];    const {fullSize} = layout.box;    const stack = stacks[layout.stack];    const factor = stack && layout.stackWeight / stack.weight;    if (layout.horizontal) {      layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth;      layout.height = hBoxMaxHeight;    } else {      layout.width = vBoxMaxWidth;      layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight;    }  }  return stacks;}function buildLayoutBoxes(boxes) {  const layoutBoxes = wrapBoxes(boxes);  const fullSize = sortByWeight(layoutBoxes.filter(wrap => wrap.box.fullSize), true);  const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);  const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));  const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);  const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));  const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');  const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');  return {    fullSize,    leftAndTop: left.concat(top),    rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),    chartArea: filterByPosition(layoutBoxes, 'chartArea'),    vertical: left.concat(right).concat(centerVertical),    horizontal: top.concat(bottom).concat(centerHorizontal)  };}function getCombinedMax(maxPadding, chartArea, a, b) {  return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);}function updateMaxPadding(maxPadding, boxPadding) {  maxPadding.top = Math.max(maxPadding.top, boxPadding.top);  maxPadding.left = Math.max(maxPadding.left, boxPadding.left);  maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);  maxPadding.right = Math.max(maxPadding.right, boxPadding.right);}function updateDims(chartArea, params, layout, stacks) {  const {pos, box} = layout;  const maxPadding = chartArea.maxPadding;  if (!isObject(pos)) {    if (layout.size) {      chartArea[pos] -= layout.size;    }    const stack = stacks[layout.stack] || {size: 0, count: 1};    stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width);    layout.size = stack.size / stack.count;    chartArea[pos] += layout.size;  }  if (box.getPadding) {    updateMaxPadding(maxPadding, box.getPadding());  }  const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));  const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));  const widthChanged = newWidth !== chartArea.w;  const heightChanged = newHeight !== chartArea.h;  chartArea.w = newWidth;  chartArea.h = newHeight;  return layout.horizontal    ? {same: widthChanged, other: heightChanged}    : {same: heightChanged, other: widthChanged};}function handleMaxPadding(chartArea) {  const maxPadding = chartArea.maxPadding;  function updatePos(pos) {    const change = Math.max(maxPadding[pos] - chartArea[pos], 0);    chartArea[pos] += change;    return change;  }  chartArea.y += updatePos('top');  chartArea.x += updatePos('left');  updatePos('right');  updatePos('bottom');}function getMargins(horizontal, chartArea) {  const maxPadding = chartArea.maxPadding;  function marginForPositions(positions) {    const margin = {left: 0, top: 0, right: 0, bottom: 0};    positions.forEach((pos) => {      margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);    });    return margin;  }  return horizontal    ? marginForPositions(['left', 'right'])    : marginForPositions(['top', 'bottom']);}function fitBoxes(boxes, chartArea, params, stacks) {  const refitBoxes = [];  let i, ilen, layout, box, refit, changed;  for (i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i) {    layout = boxes[i];    box = layout.box;    box.update(      layout.width || chartArea.w,      layout.height || chartArea.h,      getMargins(layout.horizontal, chartArea)    );    const {same, other} = updateDims(chartArea, params, layout, stacks);    refit |= same && refitBoxes.length;    changed = changed || other;    if (!box.fullSize) {      refitBoxes.push(layout);    }  }  return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed;}function setBoxDims(box, left, top, width, height) {  box.top = top;  box.left = left;  box.right = left + width;  box.bottom = top + height;  box.width = width;  box.height = height;}function placeBoxes(boxes, chartArea, params, stacks) {  const userPadding = params.padding;  let {x, y} = chartArea;  for (const layout of boxes) {    const box = layout.box;    const stack = stacks[layout.stack] || {count: 1, placed: 0, weight: 1};    const weight = (layout.stackWeight / stack.weight) || 1;    if (layout.horizontal) {      const width = chartArea.w * weight;      const height = stack.size || box.height;      if (defined(stack.start)) {        y = stack.start;      }      if (box.fullSize) {        setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height);      } else {        setBoxDims(box, chartArea.left + stack.placed, y, width, height);      }      stack.start = y;      stack.placed += width;      y = box.bottom;    } else {      const height = chartArea.h * weight;      const width = stack.size || box.width;      if (defined(stack.start)) {        x = stack.start;      }      if (box.fullSize) {        setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top);      } else {        setBoxDims(box, x, chartArea.top + stack.placed, width, height);      }      stack.start = x;      stack.placed += height;      x = box.right;    }  }  chartArea.x = x;  chartArea.y = y;}defaults.set('layout', {  autoPadding: true,  padding: {    top: 0,    right: 0,    bottom: 0,    left: 0  }});var layouts = {  addBox(chart, item) {    if (!chart.boxes) {      chart.boxes = [];    }    item.fullSize = item.fullSize || false;    item.position = item.position || 'top';    item.weight = item.weight || 0;    item._layers = item._layers || function() {      return [{        z: 0,        draw(chartArea) {          item.draw(chartArea);        }      }];    };    chart.boxes.push(item);  },  removeBox(chart, layoutItem) {    const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;    if (index !== -1) {      chart.boxes.splice(index, 1);    }  },  configure(chart, item, options) {    item.fullSize = options.fullSize;    item.position = options.position;    item.weight = options.weight;  },  update(chart, width, height, minPadding) {    if (!chart) {      return;    }    const padding = toPadding(chart.options.layout.padding);    const availableWidth = Math.max(width - padding.width, 0);    const availableHeight = Math.max(height - padding.height, 0);    const boxes = buildLayoutBoxes(chart.boxes);    const verticalBoxes = boxes.vertical;    const horizontalBoxes = boxes.horizontal;    each(chart.boxes, box => {      if (typeof box.beforeLayout === 'function') {        box.beforeLayout();      }    });    const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap) =>      wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1;    const params = Object.freeze({      outerWidth: width,      outerHeight: height,      padding,      availableWidth,      availableHeight,      vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount,      hBoxMaxHeight: availableHeight / 2    });    const maxPadding = Object.assign({}, padding);    updateMaxPadding(maxPadding, toPadding(minPadding));    const chartArea = Object.assign({      maxPadding,      w: availableWidth,      h: availableHeight,      x: padding.left,      y: padding.top    }, padding);    const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);    fitBoxes(boxes.fullSize, chartArea, params, stacks);    fitBoxes(verticalBoxes, chartArea, params, stacks);    if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) {      fitBoxes(verticalBoxes, chartArea, params, stacks);    }    handleMaxPadding(chartArea);    placeBoxes(boxes.leftAndTop, chartArea, params, stacks);    chartArea.x += chartArea.w;    chartArea.y += chartArea.h;    placeBoxes(boxes.rightAndBottom, chartArea, params, stacks);    chart.chartArea = {      left: chartArea.left,      top: chartArea.top,      right: chartArea.left + chartArea.w,      bottom: chartArea.top + chartArea.h,      height: chartArea.h,      width: chartArea.w,    };    each(boxes.chartArea, (layout) => {      const box = layout.box;      Object.assign(box, chart.chartArea);      box.update(chartArea.w, chartArea.h, {left: 0, top: 0, right: 0, bottom: 0});    });  }};function _createResolver(scopes, prefixes = [''], rootScopes = scopes, fallback, getTarget = () => scopes[0]) {  if (!defined(fallback)) {    fallback = _resolve('_fallback', scopes);  }  const cache = {    [Symbol.toStringTag]: 'Object',    _cacheable: true,    _scopes: scopes,    _rootScopes: rootScopes,    _fallback: fallback,    _getTarget: getTarget,    override: (scope) => _createResolver([scope, ...scopes], prefixes, rootScopes, fallback),  };  return new Proxy(cache, {    deleteProperty(target, prop) {      delete target[prop];      delete target._keys;      delete scopes[0][prop];      return true;    },    get(target, prop) {      return _cached(target, prop,        () => _resolveWithPrefixes(prop, prefixes, scopes, target));    },    getOwnPropertyDescriptor(target, prop) {      return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);    },    getPrototypeOf() {      return Reflect.getPrototypeOf(scopes[0]);    },    has(target, prop) {      return getKeysFromAllScopes(target).includes(prop);    },    ownKeys(target) {      return getKeysFromAllScopes(target);    },    set(target, prop, value) {      const storage = target._storage || (target._storage = getTarget());      target[prop] = storage[prop] = value;      delete target._keys;      return true;    }  });}function _attachContext(proxy, context, subProxy, descriptorDefaults) {  const cache = {    _cacheable: false,    _proxy: proxy,    _context: context,    _subProxy: subProxy,    _stack: new Set(),    _descriptors: _descriptors(proxy, descriptorDefaults),    setContext: (ctx) => _attachContext(proxy, ctx, subProxy, descriptorDefaults),    override: (scope) => _attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)  };  return new Proxy(cache, {    deleteProperty(target, prop) {      delete target[prop];      delete proxy[prop];      return true;    },    get(target, prop, receiver) {      return _cached(target, prop,        () => _resolveWithContext(target, prop, receiver));    },    getOwnPropertyDescriptor(target, prop) {      return target._descriptors.allKeys        ? Reflect.has(proxy, prop) ? {enumerable: true, configurable: true} : undefined        : Reflect.getOwnPropertyDescriptor(proxy, prop);    },    getPrototypeOf() {      return Reflect.getPrototypeOf(proxy);    },    has(target, prop) {      return Reflect.has(proxy, prop);    },    ownKeys() {      return Reflect.ownKeys(proxy);    },    set(target, prop, value) {      proxy[prop] = value;      delete target[prop];      return true;    }  });}function _descriptors(proxy, defaults = {scriptable: true, indexable: true}) {  const {_scriptable = defaults.scriptable, _indexable = defaults.indexable, _allKeys = defaults.allKeys} = proxy;  return {    allKeys: _allKeys,    scriptable: _scriptable,    indexable: _indexable,    isScriptable: isFunction(_scriptable) ? _scriptable : () => _scriptable,    isIndexable: isFunction(_indexable) ? _indexable : () => _indexable  };}const readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name;const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters' &&  (Object.getPrototypeOf(value) === null || value.constructor === Object);function _cached(target, prop, resolve) {  if (Object.prototype.hasOwnProperty.call(target, prop)) {    return target[prop];  }  const value = resolve();  target[prop] = value;  return value;}function _resolveWithContext(target, prop, receiver) {  const {_proxy, _context, _subProxy, _descriptors: descriptors} = target;  let value = _proxy[prop];  if (isFunction(value) && descriptors.isScriptable(prop)) {    value = _resolveScriptable(prop, value, target, receiver);  }  if (isArray(value) && value.length) {    value = _resolveArray(prop, value, target, descriptors.isIndexable);  }  if (needsSubResolver(prop, value)) {    value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors);  }  return value;}function _resolveScriptable(prop, value, target, receiver) {  const {_proxy, _context, _subProxy, _stack} = target;  if (_stack.has(prop)) {    throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop);  }  _stack.add(prop);  value = value(_context, _subProxy || receiver);  _stack.delete(prop);  if (needsSubResolver(prop, value)) {    value = createSubResolver(_proxy._scopes, _proxy, prop, value);  }  return value;}function _resolveArray(prop, value, target, isIndexable) {  const {_proxy, _context, _subProxy, _descriptors: descriptors} = target;  if (defined(_context.index) && isIndexable(prop)) {    value = value[_context.index % value.length];  } else if (isObject(value[0])) {    const arr = value;    const scopes = _proxy._scopes.filter(s => s !== arr);    value = [];    for (const item of arr) {      const resolver = createSubResolver(scopes, _proxy, prop, item);      value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors));    }  }  return value;}function resolveFallback(fallback, prop, value) {  return isFunction(fallback) ? fallback(prop, value) : fallback;}const getScope = (key, parent) => key === true ? parent  : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;function addScopes(set, parentScopes, key, parentFallback, value) {  for (const parent of parentScopes) {    const scope = getScope(key, parent);    if (scope) {      set.add(scope);      const fallback = resolveFallback(scope._fallback, key, value);      if (defined(fallback) && fallback !== key && fallback !== parentFallback) {        return fallback;      }    } else if (scope === false && defined(parentFallback) && key !== parentFallback) {      return null;    }  }  return false;}function createSubResolver(parentScopes, resolver, prop, value) {  const rootScopes = resolver._rootScopes;  const fallback = resolveFallback(resolver._fallback, prop, value);  const allScopes = [...parentScopes, ...rootScopes];  const set = new Set();  set.add(value);  let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);  if (key === null) {    return false;  }  if (defined(fallback) && fallback !== prop) {    key = addScopesFromKey(set, allScopes, fallback, key, value);    if (key === null) {      return false;    }  }  return _createResolver(Array.from(set), [''], rootScopes, fallback,    () => subGetTarget(resolver, prop, value));}function addScopesFromKey(set, allScopes, key, fallback, item) {  while (key) {    key = addScopes(set, allScopes, key, fallback, item);  }  return key;}function subGetTarget(resolver, prop, value) {  const parent = resolver._getTarget();  if (!(prop in parent)) {    parent[prop] = {};  }  const target = parent[prop];  if (isArray(target) && isObject(value)) {    return value;  }  return target;}function _resolveWithPrefixes(prop, prefixes, scopes, proxy) {  let value;  for (const prefix of prefixes) {    value = _resolve(readKey(prefix, prop), scopes);    if (defined(value)) {      return needsSubResolver(prop, value)        ? createSubResolver(scopes, proxy, prop, value)        : value;    }  }}function _resolve(key, scopes) {  for (const scope of scopes) {    if (!scope) {      continue;    }    const value = scope[key];    if (defined(value)) {      return value;    }  }}function getKeysFromAllScopes(target) {  let keys = target._keys;  if (!keys) {    keys = target._keys = resolveKeysFromAllScopes(target._scopes);  }  return keys;}function resolveKeysFromAllScopes(scopes) {  const set = new Set();  for (const scope of scopes) {    for (const key of Object.keys(scope).filter(k => !k.startsWith('_'))) {      set.add(key);    }  }  return Array.from(set);}const EPSILON = Number.EPSILON || 1e-14;const getPoint = (points, i) => i < points.length && !points[i].skip && points[i];const getValueAxis = (indexAxis) => indexAxis === 'x' ? 'y' : 'x';function splineCurve(firstPoint, middlePoint, afterPoint, t) {  const previous = firstPoint.skip ? middlePoint : firstPoint;  const current = middlePoint;  const next = afterPoint.skip ? middlePoint : afterPoint;  const d01 = distanceBetweenPoints(current, previous);  const d12 = distanceBetweenPoints(next, current);  let s01 = d01 / (d01 + d12);  let s12 = d12 / (d01 + d12);  s01 = isNaN(s01) ? 0 : s01;  s12 = isNaN(s12) ? 0 : s12;  const fa = t * s01;  const fb = t * s12;  return {    previous: {      x: current.x - fa * (next.x - previous.x),      y: current.y - fa * (next.y - previous.y)    },    next: {      x: current.x + fb * (next.x - previous.x),      y: current.y + fb * (next.y - previous.y)    }  };}function monotoneAdjust(points, deltaK, mK) {  const pointsLen = points.length;  let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;  let pointAfter = getPoint(points, 0);  for (let i = 0; i < pointsLen - 1; ++i) {    pointCurrent = pointAfter;    pointAfter = getPoint(points, i + 1);    if (!pointCurrent || !pointAfter) {      continue;    }    if (almostEquals(deltaK[i], 0, EPSILON)) {      mK[i] = mK[i + 1] = 0;      continue;    }    alphaK = mK[i] / deltaK[i];    betaK = mK[i + 1] / deltaK[i];    squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);    if (squaredMagnitude <= 9) {      continue;    }    tauK = 3 / Math.sqrt(squaredMagnitude);    mK[i] = alphaK * tauK * deltaK[i];    mK[i + 1] = betaK * tauK * deltaK[i];  }}function monotoneCompute(points, mK, indexAxis = 'x') {  const valueAxis = getValueAxis(indexAxis);  const pointsLen = points.length;  let delta, pointBefore, pointCurrent;  let pointAfter = getPoint(points, 0);  for (let i = 0; i < pointsLen; ++i) {    pointBefore = pointCurrent;    pointCurrent = pointAfter;    pointAfter = getPoint(points, i + 1);    if (!pointCurrent) {      continue;    }    const iPixel = pointCurrent[indexAxis];    const vPixel = pointCurrent[valueAxis];    if (pointBefore) {      delta = (iPixel - pointBefore[indexAxis]) / 3;      pointCurrent[`cp1${indexAxis}`] = iPixel - delta;      pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i];    }    if (pointAfter) {      delta = (pointAfter[indexAxis] - iPixel) / 3;      pointCurrent[`cp2${indexAxis}`] = iPixel + delta;      pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i];    }  }}function splineCurveMonotone(points, indexAxis = 'x') {  const valueAxis = getValueAxis(indexAxis);  const pointsLen = points.length;  const deltaK = Array(pointsLen).fill(0);  const mK = Array(pointsLen);  let i, pointBefore, pointCurrent;  let pointAfter = getPoint(points, 0);  for (i = 0; i < pointsLen; ++i) {    pointBefore = pointCurrent;    pointCurrent = pointAfter;    pointAfter = getPoint(points, i + 1);    if (!pointCurrent) {      continue;    }    if (pointAfter) {      const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis];      deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0;    }    mK[i] = !pointBefore ? deltaK[i]      : !pointAfter ? deltaK[i - 1]      : (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0      : (deltaK[i - 1] + deltaK[i]) / 2;  }  monotoneAdjust(points, deltaK, mK);  monotoneCompute(points, mK, indexAxis);}function capControlPoint(pt, min, max) {  return Math.max(Math.min(pt, max), min);}function capBezierPoints(points, area) {  let i, ilen, point, inArea, inAreaPrev;  let inAreaNext = _isPointInArea(points[0], area);  for (i = 0, ilen = points.length; i < ilen; ++i) {    inAreaPrev = inArea;    inArea = inAreaNext;    inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area);    if (!inArea) {      continue;    }    point = points[i];    if (inAreaPrev) {      point.cp1x = capControlPoint(point.cp1x, area.left, area.right);      point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom);    }    if (inAreaNext) {      point.cp2x = capControlPoint(point.cp2x, area.left, area.right);      point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom);    }  }}function _updateBezierControlPoints(points, options, area, loop, indexAxis) {  let i, ilen, point, controlPoints;  if (options.spanGaps) {    points = points.filter((pt) => !pt.skip);  }  if (options.cubicInterpolationMode === 'monotone') {    splineCurveMonotone(points, indexAxis);  } else {    let prev = loop ? points[points.length - 1] : points[0];    for (i = 0, ilen = points.length; i < ilen; ++i) {      point = points[i];      controlPoints = splineCurve(        prev,        point,        points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen],        options.tension      );      point.cp1x = controlPoints.previous.x;      point.cp1y = controlPoints.previous.y;      point.cp2x = controlPoints.next.x;      point.cp2y = controlPoints.next.y;      prev = point;    }  }  if (options.capBezierPoints) {    capBezierPoints(points, area);  }}const atEdge = (t) => t === 0 || t === 1;const elasticIn = (t, s, p) => -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));const elasticOut = (t, s, p) => Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;const effects = {  linear: t => t,  easeInQuad: t => t * t,  easeOutQuad: t => -t * (t - 2),  easeInOutQuad: t => ((t /= 0.5) < 1)    ? 0.5 * t * t    : -0.5 * ((--t) * (t - 2) - 1),  easeInCubic: t => t * t * t,  easeOutCubic: t => (t -= 1) * t * t + 1,  easeInOutCubic: t => ((t /= 0.5) < 1)    ? 0.5 * t * t * t    : 0.5 * ((t -= 2) * t * t + 2),  easeInQuart: t => t * t * t * t,  easeOutQuart: t => -((t -= 1) * t * t * t - 1),  easeInOutQuart: t => ((t /= 0.5) < 1)    ? 0.5 * t * t * t * t    : -0.5 * ((t -= 2) * t * t * t - 2),  easeInQuint: t => t * t * t * t * t,  easeOutQuint: t => (t -= 1) * t * t * t * t + 1,  easeInOutQuint: t => ((t /= 0.5) < 1)    ? 0.5 * t * t * t * t * t    : 0.5 * ((t -= 2) * t * t * t * t + 2),  easeInSine: t => -Math.cos(t * HALF_PI) + 1,  easeOutSine: t => Math.sin(t * HALF_PI),  easeInOutSine: t => -0.5 * (Math.cos(PI * t) - 1),  easeInExpo: t => (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)),  easeOutExpo: t => (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1,  easeInOutExpo: t => atEdge(t) ? t : t < 0.5    ? 0.5 * Math.pow(2, 10 * (t * 2 - 1))    : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2),  easeInCirc: t => (t >= 1) ? t : -(Math.sqrt(1 - t * t) - 1),  easeOutCirc: t => Math.sqrt(1 - (t -= 1) * t),  easeInOutCirc: t => ((t /= 0.5) < 1)    ? -0.5 * (Math.sqrt(1 - t * t) - 1)    : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),  easeInElastic: t => atEdge(t) ? t : elasticIn(t, 0.075, 0.3),  easeOutElastic: t => atEdge(t) ? t : elasticOut(t, 0.075, 0.3),  easeInOutElastic(t) {    const s = 0.1125;    const p = 0.45;    return atEdge(t) ? t :      t < 0.5        ? 0.5 * elasticIn(t * 2, s, p)        : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p);  },  easeInBack(t) {    const s = 1.70158;    return t * t * ((s + 1) * t - s);  },  easeOutBack(t) {    const s = 1.70158;    return (t -= 1) * t * ((s + 1) * t + s) + 1;  },  easeInOutBack(t) {    let s = 1.70158;    if ((t /= 0.5) < 1) {      return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));    }    return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);  },  easeInBounce: t => 1 - effects.easeOutBounce(1 - t),  easeOutBounce(t) {    const m = 7.5625;    const d = 2.75;    if (t < (1 / d)) {      return m * t * t;    }    if (t < (2 / d)) {      return m * (t -= (1.5 / d)) * t + 0.75;    }    if (t < (2.5 / d)) {      return m * (t -= (2.25 / d)) * t + 0.9375;    }    return m * (t -= (2.625 / d)) * t + 0.984375;  },  easeInOutBounce: t => (t < 0.5)    ? effects.easeInBounce(t * 2) * 0.5    : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5,};function _pointInLine(p1, p2, t, mode) {  return {    x: p1.x + t * (p2.x - p1.x),    y: p1.y + t * (p2.y - p1.y)  };}function _steppedInterpolation(p1, p2, t, mode) {  return {    x: p1.x + t * (p2.x - p1.x),    y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y    : mode === 'after' ? t < 1 ? p1.y : p2.y    : t > 0 ? p2.y : p1.y  };}function _bezierInterpolation(p1, p2, t, mode) {  const cp1 = {x: p1.cp2x, y: p1.cp2y};  const cp2 = {x: p2.cp1x, y: p2.cp1y};  const a = _pointInLine(p1, cp1, t);  const b = _pointInLine(cp1, cp2, t);  const c = _pointInLine(cp2, p2, t);  const d = _pointInLine(a, b, t);  const e = _pointInLine(b, c, t);  return _pointInLine(d, e, t);}const intlCache = new Map();function getNumberFormat(locale, options) {  options = options || {};  const cacheKey = locale + JSON.stringify(options);  let formatter = intlCache.get(cacheKey);  if (!formatter) {    formatter = new Intl.NumberFormat(locale, options);    intlCache.set(cacheKey, formatter);  }  return formatter;}function formatNumber(num, locale, options) {  return getNumberFormat(locale, options).format(num);}const getRightToLeftAdapter = function(rectX, width) {  return {    x(x) {      return rectX + rectX + width - x;    },    setWidth(w) {      width = w;    },    textAlign(align) {      if (align === 'center') {        return align;      }      return align === 'right' ? 'left' : 'right';    },    xPlus(x, value) {      return x - value;    },    leftForLtr(x, itemWidth) {      return x - itemWidth;    },  };};const getLeftToRightAdapter = function() {  return {    x(x) {      return x;    },    setWidth(w) {    },    textAlign(align) {      return align;    },    xPlus(x, value) {      return x + value;    },    leftForLtr(x, _itemWidth) {      return x;    },  };};function getRtlAdapter(rtl, rectX, width) {  return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();}function overrideTextDirection(ctx, direction) {  let style, original;  if (direction === 'ltr' || direction === 'rtl') {    style = ctx.canvas.style;    original = [      style.getPropertyValue('direction'),      style.getPropertyPriority('direction'),    ];    style.setProperty('direction', direction, 'important');    ctx.prevTextDirection = original;  }}function restoreTextDirection(ctx, original) {  if (original !== undefined) {    delete ctx.prevTextDirection;    ctx.canvas.style.setProperty('direction', original[0], original[1]);  }}function propertyFn(property) {  if (property === 'angle') {    return {      between: _angleBetween,      compare: _angleDiff,      normalize: _normalizeAngle,    };  }  return {    between: _isBetween,    compare: (a, b) => a - b,    normalize: x => x  };}function normalizeSegment({start, end, count, loop, style}) {  return {    start: start % count,    end: end % count,    loop: loop && (end - start + 1) % count === 0,    style  };}function getSegment(segment, points, bounds) {  const {property, start: startBound, end: endBound} = bounds;  const {between, normalize} = propertyFn(property);  const count = points.length;  let {start, end, loop} = segment;  let i, ilen;  if (loop) {    start += count;    end += count;    for (i = 0, ilen = count; i < ilen; ++i) {      if (!between(normalize(points[start % count][property]), startBound, endBound)) {        break;      }      start--;      end--;    }    start %= count;    end %= count;  }  if (end < start) {    end += count;  }  return {start, end, loop, style: segment.style};}function _boundSegment(segment, points, bounds) {  if (!bounds) {    return [segment];  }  const {property, start: startBound, end: endBound} = bounds;  const count = points.length;  const {compare, between, normalize} = propertyFn(property);  const {start, end, loop, style} = getSegment(segment, points, bounds);  const result = [];  let inside = false;  let subStart = null;  let value, point, prevValue;  const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;  const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value);  const shouldStart = () => inside || startIsBefore();  const shouldStop = () => !inside || endIsBefore();  for (let i = start, prev = start; i <= end; ++i) {    point = points[i % count];    if (point.skip) {      continue;    }    value = normalize(point[property]);    if (value === prevValue) {      continue;    }    inside = between(value, startBound, endBound);    if (subStart === null && shouldStart()) {      subStart = compare(value, startBound) === 0 ? i : prev;    }    if (subStart !== null && shouldStop()) {      result.push(normalizeSegment({start: subStart, end: i, loop, count, style}));      subStart = null;    }    prev = i;    prevValue = value;  }  if (subStart !== null) {    result.push(normalizeSegment({start: subStart, end, loop, count, style}));  }  return result;}function _boundSegments(line, bounds) {  const result = [];  const segments = line.segments;  for (let i = 0; i < segments.length; i++) {    const sub = _boundSegment(segments[i], line.points, bounds);    if (sub.length) {      result.push(...sub);    }  }  return result;}function findStartAndEnd(points, count, loop, spanGaps) {  let start = 0;  let end = count - 1;  if (loop && !spanGaps) {    while (start < count && !points[start].skip) {      start++;    }  }  while (start < count && points[start].skip) {    start++;  }  start %= count;  if (loop) {    end += start;  }  while (end > start && points[end % count].skip) {    end--;  }  end %= count;  return {start, end};}function solidSegments(points, start, max, loop) {  const count = points.length;  const result = [];  let last = start;  let prev = points[start];  let end;  for (end = start + 1; end <= max; ++end) {    const cur = points[end % count];    if (cur.skip || cur.stop) {      if (!prev.skip) {        loop = false;        result.push({start: start % count, end: (end - 1) % count, loop});        start = last = cur.stop ? end : null;      }    } else {      last = end;      if (prev.skip) {        start = end;      }    }    prev = cur;  }  if (last !== null) {    result.push({start: start % count, end: last % count, loop});  }  return result;}function _computeSegments(line, segmentOptions) {  const points = line.points;  const spanGaps = line.options.spanGaps;  const count = points.length;  if (!count) {    return [];  }  const loop = !!line._loop;  const {start, end} = findStartAndEnd(points, count, loop, spanGaps);  if (spanGaps === true) {    return splitByStyles(line, [{start, end, loop}], points, segmentOptions);  }  const max = end < start ? end + count : end;  const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;  return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions);}function splitByStyles(line, segments, points, segmentOptions) {  if (!segmentOptions || !segmentOptions.setContext || !points) {    return segments;  }  return doSplitByStyles(line, segments, points, segmentOptions);}function doSplitByStyles(line, segments, points, segmentOptions) {  const chartContext = line._chart.getContext();  const baseStyle = readStyle(line.options);  const {_datasetIndex: datasetIndex, options: {spanGaps}} = line;  const count = points.length;  const result = [];  let prevStyle = baseStyle;  let start = segments[0].start;  let i = start;  function addStyle(s, e, l, st) {    const dir = spanGaps ? -1 : 1;    if (s === e) {      return;    }    s += count;    while (points[s % count].skip) {      s -= dir;    }    while (points[e % count].skip) {      e += dir;    }    if (s % count !== e % count) {      result.push({start: s % count, end: e % count, loop: l, style: st});      prevStyle = st;      start = e % count;    }  }  for (const segment of segments) {    start = spanGaps ? start : segment.start;    let prev = points[start % count];    let style;    for (i = start + 1; i <= segment.end; i++) {      const pt = points[i % count];      style = readStyle(segmentOptions.setContext(createContext(chartContext, {        type: 'segment',        p0: prev,        p1: pt,        p0DataIndex: (i - 1) % count,        p1DataIndex: i % count,        datasetIndex      })));      if (styleChanged(style, prevStyle)) {        addStyle(start, i - 1, segment.loop, prevStyle);      }      prev = pt;      prevStyle = style;    }    if (start < i - 1) {      addStyle(start, i - 1, segment.loop, prevStyle);    }  }  return result;}function readStyle(options) {  return {    backgroundColor: options.backgroundColor,    borderCapStyle: options.borderCapStyle,    borderDash: options.borderDash,    borderDashOffset: options.borderDashOffset,    borderJoinStyle: options.borderJoinStyle,    borderWidth: options.borderWidth,    borderColor: options.borderColor  };}function styleChanged(style, prevStyle) {  return prevStyle && JSON.stringify(style) !== JSON.stringify(prevStyle);}var helpers = /*#__PURE__*/Object.freeze({__proto__: null,easingEffects: effects,color: color,getHoverColor: getHoverColor,noop: noop,uid: uid,isNullOrUndef: isNullOrUndef,isArray: isArray,isObject: isObject,isFinite: isNumberFinite,finiteOrDefault: finiteOrDefault,valueOrDefault: valueOrDefault,toPercentage: toPercentage,toDimension: toDimension,callback: callback,each: each,_elementsEqual: _elementsEqual,clone: clone,_merger: _merger,merge: merge,mergeIf: mergeIf,_mergerIf: _mergerIf,_deprecated: _deprecated,resolveObjectKey: resolveObjectKey,_capitalize: _capitalize,defined: defined,isFunction: isFunction,setsEqual: setsEqual,_isClickEvent: _isClickEvent,toFontString: toFontString,_measureText: _measureText,_longestText: _longestText,_alignPixel: _alignPixel,clearCanvas: clearCanvas,drawPoint: drawPoint,_isPointInArea: _isPointInArea,clipArea: clipArea,unclipArea: unclipArea,_steppedLineTo: _steppedLineTo,_bezierCurveTo: _bezierCurveTo,renderText: renderText,addRoundedRectPath: addRoundedRectPath,_lookup: _lookup,_lookupByKey: _lookupByKey,_rlookupByKey: _rlookupByKey,_filterBetween: _filterBetween,listenArrayEvents: listenArrayEvents,unlistenArrayEvents: unlistenArrayEvents,_arrayUnique: _arrayUnique,_createResolver: _createResolver,_attachContext: _attachContext,_descriptors: _descriptors,splineCurve: splineCurve,splineCurveMonotone: splineCurveMonotone,_updateBezierControlPoints: _updateBezierControlPoints,_isDomSupported: _isDomSupported,_getParentNode: _getParentNode,getStyle: getStyle,getRelativePosition: getRelativePosition$1,getMaximumSize: getMaximumSize,retinaScale: retinaScale,supportsEventListenerOptions: supportsEventListenerOptions,readUsedSize: readUsedSize,fontString: fontString,requestAnimFrame: requestAnimFrame,throttled: throttled,debounce: debounce,_toLeftRightCenter: _toLeftRightCenter,_alignStartEnd: _alignStartEnd,_textX: _textX,_pointInLine: _pointInLine,_steppedInterpolation: _steppedInterpolation,_bezierInterpolation: _bezierInterpolation,formatNumber: formatNumber,toLineHeight: toLineHeight,_readValueToProps: _readValueToProps,toTRBL: toTRBL,toTRBLCorners: toTRBLCorners,toPadding: toPadding,toFont: toFont,resolve: resolve,_addGrace: _addGrace,createContext: createContext,PI: PI,TAU: TAU,PITAU: PITAU,INFINITY: INFINITY,RAD_PER_DEG: RAD_PER_DEG,HALF_PI: HALF_PI,QUARTER_PI: QUARTER_PI,TWO_THIRDS_PI: TWO_THIRDS_PI,log10: log10,sign: sign,niceNum: niceNum,_factorize: _factorize,isNumber: isNumber,almostEquals: almostEquals,almostWhole: almostWhole,_setMinAndMaxByKey: _setMinAndMaxByKey,toRadians: toRadians,toDegrees: toDegrees,_decimalPlaces: _decimalPlaces,getAngleFromPoint: getAngleFromPoint,distanceBetweenPoints: distanceBetweenPoints,_angleDiff: _angleDiff,_normalizeAngle: _normalizeAngle,_angleBetween: _angleBetween,_limitValue: _limitValue,_int16Range: _int16Range,_isBetween: _isBetween,getRtlAdapter: getRtlAdapter,overrideTextDirection: overrideTextDirection,restoreTextDirection: restoreTextDirection,_boundSegment: _boundSegment,_boundSegments: _boundSegments,_computeSegments: _computeSegments});class BasePlatform {  acquireContext(canvas, aspectRatio) {}  releaseContext(context) {    return false;  }  addEventListener(chart, type, listener) {}  removeEventListener(chart, type, listener) {}  getDevicePixelRatio() {    return 1;  }  getMaximumSize(element, width, height, aspectRatio) {    width = Math.max(0, width || element.width);    height = height || element.height;    return {      width,      height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)    };  }  isAttached(canvas) {    return true;  }  updateConfig(config) {  }}class BasicPlatform extends BasePlatform {  acquireContext(item) {    return item && item.getContext && item.getContext('2d') || null;  }  updateConfig(config) {    config.options.animation = false;  }}const EXPANDO_KEY = '$chartjs';const EVENT_TYPES = {  touchstart: 'mousedown',  touchmove: 'mousemove',  touchend: 'mouseup',  pointerenter: 'mouseenter',  pointerdown: 'mousedown',  pointermove: 'mousemove',  pointerup: 'mouseup',  pointerleave: 'mouseout',  pointerout: 'mouseout'};const isNullOrEmpty = value => value === null || value === '';function initCanvas(canvas, aspectRatio) {  const style = canvas.style;  const renderHeight = canvas.getAttribute('height');  const renderWidth = canvas.getAttribute('width');  canvas[EXPANDO_KEY] = {    initial: {      height: renderHeight,      width: renderWidth,      style: {        display: style.display,        height: style.height,        width: style.width      }    }  };  style.display = style.display || 'block';  style.boxSizing = style.boxSizing || 'border-box';  if (isNullOrEmpty(renderWidth)) {    const displayWidth = readUsedSize(canvas, 'width');    if (displayWidth !== undefined) {      canvas.width = displayWidth;    }  }  if (isNullOrEmpty(renderHeight)) {    if (canvas.style.height === '') {      canvas.height = canvas.width / (aspectRatio || 2);    } else {      const displayHeight = readUsedSize(canvas, 'height');      if (displayHeight !== undefined) {        canvas.height = displayHeight;      }    }  }  return canvas;}const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;function addListener(node, type, listener) {  node.addEventListener(type, listener, eventListenerOptions);}function removeListener(chart, type, listener) {  chart.canvas.removeEventListener(type, listener, eventListenerOptions);}function fromNativeEvent(event, chart) {  const type = EVENT_TYPES[event.type] || event.type;  const {x, y} = getRelativePosition$1(event, chart);  return {    type,    chart,    native: event,    x: x !== undefined ? x : null,    y: y !== undefined ? y : null,  };}function nodeListContains(nodeList, canvas) {  for (const node of nodeList) {    if (node === canvas || node.contains(canvas)) {      return true;    }  }}function createAttachObserver(chart, type, listener) {  const canvas = chart.canvas;  const observer = new MutationObserver(entries => {    let trigger = false;    for (const entry of entries) {      trigger = trigger || nodeListContains(entry.addedNodes, canvas);      trigger = trigger && !nodeListContains(entry.removedNodes, canvas);    }    if (trigger) {      listener();    }  });  observer.observe(document, {childList: true, subtree: true});  return observer;}function createDetachObserver(chart, type, listener) {  const canvas = chart.canvas;  const observer = new MutationObserver(entries => {    let trigger = false;    for (const entry of entries) {      trigger = trigger || nodeListContains(entry.removedNodes, canvas);      trigger = trigger && !nodeListContains(entry.addedNodes, canvas);    }    if (trigger) {      listener();    }  });  observer.observe(document, {childList: true, subtree: true});  return observer;}const drpListeningCharts = new Map();let oldDevicePixelRatio = 0;function onWindowResize() {  const dpr = window.devicePixelRatio;  if (dpr === oldDevicePixelRatio) {    return;  }  oldDevicePixelRatio = dpr;  drpListeningCharts.forEach((resize, chart) => {    if (chart.currentDevicePixelRatio !== dpr) {      resize();    }  });}function listenDevicePixelRatioChanges(chart, resize) {  if (!drpListeningCharts.size) {    window.addEventListener('resize', onWindowResize);  }  drpListeningCharts.set(chart, resize);}function unlistenDevicePixelRatioChanges(chart) {  drpListeningCharts.delete(chart);  if (!drpListeningCharts.size) {    window.removeEventListener('resize', onWindowResize);  }}function createResizeObserver(chart, type, listener) {  const canvas = chart.canvas;  const container = canvas && _getParentNode(canvas);  if (!container) {    return;  }  const resize = throttled((width, height) => {    const w = container.clientWidth;    listener(width, height);    if (w < container.clientWidth) {      listener();    }  }, window);  const observer = new ResizeObserver(entries => {    const entry = entries[0];    const width = entry.contentRect.width;    const height = entry.contentRect.height;    if (width === 0 && height === 0) {      return;    }    resize(width, height);  });  observer.observe(container);  listenDevicePixelRatioChanges(chart, resize);  return observer;}function releaseObserver(chart, type, observer) {  if (observer) {    observer.disconnect();  }  if (type === 'resize') {    unlistenDevicePixelRatioChanges(chart);  }}function createProxyAndListen(chart, type, listener) {  const canvas = chart.canvas;  const proxy = throttled((event) => {    if (chart.ctx !== null) {      listener(fromNativeEvent(event, chart));    }  }, chart, (args) => {    const event = args[0];    return [event, event.offsetX, event.offsetY];  });  addListener(canvas, type, proxy);  return proxy;}class DomPlatform extends BasePlatform {  acquireContext(canvas, aspectRatio) {    const context = canvas && canvas.getContext && canvas.getContext('2d');    if (context && context.canvas === canvas) {      initCanvas(canvas, aspectRatio);      return context;    }    return null;  }  releaseContext(context) {    const canvas = context.canvas;    if (!canvas[EXPANDO_KEY]) {      return false;    }    const initial = canvas[EXPANDO_KEY].initial;    ['height', 'width'].forEach((prop) => {      const value = initial[prop];      if (isNullOrUndef(value)) {        canvas.removeAttribute(prop);      } else {        canvas.setAttribute(prop, value);      }    });    const style = initial.style || {};    Object.keys(style).forEach((key) => {      canvas.style[key] = style[key];    });    canvas.width = canvas.width;    delete canvas[EXPANDO_KEY];    return true;  }  addEventListener(chart, type, listener) {    this.removeEventListener(chart, type);    const proxies = chart.$proxies || (chart.$proxies = {});    const handlers = {      attach: createAttachObserver,      detach: createDetachObserver,      resize: createResizeObserver    };    const handler = handlers[type] || createProxyAndListen;    proxies[type] = handler(chart, type, listener);  }  removeEventListener(chart, type) {    const proxies = chart.$proxies || (chart.$proxies = {});    const proxy = proxies[type];    if (!proxy) {      return;    }    const handlers = {      attach: releaseObserver,      detach: releaseObserver,      resize: releaseObserver    };    const handler = handlers[type] || removeListener;    handler(chart, type, proxy);    proxies[type] = undefined;  }  getDevicePixelRatio() {    return window.devicePixelRatio;  }  getMaximumSize(canvas, width, height, aspectRatio) {    return getMaximumSize(canvas, width, height, aspectRatio);  }  isAttached(canvas) {    const container = _getParentNode(canvas);    return !!(container && container.isConnected);  }}function _detectPlatform(canvas) {  if (!_isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) {    return BasicPlatform;  }  return DomPlatform;}var platforms = /*#__PURE__*/Object.freeze({__proto__: null,_detectPlatform: _detectPlatform,BasePlatform: BasePlatform,BasicPlatform: BasicPlatform,DomPlatform: DomPlatform});const transparent = 'transparent';const interpolators = {  boolean(from, to, factor) {    return factor > 0.5 ? to : from;  },  color(from, to, factor) {    const c0 = color(from || transparent);    const c1 = c0.valid && color(to || transparent);    return c1 && c1.valid      ? c1.mix(c0, factor).hexString()      : to;  },  number(from, to, factor) {    return from + (to - from) * factor;  }};class Animation {  constructor(cfg, target, prop, to) {    const currentValue = target[prop];    to = resolve([cfg.to, to, currentValue, cfg.from]);    const from = resolve([cfg.from, currentValue, to]);    this._active = true;    this._fn = cfg.fn || interpolators[cfg.type || typeof from];    this._easing = effects[cfg.easing] || effects.linear;    this._start = Math.floor(Date.now() + (cfg.delay || 0));    this._duration = this._total = Math.floor(cfg.duration);    this._loop = !!cfg.loop;    this._target = target;    this._prop = prop;    this._from = from;    this._to = to;    this._promises = undefined;  }  active() {    return this._active;  }  update(cfg, to, date) {    if (this._active) {      this._notify(false);      const currentValue = this._target[this._prop];      const elapsed = date - this._start;      const remain = this._duration - elapsed;      this._start = date;      this._duration = Math.floor(Math.max(remain, cfg.duration));      this._total += elapsed;      this._loop = !!cfg.loop;      this._to = resolve([cfg.to, to, currentValue, cfg.from]);      this._from = resolve([cfg.from, currentValue, to]);    }  }  cancel() {    if (this._active) {      this.tick(Date.now());      this._active = false;      this._notify(false);    }  }  tick(date) {    const elapsed = date - this._start;    const duration = this._duration;    const prop = this._prop;    const from = this._from;    const loop = this._loop;    const to = this._to;    let factor;    this._active = from !== to && (loop || (elapsed < duration));    if (!this._active) {      this._target[prop] = to;      this._notify(true);      return;    }    if (elapsed < 0) {      this._target[prop] = from;      return;    }    factor = (elapsed / duration) % 2;    factor = loop && factor > 1 ? 2 - factor : factor;    factor = this._easing(Math.min(1, Math.max(0, factor)));    this._target[prop] = this._fn(from, to, factor);  }  wait() {    const promises = this._promises || (this._promises = []);    return new Promise((res, rej) => {      promises.push({res, rej});    });  }  _notify(resolved) {    const method = resolved ? 'res' : 'rej';    const promises = this._promises || [];    for (let i = 0; i < promises.length; i++) {      promises[i][method]();    }  }}const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension'];const colors = ['color', 'borderColor', 'backgroundColor'];defaults.set('animation', {  delay: undefined,  duration: 1000,  easing: 'easeOutQuart',  fn: undefined,  from: undefined,  loop: undefined,  to: undefined,  type: undefined,});const animationOptions = Object.keys(defaults.animation);defaults.describe('animation', {  _fallback: false,  _indexable: false,  _scriptable: (name) => name !== 'onProgress' && name !== 'onComplete' && name !== 'fn',});defaults.set('animations', {  colors: {    type: 'color',    properties: colors  },  numbers: {    type: 'number',    properties: numbers  },});defaults.describe('animations', {  _fallback: 'animation',});defaults.set('transitions', {  active: {    animation: {      duration: 400    }  },  resize: {    animation: {      duration: 0    }  },  show: {    animations: {      colors: {        from: 'transparent'      },      visible: {        type: 'boolean',        duration: 0      },    }  },  hide: {    animations: {      colors: {        to: 'transparent'      },      visible: {        type: 'boolean',        easing: 'linear',        fn: v => v | 0      },    }  }});class Animations {  constructor(chart, config) {    this._chart = chart;    this._properties = new Map();    this.configure(config);  }  configure(config) {    if (!isObject(config)) {      return;    }    const animatedProps = this._properties;    Object.getOwnPropertyNames(config).forEach(key => {      const cfg = config[key];      if (!isObject(cfg)) {        return;      }      const resolved = {};      for (const option of animationOptions) {        resolved[option] = cfg[option];      }      (isArray(cfg.properties) && cfg.properties || [key]).forEach((prop) => {        if (prop === key || !animatedProps.has(prop)) {          animatedProps.set(prop, resolved);        }      });    });  }  _animateOptions(target, values) {    const newOptions = values.options;    const options = resolveTargetOptions(target, newOptions);    if (!options) {      return [];    }    const animations = this._createAnimations(options, newOptions);    if (newOptions.$shared) {      awaitAll(target.options.$animations, newOptions).then(() => {        target.options = newOptions;      }, () => {      });    }    return animations;  }  _createAnimations(target, values) {    const animatedProps = this._properties;    const animations = [];    const running = target.$animations || (target.$animations = {});    const props = Object.keys(values);    const date = Date.now();    let i;    for (i = props.length - 1; i >= 0; --i) {      const prop = props[i];      if (prop.charAt(0) === '$') {        continue;      }      if (prop === 'options') {        animations.push(...this._animateOptions(target, values));        continue;      }      const value = values[prop];      let animation = running[prop];      const cfg = animatedProps.get(prop);      if (animation) {        if (cfg && animation.active()) {          animation.update(cfg, value, date);          continue;        } else {          animation.cancel();        }      }      if (!cfg || !cfg.duration) {        target[prop] = value;        continue;      }      running[prop] = animation = new Animation(cfg, target, prop, value);      animations.push(animation);    }    return animations;  }  update(target, values) {    if (this._properties.size === 0) {      Object.assign(target, values);      return;    }    const animations = this._createAnimations(target, values);    if (animations.length) {      animator.add(this._chart, animations);      return true;    }  }}function awaitAll(animations, properties) {  const running = [];  const keys = Object.keys(properties);  for (let i = 0; i < keys.length; i++) {    const anim = animations[keys[i]];    if (anim && anim.active()) {      running.push(anim.wait());    }  }  return Promise.all(running);}function resolveTargetOptions(target, newOptions) {  if (!newOptions) {    return;  }  let options = target.options;  if (!options) {    target.options = newOptions;    return;  }  if (options.$shared) {    target.options = options = Object.assign({}, options, {$shared: false, $animations: {}});  }  return options;}function scaleClip(scale, allowedOverflow) {  const opts = scale && scale.options || {};  const reverse = opts.reverse;  const min = opts.min === undefined ? allowedOverflow : 0;  const max = opts.max === undefined ? allowedOverflow : 0;  return {    start: reverse ? max : min,    end: reverse ? min : max  };}function defaultClip(xScale, yScale, allowedOverflow) {  if (allowedOverflow === false) {    return false;  }  const x = scaleClip(xScale, allowedOverflow);  const y = scaleClip(yScale, allowedOverflow);  return {    top: y.end,    right: x.end,    bottom: y.start,    left: x.start  };}function toClip(value) {  let t, r, b, l;  if (isObject(value)) {    t = value.top;    r = value.right;    b = value.bottom;    l = value.left;  } else {    t = r = b = l = value;  }  return {    top: t,    right: r,    bottom: b,    left: l,    disabled: value === false  };}function getSortedDatasetIndices(chart, filterVisible) {  const keys = [];  const metasets = chart._getSortedDatasetMetas(filterVisible);  let i, ilen;  for (i = 0, ilen = metasets.length; i < ilen; ++i) {    keys.push(metasets[i].index);  }  return keys;}function applyStack(stack, value, dsIndex, options = {}) {  const keys = stack.keys;  const singleMode = options.mode === 'single';  let i, ilen, datasetIndex, otherValue;  if (value === null) {    return;  }  for (i = 0, ilen = keys.length; i < ilen; ++i) {    datasetIndex = +keys[i];    if (datasetIndex === dsIndex) {      if (options.all) {        continue;      }      break;    }    otherValue = stack.values[datasetIndex];    if (isNumberFinite(otherValue) && (singleMode || (value === 0 || sign(value) === sign(otherValue)))) {      value += otherValue;    }  }  return value;}function convertObjectDataToArray(data) {  const keys = Object.keys(data);  const adata = new Array(keys.length);  let i, ilen, key;  for (i = 0, ilen = keys.length; i < ilen; ++i) {    key = keys[i];    adata[i] = {      x: key,      y: data[key]    };  }  return adata;}function isStacked(scale, meta) {  const stacked = scale && scale.options.stacked;  return stacked || (stacked === undefined && meta.stack !== undefined);}function getStackKey(indexScale, valueScale, meta) {  return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;}function getUserBounds(scale) {  const {min, max, minDefined, maxDefined} = scale.getUserBounds();  return {    min: minDefined ? min : Number.NEGATIVE_INFINITY,    max: maxDefined ? max : Number.POSITIVE_INFINITY  };}function getOrCreateStack(stacks, stackKey, indexValue) {  const subStack = stacks[stackKey] || (stacks[stackKey] = {});  return subStack[indexValue] || (subStack[indexValue] = {});}function getLastIndexInStack(stack, vScale, positive, type) {  for (const meta of vScale.getMatchingVisibleMetas(type).reverse()) {    const value = stack[meta.index];    if ((positive && value > 0) || (!positive && value < 0)) {      return meta.index;    }  }  return null;}function updateStacks(controller, parsed) {  const {chart, _cachedMeta: meta} = controller;  const stacks = chart._stacks || (chart._stacks = {});  const {iScale, vScale, index: datasetIndex} = meta;  const iAxis = iScale.axis;  const vAxis = vScale.axis;  const key = getStackKey(iScale, vScale, meta);  const ilen = parsed.length;  let stack;  for (let i = 0; i < ilen; ++i) {    const item = parsed[i];    const {[iAxis]: index, [vAxis]: value} = item;    const itemStacks = item._stacks || (item._stacks = {});    stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);    stack[datasetIndex] = value;    stack._top = getLastIndexInStack(stack, vScale, true, meta.type);    stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type);  }}function getFirstScaleId(chart, axis) {  const scales = chart.scales;  return Object.keys(scales).filter(key => scales[key].axis === axis).shift();}function createDatasetContext(parent, index) {  return createContext(parent,    {      active: false,      dataset: undefined,      datasetIndex: index,      index,      mode: 'default',      type: 'dataset'    }  );}function createDataContext(parent, index, element) {  return createContext(parent, {    active: false,    dataIndex: index,    parsed: undefined,    raw: undefined,    element,    index,    mode: 'default',    type: 'data'  });}function clearStacks(meta, items) {  const datasetIndex = meta.controller.index;  const axis = meta.vScale && meta.vScale.axis;  if (!axis) {    return;  }  items = items || meta._parsed;  for (const parsed of items) {    const stacks = parsed._stacks;    if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) {      return;    }    delete stacks[axis][datasetIndex];  }}const isDirectUpdateMode = (mode) => mode === 'reset' || mode === 'none';const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached);const createStack = (canStack, meta, chart) => canStack && !meta.hidden && meta._stacked  && {keys: getSortedDatasetIndices(chart, true), values: null};class DatasetController {  constructor(chart, datasetIndex) {    this.chart = chart;    this._ctx = chart.ctx;    this.index = datasetIndex;    this._cachedDataOpts = {};    this._cachedMeta = this.getMeta();    this._type = this._cachedMeta.type;    this.options = undefined;    this._parsing = false;    this._data = undefined;    this._objectData = undefined;    this._sharedOptions = undefined;    this._drawStart = undefined;    this._drawCount = undefined;    this.enableOptionSharing = false;    this.$context = undefined;    this._syncList = [];    this.initialize();  }  initialize() {    const meta = this._cachedMeta;    this.configure();    this.linkScales();    meta._stacked = isStacked(meta.vScale, meta);    this.addElements();  }  updateIndex(datasetIndex) {    if (this.index !== datasetIndex) {      clearStacks(this._cachedMeta);    }    this.index = datasetIndex;  }  linkScales() {    const chart = this.chart;    const meta = this._cachedMeta;    const dataset = this.getDataset();    const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y;    const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x'));    const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y'));    const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r'));    const indexAxis = meta.indexAxis;    const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);    const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);    meta.xScale = this.getScaleForId(xid);    meta.yScale = this.getScaleForId(yid);    meta.rScale = this.getScaleForId(rid);    meta.iScale = this.getScaleForId(iid);    meta.vScale = this.getScaleForId(vid);  }  getDataset() {    return this.chart.data.datasets[this.index];  }  getMeta() {    return this.chart.getDatasetMeta(this.index);  }  getScaleForId(scaleID) {    return this.chart.scales[scaleID];  }  _getOtherScale(scale) {    const meta = this._cachedMeta;    return scale === meta.iScale      ? meta.vScale      : meta.iScale;  }  reset() {    this._update('reset');  }  _destroy() {    const meta = this._cachedMeta;    if (this._data) {      unlistenArrayEvents(this._data, this);    }    if (meta._stacked) {      clearStacks(meta);    }  }  _dataCheck() {    const dataset = this.getDataset();    const data = dataset.data || (dataset.data = []);    const _data = this._data;    if (isObject(data)) {      this._data = convertObjectDataToArray(data);    } else if (_data !== data) {      if (_data) {        unlistenArrayEvents(_data, this);        const meta = this._cachedMeta;        clearStacks(meta);        meta._parsed = [];      }      if (data && Object.isExtensible(data)) {        listenArrayEvents(data, this);      }      this._syncList = [];      this._data = data;    }  }  addElements() {    const meta = this._cachedMeta;    this._dataCheck();    if (this.datasetElementType) {      meta.dataset = new this.datasetElementType();    }  }  buildOrUpdateElements(resetNewElements) {    const meta = this._cachedMeta;    const dataset = this.getDataset();    let stackChanged = false;    this._dataCheck();    const oldStacked = meta._stacked;    meta._stacked = isStacked(meta.vScale, meta);    if (meta.stack !== dataset.stack) {      stackChanged = true;      clearStacks(meta);      meta.stack = dataset.stack;    }    this._resyncElements(resetNewElements);    if (stackChanged || oldStacked !== meta._stacked) {      updateStacks(this, meta._parsed);    }  }  configure() {    const config = this.chart.config;    const scopeKeys = config.datasetScopeKeys(this._type);    const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);    this.options = config.createResolver(scopes, this.getContext());    this._parsing = this.options.parsing;    this._cachedDataOpts = {};  }  parse(start, count) {    const {_cachedMeta: meta, _data: data} = this;    const {iScale, _stacked} = meta;    const iAxis = iScale.axis;    let sorted = start === 0 && count === data.length ? true : meta._sorted;    let prev = start > 0 && meta._parsed[start - 1];    let i, cur, parsed;    if (this._parsing === false) {      meta._parsed = data;      meta._sorted = true;      parsed = data;    } else {      if (isArray(data[start])) {        parsed = this.parseArrayData(meta, data, start, count);      } else if (isObject(data[start])) {        parsed = this.parseObjectData(meta, data, start, count);      } else {        parsed = this.parsePrimitiveData(meta, data, start, count);      }      const isNotInOrderComparedToPrev = () => cur[iAxis] === null || (prev && cur[iAxis] < prev[iAxis]);      for (i = 0; i < count; ++i) {        meta._parsed[i + start] = cur = parsed[i];        if (sorted) {          if (isNotInOrderComparedToPrev()) {            sorted = false;          }          prev = cur;        }      }      meta._sorted = sorted;    }    if (_stacked) {      updateStacks(this, parsed);    }  }  parsePrimitiveData(meta, data, start, count) {    const {iScale, vScale} = meta;    const iAxis = iScale.axis;    const vAxis = vScale.axis;    const labels = iScale.getLabels();    const singleScale = iScale === vScale;    const parsed = new Array(count);    let i, ilen, index;    for (i = 0, ilen = count; i < ilen; ++i) {      index = i + start;      parsed[i] = {        [iAxis]: singleScale || iScale.parse(labels[index], index),        [vAxis]: vScale.parse(data[index], index)      };    }    return parsed;  }  parseArrayData(meta, data, start, count) {    const {xScale, yScale} = meta;    const parsed = new Array(count);    let i, ilen, index, item;    for (i = 0, ilen = count; i < ilen; ++i) {      index = i + start;      item = data[index];      parsed[i] = {        x: xScale.parse(item[0], index),        y: yScale.parse(item[1], index)      };    }    return parsed;  }  parseObjectData(meta, data, start, count) {    const {xScale, yScale} = meta;    const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;    const parsed = new Array(count);    let i, ilen, index, item;    for (i = 0, ilen = count; i < ilen; ++i) {      index = i + start;      item = data[index];      parsed[i] = {        x: xScale.parse(resolveObjectKey(item, xAxisKey), index),        y: yScale.parse(resolveObjectKey(item, yAxisKey), index)      };    }    return parsed;  }  getParsed(index) {    return this._cachedMeta._parsed[index];  }  getDataElement(index) {    return this._cachedMeta.data[index];  }  applyStack(scale, parsed, mode) {    const chart = this.chart;    const meta = this._cachedMeta;    const value = parsed[scale.axis];    const stack = {      keys: getSortedDatasetIndices(chart, true),      values: parsed._stacks[scale.axis]    };    return applyStack(stack, value, meta.index, {mode});  }  updateRangeFromParsed(range, scale, parsed, stack) {    const parsedValue = parsed[scale.axis];    let value = parsedValue === null ? NaN : parsedValue;    const values = stack && parsed._stacks[scale.axis];    if (stack && values) {      stack.values = values;      value = applyStack(stack, parsedValue, this._cachedMeta.index);    }    range.min = Math.min(range.min, value);    range.max = Math.max(range.max, value);  }  getMinMax(scale, canStack) {    const meta = this._cachedMeta;    const _parsed = meta._parsed;    const sorted = meta._sorted && scale === meta.iScale;    const ilen = _parsed.length;    const otherScale = this._getOtherScale(scale);    const stack = createStack(canStack, meta, this.chart);    const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY};    const {min: otherMin, max: otherMax} = getUserBounds(otherScale);    let i, parsed;    function _skip() {      parsed = _parsed[i];      const otherValue = parsed[otherScale.axis];      return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue;    }    for (i = 0; i < ilen; ++i) {      if (_skip()) {        continue;      }      this.updateRangeFromParsed(range, scale, parsed, stack);      if (sorted) {        break;      }    }    if (sorted) {      for (i = ilen - 1; i >= 0; --i) {        if (_skip()) {          continue;        }        this.updateRangeFromParsed(range, scale, parsed, stack);        break;      }    }    return range;  }  getAllParsedValues(scale) {    const parsed = this._cachedMeta._parsed;    const values = [];    let i, ilen, value;    for (i = 0, ilen = parsed.length; i < ilen; ++i) {      value = parsed[i][scale.axis];      if (isNumberFinite(value)) {        values.push(value);      }    }    return values;  }  getMaxOverflow() {    return false;  }  getLabelAndValue(index) {    const meta = this._cachedMeta;    const iScale = meta.iScale;    const vScale = meta.vScale;    const parsed = this.getParsed(index);    return {      label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',      value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''    };  }  _update(mode) {    const meta = this._cachedMeta;    this.update(mode || 'default');    meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));  }  update(mode) {}  draw() {    const ctx = this._ctx;    const chart = this.chart;    const meta = this._cachedMeta;    const elements = meta.data || [];    const area = chart.chartArea;    const active = [];    const start = this._drawStart || 0;    const count = this._drawCount || (elements.length - start);    const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;    let i;    if (meta.dataset) {      meta.dataset.draw(ctx, area, start, count);    }    for (i = start; i < start + count; ++i) {      const element = elements[i];      if (element.hidden) {        continue;      }      if (element.active && drawActiveElementsOnTop) {        active.push(element);      } else {        element.draw(ctx, area);      }    }    for (i = 0; i < active.length; ++i) {      active[i].draw(ctx, area);    }  }  getStyle(index, active) {    const mode = active ? 'active' : 'default';    return index === undefined && this._cachedMeta.dataset      ? this.resolveDatasetElementOptions(mode)      : this.resolveDataElementOptions(index || 0, mode);  }  getContext(index, active, mode) {    const dataset = this.getDataset();    let context;    if (index >= 0 && index < this._cachedMeta.data.length) {      const element = this._cachedMeta.data[index];      context = element.$context ||        (element.$context = createDataContext(this.getContext(), index, element));      context.parsed = this.getParsed(index);      context.raw = dataset.data[index];      context.index = context.dataIndex = index;    } else {      context = this.$context ||        (this.$context = createDatasetContext(this.chart.getContext(), this.index));      context.dataset = dataset;      context.index = context.datasetIndex = this.index;    }    context.active = !!active;    context.mode = mode;    return context;  }  resolveDatasetElementOptions(mode) {    return this._resolveElementOptions(this.datasetElementType.id, mode);  }  resolveDataElementOptions(index, mode) {    return this._resolveElementOptions(this.dataElementType.id, mode, index);  }  _resolveElementOptions(elementType, mode = 'default', index) {    const active = mode === 'active';    const cache = this._cachedDataOpts;    const cacheKey = elementType + '-' + mode;    const cached = cache[cacheKey];    const sharing = this.enableOptionSharing && defined(index);    if (cached) {      return cloneIfNotShared(cached, sharing);    }    const config = this.chart.config;    const scopeKeys = config.datasetElementScopeKeys(this._type, elementType);    const prefixes = active ? [`${elementType}Hover`, 'hover', elementType, ''] : [elementType, ''];    const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);    const names = Object.keys(defaults.elements[elementType]);    const context = () => this.getContext(index, active);    const values = config.resolveNamedOptions(scopes, names, context, prefixes);    if (values.$shared) {      values.$shared = sharing;      cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing));    }    return values;  }  _resolveAnimations(index, transition, active) {    const chart = this.chart;    const cache = this._cachedDataOpts;    const cacheKey = `animation-${transition}`;    const cached = cache[cacheKey];    if (cached) {      return cached;    }    let options;    if (chart.options.animation !== false) {      const config = this.chart.config;      const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition);      const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);      options = config.createResolver(scopes, this.getContext(index, active, transition));    }    const animations = new Animations(chart, options && options.animations);    if (options && options._cacheable) {      cache[cacheKey] = Object.freeze(animations);    }    return animations;  }  getSharedOptions(options) {    if (!options.$shared) {      return;    }    return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));  }  includeOptions(mode, sharedOptions) {    return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;  }  updateElement(element, index, properties, mode) {    if (isDirectUpdateMode(mode)) {      Object.assign(element, properties);    } else {      this._resolveAnimations(index, mode).update(element, properties);    }  }  updateSharedOptions(sharedOptions, mode, newOptions) {    if (sharedOptions && !isDirectUpdateMode(mode)) {      this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions);    }  }  _setStyle(element, index, mode, active) {    element.active = active;    const options = this.getStyle(index, active);    this._resolveAnimations(index, mode, active).update(element, {      options: (!active && this.getSharedOptions(options)) || options    });  }  removeHoverStyle(element, datasetIndex, index) {    this._setStyle(element, index, 'active', false);  }  setHoverStyle(element, datasetIndex, index) {    this._setStyle(element, index, 'active', true);  }  _removeDatasetHoverStyle() {    const element = this._cachedMeta.dataset;    if (element) {      this._setStyle(element, undefined, 'active', false);    }  }  _setDatasetHoverStyle() {    const element = this._cachedMeta.dataset;    if (element) {      this._setStyle(element, undefined, 'active', true);    }  }  _resyncElements(resetNewElements) {    const data = this._data;    const elements = this._cachedMeta.data;    for (const [method, arg1, arg2] of this._syncList) {      this[method](arg1, arg2);    }    this._syncList = [];    const numMeta = elements.length;    const numData = data.length;    const count = Math.min(numData, numMeta);    if (count) {      this.parse(0, count);    }    if (numData > numMeta) {      this._insertElements(numMeta, numData - numMeta, resetNewElements);    } else if (numData < numMeta) {      this._removeElements(numData, numMeta - numData);    }  }  _insertElements(start, count, resetNewElements = true) {    const meta = this._cachedMeta;    const data = meta.data;    const end = start + count;    let i;    const move = (arr) => {      arr.length += count;      for (i = arr.length - 1; i >= end; i--) {        arr[i] = arr[i - count];      }    };    move(data);    for (i = start; i < end; ++i) {      data[i] = new this.dataElementType();    }    if (this._parsing) {      move(meta._parsed);    }    this.parse(start, count);    if (resetNewElements) {      this.updateElements(data, start, count, 'reset');    }  }  updateElements(element, start, count, mode) {}  _removeElements(start, count) {    const meta = this._cachedMeta;    if (this._parsing) {      const removed = meta._parsed.splice(start, count);      if (meta._stacked) {        clearStacks(meta, removed);      }    }    meta.data.splice(start, count);  }  _sync(args) {    if (this._parsing) {      this._syncList.push(args);    } else {      const [method, arg1, arg2] = args;      this[method](arg1, arg2);    }    this.chart._dataChanges.push([this.index, ...args]);  }  _onDataPush() {    const count = arguments.length;    this._sync(['_insertElements', this.getDataset().data.length - count, count]);  }  _onDataPop() {    this._sync(['_removeElements', this._cachedMeta.data.length - 1, 1]);  }  _onDataShift() {    this._sync(['_removeElements', 0, 1]);  }  _onDataSplice(start, count) {    if (count) {      this._sync(['_removeElements', start, count]);    }    const newCount = arguments.length - 2;    if (newCount) {      this._sync(['_insertElements', start, newCount]);    }  }  _onDataUnshift() {    this._sync(['_insertElements', 0, arguments.length]);  }}DatasetController.defaults = {};DatasetController.prototype.datasetElementType = null;DatasetController.prototype.dataElementType = null;class Element {  constructor() {    this.x = undefined;    this.y = undefined;    this.active = false;    this.options = undefined;    this.$animations = undefined;  }  tooltipPosition(useFinalPosition) {    const {x, y} = this.getProps(['x', 'y'], useFinalPosition);    return {x, y};  }  hasValue() {    return isNumber(this.x) && isNumber(this.y);  }  getProps(props, final) {    const anims = this.$animations;    if (!final || !anims) {      return this;    }    const ret = {};    props.forEach(prop => {      ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop];    });    return ret;  }}Element.defaults = {};Element.defaultRoutes = undefined;const formatters = {  values(value) {    return isArray(value) ? value : '' + value;  },  numeric(tickValue, index, ticks) {    if (tickValue === 0) {      return '0';    }    const locale = this.chart.options.locale;    let notation;    let delta = tickValue;    if (ticks.length > 1) {      const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));      if (maxTick < 1e-4 || maxTick > 1e+15) {        notation = 'scientific';      }      delta = calculateDelta(tickValue, ticks);    }    const logDelta = log10(Math.abs(delta));    const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0);    const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal};    Object.assign(options, this.options.ticks.format);    return formatNumber(tickValue, locale, options);  },  logarithmic(tickValue, index, ticks) {    if (tickValue === 0) {      return '0';    }    const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue))));    if (remain === 1 || remain === 2 || remain === 5) {      return formatters.numeric.call(this, tickValue, index, ticks);    }    return '';  }};function calculateDelta(tickValue, ticks) {  let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;  if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) {    delta = tickValue - Math.floor(tickValue);  }  return delta;}var Ticks = {formatters};defaults.set('scale', {  display: true,  offset: false,  reverse: false,  beginAtZero: false,  bounds: 'ticks',  grace: 0,  grid: {    display: true,    lineWidth: 1,    drawBorder: true,    drawOnChartArea: true,    drawTicks: true,    tickLength: 8,    tickWidth: (_ctx, options) => options.lineWidth,    tickColor: (_ctx, options) => options.color,    offset: false,    borderDash: [],    borderDashOffset: 0.0,    borderWidth: 1  },  title: {    display: false,    text: '',    padding: {      top: 4,      bottom: 4    }  },  ticks: {    minRotation: 0,    maxRotation: 50,    mirror: false,    textStrokeWidth: 0,    textStrokeColor: '',    padding: 3,    display: true,    autoSkip: true,    autoSkipPadding: 3,    labelOffset: 0,    callback: Ticks.formatters.values,    minor: {},    major: {},    align: 'center',    crossAlign: 'near',    showLabelBackdrop: false,    backdropColor: 'rgba(255, 255, 255, 0.75)',    backdropPadding: 2,  }});defaults.route('scale.ticks', 'color', '', 'color');defaults.route('scale.grid', 'color', '', 'borderColor');defaults.route('scale.grid', 'borderColor', '', 'borderColor');defaults.route('scale.title', 'color', '', 'color');defaults.describe('scale', {  _fallback: false,  _scriptable: (name) => !name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser',  _indexable: (name) => name !== 'borderDash' && name !== 'tickBorderDash',});defaults.describe('scales', {  _fallback: 'scale',});defaults.describe('scale.ticks', {  _scriptable: (name) => name !== 'backdropPadding' && name !== 'callback',  _indexable: (name) => name !== 'backdropPadding',});function autoSkip(scale, ticks) {  const tickOpts = scale.options.ticks;  const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(scale);  const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];  const numMajorIndices = majorIndices.length;  const first = majorIndices[0];  const last = majorIndices[numMajorIndices - 1];  const newTicks = [];  if (numMajorIndices > ticksLimit) {    skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);    return newTicks;  }  const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);  if (numMajorIndices > 0) {    let i, ilen;    const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;    skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);    for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {      skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);    }    skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);    return newTicks;  }  skip(ticks, newTicks, spacing);  return newTicks;}function determineMaxTicks(scale) {  const offset = scale.options.offset;  const tickLength = scale._tickSize();  const maxScale = scale._length / tickLength + (offset ? 0 : 1);  const maxChart = scale._maxLength / tickLength;  return Math.floor(Math.min(maxScale, maxChart));}function calculateSpacing(majorIndices, ticks, ticksLimit) {  const evenMajorSpacing = getEvenSpacing(majorIndices);  const spacing = ticks.length / ticksLimit;  if (!evenMajorSpacing) {    return Math.max(spacing, 1);  }  const factors = _factorize(evenMajorSpacing);  for (let i = 0, ilen = factors.length - 1; i < ilen; i++) {    const factor = factors[i];    if (factor > spacing) {      return factor;    }  }  return Math.max(spacing, 1);}function getMajorIndices(ticks) {  const result = [];  let i, ilen;  for (i = 0, ilen = ticks.length; i < ilen; i++) {    if (ticks[i].major) {      result.push(i);    }  }  return result;}function skipMajors(ticks, newTicks, majorIndices, spacing) {  let count = 0;  let next = majorIndices[0];  let i;  spacing = Math.ceil(spacing);  for (i = 0; i < ticks.length; i++) {    if (i === next) {      newTicks.push(ticks[i]);      count++;      next = majorIndices[count * spacing];    }  }}function skip(ticks, newTicks, spacing, majorStart, majorEnd) {  const start = valueOrDefault(majorStart, 0);  const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);  let count = 0;  let length, i, next;  spacing = Math.ceil(spacing);  if (majorEnd) {    length = majorEnd - majorStart;    spacing = length / Math.floor(length / spacing);  }  next = start;  while (next < 0) {    count++;    next = Math.round(start + count * spacing);  }  for (i = Math.max(start, 0); i < end; i++) {    if (i === next) {      newTicks.push(ticks[i]);      count++;      next = Math.round(start + count * spacing);    }  }}function getEvenSpacing(arr) {  const len = arr.length;  let i, diff;  if (len < 2) {    return false;  }  for (diff = arr[0], i = 1; i < len; ++i) {    if (arr[i] - arr[i - 1] !== diff) {      return false;    }  }  return diff;}const reverseAlign = (align) => align === 'left' ? 'right' : align === 'right' ? 'left' : align;const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset;function sample(arr, numItems) {  const result = [];  const increment = arr.length / numItems;  const len = arr.length;  let i = 0;  for (; i < len; i += increment) {    result.push(arr[Math.floor(i)]);  }  return result;}function getPixelForGridLine(scale, index, offsetGridLines) {  const length = scale.ticks.length;  const validIndex = Math.min(index, length - 1);  const start = scale._startPixel;  const end = scale._endPixel;  const epsilon = 1e-6;  let lineValue = scale.getPixelForTick(validIndex);  let offset;  if (offsetGridLines) {    if (length === 1) {      offset = Math.max(lineValue - start, end - lineValue);    } else if (index === 0) {      offset = (scale.getPixelForTick(1) - lineValue) / 2;    } else {      offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;    }    lineValue += validIndex < index ? offset : -offset;    if (lineValue < start - epsilon || lineValue > end + epsilon) {      return;    }  }  return lineValue;}function garbageCollect(caches, length) {  each(caches, (cache) => {    const gc = cache.gc;    const gcLen = gc.length / 2;    let i;    if (gcLen > length) {      for (i = 0; i < gcLen; ++i) {        delete cache.data[gc[i]];      }      gc.splice(0, gcLen);    }  });}function getTickMarkLength(options) {  return options.drawTicks ? options.tickLength : 0;}function getTitleHeight(options, fallback) {  if (!options.display) {    return 0;  }  const font = toFont(options.font, fallback);  const padding = toPadding(options.padding);  const lines = isArray(options.text) ? options.text.length : 1;  return (lines * font.lineHeight) + padding.height;}function createScaleContext(parent, scale) {  return createContext(parent, {    scale,    type: 'scale'  });}function createTickContext(parent, index, tick) {  return createContext(parent, {    tick,    index,    type: 'tick'  });}function titleAlign(align, position, reverse) {  let ret = _toLeftRightCenter(align);  if ((reverse && position !== 'right') || (!reverse && position === 'right')) {    ret = reverseAlign(ret);  }  return ret;}function titleArgs(scale, offset, position, align) {  const {top, left, bottom, right, chart} = scale;  const {chartArea, scales} = chart;  let rotation = 0;  let maxWidth, titleX, titleY;  const height = bottom - top;  const width = right - left;  if (scale.isHorizontal()) {    titleX = _alignStartEnd(align, left, right);    if (isObject(position)) {      const positionAxisID = Object.keys(position)[0];      const value = position[positionAxisID];      titleY = scales[positionAxisID].getPixelForValue(value) + height - offset;    } else if (position === 'center') {      titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset;    } else {      titleY = offsetFromEdge(scale, position, offset);    }    maxWidth = right - left;  } else {    if (isObject(position)) {      const positionAxisID = Object.keys(position)[0];      const value = position[positionAxisID];      titleX = scales[positionAxisID].getPixelForValue(value) - width + offset;    } else if (position === 'center') {      titleX = (chartArea.left + chartArea.right) / 2 - width + offset;    } else {      titleX = offsetFromEdge(scale, position, offset);    }    titleY = _alignStartEnd(align, bottom, top);    rotation = position === 'left' ? -HALF_PI : HALF_PI;  }  return {titleX, titleY, maxWidth, rotation};}class Scale extends Element {  constructor(cfg) {    super();    this.id = cfg.id;    this.type = cfg.type;    this.options = undefined;    this.ctx = cfg.ctx;    this.chart = cfg.chart;    this.top = undefined;    this.bottom = undefined;    this.left = undefined;    this.right = undefined;    this.width = undefined;    this.height = undefined;    this._margins = {      left: 0,      right: 0,      top: 0,      bottom: 0    };    this.maxWidth = undefined;    this.maxHeight = undefined;    this.paddingTop = undefined;    this.paddingBottom = undefined;    this.paddingLeft = undefined;    this.paddingRight = undefined;    this.axis = undefined;    this.labelRotation = undefined;    this.min = undefined;    this.max = undefined;    this._range = undefined;    this.ticks = [];    this._gridLineItems = null;    this._labelItems = null;    this._labelSizes = null;    this._length = 0;    this._maxLength = 0;    this._longestTextCache = {};    this._startPixel = undefined;    this._endPixel = undefined;    this._reversePixels = false;    this._userMax = undefined;    this._userMin = undefined;    this._suggestedMax = undefined;    this._suggestedMin = undefined;    this._ticksLength = 0;    this._borderValue = 0;    this._cache = {};    this._dataLimitsCached = false;    this.$context = undefined;  }  init(options) {    this.options = options.setContext(this.getContext());    this.axis = options.axis;    this._userMin = this.parse(options.min);    this._userMax = this.parse(options.max);    this._suggestedMin = this.parse(options.suggestedMin);    this._suggestedMax = this.parse(options.suggestedMax);  }  parse(raw, index) {    return raw;  }  getUserBounds() {    let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this;    _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY);    _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY);    _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY);    _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY);    return {      min: finiteOrDefault(_userMin, _suggestedMin),      max: finiteOrDefault(_userMax, _suggestedMax),      minDefined: isNumberFinite(_userMin),      maxDefined: isNumberFinite(_userMax)    };  }  getMinMax(canStack) {    let {min, max, minDefined, maxDefined} = this.getUserBounds();    let range;    if (minDefined && maxDefined) {      return {min, max};    }    const metas = this.getMatchingVisibleMetas();    for (let i = 0, ilen = metas.length; i < ilen; ++i) {      range = metas[i].controller.getMinMax(this, canStack);      if (!minDefined) {        min = Math.min(min, range.min);      }      if (!maxDefined) {        max = Math.max(max, range.max);      }    }    min = maxDefined && min > max ? max : min;    max = minDefined && min > max ? min : max;    return {      min: finiteOrDefault(min, finiteOrDefault(max, min)),      max: finiteOrDefault(max, finiteOrDefault(min, max))    };  }  getPadding() {    return {      left: this.paddingLeft || 0,      top: this.paddingTop || 0,      right: this.paddingRight || 0,      bottom: this.paddingBottom || 0    };  }  getTicks() {    return this.ticks;  }  getLabels() {    const data = this.chart.data;    return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];  }  beforeLayout() {    this._cache = {};    this._dataLimitsCached = false;  }  beforeUpdate() {    callback(this.options.beforeUpdate, [this]);  }  update(maxWidth, maxHeight, margins) {    const {beginAtZero, grace, ticks: tickOpts} = this.options;    const sampleSize = tickOpts.sampleSize;    this.beforeUpdate();    this.maxWidth = maxWidth;    this.maxHeight = maxHeight;    this._margins = margins = Object.assign({      left: 0,      right: 0,      top: 0,      bottom: 0    }, margins);    this.ticks = null;    this._labelSizes = null;    this._gridLineItems = null;    this._labelItems = null;    this.beforeSetDimensions();    this.setDimensions();    this.afterSetDimensions();    this._maxLength = this.isHorizontal()      ? this.width + margins.left + margins.right      : this.height + margins.top + margins.bottom;    if (!this._dataLimitsCached) {      this.beforeDataLimits();      this.determineDataLimits();      this.afterDataLimits();      this._range = _addGrace(this, grace, beginAtZero);      this._dataLimitsCached = true;    }    this.beforeBuildTicks();    this.ticks = this.buildTicks() || [];    this.afterBuildTicks();    const samplingEnabled = sampleSize < this.ticks.length;    this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks);    this.configure();    this.beforeCalculateLabelRotation();    this.calculateLabelRotation();    this.afterCalculateLabelRotation();    if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {      this.ticks = autoSkip(this, this.ticks);      this._labelSizes = null;    }    if (samplingEnabled) {      this._convertTicksToLabels(this.ticks);    }    this.beforeFit();    this.fit();    this.afterFit();    this.afterUpdate();  }  configure() {    let reversePixels = this.options.reverse;    let startPixel, endPixel;    if (this.isHorizontal()) {      startPixel = this.left;      endPixel = this.right;    } else {      startPixel = this.top;      endPixel = this.bottom;      reversePixels = !reversePixels;    }    this._startPixel = startPixel;    this._endPixel = endPixel;    this._reversePixels = reversePixels;    this._length = endPixel - startPixel;    this._alignToPixels = this.options.alignToPixels;  }  afterUpdate() {    callback(this.options.afterUpdate, [this]);  }  beforeSetDimensions() {    callback(this.options.beforeSetDimensions, [this]);  }  setDimensions() {    if (this.isHorizontal()) {      this.width = this.maxWidth;      this.left = 0;      this.right = this.width;    } else {      this.height = this.maxHeight;      this.top = 0;      this.bottom = this.height;    }    this.paddingLeft = 0;    this.paddingTop = 0;    this.paddingRight = 0;    this.paddingBottom = 0;  }  afterSetDimensions() {    callback(this.options.afterSetDimensions, [this]);  }  _callHooks(name) {    this.chart.notifyPlugins(name, this.getContext());    callback(this.options[name], [this]);  }  beforeDataLimits() {    this._callHooks('beforeDataLimits');  }  determineDataLimits() {}  afterDataLimits() {    this._callHooks('afterDataLimits');  }  beforeBuildTicks() {    this._callHooks('beforeBuildTicks');  }  buildTicks() {    return [];  }  afterBuildTicks() {    this._callHooks('afterBuildTicks');  }  beforeTickToLabelConversion() {    callback(this.options.beforeTickToLabelConversion, [this]);  }  generateTickLabels(ticks) {    const tickOpts = this.options.ticks;    let i, ilen, tick;    for (i = 0, ilen = ticks.length; i < ilen; i++) {      tick = ticks[i];      tick.label = callback(tickOpts.callback, [tick.value, i, ticks], this);    }  }  afterTickToLabelConversion() {    callback(this.options.afterTickToLabelConversion, [this]);  }  beforeCalculateLabelRotation() {    callback(this.options.beforeCalculateLabelRotation, [this]);  }  calculateLabelRotation() {    const options = this.options;    const tickOpts = options.ticks;    const numTicks = this.ticks.length;    const minRotation = tickOpts.minRotation || 0;    const maxRotation = tickOpts.maxRotation;    let labelRotation = minRotation;    let tickWidth, maxHeight, maxLabelDiagonal;    if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) {      this.labelRotation = minRotation;      return;    }    const labelSizes = this._getLabelSizes();    const maxLabelWidth = labelSizes.widest.width;    const maxLabelHeight = labelSizes.highest.height;    const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth);    tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1);    if (maxLabelWidth + 6 > tickWidth) {      tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));      maxHeight = this.maxHeight - getTickMarkLength(options.grid)				- tickOpts.padding - getTitleHeight(options.title, this.chart.options.font);      maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);      labelRotation = toDegrees(Math.min(        Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)),        Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1))      ));      labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));    }    this.labelRotation = labelRotation;  }  afterCalculateLabelRotation() {    callback(this.options.afterCalculateLabelRotation, [this]);  }  beforeFit() {    callback(this.options.beforeFit, [this]);  }  fit() {    const minSize = {      width: 0,      height: 0    };    const {chart, options: {ticks: tickOpts, title: titleOpts, grid: gridOpts}} = this;    const display = this._isVisible();    const isHorizontal = this.isHorizontal();    if (display) {      const titleHeight = getTitleHeight(titleOpts, chart.options.font);      if (isHorizontal) {        minSize.width = this.maxWidth;        minSize.height = getTickMarkLength(gridOpts) + titleHeight;      } else {        minSize.height = this.maxHeight;        minSize.width = getTickMarkLength(gridOpts) + titleHeight;      }      if (tickOpts.display && this.ticks.length) {        const {first, last, widest, highest} = this._getLabelSizes();        const tickPadding = tickOpts.padding * 2;        const angleRadians = toRadians(this.labelRotation);        const cos = Math.cos(angleRadians);        const sin = Math.sin(angleRadians);        if (isHorizontal) {          const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height;          minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding);        } else {          const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height;          minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding);        }        this._calculatePadding(first, last, sin, cos);      }    }    this._handleMargins();    if (isHorizontal) {      this.width = this._length = chart.width - this._margins.left - this._margins.right;      this.height = minSize.height;    } else {      this.width = minSize.width;      this.height = this._length = chart.height - this._margins.top - this._margins.bottom;    }  }  _calculatePadding(first, last, sin, cos) {    const {ticks: {align, padding}, position} = this.options;    const isRotated = this.labelRotation !== 0;    const labelsBelowTicks = position !== 'top' && this.axis === 'x';    if (this.isHorizontal()) {      const offsetLeft = this.getPixelForTick(0) - this.left;      const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1);      let paddingLeft = 0;      let paddingRight = 0;      if (isRotated) {        if (labelsBelowTicks) {          paddingLeft = cos * first.width;          paddingRight = sin * last.height;        } else {          paddingLeft = sin * first.height;          paddingRight = cos * last.width;        }      } else if (align === 'start') {        paddingRight = last.width;      } else if (align === 'end') {        paddingLeft = first.width;      } else {        paddingLeft = first.width / 2;        paddingRight = last.width / 2;      }      this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0);      this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0);    } else {      let paddingTop = last.height / 2;      let paddingBottom = first.height / 2;      if (align === 'start') {        paddingTop = 0;        paddingBottom = first.height;      } else if (align === 'end') {        paddingTop = last.height;        paddingBottom = 0;      }      this.paddingTop = paddingTop + padding;      this.paddingBottom = paddingBottom + padding;    }  }  _handleMargins() {    if (this._margins) {      this._margins.left = Math.max(this.paddingLeft, this._margins.left);      this._margins.top = Math.max(this.paddingTop, this._margins.top);      this._margins.right = Math.max(this.paddingRight, this._margins.right);      this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom);    }  }  afterFit() {    callback(this.options.afterFit, [this]);  }  isHorizontal() {    const {axis, position} = this.options;    return position === 'top' || position === 'bottom' || axis === 'x';  }  isFullSize() {    return this.options.fullSize;  }  _convertTicksToLabels(ticks) {    this.beforeTickToLabelConversion();    this.generateTickLabels(ticks);    let i, ilen;    for (i = 0, ilen = ticks.length; i < ilen; i++) {      if (isNullOrUndef(ticks[i].label)) {        ticks.splice(i, 1);        ilen--;        i--;      }    }    this.afterTickToLabelConversion();  }  _getLabelSizes() {    let labelSizes = this._labelSizes;    if (!labelSizes) {      const sampleSize = this.options.ticks.sampleSize;      let ticks = this.ticks;      if (sampleSize < ticks.length) {        ticks = sample(ticks, sampleSize);      }      this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length);    }    return labelSizes;  }  _computeLabelSizes(ticks, length) {    const {ctx, _longestTextCache: caches} = this;    const widths = [];    const heights = [];    let widestLabelSize = 0;    let highestLabelSize = 0;    let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;    for (i = 0; i < length; ++i) {      label = ticks[i].label;      tickFont = this._resolveTickFontOptions(i);      ctx.font = fontString = tickFont.string;      cache = caches[fontString] = caches[fontString] || {data: {}, gc: []};      lineHeight = tickFont.lineHeight;      width = height = 0;      if (!isNullOrUndef(label) && !isArray(label)) {        width = _measureText(ctx, cache.data, cache.gc, width, label);        height = lineHeight;      } else if (isArray(label)) {        for (j = 0, jlen = label.length; j < jlen; ++j) {          nestedLabel = label[j];          if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {            width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel);            height += lineHeight;          }        }      }      widths.push(width);      heights.push(height);      widestLabelSize = Math.max(width, widestLabelSize);      highestLabelSize = Math.max(height, highestLabelSize);    }    garbageCollect(caches, length);    const widest = widths.indexOf(widestLabelSize);    const highest = heights.indexOf(highestLabelSize);    const valueAt = (idx) => ({width: widths[idx] || 0, height: heights[idx] || 0});    return {      first: valueAt(0),      last: valueAt(length - 1),      widest: valueAt(widest),      highest: valueAt(highest),      widths,      heights,    };  }  getLabelForValue(value) {    return value;  }  getPixelForValue(value, index) {    return NaN;  }  getValueForPixel(pixel) {}  getPixelForTick(index) {    const ticks = this.ticks;    if (index < 0 || index > ticks.length - 1) {      return null;    }    return this.getPixelForValue(ticks[index].value);  }  getPixelForDecimal(decimal) {    if (this._reversePixels) {      decimal = 1 - decimal;    }    const pixel = this._startPixel + decimal * this._length;    return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel);  }  getDecimalForPixel(pixel) {    const decimal = (pixel - this._startPixel) / this._length;    return this._reversePixels ? 1 - decimal : decimal;  }  getBasePixel() {    return this.getPixelForValue(this.getBaseValue());  }  getBaseValue() {    const {min, max} = this;    return min < 0 && max < 0 ? max :      min > 0 && max > 0 ? min :      0;  }  getContext(index) {    const ticks = this.ticks || [];    if (index >= 0 && index < ticks.length) {      const tick = ticks[index];      return tick.$context ||				(tick.$context = createTickContext(this.getContext(), index, tick));    }    return this.$context ||			(this.$context = createScaleContext(this.chart.getContext(), this));  }  _tickSize() {    const optionTicks = this.options.ticks;    const rot = toRadians(this.labelRotation);    const cos = Math.abs(Math.cos(rot));    const sin = Math.abs(Math.sin(rot));    const labelSizes = this._getLabelSizes();    const padding = optionTicks.autoSkipPadding || 0;    const w = labelSizes ? labelSizes.widest.width + padding : 0;    const h = labelSizes ? labelSizes.highest.height + padding : 0;    return this.isHorizontal()      ? h * cos > w * sin ? w / cos : h / sin      : h * sin < w * cos ? h / cos : w / sin;  }  _isVisible() {    const display = this.options.display;    if (display !== 'auto') {      return !!display;    }    return this.getMatchingVisibleMetas().length > 0;  }  _computeGridLineItems(chartArea) {    const axis = this.axis;    const chart = this.chart;    const options = this.options;    const {grid, position} = options;    const offset = grid.offset;    const isHorizontal = this.isHorizontal();    const ticks = this.ticks;    const ticksLength = ticks.length + (offset ? 1 : 0);    const tl = getTickMarkLength(grid);    const items = [];    const borderOpts = grid.setContext(this.getContext());    const axisWidth = borderOpts.drawBorder ? borderOpts.borderWidth : 0;    const axisHalfWidth = axisWidth / 2;    const alignBorderValue = function(pixel) {      return _alignPixel(chart, pixel, axisWidth);    };    let borderValue, i, lineValue, alignedLineValue;    let tx1, ty1, tx2, ty2, x1, y1, x2, y2;    if (position === 'top') {      borderValue = alignBorderValue(this.bottom);      ty1 = this.bottom - tl;      ty2 = borderValue - axisHalfWidth;      y1 = alignBorderValue(chartArea.top) + axisHalfWidth;      y2 = chartArea.bottom;    } else if (position === 'bottom') {      borderValue = alignBorderValue(this.top);      y1 = chartArea.top;      y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;      ty1 = borderValue + axisHalfWidth;      ty2 = this.top + tl;    } else if (position === 'left') {      borderValue = alignBorderValue(this.right);      tx1 = this.right - tl;      tx2 = borderValue - axisHalfWidth;      x1 = alignBorderValue(chartArea.left) + axisHalfWidth;      x2 = chartArea.right;    } else if (position === 'right') {      borderValue = alignBorderValue(this.left);      x1 = chartArea.left;      x2 = alignBorderValue(chartArea.right) - axisHalfWidth;      tx1 = borderValue + axisHalfWidth;      tx2 = this.left + tl;    } else if (axis === 'x') {      if (position === 'center') {        borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5);      } else if (isObject(position)) {        const positionAxisID = Object.keys(position)[0];        const value = position[positionAxisID];        borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));      }      y1 = chartArea.top;      y2 = chartArea.bottom;      ty1 = borderValue + axisHalfWidth;      ty2 = ty1 + tl;    } else if (axis === 'y') {      if (position === 'center') {        borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);      } else if (isObject(position)) {        const positionAxisID = Object.keys(position)[0];        const value = position[positionAxisID];        borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));      }      tx1 = borderValue - axisHalfWidth;      tx2 = tx1 - tl;      x1 = chartArea.left;      x2 = chartArea.right;    }    const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength);    const step = Math.max(1, Math.ceil(ticksLength / limit));    for (i = 0; i < ticksLength; i += step) {      const optsAtIndex = grid.setContext(this.getContext(i));      const lineWidth = optsAtIndex.lineWidth;      const lineColor = optsAtIndex.color;      const borderDash = grid.borderDash || [];      const borderDashOffset = optsAtIndex.borderDashOffset;      const tickWidth = optsAtIndex.tickWidth;      const tickColor = optsAtIndex.tickColor;      const tickBorderDash = optsAtIndex.tickBorderDash || [];      const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset;      lineValue = getPixelForGridLine(this, i, offset);      if (lineValue === undefined) {        continue;      }      alignedLineValue = _alignPixel(chart, lineValue, lineWidth);      if (isHorizontal) {        tx1 = tx2 = x1 = x2 = alignedLineValue;      } else {        ty1 = ty2 = y1 = y2 = alignedLineValue;      }      items.push({        tx1,        ty1,        tx2,        ty2,        x1,        y1,        x2,        y2,        width: lineWidth,        color: lineColor,        borderDash,        borderDashOffset,        tickWidth,        tickColor,        tickBorderDash,        tickBorderDashOffset,      });    }    this._ticksLength = ticksLength;    this._borderValue = borderValue;    return items;  }  _computeLabelItems(chartArea) {    const axis = this.axis;    const options = this.options;    const {position, ticks: optionTicks} = options;    const isHorizontal = this.isHorizontal();    const ticks = this.ticks;    const {align, crossAlign, padding, mirror} = optionTicks;    const tl = getTickMarkLength(options.grid);    const tickAndPadding = tl + padding;    const hTickAndPadding = mirror ? -padding : tickAndPadding;    const rotation = -toRadians(this.labelRotation);    const items = [];    let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;    let textBaseline = 'middle';    if (position === 'top') {      y = this.bottom - hTickAndPadding;      textAlign = this._getXAxisLabelAlignment();    } else if (position === 'bottom') {      y = this.top + hTickAndPadding;      textAlign = this._getXAxisLabelAlignment();    } else if (position === 'left') {      const ret = this._getYAxisLabelAlignment(tl);      textAlign = ret.textAlign;      x = ret.x;    } else if (position === 'right') {      const ret = this._getYAxisLabelAlignment(tl);      textAlign = ret.textAlign;      x = ret.x;    } else if (axis === 'x') {      if (position === 'center') {        y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding;      } else if (isObject(position)) {        const positionAxisID = Object.keys(position)[0];        const value = position[positionAxisID];        y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;      }      textAlign = this._getXAxisLabelAlignment();    } else if (axis === 'y') {      if (position === 'center') {        x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding;      } else if (isObject(position)) {        const positionAxisID = Object.keys(position)[0];        const value = position[positionAxisID];        x = this.chart.scales[positionAxisID].getPixelForValue(value);      }      textAlign = this._getYAxisLabelAlignment(tl).textAlign;    }    if (axis === 'y') {      if (align === 'start') {        textBaseline = 'top';      } else if (align === 'end') {        textBaseline = 'bottom';      }    }    const labelSizes = this._getLabelSizes();    for (i = 0, ilen = ticks.length; i < ilen; ++i) {      tick = ticks[i];      label = tick.label;      const optsAtIndex = optionTicks.setContext(this.getContext(i));      pixel = this.getPixelForTick(i) + optionTicks.labelOffset;      font = this._resolveTickFontOptions(i);      lineHeight = font.lineHeight;      lineCount = isArray(label) ? label.length : 1;      const halfCount = lineCount / 2;      const color = optsAtIndex.color;      const strokeColor = optsAtIndex.textStrokeColor;      const strokeWidth = optsAtIndex.textStrokeWidth;      if (isHorizontal) {        x = pixel;        if (position === 'top') {          if (crossAlign === 'near' || rotation !== 0) {            textOffset = -lineCount * lineHeight + lineHeight / 2;          } else if (crossAlign === 'center') {            textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight;          } else {            textOffset = -labelSizes.highest.height + lineHeight / 2;          }        } else {          if (crossAlign === 'near' || rotation !== 0) {            textOffset = lineHeight / 2;          } else if (crossAlign === 'center') {            textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight;          } else {            textOffset = labelSizes.highest.height - lineCount * lineHeight;          }        }        if (mirror) {          textOffset *= -1;        }      } else {        y = pixel;        textOffset = (1 - lineCount) * lineHeight / 2;      }      let backdrop;      if (optsAtIndex.showLabelBackdrop) {        const labelPadding = toPadding(optsAtIndex.backdropPadding);        const height = labelSizes.heights[i];        const width = labelSizes.widths[i];        let top = y + textOffset - labelPadding.top;        let left = x - labelPadding.left;        switch (textBaseline) {        case 'middle':          top -= height / 2;          break;        case 'bottom':          top -= height;          break;        }        switch (textAlign) {        case 'center':          left -= width / 2;          break;        case 'right':          left -= width;          break;        }        backdrop = {          left,          top,          width: width + labelPadding.width,          height: height + labelPadding.height,          color: optsAtIndex.backdropColor,        };      }      items.push({        rotation,        label,        font,        color,        strokeColor,        strokeWidth,        textOffset,        textAlign,        textBaseline,        translation: [x, y],        backdrop,      });    }    return items;  }  _getXAxisLabelAlignment() {    const {position, ticks} = this.options;    const rotation = -toRadians(this.labelRotation);    if (rotation) {      return position === 'top' ? 'left' : 'right';    }    let align = 'center';    if (ticks.align === 'start') {      align = 'left';    } else if (ticks.align === 'end') {      align = 'right';    }    return align;  }  _getYAxisLabelAlignment(tl) {    const {position, ticks: {crossAlign, mirror, padding}} = this.options;    const labelSizes = this._getLabelSizes();    const tickAndPadding = tl + padding;    const widest = labelSizes.widest.width;    let textAlign;    let x;    if (position === 'left') {      if (mirror) {        x = this.right + padding;        if (crossAlign === 'near') {          textAlign = 'left';        } else if (crossAlign === 'center') {          textAlign = 'center';          x += (widest / 2);        } else {          textAlign = 'right';          x += widest;        }      } else {        x = this.right - tickAndPadding;        if (crossAlign === 'near') {          textAlign = 'right';        } else if (crossAlign === 'center') {          textAlign = 'center';          x -= (widest / 2);        } else {          textAlign = 'left';          x = this.left;        }      }    } else if (position === 'right') {      if (mirror) {        x = this.left + padding;        if (crossAlign === 'near') {          textAlign = 'right';        } else if (crossAlign === 'center') {          textAlign = 'center';          x -= (widest / 2);        } else {          textAlign = 'left';          x -= widest;        }      } else {        x = this.left + tickAndPadding;        if (crossAlign === 'near') {          textAlign = 'left';        } else if (crossAlign === 'center') {          textAlign = 'center';          x += widest / 2;        } else {          textAlign = 'right';          x = this.right;        }      }    } else {      textAlign = 'right';    }    return {textAlign, x};  }  _computeLabelArea() {    if (this.options.ticks.mirror) {      return;    }    const chart = this.chart;    const position = this.options.position;    if (position === 'left' || position === 'right') {      return {top: 0, left: this.left, bottom: chart.height, right: this.right};    } if (position === 'top' || position === 'bottom') {      return {top: this.top, left: 0, bottom: this.bottom, right: chart.width};    }  }  drawBackground() {    const {ctx, options: {backgroundColor}, left, top, width, height} = this;    if (backgroundColor) {      ctx.save();      ctx.fillStyle = backgroundColor;      ctx.fillRect(left, top, width, height);      ctx.restore();    }  }  getLineWidthForValue(value) {    const grid = this.options.grid;    if (!this._isVisible() || !grid.display) {      return 0;    }    const ticks = this.ticks;    const index = ticks.findIndex(t => t.value === value);    if (index >= 0) {      const opts = grid.setContext(this.getContext(index));      return opts.lineWidth;    }    return 0;  }  drawGrid(chartArea) {    const grid = this.options.grid;    const ctx = this.ctx;    const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea));    let i, ilen;    const drawLine = (p1, p2, style) => {      if (!style.width || !style.color) {        return;      }      ctx.save();      ctx.lineWidth = style.width;      ctx.strokeStyle = style.color;      ctx.setLineDash(style.borderDash || []);      ctx.lineDashOffset = style.borderDashOffset;      ctx.beginPath();      ctx.moveTo(p1.x, p1.y);      ctx.lineTo(p2.x, p2.y);      ctx.stroke();      ctx.restore();    };    if (grid.display) {      for (i = 0, ilen = items.length; i < ilen; ++i) {        const item = items[i];        if (grid.drawOnChartArea) {          drawLine(            {x: item.x1, y: item.y1},            {x: item.x2, y: item.y2},            item          );        }        if (grid.drawTicks) {          drawLine(            {x: item.tx1, y: item.ty1},            {x: item.tx2, y: item.ty2},            {              color: item.tickColor,              width: item.tickWidth,              borderDash: item.tickBorderDash,              borderDashOffset: item.tickBorderDashOffset            }          );        }      }    }  }  drawBorder() {    const {chart, ctx, options: {grid}} = this;    const borderOpts = grid.setContext(this.getContext());    const axisWidth = grid.drawBorder ? borderOpts.borderWidth : 0;    if (!axisWidth) {      return;    }    const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth;    const borderValue = this._borderValue;    let x1, x2, y1, y2;    if (this.isHorizontal()) {      x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2;      x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2;      y1 = y2 = borderValue;    } else {      y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2;      y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2;      x1 = x2 = borderValue;    }    ctx.save();    ctx.lineWidth = borderOpts.borderWidth;    ctx.strokeStyle = borderOpts.borderColor;    ctx.beginPath();    ctx.moveTo(x1, y1);    ctx.lineTo(x2, y2);    ctx.stroke();    ctx.restore();  }  drawLabels(chartArea) {    const optionTicks = this.options.ticks;    if (!optionTicks.display) {      return;    }    const ctx = this.ctx;    const area = this._computeLabelArea();    if (area) {      clipArea(ctx, area);    }    const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea));    let i, ilen;    for (i = 0, ilen = items.length; i < ilen; ++i) {      const item = items[i];      const tickFont = item.font;      const label = item.label;      if (item.backdrop) {        ctx.fillStyle = item.backdrop.color;        ctx.fillRect(item.backdrop.left, item.backdrop.top, item.backdrop.width, item.backdrop.height);      }      let y = item.textOffset;      renderText(ctx, label, 0, y, tickFont, item);    }    if (area) {      unclipArea(ctx);    }  }  drawTitle() {    const {ctx, options: {position, title, reverse}} = this;    if (!title.display) {      return;    }    const font = toFont(title.font);    const padding = toPadding(title.padding);    const align = title.align;    let offset = font.lineHeight / 2;    if (position === 'bottom' || position === 'center' || isObject(position)) {      offset += padding.bottom;      if (isArray(title.text)) {        offset += font.lineHeight * (title.text.length - 1);      }    } else {      offset += padding.top;    }    const {titleX, titleY, maxWidth, rotation} = titleArgs(this, offset, position, align);    renderText(ctx, title.text, 0, 0, font, {      color: title.color,      maxWidth,      rotation,      textAlign: titleAlign(align, position, reverse),      textBaseline: 'middle',      translation: [titleX, titleY],    });  }  draw(chartArea) {    if (!this._isVisible()) {      return;    }    this.drawBackground();    this.drawGrid(chartArea);    this.drawBorder();    this.drawTitle();    this.drawLabels(chartArea);  }  _layers() {    const opts = this.options;    const tz = opts.ticks && opts.ticks.z || 0;    const gz = valueOrDefault(opts.grid && opts.grid.z, -1);    if (!this._isVisible() || this.draw !== Scale.prototype.draw) {      return [{        z: tz,        draw: (chartArea) => {          this.draw(chartArea);        }      }];    }    return [{      z: gz,      draw: (chartArea) => {        this.drawBackground();        this.drawGrid(chartArea);        this.drawTitle();      }    }, {      z: gz + 1,      draw: () => {        this.drawBorder();      }    }, {      z: tz,      draw: (chartArea) => {        this.drawLabels(chartArea);      }    }];  }  getMatchingVisibleMetas(type) {    const metas = this.chart.getSortedVisibleDatasetMetas();    const axisID = this.axis + 'AxisID';    const result = [];    let i, ilen;    for (i = 0, ilen = metas.length; i < ilen; ++i) {      const meta = metas[i];      if (meta[axisID] === this.id && (!type || meta.type === type)) {        result.push(meta);      }    }    return result;  }  _resolveTickFontOptions(index) {    const opts = this.options.ticks.setContext(this.getContext(index));    return toFont(opts.font);  }  _maxDigits() {    const fontSize = this._resolveTickFontOptions(0).lineHeight;    return (this.isHorizontal() ? this.width : this.height) / fontSize;  }}class TypedRegistry {  constructor(type, scope, override) {    this.type = type;    this.scope = scope;    this.override = override;    this.items = Object.create(null);  }  isForType(type) {    return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);  }  register(item) {    const proto = Object.getPrototypeOf(item);    let parentScope;    if (isIChartComponent(proto)) {      parentScope = this.register(proto);    }    const items = this.items;    const id = item.id;    const scope = this.scope + '.' + id;    if (!id) {      throw new Error('class does not have id: ' + item);    }    if (id in items) {      return scope;    }    items[id] = item;    registerDefaults(item, scope, parentScope);    if (this.override) {      defaults.override(item.id, item.overrides);    }    return scope;  }  get(id) {    return this.items[id];  }  unregister(item) {    const items = this.items;    const id = item.id;    const scope = this.scope;    if (id in items) {      delete items[id];    }    if (scope && id in defaults[scope]) {      delete defaults[scope][id];      if (this.override) {        delete overrides[id];      }    }  }}function registerDefaults(item, scope, parentScope) {  const itemDefaults = merge(Object.create(null), [    parentScope ? defaults.get(parentScope) : {},    defaults.get(scope),    item.defaults  ]);  defaults.set(scope, itemDefaults);  if (item.defaultRoutes) {    routeDefaults(scope, item.defaultRoutes);  }  if (item.descriptors) {    defaults.describe(scope, item.descriptors);  }}function routeDefaults(scope, routes) {  Object.keys(routes).forEach(property => {    const propertyParts = property.split('.');    const sourceName = propertyParts.pop();    const sourceScope = [scope].concat(propertyParts).join('.');    const parts = routes[property].split('.');    const targetName = parts.pop();    const targetScope = parts.join('.');    defaults.route(sourceScope, sourceName, targetScope, targetName);  });}function isIChartComponent(proto) {  return 'id' in proto && 'defaults' in proto;}class Registry {  constructor() {    this.controllers = new TypedRegistry(DatasetController, 'datasets', true);    this.elements = new TypedRegistry(Element, 'elements');    this.plugins = new TypedRegistry(Object, 'plugins');    this.scales = new TypedRegistry(Scale, 'scales');    this._typedRegistries = [this.controllers, this.scales, this.elements];  }  add(...args) {    this._each('register', args);  }  remove(...args) {    this._each('unregister', args);  }  addControllers(...args) {    this._each('register', args, this.controllers);  }  addElements(...args) {    this._each('register', args, this.elements);  }  addPlugins(...args) {    this._each('register', args, this.plugins);  }  addScales(...args) {    this._each('register', args, this.scales);  }  getController(id) {    return this._get(id, this.controllers, 'controller');  }  getElement(id) {    return this._get(id, this.elements, 'element');  }  getPlugin(id) {    return this._get(id, this.plugins, 'plugin');  }  getScale(id) {    return this._get(id, this.scales, 'scale');  }  removeControllers(...args) {    this._each('unregister', args, this.controllers);  }  removeElements(...args) {    this._each('unregister', args, this.elements);  }  removePlugins(...args) {    this._each('unregister', args, this.plugins);  }  removeScales(...args) {    this._each('unregister', args, this.scales);  }  _each(method, args, typedRegistry) {    [...args].forEach(arg => {      const reg = typedRegistry || this._getRegistryForType(arg);      if (typedRegistry || reg.isForType(arg) || (reg === this.plugins && arg.id)) {        this._exec(method, reg, arg);      } else {        each(arg, item => {          const itemReg = typedRegistry || this._getRegistryForType(item);          this._exec(method, itemReg, item);        });      }    });  }  _exec(method, registry, component) {    const camelMethod = _capitalize(method);    callback(component['before' + camelMethod], [], component);    registry[method](component);    callback(component['after' + camelMethod], [], component);  }  _getRegistryForType(type) {    for (let i = 0; i < this._typedRegistries.length; i++) {      const reg = this._typedRegistries[i];      if (reg.isForType(type)) {        return reg;      }    }    return this.plugins;  }  _get(id, typedRegistry, type) {    const item = typedRegistry.get(id);    if (item === undefined) {      throw new Error('"' + id + '" is not a registered ' + type + '.');    }    return item;  }}var registry = new Registry();class PluginService {  constructor() {    this._init = [];  }  notify(chart, hook, args, filter) {    if (hook === 'beforeInit') {      this._init = this._createDescriptors(chart, true);      this._notify(this._init, chart, 'install');    }    const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart);    const result = this._notify(descriptors, chart, hook, args);    if (hook === 'afterDestroy') {      this._notify(descriptors, chart, 'stop');      this._notify(this._init, chart, 'uninstall');    }    return result;  }  _notify(descriptors, chart, hook, args) {    args = args || {};    for (const descriptor of descriptors) {      const plugin = descriptor.plugin;      const method = plugin[hook];      const params = [chart, args, descriptor.options];      if (callback(method, params, plugin) === false && args.cancelable) {        return false;      }    }    return true;  }  invalidate() {    if (!isNullOrUndef(this._cache)) {      this._oldCache = this._cache;      this._cache = undefined;    }  }  _descriptors(chart) {    if (this._cache) {      return this._cache;    }    const descriptors = this._cache = this._createDescriptors(chart);    this._notifyStateChanges(chart);    return descriptors;  }  _createDescriptors(chart, all) {    const config = chart && chart.config;    const options = valueOrDefault(config.options && config.options.plugins, {});    const plugins = allPlugins(config);    return options === false && !all ? [] : createDescriptors(chart, plugins, options, all);  }  _notifyStateChanges(chart) {    const previousDescriptors = this._oldCache || [];    const descriptors = this._cache;    const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id));    this._notify(diff(previousDescriptors, descriptors), chart, 'stop');    this._notify(diff(descriptors, previousDescriptors), chart, 'start');  }}function allPlugins(config) {  const plugins = [];  const keys = Object.keys(registry.plugins.items);  for (let i = 0; i < keys.length; i++) {    plugins.push(registry.getPlugin(keys[i]));  }  const local = config.plugins || [];  for (let i = 0; i < local.length; i++) {    const plugin = local[i];    if (plugins.indexOf(plugin) === -1) {      plugins.push(plugin);    }  }  return plugins;}function getOpts(options, all) {  if (!all && options === false) {    return null;  }  if (options === true) {    return {};  }  return options;}function createDescriptors(chart, plugins, options, all) {  const result = [];  const context = chart.getContext();  for (let i = 0; i < plugins.length; i++) {    const plugin = plugins[i];    const id = plugin.id;    const opts = getOpts(options[id], all);    if (opts === null) {      continue;    }    result.push({      plugin,      options: pluginOpts(chart.config, plugin, opts, context)    });  }  return result;}function pluginOpts(config, plugin, opts, context) {  const keys = config.pluginScopeKeys(plugin);  const scopes = config.getOptionScopes(opts, keys);  return config.createResolver(scopes, context, [''], {scriptable: false, indexable: false, allKeys: true});}function getIndexAxis(type, options) {  const datasetDefaults = defaults.datasets[type] || {};  const datasetOptions = (options.datasets || {})[type] || {};  return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';}function getAxisFromDefaultScaleID(id, indexAxis) {  let axis = id;  if (id === '_index_') {    axis = indexAxis;  } else if (id === '_value_') {    axis = indexAxis === 'x' ? 'y' : 'x';  }  return axis;}function getDefaultScaleIDFromAxis(axis, indexAxis) {  return axis === indexAxis ? '_index_' : '_value_';}function axisFromPosition(position) {  if (position === 'top' || position === 'bottom') {    return 'x';  }  if (position === 'left' || position === 'right') {    return 'y';  }}function determineAxis(id, scaleOptions) {  if (id === 'x' || id === 'y') {    return id;  }  return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase();}function mergeScaleConfig(config, options) {  const chartDefaults = overrides[config.type] || {scales: {}};  const configScales = options.scales || {};  const chartIndexAxis = getIndexAxis(config.type, options);  const firstIDs = Object.create(null);  const scales = Object.create(null);  Object.keys(configScales).forEach(id => {    const scaleConf = configScales[id];    if (!isObject(scaleConf)) {      return console.error(`Invalid scale configuration for scale: ${id}`);    }    if (scaleConf._proxy) {      return console.warn(`Ignoring resolver passed as options for scale: ${id}`);    }    const axis = determineAxis(id, scaleConf);    const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);    const defaultScaleOptions = chartDefaults.scales || {};    firstIDs[axis] = firstIDs[axis] || id;    scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]);  });  config.data.datasets.forEach(dataset => {    const type = dataset.type || config.type;    const indexAxis = dataset.indexAxis || getIndexAxis(type, options);    const datasetDefaults = overrides[type] || {};    const defaultScaleOptions = datasetDefaults.scales || {};    Object.keys(defaultScaleOptions).forEach(defaultID => {      const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);      const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis;      scales[id] = scales[id] || Object.create(null);      mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]);    });  });  Object.keys(scales).forEach(key => {    const scale = scales[key];    mergeIf(scale, [defaults.scales[scale.type], defaults.scale]);  });  return scales;}function initOptions(config) {  const options = config.options || (config.options = {});  options.plugins = valueOrDefault(options.plugins, {});  options.scales = mergeScaleConfig(config, options);}function initData(data) {  data = data || {};  data.datasets = data.datasets || [];  data.labels = data.labels || [];  return data;}function initConfig(config) {  config = config || {};  config.data = initData(config.data);  initOptions(config);  return config;}const keyCache = new Map();const keysCached = new Set();function cachedKeys(cacheKey, generate) {  let keys = keyCache.get(cacheKey);  if (!keys) {    keys = generate();    keyCache.set(cacheKey, keys);    keysCached.add(keys);  }  return keys;}const addIfFound = (set, obj, key) => {  const opts = resolveObjectKey(obj, key);  if (opts !== undefined) {    set.add(opts);  }};class Config {  constructor(config) {    this._config = initConfig(config);    this._scopeCache = new Map();    this._resolverCache = new Map();  }  get platform() {    return this._config.platform;  }  get type() {    return this._config.type;  }  set type(type) {    this._config.type = type;  }  get data() {    return this._config.data;  }  set data(data) {    this._config.data = initData(data);  }  get options() {    return this._config.options;  }  set options(options) {    this._config.options = options;  }  get plugins() {    return this._config.plugins;  }  update() {    const config = this._config;    this.clearCache();    initOptions(config);  }  clearCache() {    this._scopeCache.clear();    this._resolverCache.clear();  }  datasetScopeKeys(datasetType) {    return cachedKeys(datasetType,      () => [[        `datasets.${datasetType}`,        ''      ]]);  }  datasetAnimationScopeKeys(datasetType, transition) {    return cachedKeys(`${datasetType}.transition.${transition}`,      () => [        [          `datasets.${datasetType}.transitions.${transition}`,          `transitions.${transition}`,        ],        [          `datasets.${datasetType}`,          ''        ]      ]);  }  datasetElementScopeKeys(datasetType, elementType) {    return cachedKeys(`${datasetType}-${elementType}`,      () => [[        `datasets.${datasetType}.elements.${elementType}`,        `datasets.${datasetType}`,        `elements.${elementType}`,        ''      ]]);  }  pluginScopeKeys(plugin) {    const id = plugin.id;    const type = this.type;    return cachedKeys(`${type}-plugin-${id}`,      () => [[        `plugins.${id}`,        ...plugin.additionalOptionScopes || [],      ]]);  }  _cachedScopes(mainScope, resetCache) {    const _scopeCache = this._scopeCache;    let cache = _scopeCache.get(mainScope);    if (!cache || resetCache) {      cache = new Map();      _scopeCache.set(mainScope, cache);    }    return cache;  }  getOptionScopes(mainScope, keyLists, resetCache) {    const {options, type} = this;    const cache = this._cachedScopes(mainScope, resetCache);    const cached = cache.get(keyLists);    if (cached) {      return cached;    }    const scopes = new Set();    keyLists.forEach(keys => {      if (mainScope) {        scopes.add(mainScope);        keys.forEach(key => addIfFound(scopes, mainScope, key));      }      keys.forEach(key => addIfFound(scopes, options, key));      keys.forEach(key => addIfFound(scopes, overrides[type] || {}, key));      keys.forEach(key => addIfFound(scopes, defaults, key));      keys.forEach(key => addIfFound(scopes, descriptors, key));    });    const array = Array.from(scopes);    if (array.length === 0) {      array.push(Object.create(null));    }    if (keysCached.has(keyLists)) {      cache.set(keyLists, array);    }    return array;  }  chartOptionScopes() {    const {options, type} = this;    return [      options,      overrides[type] || {},      defaults.datasets[type] || {},      {type},      defaults,      descriptors    ];  }  resolveNamedOptions(scopes, names, context, prefixes = ['']) {    const result = {$shared: true};    const {resolver, subPrefixes} = getResolver(this._resolverCache, scopes, prefixes);    let options = resolver;    if (needContext(resolver, names)) {      result.$shared = false;      context = isFunction(context) ? context() : context;      const subResolver = this.createResolver(scopes, context, subPrefixes);      options = _attachContext(resolver, context, subResolver);    }    for (const prop of names) {      result[prop] = options[prop];    }    return result;  }  createResolver(scopes, context, prefixes = [''], descriptorDefaults) {    const {resolver} = getResolver(this._resolverCache, scopes, prefixes);    return isObject(context)      ? _attachContext(resolver, context, undefined, descriptorDefaults)      : resolver;  }}function getResolver(resolverCache, scopes, prefixes) {  let cache = resolverCache.get(scopes);  if (!cache) {    cache = new Map();    resolverCache.set(scopes, cache);  }  const cacheKey = prefixes.join();  let cached = cache.get(cacheKey);  if (!cached) {    const resolver = _createResolver(scopes, prefixes);    cached = {      resolver,      subPrefixes: prefixes.filter(p => !p.toLowerCase().includes('hover'))    };    cache.set(cacheKey, cached);  }  return cached;}const hasFunction = value => isObject(value)  && Object.getOwnPropertyNames(value).reduce((acc, key) => acc || isFunction(value[key]), false);function needContext(proxy, names) {  const {isScriptable, isIndexable} = _descriptors(proxy);  for (const prop of names) {    const scriptable = isScriptable(prop);    const indexable = isIndexable(prop);    const value = (indexable || scriptable) && proxy[prop];    if ((scriptable && (isFunction(value) || hasFunction(value)))      || (indexable && isArray(value))) {      return true;    }  }  return false;}var version = "3.7.1";const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea'];function positionIsHorizontal(position, axis) {  return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x');}function compare2Level(l1, l2) {  return function(a, b) {    return a[l1] === b[l1]      ? a[l2] - b[l2]      : a[l1] - b[l1];  };}function onAnimationsComplete(context) {  const chart = context.chart;  const animationOptions = chart.options.animation;  chart.notifyPlugins('afterRender');  callback(animationOptions && animationOptions.onComplete, [context], chart);}function onAnimationProgress(context) {  const chart = context.chart;  const animationOptions = chart.options.animation;  callback(animationOptions && animationOptions.onProgress, [context], chart);}function getCanvas(item) {  if (_isDomSupported() && typeof item === 'string') {    item = document.getElementById(item);  } else if (item && item.length) {    item = item[0];  }  if (item && item.canvas) {    item = item.canvas;  }  return item;}const instances = {};const getChart = (key) => {  const canvas = getCanvas(key);  return Object.values(instances).filter((c) => c.canvas === canvas).pop();};function moveNumericKeys(obj, start, move) {  const keys = Object.keys(obj);  for (const key of keys) {    const intKey = +key;    if (intKey >= start) {      const value = obj[key];      delete obj[key];      if (move > 0 || intKey > start) {        obj[intKey + move] = value;      }    }  }}function determineLastEvent(e, lastEvent, inChartArea, isClick) {  if (!inChartArea || e.type === 'mouseout') {    return null;  }  if (isClick) {    return lastEvent;  }  return e;}class Chart {  constructor(item, userConfig) {    const config = this.config = new Config(userConfig);    const initialCanvas = getCanvas(item);    const existingChart = getChart(initialCanvas);    if (existingChart) {      throw new Error(        'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' +				' must be destroyed before the canvas can be reused.'      );    }    const options = config.createResolver(config.chartOptionScopes(), this.getContext());    this.platform = new (config.platform || _detectPlatform(initialCanvas))();    this.platform.updateConfig(config);    const context = this.platform.acquireContext(initialCanvas, options.aspectRatio);    const canvas = context && context.canvas;    const height = canvas && canvas.height;    const width = canvas && canvas.width;    this.id = uid();    this.ctx = context;    this.canvas = canvas;    this.width = width;    this.height = height;    this._options = options;    this._aspectRatio = this.aspectRatio;    this._layers = [];    this._metasets = [];    this._stacks = undefined;    this.boxes = [];    this.currentDevicePixelRatio = undefined;    this.chartArea = undefined;    this._active = [];    this._lastEvent = undefined;    this._listeners = {};    this._responsiveListeners = undefined;    this._sortedMetasets = [];    this.scales = {};    this._plugins = new PluginService();    this.$proxies = {};    this._hiddenIndices = {};    this.attached = false;    this._animationsDisabled = undefined;    this.$context = undefined;    this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0);    this._dataChanges = [];    instances[this.id] = this;    if (!context || !canvas) {      console.error("Failed to create chart: can't acquire context from the given item");      return;    }    animator.listen(this, 'complete', onAnimationsComplete);    animator.listen(this, 'progress', onAnimationProgress);    this._initialize();    if (this.attached) {      this.update();    }  }  get aspectRatio() {    const {options: {aspectRatio, maintainAspectRatio}, width, height, _aspectRatio} = this;    if (!isNullOrUndef(aspectRatio)) {      return aspectRatio;    }    if (maintainAspectRatio && _aspectRatio) {      return _aspectRatio;    }    return height ? width / height : null;  }  get data() {    return this.config.data;  }  set data(data) {    this.config.data = data;  }  get options() {    return this._options;  }  set options(options) {    this.config.options = options;  }  _initialize() {    this.notifyPlugins('beforeInit');    if (this.options.responsive) {      this.resize();    } else {      retinaScale(this, this.options.devicePixelRatio);    }    this.bindEvents();    this.notifyPlugins('afterInit');    return this;  }  clear() {    clearCanvas(this.canvas, this.ctx);    return this;  }  stop() {    animator.stop(this);    return this;  }  resize(width, height) {    if (!animator.running(this)) {      this._resize(width, height);    } else {      this._resizeBeforeDraw = {width, height};    }  }  _resize(width, height) {    const options = this.options;    const canvas = this.canvas;    const aspectRatio = options.maintainAspectRatio && this.aspectRatio;    const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio);    const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio();    const mode = this.width ? 'resize' : 'attach';    this.width = newSize.width;    this.height = newSize.height;    this._aspectRatio = this.aspectRatio;    if (!retinaScale(this, newRatio, true)) {      return;    }    this.notifyPlugins('resize', {size: newSize});    callback(options.onResize, [this, newSize], this);    if (this.attached) {      if (this._doResize(mode)) {        this.render();      }    }  }  ensureScalesHaveIDs() {    const options = this.options;    const scalesOptions = options.scales || {};    each(scalesOptions, (axisOptions, axisID) => {      axisOptions.id = axisID;    });  }  buildOrUpdateScales() {    const options = this.options;    const scaleOpts = options.scales;    const scales = this.scales;    const updated = Object.keys(scales).reduce((obj, id) => {      obj[id] = false;      return obj;    }, {});    let items = [];    if (scaleOpts) {      items = items.concat(        Object.keys(scaleOpts).map((id) => {          const scaleOptions = scaleOpts[id];          const axis = determineAxis(id, scaleOptions);          const isRadial = axis === 'r';          const isHorizontal = axis === 'x';          return {            options: scaleOptions,            dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',            dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'          };        })      );    }    each(items, (item) => {      const scaleOptions = item.options;      const id = scaleOptions.id;      const axis = determineAxis(id, scaleOptions);      const scaleType = valueOrDefault(scaleOptions.type, item.dtype);      if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {        scaleOptions.position = item.dposition;      }      updated[id] = true;      let scale = null;      if (id in scales && scales[id].type === scaleType) {        scale = scales[id];      } else {        const scaleClass = registry.getScale(scaleType);        scale = new scaleClass({          id,          type: scaleType,          ctx: this.ctx,          chart: this        });        scales[scale.id] = scale;      }      scale.init(scaleOptions, options);    });    each(updated, (hasUpdated, id) => {      if (!hasUpdated) {        delete scales[id];      }    });    each(scales, (scale) => {      layouts.configure(this, scale, scale.options);      layouts.addBox(this, scale);    });  }  _updateMetasets() {    const metasets = this._metasets;    const numData = this.data.datasets.length;    const numMeta = metasets.length;    metasets.sort((a, b) => a.index - b.index);    if (numMeta > numData) {      for (let i = numData; i < numMeta; ++i) {        this._destroyDatasetMeta(i);      }      metasets.splice(numData, numMeta - numData);    }    this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));  }  _removeUnreferencedMetasets() {    const {_metasets: metasets, data: {datasets}} = this;    if (metasets.length > datasets.length) {      delete this._stacks;    }    metasets.forEach((meta, index) => {      if (datasets.filter(x => x === meta._dataset).length === 0) {        this._destroyDatasetMeta(index);      }    });  }  buildOrUpdateControllers() {    const newControllers = [];    const datasets = this.data.datasets;    let i, ilen;    this._removeUnreferencedMetasets();    for (i = 0, ilen = datasets.length; i < ilen; i++) {      const dataset = datasets[i];      let meta = this.getDatasetMeta(i);      const type = dataset.type || this.config.type;      if (meta.type && meta.type !== type) {        this._destroyDatasetMeta(i);        meta = this.getDatasetMeta(i);      }      meta.type = type;      meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options);      meta.order = dataset.order || 0;      meta.index = i;      meta.label = '' + dataset.label;      meta.visible = this.isDatasetVisible(i);      if (meta.controller) {        meta.controller.updateIndex(i);        meta.controller.linkScales();      } else {        const ControllerClass = registry.getController(type);        const {datasetElementType, dataElementType} = defaults.datasets[type];        Object.assign(ControllerClass.prototype, {          dataElementType: registry.getElement(dataElementType),          datasetElementType: datasetElementType && registry.getElement(datasetElementType)        });        meta.controller = new ControllerClass(this, i);        newControllers.push(meta.controller);      }    }    this._updateMetasets();    return newControllers;  }  _resetElements() {    each(this.data.datasets, (dataset, datasetIndex) => {      this.getDatasetMeta(datasetIndex).controller.reset();    }, this);  }  reset() {    this._resetElements();    this.notifyPlugins('reset');  }  update(mode) {    const config = this.config;    config.update();    const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());    const animsDisabled = this._animationsDisabled = !options.animation;    this._updateScales();    this._checkEventBindings();    this._updateHiddenIndices();    this._plugins.invalidate();    if (this.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) {      return;    }    const newControllers = this.buildOrUpdateControllers();    this.notifyPlugins('beforeElementsUpdate');    let minPadding = 0;    for (let i = 0, ilen = this.data.datasets.length; i < ilen; i++) {      const {controller} = this.getDatasetMeta(i);      const reset = !animsDisabled && newControllers.indexOf(controller) === -1;      controller.buildOrUpdateElements(reset);      minPadding = Math.max(+controller.getMaxOverflow(), minPadding);    }    minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0;    this._updateLayout(minPadding);    if (!animsDisabled) {      each(newControllers, (controller) => {        controller.reset();      });    }    this._updateDatasets(mode);    this.notifyPlugins('afterUpdate', {mode});    this._layers.sort(compare2Level('z', '_idx'));    const {_active, _lastEvent} = this;    if (_lastEvent) {      this._eventHandler(_lastEvent, true);    } else if (_active.length) {      this._updateHoverStyles(_active, _active, true);    }    this.render();  }  _updateScales() {    each(this.scales, (scale) => {      layouts.removeBox(this, scale);    });    this.ensureScalesHaveIDs();    this.buildOrUpdateScales();  }  _checkEventBindings() {    const options = this.options;    const existingEvents = new Set(Object.keys(this._listeners));    const newEvents = new Set(options.events);    if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {      this.unbindEvents();      this.bindEvents();    }  }  _updateHiddenIndices() {    const {_hiddenIndices} = this;    const changes = this._getUniformDataChanges() || [];    for (const {method, start, count} of changes) {      const move = method === '_removeElements' ? -count : count;      moveNumericKeys(_hiddenIndices, start, move);    }  }  _getUniformDataChanges() {    const _dataChanges = this._dataChanges;    if (!_dataChanges || !_dataChanges.length) {      return;    }    this._dataChanges = [];    const datasetCount = this.data.datasets.length;    const makeSet = (idx) => new Set(      _dataChanges        .filter(c => c[0] === idx)        .map((c, i) => i + ',' + c.splice(1).join(','))    );    const changeSet = makeSet(0);    for (let i = 1; i < datasetCount; i++) {      if (!setsEqual(changeSet, makeSet(i))) {        return;      }    }    return Array.from(changeSet)      .map(c => c.split(','))      .map(a => ({method: a[1], start: +a[2], count: +a[3]}));  }  _updateLayout(minPadding) {    if (this.notifyPlugins('beforeLayout', {cancelable: true}) === false) {      return;    }    layouts.update(this, this.width, this.height, minPadding);    const area = this.chartArea;    const noArea = area.width <= 0 || area.height <= 0;    this._layers = [];    each(this.boxes, (box) => {      if (noArea && box.position === 'chartArea') {        return;      }      if (box.configure) {        box.configure();      }      this._layers.push(...box._layers());    }, this);    this._layers.forEach((item, index) => {      item._idx = index;    });    this.notifyPlugins('afterLayout');  }  _updateDatasets(mode) {    if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) {      return;    }    for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {      this.getDatasetMeta(i).controller.configure();    }    for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {      this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode);    }    this.notifyPlugins('afterDatasetsUpdate', {mode});  }  _updateDataset(index, mode) {    const meta = this.getDatasetMeta(index);    const args = {meta, index, mode, cancelable: true};    if (this.notifyPlugins('beforeDatasetUpdate', args) === false) {      return;    }    meta.controller._update(mode);    args.cancelable = false;    this.notifyPlugins('afterDatasetUpdate', args);  }  render() {    if (this.notifyPlugins('beforeRender', {cancelable: true}) === false) {      return;    }    if (animator.has(this)) {      if (this.attached && !animator.running(this)) {        animator.start(this);      }    } else {      this.draw();      onAnimationsComplete({chart: this});    }  }  draw() {    let i;    if (this._resizeBeforeDraw) {      const {width, height} = this._resizeBeforeDraw;      this._resize(width, height);      this._resizeBeforeDraw = null;    }    this.clear();    if (this.width <= 0 || this.height <= 0) {      return;    }    if (this.notifyPlugins('beforeDraw', {cancelable: true}) === false) {      return;    }    const layers = this._layers;    for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {      layers[i].draw(this.chartArea);    }    this._drawDatasets();    for (; i < layers.length; ++i) {      layers[i].draw(this.chartArea);    }    this.notifyPlugins('afterDraw');  }  _getSortedDatasetMetas(filterVisible) {    const metasets = this._sortedMetasets;    const result = [];    let i, ilen;    for (i = 0, ilen = metasets.length; i < ilen; ++i) {      const meta = metasets[i];      if (!filterVisible || meta.visible) {        result.push(meta);      }    }    return result;  }  getSortedVisibleDatasetMetas() {    return this._getSortedDatasetMetas(true);  }  _drawDatasets() {    if (this.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) {      return;    }    const metasets = this.getSortedVisibleDatasetMetas();    for (let i = metasets.length - 1; i >= 0; --i) {      this._drawDataset(metasets[i]);    }    this.notifyPlugins('afterDatasetsDraw');  }  _drawDataset(meta) {    const ctx = this.ctx;    const clip = meta._clip;    const useClip = !clip.disabled;    const area = this.chartArea;    const args = {      meta,      index: meta.index,      cancelable: true    };    if (this.notifyPlugins('beforeDatasetDraw', args) === false) {      return;    }    if (useClip) {      clipArea(ctx, {        left: clip.left === false ? 0 : area.left - clip.left,        right: clip.right === false ? this.width : area.right + clip.right,        top: clip.top === false ? 0 : area.top - clip.top,        bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom      });    }    meta.controller.draw();    if (useClip) {      unclipArea(ctx);    }    args.cancelable = false;    this.notifyPlugins('afterDatasetDraw', args);  }  getElementsAtEventForMode(e, mode, options, useFinalPosition) {    const method = Interaction.modes[mode];    if (typeof method === 'function') {      return method(this, e, options, useFinalPosition);    }    return [];  }  getDatasetMeta(datasetIndex) {    const dataset = this.data.datasets[datasetIndex];    const metasets = this._metasets;    let meta = metasets.filter(x => x && x._dataset === dataset).pop();    if (!meta) {      meta = {        type: null,        data: [],        dataset: null,        controller: null,        hidden: null,        xAxisID: null,        yAxisID: null,        order: dataset && dataset.order || 0,        index: datasetIndex,        _dataset: dataset,        _parsed: [],        _sorted: false      };      metasets.push(meta);    }    return meta;  }  getContext() {    return this.$context || (this.$context = createContext(null, {chart: this, type: 'chart'}));  }  getVisibleDatasetCount() {    return this.getSortedVisibleDatasetMetas().length;  }  isDatasetVisible(datasetIndex) {    const dataset = this.data.datasets[datasetIndex];    if (!dataset) {      return false;    }    const meta = this.getDatasetMeta(datasetIndex);    return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;  }  setDatasetVisibility(datasetIndex, visible) {    const meta = this.getDatasetMeta(datasetIndex);    meta.hidden = !visible;  }  toggleDataVisibility(index) {    this._hiddenIndices[index] = !this._hiddenIndices[index];  }  getDataVisibility(index) {    return !this._hiddenIndices[index];  }  _updateVisibility(datasetIndex, dataIndex, visible) {    const mode = visible ? 'show' : 'hide';    const meta = this.getDatasetMeta(datasetIndex);    const anims = meta.controller._resolveAnimations(undefined, mode);    if (defined(dataIndex)) {      meta.data[dataIndex].hidden = !visible;      this.update();    } else {      this.setDatasetVisibility(datasetIndex, visible);      anims.update(meta, {visible});      this.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined);    }  }  hide(datasetIndex, dataIndex) {    this._updateVisibility(datasetIndex, dataIndex, false);  }  show(datasetIndex, dataIndex) {    this._updateVisibility(datasetIndex, dataIndex, true);  }  _destroyDatasetMeta(datasetIndex) {    const meta = this._metasets[datasetIndex];    if (meta && meta.controller) {      meta.controller._destroy();    }    delete this._metasets[datasetIndex];  }  _stop() {    let i, ilen;    this.stop();    animator.remove(this);    for (i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {      this._destroyDatasetMeta(i);    }  }  destroy() {    this.notifyPlugins('beforeDestroy');    const {canvas, ctx} = this;    this._stop();    this.config.clearCache();    if (canvas) {      this.unbindEvents();      clearCanvas(canvas, ctx);      this.platform.releaseContext(ctx);      this.canvas = null;      this.ctx = null;    }    this.notifyPlugins('destroy');    delete instances[this.id];    this.notifyPlugins('afterDestroy');  }  toBase64Image(...args) {    return this.canvas.toDataURL(...args);  }  bindEvents() {    this.bindUserEvents();    if (this.options.responsive) {      this.bindResponsiveEvents();    } else {      this.attached = true;    }  }  bindUserEvents() {    const listeners = this._listeners;    const platform = this.platform;    const _add = (type, listener) => {      platform.addEventListener(this, type, listener);      listeners[type] = listener;    };    const listener = (e, x, y) => {      e.offsetX = x;      e.offsetY = y;      this._eventHandler(e);    };    each(this.options.events, (type) => _add(type, listener));  }  bindResponsiveEvents() {    if (!this._responsiveListeners) {      this._responsiveListeners = {};    }    const listeners = this._responsiveListeners;    const platform = this.platform;    const _add = (type, listener) => {      platform.addEventListener(this, type, listener);      listeners[type] = listener;    };    const _remove = (type, listener) => {      if (listeners[type]) {        platform.removeEventListener(this, type, listener);        delete listeners[type];      }    };    const listener = (width, height) => {      if (this.canvas) {        this.resize(width, height);      }    };    let detached;    const attached = () => {      _remove('attach', attached);      this.attached = true;      this.resize();      _add('resize', listener);      _add('detach', detached);    };    detached = () => {      this.attached = false;      _remove('resize', listener);      this._stop();      this._resize(0, 0);      _add('attach', attached);    };    if (platform.isAttached(this.canvas)) {      attached();    } else {      detached();    }  }  unbindEvents() {    each(this._listeners, (listener, type) => {      this.platform.removeEventListener(this, type, listener);    });    this._listeners = {};    each(this._responsiveListeners, (listener, type) => {      this.platform.removeEventListener(this, type, listener);    });    this._responsiveListeners = undefined;  }  updateHoverStyle(items, mode, enabled) {    const prefix = enabled ? 'set' : 'remove';    let meta, item, i, ilen;    if (mode === 'dataset') {      meta = this.getDatasetMeta(items[0].datasetIndex);      meta.controller['_' + prefix + 'DatasetHoverStyle']();    }    for (i = 0, ilen = items.length; i < ilen; ++i) {      item = items[i];      const controller = item && this.getDatasetMeta(item.datasetIndex).controller;      if (controller) {        controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);      }    }  }  getActiveElements() {    return this._active || [];  }  setActiveElements(activeElements) {    const lastActive = this._active || [];    const active = activeElements.map(({datasetIndex, index}) => {      const meta = this.getDatasetMeta(datasetIndex);      if (!meta) {        throw new Error('No dataset found at index ' + datasetIndex);      }      return {        datasetIndex,        element: meta.data[index],        index,      };    });    const changed = !_elementsEqual(active, lastActive);    if (changed) {      this._active = active;      this._lastEvent = null;      this._updateHoverStyles(active, lastActive);    }  }  notifyPlugins(hook, args, filter) {    return this._plugins.notify(this, hook, args, filter);  }  _updateHoverStyles(active, lastActive, replay) {    const hoverOptions = this.options.hover;    const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index));    const deactivated = diff(lastActive, active);    const activated = replay ? active : diff(active, lastActive);    if (deactivated.length) {      this.updateHoverStyle(deactivated, hoverOptions.mode, false);    }    if (activated.length && hoverOptions.mode) {      this.updateHoverStyle(activated, hoverOptions.mode, true);    }  }  _eventHandler(e, replay) {    const args = {      event: e,      replay,      cancelable: true,      inChartArea: _isPointInArea(e, this.chartArea, this._minPadding)    };    const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.native.type);    if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) {      return;    }    const changed = this._handleEvent(e, replay, args.inChartArea);    args.cancelable = false;    this.notifyPlugins('afterEvent', args, eventFilter);    if (changed || args.changed) {      this.render();    }    return this;  }  _handleEvent(e, replay, inChartArea) {    const {_active: lastActive = [], options} = this;    const useFinalPosition = replay;    const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition);    const isClick = _isClickEvent(e);    const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick);    if (inChartArea) {      this._lastEvent = null;      callback(options.onHover, [e, active, this], this);      if (isClick) {        callback(options.onClick, [e, active, this], this);      }    }    const changed = !_elementsEqual(active, lastActive);    if (changed || replay) {      this._active = active;      this._updateHoverStyles(active, lastActive, replay);    }    this._lastEvent = lastEvent;    return changed;  }  _getActiveElements(e, lastActive, inChartArea, useFinalPosition) {    if (e.type === 'mouseout') {      return [];    }    if (!inChartArea) {      return lastActive;    }    const hoverOptions = this.options.hover;    return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);  }}const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate());const enumerable = true;Object.defineProperties(Chart, {  defaults: {    enumerable,    value: defaults  },  instances: {    enumerable,    value: instances  },  overrides: {    enumerable,    value: overrides  },  registry: {    enumerable,    value: registry  },  version: {    enumerable,    value: version  },  getChart: {    enumerable,    value: getChart  },  register: {    enumerable,    value: (...items) => {      registry.add(...items);      invalidatePlugins();    }  },  unregister: {    enumerable,    value: (...items) => {      registry.remove(...items);      invalidatePlugins();    }  }});function abstract() {  throw new Error('This method is not implemented: Check that a complete date adapter is provided.');}class DateAdapter {  constructor(options) {    this.options = options || {};  }  formats() {    return abstract();  }  parse(value, format) {    return abstract();  }  format(timestamp, format) {    return abstract();  }  add(timestamp, amount, unit) {    return abstract();  }  diff(a, b, unit) {    return abstract();  }  startOf(timestamp, unit, weekday) {    return abstract();  }  endOf(timestamp, unit) {    return abstract();  }}DateAdapter.override = function(members) {  Object.assign(DateAdapter.prototype, members);};var _adapters = {  _date: DateAdapter};function getAllScaleValues(scale, type) {  if (!scale._cache.$bar) {    const visibleMetas = scale.getMatchingVisibleMetas(type);    let values = [];    for (let i = 0, ilen = visibleMetas.length; i < ilen; i++) {      values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale));    }    scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b));  }  return scale._cache.$bar;}function computeMinSampleSize(meta) {  const scale = meta.iScale;  const values = getAllScaleValues(scale, meta.type);  let min = scale._length;  let i, ilen, curr, prev;  const updateMinAndPrev = () => {    if (curr === 32767 || curr === -32768) {      return;    }    if (defined(prev)) {      min = Math.min(min, Math.abs(curr - prev) || min);    }    prev = curr;  };  for (i = 0, ilen = values.length; i < ilen; ++i) {    curr = scale.getPixelForValue(values[i]);    updateMinAndPrev();  }  prev = undefined;  for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) {    curr = scale.getPixelForTick(i);    updateMinAndPrev();  }  return min;}function computeFitCategoryTraits(index, ruler, options, stackCount) {  const thickness = options.barThickness;  let size, ratio;  if (isNullOrUndef(thickness)) {    size = ruler.min * options.categoryPercentage;    ratio = options.barPercentage;  } else {    size = thickness * stackCount;    ratio = 1;  }  return {    chunk: size / stackCount,    ratio,    start: ruler.pixels[index] - (size / 2)  };}function computeFlexCategoryTraits(index, ruler, options, stackCount) {  const pixels = ruler.pixels;  const curr = pixels[index];  let prev = index > 0 ? pixels[index - 1] : null;  let next = index < pixels.length - 1 ? pixels[index + 1] : null;  const percent = options.categoryPercentage;  if (prev === null) {    prev = curr - (next === null ? ruler.end - ruler.start : next - curr);  }  if (next === null) {    next = curr + curr - prev;  }  const start = curr - (curr - Math.min(prev, next)) / 2 * percent;  const size = Math.abs(next - prev) / 2 * percent;  return {    chunk: size / stackCount,    ratio: options.barPercentage,    start  };}function parseFloatBar(entry, item, vScale, i) {  const startValue = vScale.parse(entry[0], i);  const endValue = vScale.parse(entry[1], i);  const min = Math.min(startValue, endValue);  const max = Math.max(startValue, endValue);  let barStart = min;  let barEnd = max;  if (Math.abs(min) > Math.abs(max)) {    barStart = max;    barEnd = min;  }  item[vScale.axis] = barEnd;  item._custom = {    barStart,    barEnd,    start: startValue,    end: endValue,    min,    max  };}function parseValue(entry, item, vScale, i) {  if (isArray(entry)) {    parseFloatBar(entry, item, vScale, i);  } else {    item[vScale.axis] = vScale.parse(entry, i);  }  return item;}function parseArrayOrPrimitive(meta, data, start, count) {  const iScale = meta.iScale;  const vScale = meta.vScale;  const labels = iScale.getLabels();  const singleScale = iScale === vScale;  const parsed = [];  let i, ilen, item, entry;  for (i = start, ilen = start + count; i < ilen; ++i) {    entry = data[i];    item = {};    item[iScale.axis] = singleScale || iScale.parse(labels[i], i);    parsed.push(parseValue(entry, item, vScale, i));  }  return parsed;}function isFloatBar(custom) {  return custom && custom.barStart !== undefined && custom.barEnd !== undefined;}function barSign(size, vScale, actualBase) {  if (size !== 0) {    return sign(size);  }  return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1);}function borderProps(properties) {  let reverse, start, end, top, bottom;  if (properties.horizontal) {    reverse = properties.base > properties.x;    start = 'left';    end = 'right';  } else {    reverse = properties.base < properties.y;    start = 'bottom';    end = 'top';  }  if (reverse) {    top = 'end';    bottom = 'start';  } else {    top = 'start';    bottom = 'end';  }  return {start, end, reverse, top, bottom};}function setBorderSkipped(properties, options, stack, index) {  let edge = options.borderSkipped;  const res = {};  if (!edge) {    properties.borderSkipped = res;    return;  }  const {start, end, reverse, top, bottom} = borderProps(properties);  if (edge === 'middle' && stack) {    properties.enableBorderRadius = true;    if ((stack._top || 0) === index) {      edge = top;    } else if ((stack._bottom || 0) === index) {      edge = bottom;    } else {      res[parseEdge(bottom, start, end, reverse)] = true;      edge = top;    }  }  res[parseEdge(edge, start, end, reverse)] = true;  properties.borderSkipped = res;}function parseEdge(edge, a, b, reverse) {  if (reverse) {    edge = swap(edge, a, b);    edge = startEnd(edge, b, a);  } else {    edge = startEnd(edge, a, b);  }  return edge;}function swap(orig, v1, v2) {  return orig === v1 ? v2 : orig === v2 ? v1 : orig;}function startEnd(v, start, end) {  return v === 'start' ? start : v === 'end' ? end : v;}function setInflateAmount(properties, {inflateAmount}, ratio) {  properties.inflateAmount = inflateAmount === 'auto'    ? ratio === 1 ? 0.33 : 0    : inflateAmount;}class BarController extends DatasetController {  parsePrimitiveData(meta, data, start, count) {    return parseArrayOrPrimitive(meta, data, start, count);  }  parseArrayData(meta, data, start, count) {    return parseArrayOrPrimitive(meta, data, start, count);  }  parseObjectData(meta, data, start, count) {    const {iScale, vScale} = meta;    const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;    const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;    const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;    const parsed = [];    let i, ilen, item, obj;    for (i = start, ilen = start + count; i < ilen; ++i) {      obj = data[i];      item = {};      item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i);      parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i));    }    return parsed;  }  updateRangeFromParsed(range, scale, parsed, stack) {    super.updateRangeFromParsed(range, scale, parsed, stack);    const custom = parsed._custom;    if (custom && scale === this._cachedMeta.vScale) {      range.min = Math.min(range.min, custom.min);      range.max = Math.max(range.max, custom.max);    }  }  getMaxOverflow() {    return 0;  }  getLabelAndValue(index) {    const meta = this._cachedMeta;    const {iScale, vScale} = meta;    const parsed = this.getParsed(index);    const custom = parsed._custom;    const value = isFloatBar(custom)      ? '[' + custom.start + ', ' + custom.end + ']'      : '' + vScale.getLabelForValue(parsed[vScale.axis]);    return {      label: '' + iScale.getLabelForValue(parsed[iScale.axis]),      value    };  }  initialize() {    this.enableOptionSharing = true;    super.initialize();    const meta = this._cachedMeta;    meta.stack = this.getDataset().stack;  }  update(mode) {    const meta = this._cachedMeta;    this.updateElements(meta.data, 0, meta.data.length, mode);  }  updateElements(bars, start, count, mode) {    const reset = mode === 'reset';    const {index, _cachedMeta: {vScale}} = this;    const base = vScale.getBasePixel();    const horizontal = vScale.isHorizontal();    const ruler = this._getRuler();    const firstOpts = this.resolveDataElementOptions(start, mode);    const sharedOptions = this.getSharedOptions(firstOpts);    const includeOptions = this.includeOptions(mode, sharedOptions);    this.updateSharedOptions(sharedOptions, mode, firstOpts);    for (let i = start; i < start + count; i++) {      const parsed = this.getParsed(i);      const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : this._calculateBarValuePixels(i);      const ipixels = this._calculateBarIndexPixels(i, ruler);      const stack = (parsed._stacks || {})[vScale.axis];      const properties = {        horizontal,        base: vpixels.base,        enableBorderRadius: !stack || isFloatBar(parsed._custom) || (index === stack._top || index === stack._bottom),        x: horizontal ? vpixels.head : ipixels.center,        y: horizontal ? ipixels.center : vpixels.head,        height: horizontal ? ipixels.size : Math.abs(vpixels.size),        width: horizontal ? Math.abs(vpixels.size) : ipixels.size      };      if (includeOptions) {        properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode);      }      const options = properties.options || bars[i].options;      setBorderSkipped(properties, options, stack, index);      setInflateAmount(properties, options, ruler.ratio);      this.updateElement(bars[i], i, properties, mode);    }  }  _getStacks(last, dataIndex) {    const meta = this._cachedMeta;    const iScale = meta.iScale;    const metasets = iScale.getMatchingVisibleMetas(this._type);    const stacked = iScale.options.stacked;    const ilen = metasets.length;    const stacks = [];    let i, item;    for (i = 0; i < ilen; ++i) {      item = metasets[i];      if (!item.controller.options.grouped) {        continue;      }      if (typeof dataIndex !== 'undefined') {        const val = item.controller.getParsed(dataIndex)[          item.controller._cachedMeta.vScale.axis        ];        if (isNullOrUndef(val) || isNaN(val)) {          continue;        }      }      if (stacked === false || stacks.indexOf(item.stack) === -1 ||				(stacked === undefined && item.stack === undefined)) {        stacks.push(item.stack);      }      if (item.index === last) {        break;      }    }    if (!stacks.length) {      stacks.push(undefined);    }    return stacks;  }  _getStackCount(index) {    return this._getStacks(undefined, index).length;  }  _getStackIndex(datasetIndex, name, dataIndex) {    const stacks = this._getStacks(datasetIndex, dataIndex);    const index = (name !== undefined)      ? stacks.indexOf(name)      : -1;    return (index === -1)      ? stacks.length - 1      : index;  }  _getRuler() {    const opts = this.options;    const meta = this._cachedMeta;    const iScale = meta.iScale;    const pixels = [];    let i, ilen;    for (i = 0, ilen = meta.data.length; i < ilen; ++i) {      pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i));    }    const barThickness = opts.barThickness;    const min = barThickness || computeMinSampleSize(meta);    return {      min,      pixels,      start: iScale._startPixel,      end: iScale._endPixel,      stackCount: this._getStackCount(),      scale: iScale,      grouped: opts.grouped,      ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage    };  }  _calculateBarValuePixels(index) {    const {_cachedMeta: {vScale, _stacked}, options: {base: baseValue, minBarLength}} = this;    const actualBase = baseValue || 0;    const parsed = this.getParsed(index);    const custom = parsed._custom;    const floating = isFloatBar(custom);    let value = parsed[vScale.axis];    let start = 0;    let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value;    let head, size;    if (length !== value) {      start = length - value;      length = value;    }    if (floating) {      value = custom.barStart;      length = custom.barEnd - custom.barStart;      if (value !== 0 && sign(value) !== sign(custom.barEnd)) {        start = 0;      }      start += value;    }    const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start;    let base = vScale.getPixelForValue(startValue);    if (this.chart.getDataVisibility(index)) {      head = vScale.getPixelForValue(start + length);    } else {      head = base;    }    size = head - base;    if (Math.abs(size) < minBarLength) {      size = barSign(size, vScale, actualBase) * minBarLength;      if (value === actualBase) {        base -= size / 2;      }      head = base + size;    }    if (base === vScale.getPixelForValue(actualBase)) {      const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2;      base += halfGrid;      size -= halfGrid;    }    return {      size,      base,      head,      center: head + size / 2    };  }  _calculateBarIndexPixels(index, ruler) {    const scale = ruler.scale;    const options = this.options;    const skipNull = options.skipNull;    const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity);    let center, size;    if (ruler.grouped) {      const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount;      const range = options.barThickness === 'flex'        ? computeFlexCategoryTraits(index, ruler, options, stackCount)        : computeFitCategoryTraits(index, ruler, options, stackCount);      const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined);      center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);      size = Math.min(maxBarThickness, range.chunk * range.ratio);    } else {      center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index);      size = Math.min(maxBarThickness, ruler.min * ruler.ratio);    }    return {      base: center - size / 2,      head: center + size / 2,      center,      size    };  }  draw() {    const meta = this._cachedMeta;    const vScale = meta.vScale;    const rects = meta.data;    const ilen = rects.length;    let i = 0;    for (; i < ilen; ++i) {      if (this.getParsed(i)[vScale.axis] !== null) {        rects[i].draw(this._ctx);      }    }  }}BarController.id = 'bar';BarController.defaults = {  datasetElementType: false,  dataElementType: 'bar',  categoryPercentage: 0.8,  barPercentage: 0.9,  grouped: true,  animations: {    numbers: {      type: 'number',      properties: ['x', 'y', 'base', 'width', 'height']    }  }};BarController.overrides = {  scales: {    _index_: {      type: 'category',      offset: true,      grid: {        offset: true      }    },    _value_: {      type: 'linear',      beginAtZero: true,    }  }};class BubbleController extends DatasetController {  initialize() {    this.enableOptionSharing = true;    super.initialize();  }  parsePrimitiveData(meta, data, start, count) {    const parsed = super.parsePrimitiveData(meta, data, start, count);    for (let i = 0; i < parsed.length; i++) {      parsed[i]._custom = this.resolveDataElementOptions(i + start).radius;    }    return parsed;  }  parseArrayData(meta, data, start, count) {    const parsed = super.parseArrayData(meta, data, start, count);    for (let i = 0; i < parsed.length; i++) {      const item = data[start + i];      parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius);    }    return parsed;  }  parseObjectData(meta, data, start, count) {    const parsed = super.parseObjectData(meta, data, start, count);    for (let i = 0; i < parsed.length; i++) {      const item = data[start + i];      parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius);    }    return parsed;  }  getMaxOverflow() {    const data = this._cachedMeta.data;    let max = 0;    for (let i = data.length - 1; i >= 0; --i) {      max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);    }    return max > 0 && max;  }  getLabelAndValue(index) {    const meta = this._cachedMeta;    const {xScale, yScale} = meta;    const parsed = this.getParsed(index);    const x = xScale.getLabelForValue(parsed.x);    const y = yScale.getLabelForValue(parsed.y);    const r = parsed._custom;    return {      label: meta.label,      value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'    };  }  update(mode) {    const points = this._cachedMeta.data;    this.updateElements(points, 0, points.length, mode);  }  updateElements(points, start, count, mode) {    const reset = mode === 'reset';    const {iScale, vScale} = this._cachedMeta;    const firstOpts = this.resolveDataElementOptions(start, mode);    const sharedOptions = this.getSharedOptions(firstOpts);    const includeOptions = this.includeOptions(mode, sharedOptions);    const iAxis = iScale.axis;    const vAxis = vScale.axis;    for (let i = start; i < start + count; i++) {      const point = points[i];      const parsed = !reset && this.getParsed(i);      const properties = {};      const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]);      const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]);      properties.skip = isNaN(iPixel) || isNaN(vPixel);      if (includeOptions) {        properties.options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);        if (reset) {          properties.options.radius = 0;        }      }      this.updateElement(point, i, properties, mode);    }    this.updateSharedOptions(sharedOptions, mode, firstOpts);  }  resolveDataElementOptions(index, mode) {    const parsed = this.getParsed(index);    let values = super.resolveDataElementOptions(index, mode);    if (values.$shared) {      values = Object.assign({}, values, {$shared: false});    }    const radius = values.radius;    if (mode !== 'active') {      values.radius = 0;    }    values.radius += valueOrDefault(parsed && parsed._custom, radius);    return values;  }}BubbleController.id = 'bubble';BubbleController.defaults = {  datasetElementType: false,  dataElementType: 'point',  animations: {    numbers: {      type: 'number',      properties: ['x', 'y', 'borderWidth', 'radius']    }  }};BubbleController.overrides = {  scales: {    x: {      type: 'linear'    },    y: {      type: 'linear'    }  },  plugins: {    tooltip: {      callbacks: {        title() {          return '';        }      }    }  }};function getRatioAndOffset(rotation, circumference, cutout) {  let ratioX = 1;  let ratioY = 1;  let offsetX = 0;  let offsetY = 0;  if (circumference < TAU) {    const startAngle = rotation;    const endAngle = startAngle + circumference;    const startX = Math.cos(startAngle);    const startY = Math.sin(startAngle);    const endX = Math.cos(endAngle);    const endY = Math.sin(endAngle);    const calcMax = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout);    const calcMin = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout);    const maxX = calcMax(0, startX, endX);    const maxY = calcMax(HALF_PI, startY, endY);    const minX = calcMin(PI, startX, endX);    const minY = calcMin(PI + HALF_PI, startY, endY);    ratioX = (maxX - minX) / 2;    ratioY = (maxY - minY) / 2;    offsetX = -(maxX + minX) / 2;    offsetY = -(maxY + minY) / 2;  }  return {ratioX, ratioY, offsetX, offsetY};}class DoughnutController extends DatasetController {  constructor(chart, datasetIndex) {    super(chart, datasetIndex);    this.enableOptionSharing = true;    this.innerRadius = undefined;    this.outerRadius = undefined;    this.offsetX = undefined;    this.offsetY = undefined;  }  linkScales() {}  parse(start, count) {    const data = this.getDataset().data;    const meta = this._cachedMeta;    if (this._parsing === false) {      meta._parsed = data;    } else {      let getter = (i) => +data[i];      if (isObject(data[start])) {        const {key = 'value'} = this._parsing;        getter = (i) => +resolveObjectKey(data[i], key);      }      let i, ilen;      for (i = start, ilen = start + count; i < ilen; ++i) {        meta._parsed[i] = getter(i);      }    }  }  _getRotation() {    return toRadians(this.options.rotation - 90);  }  _getCircumference() {    return toRadians(this.options.circumference);  }  _getRotationExtents() {    let min = TAU;    let max = -TAU;    for (let i = 0; i < this.chart.data.datasets.length; ++i) {      if (this.chart.isDatasetVisible(i)) {        const controller = this.chart.getDatasetMeta(i).controller;        const rotation = controller._getRotation();        const circumference = controller._getCircumference();        min = Math.min(min, rotation);        max = Math.max(max, rotation + circumference);      }    }    return {      rotation: min,      circumference: max - min,    };  }  update(mode) {    const chart = this.chart;    const {chartArea} = chart;    const meta = this._cachedMeta;    const arcs = meta.data;    const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing;    const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0);    const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1);    const chartWeight = this._getRingWeight(this.index);    const {circumference, rotation} = this._getRotationExtents();    const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout);    const maxWidth = (chartArea.width - spacing) / ratioX;    const maxHeight = (chartArea.height - spacing) / ratioY;    const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);    const outerRadius = toDimension(this.options.radius, maxRadius);    const innerRadius = Math.max(outerRadius * cutout, 0);    const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal();    this.offsetX = offsetX * outerRadius;    this.offsetY = offsetY * outerRadius;    meta.total = this.calculateTotal();    this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index);    this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0);    this.updateElements(arcs, 0, arcs.length, mode);  }  _circumference(i, reset) {    const opts = this.options;    const meta = this._cachedMeta;    const circumference = this._getCircumference();    if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) {      return 0;    }    return this.calculateCircumference(meta._parsed[i] * circumference / TAU);  }  updateElements(arcs, start, count, mode) {    const reset = mode === 'reset';    const chart = this.chart;    const chartArea = chart.chartArea;    const opts = chart.options;    const animationOpts = opts.animation;    const centerX = (chartArea.left + chartArea.right) / 2;    const centerY = (chartArea.top + chartArea.bottom) / 2;    const animateScale = reset && animationOpts.animateScale;    const innerRadius = animateScale ? 0 : this.innerRadius;    const outerRadius = animateScale ? 0 : this.outerRadius;    const firstOpts = this.resolveDataElementOptions(start, mode);    const sharedOptions = this.getSharedOptions(firstOpts);    const includeOptions = this.includeOptions(mode, sharedOptions);    let startAngle = this._getRotation();    let i;    for (i = 0; i < start; ++i) {      startAngle += this._circumference(i, reset);    }    for (i = start; i < start + count; ++i) {      const circumference = this._circumference(i, reset);      const arc = arcs[i];      const properties = {        x: centerX + this.offsetX,        y: centerY + this.offsetY,        startAngle,        endAngle: startAngle + circumference,        circumference,        outerRadius,        innerRadius      };      if (includeOptions) {        properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode);      }      startAngle += circumference;      this.updateElement(arc, i, properties, mode);    }    this.updateSharedOptions(sharedOptions, mode, firstOpts);  }  calculateTotal() {    const meta = this._cachedMeta;    const metaData = meta.data;    let total = 0;    let i;    for (i = 0; i < metaData.length; i++) {      const value = meta._parsed[i];      if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) {        total += Math.abs(value);      }    }    return total;  }  calculateCircumference(value) {    const total = this._cachedMeta.total;    if (total > 0 && !isNaN(value)) {      return TAU * (Math.abs(value) / total);    }    return 0;  }  getLabelAndValue(index) {    const meta = this._cachedMeta;    const chart = this.chart;    const labels = chart.data.labels || [];    const value = formatNumber(meta._parsed[index], chart.options.locale);    return {      label: labels[index] || '',      value,    };  }  getMaxBorderWidth(arcs) {    let max = 0;    const chart = this.chart;    let i, ilen, meta, controller, options;    if (!arcs) {      for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {        if (chart.isDatasetVisible(i)) {          meta = chart.getDatasetMeta(i);          arcs = meta.data;          controller = meta.controller;          break;        }      }    }    if (!arcs) {      return 0;    }    for (i = 0, ilen = arcs.length; i < ilen; ++i) {      options = controller.resolveDataElementOptions(i);      if (options.borderAlign !== 'inner') {        max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);      }    }    return max;  }  getMaxOffset(arcs) {    let max = 0;    for (let i = 0, ilen = arcs.length; i < ilen; ++i) {      const options = this.resolveDataElementOptions(i);      max = Math.max(max, options.offset || 0, options.hoverOffset || 0);    }    return max;  }  _getRingWeightOffset(datasetIndex) {    let ringWeightOffset = 0;    for (let i = 0; i < datasetIndex; ++i) {      if (this.chart.isDatasetVisible(i)) {        ringWeightOffset += this._getRingWeight(i);      }    }    return ringWeightOffset;  }  _getRingWeight(datasetIndex) {    return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0);  }  _getVisibleDatasetWeightTotal() {    return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;  }}DoughnutController.id = 'doughnut';DoughnutController.defaults = {  datasetElementType: false,  dataElementType: 'arc',  animation: {    animateRotate: true,    animateScale: false  },  animations: {    numbers: {      type: 'number',      properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing']    },  },  cutout: '50%',  rotation: 0,  circumference: 360,  radius: '100%',  spacing: 0,  indexAxis: 'r',};DoughnutController.descriptors = {  _scriptable: (name) => name !== 'spacing',  _indexable: (name) => name !== 'spacing',};DoughnutController.overrides = {  aspectRatio: 1,  plugins: {    legend: {      labels: {        generateLabels(chart) {          const data = chart.data;          if (data.labels.length && data.datasets.length) {            const {labels: {pointStyle}} = chart.legend.options;            return data.labels.map((label, i) => {              const meta = chart.getDatasetMeta(0);              const style = meta.controller.getStyle(i);              return {                text: label,                fillStyle: style.backgroundColor,                strokeStyle: style.borderColor,                lineWidth: style.borderWidth,                pointStyle: pointStyle,                hidden: !chart.getDataVisibility(i),                index: i              };            });          }          return [];        }      },      onClick(e, legendItem, legend) {        legend.chart.toggleDataVisibility(legendItem.index);        legend.chart.update();      }    },    tooltip: {      callbacks: {        title() {          return '';        },        label(tooltipItem) {          let dataLabel = tooltipItem.label;          const value = ': ' + tooltipItem.formattedValue;          if (isArray(dataLabel)) {            dataLabel = dataLabel.slice();            dataLabel[0] += value;          } else {            dataLabel += value;          }          return dataLabel;        }      }    }  }};class LineController extends DatasetController {  initialize() {    this.enableOptionSharing = true;    super.initialize();  }  update(mode) {    const meta = this._cachedMeta;    const {dataset: line, data: points = [], _dataset} = meta;    const animationsDisabled = this.chart._animationsDisabled;    let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled);    this._drawStart = start;    this._drawCount = count;    if (scaleRangesChanged(meta)) {      start = 0;      count = points.length;    }    line._chart = this.chart;    line._datasetIndex = this.index;    line._decimated = !!_dataset._decimated;    line.points = points;    const options = this.resolveDatasetElementOptions(mode);    if (!this.options.showLine) {      options.borderWidth = 0;    }    options.segment = this.options.segment;    this.updateElement(line, undefined, {      animated: !animationsDisabled,      options    }, mode);    this.updateElements(points, start, count, mode);  }  updateElements(points, start, count, mode) {    const reset = mode === 'reset';    const {iScale, vScale, _stacked, _dataset} = this._cachedMeta;    const firstOpts = this.resolveDataElementOptions(start, mode);    const sharedOptions = this.getSharedOptions(firstOpts);    const includeOptions = this.includeOptions(mode, sharedOptions);    const iAxis = iScale.axis;    const vAxis = vScale.axis;    const {spanGaps, segment} = this.options;    const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;    const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';    let prevParsed = start > 0 && this.getParsed(start - 1);    for (let i = start; i < start + count; ++i) {      const point = points[i];      const parsed = this.getParsed(i);      const properties = directUpdate ? point : {};      const nullData = isNullOrUndef(parsed[vAxis]);      const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);      const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);      properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;      properties.stop = i > 0 && (parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;      if (segment) {        properties.parsed = parsed;        properties.raw = _dataset.data[i];      }      if (includeOptions) {        properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);      }      if (!directUpdate) {        this.updateElement(point, i, properties, mode);      }      prevParsed = parsed;    }    this.updateSharedOptions(sharedOptions, mode, firstOpts);  }  getMaxOverflow() {    const meta = this._cachedMeta;    const dataset = meta.dataset;    const border = dataset.options && dataset.options.borderWidth || 0;    const data = meta.data || [];    if (!data.length) {      return border;    }    const firstPoint = data[0].size(this.resolveDataElementOptions(0));    const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));    return Math.max(border, firstPoint, lastPoint) / 2;  }  draw() {    const meta = this._cachedMeta;    meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis);    super.draw();  }}LineController.id = 'line';LineController.defaults = {  datasetElementType: 'line',  dataElementType: 'point',  showLine: true,  spanGaps: false,};LineController.overrides = {  scales: {    _index_: {      type: 'category',    },    _value_: {      type: 'linear',    },  }};function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) {  const pointCount = points.length;  let start = 0;  let count = pointCount;  if (meta._sorted) {    const {iScale, _parsed} = meta;    const axis = iScale.axis;    const {min, max, minDefined, maxDefined} = iScale.getUserBounds();    if (minDefined) {      start = _limitValue(Math.min(        _lookupByKey(_parsed, iScale.axis, min).lo,        animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo),      0, pointCount - 1);    }    if (maxDefined) {      count = _limitValue(Math.max(        _lookupByKey(_parsed, iScale.axis, max).hi + 1,        animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1),      start, pointCount) - start;    } else {      count = pointCount - start;    }  }  return {start, count};}function scaleRangesChanged(meta) {  const {xScale, yScale, _scaleRanges} = meta;  const newRanges = {    xmin: xScale.min,    xmax: xScale.max,    ymin: yScale.min,    ymax: yScale.max  };  if (!_scaleRanges) {    meta._scaleRanges = newRanges;    return true;  }  const changed = _scaleRanges.xmin !== xScale.min		|| _scaleRanges.xmax !== xScale.max		|| _scaleRanges.ymin !== yScale.min		|| _scaleRanges.ymax !== yScale.max;  Object.assign(_scaleRanges, newRanges);  return changed;}class PolarAreaController extends DatasetController {  constructor(chart, datasetIndex) {    super(chart, datasetIndex);    this.innerRadius = undefined;    this.outerRadius = undefined;  }  getLabelAndValue(index) {    const meta = this._cachedMeta;    const chart = this.chart;    const labels = chart.data.labels || [];    const value = formatNumber(meta._parsed[index].r, chart.options.locale);    return {      label: labels[index] || '',      value,    };  }  update(mode) {    const arcs = this._cachedMeta.data;    this._updateRadius();    this.updateElements(arcs, 0, arcs.length, mode);  }  _updateRadius() {    const chart = this.chart;    const chartArea = chart.chartArea;    const opts = chart.options;    const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);    const outerRadius = Math.max(minSize / 2, 0);    const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);    const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();    this.outerRadius = outerRadius - (radiusLength * this.index);    this.innerRadius = this.outerRadius - radiusLength;  }  updateElements(arcs, start, count, mode) {    const reset = mode === 'reset';    const chart = this.chart;    const dataset = this.getDataset();    const opts = chart.options;    const animationOpts = opts.animation;    const scale = this._cachedMeta.rScale;    const centerX = scale.xCenter;    const centerY = scale.yCenter;    const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI;    let angle = datasetStartAngle;    let i;    const defaultAngle = 360 / this.countVisibleElements();    for (i = 0; i < start; ++i) {      angle += this._computeAngle(i, mode, defaultAngle);    }    for (i = start; i < start + count; i++) {      const arc = arcs[i];      let startAngle = angle;      let endAngle = angle + this._computeAngle(i, mode, defaultAngle);      let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0;      angle = endAngle;      if (reset) {        if (animationOpts.animateScale) {          outerRadius = 0;        }        if (animationOpts.animateRotate) {          startAngle = endAngle = datasetStartAngle;        }      }      const properties = {        x: centerX,        y: centerY,        innerRadius: 0,        outerRadius,        startAngle,        endAngle,        options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode)      };      this.updateElement(arc, i, properties, mode);    }  }  countVisibleElements() {    const dataset = this.getDataset();    const meta = this._cachedMeta;    let count = 0;    meta.data.forEach((element, index) => {      if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) {        count++;      }    });    return count;  }  _computeAngle(index, mode, defaultAngle) {    return this.chart.getDataVisibility(index)      ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle)      : 0;  }}PolarAreaController.id = 'polarArea';PolarAreaController.defaults = {  dataElementType: 'arc',  animation: {    animateRotate: true,    animateScale: true  },  animations: {    numbers: {      type: 'number',      properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius']    },  },  indexAxis: 'r',  startAngle: 0,};PolarAreaController.overrides = {  aspectRatio: 1,  plugins: {    legend: {      labels: {        generateLabels(chart) {          const data = chart.data;          if (data.labels.length && data.datasets.length) {            const {labels: {pointStyle}} = chart.legend.options;            return data.labels.map((label, i) => {              const meta = chart.getDatasetMeta(0);              const style = meta.controller.getStyle(i);              return {                text: label,                fillStyle: style.backgroundColor,                strokeStyle: style.borderColor,                lineWidth: style.borderWidth,                pointStyle: pointStyle,                hidden: !chart.getDataVisibility(i),                index: i              };            });          }          return [];        }      },      onClick(e, legendItem, legend) {        legend.chart.toggleDataVisibility(legendItem.index);        legend.chart.update();      }    },    tooltip: {      callbacks: {        title() {          return '';        },        label(context) {          return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue;        }      }    }  },  scales: {    r: {      type: 'radialLinear',      angleLines: {        display: false      },      beginAtZero: true,      grid: {        circular: true      },      pointLabels: {        display: false      },      startAngle: 0    }  }};class PieController extends DoughnutController {}PieController.id = 'pie';PieController.defaults = {  cutout: 0,  rotation: 0,  circumference: 360,  radius: '100%'};class RadarController extends DatasetController {  getLabelAndValue(index) {    const vScale = this._cachedMeta.vScale;    const parsed = this.getParsed(index);    return {      label: vScale.getLabels()[index],      value: '' + vScale.getLabelForValue(parsed[vScale.axis])    };  }  update(mode) {    const meta = this._cachedMeta;    const line = meta.dataset;    const points = meta.data || [];    const labels = meta.iScale.getLabels();    line.points = points;    if (mode !== 'resize') {      const options = this.resolveDatasetElementOptions(mode);      if (!this.options.showLine) {        options.borderWidth = 0;      }      const properties = {        _loop: true,        _fullLoop: labels.length === points.length,        options      };      this.updateElement(line, undefined, properties, mode);    }    this.updateElements(points, 0, points.length, mode);  }  updateElements(points, start, count, mode) {    const dataset = this.getDataset();    const scale = this._cachedMeta.rScale;    const reset = mode === 'reset';    for (let i = start; i < start + count; i++) {      const point = points[i];      const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);      const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]);      const x = reset ? scale.xCenter : pointPosition.x;      const y = reset ? scale.yCenter : pointPosition.y;      const properties = {        x,        y,        angle: pointPosition.angle,        skip: isNaN(x) || isNaN(y),        options      };      this.updateElement(point, i, properties, mode);    }  }}RadarController.id = 'radar';RadarController.defaults = {  datasetElementType: 'line',  dataElementType: 'point',  indexAxis: 'r',  showLine: true,  elements: {    line: {      fill: 'start'    }  },};RadarController.overrides = {  aspectRatio: 1,  scales: {    r: {      type: 'radialLinear',    }  }};class ScatterController extends LineController {}ScatterController.id = 'scatter';ScatterController.defaults = {  showLine: false,  fill: false};ScatterController.overrides = {  interaction: {    mode: 'point'  },  plugins: {    tooltip: {      callbacks: {        title() {          return '';        },        label(item) {          return '(' + item.label + ', ' + item.formattedValue + ')';        }      }    }  },  scales: {    x: {      type: 'linear'    },    y: {      type: 'linear'    }  }};var controllers = /*#__PURE__*/Object.freeze({__proto__: null,BarController: BarController,BubbleController: BubbleController,DoughnutController: DoughnutController,LineController: LineController,PolarAreaController: PolarAreaController,PieController: PieController,RadarController: RadarController,ScatterController: ScatterController});function clipArc(ctx, element, endAngle) {  const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element;  let angleMargin = pixelMargin / outerRadius;  ctx.beginPath();  ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);  if (innerRadius > pixelMargin) {    angleMargin = pixelMargin / innerRadius;    ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);  } else {    ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI);  }  ctx.closePath();  ctx.clip();}function toRadiusCorners(value) {  return _readValueToProps(value, ['outerStart', 'outerEnd', 'innerStart', 'innerEnd']);}function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) {  const o = toRadiusCorners(arc.options.borderRadius);  const halfThickness = (outerRadius - innerRadius) / 2;  const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2);  const computeOuterLimit = (val) => {    const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2;    return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit));  };  return {    outerStart: computeOuterLimit(o.outerStart),    outerEnd: computeOuterLimit(o.outerEnd),    innerStart: _limitValue(o.innerStart, 0, innerLimit),    innerEnd: _limitValue(o.innerEnd, 0, innerLimit),  };}function rThetaToXY(r, theta, x, y) {  return {    x: x + r * Math.cos(theta),    y: y + r * Math.sin(theta),  };}function pathArc(ctx, element, offset, spacing, end) {  const {x, y, startAngle: start, pixelMargin, innerRadius: innerR} = element;  const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);  const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0;  let spacingOffset = 0;  const alpha = end - start;  if (spacing) {    const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0;    const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0;    const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2;    const adjustedAngle = avNogSpacingRadius !== 0 ? (alpha * avNogSpacingRadius) / (avNogSpacingRadius + spacing) : alpha;    spacingOffset = (alpha - adjustedAngle) / 2;  }  const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius;  const angleOffset = (alpha - beta) / 2;  const startAngle = start + angleOffset + spacingOffset;  const endAngle = end - angleOffset - spacingOffset;  const {outerStart, outerEnd, innerStart, innerEnd} = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle);  const outerStartAdjustedRadius = outerRadius - outerStart;  const outerEndAdjustedRadius = outerRadius - outerEnd;  const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius;  const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius;  const innerStartAdjustedRadius = innerRadius + innerStart;  const innerEndAdjustedRadius = innerRadius + innerEnd;  const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius;  const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius;  ctx.beginPath();  ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle);  if (outerEnd > 0) {    const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);    ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI);  }  const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);  ctx.lineTo(p4.x, p4.y);  if (innerEnd > 0) {    const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);    ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI);  }  ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true);  if (innerStart > 0) {    const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);    ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI);  }  const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);  ctx.lineTo(p8.x, p8.y);  if (outerStart > 0) {    const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);    ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle);  }  ctx.closePath();}function drawArc(ctx, element, offset, spacing) {  const {fullCircles, startAngle, circumference} = element;  let endAngle = element.endAngle;  if (fullCircles) {    pathArc(ctx, element, offset, spacing, startAngle + TAU);    for (let i = 0; i < fullCircles; ++i) {      ctx.fill();    }    if (!isNaN(circumference)) {      endAngle = startAngle + circumference % TAU;      if (circumference % TAU === 0) {        endAngle += TAU;      }    }  }  pathArc(ctx, element, offset, spacing, endAngle);  ctx.fill();  return endAngle;}function drawFullCircleBorders(ctx, element, inner) {  const {x, y, startAngle, pixelMargin, fullCircles} = element;  const outerRadius = Math.max(element.outerRadius - pixelMargin, 0);  const innerRadius = element.innerRadius + pixelMargin;  let i;  if (inner) {    clipArc(ctx, element, startAngle + TAU);  }  ctx.beginPath();  ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true);  for (i = 0; i < fullCircles; ++i) {    ctx.stroke();  }  ctx.beginPath();  ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU);  for (i = 0; i < fullCircles; ++i) {    ctx.stroke();  }}function drawBorder(ctx, element, offset, spacing, endAngle) {  const {options} = element;  const {borderWidth, borderJoinStyle} = options;  const inner = options.borderAlign === 'inner';  if (!borderWidth) {    return;  }  if (inner) {    ctx.lineWidth = borderWidth * 2;    ctx.lineJoin = borderJoinStyle || 'round';  } else {    ctx.lineWidth = borderWidth;    ctx.lineJoin = borderJoinStyle || 'bevel';  }  if (element.fullCircles) {    drawFullCircleBorders(ctx, element, inner);  }  if (inner) {    clipArc(ctx, element, endAngle);  }  pathArc(ctx, element, offset, spacing, endAngle);  ctx.stroke();}class ArcElement extends Element {  constructor(cfg) {    super();    this.options = undefined;    this.circumference = undefined;    this.startAngle = undefined;    this.endAngle = undefined;    this.innerRadius = undefined;    this.outerRadius = undefined;    this.pixelMargin = 0;    this.fullCircles = 0;    if (cfg) {      Object.assign(this, cfg);    }  }  inRange(chartX, chartY, useFinalPosition) {    const point = this.getProps(['x', 'y'], useFinalPosition);    const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY});    const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([      'startAngle',      'endAngle',      'innerRadius',      'outerRadius',      'circumference'    ], useFinalPosition);    const rAdjust = this.options.spacing / 2;    const _circumference = valueOrDefault(circumference, endAngle - startAngle);    const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle);    const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust);    return (betweenAngles && withinRadius);  }  getCenterPoint(useFinalPosition) {    const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([      'x',      'y',      'startAngle',      'endAngle',      'innerRadius',      'outerRadius',      'circumference',    ], useFinalPosition);    const {offset, spacing} = this.options;    const halfAngle = (startAngle + endAngle) / 2;    const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2;    return {      x: x + Math.cos(halfAngle) * halfRadius,      y: y + Math.sin(halfAngle) * halfRadius    };  }  tooltipPosition(useFinalPosition) {    return this.getCenterPoint(useFinalPosition);  }  draw(ctx) {    const {options, circumference} = this;    const offset = (options.offset || 0) / 2;    const spacing = (options.spacing || 0) / 2;    this.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0;    this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0;    if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) {      return;    }    ctx.save();    let radiusOffset = 0;    if (offset) {      radiusOffset = offset / 2;      const halfAngle = (this.startAngle + this.endAngle) / 2;      ctx.translate(Math.cos(halfAngle) * radiusOffset, Math.sin(halfAngle) * radiusOffset);      if (this.circumference >= PI) {        radiusOffset = offset;      }    }    ctx.fillStyle = options.backgroundColor;    ctx.strokeStyle = options.borderColor;    const endAngle = drawArc(ctx, this, radiusOffset, spacing);    drawBorder(ctx, this, radiusOffset, spacing, endAngle);    ctx.restore();  }}ArcElement.id = 'arc';ArcElement.defaults = {  borderAlign: 'center',  borderColor: '#fff',  borderJoinStyle: undefined,  borderRadius: 0,  borderWidth: 2,  offset: 0,  spacing: 0,  angle: undefined,};ArcElement.defaultRoutes = {  backgroundColor: 'backgroundColor'};function setStyle(ctx, options, style = options) {  ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle);  ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash));  ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset);  ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle);  ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth);  ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor);}function lineTo(ctx, previous, target) {  ctx.lineTo(target.x, target.y);}function getLineMethod(options) {  if (options.stepped) {    return _steppedLineTo;  }  if (options.tension || options.cubicInterpolationMode === 'monotone') {    return _bezierCurveTo;  }  return lineTo;}function pathVars(points, segment, params = {}) {  const count = points.length;  const {start: paramsStart = 0, end: paramsEnd = count - 1} = params;  const {start: segmentStart, end: segmentEnd} = segment;  const start = Math.max(paramsStart, segmentStart);  const end = Math.min(paramsEnd, segmentEnd);  const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd;  return {    count,    start,    loop: segment.loop,    ilen: end < start && !outside ? count + end - start : end - start  };}function pathSegment(ctx, line, segment, params) {  const {points, options} = line;  const {count, start, loop, ilen} = pathVars(points, segment, params);  const lineMethod = getLineMethod(options);  let {move = true, reverse} = params || {};  let i, point, prev;  for (i = 0; i <= ilen; ++i) {    point = points[(start + (reverse ? ilen - i : i)) % count];    if (point.skip) {      continue;    } else if (move) {      ctx.moveTo(point.x, point.y);      move = false;    } else {      lineMethod(ctx, prev, point, reverse, options.stepped);    }    prev = point;  }  if (loop) {    point = points[(start + (reverse ? ilen : 0)) % count];    lineMethod(ctx, prev, point, reverse, options.stepped);  }  return !!loop;}function fastPathSegment(ctx, line, segment, params) {  const points = line.points;  const {count, start, ilen} = pathVars(points, segment, params);  const {move = true, reverse} = params || {};  let avgX = 0;  let countX = 0;  let i, point, prevX, minY, maxY, lastY;  const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count;  const drawX = () => {    if (minY !== maxY) {      ctx.lineTo(avgX, maxY);      ctx.lineTo(avgX, minY);      ctx.lineTo(avgX, lastY);    }  };  if (move) {    point = points[pointIndex(0)];    ctx.moveTo(point.x, point.y);  }  for (i = 0; i <= ilen; ++i) {    point = points[pointIndex(i)];    if (point.skip) {      continue;    }    const x = point.x;    const y = point.y;    const truncX = x | 0;    if (truncX === prevX) {      if (y < minY) {        minY = y;      } else if (y > maxY) {        maxY = y;      }      avgX = (countX * avgX + x) / ++countX;    } else {      drawX();      ctx.lineTo(x, y);      prevX = truncX;      countX = 0;      minY = maxY = y;    }    lastY = y;  }  drawX();}function _getSegmentMethod(line) {  const opts = line.options;  const borderDash = opts.borderDash && opts.borderDash.length;  const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash;  return useFastPath ? fastPathSegment : pathSegment;}function _getInterpolationMethod(options) {  if (options.stepped) {    return _steppedInterpolation;  }  if (options.tension || options.cubicInterpolationMode === 'monotone') {    return _bezierInterpolation;  }  return _pointInLine;}function strokePathWithCache(ctx, line, start, count) {  let path = line._path;  if (!path) {    path = line._path = new Path2D();    if (line.path(path, start, count)) {      path.closePath();    }  }  setStyle(ctx, line.options);  ctx.stroke(path);}function strokePathDirect(ctx, line, start, count) {  const {segments, options} = line;  const segmentMethod = _getSegmentMethod(line);  for (const segment of segments) {    setStyle(ctx, options, segment.style);    ctx.beginPath();    if (segmentMethod(ctx, line, segment, {start, end: start + count - 1})) {      ctx.closePath();    }    ctx.stroke();  }}const usePath2D = typeof Path2D === 'function';function draw(ctx, line, start, count) {  if (usePath2D && !line.options.segment) {    strokePathWithCache(ctx, line, start, count);  } else {    strokePathDirect(ctx, line, start, count);  }}class LineElement extends Element {  constructor(cfg) {    super();    this.animated = true;    this.options = undefined;    this._chart = undefined;    this._loop = undefined;    this._fullLoop = undefined;    this._path = undefined;    this._points = undefined;    this._segments = undefined;    this._decimated = false;    this._pointsUpdated = false;    this._datasetIndex = undefined;    if (cfg) {      Object.assign(this, cfg);    }  }  updateControlPoints(chartArea, indexAxis) {    const options = this.options;    if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) {      const loop = options.spanGaps ? this._loop : this._fullLoop;      _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis);      this._pointsUpdated = true;    }  }  set points(points) {    this._points = points;    delete this._segments;    delete this._path;    this._pointsUpdated = false;  }  get points() {    return this._points;  }  get segments() {    return this._segments || (this._segments = _computeSegments(this, this.options.segment));  }  first() {    const segments = this.segments;    const points = this.points;    return segments.length && points[segments[0].start];  }  last() {    const segments = this.segments;    const points = this.points;    const count = segments.length;    return count && points[segments[count - 1].end];  }  interpolate(point, property) {    const options = this.options;    const value = point[property];    const points = this.points;    const segments = _boundSegments(this, {property, start: value, end: value});    if (!segments.length) {      return;    }    const result = [];    const _interpolate = _getInterpolationMethod(options);    let i, ilen;    for (i = 0, ilen = segments.length; i < ilen; ++i) {      const {start, end} = segments[i];      const p1 = points[start];      const p2 = points[end];      if (p1 === p2) {        result.push(p1);        continue;      }      const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));      const interpolated = _interpolate(p1, p2, t, options.stepped);      interpolated[property] = point[property];      result.push(interpolated);    }    return result.length === 1 ? result[0] : result;  }  pathSegment(ctx, segment, params) {    const segmentMethod = _getSegmentMethod(this);    return segmentMethod(ctx, this, segment, params);  }  path(ctx, start, count) {    const segments = this.segments;    const segmentMethod = _getSegmentMethod(this);    let loop = this._loop;    start = start || 0;    count = count || (this.points.length - start);    for (const segment of segments) {      loop &= segmentMethod(ctx, this, segment, {start, end: start + count - 1});    }    return !!loop;  }  draw(ctx, chartArea, start, count) {    const options = this.options || {};    const points = this.points || [];    if (points.length && options.borderWidth) {      ctx.save();      draw(ctx, this, start, count);      ctx.restore();    }    if (this.animated) {      this._pointsUpdated = false;      this._path = undefined;    }  }}LineElement.id = 'line';LineElement.defaults = {  borderCapStyle: 'butt',  borderDash: [],  borderDashOffset: 0,  borderJoinStyle: 'miter',  borderWidth: 3,  capBezierPoints: true,  cubicInterpolationMode: 'default',  fill: false,  spanGaps: false,  stepped: false,  tension: 0,};LineElement.defaultRoutes = {  backgroundColor: 'backgroundColor',  borderColor: 'borderColor'};LineElement.descriptors = {  _scriptable: true,  _indexable: (name) => name !== 'borderDash' && name !== 'fill',};function inRange$1(el, pos, axis, useFinalPosition) {  const options = el.options;  const {[axis]: value} = el.getProps([axis], useFinalPosition);  return (Math.abs(pos - value) < options.radius + options.hitRadius);}class PointElement extends Element {  constructor(cfg) {    super();    this.options = undefined;    this.parsed = undefined;    this.skip = undefined;    this.stop = undefined;    if (cfg) {      Object.assign(this, cfg);    }  }  inRange(mouseX, mouseY, useFinalPosition) {    const options = this.options;    const {x, y} = this.getProps(['x', 'y'], useFinalPosition);    return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2));  }  inXRange(mouseX, useFinalPosition) {    return inRange$1(this, mouseX, 'x', useFinalPosition);  }  inYRange(mouseY, useFinalPosition) {    return inRange$1(this, mouseY, 'y', useFinalPosition);  }  getCenterPoint(useFinalPosition) {    const {x, y} = this.getProps(['x', 'y'], useFinalPosition);    return {x, y};  }  size(options) {    options = options || this.options || {};    let radius = options.radius || 0;    radius = Math.max(radius, radius && options.hoverRadius || 0);    const borderWidth = radius && options.borderWidth || 0;    return (radius + borderWidth) * 2;  }  draw(ctx, area) {    const options = this.options;    if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) {      return;    }    ctx.strokeStyle = options.borderColor;    ctx.lineWidth = options.borderWidth;    ctx.fillStyle = options.backgroundColor;    drawPoint(ctx, options, this.x, this.y);  }  getRange() {    const options = this.options || {};    return options.radius + options.hitRadius;  }}PointElement.id = 'point';PointElement.defaults = {  borderWidth: 1,  hitRadius: 1,  hoverBorderWidth: 1,  hoverRadius: 4,  pointStyle: 'circle',  radius: 3,  rotation: 0};PointElement.defaultRoutes = {  backgroundColor: 'backgroundColor',  borderColor: 'borderColor'};function getBarBounds(bar, useFinalPosition) {  const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition);  let left, right, top, bottom, half;  if (bar.horizontal) {    half = height / 2;    left = Math.min(x, base);    right = Math.max(x, base);    top = y - half;    bottom = y + half;  } else {    half = width / 2;    left = x - half;    right = x + half;    top = Math.min(y, base);    bottom = Math.max(y, base);  }  return {left, top, right, bottom};}function skipOrLimit(skip, value, min, max) {  return skip ? 0 : _limitValue(value, min, max);}function parseBorderWidth(bar, maxW, maxH) {  const value = bar.options.borderWidth;  const skip = bar.borderSkipped;  const o = toTRBL(value);  return {    t: skipOrLimit(skip.top, o.top, 0, maxH),    r: skipOrLimit(skip.right, o.right, 0, maxW),    b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),    l: skipOrLimit(skip.left, o.left, 0, maxW)  };}function parseBorderRadius(bar, maxW, maxH) {  const {enableBorderRadius} = bar.getProps(['enableBorderRadius']);  const value = bar.options.borderRadius;  const o = toTRBLCorners(value);  const maxR = Math.min(maxW, maxH);  const skip = bar.borderSkipped;  const enableBorder = enableBorderRadius || isObject(value);  return {    topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR),    topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR),    bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR),    bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR)  };}function boundingRects(bar) {  const bounds = getBarBounds(bar);  const width = bounds.right - bounds.left;  const height = bounds.bottom - bounds.top;  const border = parseBorderWidth(bar, width / 2, height / 2);  const radius = parseBorderRadius(bar, width / 2, height / 2);  return {    outer: {      x: bounds.left,      y: bounds.top,      w: width,      h: height,      radius    },    inner: {      x: bounds.left + border.l,      y: bounds.top + border.t,      w: width - border.l - border.r,      h: height - border.t - border.b,      radius: {        topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),        topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),        bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),        bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)),      }    }  };}function inRange(bar, x, y, useFinalPosition) {  const skipX = x === null;  const skipY = y === null;  const skipBoth = skipX && skipY;  const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);  return bounds		&& (skipX || _isBetween(x, bounds.left, bounds.right))		&& (skipY || _isBetween(y, bounds.top, bounds.bottom));}function hasRadius(radius) {  return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;}function addNormalRectPath(ctx, rect) {  ctx.rect(rect.x, rect.y, rect.w, rect.h);}function inflateRect(rect, amount, refRect = {}) {  const x = rect.x !== refRect.x ? -amount : 0;  const y = rect.y !== refRect.y ? -amount : 0;  const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x;  const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y;  return {    x: rect.x + x,    y: rect.y + y,    w: rect.w + w,    h: rect.h + h,    radius: rect.radius  };}class BarElement extends Element {  constructor(cfg) {    super();    this.options = undefined;    this.horizontal = undefined;    this.base = undefined;    this.width = undefined;    this.height = undefined;    this.inflateAmount = undefined;    if (cfg) {      Object.assign(this, cfg);    }  }  draw(ctx) {    const {inflateAmount, options: {borderColor, backgroundColor}} = this;    const {inner, outer} = boundingRects(this);    const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath;    ctx.save();    if (outer.w !== inner.w || outer.h !== inner.h) {      ctx.beginPath();      addRectPath(ctx, inflateRect(outer, inflateAmount, inner));      ctx.clip();      addRectPath(ctx, inflateRect(inner, -inflateAmount, outer));      ctx.fillStyle = borderColor;      ctx.fill('evenodd');    }    ctx.beginPath();    addRectPath(ctx, inflateRect(inner, inflateAmount));    ctx.fillStyle = backgroundColor;    ctx.fill();    ctx.restore();  }  inRange(mouseX, mouseY, useFinalPosition) {    return inRange(this, mouseX, mouseY, useFinalPosition);  }  inXRange(mouseX, useFinalPosition) {    return inRange(this, mouseX, null, useFinalPosition);  }  inYRange(mouseY, useFinalPosition) {    return inRange(this, null, mouseY, useFinalPosition);  }  getCenterPoint(useFinalPosition) {    const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition);    return {      x: horizontal ? (x + base) / 2 : x,      y: horizontal ? y : (y + base) / 2    };  }  getRange(axis) {    return axis === 'x' ? this.width / 2 : this.height / 2;  }}BarElement.id = 'bar';BarElement.defaults = {  borderSkipped: 'start',  borderWidth: 0,  borderRadius: 0,  inflateAmount: 'auto',  pointStyle: undefined};BarElement.defaultRoutes = {  backgroundColor: 'backgroundColor',  borderColor: 'borderColor'};var elements = /*#__PURE__*/Object.freeze({__proto__: null,ArcElement: ArcElement,LineElement: LineElement,PointElement: PointElement,BarElement: BarElement});function lttbDecimation(data, start, count, availableWidth, options) {  const samples = options.samples || availableWidth;  if (samples >= count) {    return data.slice(start, start + count);  }  const decimated = [];  const bucketWidth = (count - 2) / (samples - 2);  let sampledIndex = 0;  const endIndex = start + count - 1;  let a = start;  let i, maxAreaPoint, maxArea, area, nextA;  decimated[sampledIndex++] = data[a];  for (i = 0; i < samples - 2; i++) {    let avgX = 0;    let avgY = 0;    let j;    const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start;    const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start;    const avgRangeLength = avgRangeEnd - avgRangeStart;    for (j = avgRangeStart; j < avgRangeEnd; j++) {      avgX += data[j].x;      avgY += data[j].y;    }    avgX /= avgRangeLength;    avgY /= avgRangeLength;    const rangeOffs = Math.floor(i * bucketWidth) + 1 + start;    const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start;    const {x: pointAx, y: pointAy} = data[a];    maxArea = area = -1;    for (j = rangeOffs; j < rangeTo; j++) {      area = 0.5 * Math.abs(        (pointAx - avgX) * (data[j].y - pointAy) -        (pointAx - data[j].x) * (avgY - pointAy)      );      if (area > maxArea) {        maxArea = area;        maxAreaPoint = data[j];        nextA = j;      }    }    decimated[sampledIndex++] = maxAreaPoint;    a = nextA;  }  decimated[sampledIndex++] = data[endIndex];  return decimated;}function minMaxDecimation(data, start, count, availableWidth) {  let avgX = 0;  let countX = 0;  let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY;  const decimated = [];  const endIndex = start + count - 1;  const xMin = data[start].x;  const xMax = data[endIndex].x;  const dx = xMax - xMin;  for (i = start; i < start + count; ++i) {    point = data[i];    x = (point.x - xMin) / dx * availableWidth;    y = point.y;    const truncX = x | 0;    if (truncX === prevX) {      if (y < minY) {        minY = y;        minIndex = i;      } else if (y > maxY) {        maxY = y;        maxIndex = i;      }      avgX = (countX * avgX + point.x) / ++countX;    } else {      const lastIndex = i - 1;      if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) {        const intermediateIndex1 = Math.min(minIndex, maxIndex);        const intermediateIndex2 = Math.max(minIndex, maxIndex);        if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) {          decimated.push({            ...data[intermediateIndex1],            x: avgX,          });        }        if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) {          decimated.push({            ...data[intermediateIndex2],            x: avgX          });        }      }      if (i > 0 && lastIndex !== startIndex) {        decimated.push(data[lastIndex]);      }      decimated.push(point);      prevX = truncX;      countX = 0;      minY = maxY = y;      minIndex = maxIndex = startIndex = i;    }  }  return decimated;}function cleanDecimatedDataset(dataset) {  if (dataset._decimated) {    const data = dataset._data;    delete dataset._decimated;    delete dataset._data;    Object.defineProperty(dataset, 'data', {value: data});  }}function cleanDecimatedData(chart) {  chart.data.datasets.forEach((dataset) => {    cleanDecimatedDataset(dataset);  });}function getStartAndCountOfVisiblePointsSimplified(meta, points) {  const pointCount = points.length;  let start = 0;  let count;  const {iScale} = meta;  const {min, max, minDefined, maxDefined} = iScale.getUserBounds();  if (minDefined) {    start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1);  }  if (maxDefined) {    count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start;  } else {    count = pointCount - start;  }  return {start, count};}var plugin_decimation = {  id: 'decimation',  defaults: {    algorithm: 'min-max',    enabled: false,  },  beforeElementsUpdate: (chart, args, options) => {    if (!options.enabled) {      cleanDecimatedData(chart);      return;    }    const availableWidth = chart.width;    chart.data.datasets.forEach((dataset, datasetIndex) => {      const {_data, indexAxis} = dataset;      const meta = chart.getDatasetMeta(datasetIndex);      const data = _data || dataset.data;      if (resolve([indexAxis, chart.options.indexAxis]) === 'y') {        return;      }      if (meta.type !== 'line') {        return;      }      const xAxis = chart.scales[meta.xAxisID];      if (xAxis.type !== 'linear' && xAxis.type !== 'time') {        return;      }      if (chart.options.parsing) {        return;      }      let {start, count} = getStartAndCountOfVisiblePointsSimplified(meta, data);      const threshold = options.threshold || 4 * availableWidth;      if (count <= threshold) {        cleanDecimatedDataset(dataset);        return;      }      if (isNullOrUndef(_data)) {        dataset._data = data;        delete dataset.data;        Object.defineProperty(dataset, 'data', {          configurable: true,          enumerable: true,          get: function() {            return this._decimated;          },          set: function(d) {            this._data = d;          }        });      }      let decimated;      switch (options.algorithm) {      case 'lttb':        decimated = lttbDecimation(data, start, count, availableWidth, options);        break;      case 'min-max':        decimated = minMaxDecimation(data, start, count, availableWidth);        break;      default:        throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);      }      dataset._decimated = decimated;    });  },  destroy(chart) {    cleanDecimatedData(chart);  }};function getLineByIndex(chart, index) {  const meta = chart.getDatasetMeta(index);  const visible = meta && chart.isDatasetVisible(index);  return visible ? meta.dataset : null;}function parseFillOption(line) {  const options = line.options;  const fillOption = options.fill;  let fill = valueOrDefault(fillOption && fillOption.target, fillOption);  if (fill === undefined) {    fill = !!options.backgroundColor;  }  if (fill === false || fill === null) {    return false;  }  if (fill === true) {    return 'origin';  }  return fill;}function decodeFill(line, index, count) {  const fill = parseFillOption(line);  if (isObject(fill)) {    return isNaN(fill.value) ? false : fill;  }  let target = parseFloat(fill);  if (isNumberFinite(target) && Math.floor(target) === target) {    if (fill[0] === '-' || fill[0] === '+') {      target = index + target;    }    if (target === index || target < 0 || target >= count) {      return false;    }    return target;  }  return ['origin', 'start', 'end', 'stack', 'shape'].indexOf(fill) >= 0 && fill;}function computeLinearBoundary(source) {  const {scale = {}, fill} = source;  let target = null;  let horizontal;  if (fill === 'start') {    target = scale.bottom;  } else if (fill === 'end') {    target = scale.top;  } else if (isObject(fill)) {    target = scale.getPixelForValue(fill.value);  } else if (scale.getBasePixel) {    target = scale.getBasePixel();  }  if (isNumberFinite(target)) {    horizontal = scale.isHorizontal();    return {      x: horizontal ? target : null,      y: horizontal ? null : target    };  }  return null;}class simpleArc {  constructor(opts) {    this.x = opts.x;    this.y = opts.y;    this.radius = opts.radius;  }  pathSegment(ctx, bounds, opts) {    const {x, y, radius} = this;    bounds = bounds || {start: 0, end: TAU};    ctx.arc(x, y, radius, bounds.end, bounds.start, true);    return !opts.bounds;  }  interpolate(point) {    const {x, y, radius} = this;    const angle = point.angle;    return {      x: x + Math.cos(angle) * radius,      y: y + Math.sin(angle) * radius,      angle    };  }}function computeCircularBoundary(source) {  const {scale, fill} = source;  const options = scale.options;  const length = scale.getLabels().length;  const target = [];  const start = options.reverse ? scale.max : scale.min;  const end = options.reverse ? scale.min : scale.max;  let i, center, value;  if (fill === 'start') {    value = start;  } else if (fill === 'end') {    value = end;  } else if (isObject(fill)) {    value = fill.value;  } else {    value = scale.getBaseValue();  }  if (options.grid.circular) {    center = scale.getPointPositionForValue(0, start);    return new simpleArc({      x: center.x,      y: center.y,      radius: scale.getDistanceFromCenterForValue(value)    });  }  for (i = 0; i < length; ++i) {    target.push(scale.getPointPositionForValue(i, value));  }  return target;}function computeBoundary(source) {  const scale = source.scale || {};  if (scale.getPointPositionForValue) {    return computeCircularBoundary(source);  }  return computeLinearBoundary(source);}function findSegmentEnd(start, end, points) {  for (;end > start; end--) {    const point = points[end];    if (!isNaN(point.x) && !isNaN(point.y)) {      break;    }  }  return end;}function pointsFromSegments(boundary, line) {  const {x = null, y = null} = boundary || {};  const linePoints = line.points;  const points = [];  line.segments.forEach(({start, end}) => {    end = findSegmentEnd(start, end, linePoints);    const first = linePoints[start];    const last = linePoints[end];    if (y !== null) {      points.push({x: first.x, y});      points.push({x: last.x, y});    } else if (x !== null) {      points.push({x, y: first.y});      points.push({x, y: last.y});    }  });  return points;}function buildStackLine(source) {  const {scale, index, line} = source;  const points = [];  const segments = line.segments;  const sourcePoints = line.points;  const linesBelow = getLinesBelow(scale, index);  linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line));  for (let i = 0; i < segments.length; i++) {    const segment = segments[i];    for (let j = segment.start; j <= segment.end; j++) {      addPointsBelow(points, sourcePoints[j], linesBelow);    }  }  return new LineElement({points, options: {}});}function getLinesBelow(scale, index) {  const below = [];  const metas = scale.getMatchingVisibleMetas('line');  for (let i = 0; i < metas.length; i++) {    const meta = metas[i];    if (meta.index === index) {      break;    }    if (!meta.hidden) {      below.unshift(meta.dataset);    }  }  return below;}function addPointsBelow(points, sourcePoint, linesBelow) {  const postponed = [];  for (let j = 0; j < linesBelow.length; j++) {    const line = linesBelow[j];    const {first, last, point} = findPoint(line, sourcePoint, 'x');    if (!point || (first && last)) {      continue;    }    if (first) {      postponed.unshift(point);    } else {      points.push(point);      if (!last) {        break;      }    }  }  points.push(...postponed);}function findPoint(line, sourcePoint, property) {  const point = line.interpolate(sourcePoint, property);  if (!point) {    return {};  }  const pointValue = point[property];  const segments = line.segments;  const linePoints = line.points;  let first = false;  let last = false;  for (let i = 0; i < segments.length; i++) {    const segment = segments[i];    const firstValue = linePoints[segment.start][property];    const lastValue = linePoints[segment.end][property];    if (_isBetween(pointValue, firstValue, lastValue)) {      first = pointValue === firstValue;      last = pointValue === lastValue;      break;    }  }  return {first, last, point};}function getTarget(source) {  const {chart, fill, line} = source;  if (isNumberFinite(fill)) {    return getLineByIndex(chart, fill);  }  if (fill === 'stack') {    return buildStackLine(source);  }  if (fill === 'shape') {    return true;  }  const boundary = computeBoundary(source);  if (boundary instanceof simpleArc) {    return boundary;  }  return createBoundaryLine(boundary, line);}function createBoundaryLine(boundary, line) {  let points = [];  let _loop = false;  if (isArray(boundary)) {    _loop = true;    points = boundary;  } else {    points = pointsFromSegments(boundary, line);  }  return points.length ? new LineElement({    points,    options: {tension: 0},    _loop,    _fullLoop: _loop  }) : null;}function resolveTarget(sources, index, propagate) {  const source = sources[index];  let fill = source.fill;  const visited = [index];  let target;  if (!propagate) {    return fill;  }  while (fill !== false && visited.indexOf(fill) === -1) {    if (!isNumberFinite(fill)) {      return fill;    }    target = sources[fill];    if (!target) {      return false;    }    if (target.visible) {      return fill;    }    visited.push(fill);    fill = target.fill;  }  return false;}function _clip(ctx, target, clipY) {  const {segments, points} = target;  let first = true;  let lineLoop = false;  ctx.beginPath();  for (const segment of segments) {    const {start, end} = segment;    const firstPoint = points[start];    const lastPoint = points[findSegmentEnd(start, end, points)];    if (first) {      ctx.moveTo(firstPoint.x, firstPoint.y);      first = false;    } else {      ctx.lineTo(firstPoint.x, clipY);      ctx.lineTo(firstPoint.x, firstPoint.y);    }    lineLoop = !!target.pathSegment(ctx, segment, {move: lineLoop});    if (lineLoop) {      ctx.closePath();    } else {      ctx.lineTo(lastPoint.x, clipY);    }  }  ctx.lineTo(target.first().x, clipY);  ctx.closePath();  ctx.clip();}function getBounds(property, first, last, loop) {  if (loop) {    return;  }  let start = first[property];  let end = last[property];  if (property === 'angle') {    start = _normalizeAngle(start);    end = _normalizeAngle(end);  }  return {property, start, end};}function _getEdge(a, b, prop, fn) {  if (a && b) {    return fn(a[prop], b[prop]);  }  return a ? a[prop] : b ? b[prop] : 0;}function _segments(line, target, property) {  const segments = line.segments;  const points = line.points;  const tpoints = target.points;  const parts = [];  for (const segment of segments) {    let {start, end} = segment;    end = findSegmentEnd(start, end, points);    const bounds = getBounds(property, points[start], points[end], segment.loop);    if (!target.segments) {      parts.push({        source: segment,        target: bounds,        start: points[start],        end: points[end]      });      continue;    }    const targetSegments = _boundSegments(target, bounds);    for (const tgt of targetSegments) {      const subBounds = getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop);      const fillSources = _boundSegment(segment, points, subBounds);      for (const fillSource of fillSources) {        parts.push({          source: fillSource,          target: tgt,          start: {            [property]: _getEdge(bounds, subBounds, 'start', Math.max)          },          end: {            [property]: _getEdge(bounds, subBounds, 'end', Math.min)          }        });      }    }  }  return parts;}function clipBounds(ctx, scale, bounds) {  const {top, bottom} = scale.chart.chartArea;  const {property, start, end} = bounds || {};  if (property === 'x') {    ctx.beginPath();    ctx.rect(start, top, end - start, bottom - top);    ctx.clip();  }}function interpolatedLineTo(ctx, target, point, property) {  const interpolatedPoint = target.interpolate(point, property);  if (interpolatedPoint) {    ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);  }}function _fill(ctx, cfg) {  const {line, target, property, color, scale} = cfg;  const segments = _segments(line, target, property);  for (const {source: src, target: tgt, start, end} of segments) {    const {style: {backgroundColor = color} = {}} = src;    const notShape = target !== true;    ctx.save();    ctx.fillStyle = backgroundColor;    clipBounds(ctx, scale, notShape && getBounds(property, start, end));    ctx.beginPath();    const lineLoop = !!line.pathSegment(ctx, src);    let loop;    if (notShape) {      if (lineLoop) {        ctx.closePath();      } else {        interpolatedLineTo(ctx, target, end, property);      }      const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true});      loop = lineLoop && targetLoop;      if (!loop) {        interpolatedLineTo(ctx, target, start, property);      }    }    ctx.closePath();    ctx.fill(loop ? 'evenodd' : 'nonzero');    ctx.restore();  }}function doFill(ctx, cfg) {  const {line, target, above, below, area, scale} = cfg;  const property = line._loop ? 'angle' : cfg.axis;  ctx.save();  if (property === 'x' && below !== above) {    _clip(ctx, target, area.top);    _fill(ctx, {line, target, color: above, scale, property});    ctx.restore();    ctx.save();    _clip(ctx, target, area.bottom);  }  _fill(ctx, {line, target, color: below, scale, property});  ctx.restore();}function drawfill(ctx, source, area) {  const target = getTarget(source);  const {line, scale, axis} = source;  const lineOpts = line.options;  const fillOption = lineOpts.fill;  const color = lineOpts.backgroundColor;  const {above = color, below = color} = fillOption || {};  if (target && line.points.length) {    clipArea(ctx, area);    doFill(ctx, {line, target, above, below, area, scale, axis});    unclipArea(ctx);  }}var plugin_filler = {  id: 'filler',  afterDatasetsUpdate(chart, _args, options) {    const count = (chart.data.datasets || []).length;    const sources = [];    let meta, i, line, source;    for (i = 0; i < count; ++i) {      meta = chart.getDatasetMeta(i);      line = meta.dataset;      source = null;      if (line && line.options && line instanceof LineElement) {        source = {          visible: chart.isDatasetVisible(i),          index: i,          fill: decodeFill(line, i, count),          chart,          axis: meta.controller.options.indexAxis,          scale: meta.vScale,          line,        };      }      meta.$filler = source;      sources.push(source);    }    for (i = 0; i < count; ++i) {      source = sources[i];      if (!source || source.fill === false) {        continue;      }      source.fill = resolveTarget(sources, i, options.propagate);    }  },  beforeDraw(chart, _args, options) {    const draw = options.drawTime === 'beforeDraw';    const metasets = chart.getSortedVisibleDatasetMetas();    const area = chart.chartArea;    for (let i = metasets.length - 1; i >= 0; --i) {      const source = metasets[i].$filler;      if (!source) {        continue;      }      source.line.updateControlPoints(area, source.axis);      if (draw) {        drawfill(chart.ctx, source, area);      }    }  },  beforeDatasetsDraw(chart, _args, options) {    if (options.drawTime !== 'beforeDatasetsDraw') {      return;    }    const metasets = chart.getSortedVisibleDatasetMetas();    for (let i = metasets.length - 1; i >= 0; --i) {      const source = metasets[i].$filler;      if (source) {        drawfill(chart.ctx, source, chart.chartArea);      }    }  },  beforeDatasetDraw(chart, args, options) {    const source = args.meta.$filler;    if (!source || source.fill === false || options.drawTime !== 'beforeDatasetDraw') {      return;    }    drawfill(chart.ctx, source, chart.chartArea);  },  defaults: {    propagate: true,    drawTime: 'beforeDatasetDraw'  }};const getBoxSize = (labelOpts, fontSize) => {  let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts;  if (labelOpts.usePointStyle) {    boxHeight = Math.min(boxHeight, fontSize);    boxWidth = Math.min(boxWidth, fontSize);  }  return {    boxWidth,    boxHeight,    itemHeight: Math.max(fontSize, boxHeight)  };};const itemsEqual = (a, b) => a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index;class Legend extends Element {  constructor(config) {    super();    this._added = false;    this.legendHitBoxes = [];    this._hoveredItem = null;    this.doughnutMode = false;    this.chart = config.chart;    this.options = config.options;    this.ctx = config.ctx;    this.legendItems = undefined;    this.columnSizes = undefined;    this.lineWidths = undefined;    this.maxHeight = undefined;    this.maxWidth = undefined;    this.top = undefined;    this.bottom = undefined;    this.left = undefined;    this.right = undefined;    this.height = undefined;    this.width = undefined;    this._margins = undefined;    this.position = undefined;    this.weight = undefined;    this.fullSize = undefined;  }  update(maxWidth, maxHeight, margins) {    this.maxWidth = maxWidth;    this.maxHeight = maxHeight;    this._margins = margins;    this.setDimensions();    this.buildLabels();    this.fit();  }  setDimensions() {    if (this.isHorizontal()) {      this.width = this.maxWidth;      this.left = this._margins.left;      this.right = this.width;    } else {      this.height = this.maxHeight;      this.top = this._margins.top;      this.bottom = this.height;    }  }  buildLabels() {    const labelOpts = this.options.labels || {};    let legendItems = callback(labelOpts.generateLabels, [this.chart], this) || [];    if (labelOpts.filter) {      legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data));    }    if (labelOpts.sort) {      legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, this.chart.data));    }    if (this.options.reverse) {      legendItems.reverse();    }    this.legendItems = legendItems;  }  fit() {    const {options, ctx} = this;    if (!options.display) {      this.width = this.height = 0;      return;    }    const labelOpts = options.labels;    const labelFont = toFont(labelOpts.font);    const fontSize = labelFont.size;    const titleHeight = this._computeTitleHeight();    const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize);    let width, height;    ctx.font = labelFont.string;    if (this.isHorizontal()) {      width = this.maxWidth;      height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;    } else {      height = this.maxHeight;      width = this._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10;    }    this.width = Math.min(width, options.maxWidth || this.maxWidth);    this.height = Math.min(height, options.maxHeight || this.maxHeight);  }  _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {    const {ctx, maxWidth, options: {labels: {padding}}} = this;    const hitboxes = this.legendHitBoxes = [];    const lineWidths = this.lineWidths = [0];    const lineHeight = itemHeight + padding;    let totalHeight = titleHeight;    ctx.textAlign = 'left';    ctx.textBaseline = 'middle';    let row = -1;    let top = -lineHeight;    this.legendItems.forEach((legendItem, i) => {      const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;      if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {        totalHeight += lineHeight;        lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;        top += lineHeight;        row++;      }      hitboxes[i] = {left: 0, top, row, width: itemWidth, height: itemHeight};      lineWidths[lineWidths.length - 1] += itemWidth + padding;    });    return totalHeight;  }  _fitCols(titleHeight, fontSize, boxWidth, itemHeight) {    const {ctx, maxHeight, options: {labels: {padding}}} = this;    const hitboxes = this.legendHitBoxes = [];    const columnSizes = this.columnSizes = [];    const heightLimit = maxHeight - titleHeight;    let totalWidth = padding;    let currentColWidth = 0;    let currentColHeight = 0;    let left = 0;    let col = 0;    this.legendItems.forEach((legendItem, i) => {      const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;      if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {        totalWidth += currentColWidth + padding;        columnSizes.push({width: currentColWidth, height: currentColHeight});        left += currentColWidth + padding;        col++;        currentColWidth = currentColHeight = 0;      }      hitboxes[i] = {left, top: currentColHeight, col, width: itemWidth, height: itemHeight};      currentColWidth = Math.max(currentColWidth, itemWidth);      currentColHeight += itemHeight + padding;    });    totalWidth += currentColWidth;    columnSizes.push({width: currentColWidth, height: currentColHeight});    return totalWidth;  }  adjustHitBoxes() {    if (!this.options.display) {      return;    }    const titleHeight = this._computeTitleHeight();    const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = this;    const rtlHelper = getRtlAdapter(rtl, this.left, this.width);    if (this.isHorizontal()) {      let row = 0;      let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);      for (const hitbox of hitboxes) {        if (row !== hitbox.row) {          row = hitbox.row;          left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);        }        hitbox.top += this.top + titleHeight + padding;        hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);        left += hitbox.width + padding;      }    } else {      let col = 0;      let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);      for (const hitbox of hitboxes) {        if (hitbox.col !== col) {          col = hitbox.col;          top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);        }        hitbox.top = top;        hitbox.left += this.left + padding;        hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);        top += hitbox.height + padding;      }    }  }  isHorizontal() {    return this.options.position === 'top' || this.options.position === 'bottom';  }  draw() {    if (this.options.display) {      const ctx = this.ctx;      clipArea(ctx, this);      this._draw();      unclipArea(ctx);    }  }  _draw() {    const {options: opts, columnSizes, lineWidths, ctx} = this;    const {align, labels: labelOpts} = opts;    const defaultColor = defaults.color;    const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);    const labelFont = toFont(labelOpts.font);    const {color: fontColor, padding} = labelOpts;    const fontSize = labelFont.size;    const halfFontSize = fontSize / 2;    let cursor;    this.drawTitle();    ctx.textAlign = rtlHelper.textAlign('left');    ctx.textBaseline = 'middle';    ctx.lineWidth = 0.5;    ctx.font = labelFont.string;    const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize);    const drawLegendBox = function(x, y, legendItem) {      if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {        return;      }      ctx.save();      const lineWidth = valueOrDefault(legendItem.lineWidth, 1);      ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor);      ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt');      ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0);      ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter');      ctx.lineWidth = lineWidth;      ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor);      ctx.setLineDash(valueOrDefault(legendItem.lineDash, []));      if (labelOpts.usePointStyle) {        const drawOptions = {          radius: boxWidth * Math.SQRT2 / 2,          pointStyle: legendItem.pointStyle,          rotation: legendItem.rotation,          borderWidth: lineWidth        };        const centerX = rtlHelper.xPlus(x, boxWidth / 2);        const centerY = y + halfFontSize;        drawPoint(ctx, drawOptions, centerX, centerY);      } else {        const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);        const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth);        const borderRadius = toTRBLCorners(legendItem.borderRadius);        ctx.beginPath();        if (Object.values(borderRadius).some(v => v !== 0)) {          addRoundedRectPath(ctx, {            x: xBoxLeft,            y: yBoxTop,            w: boxWidth,            h: boxHeight,            radius: borderRadius,          });        } else {          ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight);        }        ctx.fill();        if (lineWidth !== 0) {          ctx.stroke();        }      }      ctx.restore();    };    const fillText = function(x, y, legendItem) {      renderText(ctx, legendItem.text, x, y + (itemHeight / 2), labelFont, {        strikethrough: legendItem.hidden,        textAlign: rtlHelper.textAlign(legendItem.textAlign)      });    };    const isHorizontal = this.isHorizontal();    const titleHeight = this._computeTitleHeight();    if (isHorizontal) {      cursor = {        x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]),        y: this.top + padding + titleHeight,        line: 0      };    } else {      cursor = {        x: this.left + padding,        y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),        line: 0      };    }    overrideTextDirection(this.ctx, opts.textDirection);    const lineHeight = itemHeight + padding;    this.legendItems.forEach((legendItem, i) => {      ctx.strokeStyle = legendItem.fontColor || fontColor;      ctx.fillStyle = legendItem.fontColor || fontColor;      const textWidth = ctx.measureText(legendItem.text).width;      const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign));      const width = boxWidth + halfFontSize + textWidth;      let x = cursor.x;      let y = cursor.y;      rtlHelper.setWidth(this.width);      if (isHorizontal) {        if (i > 0 && x + width + padding > this.right) {          y = cursor.y += lineHeight;          cursor.line++;          x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]);        }      } else if (i > 0 && y + lineHeight > this.bottom) {        x = cursor.x = x + columnSizes[cursor.line].width + padding;        cursor.line++;        y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);      }      const realX = rtlHelper.x(x);      drawLegendBox(realX, y, legendItem);      x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl);      fillText(rtlHelper.x(x), y, legendItem);      if (isHorizontal) {        cursor.x += width + padding;      } else {        cursor.y += lineHeight;      }    });    restoreTextDirection(this.ctx, opts.textDirection);  }  drawTitle() {    const opts = this.options;    const titleOpts = opts.title;    const titleFont = toFont(titleOpts.font);    const titlePadding = toPadding(titleOpts.padding);    if (!titleOpts.display) {      return;    }    const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);    const ctx = this.ctx;    const position = titleOpts.position;    const halfFontSize = titleFont.size / 2;    const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;    let y;    let left = this.left;    let maxWidth = this.width;    if (this.isHorizontal()) {      maxWidth = Math.max(...this.lineWidths);      y = this.top + topPaddingPlusHalfFontSize;      left = _alignStartEnd(opts.align, left, this.right - maxWidth);    } else {      const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0);      y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());    }    const x = _alignStartEnd(position, left, left + maxWidth);    ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position));    ctx.textBaseline = 'middle';    ctx.strokeStyle = titleOpts.color;    ctx.fillStyle = titleOpts.color;    ctx.font = titleFont.string;    renderText(ctx, titleOpts.text, x, y, titleFont);  }  _computeTitleHeight() {    const titleOpts = this.options.title;    const titleFont = toFont(titleOpts.font);    const titlePadding = toPadding(titleOpts.padding);    return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;  }  _getLegendItemAt(x, y) {    let i, hitBox, lh;    if (_isBetween(x, this.left, this.right)      && _isBetween(y, this.top, this.bottom)) {      lh = this.legendHitBoxes;      for (i = 0; i < lh.length; ++i) {        hitBox = lh[i];        if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width)          && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) {          return this.legendItems[i];        }      }    }    return null;  }  handleEvent(e) {    const opts = this.options;    if (!isListened(e.type, opts)) {      return;    }    const hoveredItem = this._getLegendItemAt(e.x, e.y);    if (e.type === 'mousemove') {      const previous = this._hoveredItem;      const sameItem = itemsEqual(previous, hoveredItem);      if (previous && !sameItem) {        callback(opts.onLeave, [e, previous, this], this);      }      this._hoveredItem = hoveredItem;      if (hoveredItem && !sameItem) {        callback(opts.onHover, [e, hoveredItem, this], this);      }    } else if (hoveredItem) {      callback(opts.onClick, [e, hoveredItem, this], this);    }  }}function isListened(type, opts) {  if (type === 'mousemove' && (opts.onHover || opts.onLeave)) {    return true;  }  if (opts.onClick && (type === 'click' || type === 'mouseup')) {    return true;  }  return false;}var plugin_legend = {  id: 'legend',  _element: Legend,  start(chart, _args, options) {    const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart});    layouts.configure(chart, legend, options);    layouts.addBox(chart, legend);  },  stop(chart) {    layouts.removeBox(chart, chart.legend);    delete chart.legend;  },  beforeUpdate(chart, _args, options) {    const legend = chart.legend;    layouts.configure(chart, legend, options);    legend.options = options;  },  afterUpdate(chart) {    const legend = chart.legend;    legend.buildLabels();    legend.adjustHitBoxes();  },  afterEvent(chart, args) {    if (!args.replay) {      chart.legend.handleEvent(args.event);    }  },  defaults: {    display: true,    position: 'top',    align: 'center',    fullSize: true,    reverse: false,    weight: 1000,    onClick(e, legendItem, legend) {      const index = legendItem.datasetIndex;      const ci = legend.chart;      if (ci.isDatasetVisible(index)) {        ci.hide(index);        legendItem.hidden = true;      } else {        ci.show(index);        legendItem.hidden = false;      }    },    onHover: null,    onLeave: null,    labels: {      color: (ctx) => ctx.chart.options.color,      boxWidth: 40,      padding: 10,      generateLabels(chart) {        const datasets = chart.data.datasets;        const {labels: {usePointStyle, pointStyle, textAlign, color}} = chart.legend.options;        return chart._getSortedDatasetMetas().map((meta) => {          const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);          const borderWidth = toPadding(style.borderWidth);          return {            text: datasets[meta.index].label,            fillStyle: style.backgroundColor,            fontColor: color,            hidden: !meta.visible,            lineCap: style.borderCapStyle,            lineDash: style.borderDash,            lineDashOffset: style.borderDashOffset,            lineJoin: style.borderJoinStyle,            lineWidth: (borderWidth.width + borderWidth.height) / 4,            strokeStyle: style.borderColor,            pointStyle: pointStyle || style.pointStyle,            rotation: style.rotation,            textAlign: textAlign || style.textAlign,            borderRadius: 0,            datasetIndex: meta.index          };        }, this);      }    },    title: {      color: (ctx) => ctx.chart.options.color,      display: false,      position: 'center',      text: '',    }  },  descriptors: {    _scriptable: (name) => !name.startsWith('on'),    labels: {      _scriptable: (name) => !['generateLabels', 'filter', 'sort'].includes(name),    }  },};class Title extends Element {  constructor(config) {    super();    this.chart = config.chart;    this.options = config.options;    this.ctx = config.ctx;    this._padding = undefined;    this.top = undefined;    this.bottom = undefined;    this.left = undefined;    this.right = undefined;    this.width = undefined;    this.height = undefined;    this.position = undefined;    this.weight = undefined;    this.fullSize = undefined;  }  update(maxWidth, maxHeight) {    const opts = this.options;    this.left = 0;    this.top = 0;    if (!opts.display) {      this.width = this.height = this.right = this.bottom = 0;      return;    }    this.width = this.right = maxWidth;    this.height = this.bottom = maxHeight;    const lineCount = isArray(opts.text) ? opts.text.length : 1;    this._padding = toPadding(opts.padding);    const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height;    if (this.isHorizontal()) {      this.height = textSize;    } else {      this.width = textSize;    }  }  isHorizontal() {    const pos = this.options.position;    return pos === 'top' || pos === 'bottom';  }  _drawArgs(offset) {    const {top, left, bottom, right, options} = this;    const align = options.align;    let rotation = 0;    let maxWidth, titleX, titleY;    if (this.isHorizontal()) {      titleX = _alignStartEnd(align, left, right);      titleY = top + offset;      maxWidth = right - left;    } else {      if (options.position === 'left') {        titleX = left + offset;        titleY = _alignStartEnd(align, bottom, top);        rotation = PI * -0.5;      } else {        titleX = right - offset;        titleY = _alignStartEnd(align, top, bottom);        rotation = PI * 0.5;      }      maxWidth = bottom - top;    }    return {titleX, titleY, maxWidth, rotation};  }  draw() {    const ctx = this.ctx;    const opts = this.options;    if (!opts.display) {      return;    }    const fontOpts = toFont(opts.font);    const lineHeight = fontOpts.lineHeight;    const offset = lineHeight / 2 + this._padding.top;    const {titleX, titleY, maxWidth, rotation} = this._drawArgs(offset);    renderText(ctx, opts.text, 0, 0, fontOpts, {      color: opts.color,      maxWidth,      rotation,      textAlign: _toLeftRightCenter(opts.align),      textBaseline: 'middle',      translation: [titleX, titleY],    });  }}function createTitle(chart, titleOpts) {  const title = new Title({    ctx: chart.ctx,    options: titleOpts,    chart  });  layouts.configure(chart, title, titleOpts);  layouts.addBox(chart, title);  chart.titleBlock = title;}var plugin_title = {  id: 'title',  _element: Title,  start(chart, _args, options) {    createTitle(chart, options);  },  stop(chart) {    const titleBlock = chart.titleBlock;    layouts.removeBox(chart, titleBlock);    delete chart.titleBlock;  },  beforeUpdate(chart, _args, options) {    const title = chart.titleBlock;    layouts.configure(chart, title, options);    title.options = options;  },  defaults: {    align: 'center',    display: false,    font: {      weight: 'bold',    },    fullSize: true,    padding: 10,    position: 'top',    text: '',    weight: 2000  },  defaultRoutes: {    color: 'color'  },  descriptors: {    _scriptable: true,    _indexable: false,  },};const map = new WeakMap();var plugin_subtitle = {  id: 'subtitle',  start(chart, _args, options) {    const title = new Title({      ctx: chart.ctx,      options,      chart    });    layouts.configure(chart, title, options);    layouts.addBox(chart, title);    map.set(chart, title);  },  stop(chart) {    layouts.removeBox(chart, map.get(chart));    map.delete(chart);  },  beforeUpdate(chart, _args, options) {    const title = map.get(chart);    layouts.configure(chart, title, options);    title.options = options;  },  defaults: {    align: 'center',    display: false,    font: {      weight: 'normal',    },    fullSize: true,    padding: 0,    position: 'top',    text: '',    weight: 1500  },  defaultRoutes: {    color: 'color'  },  descriptors: {    _scriptable: true,    _indexable: false,  },};const positioners = {  average(items) {    if (!items.length) {      return false;    }    let i, len;    let x = 0;    let y = 0;    let count = 0;    for (i = 0, len = items.length; i < len; ++i) {      const el = items[i].element;      if (el && el.hasValue()) {        const pos = el.tooltipPosition();        x += pos.x;        y += pos.y;        ++count;      }    }    return {      x: x / count,      y: y / count    };  },  nearest(items, eventPosition) {    if (!items.length) {      return false;    }    let x = eventPosition.x;    let y = eventPosition.y;    let minDistance = Number.POSITIVE_INFINITY;    let i, len, nearestElement;    for (i = 0, len = items.length; i < len; ++i) {      const el = items[i].element;      if (el && el.hasValue()) {        const center = el.getCenterPoint();        const d = distanceBetweenPoints(eventPosition, center);        if (d < minDistance) {          minDistance = d;          nearestElement = el;        }      }    }    if (nearestElement) {      const tp = nearestElement.tooltipPosition();      x = tp.x;      y = tp.y;    }    return {      x,      y    };  }};function pushOrConcat(base, toPush) {  if (toPush) {    if (isArray(toPush)) {      Array.prototype.push.apply(base, toPush);    } else {      base.push(toPush);    }  }  return base;}function splitNewlines(str) {  if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {    return str.split('\n');  }  return str;}function createTooltipItem(chart, item) {  const {element, datasetIndex, index} = item;  const controller = chart.getDatasetMeta(datasetIndex).controller;  const {label, value} = controller.getLabelAndValue(index);  return {    chart,    label,    parsed: controller.getParsed(index),    raw: chart.data.datasets[datasetIndex].data[index],    formattedValue: value,    dataset: controller.getDataset(),    dataIndex: index,    datasetIndex,    element  };}function getTooltipSize(tooltip, options) {  const ctx = tooltip.chart.ctx;  const {body, footer, title} = tooltip;  const {boxWidth, boxHeight} = options;  const bodyFont = toFont(options.bodyFont);  const titleFont = toFont(options.titleFont);  const footerFont = toFont(options.footerFont);  const titleLineCount = title.length;  const footerLineCount = footer.length;  const bodyLineItemCount = body.length;  const padding = toPadding(options.padding);  let height = padding.height;  let width = 0;  let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);  combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;  if (titleLineCount) {    height += titleLineCount * titleFont.lineHeight			+ (titleLineCount - 1) * options.titleSpacing			+ options.titleMarginBottom;  }  if (combinedBodyLength) {    const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;    height += bodyLineItemCount * bodyLineHeight			+ (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight			+ (combinedBodyLength - 1) * options.bodySpacing;  }  if (footerLineCount) {    height += options.footerMarginTop			+ footerLineCount * footerFont.lineHeight			+ (footerLineCount - 1) * options.footerSpacing;  }  let widthPadding = 0;  const maxLineWidth = function(line) {    width = Math.max(width, ctx.measureText(line).width + widthPadding);  };  ctx.save();  ctx.font = titleFont.string;  each(tooltip.title, maxLineWidth);  ctx.font = bodyFont.string;  each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);  widthPadding = options.displayColors ? (boxWidth + 2 + options.boxPadding) : 0;  each(body, (bodyItem) => {    each(bodyItem.before, maxLineWidth);    each(bodyItem.lines, maxLineWidth);    each(bodyItem.after, maxLineWidth);  });  widthPadding = 0;  ctx.font = footerFont.string;  each(tooltip.footer, maxLineWidth);  ctx.restore();  width += padding.width;  return {width, height};}function determineYAlign(chart, size) {  const {y, height} = size;  if (y < height / 2) {    return 'top';  } else if (y > (chart.height - height / 2)) {    return 'bottom';  }  return 'center';}function doesNotFitWithAlign(xAlign, chart, options, size) {  const {x, width} = size;  const caret = options.caretSize + options.caretPadding;  if (xAlign === 'left' && x + width + caret > chart.width) {    return true;  }  if (xAlign === 'right' && x - width - caret < 0) {    return true;  }}function determineXAlign(chart, options, size, yAlign) {  const {x, width} = size;  const {width: chartWidth, chartArea: {left, right}} = chart;  let xAlign = 'center';  if (yAlign === 'center') {    xAlign = x <= (left + right) / 2 ? 'left' : 'right';  } else if (x <= width / 2) {    xAlign = 'left';  } else if (x >= chartWidth - width / 2) {    xAlign = 'right';  }  if (doesNotFitWithAlign(xAlign, chart, options, size)) {    xAlign = 'center';  }  return xAlign;}function determineAlignment(chart, options, size) {  const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);  return {    xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),    yAlign  };}function alignX(size, xAlign) {  let {x, width} = size;  if (xAlign === 'right') {    x -= width;  } else if (xAlign === 'center') {    x -= (width / 2);  }  return x;}function alignY(size, yAlign, paddingAndSize) {  let {y, height} = size;  if (yAlign === 'top') {    y += paddingAndSize;  } else if (yAlign === 'bottom') {    y -= height + paddingAndSize;  } else {    y -= (height / 2);  }  return y;}function getBackgroundPoint(options, size, alignment, chart) {  const {caretSize, caretPadding, cornerRadius} = options;  const {xAlign, yAlign} = alignment;  const paddingAndSize = caretSize + caretPadding;  const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius);  let x = alignX(size, xAlign);  const y = alignY(size, yAlign, paddingAndSize);  if (yAlign === 'center') {    if (xAlign === 'left') {      x += paddingAndSize;    } else if (xAlign === 'right') {      x -= paddingAndSize;    }  } else if (xAlign === 'left') {    x -= Math.max(topLeft, bottomLeft) + caretSize;  } else if (xAlign === 'right') {    x += Math.max(topRight, bottomRight) + caretSize;  }  return {    x: _limitValue(x, 0, chart.width - size.width),    y: _limitValue(y, 0, chart.height - size.height)  };}function getAlignedX(tooltip, align, options) {  const padding = toPadding(options.padding);  return align === 'center'    ? tooltip.x + tooltip.width / 2    : align === 'right'      ? tooltip.x + tooltip.width - padding.right      : tooltip.x + padding.left;}function getBeforeAfterBodyLines(callback) {  return pushOrConcat([], splitNewlines(callback));}function createTooltipContext(parent, tooltip, tooltipItems) {  return createContext(parent, {    tooltip,    tooltipItems,    type: 'tooltip'  });}function overrideCallbacks(callbacks, context) {  const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks;  return override ? callbacks.override(override) : callbacks;}class Tooltip extends Element {  constructor(config) {    super();    this.opacity = 0;    this._active = [];    this._eventPosition = undefined;    this._size = undefined;    this._cachedAnimations = undefined;    this._tooltipItems = [];    this.$animations = undefined;    this.$context = undefined;    this.chart = config.chart || config._chart;    this._chart = this.chart;    this.options = config.options;    this.dataPoints = undefined;    this.title = undefined;    this.beforeBody = undefined;    this.body = undefined;    this.afterBody = undefined;    this.footer = undefined;    this.xAlign = undefined;    this.yAlign = undefined;    this.x = undefined;    this.y = undefined;    this.height = undefined;    this.width = undefined;    this.caretX = undefined;    this.caretY = undefined;    this.labelColors = undefined;    this.labelPointStyles = undefined;    this.labelTextColors = undefined;  }  initialize(options) {    this.options = options;    this._cachedAnimations = undefined;    this.$context = undefined;  }  _resolveAnimations() {    const cached = this._cachedAnimations;    if (cached) {      return cached;    }    const chart = this.chart;    const options = this.options.setContext(this.getContext());    const opts = options.enabled && chart.options.animation && options.animations;    const animations = new Animations(this.chart, opts);    if (opts._cacheable) {      this._cachedAnimations = Object.freeze(animations);    }    return animations;  }  getContext() {    return this.$context ||			(this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));  }  getTitle(context, options) {    const {callbacks} = options;    const beforeTitle = callbacks.beforeTitle.apply(this, [context]);    const title = callbacks.title.apply(this, [context]);    const afterTitle = callbacks.afterTitle.apply(this, [context]);    let lines = [];    lines = pushOrConcat(lines, splitNewlines(beforeTitle));    lines = pushOrConcat(lines, splitNewlines(title));    lines = pushOrConcat(lines, splitNewlines(afterTitle));    return lines;  }  getBeforeBody(tooltipItems, options) {    return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems]));  }  getBody(tooltipItems, options) {    const {callbacks} = options;    const bodyItems = [];    each(tooltipItems, (context) => {      const bodyItem = {        before: [],        lines: [],        after: []      };      const scoped = overrideCallbacks(callbacks, context);      pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context)));      pushOrConcat(bodyItem.lines, scoped.label.call(this, context));      pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context)));      bodyItems.push(bodyItem);    });    return bodyItems;  }  getAfterBody(tooltipItems, options) {    return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems]));  }  getFooter(tooltipItems, options) {    const {callbacks} = options;    const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]);    const footer = callbacks.footer.apply(this, [tooltipItems]);    const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]);    let lines = [];    lines = pushOrConcat(lines, splitNewlines(beforeFooter));    lines = pushOrConcat(lines, splitNewlines(footer));    lines = pushOrConcat(lines, splitNewlines(afterFooter));    return lines;  }  _createItems(options) {    const active = this._active;    const data = this.chart.data;    const labelColors = [];    const labelPointStyles = [];    const labelTextColors = [];    let tooltipItems = [];    let i, len;    for (i = 0, len = active.length; i < len; ++i) {      tooltipItems.push(createTooltipItem(this.chart, active[i]));    }    if (options.filter) {      tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data));    }    if (options.itemSort) {      tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data));    }    each(tooltipItems, (context) => {      const scoped = overrideCallbacks(options.callbacks, context);      labelColors.push(scoped.labelColor.call(this, context));      labelPointStyles.push(scoped.labelPointStyle.call(this, context));      labelTextColors.push(scoped.labelTextColor.call(this, context));    });    this.labelColors = labelColors;    this.labelPointStyles = labelPointStyles;    this.labelTextColors = labelTextColors;    this.dataPoints = tooltipItems;    return tooltipItems;  }  update(changed, replay) {    const options = this.options.setContext(this.getContext());    const active = this._active;    let properties;    let tooltipItems = [];    if (!active.length) {      if (this.opacity !== 0) {        properties = {          opacity: 0        };      }    } else {      const position = positioners[options.position].call(this, active, this._eventPosition);      tooltipItems = this._createItems(options);      this.title = this.getTitle(tooltipItems, options);      this.beforeBody = this.getBeforeBody(tooltipItems, options);      this.body = this.getBody(tooltipItems, options);      this.afterBody = this.getAfterBody(tooltipItems, options);      this.footer = this.getFooter(tooltipItems, options);      const size = this._size = getTooltipSize(this, options);      const positionAndSize = Object.assign({}, position, size);      const alignment = determineAlignment(this.chart, options, positionAndSize);      const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);      this.xAlign = alignment.xAlign;      this.yAlign = alignment.yAlign;      properties = {        opacity: 1,        x: backgroundPoint.x,        y: backgroundPoint.y,        width: size.width,        height: size.height,        caretX: position.x,        caretY: position.y      };    }    this._tooltipItems = tooltipItems;    this.$context = undefined;    if (properties) {      this._resolveAnimations().update(this, properties);    }    if (changed && options.external) {      options.external.call(this, {chart: this.chart, tooltip: this, replay});    }  }  drawCaret(tooltipPoint, ctx, size, options) {    const caretPosition = this.getCaretPosition(tooltipPoint, size, options);    ctx.lineTo(caretPosition.x1, caretPosition.y1);    ctx.lineTo(caretPosition.x2, caretPosition.y2);    ctx.lineTo(caretPosition.x3, caretPosition.y3);  }  getCaretPosition(tooltipPoint, size, options) {    const {xAlign, yAlign} = this;    const {caretSize, cornerRadius} = options;    const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius);    const {x: ptX, y: ptY} = tooltipPoint;    const {width, height} = size;    let x1, x2, x3, y1, y2, y3;    if (yAlign === 'center') {      y2 = ptY + (height / 2);      if (xAlign === 'left') {        x1 = ptX;        x2 = x1 - caretSize;        y1 = y2 + caretSize;        y3 = y2 - caretSize;      } else {        x1 = ptX + width;        x2 = x1 + caretSize;        y1 = y2 - caretSize;        y3 = y2 + caretSize;      }      x3 = x1;    } else {      if (xAlign === 'left') {        x2 = ptX + Math.max(topLeft, bottomLeft) + (caretSize);      } else if (xAlign === 'right') {        x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;      } else {        x2 = this.caretX;      }      if (yAlign === 'top') {        y1 = ptY;        y2 = y1 - caretSize;        x1 = x2 - caretSize;        x3 = x2 + caretSize;      } else {        y1 = ptY + height;        y2 = y1 + caretSize;        x1 = x2 + caretSize;        x3 = x2 - caretSize;      }      y3 = y1;    }    return {x1, x2, x3, y1, y2, y3};  }  drawTitle(pt, ctx, options) {    const title = this.title;    const length = title.length;    let titleFont, titleSpacing, i;    if (length) {      const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);      pt.x = getAlignedX(this, options.titleAlign, options);      ctx.textAlign = rtlHelper.textAlign(options.titleAlign);      ctx.textBaseline = 'middle';      titleFont = toFont(options.titleFont);      titleSpacing = options.titleSpacing;      ctx.fillStyle = options.titleColor;      ctx.font = titleFont.string;      for (i = 0; i < length; ++i) {        ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2);        pt.y += titleFont.lineHeight + titleSpacing;        if (i + 1 === length) {          pt.y += options.titleMarginBottom - titleSpacing;        }      }    }  }  _drawColorBox(ctx, pt, i, rtlHelper, options) {    const labelColors = this.labelColors[i];    const labelPointStyle = this.labelPointStyles[i];    const {boxHeight, boxWidth, boxPadding} = options;    const bodyFont = toFont(options.bodyFont);    const colorX = getAlignedX(this, 'left', options);    const rtlColorX = rtlHelper.x(colorX);    const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;    const colorY = pt.y + yOffSet;    if (options.usePointStyle) {      const drawOptions = {        radius: Math.min(boxWidth, boxHeight) / 2,        pointStyle: labelPointStyle.pointStyle,        rotation: labelPointStyle.rotation,        borderWidth: 1      };      const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;      const centerY = colorY + boxHeight / 2;      ctx.strokeStyle = options.multiKeyBackground;      ctx.fillStyle = options.multiKeyBackground;      drawPoint(ctx, drawOptions, centerX, centerY);      ctx.strokeStyle = labelColors.borderColor;      ctx.fillStyle = labelColors.backgroundColor;      drawPoint(ctx, drawOptions, centerX, centerY);    } else {      ctx.lineWidth = labelColors.borderWidth || 1;      ctx.strokeStyle = labelColors.borderColor;      ctx.setLineDash(labelColors.borderDash || []);      ctx.lineDashOffset = labelColors.borderDashOffset || 0;      const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth - boxPadding);      const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - boxPadding - 2);      const borderRadius = toTRBLCorners(labelColors.borderRadius);      if (Object.values(borderRadius).some(v => v !== 0)) {        ctx.beginPath();        ctx.fillStyle = options.multiKeyBackground;        addRoundedRectPath(ctx, {          x: outerX,          y: colorY,          w: boxWidth,          h: boxHeight,          radius: borderRadius,        });        ctx.fill();        ctx.stroke();        ctx.fillStyle = labelColors.backgroundColor;        ctx.beginPath();        addRoundedRectPath(ctx, {          x: innerX,          y: colorY + 1,          w: boxWidth - 2,          h: boxHeight - 2,          radius: borderRadius,        });        ctx.fill();      } else {        ctx.fillStyle = options.multiKeyBackground;        ctx.fillRect(outerX, colorY, boxWidth, boxHeight);        ctx.strokeRect(outerX, colorY, boxWidth, boxHeight);        ctx.fillStyle = labelColors.backgroundColor;        ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2);      }    }    ctx.fillStyle = this.labelTextColors[i];  }  drawBody(pt, ctx, options) {    const {body} = this;    const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding} = options;    const bodyFont = toFont(options.bodyFont);    let bodyLineHeight = bodyFont.lineHeight;    let xLinePadding = 0;    const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);    const fillLineOfText = function(line) {      ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);      pt.y += bodyLineHeight + bodySpacing;    };    const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);    let bodyItem, textColor, lines, i, j, ilen, jlen;    ctx.textAlign = bodyAlign;    ctx.textBaseline = 'middle';    ctx.font = bodyFont.string;    pt.x = getAlignedX(this, bodyAlignForCalculation, options);    ctx.fillStyle = options.bodyColor;    each(this.beforeBody, fillLineOfText);    xLinePadding = displayColors && bodyAlignForCalculation !== 'right'      ? bodyAlign === 'center' ? (boxWidth / 2 + boxPadding) : (boxWidth + 2 + boxPadding)      : 0;    for (i = 0, ilen = body.length; i < ilen; ++i) {      bodyItem = body[i];      textColor = this.labelTextColors[i];      ctx.fillStyle = textColor;      each(bodyItem.before, fillLineOfText);      lines = bodyItem.lines;      if (displayColors && lines.length) {        this._drawColorBox(ctx, pt, i, rtlHelper, options);        bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);      }      for (j = 0, jlen = lines.length; j < jlen; ++j) {        fillLineOfText(lines[j]);        bodyLineHeight = bodyFont.lineHeight;      }      each(bodyItem.after, fillLineOfText);    }    xLinePadding = 0;    bodyLineHeight = bodyFont.lineHeight;    each(this.afterBody, fillLineOfText);    pt.y -= bodySpacing;  }  drawFooter(pt, ctx, options) {    const footer = this.footer;    const length = footer.length;    let footerFont, i;    if (length) {      const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);      pt.x = getAlignedX(this, options.footerAlign, options);      pt.y += options.footerMarginTop;      ctx.textAlign = rtlHelper.textAlign(options.footerAlign);      ctx.textBaseline = 'middle';      footerFont = toFont(options.footerFont);      ctx.fillStyle = options.footerColor;      ctx.font = footerFont.string;      for (i = 0; i < length; ++i) {        ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2);        pt.y += footerFont.lineHeight + options.footerSpacing;      }    }  }  drawBackground(pt, ctx, tooltipSize, options) {    const {xAlign, yAlign} = this;    const {x, y} = pt;    const {width, height} = tooltipSize;    const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(options.cornerRadius);    ctx.fillStyle = options.backgroundColor;    ctx.strokeStyle = options.borderColor;    ctx.lineWidth = options.borderWidth;    ctx.beginPath();    ctx.moveTo(x + topLeft, y);    if (yAlign === 'top') {      this.drawCaret(pt, ctx, tooltipSize, options);    }    ctx.lineTo(x + width - topRight, y);    ctx.quadraticCurveTo(x + width, y, x + width, y + topRight);    if (yAlign === 'center' && xAlign === 'right') {      this.drawCaret(pt, ctx, tooltipSize, options);    }    ctx.lineTo(x + width, y + height - bottomRight);    ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height);    if (yAlign === 'bottom') {      this.drawCaret(pt, ctx, tooltipSize, options);    }    ctx.lineTo(x + bottomLeft, y + height);    ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft);    if (yAlign === 'center' && xAlign === 'left') {      this.drawCaret(pt, ctx, tooltipSize, options);    }    ctx.lineTo(x, y + topLeft);    ctx.quadraticCurveTo(x, y, x + topLeft, y);    ctx.closePath();    ctx.fill();    if (options.borderWidth > 0) {      ctx.stroke();    }  }  _updateAnimationTarget(options) {    const chart = this.chart;    const anims = this.$animations;    const animX = anims && anims.x;    const animY = anims && anims.y;    if (animX || animY) {      const position = positioners[options.position].call(this, this._active, this._eventPosition);      if (!position) {        return;      }      const size = this._size = getTooltipSize(this, options);      const positionAndSize = Object.assign({}, position, this._size);      const alignment = determineAlignment(chart, options, positionAndSize);      const point = getBackgroundPoint(options, positionAndSize, alignment, chart);      if (animX._to !== point.x || animY._to !== point.y) {        this.xAlign = alignment.xAlign;        this.yAlign = alignment.yAlign;        this.width = size.width;        this.height = size.height;        this.caretX = position.x;        this.caretY = position.y;        this._resolveAnimations().update(this, point);      }    }  }  draw(ctx) {    const options = this.options.setContext(this.getContext());    let opacity = this.opacity;    if (!opacity) {      return;    }    this._updateAnimationTarget(options);    const tooltipSize = {      width: this.width,      height: this.height    };    const pt = {      x: this.x,      y: this.y    };    opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;    const padding = toPadding(options.padding);    const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;    if (options.enabled && hasTooltipContent) {      ctx.save();      ctx.globalAlpha = opacity;      this.drawBackground(pt, ctx, tooltipSize, options);      overrideTextDirection(ctx, options.textDirection);      pt.y += padding.top;      this.drawTitle(pt, ctx, options);      this.drawBody(pt, ctx, options);      this.drawFooter(pt, ctx, options);      restoreTextDirection(ctx, options.textDirection);      ctx.restore();    }  }  getActiveElements() {    return this._active || [];  }  setActiveElements(activeElements, eventPosition) {    const lastActive = this._active;    const active = activeElements.map(({datasetIndex, index}) => {      const meta = this.chart.getDatasetMeta(datasetIndex);      if (!meta) {        throw new Error('Cannot find a dataset at index ' + datasetIndex);      }      return {        datasetIndex,        element: meta.data[index],        index,      };    });    const changed = !_elementsEqual(lastActive, active);    const positionChanged = this._positionChanged(active, eventPosition);    if (changed || positionChanged) {      this._active = active;      this._eventPosition = eventPosition;      this._ignoreReplayEvents = true;      this.update(true);    }  }  handleEvent(e, replay, inChartArea = true) {    if (replay && this._ignoreReplayEvents) {      return false;    }    this._ignoreReplayEvents = false;    const options = this.options;    const lastActive = this._active || [];    const active = this._getActiveElements(e, lastActive, replay, inChartArea);    const positionChanged = this._positionChanged(active, e);    const changed = replay || !_elementsEqual(active, lastActive) || positionChanged;    if (changed) {      this._active = active;      if (options.enabled || options.external) {        this._eventPosition = {          x: e.x,          y: e.y        };        this.update(true, replay);      }    }    return changed;  }  _getActiveElements(e, lastActive, replay, inChartArea) {    const options = this.options;    if (e.type === 'mouseout') {      return [];    }    if (!inChartArea) {      return lastActive;    }    const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay);    if (options.reverse) {      active.reverse();    }    return active;  }  _positionChanged(active, e) {    const {caretX, caretY, options} = this;    const position = positioners[options.position].call(this, active, e);    return position !== false && (caretX !== position.x || caretY !== position.y);  }}Tooltip.positioners = positioners;var plugin_tooltip = {  id: 'tooltip',  _element: Tooltip,  positioners,  afterInit(chart, _args, options) {    if (options) {      chart.tooltip = new Tooltip({chart, options});    }  },  beforeUpdate(chart, _args, options) {    if (chart.tooltip) {      chart.tooltip.initialize(options);    }  },  reset(chart, _args, options) {    if (chart.tooltip) {      chart.tooltip.initialize(options);    }  },  afterDraw(chart) {    const tooltip = chart.tooltip;    const args = {      tooltip    };    if (chart.notifyPlugins('beforeTooltipDraw', args) === false) {      return;    }    if (tooltip) {      tooltip.draw(chart.ctx);    }    chart.notifyPlugins('afterTooltipDraw', args);  },  afterEvent(chart, args) {    if (chart.tooltip) {      const useFinalPosition = args.replay;      if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) {        args.changed = true;      }    }  },  defaults: {    enabled: true,    external: null,    position: 'average',    backgroundColor: 'rgba(0,0,0,0.8)',    titleColor: '#fff',    titleFont: {      weight: 'bold',    },    titleSpacing: 2,    titleMarginBottom: 6,    titleAlign: 'left',    bodyColor: '#fff',    bodySpacing: 2,    bodyFont: {    },    bodyAlign: 'left',    footerColor: '#fff',    footerSpacing: 2,    footerMarginTop: 6,    footerFont: {      weight: 'bold',    },    footerAlign: 'left',    padding: 6,    caretPadding: 2,    caretSize: 5,    cornerRadius: 6,    boxHeight: (ctx, opts) => opts.bodyFont.size,    boxWidth: (ctx, opts) => opts.bodyFont.size,    multiKeyBackground: '#fff',    displayColors: true,    boxPadding: 0,    borderColor: 'rgba(0,0,0,0)',    borderWidth: 0,    animation: {      duration: 400,      easing: 'easeOutQuart',    },    animations: {      numbers: {        type: 'number',        properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'],      },      opacity: {        easing: 'linear',        duration: 200      }    },    callbacks: {      beforeTitle: noop,      title(tooltipItems) {        if (tooltipItems.length > 0) {          const item = tooltipItems[0];          const labels = item.chart.data.labels;          const labelCount = labels ? labels.length : 0;          if (this && this.options && this.options.mode === 'dataset') {            return item.dataset.label || '';          } else if (item.label) {            return item.label;          } else if (labelCount > 0 && item.dataIndex < labelCount) {            return labels[item.dataIndex];          }        }        return '';      },      afterTitle: noop,      beforeBody: noop,      beforeLabel: noop,      label(tooltipItem) {        if (this && this.options && this.options.mode === 'dataset') {          return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;        }        let label = tooltipItem.dataset.label || '';        if (label) {          label += ': ';        }        const value = tooltipItem.formattedValue;        if (!isNullOrUndef(value)) {          label += value;        }        return label;      },      labelColor(tooltipItem) {        const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);        const options = meta.controller.getStyle(tooltipItem.dataIndex);        return {          borderColor: options.borderColor,          backgroundColor: options.backgroundColor,          borderWidth: options.borderWidth,          borderDash: options.borderDash,          borderDashOffset: options.borderDashOffset,          borderRadius: 0,        };      },      labelTextColor() {        return this.options.bodyColor;      },      labelPointStyle(tooltipItem) {        const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);        const options = meta.controller.getStyle(tooltipItem.dataIndex);        return {          pointStyle: options.pointStyle,          rotation: options.rotation,        };      },      afterLabel: noop,      afterBody: noop,      beforeFooter: noop,      footer: noop,      afterFooter: noop    }  },  defaultRoutes: {    bodyFont: 'font',    footerFont: 'font',    titleFont: 'font'  },  descriptors: {    _scriptable: (name) => name !== 'filter' && name !== 'itemSort' && name !== 'external',    _indexable: false,    callbacks: {      _scriptable: false,      _indexable: false,    },    animation: {      _fallback: false    },    animations: {      _fallback: 'animation'    }  },  additionalOptionScopes: ['interaction']};var plugins = /*#__PURE__*/Object.freeze({__proto__: null,Decimation: plugin_decimation,Filler: plugin_filler,Legend: plugin_legend,SubTitle: plugin_subtitle,Title: plugin_title,Tooltip: plugin_tooltip});const addIfString = (labels, raw, index, addedLabels) => {  if (typeof raw === 'string') {    index = labels.push(raw) - 1;    addedLabels.unshift({index, label: raw});  } else if (isNaN(raw)) {    index = null;  }  return index;};function findOrAddLabel(labels, raw, index, addedLabels) {  const first = labels.indexOf(raw);  if (first === -1) {    return addIfString(labels, raw, index, addedLabels);  }  const last = labels.lastIndexOf(raw);  return first !== last ? index : first;}const validIndex = (index, max) => index === null ? null : _limitValue(Math.round(index), 0, max);class CategoryScale extends Scale {  constructor(cfg) {    super(cfg);    this._startValue = undefined;    this._valueRange = 0;    this._addedLabels = [];  }  init(scaleOptions) {    const added = this._addedLabels;    if (added.length) {      const labels = this.getLabels();      for (const {index, label} of added) {        if (labels[index] === label) {          labels.splice(index, 1);        }      }      this._addedLabels = [];    }    super.init(scaleOptions);  }  parse(raw, index) {    if (isNullOrUndef(raw)) {      return null;    }    const labels = this.getLabels();    index = isFinite(index) && labels[index] === raw ? index      : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels);    return validIndex(index, labels.length - 1);  }  determineDataLimits() {    const {minDefined, maxDefined} = this.getUserBounds();    let {min, max} = this.getMinMax(true);    if (this.options.bounds === 'ticks') {      if (!minDefined) {        min = 0;      }      if (!maxDefined) {        max = this.getLabels().length - 1;      }    }    this.min = min;    this.max = max;  }  buildTicks() {    const min = this.min;    const max = this.max;    const offset = this.options.offset;    const ticks = [];    let labels = this.getLabels();    labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1);    this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);    this._startValue = this.min - (offset ? 0.5 : 0);    for (let value = min; value <= max; value++) {      ticks.push({value});    }    return ticks;  }  getLabelForValue(value) {    const labels = this.getLabels();    if (value >= 0 && value < labels.length) {      return labels[value];    }    return value;  }  configure() {    super.configure();    if (!this.isHorizontal()) {      this._reversePixels = !this._reversePixels;    }  }  getPixelForValue(value) {    if (typeof value !== 'number') {      value = this.parse(value);    }    return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);  }  getPixelForTick(index) {    const ticks = this.ticks;    if (index < 0 || index > ticks.length - 1) {      return null;    }    return this.getPixelForValue(ticks[index].value);  }  getValueForPixel(pixel) {    return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange);  }  getBasePixel() {    return this.bottom;  }}CategoryScale.id = 'category';CategoryScale.defaults = {  ticks: {    callback: CategoryScale.prototype.getLabelForValue  }};function generateTicks$1(generationOptions, dataRange) {  const ticks = [];  const MIN_SPACING = 1e-14;  const {bounds, step, min, max, precision, count, maxTicks, maxDigits, includeBounds} = generationOptions;  const unit = step || 1;  const maxSpaces = maxTicks - 1;  const {min: rmin, max: rmax} = dataRange;  const minDefined = !isNullOrUndef(min);  const maxDefined = !isNullOrUndef(max);  const countDefined = !isNullOrUndef(count);  const minSpacing = (rmax - rmin) / (maxDigits + 1);  let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit;  let factor, niceMin, niceMax, numSpaces;  if (spacing < MIN_SPACING && !minDefined && !maxDefined) {    return [{value: rmin}, {value: rmax}];  }  numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);  if (numSpaces > maxSpaces) {    spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit;  }  if (!isNullOrUndef(precision)) {    factor = Math.pow(10, precision);    spacing = Math.ceil(spacing * factor) / factor;  }  if (bounds === 'ticks') {    niceMin = Math.floor(rmin / spacing) * spacing;    niceMax = Math.ceil(rmax / spacing) * spacing;  } else {    niceMin = rmin;    niceMax = rmax;  }  if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) {    numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks));    spacing = (max - min) / numSpaces;    niceMin = min;    niceMax = max;  } else if (countDefined) {    niceMin = minDefined ? min : niceMin;    niceMax = maxDefined ? max : niceMax;    numSpaces = count - 1;    spacing = (niceMax - niceMin) / numSpaces;  } else {    numSpaces = (niceMax - niceMin) / spacing;    if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {      numSpaces = Math.round(numSpaces);    } else {      numSpaces = Math.ceil(numSpaces);    }  }  const decimalPlaces = Math.max(    _decimalPlaces(spacing),    _decimalPlaces(niceMin)  );  factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision);  niceMin = Math.round(niceMin * factor) / factor;  niceMax = Math.round(niceMax * factor) / factor;  let j = 0;  if (minDefined) {    if (includeBounds && niceMin !== min) {      ticks.push({value: min});      if (niceMin < min) {        j++;      }      if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) {        j++;      }    } else if (niceMin < min) {      j++;    }  }  for (; j < numSpaces; ++j) {    ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor});  }  if (maxDefined && includeBounds && niceMax !== max) {    if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) {      ticks[ticks.length - 1].value = max;    } else {      ticks.push({value: max});    }  } else if (!maxDefined || niceMax === max) {    ticks.push({value: niceMax});  }  return ticks;}function relativeLabelSize(value, minSpacing, {horizontal, minRotation}) {  const rad = toRadians(minRotation);  const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001;  const length = 0.75 * minSpacing * ('' + value).length;  return Math.min(minSpacing / ratio, length);}class LinearScaleBase extends Scale {  constructor(cfg) {    super(cfg);    this.start = undefined;    this.end = undefined;    this._startValue = undefined;    this._endValue = undefined;    this._valueRange = 0;  }  parse(raw, index) {    if (isNullOrUndef(raw)) {      return null;    }    if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {      return null;    }    return +raw;  }  handleTickRangeOptions() {    const {beginAtZero} = this.options;    const {minDefined, maxDefined} = this.getUserBounds();    let {min, max} = this;    const setMin = v => (min = minDefined ? min : v);    const setMax = v => (max = maxDefined ? max : v);    if (beginAtZero) {      const minSign = sign(min);      const maxSign = sign(max);      if (minSign < 0 && maxSign < 0) {        setMax(0);      } else if (minSign > 0 && maxSign > 0) {        setMin(0);      }    }    if (min === max) {      let offset = 1;      if (max >= Number.MAX_SAFE_INTEGER || min <= Number.MIN_SAFE_INTEGER) {        offset = Math.abs(max * 0.05);      }      setMax(max + offset);      if (!beginAtZero) {        setMin(min - offset);      }    }    this.min = min;    this.max = max;  }  getTickLimit() {    const tickOpts = this.options.ticks;    let {maxTicksLimit, stepSize} = tickOpts;    let maxTicks;    if (stepSize) {      maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1;      if (maxTicks > 1000) {        console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`);        maxTicks = 1000;      }    } else {      maxTicks = this.computeTickLimit();      maxTicksLimit = maxTicksLimit || 11;    }    if (maxTicksLimit) {      maxTicks = Math.min(maxTicksLimit, maxTicks);    }    return maxTicks;  }  computeTickLimit() {    return Number.POSITIVE_INFINITY;  }  buildTicks() {    const opts = this.options;    const tickOpts = opts.ticks;    let maxTicks = this.getTickLimit();    maxTicks = Math.max(2, maxTicks);    const numericGeneratorOptions = {      maxTicks,      bounds: opts.bounds,      min: opts.min,      max: opts.max,      precision: tickOpts.precision,      step: tickOpts.stepSize,      count: tickOpts.count,      maxDigits: this._maxDigits(),      horizontal: this.isHorizontal(),      minRotation: tickOpts.minRotation || 0,      includeBounds: tickOpts.includeBounds !== false    };    const dataRange = this._range || this;    const ticks = generateTicks$1(numericGeneratorOptions, dataRange);    if (opts.bounds === 'ticks') {      _setMinAndMaxByKey(ticks, this, 'value');    }    if (opts.reverse) {      ticks.reverse();      this.start = this.max;      this.end = this.min;    } else {      this.start = this.min;      this.end = this.max;    }    return ticks;  }  configure() {    const ticks = this.ticks;    let start = this.min;    let end = this.max;    super.configure();    if (this.options.offset && ticks.length) {      const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;      start -= offset;      end += offset;    }    this._startValue = start;    this._endValue = end;    this._valueRange = end - start;  }  getLabelForValue(value) {    return formatNumber(value, this.chart.options.locale, this.options.ticks.format);  }}class LinearScale extends LinearScaleBase {  determineDataLimits() {    const {min, max} = this.getMinMax(true);    this.min = isNumberFinite(min) ? min : 0;    this.max = isNumberFinite(max) ? max : 1;    this.handleTickRangeOptions();  }  computeTickLimit() {    const horizontal = this.isHorizontal();    const length = horizontal ? this.width : this.height;    const minRotation = toRadians(this.options.ticks.minRotation);    const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001;    const tickFont = this._resolveTickFontOptions(0);    return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio));  }  getPixelForValue(value) {    return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);  }  getValueForPixel(pixel) {    return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;  }}LinearScale.id = 'linear';LinearScale.defaults = {  ticks: {    callback: Ticks.formatters.numeric  }};function isMajor(tickVal) {  const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal))));  return remain === 1;}function generateTicks(generationOptions, dataRange) {  const endExp = Math.floor(log10(dataRange.max));  const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));  const ticks = [];  let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));  let exp = Math.floor(log10(tickVal));  let significand = Math.floor(tickVal / Math.pow(10, exp));  let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;  do {    ticks.push({value: tickVal, major: isMajor(tickVal)});    ++significand;    if (significand === 10) {      significand = 1;      ++exp;      precision = exp >= 0 ? 1 : precision;    }    tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;  } while (exp < endExp || (exp === endExp && significand < endSignificand));  const lastTick = finiteOrDefault(generationOptions.max, tickVal);  ticks.push({value: lastTick, major: isMajor(tickVal)});  return ticks;}class LogarithmicScale extends Scale {  constructor(cfg) {    super(cfg);    this.start = undefined;    this.end = undefined;    this._startValue = undefined;    this._valueRange = 0;  }  parse(raw, index) {    const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]);    if (value === 0) {      this._zero = true;      return undefined;    }    return isNumberFinite(value) && value > 0 ? value : null;  }  determineDataLimits() {    const {min, max} = this.getMinMax(true);    this.min = isNumberFinite(min) ? Math.max(0, min) : null;    this.max = isNumberFinite(max) ? Math.max(0, max) : null;    if (this.options.beginAtZero) {      this._zero = true;    }    this.handleTickRangeOptions();  }  handleTickRangeOptions() {    const {minDefined, maxDefined} = this.getUserBounds();    let min = this.min;    let max = this.max;    const setMin = v => (min = minDefined ? min : v);    const setMax = v => (max = maxDefined ? max : v);    const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m);    if (min === max) {      if (min <= 0) {        setMin(1);        setMax(10);      } else {        setMin(exp(min, -1));        setMax(exp(max, +1));      }    }    if (min <= 0) {      setMin(exp(max, -1));    }    if (max <= 0) {      setMax(exp(min, +1));    }    if (this._zero && this.min !== this._suggestedMin && min === exp(this.min, 0)) {      setMin(exp(min, -1));    }    this.min = min;    this.max = max;  }  buildTicks() {    const opts = this.options;    const generationOptions = {      min: this._userMin,      max: this._userMax    };    const ticks = generateTicks(generationOptions, this);    if (opts.bounds === 'ticks') {      _setMinAndMaxByKey(ticks, this, 'value');    }    if (opts.reverse) {      ticks.reverse();      this.start = this.max;      this.end = this.min;    } else {      this.start = this.min;      this.end = this.max;    }    return ticks;  }  getLabelForValue(value) {    return value === undefined      ? '0'      : formatNumber(value, this.chart.options.locale, this.options.ticks.format);  }  configure() {    const start = this.min;    super.configure();    this._startValue = log10(start);    this._valueRange = log10(this.max) - log10(start);  }  getPixelForValue(value) {    if (value === undefined || value === 0) {      value = this.min;    }    if (value === null || isNaN(value)) {      return NaN;    }    return this.getPixelForDecimal(value === this.min      ? 0      : (log10(value) - this._startValue) / this._valueRange);  }  getValueForPixel(pixel) {    const decimal = this.getDecimalForPixel(pixel);    return Math.pow(10, this._startValue + decimal * this._valueRange);  }}LogarithmicScale.id = 'logarithmic';LogarithmicScale.defaults = {  ticks: {    callback: Ticks.formatters.logarithmic,    major: {      enabled: true    }  }};function getTickBackdropHeight(opts) {  const tickOpts = opts.ticks;  if (tickOpts.display && opts.display) {    const padding = toPadding(tickOpts.backdropPadding);    return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height;  }  return 0;}function measureLabelSize(ctx, font, label) {  label = isArray(label) ? label : [label];  return {    w: _longestText(ctx, font.string, label),    h: label.length * font.lineHeight  };}function determineLimits(angle, pos, size, min, max) {  if (angle === min || angle === max) {    return {      start: pos - (size / 2),      end: pos + (size / 2)    };  } else if (angle < min || angle > max) {    return {      start: pos - size,      end: pos    };  }  return {    start: pos,    end: pos + size  };}function fitWithPointLabels(scale) {  const orig = {    l: scale.left + scale._padding.left,    r: scale.right - scale._padding.right,    t: scale.top + scale._padding.top,    b: scale.bottom - scale._padding.bottom  };  const limits = Object.assign({}, orig);  const labelSizes = [];  const padding = [];  const valueCount = scale._pointLabels.length;  const pointLabelOpts = scale.options.pointLabels;  const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0;  for (let i = 0; i < valueCount; i++) {    const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i));    padding[i] = opts.padding;    const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle);    const plFont = toFont(opts.font);    const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]);    labelSizes[i] = textSize;    const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle);    const angle = Math.round(toDegrees(angleRadians));    const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);    const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);    updateLimits(limits, orig, angleRadians, hLimits, vLimits);  }  scale.setCenterPoint(    orig.l - limits.l,    limits.r - orig.r,    orig.t - limits.t,    limits.b - orig.b  );  scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);}function updateLimits(limits, orig, angle, hLimits, vLimits) {  const sin = Math.abs(Math.sin(angle));  const cos = Math.abs(Math.cos(angle));  let x = 0;  let y = 0;  if (hLimits.start < orig.l) {    x = (orig.l - hLimits.start) / sin;    limits.l = Math.min(limits.l, orig.l - x);  } else if (hLimits.end > orig.r) {    x = (hLimits.end - orig.r) / sin;    limits.r = Math.max(limits.r, orig.r + x);  }  if (vLimits.start < orig.t) {    y = (orig.t - vLimits.start) / cos;    limits.t = Math.min(limits.t, orig.t - y);  } else if (vLimits.end > orig.b) {    y = (vLimits.end - orig.b) / cos;    limits.b = Math.max(limits.b, orig.b + y);  }}function buildPointLabelItems(scale, labelSizes, padding) {  const items = [];  const valueCount = scale._pointLabels.length;  const opts = scale.options;  const extra = getTickBackdropHeight(opts) / 2;  const outerDistance = scale.drawingArea;  const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0;  for (let i = 0; i < valueCount; i++) {    const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle);    const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI)));    const size = labelSizes[i];    const y = yForAngle(pointLabelPosition.y, size.h, angle);    const textAlign = getTextAlignForAngle(angle);    const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign);    items.push({      x: pointLabelPosition.x,      y,      textAlign,      left,      top: y,      right: left + size.w,      bottom: y + size.h    });  }  return items;}function getTextAlignForAngle(angle) {  if (angle === 0 || angle === 180) {    return 'center';  } else if (angle < 180) {    return 'left';  }  return 'right';}function leftForTextAlign(x, w, align) {  if (align === 'right') {    x -= w;  } else if (align === 'center') {    x -= (w / 2);  }  return x;}function yForAngle(y, h, angle) {  if (angle === 90 || angle === 270) {    y -= (h / 2);  } else if (angle > 270 || angle < 90) {    y -= h;  }  return y;}function drawPointLabels(scale, labelCount) {  const {ctx, options: {pointLabels}} = scale;  for (let i = labelCount - 1; i >= 0; i--) {    const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i));    const plFont = toFont(optsAtIndex.font);    const {x, y, textAlign, left, top, right, bottom} = scale._pointLabelItems[i];    const {backdropColor} = optsAtIndex;    if (!isNullOrUndef(backdropColor)) {      const padding = toPadding(optsAtIndex.backdropPadding);      ctx.fillStyle = backdropColor;      ctx.fillRect(left - padding.left, top - padding.top, right - left + padding.width, bottom - top + padding.height);    }    renderText(      ctx,      scale._pointLabels[i],      x,      y + (plFont.lineHeight / 2),      plFont,      {        color: optsAtIndex.color,        textAlign: textAlign,        textBaseline: 'middle'      }    );  }}function pathRadiusLine(scale, radius, circular, labelCount) {  const {ctx} = scale;  if (circular) {    ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU);  } else {    let pointPosition = scale.getPointPosition(0, radius);    ctx.moveTo(pointPosition.x, pointPosition.y);    for (let i = 1; i < labelCount; i++) {      pointPosition = scale.getPointPosition(i, radius);      ctx.lineTo(pointPosition.x, pointPosition.y);    }  }}function drawRadiusLine(scale, gridLineOpts, radius, labelCount) {  const ctx = scale.ctx;  const circular = gridLineOpts.circular;  const {color, lineWidth} = gridLineOpts;  if ((!circular && !labelCount) || !color || !lineWidth || radius < 0) {    return;  }  ctx.save();  ctx.strokeStyle = color;  ctx.lineWidth = lineWidth;  ctx.setLineDash(gridLineOpts.borderDash);  ctx.lineDashOffset = gridLineOpts.borderDashOffset;  ctx.beginPath();  pathRadiusLine(scale, radius, circular, labelCount);  ctx.closePath();  ctx.stroke();  ctx.restore();}function createPointLabelContext(parent, index, label) {  return createContext(parent, {    label,    index,    type: 'pointLabel'  });}class RadialLinearScale extends LinearScaleBase {  constructor(cfg) {    super(cfg);    this.xCenter = undefined;    this.yCenter = undefined;    this.drawingArea = undefined;    this._pointLabels = [];    this._pointLabelItems = [];  }  setDimensions() {    const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2);    const w = this.width = this.maxWidth - padding.width;    const h = this.height = this.maxHeight - padding.height;    this.xCenter = Math.floor(this.left + w / 2 + padding.left);    this.yCenter = Math.floor(this.top + h / 2 + padding.top);    this.drawingArea = Math.floor(Math.min(w, h) / 2);  }  determineDataLimits() {    const {min, max} = this.getMinMax(false);    this.min = isNumberFinite(min) && !isNaN(min) ? min : 0;    this.max = isNumberFinite(max) && !isNaN(max) ? max : 0;    this.handleTickRangeOptions();  }  computeTickLimit() {    return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));  }  generateTickLabels(ticks) {    LinearScaleBase.prototype.generateTickLabels.call(this, ticks);    this._pointLabels = this.getLabels()      .map((value, index) => {        const label = callback(this.options.pointLabels.callback, [value, index], this);        return label || label === 0 ? label : '';      })      .filter((v, i) => this.chart.getDataVisibility(i));  }  fit() {    const opts = this.options;    if (opts.display && opts.pointLabels.display) {      fitWithPointLabels(this);    } else {      this.setCenterPoint(0, 0, 0, 0);    }  }  setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {    this.xCenter += Math.floor((leftMovement - rightMovement) / 2);    this.yCenter += Math.floor((topMovement - bottomMovement) / 2);    this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));  }  getIndexAngle(index) {    const angleMultiplier = TAU / (this._pointLabels.length || 1);    const startAngle = this.options.startAngle || 0;    return _normalizeAngle(index * angleMultiplier + toRadians(startAngle));  }  getDistanceFromCenterForValue(value) {    if (isNullOrUndef(value)) {      return NaN;    }    const scalingFactor = this.drawingArea / (this.max - this.min);    if (this.options.reverse) {      return (this.max - value) * scalingFactor;    }    return (value - this.min) * scalingFactor;  }  getValueForDistanceFromCenter(distance) {    if (isNullOrUndef(distance)) {      return NaN;    }    const scaledDistance = distance / (this.drawingArea / (this.max - this.min));    return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance;  }  getPointLabelContext(index) {    const pointLabels = this._pointLabels || [];    if (index >= 0 && index < pointLabels.length) {      const pointLabel = pointLabels[index];      return createPointLabelContext(this.getContext(), index, pointLabel);    }  }  getPointPosition(index, distanceFromCenter, additionalAngle = 0) {    const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle;    return {      x: Math.cos(angle) * distanceFromCenter + this.xCenter,      y: Math.sin(angle) * distanceFromCenter + this.yCenter,      angle    };  }  getPointPositionForValue(index, value) {    return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));  }  getBasePosition(index) {    return this.getPointPositionForValue(index || 0, this.getBaseValue());  }  getPointLabelPosition(index) {    const {left, top, right, bottom} = this._pointLabelItems[index];    return {      left,      top,      right,      bottom,    };  }  drawBackground() {    const {backgroundColor, grid: {circular}} = this.options;    if (backgroundColor) {      const ctx = this.ctx;      ctx.save();      ctx.beginPath();      pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);      ctx.closePath();      ctx.fillStyle = backgroundColor;      ctx.fill();      ctx.restore();    }  }  drawGrid() {    const ctx = this.ctx;    const opts = this.options;    const {angleLines, grid} = opts;    const labelCount = this._pointLabels.length;    let i, offset, position;    if (opts.pointLabels.display) {      drawPointLabels(this, labelCount);    }    if (grid.display) {      this.ticks.forEach((tick, index) => {        if (index !== 0) {          offset = this.getDistanceFromCenterForValue(tick.value);          const optsAtIndex = grid.setContext(this.getContext(index - 1));          drawRadiusLine(this, optsAtIndex, offset, labelCount);        }      });    }    if (angleLines.display) {      ctx.save();      for (i = labelCount - 1; i >= 0; i--) {        const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i));        const {color, lineWidth} = optsAtIndex;        if (!lineWidth || !color) {          continue;        }        ctx.lineWidth = lineWidth;        ctx.strokeStyle = color;        ctx.setLineDash(optsAtIndex.borderDash);        ctx.lineDashOffset = optsAtIndex.borderDashOffset;        offset = this.getDistanceFromCenterForValue(opts.ticks.reverse ? this.min : this.max);        position = this.getPointPosition(i, offset);        ctx.beginPath();        ctx.moveTo(this.xCenter, this.yCenter);        ctx.lineTo(position.x, position.y);        ctx.stroke();      }      ctx.restore();    }  }  drawBorder() {}  drawLabels() {    const ctx = this.ctx;    const opts = this.options;    const tickOpts = opts.ticks;    if (!tickOpts.display) {      return;    }    const startAngle = this.getIndexAngle(0);    let offset, width;    ctx.save();    ctx.translate(this.xCenter, this.yCenter);    ctx.rotate(startAngle);    ctx.textAlign = 'center';    ctx.textBaseline = 'middle';    this.ticks.forEach((tick, index) => {      if (index === 0 && !opts.reverse) {        return;      }      const optsAtIndex = tickOpts.setContext(this.getContext(index));      const tickFont = toFont(optsAtIndex.font);      offset = this.getDistanceFromCenterForValue(this.ticks[index].value);      if (optsAtIndex.showLabelBackdrop) {        ctx.font = tickFont.string;        width = ctx.measureText(tick.label).width;        ctx.fillStyle = optsAtIndex.backdropColor;        const padding = toPadding(optsAtIndex.backdropPadding);        ctx.fillRect(          -width / 2 - padding.left,          -offset - tickFont.size / 2 - padding.top,          width + padding.width,          tickFont.size + padding.height        );      }      renderText(ctx, tick.label, 0, -offset, tickFont, {        color: optsAtIndex.color,      });    });    ctx.restore();  }  drawTitle() {}}RadialLinearScale.id = 'radialLinear';RadialLinearScale.defaults = {  display: true,  animate: true,  position: 'chartArea',  angleLines: {    display: true,    lineWidth: 1,    borderDash: [],    borderDashOffset: 0.0  },  grid: {    circular: false  },  startAngle: 0,  ticks: {    showLabelBackdrop: true,    callback: Ticks.formatters.numeric  },  pointLabels: {    backdropColor: undefined,    backdropPadding: 2,    display: true,    font: {      size: 10    },    callback(label) {      return label;    },    padding: 5,    centerPointLabels: false  }};RadialLinearScale.defaultRoutes = {  'angleLines.color': 'borderColor',  'pointLabels.color': 'color',  'ticks.color': 'color'};RadialLinearScale.descriptors = {  angleLines: {    _fallback: 'grid'  }};const INTERVALS = {  millisecond: {common: true, size: 1, steps: 1000},  second: {common: true, size: 1000, steps: 60},  minute: {common: true, size: 60000, steps: 60},  hour: {common: true, size: 3600000, steps: 24},  day: {common: true, size: 86400000, steps: 30},  week: {common: false, size: 604800000, steps: 4},  month: {common: true, size: 2.628e9, steps: 12},  quarter: {common: false, size: 7.884e9, steps: 4},  year: {common: true, size: 3.154e10}};const UNITS = (Object.keys(INTERVALS));function sorter(a, b) {  return a - b;}function parse(scale, input) {  if (isNullOrUndef(input)) {    return null;  }  const adapter = scale._adapter;  const {parser, round, isoWeekday} = scale._parseOpts;  let value = input;  if (typeof parser === 'function') {    value = parser(value);  }  if (!isNumberFinite(value)) {    value = typeof parser === 'string'      ? adapter.parse(value, parser)      : adapter.parse(value);  }  if (value === null) {    return null;  }  if (round) {    value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true)      ? adapter.startOf(value, 'isoWeek', isoWeekday)      : adapter.startOf(value, round);  }  return +value;}function determineUnitForAutoTicks(minUnit, min, max, capacity) {  const ilen = UNITS.length;  for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {    const interval = INTERVALS[UNITS[i]];    const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER;    if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {      return UNITS[i];    }  }  return UNITS[ilen - 1];}function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {  for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {    const unit = UNITS[i];    if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {      return unit;    }  }  return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];}function determineMajorUnit(unit) {  for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {    if (INTERVALS[UNITS[i]].common) {      return UNITS[i];    }  }}function addTick(ticks, time, timestamps) {  if (!timestamps) {    ticks[time] = true;  } else if (timestamps.length) {    const {lo, hi} = _lookup(timestamps, time);    const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];    ticks[timestamp] = true;  }}function setMajorTicks(scale, ticks, map, majorUnit) {  const adapter = scale._adapter;  const first = +adapter.startOf(ticks[0].value, majorUnit);  const last = ticks[ticks.length - 1].value;  let major, index;  for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) {    index = map[major];    if (index >= 0) {      ticks[index].major = true;    }  }  return ticks;}function ticksFromTimestamps(scale, values, majorUnit) {  const ticks = [];  const map = {};  const ilen = values.length;  let i, value;  for (i = 0; i < ilen; ++i) {    value = values[i];    map[value] = i;    ticks.push({      value,      major: false    });  }  return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);}class TimeScale extends Scale {  constructor(props) {    super(props);    this._cache = {      data: [],      labels: [],      all: []    };    this._unit = 'day';    this._majorUnit = undefined;    this._offsets = {};    this._normalized = false;    this._parseOpts = undefined;  }  init(scaleOpts, opts) {    const time = scaleOpts.time || (scaleOpts.time = {});    const adapter = this._adapter = new _adapters._date(scaleOpts.adapters.date);    mergeIf(time.displayFormats, adapter.formats());    this._parseOpts = {      parser: time.parser,      round: time.round,      isoWeekday: time.isoWeekday    };    super.init(scaleOpts);    this._normalized = opts.normalized;  }  parse(raw, index) {    if (raw === undefined) {      return null;    }    return parse(this, raw);  }  beforeLayout() {    super.beforeLayout();    this._cache = {      data: [],      labels: [],      all: []    };  }  determineDataLimits() {    const options = this.options;    const adapter = this._adapter;    const unit = options.time.unit || 'day';    let {min, max, minDefined, maxDefined} = this.getUserBounds();    function _applyBounds(bounds) {      if (!minDefined && !isNaN(bounds.min)) {        min = Math.min(min, bounds.min);      }      if (!maxDefined && !isNaN(bounds.max)) {        max = Math.max(max, bounds.max);      }    }    if (!minDefined || !maxDefined) {      _applyBounds(this._getLabelBounds());      if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {        _applyBounds(this.getMinMax(false));      }    }    min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);    max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;    this.min = Math.min(min, max - 1);    this.max = Math.max(min + 1, max);  }  _getLabelBounds() {    const arr = this.getLabelTimestamps();    let min = Number.POSITIVE_INFINITY;    let max = Number.NEGATIVE_INFINITY;    if (arr.length) {      min = arr[0];      max = arr[arr.length - 1];    }    return {min, max};  }  buildTicks() {    const options = this.options;    const timeOpts = options.time;    const tickOpts = options.ticks;    const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate();    if (options.bounds === 'ticks' && timestamps.length) {      this.min = this._userMin || timestamps[0];      this.max = this._userMax || timestamps[timestamps.length - 1];    }    const min = this.min;    const max = this.max;    const ticks = _filterBetween(timestamps, min, max);    this._unit = timeOpts.unit || (tickOpts.autoSkip      ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min))      : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max));    this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined      : determineMajorUnit(this._unit);    this.initOffsets(timestamps);    if (options.reverse) {      ticks.reverse();    }    return ticksFromTimestamps(this, ticks, this._majorUnit);  }  initOffsets(timestamps) {    let start = 0;    let end = 0;    let first, last;    if (this.options.offset && timestamps.length) {      first = this.getDecimalForValue(timestamps[0]);      if (timestamps.length === 1) {        start = 1 - first;      } else {        start = (this.getDecimalForValue(timestamps[1]) - first) / 2;      }      last = this.getDecimalForValue(timestamps[timestamps.length - 1]);      if (timestamps.length === 1) {        end = last;      } else {        end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;      }    }    const limit = timestamps.length < 3 ? 0.5 : 0.25;    start = _limitValue(start, 0, limit);    end = _limitValue(end, 0, limit);    this._offsets = {start, end, factor: 1 / (start + 1 + end)};  }  _generate() {    const adapter = this._adapter;    const min = this.min;    const max = this.max;    const options = this.options;    const timeOpts = options.time;    const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));    const stepSize = valueOrDefault(timeOpts.stepSize, 1);    const weekday = minor === 'week' ? timeOpts.isoWeekday : false;    const hasWeekday = isNumber(weekday) || weekday === true;    const ticks = {};    let first = min;    let time, count;    if (hasWeekday) {      first = +adapter.startOf(first, 'isoWeek', weekday);    }    first = +adapter.startOf(first, hasWeekday ? 'day' : minor);    if (adapter.diff(max, min, minor) > 100000 * stepSize) {      throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);    }    const timestamps = options.ticks.source === 'data' && this.getDataTimestamps();    for (time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++) {      addTick(ticks, time, timestamps);    }    if (time === max || options.bounds === 'ticks' || count === 1) {      addTick(ticks, time, timestamps);    }    return Object.keys(ticks).sort((a, b) => a - b).map(x => +x);  }  getLabelForValue(value) {    const adapter = this._adapter;    const timeOpts = this.options.time;    if (timeOpts.tooltipFormat) {      return adapter.format(value, timeOpts.tooltipFormat);    }    return adapter.format(value, timeOpts.displayFormats.datetime);  }  _tickFormatFunction(time, index, ticks, format) {    const options = this.options;    const formats = options.time.displayFormats;    const unit = this._unit;    const majorUnit = this._majorUnit;    const minorFormat = unit && formats[unit];    const majorFormat = majorUnit && formats[majorUnit];    const tick = ticks[index];    const major = majorUnit && majorFormat && tick && tick.major;    const label = this._adapter.format(time, format || (major ? majorFormat : minorFormat));    const formatter = options.ticks.callback;    return formatter ? callback(formatter, [label, index, ticks], this) : label;  }  generateTickLabels(ticks) {    let i, ilen, tick;    for (i = 0, ilen = ticks.length; i < ilen; ++i) {      tick = ticks[i];      tick.label = this._tickFormatFunction(tick.value, i, ticks);    }  }  getDecimalForValue(value) {    return value === null ? NaN : (value - this.min) / (this.max - this.min);  }  getPixelForValue(value) {    const offsets = this._offsets;    const pos = this.getDecimalForValue(value);    return this.getPixelForDecimal((offsets.start + pos) * offsets.factor);  }  getValueForPixel(pixel) {    const offsets = this._offsets;    const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;    return this.min + pos * (this.max - this.min);  }  _getLabelSize(label) {    const ticksOpts = this.options.ticks;    const tickLabelWidth = this.ctx.measureText(label).width;    const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);    const cosRotation = Math.cos(angle);    const sinRotation = Math.sin(angle);    const tickFontSize = this._resolveTickFontOptions(0).size;    return {      w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation),      h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation)    };  }  _getLabelCapacity(exampleTime) {    const timeOpts = this.options.time;    const displayFormats = timeOpts.displayFormats;    const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;    const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [exampleTime], this._majorUnit), format);    const size = this._getLabelSize(exampleLabel);    const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1;    return capacity > 0 ? capacity : 1;  }  getDataTimestamps() {    let timestamps = this._cache.data || [];    let i, ilen;    if (timestamps.length) {      return timestamps;    }    const metas = this.getMatchingVisibleMetas();    if (this._normalized && metas.length) {      return (this._cache.data = metas[0].controller.getAllParsedValues(this));    }    for (i = 0, ilen = metas.length; i < ilen; ++i) {      timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this));    }    return (this._cache.data = this.normalize(timestamps));  }  getLabelTimestamps() {    const timestamps = this._cache.labels || [];    let i, ilen;    if (timestamps.length) {      return timestamps;    }    const labels = this.getLabels();    for (i = 0, ilen = labels.length; i < ilen; ++i) {      timestamps.push(parse(this, labels[i]));    }    return (this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps));  }  normalize(values) {    return _arrayUnique(values.sort(sorter));  }}TimeScale.id = 'time';TimeScale.defaults = {  bounds: 'data',  adapters: {},  time: {    parser: false,    unit: false,    round: false,    isoWeekday: false,    minUnit: 'millisecond',    displayFormats: {}  },  ticks: {    source: 'auto',    major: {      enabled: false    }  }};function interpolate(table, val, reverse) {  let lo = 0;  let hi = table.length - 1;  let prevSource, nextSource, prevTarget, nextTarget;  if (reverse) {    if (val >= table[lo].pos && val <= table[hi].pos) {      ({lo, hi} = _lookupByKey(table, 'pos', val));    }    ({pos: prevSource, time: prevTarget} = table[lo]);    ({pos: nextSource, time: nextTarget} = table[hi]);  } else {    if (val >= table[lo].time && val <= table[hi].time) {      ({lo, hi} = _lookupByKey(table, 'time', val));    }    ({time: prevSource, pos: prevTarget} = table[lo]);    ({time: nextSource, pos: nextTarget} = table[hi]);  }  const span = nextSource - prevSource;  return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;}class TimeSeriesScale extends TimeScale {  constructor(props) {    super(props);    this._table = [];    this._minPos = undefined;    this._tableRange = undefined;  }  initOffsets() {    const timestamps = this._getTimestampsForTable();    const table = this._table = this.buildLookupTable(timestamps);    this._minPos = interpolate(table, this.min);    this._tableRange = interpolate(table, this.max) - this._minPos;    super.initOffsets(timestamps);  }  buildLookupTable(timestamps) {    const {min, max} = this;    const items = [];    const table = [];    let i, ilen, prev, curr, next;    for (i = 0, ilen = timestamps.length; i < ilen; ++i) {      curr = timestamps[i];      if (curr >= min && curr <= max) {        items.push(curr);      }    }    if (items.length < 2) {      return [        {time: min, pos: 0},        {time: max, pos: 1}      ];    }    for (i = 0, ilen = items.length; i < ilen; ++i) {      next = items[i + 1];      prev = items[i - 1];      curr = items[i];      if (Math.round((next + prev) / 2) !== curr) {        table.push({time: curr, pos: i / (ilen - 1)});      }    }    return table;  }  _getTimestampsForTable() {    let timestamps = this._cache.all || [];    if (timestamps.length) {      return timestamps;    }    const data = this.getDataTimestamps();    const label = this.getLabelTimestamps();    if (data.length && label.length) {      timestamps = this.normalize(data.concat(label));    } else {      timestamps = data.length ? data : label;    }    timestamps = this._cache.all = timestamps;    return timestamps;  }  getDecimalForValue(value) {    return (interpolate(this._table, value) - this._minPos) / this._tableRange;  }  getValueForPixel(pixel) {    const offsets = this._offsets;    const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;    return interpolate(this._table, decimal * this._tableRange + this._minPos, true);  }}TimeSeriesScale.id = 'timeseries';TimeSeriesScale.defaults = TimeScale.defaults;var scales = /*#__PURE__*/Object.freeze({__proto__: null,CategoryScale: CategoryScale,LinearScale: LinearScale,LogarithmicScale: LogarithmicScale,RadialLinearScale: RadialLinearScale,TimeScale: TimeScale,TimeSeriesScale: TimeSeriesScale});Chart.register(controllers, scales, elements, plugins);Chart.helpers = {...helpers};Chart._adapters = _adapters;Chart.Animation = Animation;Chart.Animations = Animations;Chart.animator = animator;Chart.controllers = registry.controllers.items;Chart.DatasetController = DatasetController;Chart.Element = Element;Chart.elements = elements;Chart.Interaction = Interaction;Chart.layouts = layouts;Chart.platforms = platforms;Chart.Scale = Scale;Chart.Ticks = Ticks;Object.assign(Chart, controllers, scales, elements, plugins, platforms);Chart.Chart = Chart;if (typeof window !== 'undefined') {  window.Chart = Chart;}return Chart;}));
 |