| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578 | 
							- (function (factory) {
 
- 	typeof define === 'function' && define.amd ? define(factory) :
 
- 	factory();
 
- })((function () { 'use strict';
 
- 	var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
 
- 	function getDefaultExportFromCjs (x) {
 
- 		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
 
- 	}
 
- 	/**
 
- 	 * Create test stream
 
- 	 * @param {string} url
 
- 	 * @param {string} description
 
- 	 * @param {boolean} [live]
 
- 	 * @param {boolean} [abr]
 
- 	 * @param {string[]} [skip_ua]
 
- 	 * @returns {{url: string, description: string, live: boolean, abr: boolean, skip_ua: string[]}}
 
- 	 */
 
- 	function createTestStream(url, description, live, abr, skip_ua) {
 
- 	  if (live === void 0) {
 
- 	    live = false;
 
- 	  }
 
- 	  if (abr === void 0) {
 
- 	    abr = true;
 
- 	  }
 
- 	  if (skip_ua === void 0) {
 
- 	    skip_ua = [];
 
- 	  }
 
- 	  return {
 
- 	    url: url,
 
- 	    description: description,
 
- 	    live: live,
 
- 	    abr: abr,
 
- 	    skip_ua: skip_ua
 
- 	  };
 
- 	}
 
- 	/**
 
- 	 * @param {Object} target
 
- 	 * @param {Object} [config]
 
- 	 * @returns {{url: string, description: string, live: boolean, abr: boolean, skip_ua: string[]}}
 
- 	 */
 
- 	function createTestStreamWithConfig(target, config) {
 
- 	  if (typeof target !== 'object') {
 
- 	    throw new Error('target should be object');
 
- 	  }
 
- 	  var testStream = createTestStream(target.url, target.description, target.live, target.abr, target.skip_ua);
 
- 	  testStream.config = config;
 
- 	  return testStream;
 
- 	}
 
- 	var testStreams$1 = {
 
- 	  bbb: {
 
- 	    url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
 
- 	    description: 'Big Buck Bunny - adaptive qualities',
 
- 	    abr: true
 
- 	  },
 
- 	  fdr: {
 
- 	    url: 'https://cdn.jwplayer.com/manifests/pZxWPRg4.m3u8',
 
- 	    description: 'FDR - CDN packaged, 4s segments, 180p - 1080p',
 
- 	    abr: true
 
- 	  },
 
- 	  bigBuckBunny480p: {
 
- 	    url: 'https://test-streams.mux.dev/x36xhzz/url_6/193039199_mp4_h264_aac_hq_7.m3u8',
 
- 	    description: 'Big Buck Bunny - 480p only',
 
- 	    abr: false
 
- 	  },
 
- 	  arte: {
 
- 	    url: 'https://test-streams.mux.dev/test_001/stream.m3u8',
 
- 	    description: 'ARTE China,ABR',
 
- 	    abr: true
 
- 	  },
 
- 	  deltatreDAI: {
 
- 	    url: 'https://test-streams.mux.dev/dai-discontinuity-deltatre/manifest.m3u8',
 
- 	    description: 'Ad-insertion in event stream',
 
- 	    abr: false
 
- 	  },
 
- 	  issue666: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/issue666/playlists/cisq0gim60007xzvi505emlxx.m3u8',
 
- 	    description: 'Surveillance footage - https://github.com/video-dev/hls.js/issues/666',
 
- 	    abr: false
 
- 	  },
 
- 	  closedCaptions: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/captions/playlist.m3u8',
 
- 	    description: 'CNN special report, with CC',
 
- 	    abr: false
 
- 	  },
 
- 	  customIvBadDts: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/customIV/prog_index.m3u8',
 
- 	    description: 'Custom IV with bad PTS DTS',
 
- 	    abr: false
 
- 	  },
 
- 	  oceansAES: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/oceans_aes/oceans_aes.m3u8',
 
- 	    description: 'AES-128 encrypted, ABR',
 
- 	    abr: true
 
- 	  },
 
- 	  tracksWithAES: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/aes-with-tracks/master.m3u8',
 
- 	    description: 'AES-128 encrypted, TS main with AAC audio track',
 
- 	    abr: false
 
- 	  },
 
- 	  mp3Audio: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/vod-with-mp3/manifest.m3u8',
 
- 	    description: 'MP3 VOD demo',
 
- 	    abr: false
 
- 	  },
 
- 	  mpegAudioOnly: {
 
- 	    url: 'https://pl.streamingvideoprovider.com/mp3-playlist/playlist.m3u8',
 
- 	    description: 'MPEG Audio Only demo',
 
- 	    abr: false,
 
- 	    skip_ua: ['MicrosoftEdge', 'firefox']
 
- 	  },
 
- 	  fmp4: {
 
- 	    url: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8',
 
- 	    description: 'HLS fMP4 Angel-One multiple audio-tracks',
 
- 	    abr: true
 
- 	  },
 
- 	  fmp4Bitmovin: {
 
- 	    url: 'https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s-fmp4/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8',
 
- 	    description: 'HLS fMP4 by Bitmovin',
 
- 	    abr: true
 
- 	  },
 
- 	  fmp4BitmovinHevc: {
 
- 	    url: 'https://bitmovin-a.akamaihd.net/content/dataset/multi-codec/hevc/stream_fmp4.m3u8',
 
- 	    description: 'HLS HEVC fMP4 by Bitmovin (Safari and Edge? only as of 2020-08)',
 
- 	    abr: true,
 
- 	    skipFunctionalTests: true
 
- 	  },
 
- 	  offset_pts: {
 
- 	    url: 'https://test-streams.mux.dev/pts_shift/master.m3u8',
 
- 	    description: 'DK Turntable, PTS shifted by 2.3s',
 
- 	    abr: true
 
- 	  },
 
- 	  angelOneShakaWidevine: createTestStreamWithConfig({
 
- 	    url: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine-hls/hls.m3u8',
 
- 	    description: 'Shaka-packager Widevine DRM (EME) HLS-fMP4 - Angel One Demo',
 
- 	    abr: true,
 
- 	    skip_ua: ['firefox', 'safari', {
 
- 	      name: 'chrome',
 
- 	      version: '75.0'
 
- 	    }, {
 
- 	      name: 'chrome',
 
- 	      version: '79.0'
 
- 	    }]
 
- 	  }, {
 
- 	    widevineLicenseUrl: 'https://cwip-shaka-proxy.appspot.com/no_auth',
 
- 	    emeEnabled: true
 
- 	  }),
 
- 	  audioOnlyMultipleLevels: {
 
- 	    url: 'https://s3.amazonaws.com/qa.jwplayer.com/~alex/121628/new_master.m3u8',
 
- 	    description: 'Multiple non-alternate audio levels',
 
- 	    abr: true
 
- 	  },
 
- 	  pdtDuplicate: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/artbeats/manifest.m3u8',
 
- 	    description: 'Duplicate sequential PDT values',
 
- 	    abr: false
 
- 	  },
 
- 	  pdtLargeGap: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/boxee/playlist.m3u8',
 
- 	    description: 'PDTs with large gaps following discontinuities',
 
- 	    abr: false
 
- 	  },
 
- 	  pdtBadValues: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/progdatime/playlist2.m3u8',
 
- 	    description: 'PDTs with bad values',
 
- 	    abr: false
 
- 	  },
 
- 	  pdtOneValue: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/aviion/manifest.m3u8',
 
- 	    description: 'One PDT, no discontinuities',
 
- 	    abr: false
 
- 	  },
 
- 	  noTrackIntersection: createTestStreamWithConfig({
 
- 	    url: 'https://s3.amazonaws.com/qa.jwplayer.com/~alex/123633/new_master.m3u8',
 
- 	    description: 'Audio/video track PTS values do not intersect; 10 second start gap',
 
- 	    abr: false
 
- 	  }, {
 
- 	    avBufferOffset: 10.5
 
- 	  }),
 
- 	  altAudioAndTracks: {
 
- 	    // url: 'https://wowzaec2demo.streamlock.net/vod-multitrack/_definst_/smil:ElephantsDream/elephantsdream2.smil/playlist.m3u',
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
 
- 	    description: 'Alternate audio tracks, and multiple VTT tracks',
 
- 	    vendor: 'wowza',
 
- 	    abr: true
 
- 	  },
 
- 	  altAudioAudioOnly: createTestStreamWithConfig({
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/alt-audio-no-video/sintel/playlist.m3u8',
 
- 	    description: 'Audio only with alternate audio track (Sintel)',
 
- 	    abr: false
 
- 	  }, {
 
- 	    // the playlist segment durations are longer than the media. So much so, that when seeking near the end,
 
- 	    // the timeline shifts roughly 10 seconds seconds back, and as a result buffering skips several segments
 
- 	    // to adjust for the currentTime now being places at the very end of the stream.
 
- 	    allowedBufferedRangesInSeekTest: 3
 
- 	  }),
 
- 	  altAudioMultiAudioOnly: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/alt-audio-no-video/angel-one.m3u8',
 
- 	    description: 'Audio only with multiple alternate audio tracks (Angel One)',
 
- 	    abr: false
 
- 	  },
 
- 	  muxedFmp4: {
 
- 	    url: 'https://s3.amazonaws.com/qa.jwplayer.com/hlsjs/muxed-fmp4/hls.m3u8',
 
- 	    description: 'Muxed av fmp4 - appended to "audiovideo" SourceBuffer',
 
- 	    abr: false
 
- 	  },
 
- 	  altAudioWithPdtAndStartGap: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/hls-test-streams/test-audio-pdt/playlist.m3u8',
 
- 	    description: 'PDT before each segment, 1.59s start gap',
 
- 	    // Disable smooth switch on this stream. Test is flakey because of what looks like (auto)play issue. To be expected with this large a gap (for now).
 
- 	    // abr: true,
 
- 	    startSeek: true
 
- 	  },
 
- 	  AppleAdvancedHevcAvcHls: {
 
- 	    url: 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8',
 
- 	    description: 'Advanced stream (HEVC/H.264, AC-3/AAC,  WebVTT, fMP4 segments)'
 
- 	  },
 
- 	  MuxLowLatencyHls: {
 
- 	    url: 'https://stream.mux.com/v69RSHhFelSm4701snP22dYz2jICy4E4FUyk02rW4gxRM.m3u8',
 
- 	    description: 'Low-Latency HLS sample of Big Buck Bunny loop and a timer. Restarts every 12 hours. (fMP4 segments)',
 
- 	    live: true
 
- 	  },
 
- 	  //   AppleLowLatencyHls: {
 
- 	  //     url: 'https://ll-hls-test.apple.com/master.m3u8',
 
- 	  //     description: 'Apple Low-Latency HLS sample (TS segments)',
 
- 	  //     live: true,
 
- 	  //   },
 
- 	  //   AppleLowLatencyCmafHls: {
 
- 	  //     url: 'https://ll-hls-test.apple.com/cmaf/master.m3u8',
 
- 	  //     description: 'Apple Low-Latency HLS sample (fMP4 segments)',
 
- 	  //     live: true,
 
- 	  //   },
 
- 	  groupIds: {
 
- 	    url: 'https://mtoczko.github.io/hls-test-streams/test-group/playlist.m3u8',
 
- 	    description: 'Group-id: subtitle and audio',
 
- 	    abr: true,
 
- 	    skipFunctionalTests: true
 
- 	  },
 
- 	  redundantLevelsWithTrackGroups: {
 
- 	    url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/redundant.m3u8',
 
- 	    description: 'Redundant levels with subtitle and audio track groups',
 
- 	    abr: true,
 
- 	    skipFunctionalTests: true
 
- 	  },
 
- 	  startDelimiterOverlappingBetweenPESPackets: {
 
- 	    url: 'https://hlsjs-test-streams-wistia.s3.amazonaws.com/start-delimiter.m3u8',
 
- 	    description: "A stream with the start delimiter overlapping between PES packets.\n       Related to https://github.com/video-dev/hls.js/issues/3834, where Apple Silicon chips throw decoding errors if\n       NAL units are not starting right at the beginning of the PES packet when using hardware accelerated decoding.",
 
- 	    abr: false
 
- 	  }
 
- 	};
 
- 	var main = {};
 
- 	/*
 
- 	 Copyright (c) 2013, Rodrigo González, Sapienlab All Rights Reserved.
 
- 	 Available via MIT LICENSE. See https://github.com/roro89/jsonpack/blob/master/LICENSE.md for details.
 
- 	 */
 
- 	(function (exports) {
 
- 		(function(define) {
 
- 			define([], function() {
 
- 				var TOKEN_TRUE = -1;
 
- 				var TOKEN_FALSE = -2;
 
- 				var TOKEN_NULL = -3;
 
- 				var TOKEN_EMPTY_STRING = -4;
 
- 				var TOKEN_UNDEFINED = -5;
 
- 				var pack = function(json, options) {
 
- 					// Canonizes the options
 
- 					options = options || {};
 
- 					// A shorthand for debugging
 
- 					var verbose = options.verbose || false;
 
- 					verbose && console.log('Normalize the JSON Object');
 
- 					// JSON as Javascript Object (Not string representation)
 
- 					json = typeof json === 'string' ? this.JSON.parse(json) : json;
 
- 					verbose && console.log('Creating a empty dictionary');
 
- 					// The dictionary
 
- 					var dictionary = {
 
- 						strings : [],
 
- 						integers : [],
 
- 						floats : []
 
- 					};
 
- 					verbose && console.log('Creating the AST');
 
- 					// The AST
 
- 					var ast = (function recursiveAstBuilder(item) {
 
- 						verbose && console.log('Calling recursiveAstBuilder with ' + this.JSON.stringify(item));
 
- 						// The type of the item
 
- 						var type = typeof item;
 
- 						// Case 7: The item is null
 
- 						if (item === null) {
 
- 							return {
 
- 								type : 'null',
 
- 								index : TOKEN_NULL
 
- 							};
 
- 						}
 
- 						
 
- 						//add undefined 
 
- 						if (typeof item === 'undefined') {
 
- 							return {
 
- 								type : 'undefined',
 
- 								index : TOKEN_UNDEFINED
 
- 							};
 
- 						}
 
- 						// Case 1: The item is Array Object
 
- 						if ( item instanceof Array) {
 
- 							// Create a new sub-AST of type Array (@)
 
- 							var ast = ['@'];
 
- 							// Add each items
 
- 							for (var i in item) {
 
- 								
 
- 								if (!item.hasOwnProperty(i)) continue;
 
- 								ast.push(recursiveAstBuilder(item[i]));
 
- 							}
 
- 							// And return
 
- 							return ast;
 
- 						}
 
- 						// Case 2: The item is Object
 
- 						if (type === 'object') {
 
- 							// Create a new sub-AST of type Object ($)
 
- 							var ast = ['$'];
 
- 							// Add each items
 
- 							for (var key in item) {
 
- 								if (!item.hasOwnProperty(key))
 
- 									continue;
 
- 								ast.push(recursiveAstBuilder(key));
 
- 								ast.push(recursiveAstBuilder(item[key]));
 
- 							}
 
- 							// And return
 
- 							return ast;
 
- 						}
 
- 						// Case 3: The item empty string
 
- 						if (item === '') {
 
- 							return {
 
- 								type : 'empty',
 
- 								index : TOKEN_EMPTY_STRING
 
- 							};
 
- 						}
 
- 						// Case 4: The item is String
 
- 						if (type === 'string') {
 
- 							// The index of that word in the dictionary
 
- 							var index = _indexOf.call(dictionary.strings, item);
 
- 							// If not, add to the dictionary and actualize the index
 
- 							if (index == -1) {
 
- 								dictionary.strings.push(_encode(item));
 
- 								index = dictionary.strings.length - 1;
 
- 							}
 
- 							// Return the token
 
- 							return {
 
- 								type : 'strings',
 
- 								index : index
 
- 							};
 
- 						}
 
- 						// Case 5: The item is integer
 
- 						if (type === 'number' && item % 1 === 0) {
 
- 							// The index of that number in the dictionary
 
- 							var index = _indexOf.call(dictionary.integers, item);
 
- 							// If not, add to the dictionary and actualize the index
 
- 							if (index == -1) {
 
- 								dictionary.integers.push(_base10To36(item));
 
- 								index = dictionary.integers.length - 1;
 
- 							}
 
- 							// Return the token
 
- 							return {
 
- 								type : 'integers',
 
- 								index : index
 
- 							};
 
- 						}
 
- 						// Case 6: The item is float
 
- 						if (type === 'number') {
 
- 							// The index of that number in the dictionary
 
- 							var index = _indexOf.call(dictionary.floats, item);
 
- 							// If not, add to the dictionary and actualize the index
 
- 							if (index == -1) {
 
- 								// Float not use base 36
 
- 								dictionary.floats.push(item);
 
- 								index = dictionary.floats.length - 1;
 
- 							}
 
- 							// Return the token
 
- 							return {
 
- 								type : 'floats',
 
- 								index : index
 
- 							};
 
- 						}
 
- 						// Case 7: The item is boolean
 
- 						if (type === 'boolean') {
 
- 							return {
 
- 								type : 'boolean',
 
- 								index : item ? TOKEN_TRUE : TOKEN_FALSE
 
- 							};
 
- 						}
 
- 						// Default
 
- 						throw new Error('Unexpected argument of type ' + typeof (item));
 
- 					})(json);
 
- 					// A set of shorthands proxies for the length of the dictionaries
 
- 					var stringLength = dictionary.strings.length;
 
- 					var integerLength = dictionary.integers.length;
 
- 					dictionary.floats.length;
 
- 					verbose && console.log('Parsing the dictionary');
 
- 					// Create a raw dictionary
 
- 					var packed = dictionary.strings.join('|');
 
- 					packed += '^' + dictionary.integers.join('|');
 
- 					packed += '^' + dictionary.floats.join('|');
 
- 					verbose && console.log('Parsing the structure');
 
- 					// And add the structure
 
- 					packed += '^' + (function recursiveParser(item) {
 
- 						verbose && console.log('Calling a recursiveParser with ' + this.JSON.stringify(item));
 
- 						// If the item is Array, then is a object of
 
- 						// type [object Object] or [object Array]
 
- 						if ( item instanceof Array) {
 
- 							// The packed resulting
 
- 							var packed = item.shift();
 
- 							for (var i in item) {
 
- 								
 
- 								if (!item.hasOwnProperty(i)) 
 
- 									continue;
 
- 								
 
- 								packed += recursiveParser(item[i]) + '|';
 
- 							}
 
- 							return (packed[packed.length - 1] === '|' ? packed.slice(0, -1) : packed) + ']';
 
- 						}
 
- 						// A shorthand proxies
 
- 						var type = item.type, index = item.index;
 
- 						if (type === 'strings') {
 
- 							// Just return the base 36 of index
 
- 							return _base10To36(index);
 
- 						}
 
- 						if (type === 'integers') {
 
- 							// Return a base 36 of index plus stringLength offset
 
- 							return _base10To36(stringLength + index);
 
- 						}
 
- 						if (type === 'floats') {
 
- 							// Return a base 36 of index plus stringLength and integerLength offset
 
- 							return _base10To36(stringLength + integerLength + index);
 
- 						}
 
- 						if (type === 'boolean') {
 
- 							return item.index;
 
- 						}
 
- 						if (type === 'null') {
 
- 							return TOKEN_NULL;
 
- 						}
 
- 						if (type === 'undefined') {
 
- 							return TOKEN_UNDEFINED;
 
- 						}
 
- 						if (type === 'empty') {
 
- 							return TOKEN_EMPTY_STRING;
 
- 						}
 
- 						throw new TypeError('The item is alien!');
 
- 					})(ast);
 
- 					verbose && console.log('Ending parser');
 
- 					// If debug, return a internal representation of dictionary and stuff
 
- 					if (options.debug)
 
- 						return {
 
- 							dictionary : dictionary,
 
- 							ast : ast,
 
- 							packed : packed
 
- 						};
 
- 					return packed;
 
- 				};
 
- 				var unpack = function(packed, options) {
 
- 					// Canonizes the options
 
- 					options = options || {};
 
- 					// A raw buffer
 
- 					var rawBuffers = packed.split('^');
 
- 					// Create a dictionary
 
- 					options.verbose && console.log('Building dictionary');
 
- 					var dictionary = [];
 
- 					// Add the strings values
 
- 					var buffer = rawBuffers[0];
 
- 					if (buffer !== '') {
 
- 						buffer = buffer.split('|');
 
- 						options.verbose && console.log('Parse the strings dictionary');
 
- 						for (var i=0, n=buffer.length; i<n; i++){
 
- 							dictionary.push(_decode(buffer[i]));
 
- 						}
 
- 					}
 
- 					// Add the integers values
 
- 					buffer = rawBuffers[1];
 
- 					if (buffer !== '') {
 
- 						buffer = buffer.split('|');
 
- 						options.verbose && console.log('Parse the integers dictionary');
 
- 						for (var i=0, n=buffer.length; i<n; i++){
 
- 							dictionary.push(_base36To10(buffer[i]));
 
- 						}
 
- 					}
 
- 					// Add the floats values
 
- 					buffer = rawBuffers[2];
 
- 					if (buffer !== '') {
 
- 						buffer = buffer.split('|');
 
- 						options.verbose && console.log('Parse the floats dictionary');
 
- 						for (var i=0, n=buffer.length; i<n; i++){
 
- 							dictionary.push(parseFloat(buffer[i]));
 
- 						}
 
- 					}
 
- 					// Free memory
 
- 					buffer = null;
 
- 					options.verbose && console.log('Tokenizing the structure');
 
- 					// Tokenizer the structure
 
- 					var number36 = '';
 
- 					var tokens = [];
 
- 					var len=rawBuffers[3].length;
 
- 					for (var i = 0; i < len; i++) {
 
- 						var symbol = rawBuffers[3].charAt(i);
 
- 						if (symbol === '|' || symbol === '$' || symbol === '@' || symbol === ']') {
 
- 							if (number36) {
 
- 								tokens.push(_base36To10(number36));
 
- 								number36 = '';
 
- 							}
 
- 							symbol !== '|' && tokens.push(symbol);
 
- 						} else {
 
- 							number36 += symbol;
 
- 						}
 
- 					}
 
- 					// A shorthand proxy for tokens.length
 
- 					var tokensLength = tokens.length;
 
- 					// The index of the next token to read
 
- 					var tokensIndex = 0;
 
- 					options.verbose && console.log('Starting recursive parser');
 
- 					return (function recursiveUnpackerParser() {
 
- 						// Maybe '$' (object) or '@' (array)
 
- 						var type = tokens[tokensIndex++];
 
- 						options.verbose && console.log('Reading collection type ' + (type === '$' ? 'object' : 'Array'));
 
- 						// Parse an array
 
- 						if (type === '@') {
 
- 							var node = [];
 
- 							for (; tokensIndex < tokensLength; tokensIndex++) {
 
- 								var value = tokens[tokensIndex];
 
- 								options.verbose && console.log('Read ' + value + ' symbol');
 
- 								if (value === ']')
 
- 									return node;
 
- 								if (value === '@' || value === '$') {
 
- 									node.push(recursiveUnpackerParser());
 
- 								} else {
 
- 									switch(value) {
 
- 										case TOKEN_TRUE:
 
- 											node.push(true);
 
- 											break;
 
- 										case TOKEN_FALSE:
 
- 											node.push(false);
 
- 											break;
 
- 										case TOKEN_NULL:
 
- 											node.push(null);
 
- 											break;
 
- 										case TOKEN_UNDEFINED:
 
- 											node.push(undefined);
 
- 											break;
 
- 										case TOKEN_EMPTY_STRING:
 
- 											node.push('');
 
- 											break;
 
- 										default:
 
- 											node.push(dictionary[value]);
 
- 									}
 
- 								}
 
- 							}
 
- 							options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
 
- 							return node;
 
- 						}
 
- 						// Parse a object
 
- 						if (type === '$') {
 
- 							var node = {};
 
- 							for (; tokensIndex < tokensLength; tokensIndex++) {
 
- 								var key = tokens[tokensIndex];
 
- 								if (key === ']')
 
- 									return node;
 
- 								if (key === TOKEN_EMPTY_STRING)
 
- 									key = '';
 
- 								else
 
- 									key = dictionary[key];
 
- 								var value = tokens[++tokensIndex];
 
- 								if (value === '@' || value === '$') {
 
- 									node[key] = recursiveUnpackerParser();
 
- 								} else {
 
- 									switch(value) {
 
- 										case TOKEN_TRUE:
 
- 											node[key] = true;
 
- 											break;
 
- 										case TOKEN_FALSE:
 
- 											node[key] = false;
 
- 											break;
 
- 										case TOKEN_NULL:
 
- 											node[key] = null;
 
- 											break;
 
- 										case TOKEN_UNDEFINED:
 
- 											node[key] = undefined;
 
- 											break;
 
- 										case TOKEN_EMPTY_STRING:
 
- 											node[key] = '';
 
- 											break;
 
- 										default:
 
- 											node[key] = dictionary[value];
 
- 									}
 
- 								}
 
- 							}
 
- 							options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
 
- 							return node;
 
- 						}
 
- 						throw new TypeError('Bad token ' + type + ' isn\'t a type');
 
- 					})();
 
- 				};
 
- 				var _encode = function(str) {
 
- 					if ( typeof str !== 'string')
 
- 						return str;
 
- 					return str.replace(/[\+ \|\^\%]/g, function(a) {
 
- 						return ({
 
- 						' ' : '+',
 
- 						'+' : '%2B',
 
- 						'|' : '%7C',
 
- 						'^' : '%5E',
 
- 						'%' : '%25'
 
- 						})[a]
 
- 					});
 
- 				};
 
- 				var _decode = function(str) {
 
- 					if ( typeof str !== 'string')
 
- 						return str;
 
- 					return str.replace(/\+|%2B|%7C|%5E|%25/g, function(a) {
 
- 						return ({
 
- 						'+' : ' ',
 
- 						'%2B' : '+',
 
- 						'%7C' : '|',
 
- 						'%5E' : '^',
 
- 						'%25' : '%'
 
- 						})[a]
 
- 					})
 
- 				};
 
- 				var _base10To36 = function(number) {
 
- 					return Number.prototype.toString.call(number, 36).toUpperCase();
 
- 				};
 
- 				var _base36To10 = function(number) {
 
- 					return parseInt(number, 36);
 
- 				};
 
- 				var _indexOf = Array.prototype.indexOf ||
 
- 				function(obj, start) {
 
- 					for (var i = (start || 0), j = this.length; i < j; i++) {
 
- 						if (this[i] === obj) {
 
- 							return i;
 
- 						}
 
- 					}
 
- 					return -1;
 
- 				};
 
- 				return {
 
- 					JSON : JSON,
 
- 					pack : pack,
 
- 					unpack : unpack
 
- 				};
 
- 			});
 
- 		})( function(deps, factory) {
 
- 			var jsonpack = factory();
 
- 			for (var key in jsonpack)
 
- 				exports[key] = jsonpack[key];
 
- 		} ); 
 
- 	} (main));
 
- 	/**
 
- 	 * @this {Promise}
 
- 	 */
 
- 	function finallyConstructor(callback) {
 
- 	  var constructor = this.constructor;
 
- 	  return this.then(
 
- 	    function(value) {
 
- 	      // @ts-ignore
 
- 	      return constructor.resolve(callback()).then(function() {
 
- 	        return value;
 
- 	      });
 
- 	    },
 
- 	    function(reason) {
 
- 	      // @ts-ignore
 
- 	      return constructor.resolve(callback()).then(function() {
 
- 	        // @ts-ignore
 
- 	        return constructor.reject(reason);
 
- 	      });
 
- 	    }
 
- 	  );
 
- 	}
 
- 	function allSettled(arr) {
 
- 	  var P = this;
 
- 	  return new P(function(resolve, reject) {
 
- 	    if (!(arr && typeof arr.length !== 'undefined')) {
 
- 	      return reject(
 
- 	        new TypeError(
 
- 	          typeof arr +
 
- 	            ' ' +
 
- 	            arr +
 
- 	            ' is not iterable(cannot read property Symbol(Symbol.iterator))'
 
- 	        )
 
- 	      );
 
- 	    }
 
- 	    var args = Array.prototype.slice.call(arr);
 
- 	    if (args.length === 0) return resolve([]);
 
- 	    var remaining = args.length;
 
- 	    function res(i, val) {
 
- 	      if (val && (typeof val === 'object' || typeof val === 'function')) {
 
- 	        var then = val.then;
 
- 	        if (typeof then === 'function') {
 
- 	          then.call(
 
- 	            val,
 
- 	            function(val) {
 
- 	              res(i, val);
 
- 	            },
 
- 	            function(e) {
 
- 	              args[i] = { status: 'rejected', reason: e };
 
- 	              if (--remaining === 0) {
 
- 	                resolve(args);
 
- 	              }
 
- 	            }
 
- 	          );
 
- 	          return;
 
- 	        }
 
- 	      }
 
- 	      args[i] = { status: 'fulfilled', value: val };
 
- 	      if (--remaining === 0) {
 
- 	        resolve(args);
 
- 	      }
 
- 	    }
 
- 	    for (var i = 0; i < args.length; i++) {
 
- 	      res(i, args[i]);
 
- 	    }
 
- 	  });
 
- 	}
 
- 	/**
 
- 	 * @constructor
 
- 	 */
 
- 	function AggregateError(errors, message) {
 
- 	  (this.name = 'AggregateError'), (this.errors = errors);
 
- 	  this.message = message || '';
 
- 	}
 
- 	AggregateError.prototype = Error.prototype;
 
- 	function any(arr) {
 
- 	  var P = this;
 
- 	  return new P(function(resolve, reject) {
 
- 	    if (!(arr && typeof arr.length !== 'undefined')) {
 
- 	      return reject(new TypeError('Promise.any accepts an array'));
 
- 	    }
 
- 	    var args = Array.prototype.slice.call(arr);
 
- 	    if (args.length === 0) return reject();
 
- 	    var rejectionReasons = [];
 
- 	    for (var i = 0; i < args.length; i++) {
 
- 	      try {
 
- 	        P.resolve(args[i])
 
- 	          .then(resolve)
 
- 	          .catch(function(error) {
 
- 	            rejectionReasons.push(error);
 
- 	            if (rejectionReasons.length === args.length) {
 
- 	              reject(
 
- 	                new AggregateError(
 
- 	                  rejectionReasons,
 
- 	                  'All promises were rejected'
 
- 	                )
 
- 	              );
 
- 	            }
 
- 	          });
 
- 	      } catch (ex) {
 
- 	        reject(ex);
 
- 	      }
 
- 	    }
 
- 	  });
 
- 	}
 
- 	// Store setTimeout reference so promise-polyfill will be unaffected by
 
- 	// other code modifying setTimeout (like sinon.useFakeTimers())
 
- 	var setTimeoutFunc = setTimeout;
 
- 	function isArray(x) {
 
- 	  return Boolean(x && typeof x.length !== 'undefined');
 
- 	}
 
- 	function noop() {}
 
- 	// Polyfill for Function.prototype.bind
 
- 	function bind(fn, thisArg) {
 
- 	  return function() {
 
- 	    fn.apply(thisArg, arguments);
 
- 	  };
 
- 	}
 
- 	/**
 
- 	 * @constructor
 
- 	 * @param {Function} fn
 
- 	 */
 
- 	function Promise$1(fn) {
 
- 	  if (!(this instanceof Promise$1))
 
- 	    throw new TypeError('Promises must be constructed via new');
 
- 	  if (typeof fn !== 'function') throw new TypeError('not a function');
 
- 	  /** @type {!number} */
 
- 	  this._state = 0;
 
- 	  /** @type {!boolean} */
 
- 	  this._handled = false;
 
- 	  /** @type {Promise|undefined} */
 
- 	  this._value = undefined;
 
- 	  /** @type {!Array<!Function>} */
 
- 	  this._deferreds = [];
 
- 	  doResolve(fn, this);
 
- 	}
 
- 	function handle(self, deferred) {
 
- 	  while (self._state === 3) {
 
- 	    self = self._value;
 
- 	  }
 
- 	  if (self._state === 0) {
 
- 	    self._deferreds.push(deferred);
 
- 	    return;
 
- 	  }
 
- 	  self._handled = true;
 
- 	  Promise$1._immediateFn(function() {
 
- 	    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
 
- 	    if (cb === null) {
 
- 	      (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
 
- 	      return;
 
- 	    }
 
- 	    var ret;
 
- 	    try {
 
- 	      ret = cb(self._value);
 
- 	    } catch (e) {
 
- 	      reject(deferred.promise, e);
 
- 	      return;
 
- 	    }
 
- 	    resolve(deferred.promise, ret);
 
- 	  });
 
- 	}
 
- 	function resolve(self, newValue) {
 
- 	  try {
 
- 	    // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
 
- 	    if (newValue === self)
 
- 	      throw new TypeError('A promise cannot be resolved with itself.');
 
- 	    if (
 
- 	      newValue &&
 
- 	      (typeof newValue === 'object' || typeof newValue === 'function')
 
- 	    ) {
 
- 	      var then = newValue.then;
 
- 	      if (newValue instanceof Promise$1) {
 
- 	        self._state = 3;
 
- 	        self._value = newValue;
 
- 	        finale(self);
 
- 	        return;
 
- 	      } else if (typeof then === 'function') {
 
- 	        doResolve(bind(then, newValue), self);
 
- 	        return;
 
- 	      }
 
- 	    }
 
- 	    self._state = 1;
 
- 	    self._value = newValue;
 
- 	    finale(self);
 
- 	  } catch (e) {
 
- 	    reject(self, e);
 
- 	  }
 
- 	}
 
- 	function reject(self, newValue) {
 
- 	  self._state = 2;
 
- 	  self._value = newValue;
 
- 	  finale(self);
 
- 	}
 
- 	function finale(self) {
 
- 	  if (self._state === 2 && self._deferreds.length === 0) {
 
- 	    Promise$1._immediateFn(function() {
 
- 	      if (!self._handled) {
 
- 	        Promise$1._unhandledRejectionFn(self._value);
 
- 	      }
 
- 	    });
 
- 	  }
 
- 	  for (var i = 0, len = self._deferreds.length; i < len; i++) {
 
- 	    handle(self, self._deferreds[i]);
 
- 	  }
 
- 	  self._deferreds = null;
 
- 	}
 
- 	/**
 
- 	 * @constructor
 
- 	 */
 
- 	function Handler(onFulfilled, onRejected, promise) {
 
- 	  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
 
- 	  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
 
- 	  this.promise = promise;
 
- 	}
 
- 	/**
 
- 	 * Take a potentially misbehaving resolver function and make sure
 
- 	 * onFulfilled and onRejected are only called once.
 
- 	 *
 
- 	 * Makes no guarantees about asynchrony.
 
- 	 */
 
- 	function doResolve(fn, self) {
 
- 	  var done = false;
 
- 	  try {
 
- 	    fn(
 
- 	      function(value) {
 
- 	        if (done) return;
 
- 	        done = true;
 
- 	        resolve(self, value);
 
- 	      },
 
- 	      function(reason) {
 
- 	        if (done) return;
 
- 	        done = true;
 
- 	        reject(self, reason);
 
- 	      }
 
- 	    );
 
- 	  } catch (ex) {
 
- 	    if (done) return;
 
- 	    done = true;
 
- 	    reject(self, ex);
 
- 	  }
 
- 	}
 
- 	Promise$1.prototype['catch'] = function(onRejected) {
 
- 	  return this.then(null, onRejected);
 
- 	};
 
- 	Promise$1.prototype.then = function(onFulfilled, onRejected) {
 
- 	  // @ts-ignore
 
- 	  var prom = new this.constructor(noop);
 
- 	  handle(this, new Handler(onFulfilled, onRejected, prom));
 
- 	  return prom;
 
- 	};
 
- 	Promise$1.prototype['finally'] = finallyConstructor;
 
- 	Promise$1.all = function(arr) {
 
- 	  return new Promise$1(function(resolve, reject) {
 
- 	    if (!isArray(arr)) {
 
- 	      return reject(new TypeError('Promise.all accepts an array'));
 
- 	    }
 
- 	    var args = Array.prototype.slice.call(arr);
 
- 	    if (args.length === 0) return resolve([]);
 
- 	    var remaining = args.length;
 
- 	    function res(i, val) {
 
- 	      try {
 
- 	        if (val && (typeof val === 'object' || typeof val === 'function')) {
 
- 	          var then = val.then;
 
- 	          if (typeof then === 'function') {
 
- 	            then.call(
 
- 	              val,
 
- 	              function(val) {
 
- 	                res(i, val);
 
- 	              },
 
- 	              reject
 
- 	            );
 
- 	            return;
 
- 	          }
 
- 	        }
 
- 	        args[i] = val;
 
- 	        if (--remaining === 0) {
 
- 	          resolve(args);
 
- 	        }
 
- 	      } catch (ex) {
 
- 	        reject(ex);
 
- 	      }
 
- 	    }
 
- 	    for (var i = 0; i < args.length; i++) {
 
- 	      res(i, args[i]);
 
- 	    }
 
- 	  });
 
- 	};
 
- 	Promise$1.any = any;
 
- 	Promise$1.allSettled = allSettled;
 
- 	Promise$1.resolve = function(value) {
 
- 	  if (value && typeof value === 'object' && value.constructor === Promise$1) {
 
- 	    return value;
 
- 	  }
 
- 	  return new Promise$1(function(resolve) {
 
- 	    resolve(value);
 
- 	  });
 
- 	};
 
- 	Promise$1.reject = function(value) {
 
- 	  return new Promise$1(function(resolve, reject) {
 
- 	    reject(value);
 
- 	  });
 
- 	};
 
- 	Promise$1.race = function(arr) {
 
- 	  return new Promise$1(function(resolve, reject) {
 
- 	    if (!isArray(arr)) {
 
- 	      return reject(new TypeError('Promise.race accepts an array'));
 
- 	    }
 
- 	    for (var i = 0, len = arr.length; i < len; i++) {
 
- 	      Promise$1.resolve(arr[i]).then(resolve, reject);
 
- 	    }
 
- 	  });
 
- 	};
 
- 	// Use polyfill for setImmediate for performance gains
 
- 	Promise$1._immediateFn =
 
- 	  // @ts-ignore
 
- 	  (typeof setImmediate === 'function' &&
 
- 	    function(fn) {
 
- 	      // @ts-ignore
 
- 	      setImmediate(fn);
 
- 	    }) ||
 
- 	  function(fn) {
 
- 	    setTimeoutFunc(fn, 0);
 
- 	  };
 
- 	Promise$1._unhandledRejectionFn = function _unhandledRejectionFn(err) {
 
- 	  if (typeof console !== 'undefined' && console) {
 
- 	    console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
 
- 	  }
 
- 	};
 
- 	/** @suppress {undefinedVars} */
 
- 	var globalNS = (function() {
 
- 	  // the only reliable means to get the global object is
 
- 	  // `Function('return this')()`
 
- 	  // However, this causes CSP violations in Chrome apps.
 
- 	  if (typeof self !== 'undefined') {
 
- 	    return self;
 
- 	  }
 
- 	  if (typeof window !== 'undefined') {
 
- 	    return window;
 
- 	  }
 
- 	  if (typeof global !== 'undefined') {
 
- 	    return global;
 
- 	  }
 
- 	  throw new Error('unable to locate global object');
 
- 	})();
 
- 	// Expose the polyfill if Promise is undefined or set to a
 
- 	// non-function value. The latter can be due to a named HTMLElement
 
- 	// being exposed by browsers for legacy reasons.
 
- 	// https://github.com/taylorhakes/promise-polyfill/issues/114
 
- 	if (typeof globalNS['Promise'] !== 'function') {
 
- 	  globalNS['Promise'] = Promise$1;
 
- 	} else {
 
- 	  if (!globalNS.Promise.prototype['finally']) {
 
- 	    globalNS.Promise.prototype['finally'] = finallyConstructor;
 
- 	  }
 
- 	  if (!globalNS.Promise.allSettled) {
 
- 	    globalNS.Promise.allSettled = allSettled;
 
- 	  }
 
- 	  if (!globalNS.Promise.any) {
 
- 	    globalNS.Promise.any = any;
 
- 	  }
 
- 	}
 
- 	function sortObject(obj) {
 
- 	  if (typeof obj !== 'object') {
 
- 	    return obj;
 
- 	  }
 
- 	  var temp = {};
 
- 	  var keys = [];
 
- 	  for (var key in obj) {
 
- 	    keys.push(key);
 
- 	  }
 
- 	  keys.sort();
 
- 	  for (var index in keys) {
 
- 	    temp[keys[index]] = sortObject(obj[keys[index]]);
 
- 	  }
 
- 	  return temp;
 
- 	}
 
- 	function copyTextToClipboard(text) {
 
- 	  var textArea = document.createElement('textarea');
 
- 	  textArea.value = text;
 
- 	  document.body.appendChild(textArea);
 
- 	  textArea.select();
 
- 	  try {
 
- 	    var successful = document.execCommand('copy');
 
- 	    var msg = successful ? 'successful' : 'unsuccessful';
 
- 	    console.log('Copying text command was ' + msg);
 
- 	  } catch (err) {
 
- 	    console.log('Oops, unable to copy');
 
- 	  }
 
- 	  document.body.removeChild(textArea);
 
- 	}
 
- 	function _toPrimitive(t, r) {
 
- 	  if ("object" != typeof t || !t) return t;
 
- 	  var e = t[Symbol.toPrimitive];
 
- 	  if (void 0 !== e) {
 
- 	    var i = e.call(t, r || "default");
 
- 	    if ("object" != typeof i) return i;
 
- 	    throw new TypeError("@@toPrimitive must return a primitive value.");
 
- 	  }
 
- 	  return ("string" === r ? String : Number)(t);
 
- 	}
 
- 	function _toPropertyKey(t) {
 
- 	  var i = _toPrimitive(t, "string");
 
- 	  return "symbol" == typeof i ? i : String(i);
 
- 	}
 
- 	function _defineProperties(target, props) {
 
- 	  for (var i = 0; i < props.length; i++) {
 
- 	    var descriptor = props[i];
 
- 	    descriptor.enumerable = descriptor.enumerable || false;
 
- 	    descriptor.configurable = true;
 
- 	    if ("value" in descriptor) descriptor.writable = true;
 
- 	    Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
 
- 	  }
 
- 	}
 
- 	function _createClass(Constructor, protoProps, staticProps) {
 
- 	  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
 
- 	  if (staticProps) _defineProperties(Constructor, staticProps);
 
- 	  Object.defineProperty(Constructor, "prototype", {
 
- 	    writable: false
 
- 	  });
 
- 	  return Constructor;
 
- 	}
 
- 	function _extends() {
 
- 	  _extends = Object.assign ? Object.assign.bind() : function (target) {
 
- 	    for (var i = 1; i < arguments.length; i++) {
 
- 	      var source = arguments[i];
 
- 	      for (var key in source) {
 
- 	        if (Object.prototype.hasOwnProperty.call(source, key)) {
 
- 	          target[key] = source[key];
 
- 	        }
 
- 	      }
 
- 	    }
 
- 	    return target;
 
- 	  };
 
- 	  return _extends.apply(this, arguments);
 
- 	}
 
- 	var Chart$1 = {exports: {}};
 
- 	function commonjsRequire(path) {
 
- 		throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
 
- 	}
 
- 	var moment = {exports: {}};
 
- 	var hasRequiredMoment;
 
- 	function requireMoment () {
 
- 		if (hasRequiredMoment) return moment.exports;
 
- 		hasRequiredMoment = 1;
 
- 		(function (module, exports) {
 
- 	(function (global, factory) {
 
- 			    module.exports = factory() ;
 
- 			}(commonjsGlobal, (function () {
 
- 			    var hookCallback;
 
- 			    function hooks() {
 
- 			        return hookCallback.apply(null, arguments);
 
- 			    }
 
- 			    // This is done to register the method called with moment()
 
- 			    // without creating circular dependencies.
 
- 			    function setHookCallback(callback) {
 
- 			        hookCallback = callback;
 
- 			    }
 
- 			    function isArray(input) {
 
- 			        return (
 
- 			            input instanceof Array ||
 
- 			            Object.prototype.toString.call(input) === '[object Array]'
 
- 			        );
 
- 			    }
 
- 			    function isObject(input) {
 
- 			        // IE8 will treat undefined and null as object if it wasn't for
 
- 			        // input != null
 
- 			        return (
 
- 			            input != null &&
 
- 			            Object.prototype.toString.call(input) === '[object Object]'
 
- 			        );
 
- 			    }
 
- 			    function hasOwnProp(a, b) {
 
- 			        return Object.prototype.hasOwnProperty.call(a, b);
 
- 			    }
 
- 			    function isObjectEmpty(obj) {
 
- 			        if (Object.getOwnPropertyNames) {
 
- 			            return Object.getOwnPropertyNames(obj).length === 0;
 
- 			        } else {
 
- 			            var k;
 
- 			            for (k in obj) {
 
- 			                if (hasOwnProp(obj, k)) {
 
- 			                    return false;
 
- 			                }
 
- 			            }
 
- 			            return true;
 
- 			        }
 
- 			    }
 
- 			    function isUndefined(input) {
 
- 			        return input === void 0;
 
- 			    }
 
- 			    function isNumber(input) {
 
- 			        return (
 
- 			            typeof input === 'number' ||
 
- 			            Object.prototype.toString.call(input) === '[object Number]'
 
- 			        );
 
- 			    }
 
- 			    function isDate(input) {
 
- 			        return (
 
- 			            input instanceof Date ||
 
- 			            Object.prototype.toString.call(input) === '[object Date]'
 
- 			        );
 
- 			    }
 
- 			    function map(arr, fn) {
 
- 			        var res = [],
 
- 			            i,
 
- 			            arrLen = arr.length;
 
- 			        for (i = 0; i < arrLen; ++i) {
 
- 			            res.push(fn(arr[i], i));
 
- 			        }
 
- 			        return res;
 
- 			    }
 
- 			    function extend(a, b) {
 
- 			        for (var i in b) {
 
- 			            if (hasOwnProp(b, i)) {
 
- 			                a[i] = b[i];
 
- 			            }
 
- 			        }
 
- 			        if (hasOwnProp(b, 'toString')) {
 
- 			            a.toString = b.toString;
 
- 			        }
 
- 			        if (hasOwnProp(b, 'valueOf')) {
 
- 			            a.valueOf = b.valueOf;
 
- 			        }
 
- 			        return a;
 
- 			    }
 
- 			    function createUTC(input, format, locale, strict) {
 
- 			        return createLocalOrUTC(input, format, locale, strict, true).utc();
 
- 			    }
 
- 			    function defaultParsingFlags() {
 
- 			        // We need to deep clone this object.
 
- 			        return {
 
- 			            empty: false,
 
- 			            unusedTokens: [],
 
- 			            unusedInput: [],
 
- 			            overflow: -2,
 
- 			            charsLeftOver: 0,
 
- 			            nullInput: false,
 
- 			            invalidEra: null,
 
- 			            invalidMonth: null,
 
- 			            invalidFormat: false,
 
- 			            userInvalidated: false,
 
- 			            iso: false,
 
- 			            parsedDateParts: [],
 
- 			            era: null,
 
- 			            meridiem: null,
 
- 			            rfc2822: false,
 
- 			            weekdayMismatch: false,
 
- 			        };
 
- 			    }
 
- 			    function getParsingFlags(m) {
 
- 			        if (m._pf == null) {
 
- 			            m._pf = defaultParsingFlags();
 
- 			        }
 
- 			        return m._pf;
 
- 			    }
 
- 			    var some;
 
- 			    if (Array.prototype.some) {
 
- 			        some = Array.prototype.some;
 
- 			    } else {
 
- 			        some = function (fun) {
 
- 			            var t = Object(this),
 
- 			                len = t.length >>> 0,
 
- 			                i;
 
- 			            for (i = 0; i < len; i++) {
 
- 			                if (i in t && fun.call(this, t[i], i, t)) {
 
- 			                    return true;
 
- 			                }
 
- 			            }
 
- 			            return false;
 
- 			        };
 
- 			    }
 
- 			    function isValid(m) {
 
- 			        if (m._isValid == null) {
 
- 			            var flags = getParsingFlags(m),
 
- 			                parsedParts = some.call(flags.parsedDateParts, function (i) {
 
- 			                    return i != null;
 
- 			                }),
 
- 			                isNowValid =
 
- 			                    !isNaN(m._d.getTime()) &&
 
- 			                    flags.overflow < 0 &&
 
- 			                    !flags.empty &&
 
- 			                    !flags.invalidEra &&
 
- 			                    !flags.invalidMonth &&
 
- 			                    !flags.invalidWeekday &&
 
- 			                    !flags.weekdayMismatch &&
 
- 			                    !flags.nullInput &&
 
- 			                    !flags.invalidFormat &&
 
- 			                    !flags.userInvalidated &&
 
- 			                    (!flags.meridiem || (flags.meridiem && parsedParts));
 
- 			            if (m._strict) {
 
- 			                isNowValid =
 
- 			                    isNowValid &&
 
- 			                    flags.charsLeftOver === 0 &&
 
- 			                    flags.unusedTokens.length === 0 &&
 
- 			                    flags.bigHour === undefined;
 
- 			            }
 
- 			            if (Object.isFrozen == null || !Object.isFrozen(m)) {
 
- 			                m._isValid = isNowValid;
 
- 			            } else {
 
- 			                return isNowValid;
 
- 			            }
 
- 			        }
 
- 			        return m._isValid;
 
- 			    }
 
- 			    function createInvalid(flags) {
 
- 			        var m = createUTC(NaN);
 
- 			        if (flags != null) {
 
- 			            extend(getParsingFlags(m), flags);
 
- 			        } else {
 
- 			            getParsingFlags(m).userInvalidated = true;
 
- 			        }
 
- 			        return m;
 
- 			    }
 
- 			    // Plugins that add properties should also add the key here (null value),
 
- 			    // so we can properly clone ourselves.
 
- 			    var momentProperties = (hooks.momentProperties = []),
 
- 			        updateInProgress = false;
 
- 			    function copyConfig(to, from) {
 
- 			        var i,
 
- 			            prop,
 
- 			            val,
 
- 			            momentPropertiesLen = momentProperties.length;
 
- 			        if (!isUndefined(from._isAMomentObject)) {
 
- 			            to._isAMomentObject = from._isAMomentObject;
 
- 			        }
 
- 			        if (!isUndefined(from._i)) {
 
- 			            to._i = from._i;
 
- 			        }
 
- 			        if (!isUndefined(from._f)) {
 
- 			            to._f = from._f;
 
- 			        }
 
- 			        if (!isUndefined(from._l)) {
 
- 			            to._l = from._l;
 
- 			        }
 
- 			        if (!isUndefined(from._strict)) {
 
- 			            to._strict = from._strict;
 
- 			        }
 
- 			        if (!isUndefined(from._tzm)) {
 
- 			            to._tzm = from._tzm;
 
- 			        }
 
- 			        if (!isUndefined(from._isUTC)) {
 
- 			            to._isUTC = from._isUTC;
 
- 			        }
 
- 			        if (!isUndefined(from._offset)) {
 
- 			            to._offset = from._offset;
 
- 			        }
 
- 			        if (!isUndefined(from._pf)) {
 
- 			            to._pf = getParsingFlags(from);
 
- 			        }
 
- 			        if (!isUndefined(from._locale)) {
 
- 			            to._locale = from._locale;
 
- 			        }
 
- 			        if (momentPropertiesLen > 0) {
 
- 			            for (i = 0; i < momentPropertiesLen; i++) {
 
- 			                prop = momentProperties[i];
 
- 			                val = from[prop];
 
- 			                if (!isUndefined(val)) {
 
- 			                    to[prop] = val;
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        return to;
 
- 			    }
 
- 			    // Moment prototype object
 
- 			    function Moment(config) {
 
- 			        copyConfig(this, config);
 
- 			        this._d = new Date(config._d != null ? config._d.getTime() : NaN);
 
- 			        if (!this.isValid()) {
 
- 			            this._d = new Date(NaN);
 
- 			        }
 
- 			        // Prevent infinite loop in case updateOffset creates new moment
 
- 			        // objects.
 
- 			        if (updateInProgress === false) {
 
- 			            updateInProgress = true;
 
- 			            hooks.updateOffset(this);
 
- 			            updateInProgress = false;
 
- 			        }
 
- 			    }
 
- 			    function isMoment(obj) {
 
- 			        return (
 
- 			            obj instanceof Moment || (obj != null && obj._isAMomentObject != null)
 
- 			        );
 
- 			    }
 
- 			    function warn(msg) {
 
- 			        if (
 
- 			            hooks.suppressDeprecationWarnings === false &&
 
- 			            typeof console !== 'undefined' &&
 
- 			            console.warn
 
- 			        ) {
 
- 			            console.warn('Deprecation warning: ' + msg);
 
- 			        }
 
- 			    }
 
- 			    function deprecate(msg, fn) {
 
- 			        var firstTime = true;
 
- 			        return extend(function () {
 
- 			            if (hooks.deprecationHandler != null) {
 
- 			                hooks.deprecationHandler(null, msg);
 
- 			            }
 
- 			            if (firstTime) {
 
- 			                var args = [],
 
- 			                    arg,
 
- 			                    i,
 
- 			                    key,
 
- 			                    argLen = arguments.length;
 
- 			                for (i = 0; i < argLen; i++) {
 
- 			                    arg = '';
 
- 			                    if (typeof arguments[i] === 'object') {
 
- 			                        arg += '\n[' + i + '] ';
 
- 			                        for (key in arguments[0]) {
 
- 			                            if (hasOwnProp(arguments[0], key)) {
 
- 			                                arg += key + ': ' + arguments[0][key] + ', ';
 
- 			                            }
 
- 			                        }
 
- 			                        arg = arg.slice(0, -2); // Remove trailing comma and space
 
- 			                    } else {
 
- 			                        arg = arguments[i];
 
- 			                    }
 
- 			                    args.push(arg);
 
- 			                }
 
- 			                warn(
 
- 			                    msg +
 
- 			                        '\nArguments: ' +
 
- 			                        Array.prototype.slice.call(args).join('') +
 
- 			                        '\n' +
 
- 			                        new Error().stack
 
- 			                );
 
- 			                firstTime = false;
 
- 			            }
 
- 			            return fn.apply(this, arguments);
 
- 			        }, fn);
 
- 			    }
 
- 			    var deprecations = {};
 
- 			    function deprecateSimple(name, msg) {
 
- 			        if (hooks.deprecationHandler != null) {
 
- 			            hooks.deprecationHandler(name, msg);
 
- 			        }
 
- 			        if (!deprecations[name]) {
 
- 			            warn(msg);
 
- 			            deprecations[name] = true;
 
- 			        }
 
- 			    }
 
- 			    hooks.suppressDeprecationWarnings = false;
 
- 			    hooks.deprecationHandler = null;
 
- 			    function isFunction(input) {
 
- 			        return (
 
- 			            (typeof Function !== 'undefined' && input instanceof Function) ||
 
- 			            Object.prototype.toString.call(input) === '[object Function]'
 
- 			        );
 
- 			    }
 
- 			    function set(config) {
 
- 			        var prop, i;
 
- 			        for (i in config) {
 
- 			            if (hasOwnProp(config, i)) {
 
- 			                prop = config[i];
 
- 			                if (isFunction(prop)) {
 
- 			                    this[i] = prop;
 
- 			                } else {
 
- 			                    this['_' + i] = prop;
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        this._config = config;
 
- 			        // Lenient ordinal parsing accepts just a number in addition to
 
- 			        // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
 
- 			        // TODO: Remove "ordinalParse" fallback in next major release.
 
- 			        this._dayOfMonthOrdinalParseLenient = new RegExp(
 
- 			            (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
 
- 			                '|' +
 
- 			                /\d{1,2}/.source
 
- 			        );
 
- 			    }
 
- 			    function mergeConfigs(parentConfig, childConfig) {
 
- 			        var res = extend({}, parentConfig),
 
- 			            prop;
 
- 			        for (prop in childConfig) {
 
- 			            if (hasOwnProp(childConfig, prop)) {
 
- 			                if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
 
- 			                    res[prop] = {};
 
- 			                    extend(res[prop], parentConfig[prop]);
 
- 			                    extend(res[prop], childConfig[prop]);
 
- 			                } else if (childConfig[prop] != null) {
 
- 			                    res[prop] = childConfig[prop];
 
- 			                } else {
 
- 			                    delete res[prop];
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        for (prop in parentConfig) {
 
- 			            if (
 
- 			                hasOwnProp(parentConfig, prop) &&
 
- 			                !hasOwnProp(childConfig, prop) &&
 
- 			                isObject(parentConfig[prop])
 
- 			            ) {
 
- 			                // make sure changes to properties don't modify parent config
 
- 			                res[prop] = extend({}, res[prop]);
 
- 			            }
 
- 			        }
 
- 			        return res;
 
- 			    }
 
- 			    function Locale(config) {
 
- 			        if (config != null) {
 
- 			            this.set(config);
 
- 			        }
 
- 			    }
 
- 			    var keys;
 
- 			    if (Object.keys) {
 
- 			        keys = Object.keys;
 
- 			    } else {
 
- 			        keys = function (obj) {
 
- 			            var i,
 
- 			                res = [];
 
- 			            for (i in obj) {
 
- 			                if (hasOwnProp(obj, i)) {
 
- 			                    res.push(i);
 
- 			                }
 
- 			            }
 
- 			            return res;
 
- 			        };
 
- 			    }
 
- 			    var defaultCalendar = {
 
- 			        sameDay: '[Today at] LT',
 
- 			        nextDay: '[Tomorrow at] LT',
 
- 			        nextWeek: 'dddd [at] LT',
 
- 			        lastDay: '[Yesterday at] LT',
 
- 			        lastWeek: '[Last] dddd [at] LT',
 
- 			        sameElse: 'L',
 
- 			    };
 
- 			    function calendar(key, mom, now) {
 
- 			        var output = this._calendar[key] || this._calendar['sameElse'];
 
- 			        return isFunction(output) ? output.call(mom, now) : output;
 
- 			    }
 
- 			    function zeroFill(number, targetLength, forceSign) {
 
- 			        var absNumber = '' + Math.abs(number),
 
- 			            zerosToFill = targetLength - absNumber.length,
 
- 			            sign = number >= 0;
 
- 			        return (
 
- 			            (sign ? (forceSign ? '+' : '') : '-') +
 
- 			            Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) +
 
- 			            absNumber
 
- 			        );
 
- 			    }
 
- 			    var formattingTokens =
 
- 			            /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,
 
- 			        localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,
 
- 			        formatFunctions = {},
 
- 			        formatTokenFunctions = {};
 
- 			    // token:    'M'
 
- 			    // padded:   ['MM', 2]
 
- 			    // ordinal:  'Mo'
 
- 			    // callback: function () { this.month() + 1 }
 
- 			    function addFormatToken(token, padded, ordinal, callback) {
 
- 			        var func = callback;
 
- 			        if (typeof callback === 'string') {
 
- 			            func = function () {
 
- 			                return this[callback]();
 
- 			            };
 
- 			        }
 
- 			        if (token) {
 
- 			            formatTokenFunctions[token] = func;
 
- 			        }
 
- 			        if (padded) {
 
- 			            formatTokenFunctions[padded[0]] = function () {
 
- 			                return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
 
- 			            };
 
- 			        }
 
- 			        if (ordinal) {
 
- 			            formatTokenFunctions[ordinal] = function () {
 
- 			                return this.localeData().ordinal(
 
- 			                    func.apply(this, arguments),
 
- 			                    token
 
- 			                );
 
- 			            };
 
- 			        }
 
- 			    }
 
- 			    function removeFormattingTokens(input) {
 
- 			        if (input.match(/\[[\s\S]/)) {
 
- 			            return input.replace(/^\[|\]$/g, '');
 
- 			        }
 
- 			        return input.replace(/\\/g, '');
 
- 			    }
 
- 			    function makeFormatFunction(format) {
 
- 			        var array = format.match(formattingTokens),
 
- 			            i,
 
- 			            length;
 
- 			        for (i = 0, length = array.length; i < length; i++) {
 
- 			            if (formatTokenFunctions[array[i]]) {
 
- 			                array[i] = formatTokenFunctions[array[i]];
 
- 			            } else {
 
- 			                array[i] = removeFormattingTokens(array[i]);
 
- 			            }
 
- 			        }
 
- 			        return function (mom) {
 
- 			            var output = '',
 
- 			                i;
 
- 			            for (i = 0; i < length; i++) {
 
- 			                output += isFunction(array[i])
 
- 			                    ? array[i].call(mom, format)
 
- 			                    : array[i];
 
- 			            }
 
- 			            return output;
 
- 			        };
 
- 			    }
 
- 			    // format date using native date object
 
- 			    function formatMoment(m, format) {
 
- 			        if (!m.isValid()) {
 
- 			            return m.localeData().invalidDate();
 
- 			        }
 
- 			        format = expandFormat(format, m.localeData());
 
- 			        formatFunctions[format] =
 
- 			            formatFunctions[format] || makeFormatFunction(format);
 
- 			        return formatFunctions[format](m);
 
- 			    }
 
- 			    function expandFormat(format, locale) {
 
- 			        var i = 5;
 
- 			        function replaceLongDateFormatTokens(input) {
 
- 			            return locale.longDateFormat(input) || input;
 
- 			        }
 
- 			        localFormattingTokens.lastIndex = 0;
 
- 			        while (i >= 0 && localFormattingTokens.test(format)) {
 
- 			            format = format.replace(
 
- 			                localFormattingTokens,
 
- 			                replaceLongDateFormatTokens
 
- 			            );
 
- 			            localFormattingTokens.lastIndex = 0;
 
- 			            i -= 1;
 
- 			        }
 
- 			        return format;
 
- 			    }
 
- 			    var defaultLongDateFormat = {
 
- 			        LTS: 'h:mm:ss A',
 
- 			        LT: 'h:mm A',
 
- 			        L: 'MM/DD/YYYY',
 
- 			        LL: 'MMMM D, YYYY',
 
- 			        LLL: 'MMMM D, YYYY h:mm A',
 
- 			        LLLL: 'dddd, MMMM D, YYYY h:mm A',
 
- 			    };
 
- 			    function longDateFormat(key) {
 
- 			        var format = this._longDateFormat[key],
 
- 			            formatUpper = this._longDateFormat[key.toUpperCase()];
 
- 			        if (format || !formatUpper) {
 
- 			            return format;
 
- 			        }
 
- 			        this._longDateFormat[key] = formatUpper
 
- 			            .match(formattingTokens)
 
- 			            .map(function (tok) {
 
- 			                if (
 
- 			                    tok === 'MMMM' ||
 
- 			                    tok === 'MM' ||
 
- 			                    tok === 'DD' ||
 
- 			                    tok === 'dddd'
 
- 			                ) {
 
- 			                    return tok.slice(1);
 
- 			                }
 
- 			                return tok;
 
- 			            })
 
- 			            .join('');
 
- 			        return this._longDateFormat[key];
 
- 			    }
 
- 			    var defaultInvalidDate = 'Invalid date';
 
- 			    function invalidDate() {
 
- 			        return this._invalidDate;
 
- 			    }
 
- 			    var defaultOrdinal = '%d',
 
- 			        defaultDayOfMonthOrdinalParse = /\d{1,2}/;
 
- 			    function ordinal(number) {
 
- 			        return this._ordinal.replace('%d', number);
 
- 			    }
 
- 			    var defaultRelativeTime = {
 
- 			        future: 'in %s',
 
- 			        past: '%s ago',
 
- 			        s: 'a few seconds',
 
- 			        ss: '%d seconds',
 
- 			        m: 'a minute',
 
- 			        mm: '%d minutes',
 
- 			        h: 'an hour',
 
- 			        hh: '%d hours',
 
- 			        d: 'a day',
 
- 			        dd: '%d days',
 
- 			        w: 'a week',
 
- 			        ww: '%d weeks',
 
- 			        M: 'a month',
 
- 			        MM: '%d months',
 
- 			        y: 'a year',
 
- 			        yy: '%d years',
 
- 			    };
 
- 			    function relativeTime(number, withoutSuffix, string, isFuture) {
 
- 			        var output = this._relativeTime[string];
 
- 			        return isFunction(output)
 
- 			            ? output(number, withoutSuffix, string, isFuture)
 
- 			            : output.replace(/%d/i, number);
 
- 			    }
 
- 			    function pastFuture(diff, output) {
 
- 			        var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
 
- 			        return isFunction(format) ? format(output) : format.replace(/%s/i, output);
 
- 			    }
 
- 			    var aliases = {};
 
- 			    function addUnitAlias(unit, shorthand) {
 
- 			        var lowerCase = unit.toLowerCase();
 
- 			        aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
 
- 			    }
 
- 			    function normalizeUnits(units) {
 
- 			        return typeof units === 'string'
 
- 			            ? aliases[units] || aliases[units.toLowerCase()]
 
- 			            : undefined;
 
- 			    }
 
- 			    function normalizeObjectUnits(inputObject) {
 
- 			        var normalizedInput = {},
 
- 			            normalizedProp,
 
- 			            prop;
 
- 			        for (prop in inputObject) {
 
- 			            if (hasOwnProp(inputObject, prop)) {
 
- 			                normalizedProp = normalizeUnits(prop);
 
- 			                if (normalizedProp) {
 
- 			                    normalizedInput[normalizedProp] = inputObject[prop];
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        return normalizedInput;
 
- 			    }
 
- 			    var priorities = {};
 
- 			    function addUnitPriority(unit, priority) {
 
- 			        priorities[unit] = priority;
 
- 			    }
 
- 			    function getPrioritizedUnits(unitsObj) {
 
- 			        var units = [],
 
- 			            u;
 
- 			        for (u in unitsObj) {
 
- 			            if (hasOwnProp(unitsObj, u)) {
 
- 			                units.push({ unit: u, priority: priorities[u] });
 
- 			            }
 
- 			        }
 
- 			        units.sort(function (a, b) {
 
- 			            return a.priority - b.priority;
 
- 			        });
 
- 			        return units;
 
- 			    }
 
- 			    function isLeapYear(year) {
 
- 			        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
 
- 			    }
 
- 			    function absFloor(number) {
 
- 			        if (number < 0) {
 
- 			            // -0 -> 0
 
- 			            return Math.ceil(number) || 0;
 
- 			        } else {
 
- 			            return Math.floor(number);
 
- 			        }
 
- 			    }
 
- 			    function toInt(argumentForCoercion) {
 
- 			        var coercedNumber = +argumentForCoercion,
 
- 			            value = 0;
 
- 			        if (coercedNumber !== 0 && isFinite(coercedNumber)) {
 
- 			            value = absFloor(coercedNumber);
 
- 			        }
 
- 			        return value;
 
- 			    }
 
- 			    function makeGetSet(unit, keepTime) {
 
- 			        return function (value) {
 
- 			            if (value != null) {
 
- 			                set$1(this, unit, value);
 
- 			                hooks.updateOffset(this, keepTime);
 
- 			                return this;
 
- 			            } else {
 
- 			                return get(this, unit);
 
- 			            }
 
- 			        };
 
- 			    }
 
- 			    function get(mom, unit) {
 
- 			        return mom.isValid()
 
- 			            ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]()
 
- 			            : NaN;
 
- 			    }
 
- 			    function set$1(mom, unit, value) {
 
- 			        if (mom.isValid() && !isNaN(value)) {
 
- 			            if (
 
- 			                unit === 'FullYear' &&
 
- 			                isLeapYear(mom.year()) &&
 
- 			                mom.month() === 1 &&
 
- 			                mom.date() === 29
 
- 			            ) {
 
- 			                value = toInt(value);
 
- 			                mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](
 
- 			                    value,
 
- 			                    mom.month(),
 
- 			                    daysInMonth(value, mom.month())
 
- 			                );
 
- 			            } else {
 
- 			                mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
 
- 			            }
 
- 			        }
 
- 			    }
 
- 			    // MOMENTS
 
- 			    function stringGet(units) {
 
- 			        units = normalizeUnits(units);
 
- 			        if (isFunction(this[units])) {
 
- 			            return this[units]();
 
- 			        }
 
- 			        return this;
 
- 			    }
 
- 			    function stringSet(units, value) {
 
- 			        if (typeof units === 'object') {
 
- 			            units = normalizeObjectUnits(units);
 
- 			            var prioritized = getPrioritizedUnits(units),
 
- 			                i,
 
- 			                prioritizedLen = prioritized.length;
 
- 			            for (i = 0; i < prioritizedLen; i++) {
 
- 			                this[prioritized[i].unit](units[prioritized[i].unit]);
 
- 			            }
 
- 			        } else {
 
- 			            units = normalizeUnits(units);
 
- 			            if (isFunction(this[units])) {
 
- 			                return this[units](value);
 
- 			            }
 
- 			        }
 
- 			        return this;
 
- 			    }
 
- 			    var match1 = /\d/, //       0 - 9
 
- 			        match2 = /\d\d/, //      00 - 99
 
- 			        match3 = /\d{3}/, //     000 - 999
 
- 			        match4 = /\d{4}/, //    0000 - 9999
 
- 			        match6 = /[+-]?\d{6}/, // -999999 - 999999
 
- 			        match1to2 = /\d\d?/, //       0 - 99
 
- 			        match3to4 = /\d\d\d\d?/, //     999 - 9999
 
- 			        match5to6 = /\d\d\d\d\d\d?/, //   99999 - 999999
 
- 			        match1to3 = /\d{1,3}/, //       0 - 999
 
- 			        match1to4 = /\d{1,4}/, //       0 - 9999
 
- 			        match1to6 = /[+-]?\d{1,6}/, // -999999 - 999999
 
- 			        matchUnsigned = /\d+/, //       0 - inf
 
- 			        matchSigned = /[+-]?\d+/, //    -inf - inf
 
- 			        matchOffset = /Z|[+-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
 
- 			        matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, // +00 -00 +00:00 -00:00 +0000 -0000 or Z
 
- 			        matchTimestamp = /[+-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
 
- 			        // any word (or two) characters or numbers including two/three word month in arabic.
 
- 			        // includes scottish gaelic two word and hyphenated months
 
- 			        matchWord =
 
- 			            /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i,
 
- 			        regexes;
 
- 			    regexes = {};
 
- 			    function addRegexToken(token, regex, strictRegex) {
 
- 			        regexes[token] = isFunction(regex)
 
- 			            ? regex
 
- 			            : function (isStrict, localeData) {
 
- 			                  return isStrict && strictRegex ? strictRegex : regex;
 
- 			              };
 
- 			    }
 
- 			    function getParseRegexForToken(token, config) {
 
- 			        if (!hasOwnProp(regexes, token)) {
 
- 			            return new RegExp(unescapeFormat(token));
 
- 			        }
 
- 			        return regexes[token](config._strict, config._locale);
 
- 			    }
 
- 			    // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
 
- 			    function unescapeFormat(s) {
 
- 			        return regexEscape(
 
- 			            s
 
- 			                .replace('\\', '')
 
- 			                .replace(
 
- 			                    /\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,
 
- 			                    function (matched, p1, p2, p3, p4) {
 
- 			                        return p1 || p2 || p3 || p4;
 
- 			                    }
 
- 			                )
 
- 			        );
 
- 			    }
 
- 			    function regexEscape(s) {
 
- 			        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
 
- 			    }
 
- 			    var tokens = {};
 
- 			    function addParseToken(token, callback) {
 
- 			        var i,
 
- 			            func = callback,
 
- 			            tokenLen;
 
- 			        if (typeof token === 'string') {
 
- 			            token = [token];
 
- 			        }
 
- 			        if (isNumber(callback)) {
 
- 			            func = function (input, array) {
 
- 			                array[callback] = toInt(input);
 
- 			            };
 
- 			        }
 
- 			        tokenLen = token.length;
 
- 			        for (i = 0; i < tokenLen; i++) {
 
- 			            tokens[token[i]] = func;
 
- 			        }
 
- 			    }
 
- 			    function addWeekParseToken(token, callback) {
 
- 			        addParseToken(token, function (input, array, config, token) {
 
- 			            config._w = config._w || {};
 
- 			            callback(input, config._w, config, token);
 
- 			        });
 
- 			    }
 
- 			    function addTimeToArrayFromToken(token, input, config) {
 
- 			        if (input != null && hasOwnProp(tokens, token)) {
 
- 			            tokens[token](input, config._a, config, token);
 
- 			        }
 
- 			    }
 
- 			    var YEAR = 0,
 
- 			        MONTH = 1,
 
- 			        DATE = 2,
 
- 			        HOUR = 3,
 
- 			        MINUTE = 4,
 
- 			        SECOND = 5,
 
- 			        MILLISECOND = 6,
 
- 			        WEEK = 7,
 
- 			        WEEKDAY = 8;
 
- 			    function mod(n, x) {
 
- 			        return ((n % x) + x) % x;
 
- 			    }
 
- 			    var indexOf;
 
- 			    if (Array.prototype.indexOf) {
 
- 			        indexOf = Array.prototype.indexOf;
 
- 			    } else {
 
- 			        indexOf = function (o) {
 
- 			            // I know
 
- 			            var i;
 
- 			            for (i = 0; i < this.length; ++i) {
 
- 			                if (this[i] === o) {
 
- 			                    return i;
 
- 			                }
 
- 			            }
 
- 			            return -1;
 
- 			        };
 
- 			    }
 
- 			    function daysInMonth(year, month) {
 
- 			        if (isNaN(year) || isNaN(month)) {
 
- 			            return NaN;
 
- 			        }
 
- 			        var modMonth = mod(month, 12);
 
- 			        year += (month - modMonth) / 12;
 
- 			        return modMonth === 1
 
- 			            ? isLeapYear(year)
 
- 			                ? 29
 
- 			                : 28
 
- 			            : 31 - ((modMonth % 7) % 2);
 
- 			    }
 
- 			    // FORMATTING
 
- 			    addFormatToken('M', ['MM', 2], 'Mo', function () {
 
- 			        return this.month() + 1;
 
- 			    });
 
- 			    addFormatToken('MMM', 0, 0, function (format) {
 
- 			        return this.localeData().monthsShort(this, format);
 
- 			    });
 
- 			    addFormatToken('MMMM', 0, 0, function (format) {
 
- 			        return this.localeData().months(this, format);
 
- 			    });
 
- 			    // ALIASES
 
- 			    addUnitAlias('month', 'M');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('month', 8);
 
- 			    // PARSING
 
- 			    addRegexToken('M', match1to2);
 
- 			    addRegexToken('MM', match1to2, match2);
 
- 			    addRegexToken('MMM', function (isStrict, locale) {
 
- 			        return locale.monthsShortRegex(isStrict);
 
- 			    });
 
- 			    addRegexToken('MMMM', function (isStrict, locale) {
 
- 			        return locale.monthsRegex(isStrict);
 
- 			    });
 
- 			    addParseToken(['M', 'MM'], function (input, array) {
 
- 			        array[MONTH] = toInt(input) - 1;
 
- 			    });
 
- 			    addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
 
- 			        var month = config._locale.monthsParse(input, token, config._strict);
 
- 			        // if we didn't find a month name, mark the date as invalid.
 
- 			        if (month != null) {
 
- 			            array[MONTH] = month;
 
- 			        } else {
 
- 			            getParsingFlags(config).invalidMonth = input;
 
- 			        }
 
- 			    });
 
- 			    // LOCALES
 
- 			    var defaultLocaleMonths =
 
- 			            'January_February_March_April_May_June_July_August_September_October_November_December'.split(
 
- 			                '_'
 
- 			            ),
 
- 			        defaultLocaleMonthsShort =
 
- 			            'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
 
- 			        MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,
 
- 			        defaultMonthsShortRegex = matchWord,
 
- 			        defaultMonthsRegex = matchWord;
 
- 			    function localeMonths(m, format) {
 
- 			        if (!m) {
 
- 			            return isArray(this._months)
 
- 			                ? this._months
 
- 			                : this._months['standalone'];
 
- 			        }
 
- 			        return isArray(this._months)
 
- 			            ? this._months[m.month()]
 
- 			            : this._months[
 
- 			                  (this._months.isFormat || MONTHS_IN_FORMAT).test(format)
 
- 			                      ? 'format'
 
- 			                      : 'standalone'
 
- 			              ][m.month()];
 
- 			    }
 
- 			    function localeMonthsShort(m, format) {
 
- 			        if (!m) {
 
- 			            return isArray(this._monthsShort)
 
- 			                ? this._monthsShort
 
- 			                : this._monthsShort['standalone'];
 
- 			        }
 
- 			        return isArray(this._monthsShort)
 
- 			            ? this._monthsShort[m.month()]
 
- 			            : this._monthsShort[
 
- 			                  MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'
 
- 			              ][m.month()];
 
- 			    }
 
- 			    function handleStrictParse(monthName, format, strict) {
 
- 			        var i,
 
- 			            ii,
 
- 			            mom,
 
- 			            llc = monthName.toLocaleLowerCase();
 
- 			        if (!this._monthsParse) {
 
- 			            // this is not used
 
- 			            this._monthsParse = [];
 
- 			            this._longMonthsParse = [];
 
- 			            this._shortMonthsParse = [];
 
- 			            for (i = 0; i < 12; ++i) {
 
- 			                mom = createUTC([2000, i]);
 
- 			                this._shortMonthsParse[i] = this.monthsShort(
 
- 			                    mom,
 
- 			                    ''
 
- 			                ).toLocaleLowerCase();
 
- 			                this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
 
- 			            }
 
- 			        }
 
- 			        if (strict) {
 
- 			            if (format === 'MMM') {
 
- 			                ii = indexOf.call(this._shortMonthsParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            } else {
 
- 			                ii = indexOf.call(this._longMonthsParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            }
 
- 			        } else {
 
- 			            if (format === 'MMM') {
 
- 			                ii = indexOf.call(this._shortMonthsParse, llc);
 
- 			                if (ii !== -1) {
 
- 			                    return ii;
 
- 			                }
 
- 			                ii = indexOf.call(this._longMonthsParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            } else {
 
- 			                ii = indexOf.call(this._longMonthsParse, llc);
 
- 			                if (ii !== -1) {
 
- 			                    return ii;
 
- 			                }
 
- 			                ii = indexOf.call(this._shortMonthsParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            }
 
- 			        }
 
- 			    }
 
- 			    function localeMonthsParse(monthName, format, strict) {
 
- 			        var i, mom, regex;
 
- 			        if (this._monthsParseExact) {
 
- 			            return handleStrictParse.call(this, monthName, format, strict);
 
- 			        }
 
- 			        if (!this._monthsParse) {
 
- 			            this._monthsParse = [];
 
- 			            this._longMonthsParse = [];
 
- 			            this._shortMonthsParse = [];
 
- 			        }
 
- 			        // TODO: add sorting
 
- 			        // Sorting makes sure if one month (or abbr) is a prefix of another
 
- 			        // see sorting in computeMonthsParse
 
- 			        for (i = 0; i < 12; i++) {
 
- 			            // make the regex if we don't have it already
 
- 			            mom = createUTC([2000, i]);
 
- 			            if (strict && !this._longMonthsParse[i]) {
 
- 			                this._longMonthsParse[i] = new RegExp(
 
- 			                    '^' + this.months(mom, '').replace('.', '') + '$',
 
- 			                    'i'
 
- 			                );
 
- 			                this._shortMonthsParse[i] = new RegExp(
 
- 			                    '^' + this.monthsShort(mom, '').replace('.', '') + '$',
 
- 			                    'i'
 
- 			                );
 
- 			            }
 
- 			            if (!strict && !this._monthsParse[i]) {
 
- 			                regex =
 
- 			                    '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
 
- 			                this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
 
- 			            }
 
- 			            // test the regex
 
- 			            if (
 
- 			                strict &&
 
- 			                format === 'MMMM' &&
 
- 			                this._longMonthsParse[i].test(monthName)
 
- 			            ) {
 
- 			                return i;
 
- 			            } else if (
 
- 			                strict &&
 
- 			                format === 'MMM' &&
 
- 			                this._shortMonthsParse[i].test(monthName)
 
- 			            ) {
 
- 			                return i;
 
- 			            } else if (!strict && this._monthsParse[i].test(monthName)) {
 
- 			                return i;
 
- 			            }
 
- 			        }
 
- 			    }
 
- 			    // MOMENTS
 
- 			    function setMonth(mom, value) {
 
- 			        var dayOfMonth;
 
- 			        if (!mom.isValid()) {
 
- 			            // No op
 
- 			            return mom;
 
- 			        }
 
- 			        if (typeof value === 'string') {
 
- 			            if (/^\d+$/.test(value)) {
 
- 			                value = toInt(value);
 
- 			            } else {
 
- 			                value = mom.localeData().monthsParse(value);
 
- 			                // TODO: Another silent failure?
 
- 			                if (!isNumber(value)) {
 
- 			                    return mom;
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
 
- 			        mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
 
- 			        return mom;
 
- 			    }
 
- 			    function getSetMonth(value) {
 
- 			        if (value != null) {
 
- 			            setMonth(this, value);
 
- 			            hooks.updateOffset(this, true);
 
- 			            return this;
 
- 			        } else {
 
- 			            return get(this, 'Month');
 
- 			        }
 
- 			    }
 
- 			    function getDaysInMonth() {
 
- 			        return daysInMonth(this.year(), this.month());
 
- 			    }
 
- 			    function monthsShortRegex(isStrict) {
 
- 			        if (this._monthsParseExact) {
 
- 			            if (!hasOwnProp(this, '_monthsRegex')) {
 
- 			                computeMonthsParse.call(this);
 
- 			            }
 
- 			            if (isStrict) {
 
- 			                return this._monthsShortStrictRegex;
 
- 			            } else {
 
- 			                return this._monthsShortRegex;
 
- 			            }
 
- 			        } else {
 
- 			            if (!hasOwnProp(this, '_monthsShortRegex')) {
 
- 			                this._monthsShortRegex = defaultMonthsShortRegex;
 
- 			            }
 
- 			            return this._monthsShortStrictRegex && isStrict
 
- 			                ? this._monthsShortStrictRegex
 
- 			                : this._monthsShortRegex;
 
- 			        }
 
- 			    }
 
- 			    function monthsRegex(isStrict) {
 
- 			        if (this._monthsParseExact) {
 
- 			            if (!hasOwnProp(this, '_monthsRegex')) {
 
- 			                computeMonthsParse.call(this);
 
- 			            }
 
- 			            if (isStrict) {
 
- 			                return this._monthsStrictRegex;
 
- 			            } else {
 
- 			                return this._monthsRegex;
 
- 			            }
 
- 			        } else {
 
- 			            if (!hasOwnProp(this, '_monthsRegex')) {
 
- 			                this._monthsRegex = defaultMonthsRegex;
 
- 			            }
 
- 			            return this._monthsStrictRegex && isStrict
 
- 			                ? this._monthsStrictRegex
 
- 			                : this._monthsRegex;
 
- 			        }
 
- 			    }
 
- 			    function computeMonthsParse() {
 
- 			        function cmpLenRev(a, b) {
 
- 			            return b.length - a.length;
 
- 			        }
 
- 			        var shortPieces = [],
 
- 			            longPieces = [],
 
- 			            mixedPieces = [],
 
- 			            i,
 
- 			            mom;
 
- 			        for (i = 0; i < 12; i++) {
 
- 			            // make the regex if we don't have it already
 
- 			            mom = createUTC([2000, i]);
 
- 			            shortPieces.push(this.monthsShort(mom, ''));
 
- 			            longPieces.push(this.months(mom, ''));
 
- 			            mixedPieces.push(this.months(mom, ''));
 
- 			            mixedPieces.push(this.monthsShort(mom, ''));
 
- 			        }
 
- 			        // Sorting makes sure if one month (or abbr) is a prefix of another it
 
- 			        // will match the longer piece.
 
- 			        shortPieces.sort(cmpLenRev);
 
- 			        longPieces.sort(cmpLenRev);
 
- 			        mixedPieces.sort(cmpLenRev);
 
- 			        for (i = 0; i < 12; i++) {
 
- 			            shortPieces[i] = regexEscape(shortPieces[i]);
 
- 			            longPieces[i] = regexEscape(longPieces[i]);
 
- 			        }
 
- 			        for (i = 0; i < 24; i++) {
 
- 			            mixedPieces[i] = regexEscape(mixedPieces[i]);
 
- 			        }
 
- 			        this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
 
- 			        this._monthsShortRegex = this._monthsRegex;
 
- 			        this._monthsStrictRegex = new RegExp(
 
- 			            '^(' + longPieces.join('|') + ')',
 
- 			            'i'
 
- 			        );
 
- 			        this._monthsShortStrictRegex = new RegExp(
 
- 			            '^(' + shortPieces.join('|') + ')',
 
- 			            'i'
 
- 			        );
 
- 			    }
 
- 			    // FORMATTING
 
- 			    addFormatToken('Y', 0, 0, function () {
 
- 			        var y = this.year();
 
- 			        return y <= 9999 ? zeroFill(y, 4) : '+' + y;
 
- 			    });
 
- 			    addFormatToken(0, ['YY', 2], 0, function () {
 
- 			        return this.year() % 100;
 
- 			    });
 
- 			    addFormatToken(0, ['YYYY', 4], 0, 'year');
 
- 			    addFormatToken(0, ['YYYYY', 5], 0, 'year');
 
- 			    addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
 
- 			    // ALIASES
 
- 			    addUnitAlias('year', 'y');
 
- 			    // PRIORITIES
 
- 			    addUnitPriority('year', 1);
 
- 			    // PARSING
 
- 			    addRegexToken('Y', matchSigned);
 
- 			    addRegexToken('YY', match1to2, match2);
 
- 			    addRegexToken('YYYY', match1to4, match4);
 
- 			    addRegexToken('YYYYY', match1to6, match6);
 
- 			    addRegexToken('YYYYYY', match1to6, match6);
 
- 			    addParseToken(['YYYYY', 'YYYYYY'], YEAR);
 
- 			    addParseToken('YYYY', function (input, array) {
 
- 			        array[YEAR] =
 
- 			            input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
 
- 			    });
 
- 			    addParseToken('YY', function (input, array) {
 
- 			        array[YEAR] = hooks.parseTwoDigitYear(input);
 
- 			    });
 
- 			    addParseToken('Y', function (input, array) {
 
- 			        array[YEAR] = parseInt(input, 10);
 
- 			    });
 
- 			    // HELPERS
 
- 			    function daysInYear(year) {
 
- 			        return isLeapYear(year) ? 366 : 365;
 
- 			    }
 
- 			    // HOOKS
 
- 			    hooks.parseTwoDigitYear = function (input) {
 
- 			        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
 
- 			    };
 
- 			    // MOMENTS
 
- 			    var getSetYear = makeGetSet('FullYear', true);
 
- 			    function getIsLeapYear() {
 
- 			        return isLeapYear(this.year());
 
- 			    }
 
- 			    function createDate(y, m, d, h, M, s, ms) {
 
- 			        // can't just apply() to create a date:
 
- 			        // https://stackoverflow.com/q/181348
 
- 			        var date;
 
- 			        // the date constructor remaps years 0-99 to 1900-1999
 
- 			        if (y < 100 && y >= 0) {
 
- 			            // preserve leap years using a full 400 year cycle, then reset
 
- 			            date = new Date(y + 400, m, d, h, M, s, ms);
 
- 			            if (isFinite(date.getFullYear())) {
 
- 			                date.setFullYear(y);
 
- 			            }
 
- 			        } else {
 
- 			            date = new Date(y, m, d, h, M, s, ms);
 
- 			        }
 
- 			        return date;
 
- 			    }
 
- 			    function createUTCDate(y) {
 
- 			        var date, args;
 
- 			        // the Date.UTC function remaps years 0-99 to 1900-1999
 
- 			        if (y < 100 && y >= 0) {
 
- 			            args = Array.prototype.slice.call(arguments);
 
- 			            // preserve leap years using a full 400 year cycle, then reset
 
- 			            args[0] = y + 400;
 
- 			            date = new Date(Date.UTC.apply(null, args));
 
- 			            if (isFinite(date.getUTCFullYear())) {
 
- 			                date.setUTCFullYear(y);
 
- 			            }
 
- 			        } else {
 
- 			            date = new Date(Date.UTC.apply(null, arguments));
 
- 			        }
 
- 			        return date;
 
- 			    }
 
- 			    // start-of-first-week - start-of-year
 
- 			    function firstWeekOffset(year, dow, doy) {
 
- 			        var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
 
- 			            fwd = 7 + dow - doy,
 
- 			            // first-week day local weekday -- which local weekday is fwd
 
- 			            fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
 
- 			        return -fwdlw + fwd - 1;
 
- 			    }
 
- 			    // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
 
- 			    function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
 
- 			        var localWeekday = (7 + weekday - dow) % 7,
 
- 			            weekOffset = firstWeekOffset(year, dow, doy),
 
- 			            dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
 
- 			            resYear,
 
- 			            resDayOfYear;
 
- 			        if (dayOfYear <= 0) {
 
- 			            resYear = year - 1;
 
- 			            resDayOfYear = daysInYear(resYear) + dayOfYear;
 
- 			        } else if (dayOfYear > daysInYear(year)) {
 
- 			            resYear = year + 1;
 
- 			            resDayOfYear = dayOfYear - daysInYear(year);
 
- 			        } else {
 
- 			            resYear = year;
 
- 			            resDayOfYear = dayOfYear;
 
- 			        }
 
- 			        return {
 
- 			            year: resYear,
 
- 			            dayOfYear: resDayOfYear,
 
- 			        };
 
- 			    }
 
- 			    function weekOfYear(mom, dow, doy) {
 
- 			        var weekOffset = firstWeekOffset(mom.year(), dow, doy),
 
- 			            week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
 
- 			            resWeek,
 
- 			            resYear;
 
- 			        if (week < 1) {
 
- 			            resYear = mom.year() - 1;
 
- 			            resWeek = week + weeksInYear(resYear, dow, doy);
 
- 			        } else if (week > weeksInYear(mom.year(), dow, doy)) {
 
- 			            resWeek = week - weeksInYear(mom.year(), dow, doy);
 
- 			            resYear = mom.year() + 1;
 
- 			        } else {
 
- 			            resYear = mom.year();
 
- 			            resWeek = week;
 
- 			        }
 
- 			        return {
 
- 			            week: resWeek,
 
- 			            year: resYear,
 
- 			        };
 
- 			    }
 
- 			    function weeksInYear(year, dow, doy) {
 
- 			        var weekOffset = firstWeekOffset(year, dow, doy),
 
- 			            weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
 
- 			        return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
 
- 			    }
 
- 			    // FORMATTING
 
- 			    addFormatToken('w', ['ww', 2], 'wo', 'week');
 
- 			    addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
 
- 			    // ALIASES
 
- 			    addUnitAlias('week', 'w');
 
- 			    addUnitAlias('isoWeek', 'W');
 
- 			    // PRIORITIES
 
- 			    addUnitPriority('week', 5);
 
- 			    addUnitPriority('isoWeek', 5);
 
- 			    // PARSING
 
- 			    addRegexToken('w', match1to2);
 
- 			    addRegexToken('ww', match1to2, match2);
 
- 			    addRegexToken('W', match1to2);
 
- 			    addRegexToken('WW', match1to2, match2);
 
- 			    addWeekParseToken(
 
- 			        ['w', 'ww', 'W', 'WW'],
 
- 			        function (input, week, config, token) {
 
- 			            week[token.substr(0, 1)] = toInt(input);
 
- 			        }
 
- 			    );
 
- 			    // HELPERS
 
- 			    // LOCALES
 
- 			    function localeWeek(mom) {
 
- 			        return weekOfYear(mom, this._week.dow, this._week.doy).week;
 
- 			    }
 
- 			    var defaultLocaleWeek = {
 
- 			        dow: 0, // Sunday is the first day of the week.
 
- 			        doy: 6, // The week that contains Jan 6th is the first week of the year.
 
- 			    };
 
- 			    function localeFirstDayOfWeek() {
 
- 			        return this._week.dow;
 
- 			    }
 
- 			    function localeFirstDayOfYear() {
 
- 			        return this._week.doy;
 
- 			    }
 
- 			    // MOMENTS
 
- 			    function getSetWeek(input) {
 
- 			        var week = this.localeData().week(this);
 
- 			        return input == null ? week : this.add((input - week) * 7, 'd');
 
- 			    }
 
- 			    function getSetISOWeek(input) {
 
- 			        var week = weekOfYear(this, 1, 4).week;
 
- 			        return input == null ? week : this.add((input - week) * 7, 'd');
 
- 			    }
 
- 			    // FORMATTING
 
- 			    addFormatToken('d', 0, 'do', 'day');
 
- 			    addFormatToken('dd', 0, 0, function (format) {
 
- 			        return this.localeData().weekdaysMin(this, format);
 
- 			    });
 
- 			    addFormatToken('ddd', 0, 0, function (format) {
 
- 			        return this.localeData().weekdaysShort(this, format);
 
- 			    });
 
- 			    addFormatToken('dddd', 0, 0, function (format) {
 
- 			        return this.localeData().weekdays(this, format);
 
- 			    });
 
- 			    addFormatToken('e', 0, 0, 'weekday');
 
- 			    addFormatToken('E', 0, 0, 'isoWeekday');
 
- 			    // ALIASES
 
- 			    addUnitAlias('day', 'd');
 
- 			    addUnitAlias('weekday', 'e');
 
- 			    addUnitAlias('isoWeekday', 'E');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('day', 11);
 
- 			    addUnitPriority('weekday', 11);
 
- 			    addUnitPriority('isoWeekday', 11);
 
- 			    // PARSING
 
- 			    addRegexToken('d', match1to2);
 
- 			    addRegexToken('e', match1to2);
 
- 			    addRegexToken('E', match1to2);
 
- 			    addRegexToken('dd', function (isStrict, locale) {
 
- 			        return locale.weekdaysMinRegex(isStrict);
 
- 			    });
 
- 			    addRegexToken('ddd', function (isStrict, locale) {
 
- 			        return locale.weekdaysShortRegex(isStrict);
 
- 			    });
 
- 			    addRegexToken('dddd', function (isStrict, locale) {
 
- 			        return locale.weekdaysRegex(isStrict);
 
- 			    });
 
- 			    addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
 
- 			        var weekday = config._locale.weekdaysParse(input, token, config._strict);
 
- 			        // if we didn't get a weekday name, mark the date as invalid
 
- 			        if (weekday != null) {
 
- 			            week.d = weekday;
 
- 			        } else {
 
- 			            getParsingFlags(config).invalidWeekday = input;
 
- 			        }
 
- 			    });
 
- 			    addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
 
- 			        week[token] = toInt(input);
 
- 			    });
 
- 			    // HELPERS
 
- 			    function parseWeekday(input, locale) {
 
- 			        if (typeof input !== 'string') {
 
- 			            return input;
 
- 			        }
 
- 			        if (!isNaN(input)) {
 
- 			            return parseInt(input, 10);
 
- 			        }
 
- 			        input = locale.weekdaysParse(input);
 
- 			        if (typeof input === 'number') {
 
- 			            return input;
 
- 			        }
 
- 			        return null;
 
- 			    }
 
- 			    function parseIsoWeekday(input, locale) {
 
- 			        if (typeof input === 'string') {
 
- 			            return locale.weekdaysParse(input) % 7 || 7;
 
- 			        }
 
- 			        return isNaN(input) ? null : input;
 
- 			    }
 
- 			    // LOCALES
 
- 			    function shiftWeekdays(ws, n) {
 
- 			        return ws.slice(n, 7).concat(ws.slice(0, n));
 
- 			    }
 
- 			    var defaultLocaleWeekdays =
 
- 			            'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
 
- 			        defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
 
- 			        defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
 
- 			        defaultWeekdaysRegex = matchWord,
 
- 			        defaultWeekdaysShortRegex = matchWord,
 
- 			        defaultWeekdaysMinRegex = matchWord;
 
- 			    function localeWeekdays(m, format) {
 
- 			        var weekdays = isArray(this._weekdays)
 
- 			            ? this._weekdays
 
- 			            : this._weekdays[
 
- 			                  m && m !== true && this._weekdays.isFormat.test(format)
 
- 			                      ? 'format'
 
- 			                      : 'standalone'
 
- 			              ];
 
- 			        return m === true
 
- 			            ? shiftWeekdays(weekdays, this._week.dow)
 
- 			            : m
 
- 			            ? weekdays[m.day()]
 
- 			            : weekdays;
 
- 			    }
 
- 			    function localeWeekdaysShort(m) {
 
- 			        return m === true
 
- 			            ? shiftWeekdays(this._weekdaysShort, this._week.dow)
 
- 			            : m
 
- 			            ? this._weekdaysShort[m.day()]
 
- 			            : this._weekdaysShort;
 
- 			    }
 
- 			    function localeWeekdaysMin(m) {
 
- 			        return m === true
 
- 			            ? shiftWeekdays(this._weekdaysMin, this._week.dow)
 
- 			            : m
 
- 			            ? this._weekdaysMin[m.day()]
 
- 			            : this._weekdaysMin;
 
- 			    }
 
- 			    function handleStrictParse$1(weekdayName, format, strict) {
 
- 			        var i,
 
- 			            ii,
 
- 			            mom,
 
- 			            llc = weekdayName.toLocaleLowerCase();
 
- 			        if (!this._weekdaysParse) {
 
- 			            this._weekdaysParse = [];
 
- 			            this._shortWeekdaysParse = [];
 
- 			            this._minWeekdaysParse = [];
 
- 			            for (i = 0; i < 7; ++i) {
 
- 			                mom = createUTC([2000, 1]).day(i);
 
- 			                this._minWeekdaysParse[i] = this.weekdaysMin(
 
- 			                    mom,
 
- 			                    ''
 
- 			                ).toLocaleLowerCase();
 
- 			                this._shortWeekdaysParse[i] = this.weekdaysShort(
 
- 			                    mom,
 
- 			                    ''
 
- 			                ).toLocaleLowerCase();
 
- 			                this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
 
- 			            }
 
- 			        }
 
- 			        if (strict) {
 
- 			            if (format === 'dddd') {
 
- 			                ii = indexOf.call(this._weekdaysParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            } else if (format === 'ddd') {
 
- 			                ii = indexOf.call(this._shortWeekdaysParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            } else {
 
- 			                ii = indexOf.call(this._minWeekdaysParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            }
 
- 			        } else {
 
- 			            if (format === 'dddd') {
 
- 			                ii = indexOf.call(this._weekdaysParse, llc);
 
- 			                if (ii !== -1) {
 
- 			                    return ii;
 
- 			                }
 
- 			                ii = indexOf.call(this._shortWeekdaysParse, llc);
 
- 			                if (ii !== -1) {
 
- 			                    return ii;
 
- 			                }
 
- 			                ii = indexOf.call(this._minWeekdaysParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            } else if (format === 'ddd') {
 
- 			                ii = indexOf.call(this._shortWeekdaysParse, llc);
 
- 			                if (ii !== -1) {
 
- 			                    return ii;
 
- 			                }
 
- 			                ii = indexOf.call(this._weekdaysParse, llc);
 
- 			                if (ii !== -1) {
 
- 			                    return ii;
 
- 			                }
 
- 			                ii = indexOf.call(this._minWeekdaysParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            } else {
 
- 			                ii = indexOf.call(this._minWeekdaysParse, llc);
 
- 			                if (ii !== -1) {
 
- 			                    return ii;
 
- 			                }
 
- 			                ii = indexOf.call(this._weekdaysParse, llc);
 
- 			                if (ii !== -1) {
 
- 			                    return ii;
 
- 			                }
 
- 			                ii = indexOf.call(this._shortWeekdaysParse, llc);
 
- 			                return ii !== -1 ? ii : null;
 
- 			            }
 
- 			        }
 
- 			    }
 
- 			    function localeWeekdaysParse(weekdayName, format, strict) {
 
- 			        var i, mom, regex;
 
- 			        if (this._weekdaysParseExact) {
 
- 			            return handleStrictParse$1.call(this, weekdayName, format, strict);
 
- 			        }
 
- 			        if (!this._weekdaysParse) {
 
- 			            this._weekdaysParse = [];
 
- 			            this._minWeekdaysParse = [];
 
- 			            this._shortWeekdaysParse = [];
 
- 			            this._fullWeekdaysParse = [];
 
- 			        }
 
- 			        for (i = 0; i < 7; i++) {
 
- 			            // make the regex if we don't have it already
 
- 			            mom = createUTC([2000, 1]).day(i);
 
- 			            if (strict && !this._fullWeekdaysParse[i]) {
 
- 			                this._fullWeekdaysParse[i] = new RegExp(
 
- 			                    '^' + this.weekdays(mom, '').replace('.', '\\.?') + '$',
 
- 			                    'i'
 
- 			                );
 
- 			                this._shortWeekdaysParse[i] = new RegExp(
 
- 			                    '^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$',
 
- 			                    'i'
 
- 			                );
 
- 			                this._minWeekdaysParse[i] = new RegExp(
 
- 			                    '^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$',
 
- 			                    'i'
 
- 			                );
 
- 			            }
 
- 			            if (!this._weekdaysParse[i]) {
 
- 			                regex =
 
- 			                    '^' +
 
- 			                    this.weekdays(mom, '') +
 
- 			                    '|^' +
 
- 			                    this.weekdaysShort(mom, '') +
 
- 			                    '|^' +
 
- 			                    this.weekdaysMin(mom, '');
 
- 			                this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
 
- 			            }
 
- 			            // test the regex
 
- 			            if (
 
- 			                strict &&
 
- 			                format === 'dddd' &&
 
- 			                this._fullWeekdaysParse[i].test(weekdayName)
 
- 			            ) {
 
- 			                return i;
 
- 			            } else if (
 
- 			                strict &&
 
- 			                format === 'ddd' &&
 
- 			                this._shortWeekdaysParse[i].test(weekdayName)
 
- 			            ) {
 
- 			                return i;
 
- 			            } else if (
 
- 			                strict &&
 
- 			                format === 'dd' &&
 
- 			                this._minWeekdaysParse[i].test(weekdayName)
 
- 			            ) {
 
- 			                return i;
 
- 			            } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
 
- 			                return i;
 
- 			            }
 
- 			        }
 
- 			    }
 
- 			    // MOMENTS
 
- 			    function getSetDayOfWeek(input) {
 
- 			        if (!this.isValid()) {
 
- 			            return input != null ? this : NaN;
 
- 			        }
 
- 			        var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
 
- 			        if (input != null) {
 
- 			            input = parseWeekday(input, this.localeData());
 
- 			            return this.add(input - day, 'd');
 
- 			        } else {
 
- 			            return day;
 
- 			        }
 
- 			    }
 
- 			    function getSetLocaleDayOfWeek(input) {
 
- 			        if (!this.isValid()) {
 
- 			            return input != null ? this : NaN;
 
- 			        }
 
- 			        var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
 
- 			        return input == null ? weekday : this.add(input - weekday, 'd');
 
- 			    }
 
- 			    function getSetISODayOfWeek(input) {
 
- 			        if (!this.isValid()) {
 
- 			            return input != null ? this : NaN;
 
- 			        }
 
- 			        // behaves the same as moment#day except
 
- 			        // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
 
- 			        // as a setter, sunday should belong to the previous week.
 
- 			        if (input != null) {
 
- 			            var weekday = parseIsoWeekday(input, this.localeData());
 
- 			            return this.day(this.day() % 7 ? weekday : weekday - 7);
 
- 			        } else {
 
- 			            return this.day() || 7;
 
- 			        }
 
- 			    }
 
- 			    function weekdaysRegex(isStrict) {
 
- 			        if (this._weekdaysParseExact) {
 
- 			            if (!hasOwnProp(this, '_weekdaysRegex')) {
 
- 			                computeWeekdaysParse.call(this);
 
- 			            }
 
- 			            if (isStrict) {
 
- 			                return this._weekdaysStrictRegex;
 
- 			            } else {
 
- 			                return this._weekdaysRegex;
 
- 			            }
 
- 			        } else {
 
- 			            if (!hasOwnProp(this, '_weekdaysRegex')) {
 
- 			                this._weekdaysRegex = defaultWeekdaysRegex;
 
- 			            }
 
- 			            return this._weekdaysStrictRegex && isStrict
 
- 			                ? this._weekdaysStrictRegex
 
- 			                : this._weekdaysRegex;
 
- 			        }
 
- 			    }
 
- 			    function weekdaysShortRegex(isStrict) {
 
- 			        if (this._weekdaysParseExact) {
 
- 			            if (!hasOwnProp(this, '_weekdaysRegex')) {
 
- 			                computeWeekdaysParse.call(this);
 
- 			            }
 
- 			            if (isStrict) {
 
- 			                return this._weekdaysShortStrictRegex;
 
- 			            } else {
 
- 			                return this._weekdaysShortRegex;
 
- 			            }
 
- 			        } else {
 
- 			            if (!hasOwnProp(this, '_weekdaysShortRegex')) {
 
- 			                this._weekdaysShortRegex = defaultWeekdaysShortRegex;
 
- 			            }
 
- 			            return this._weekdaysShortStrictRegex && isStrict
 
- 			                ? this._weekdaysShortStrictRegex
 
- 			                : this._weekdaysShortRegex;
 
- 			        }
 
- 			    }
 
- 			    function weekdaysMinRegex(isStrict) {
 
- 			        if (this._weekdaysParseExact) {
 
- 			            if (!hasOwnProp(this, '_weekdaysRegex')) {
 
- 			                computeWeekdaysParse.call(this);
 
- 			            }
 
- 			            if (isStrict) {
 
- 			                return this._weekdaysMinStrictRegex;
 
- 			            } else {
 
- 			                return this._weekdaysMinRegex;
 
- 			            }
 
- 			        } else {
 
- 			            if (!hasOwnProp(this, '_weekdaysMinRegex')) {
 
- 			                this._weekdaysMinRegex = defaultWeekdaysMinRegex;
 
- 			            }
 
- 			            return this._weekdaysMinStrictRegex && isStrict
 
- 			                ? this._weekdaysMinStrictRegex
 
- 			                : this._weekdaysMinRegex;
 
- 			        }
 
- 			    }
 
- 			    function computeWeekdaysParse() {
 
- 			        function cmpLenRev(a, b) {
 
- 			            return b.length - a.length;
 
- 			        }
 
- 			        var minPieces = [],
 
- 			            shortPieces = [],
 
- 			            longPieces = [],
 
- 			            mixedPieces = [],
 
- 			            i,
 
- 			            mom,
 
- 			            minp,
 
- 			            shortp,
 
- 			            longp;
 
- 			        for (i = 0; i < 7; i++) {
 
- 			            // make the regex if we don't have it already
 
- 			            mom = createUTC([2000, 1]).day(i);
 
- 			            minp = regexEscape(this.weekdaysMin(mom, ''));
 
- 			            shortp = regexEscape(this.weekdaysShort(mom, ''));
 
- 			            longp = regexEscape(this.weekdays(mom, ''));
 
- 			            minPieces.push(minp);
 
- 			            shortPieces.push(shortp);
 
- 			            longPieces.push(longp);
 
- 			            mixedPieces.push(minp);
 
- 			            mixedPieces.push(shortp);
 
- 			            mixedPieces.push(longp);
 
- 			        }
 
- 			        // Sorting makes sure if one weekday (or abbr) is a prefix of another it
 
- 			        // will match the longer piece.
 
- 			        minPieces.sort(cmpLenRev);
 
- 			        shortPieces.sort(cmpLenRev);
 
- 			        longPieces.sort(cmpLenRev);
 
- 			        mixedPieces.sort(cmpLenRev);
 
- 			        this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
 
- 			        this._weekdaysShortRegex = this._weekdaysRegex;
 
- 			        this._weekdaysMinRegex = this._weekdaysRegex;
 
- 			        this._weekdaysStrictRegex = new RegExp(
 
- 			            '^(' + longPieces.join('|') + ')',
 
- 			            'i'
 
- 			        );
 
- 			        this._weekdaysShortStrictRegex = new RegExp(
 
- 			            '^(' + shortPieces.join('|') + ')',
 
- 			            'i'
 
- 			        );
 
- 			        this._weekdaysMinStrictRegex = new RegExp(
 
- 			            '^(' + minPieces.join('|') + ')',
 
- 			            'i'
 
- 			        );
 
- 			    }
 
- 			    // FORMATTING
 
- 			    function hFormat() {
 
- 			        return this.hours() % 12 || 12;
 
- 			    }
 
- 			    function kFormat() {
 
- 			        return this.hours() || 24;
 
- 			    }
 
- 			    addFormatToken('H', ['HH', 2], 0, 'hour');
 
- 			    addFormatToken('h', ['hh', 2], 0, hFormat);
 
- 			    addFormatToken('k', ['kk', 2], 0, kFormat);
 
- 			    addFormatToken('hmm', 0, 0, function () {
 
- 			        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
 
- 			    });
 
- 			    addFormatToken('hmmss', 0, 0, function () {
 
- 			        return (
 
- 			            '' +
 
- 			            hFormat.apply(this) +
 
- 			            zeroFill(this.minutes(), 2) +
 
- 			            zeroFill(this.seconds(), 2)
 
- 			        );
 
- 			    });
 
- 			    addFormatToken('Hmm', 0, 0, function () {
 
- 			        return '' + this.hours() + zeroFill(this.minutes(), 2);
 
- 			    });
 
- 			    addFormatToken('Hmmss', 0, 0, function () {
 
- 			        return (
 
- 			            '' +
 
- 			            this.hours() +
 
- 			            zeroFill(this.minutes(), 2) +
 
- 			            zeroFill(this.seconds(), 2)
 
- 			        );
 
- 			    });
 
- 			    function meridiem(token, lowercase) {
 
- 			        addFormatToken(token, 0, 0, function () {
 
- 			            return this.localeData().meridiem(
 
- 			                this.hours(),
 
- 			                this.minutes(),
 
- 			                lowercase
 
- 			            );
 
- 			        });
 
- 			    }
 
- 			    meridiem('a', true);
 
- 			    meridiem('A', false);
 
- 			    // ALIASES
 
- 			    addUnitAlias('hour', 'h');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('hour', 13);
 
- 			    // PARSING
 
- 			    function matchMeridiem(isStrict, locale) {
 
- 			        return locale._meridiemParse;
 
- 			    }
 
- 			    addRegexToken('a', matchMeridiem);
 
- 			    addRegexToken('A', matchMeridiem);
 
- 			    addRegexToken('H', match1to2);
 
- 			    addRegexToken('h', match1to2);
 
- 			    addRegexToken('k', match1to2);
 
- 			    addRegexToken('HH', match1to2, match2);
 
- 			    addRegexToken('hh', match1to2, match2);
 
- 			    addRegexToken('kk', match1to2, match2);
 
- 			    addRegexToken('hmm', match3to4);
 
- 			    addRegexToken('hmmss', match5to6);
 
- 			    addRegexToken('Hmm', match3to4);
 
- 			    addRegexToken('Hmmss', match5to6);
 
- 			    addParseToken(['H', 'HH'], HOUR);
 
- 			    addParseToken(['k', 'kk'], function (input, array, config) {
 
- 			        var kInput = toInt(input);
 
- 			        array[HOUR] = kInput === 24 ? 0 : kInput;
 
- 			    });
 
- 			    addParseToken(['a', 'A'], function (input, array, config) {
 
- 			        config._isPm = config._locale.isPM(input);
 
- 			        config._meridiem = input;
 
- 			    });
 
- 			    addParseToken(['h', 'hh'], function (input, array, config) {
 
- 			        array[HOUR] = toInt(input);
 
- 			        getParsingFlags(config).bigHour = true;
 
- 			    });
 
- 			    addParseToken('hmm', function (input, array, config) {
 
- 			        var pos = input.length - 2;
 
- 			        array[HOUR] = toInt(input.substr(0, pos));
 
- 			        array[MINUTE] = toInt(input.substr(pos));
 
- 			        getParsingFlags(config).bigHour = true;
 
- 			    });
 
- 			    addParseToken('hmmss', function (input, array, config) {
 
- 			        var pos1 = input.length - 4,
 
- 			            pos2 = input.length - 2;
 
- 			        array[HOUR] = toInt(input.substr(0, pos1));
 
- 			        array[MINUTE] = toInt(input.substr(pos1, 2));
 
- 			        array[SECOND] = toInt(input.substr(pos2));
 
- 			        getParsingFlags(config).bigHour = true;
 
- 			    });
 
- 			    addParseToken('Hmm', function (input, array, config) {
 
- 			        var pos = input.length - 2;
 
- 			        array[HOUR] = toInt(input.substr(0, pos));
 
- 			        array[MINUTE] = toInt(input.substr(pos));
 
- 			    });
 
- 			    addParseToken('Hmmss', function (input, array, config) {
 
- 			        var pos1 = input.length - 4,
 
- 			            pos2 = input.length - 2;
 
- 			        array[HOUR] = toInt(input.substr(0, pos1));
 
- 			        array[MINUTE] = toInt(input.substr(pos1, 2));
 
- 			        array[SECOND] = toInt(input.substr(pos2));
 
- 			    });
 
- 			    // LOCALES
 
- 			    function localeIsPM(input) {
 
- 			        // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
 
- 			        // Using charAt should be more compatible.
 
- 			        return (input + '').toLowerCase().charAt(0) === 'p';
 
- 			    }
 
- 			    var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i,
 
- 			        // Setting the hour should keep the time, because the user explicitly
 
- 			        // specified which hour they want. So trying to maintain the same hour (in
 
- 			        // a new timezone) makes sense. Adding/subtracting hours does not follow
 
- 			        // this rule.
 
- 			        getSetHour = makeGetSet('Hours', true);
 
- 			    function localeMeridiem(hours, minutes, isLower) {
 
- 			        if (hours > 11) {
 
- 			            return isLower ? 'pm' : 'PM';
 
- 			        } else {
 
- 			            return isLower ? 'am' : 'AM';
 
- 			        }
 
- 			    }
 
- 			    var baseConfig = {
 
- 			        calendar: defaultCalendar,
 
- 			        longDateFormat: defaultLongDateFormat,
 
- 			        invalidDate: defaultInvalidDate,
 
- 			        ordinal: defaultOrdinal,
 
- 			        dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
 
- 			        relativeTime: defaultRelativeTime,
 
- 			        months: defaultLocaleMonths,
 
- 			        monthsShort: defaultLocaleMonthsShort,
 
- 			        week: defaultLocaleWeek,
 
- 			        weekdays: defaultLocaleWeekdays,
 
- 			        weekdaysMin: defaultLocaleWeekdaysMin,
 
- 			        weekdaysShort: defaultLocaleWeekdaysShort,
 
- 			        meridiemParse: defaultLocaleMeridiemParse,
 
- 			    };
 
- 			    // internal storage for locale config files
 
- 			    var locales = {},
 
- 			        localeFamilies = {},
 
- 			        globalLocale;
 
- 			    function commonPrefix(arr1, arr2) {
 
- 			        var i,
 
- 			            minl = Math.min(arr1.length, arr2.length);
 
- 			        for (i = 0; i < minl; i += 1) {
 
- 			            if (arr1[i] !== arr2[i]) {
 
- 			                return i;
 
- 			            }
 
- 			        }
 
- 			        return minl;
 
- 			    }
 
- 			    function normalizeLocale(key) {
 
- 			        return key ? key.toLowerCase().replace('_', '-') : key;
 
- 			    }
 
- 			    // pick the locale from the array
 
- 			    // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
 
- 			    // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
 
- 			    function chooseLocale(names) {
 
- 			        var i = 0,
 
- 			            j,
 
- 			            next,
 
- 			            locale,
 
- 			            split;
 
- 			        while (i < names.length) {
 
- 			            split = normalizeLocale(names[i]).split('-');
 
- 			            j = split.length;
 
- 			            next = normalizeLocale(names[i + 1]);
 
- 			            next = next ? next.split('-') : null;
 
- 			            while (j > 0) {
 
- 			                locale = loadLocale(split.slice(0, j).join('-'));
 
- 			                if (locale) {
 
- 			                    return locale;
 
- 			                }
 
- 			                if (
 
- 			                    next &&
 
- 			                    next.length >= j &&
 
- 			                    commonPrefix(split, next) >= j - 1
 
- 			                ) {
 
- 			                    //the next array item is better than a shallower substring of this one
 
- 			                    break;
 
- 			                }
 
- 			                j--;
 
- 			            }
 
- 			            i++;
 
- 			        }
 
- 			        return globalLocale;
 
- 			    }
 
- 			    function isLocaleNameSane(name) {
 
- 			        // Prevent names that look like filesystem paths, i.e contain '/' or '\'
 
- 			        return name.match('^[^/\\\\]*$') != null;
 
- 			    }
 
- 			    function loadLocale(name) {
 
- 			        var oldLocale = null,
 
- 			            aliasedRequire;
 
- 			        // TODO: Find a better way to register and load all the locales in Node
 
- 			        if (
 
- 			            locales[name] === undefined &&
 
- 			            'object' !== 'undefined' &&
 
- 			            module &&
 
- 			            module.exports &&
 
- 			            isLocaleNameSane(name)
 
- 			        ) {
 
- 			            try {
 
- 			                oldLocale = globalLocale._abbr;
 
- 			                aliasedRequire = commonjsRequire;
 
- 			                aliasedRequire('./locale/' + name);
 
- 			                getSetGlobalLocale(oldLocale);
 
- 			            } catch (e) {
 
- 			                // mark as not found to avoid repeating expensive file require call causing high CPU
 
- 			                // when trying to find en-US, en_US, en-us for every format call
 
- 			                locales[name] = null; // null means not found
 
- 			            }
 
- 			        }
 
- 			        return locales[name];
 
- 			    }
 
- 			    // This function will load locale and then set the global locale.  If
 
- 			    // no arguments are passed in, it will simply return the current global
 
- 			    // locale key.
 
- 			    function getSetGlobalLocale(key, values) {
 
- 			        var data;
 
- 			        if (key) {
 
- 			            if (isUndefined(values)) {
 
- 			                data = getLocale(key);
 
- 			            } else {
 
- 			                data = defineLocale(key, values);
 
- 			            }
 
- 			            if (data) {
 
- 			                // moment.duration._locale = moment._locale = data;
 
- 			                globalLocale = data;
 
- 			            } else {
 
- 			                if (typeof console !== 'undefined' && console.warn) {
 
- 			                    //warn user if arguments are passed but the locale could not be set
 
- 			                    console.warn(
 
- 			                        'Locale ' + key + ' not found. Did you forget to load it?'
 
- 			                    );
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        return globalLocale._abbr;
 
- 			    }
 
- 			    function defineLocale(name, config) {
 
- 			        if (config !== null) {
 
- 			            var locale,
 
- 			                parentConfig = baseConfig;
 
- 			            config.abbr = name;
 
- 			            if (locales[name] != null) {
 
- 			                deprecateSimple(
 
- 			                    'defineLocaleOverride',
 
- 			                    'use moment.updateLocale(localeName, config) to change ' +
 
- 			                        'an existing locale. moment.defineLocale(localeName, ' +
 
- 			                        'config) should only be used for creating a new locale ' +
 
- 			                        'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.'
 
- 			                );
 
- 			                parentConfig = locales[name]._config;
 
- 			            } else if (config.parentLocale != null) {
 
- 			                if (locales[config.parentLocale] != null) {
 
- 			                    parentConfig = locales[config.parentLocale]._config;
 
- 			                } else {
 
- 			                    locale = loadLocale(config.parentLocale);
 
- 			                    if (locale != null) {
 
- 			                        parentConfig = locale._config;
 
- 			                    } else {
 
- 			                        if (!localeFamilies[config.parentLocale]) {
 
- 			                            localeFamilies[config.parentLocale] = [];
 
- 			                        }
 
- 			                        localeFamilies[config.parentLocale].push({
 
- 			                            name: name,
 
- 			                            config: config,
 
- 			                        });
 
- 			                        return null;
 
- 			                    }
 
- 			                }
 
- 			            }
 
- 			            locales[name] = new Locale(mergeConfigs(parentConfig, config));
 
- 			            if (localeFamilies[name]) {
 
- 			                localeFamilies[name].forEach(function (x) {
 
- 			                    defineLocale(x.name, x.config);
 
- 			                });
 
- 			            }
 
- 			            // backwards compat for now: also set the locale
 
- 			            // make sure we set the locale AFTER all child locales have been
 
- 			            // created, so we won't end up with the child locale set.
 
- 			            getSetGlobalLocale(name);
 
- 			            return locales[name];
 
- 			        } else {
 
- 			            // useful for testing
 
- 			            delete locales[name];
 
- 			            return null;
 
- 			        }
 
- 			    }
 
- 			    function updateLocale(name, config) {
 
- 			        if (config != null) {
 
- 			            var locale,
 
- 			                tmpLocale,
 
- 			                parentConfig = baseConfig;
 
- 			            if (locales[name] != null && locales[name].parentLocale != null) {
 
- 			                // Update existing child locale in-place to avoid memory-leaks
 
- 			                locales[name].set(mergeConfigs(locales[name]._config, config));
 
- 			            } else {
 
- 			                // MERGE
 
- 			                tmpLocale = loadLocale(name);
 
- 			                if (tmpLocale != null) {
 
- 			                    parentConfig = tmpLocale._config;
 
- 			                }
 
- 			                config = mergeConfigs(parentConfig, config);
 
- 			                if (tmpLocale == null) {
 
- 			                    // updateLocale is called for creating a new locale
 
- 			                    // Set abbr so it will have a name (getters return
 
- 			                    // undefined otherwise).
 
- 			                    config.abbr = name;
 
- 			                }
 
- 			                locale = new Locale(config);
 
- 			                locale.parentLocale = locales[name];
 
- 			                locales[name] = locale;
 
- 			            }
 
- 			            // backwards compat for now: also set the locale
 
- 			            getSetGlobalLocale(name);
 
- 			        } else {
 
- 			            // pass null for config to unupdate, useful for tests
 
- 			            if (locales[name] != null) {
 
- 			                if (locales[name].parentLocale != null) {
 
- 			                    locales[name] = locales[name].parentLocale;
 
- 			                    if (name === getSetGlobalLocale()) {
 
- 			                        getSetGlobalLocale(name);
 
- 			                    }
 
- 			                } else if (locales[name] != null) {
 
- 			                    delete locales[name];
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        return locales[name];
 
- 			    }
 
- 			    // returns locale data
 
- 			    function getLocale(key) {
 
- 			        var locale;
 
- 			        if (key && key._locale && key._locale._abbr) {
 
- 			            key = key._locale._abbr;
 
- 			        }
 
- 			        if (!key) {
 
- 			            return globalLocale;
 
- 			        }
 
- 			        if (!isArray(key)) {
 
- 			            //short-circuit everything else
 
- 			            locale = loadLocale(key);
 
- 			            if (locale) {
 
- 			                return locale;
 
- 			            }
 
- 			            key = [key];
 
- 			        }
 
- 			        return chooseLocale(key);
 
- 			    }
 
- 			    function listLocales() {
 
- 			        return keys(locales);
 
- 			    }
 
- 			    function checkOverflow(m) {
 
- 			        var overflow,
 
- 			            a = m._a;
 
- 			        if (a && getParsingFlags(m).overflow === -2) {
 
- 			            overflow =
 
- 			                a[MONTH] < 0 || a[MONTH] > 11
 
- 			                    ? MONTH
 
- 			                    : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH])
 
- 			                    ? DATE
 
- 			                    : a[HOUR] < 0 ||
 
- 			                      a[HOUR] > 24 ||
 
- 			                      (a[HOUR] === 24 &&
 
- 			                          (a[MINUTE] !== 0 ||
 
- 			                              a[SECOND] !== 0 ||
 
- 			                              a[MILLISECOND] !== 0))
 
- 			                    ? HOUR
 
- 			                    : a[MINUTE] < 0 || a[MINUTE] > 59
 
- 			                    ? MINUTE
 
- 			                    : a[SECOND] < 0 || a[SECOND] > 59
 
- 			                    ? SECOND
 
- 			                    : a[MILLISECOND] < 0 || a[MILLISECOND] > 999
 
- 			                    ? MILLISECOND
 
- 			                    : -1;
 
- 			            if (
 
- 			                getParsingFlags(m)._overflowDayOfYear &&
 
- 			                (overflow < YEAR || overflow > DATE)
 
- 			            ) {
 
- 			                overflow = DATE;
 
- 			            }
 
- 			            if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
 
- 			                overflow = WEEK;
 
- 			            }
 
- 			            if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
 
- 			                overflow = WEEKDAY;
 
- 			            }
 
- 			            getParsingFlags(m).overflow = overflow;
 
- 			        }
 
- 			        return m;
 
- 			    }
 
- 			    // iso 8601 regex
 
- 			    // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
 
- 			    var extendedIsoRegex =
 
- 			            /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
 
- 			        basicIsoRegex =
 
- 			            /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
 
- 			        tzRegex = /Z|[+-]\d\d(?::?\d\d)?/,
 
- 			        isoDates = [
 
- 			            ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
 
- 			            ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
 
- 			            ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
 
- 			            ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
 
- 			            ['YYYY-DDD', /\d{4}-\d{3}/],
 
- 			            ['YYYY-MM', /\d{4}-\d\d/, false],
 
- 			            ['YYYYYYMMDD', /[+-]\d{10}/],
 
- 			            ['YYYYMMDD', /\d{8}/],
 
- 			            ['GGGG[W]WWE', /\d{4}W\d{3}/],
 
- 			            ['GGGG[W]WW', /\d{4}W\d{2}/, false],
 
- 			            ['YYYYDDD', /\d{7}/],
 
- 			            ['YYYYMM', /\d{6}/, false],
 
- 			            ['YYYY', /\d{4}/, false],
 
- 			        ],
 
- 			        // iso time formats and regexes
 
- 			        isoTimes = [
 
- 			            ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
 
- 			            ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
 
- 			            ['HH:mm:ss', /\d\d:\d\d:\d\d/],
 
- 			            ['HH:mm', /\d\d:\d\d/],
 
- 			            ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
 
- 			            ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
 
- 			            ['HHmmss', /\d\d\d\d\d\d/],
 
- 			            ['HHmm', /\d\d\d\d/],
 
- 			            ['HH', /\d\d/],
 
- 			        ],
 
- 			        aspNetJsonRegex = /^\/?Date\((-?\d+)/i,
 
- 			        // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
 
- 			        rfc2822 =
 
- 			            /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,
 
- 			        obsOffsets = {
 
- 			            UT: 0,
 
- 			            GMT: 0,
 
- 			            EDT: -4 * 60,
 
- 			            EST: -5 * 60,
 
- 			            CDT: -5 * 60,
 
- 			            CST: -6 * 60,
 
- 			            MDT: -6 * 60,
 
- 			            MST: -7 * 60,
 
- 			            PDT: -7 * 60,
 
- 			            PST: -8 * 60,
 
- 			        };
 
- 			    // date from iso format
 
- 			    function configFromISO(config) {
 
- 			        var i,
 
- 			            l,
 
- 			            string = config._i,
 
- 			            match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
 
- 			            allowTime,
 
- 			            dateFormat,
 
- 			            timeFormat,
 
- 			            tzFormat,
 
- 			            isoDatesLen = isoDates.length,
 
- 			            isoTimesLen = isoTimes.length;
 
- 			        if (match) {
 
- 			            getParsingFlags(config).iso = true;
 
- 			            for (i = 0, l = isoDatesLen; i < l; i++) {
 
- 			                if (isoDates[i][1].exec(match[1])) {
 
- 			                    dateFormat = isoDates[i][0];
 
- 			                    allowTime = isoDates[i][2] !== false;
 
- 			                    break;
 
- 			                }
 
- 			            }
 
- 			            if (dateFormat == null) {
 
- 			                config._isValid = false;
 
- 			                return;
 
- 			            }
 
- 			            if (match[3]) {
 
- 			                for (i = 0, l = isoTimesLen; i < l; i++) {
 
- 			                    if (isoTimes[i][1].exec(match[3])) {
 
- 			                        // match[2] should be 'T' or space
 
- 			                        timeFormat = (match[2] || ' ') + isoTimes[i][0];
 
- 			                        break;
 
- 			                    }
 
- 			                }
 
- 			                if (timeFormat == null) {
 
- 			                    config._isValid = false;
 
- 			                    return;
 
- 			                }
 
- 			            }
 
- 			            if (!allowTime && timeFormat != null) {
 
- 			                config._isValid = false;
 
- 			                return;
 
- 			            }
 
- 			            if (match[4]) {
 
- 			                if (tzRegex.exec(match[4])) {
 
- 			                    tzFormat = 'Z';
 
- 			                } else {
 
- 			                    config._isValid = false;
 
- 			                    return;
 
- 			                }
 
- 			            }
 
- 			            config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
 
- 			            configFromStringAndFormat(config);
 
- 			        } else {
 
- 			            config._isValid = false;
 
- 			        }
 
- 			    }
 
- 			    function extractFromRFC2822Strings(
 
- 			        yearStr,
 
- 			        monthStr,
 
- 			        dayStr,
 
- 			        hourStr,
 
- 			        minuteStr,
 
- 			        secondStr
 
- 			    ) {
 
- 			        var result = [
 
- 			            untruncateYear(yearStr),
 
- 			            defaultLocaleMonthsShort.indexOf(monthStr),
 
- 			            parseInt(dayStr, 10),
 
- 			            parseInt(hourStr, 10),
 
- 			            parseInt(minuteStr, 10),
 
- 			        ];
 
- 			        if (secondStr) {
 
- 			            result.push(parseInt(secondStr, 10));
 
- 			        }
 
- 			        return result;
 
- 			    }
 
- 			    function untruncateYear(yearStr) {
 
- 			        var year = parseInt(yearStr, 10);
 
- 			        if (year <= 49) {
 
- 			            return 2000 + year;
 
- 			        } else if (year <= 999) {
 
- 			            return 1900 + year;
 
- 			        }
 
- 			        return year;
 
- 			    }
 
- 			    function preprocessRFC2822(s) {
 
- 			        // Remove comments and folding whitespace and replace multiple-spaces with a single space
 
- 			        return s
 
- 			            .replace(/\([^()]*\)|[\n\t]/g, ' ')
 
- 			            .replace(/(\s\s+)/g, ' ')
 
- 			            .replace(/^\s\s*/, '')
 
- 			            .replace(/\s\s*$/, '');
 
- 			    }
 
- 			    function checkWeekday(weekdayStr, parsedInput, config) {
 
- 			        if (weekdayStr) {
 
- 			            // TODO: Replace the vanilla JS Date object with an independent day-of-week check.
 
- 			            var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
 
- 			                weekdayActual = new Date(
 
- 			                    parsedInput[0],
 
- 			                    parsedInput[1],
 
- 			                    parsedInput[2]
 
- 			                ).getDay();
 
- 			            if (weekdayProvided !== weekdayActual) {
 
- 			                getParsingFlags(config).weekdayMismatch = true;
 
- 			                config._isValid = false;
 
- 			                return false;
 
- 			            }
 
- 			        }
 
- 			        return true;
 
- 			    }
 
- 			    function calculateOffset(obsOffset, militaryOffset, numOffset) {
 
- 			        if (obsOffset) {
 
- 			            return obsOffsets[obsOffset];
 
- 			        } else if (militaryOffset) {
 
- 			            // the only allowed military tz is Z
 
- 			            return 0;
 
- 			        } else {
 
- 			            var hm = parseInt(numOffset, 10),
 
- 			                m = hm % 100,
 
- 			                h = (hm - m) / 100;
 
- 			            return h * 60 + m;
 
- 			        }
 
- 			    }
 
- 			    // date and time from ref 2822 format
 
- 			    function configFromRFC2822(config) {
 
- 			        var match = rfc2822.exec(preprocessRFC2822(config._i)),
 
- 			            parsedArray;
 
- 			        if (match) {
 
- 			            parsedArray = extractFromRFC2822Strings(
 
- 			                match[4],
 
- 			                match[3],
 
- 			                match[2],
 
- 			                match[5],
 
- 			                match[6],
 
- 			                match[7]
 
- 			            );
 
- 			            if (!checkWeekday(match[1], parsedArray, config)) {
 
- 			                return;
 
- 			            }
 
- 			            config._a = parsedArray;
 
- 			            config._tzm = calculateOffset(match[8], match[9], match[10]);
 
- 			            config._d = createUTCDate.apply(null, config._a);
 
- 			            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
 
- 			            getParsingFlags(config).rfc2822 = true;
 
- 			        } else {
 
- 			            config._isValid = false;
 
- 			        }
 
- 			    }
 
- 			    // date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict
 
- 			    function configFromString(config) {
 
- 			        var matched = aspNetJsonRegex.exec(config._i);
 
- 			        if (matched !== null) {
 
- 			            config._d = new Date(+matched[1]);
 
- 			            return;
 
- 			        }
 
- 			        configFromISO(config);
 
- 			        if (config._isValid === false) {
 
- 			            delete config._isValid;
 
- 			        } else {
 
- 			            return;
 
- 			        }
 
- 			        configFromRFC2822(config);
 
- 			        if (config._isValid === false) {
 
- 			            delete config._isValid;
 
- 			        } else {
 
- 			            return;
 
- 			        }
 
- 			        if (config._strict) {
 
- 			            config._isValid = false;
 
- 			        } else {
 
- 			            // Final attempt, use Input Fallback
 
- 			            hooks.createFromInputFallback(config);
 
- 			        }
 
- 			    }
 
- 			    hooks.createFromInputFallback = deprecate(
 
- 			        'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
 
- 			            'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
 
- 			            'discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.',
 
- 			        function (config) {
 
- 			            config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
 
- 			        }
 
- 			    );
 
- 			    // Pick the first defined of two or three arguments.
 
- 			    function defaults(a, b, c) {
 
- 			        if (a != null) {
 
- 			            return a;
 
- 			        }
 
- 			        if (b != null) {
 
- 			            return b;
 
- 			        }
 
- 			        return c;
 
- 			    }
 
- 			    function currentDateArray(config) {
 
- 			        // hooks is actually the exported moment object
 
- 			        var nowValue = new Date(hooks.now());
 
- 			        if (config._useUTC) {
 
- 			            return [
 
- 			                nowValue.getUTCFullYear(),
 
- 			                nowValue.getUTCMonth(),
 
- 			                nowValue.getUTCDate(),
 
- 			            ];
 
- 			        }
 
- 			        return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
 
- 			    }
 
- 			    // convert an array to a date.
 
- 			    // the array should mirror the parameters below
 
- 			    // note: all values past the year are optional and will default to the lowest possible value.
 
- 			    // [year, month, day , hour, minute, second, millisecond]
 
- 			    function configFromArray(config) {
 
- 			        var i,
 
- 			            date,
 
- 			            input = [],
 
- 			            currentDate,
 
- 			            expectedWeekday,
 
- 			            yearToUse;
 
- 			        if (config._d) {
 
- 			            return;
 
- 			        }
 
- 			        currentDate = currentDateArray(config);
 
- 			        //compute day of the year from weeks and weekdays
 
- 			        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
 
- 			            dayOfYearFromWeekInfo(config);
 
- 			        }
 
- 			        //if the day of the year is set, figure out what it is
 
- 			        if (config._dayOfYear != null) {
 
- 			            yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
 
- 			            if (
 
- 			                config._dayOfYear > daysInYear(yearToUse) ||
 
- 			                config._dayOfYear === 0
 
- 			            ) {
 
- 			                getParsingFlags(config)._overflowDayOfYear = true;
 
- 			            }
 
- 			            date = createUTCDate(yearToUse, 0, config._dayOfYear);
 
- 			            config._a[MONTH] = date.getUTCMonth();
 
- 			            config._a[DATE] = date.getUTCDate();
 
- 			        }
 
- 			        // Default to current date.
 
- 			        // * if no year, month, day of month are given, default to today
 
- 			        // * if day of month is given, default month and year
 
- 			        // * if month is given, default only year
 
- 			        // * if year is given, don't default anything
 
- 			        for (i = 0; i < 3 && config._a[i] == null; ++i) {
 
- 			            config._a[i] = input[i] = currentDate[i];
 
- 			        }
 
- 			        // Zero out whatever was not defaulted, including time
 
- 			        for (; i < 7; i++) {
 
- 			            config._a[i] = input[i] =
 
- 			                config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i];
 
- 			        }
 
- 			        // Check for 24:00:00.000
 
- 			        if (
 
- 			            config._a[HOUR] === 24 &&
 
- 			            config._a[MINUTE] === 0 &&
 
- 			            config._a[SECOND] === 0 &&
 
- 			            config._a[MILLISECOND] === 0
 
- 			        ) {
 
- 			            config._nextDay = true;
 
- 			            config._a[HOUR] = 0;
 
- 			        }
 
- 			        config._d = (config._useUTC ? createUTCDate : createDate).apply(
 
- 			            null,
 
- 			            input
 
- 			        );
 
- 			        expectedWeekday = config._useUTC
 
- 			            ? config._d.getUTCDay()
 
- 			            : config._d.getDay();
 
- 			        // Apply timezone offset from input. The actual utcOffset can be changed
 
- 			        // with parseZone.
 
- 			        if (config._tzm != null) {
 
- 			            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
 
- 			        }
 
- 			        if (config._nextDay) {
 
- 			            config._a[HOUR] = 24;
 
- 			        }
 
- 			        // check for mismatching day of week
 
- 			        if (
 
- 			            config._w &&
 
- 			            typeof config._w.d !== 'undefined' &&
 
- 			            config._w.d !== expectedWeekday
 
- 			        ) {
 
- 			            getParsingFlags(config).weekdayMismatch = true;
 
- 			        }
 
- 			    }
 
- 			    function dayOfYearFromWeekInfo(config) {
 
- 			        var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek;
 
- 			        w = config._w;
 
- 			        if (w.GG != null || w.W != null || w.E != null) {
 
- 			            dow = 1;
 
- 			            doy = 4;
 
- 			            // TODO: We need to take the current isoWeekYear, but that depends on
 
- 			            // how we interpret now (local, utc, fixed offset). So create
 
- 			            // a now version of current config (take local/utc/offset flags, and
 
- 			            // create now).
 
- 			            weekYear = defaults(
 
- 			                w.GG,
 
- 			                config._a[YEAR],
 
- 			                weekOfYear(createLocal(), 1, 4).year
 
- 			            );
 
- 			            week = defaults(w.W, 1);
 
- 			            weekday = defaults(w.E, 1);
 
- 			            if (weekday < 1 || weekday > 7) {
 
- 			                weekdayOverflow = true;
 
- 			            }
 
- 			        } else {
 
- 			            dow = config._locale._week.dow;
 
- 			            doy = config._locale._week.doy;
 
- 			            curWeek = weekOfYear(createLocal(), dow, doy);
 
- 			            weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
 
- 			            // Default to current week.
 
- 			            week = defaults(w.w, curWeek.week);
 
- 			            if (w.d != null) {
 
- 			                // weekday -- low day numbers are considered next week
 
- 			                weekday = w.d;
 
- 			                if (weekday < 0 || weekday > 6) {
 
- 			                    weekdayOverflow = true;
 
- 			                }
 
- 			            } else if (w.e != null) {
 
- 			                // local weekday -- counting starts from beginning of week
 
- 			                weekday = w.e + dow;
 
- 			                if (w.e < 0 || w.e > 6) {
 
- 			                    weekdayOverflow = true;
 
- 			                }
 
- 			            } else {
 
- 			                // default to beginning of week
 
- 			                weekday = dow;
 
- 			            }
 
- 			        }
 
- 			        if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
 
- 			            getParsingFlags(config)._overflowWeeks = true;
 
- 			        } else if (weekdayOverflow != null) {
 
- 			            getParsingFlags(config)._overflowWeekday = true;
 
- 			        } else {
 
- 			            temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
 
- 			            config._a[YEAR] = temp.year;
 
- 			            config._dayOfYear = temp.dayOfYear;
 
- 			        }
 
- 			    }
 
- 			    // constant that refers to the ISO standard
 
- 			    hooks.ISO_8601 = function () {};
 
- 			    // constant that refers to the RFC 2822 form
 
- 			    hooks.RFC_2822 = function () {};
 
- 			    // date from string and format string
 
- 			    function configFromStringAndFormat(config) {
 
- 			        // TODO: Move this to another part of the creation flow to prevent circular deps
 
- 			        if (config._f === hooks.ISO_8601) {
 
- 			            configFromISO(config);
 
- 			            return;
 
- 			        }
 
- 			        if (config._f === hooks.RFC_2822) {
 
- 			            configFromRFC2822(config);
 
- 			            return;
 
- 			        }
 
- 			        config._a = [];
 
- 			        getParsingFlags(config).empty = true;
 
- 			        // This array is used to make a Date, either with `new Date` or `Date.UTC`
 
- 			        var string = '' + config._i,
 
- 			            i,
 
- 			            parsedInput,
 
- 			            tokens,
 
- 			            token,
 
- 			            skipped,
 
- 			            stringLength = string.length,
 
- 			            totalParsedInputLength = 0,
 
- 			            era,
 
- 			            tokenLen;
 
- 			        tokens =
 
- 			            expandFormat(config._f, config._locale).match(formattingTokens) || [];
 
- 			        tokenLen = tokens.length;
 
- 			        for (i = 0; i < tokenLen; i++) {
 
- 			            token = tokens[i];
 
- 			            parsedInput = (string.match(getParseRegexForToken(token, config)) ||
 
- 			                [])[0];
 
- 			            if (parsedInput) {
 
- 			                skipped = string.substr(0, string.indexOf(parsedInput));
 
- 			                if (skipped.length > 0) {
 
- 			                    getParsingFlags(config).unusedInput.push(skipped);
 
- 			                }
 
- 			                string = string.slice(
 
- 			                    string.indexOf(parsedInput) + parsedInput.length
 
- 			                );
 
- 			                totalParsedInputLength += parsedInput.length;
 
- 			            }
 
- 			            // don't parse if it's not a known token
 
- 			            if (formatTokenFunctions[token]) {
 
- 			                if (parsedInput) {
 
- 			                    getParsingFlags(config).empty = false;
 
- 			                } else {
 
- 			                    getParsingFlags(config).unusedTokens.push(token);
 
- 			                }
 
- 			                addTimeToArrayFromToken(token, parsedInput, config);
 
- 			            } else if (config._strict && !parsedInput) {
 
- 			                getParsingFlags(config).unusedTokens.push(token);
 
- 			            }
 
- 			        }
 
- 			        // add remaining unparsed input length to the string
 
- 			        getParsingFlags(config).charsLeftOver =
 
- 			            stringLength - totalParsedInputLength;
 
- 			        if (string.length > 0) {
 
- 			            getParsingFlags(config).unusedInput.push(string);
 
- 			        }
 
- 			        // clear _12h flag if hour is <= 12
 
- 			        if (
 
- 			            config._a[HOUR] <= 12 &&
 
- 			            getParsingFlags(config).bigHour === true &&
 
- 			            config._a[HOUR] > 0
 
- 			        ) {
 
- 			            getParsingFlags(config).bigHour = undefined;
 
- 			        }
 
- 			        getParsingFlags(config).parsedDateParts = config._a.slice(0);
 
- 			        getParsingFlags(config).meridiem = config._meridiem;
 
- 			        // handle meridiem
 
- 			        config._a[HOUR] = meridiemFixWrap(
 
- 			            config._locale,
 
- 			            config._a[HOUR],
 
- 			            config._meridiem
 
- 			        );
 
- 			        // handle era
 
- 			        era = getParsingFlags(config).era;
 
- 			        if (era !== null) {
 
- 			            config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]);
 
- 			        }
 
- 			        configFromArray(config);
 
- 			        checkOverflow(config);
 
- 			    }
 
- 			    function meridiemFixWrap(locale, hour, meridiem) {
 
- 			        var isPm;
 
- 			        if (meridiem == null) {
 
- 			            // nothing to do
 
- 			            return hour;
 
- 			        }
 
- 			        if (locale.meridiemHour != null) {
 
- 			            return locale.meridiemHour(hour, meridiem);
 
- 			        } else if (locale.isPM != null) {
 
- 			            // Fallback
 
- 			            isPm = locale.isPM(meridiem);
 
- 			            if (isPm && hour < 12) {
 
- 			                hour += 12;
 
- 			            }
 
- 			            if (!isPm && hour === 12) {
 
- 			                hour = 0;
 
- 			            }
 
- 			            return hour;
 
- 			        } else {
 
- 			            // this is not supposed to happen
 
- 			            return hour;
 
- 			        }
 
- 			    }
 
- 			    // date from string and array of format strings
 
- 			    function configFromStringAndArray(config) {
 
- 			        var tempConfig,
 
- 			            bestMoment,
 
- 			            scoreToBeat,
 
- 			            i,
 
- 			            currentScore,
 
- 			            validFormatFound,
 
- 			            bestFormatIsValid = false,
 
- 			            configfLen = config._f.length;
 
- 			        if (configfLen === 0) {
 
- 			            getParsingFlags(config).invalidFormat = true;
 
- 			            config._d = new Date(NaN);
 
- 			            return;
 
- 			        }
 
- 			        for (i = 0; i < configfLen; i++) {
 
- 			            currentScore = 0;
 
- 			            validFormatFound = false;
 
- 			            tempConfig = copyConfig({}, config);
 
- 			            if (config._useUTC != null) {
 
- 			                tempConfig._useUTC = config._useUTC;
 
- 			            }
 
- 			            tempConfig._f = config._f[i];
 
- 			            configFromStringAndFormat(tempConfig);
 
- 			            if (isValid(tempConfig)) {
 
- 			                validFormatFound = true;
 
- 			            }
 
- 			            // if there is any input that was not parsed add a penalty for that format
 
- 			            currentScore += getParsingFlags(tempConfig).charsLeftOver;
 
- 			            //or tokens
 
- 			            currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
 
- 			            getParsingFlags(tempConfig).score = currentScore;
 
- 			            if (!bestFormatIsValid) {
 
- 			                if (
 
- 			                    scoreToBeat == null ||
 
- 			                    currentScore < scoreToBeat ||
 
- 			                    validFormatFound
 
- 			                ) {
 
- 			                    scoreToBeat = currentScore;
 
- 			                    bestMoment = tempConfig;
 
- 			                    if (validFormatFound) {
 
- 			                        bestFormatIsValid = true;
 
- 			                    }
 
- 			                }
 
- 			            } else {
 
- 			                if (currentScore < scoreToBeat) {
 
- 			                    scoreToBeat = currentScore;
 
- 			                    bestMoment = tempConfig;
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        extend(config, bestMoment || tempConfig);
 
- 			    }
 
- 			    function configFromObject(config) {
 
- 			        if (config._d) {
 
- 			            return;
 
- 			        }
 
- 			        var i = normalizeObjectUnits(config._i),
 
- 			            dayOrDate = i.day === undefined ? i.date : i.day;
 
- 			        config._a = map(
 
- 			            [i.year, i.month, dayOrDate, i.hour, i.minute, i.second, i.millisecond],
 
- 			            function (obj) {
 
- 			                return obj && parseInt(obj, 10);
 
- 			            }
 
- 			        );
 
- 			        configFromArray(config);
 
- 			    }
 
- 			    function createFromConfig(config) {
 
- 			        var res = new Moment(checkOverflow(prepareConfig(config)));
 
- 			        if (res._nextDay) {
 
- 			            // Adding is smart enough around DST
 
- 			            res.add(1, 'd');
 
- 			            res._nextDay = undefined;
 
- 			        }
 
- 			        return res;
 
- 			    }
 
- 			    function prepareConfig(config) {
 
- 			        var input = config._i,
 
- 			            format = config._f;
 
- 			        config._locale = config._locale || getLocale(config._l);
 
- 			        if (input === null || (format === undefined && input === '')) {
 
- 			            return createInvalid({ nullInput: true });
 
- 			        }
 
- 			        if (typeof input === 'string') {
 
- 			            config._i = input = config._locale.preparse(input);
 
- 			        }
 
- 			        if (isMoment(input)) {
 
- 			            return new Moment(checkOverflow(input));
 
- 			        } else if (isDate(input)) {
 
- 			            config._d = input;
 
- 			        } else if (isArray(format)) {
 
- 			            configFromStringAndArray(config);
 
- 			        } else if (format) {
 
- 			            configFromStringAndFormat(config);
 
- 			        } else {
 
- 			            configFromInput(config);
 
- 			        }
 
- 			        if (!isValid(config)) {
 
- 			            config._d = null;
 
- 			        }
 
- 			        return config;
 
- 			    }
 
- 			    function configFromInput(config) {
 
- 			        var input = config._i;
 
- 			        if (isUndefined(input)) {
 
- 			            config._d = new Date(hooks.now());
 
- 			        } else if (isDate(input)) {
 
- 			            config._d = new Date(input.valueOf());
 
- 			        } else if (typeof input === 'string') {
 
- 			            configFromString(config);
 
- 			        } else if (isArray(input)) {
 
- 			            config._a = map(input.slice(0), function (obj) {
 
- 			                return parseInt(obj, 10);
 
- 			            });
 
- 			            configFromArray(config);
 
- 			        } else if (isObject(input)) {
 
- 			            configFromObject(config);
 
- 			        } else if (isNumber(input)) {
 
- 			            // from milliseconds
 
- 			            config._d = new Date(input);
 
- 			        } else {
 
- 			            hooks.createFromInputFallback(config);
 
- 			        }
 
- 			    }
 
- 			    function createLocalOrUTC(input, format, locale, strict, isUTC) {
 
- 			        var c = {};
 
- 			        if (format === true || format === false) {
 
- 			            strict = format;
 
- 			            format = undefined;
 
- 			        }
 
- 			        if (locale === true || locale === false) {
 
- 			            strict = locale;
 
- 			            locale = undefined;
 
- 			        }
 
- 			        if (
 
- 			            (isObject(input) && isObjectEmpty(input)) ||
 
- 			            (isArray(input) && input.length === 0)
 
- 			        ) {
 
- 			            input = undefined;
 
- 			        }
 
- 			        // object construction must be done this way.
 
- 			        // https://github.com/moment/moment/issues/1423
 
- 			        c._isAMomentObject = true;
 
- 			        c._useUTC = c._isUTC = isUTC;
 
- 			        c._l = locale;
 
- 			        c._i = input;
 
- 			        c._f = format;
 
- 			        c._strict = strict;
 
- 			        return createFromConfig(c);
 
- 			    }
 
- 			    function createLocal(input, format, locale, strict) {
 
- 			        return createLocalOrUTC(input, format, locale, strict, false);
 
- 			    }
 
- 			    var prototypeMin = deprecate(
 
- 			            'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
 
- 			            function () {
 
- 			                var other = createLocal.apply(null, arguments);
 
- 			                if (this.isValid() && other.isValid()) {
 
- 			                    return other < this ? this : other;
 
- 			                } else {
 
- 			                    return createInvalid();
 
- 			                }
 
- 			            }
 
- 			        ),
 
- 			        prototypeMax = deprecate(
 
- 			            'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
 
- 			            function () {
 
- 			                var other = createLocal.apply(null, arguments);
 
- 			                if (this.isValid() && other.isValid()) {
 
- 			                    return other > this ? this : other;
 
- 			                } else {
 
- 			                    return createInvalid();
 
- 			                }
 
- 			            }
 
- 			        );
 
- 			    // Pick a moment m from moments so that m[fn](other) is true for all
 
- 			    // other. This relies on the function fn to be transitive.
 
- 			    //
 
- 			    // moments should either be an array of moment objects or an array, whose
 
- 			    // first element is an array of moment objects.
 
- 			    function pickBy(fn, moments) {
 
- 			        var res, i;
 
- 			        if (moments.length === 1 && isArray(moments[0])) {
 
- 			            moments = moments[0];
 
- 			        }
 
- 			        if (!moments.length) {
 
- 			            return createLocal();
 
- 			        }
 
- 			        res = moments[0];
 
- 			        for (i = 1; i < moments.length; ++i) {
 
- 			            if (!moments[i].isValid() || moments[i][fn](res)) {
 
- 			                res = moments[i];
 
- 			            }
 
- 			        }
 
- 			        return res;
 
- 			    }
 
- 			    // TODO: Use [].sort instead?
 
- 			    function min() {
 
- 			        var args = [].slice.call(arguments, 0);
 
- 			        return pickBy('isBefore', args);
 
- 			    }
 
- 			    function max() {
 
- 			        var args = [].slice.call(arguments, 0);
 
- 			        return pickBy('isAfter', args);
 
- 			    }
 
- 			    var now = function () {
 
- 			        return Date.now ? Date.now() : +new Date();
 
- 			    };
 
- 			    var ordering = [
 
- 			        'year',
 
- 			        'quarter',
 
- 			        'month',
 
- 			        'week',
 
- 			        'day',
 
- 			        'hour',
 
- 			        'minute',
 
- 			        'second',
 
- 			        'millisecond',
 
- 			    ];
 
- 			    function isDurationValid(m) {
 
- 			        var key,
 
- 			            unitHasDecimal = false,
 
- 			            i,
 
- 			            orderLen = ordering.length;
 
- 			        for (key in m) {
 
- 			            if (
 
- 			                hasOwnProp(m, key) &&
 
- 			                !(
 
- 			                    indexOf.call(ordering, key) !== -1 &&
 
- 			                    (m[key] == null || !isNaN(m[key]))
 
- 			                )
 
- 			            ) {
 
- 			                return false;
 
- 			            }
 
- 			        }
 
- 			        for (i = 0; i < orderLen; ++i) {
 
- 			            if (m[ordering[i]]) {
 
- 			                if (unitHasDecimal) {
 
- 			                    return false; // only allow non-integers for smallest unit
 
- 			                }
 
- 			                if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
 
- 			                    unitHasDecimal = true;
 
- 			                }
 
- 			            }
 
- 			        }
 
- 			        return true;
 
- 			    }
 
- 			    function isValid$1() {
 
- 			        return this._isValid;
 
- 			    }
 
- 			    function createInvalid$1() {
 
- 			        return createDuration(NaN);
 
- 			    }
 
- 			    function Duration(duration) {
 
- 			        var normalizedInput = normalizeObjectUnits(duration),
 
- 			            years = normalizedInput.year || 0,
 
- 			            quarters = normalizedInput.quarter || 0,
 
- 			            months = normalizedInput.month || 0,
 
- 			            weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
 
- 			            days = normalizedInput.day || 0,
 
- 			            hours = normalizedInput.hour || 0,
 
- 			            minutes = normalizedInput.minute || 0,
 
- 			            seconds = normalizedInput.second || 0,
 
- 			            milliseconds = normalizedInput.millisecond || 0;
 
- 			        this._isValid = isDurationValid(normalizedInput);
 
- 			        // representation for dateAddRemove
 
- 			        this._milliseconds =
 
- 			            +milliseconds +
 
- 			            seconds * 1e3 + // 1000
 
- 			            minutes * 6e4 + // 1000 * 60
 
- 			            hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
 
- 			        // Because of dateAddRemove treats 24 hours as different from a
 
- 			        // day when working around DST, we need to store them separately
 
- 			        this._days = +days + weeks * 7;
 
- 			        // It is impossible to translate months into days without knowing
 
- 			        // which months you are are talking about, so we have to store
 
- 			        // it separately.
 
- 			        this._months = +months + quarters * 3 + years * 12;
 
- 			        this._data = {};
 
- 			        this._locale = getLocale();
 
- 			        this._bubble();
 
- 			    }
 
- 			    function isDuration(obj) {
 
- 			        return obj instanceof Duration;
 
- 			    }
 
- 			    function absRound(number) {
 
- 			        if (number < 0) {
 
- 			            return Math.round(-1 * number) * -1;
 
- 			        } else {
 
- 			            return Math.round(number);
 
- 			        }
 
- 			    }
 
- 			    // compare two arrays, return the number of differences
 
- 			    function compareArrays(array1, array2, dontConvert) {
 
- 			        var len = Math.min(array1.length, array2.length),
 
- 			            lengthDiff = Math.abs(array1.length - array2.length),
 
- 			            diffs = 0,
 
- 			            i;
 
- 			        for (i = 0; i < len; i++) {
 
- 			            if (
 
- 			                (dontConvert && array1[i] !== array2[i]) ||
 
- 			                (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))
 
- 			            ) {
 
- 			                diffs++;
 
- 			            }
 
- 			        }
 
- 			        return diffs + lengthDiff;
 
- 			    }
 
- 			    // FORMATTING
 
- 			    function offset(token, separator) {
 
- 			        addFormatToken(token, 0, 0, function () {
 
- 			            var offset = this.utcOffset(),
 
- 			                sign = '+';
 
- 			            if (offset < 0) {
 
- 			                offset = -offset;
 
- 			                sign = '-';
 
- 			            }
 
- 			            return (
 
- 			                sign +
 
- 			                zeroFill(~~(offset / 60), 2) +
 
- 			                separator +
 
- 			                zeroFill(~~offset % 60, 2)
 
- 			            );
 
- 			        });
 
- 			    }
 
- 			    offset('Z', ':');
 
- 			    offset('ZZ', '');
 
- 			    // PARSING
 
- 			    addRegexToken('Z', matchShortOffset);
 
- 			    addRegexToken('ZZ', matchShortOffset);
 
- 			    addParseToken(['Z', 'ZZ'], function (input, array, config) {
 
- 			        config._useUTC = true;
 
- 			        config._tzm = offsetFromString(matchShortOffset, input);
 
- 			    });
 
- 			    // HELPERS
 
- 			    // timezone chunker
 
- 			    // '+10:00' > ['10',  '00']
 
- 			    // '-1530'  > ['-15', '30']
 
- 			    var chunkOffset = /([\+\-]|\d\d)/gi;
 
- 			    function offsetFromString(matcher, string) {
 
- 			        var matches = (string || '').match(matcher),
 
- 			            chunk,
 
- 			            parts,
 
- 			            minutes;
 
- 			        if (matches === null) {
 
- 			            return null;
 
- 			        }
 
- 			        chunk = matches[matches.length - 1] || [];
 
- 			        parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
 
- 			        minutes = +(parts[1] * 60) + toInt(parts[2]);
 
- 			        return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
 
- 			    }
 
- 			    // Return a moment from input, that is local/utc/zone equivalent to model.
 
- 			    function cloneWithOffset(input, model) {
 
- 			        var res, diff;
 
- 			        if (model._isUTC) {
 
- 			            res = model.clone();
 
- 			            diff =
 
- 			                (isMoment(input) || isDate(input)
 
- 			                    ? input.valueOf()
 
- 			                    : createLocal(input).valueOf()) - res.valueOf();
 
- 			            // Use low-level api, because this fn is low-level api.
 
- 			            res._d.setTime(res._d.valueOf() + diff);
 
- 			            hooks.updateOffset(res, false);
 
- 			            return res;
 
- 			        } else {
 
- 			            return createLocal(input).local();
 
- 			        }
 
- 			    }
 
- 			    function getDateOffset(m) {
 
- 			        // On Firefox.24 Date#getTimezoneOffset returns a floating point.
 
- 			        // https://github.com/moment/moment/pull/1871
 
- 			        return -Math.round(m._d.getTimezoneOffset());
 
- 			    }
 
- 			    // HOOKS
 
- 			    // This function will be called whenever a moment is mutated.
 
- 			    // It is intended to keep the offset in sync with the timezone.
 
- 			    hooks.updateOffset = function () {};
 
- 			    // MOMENTS
 
- 			    // keepLocalTime = true means only change the timezone, without
 
- 			    // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
 
- 			    // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
 
- 			    // +0200, so we adjust the time as needed, to be valid.
 
- 			    //
 
- 			    // Keeping the time actually adds/subtracts (one hour)
 
- 			    // from the actual represented time. That is why we call updateOffset
 
- 			    // a second time. In case it wants us to change the offset again
 
- 			    // _changeInProgress == true case, then we have to adjust, because
 
- 			    // there is no such time in the given timezone.
 
- 			    function getSetOffset(input, keepLocalTime, keepMinutes) {
 
- 			        var offset = this._offset || 0,
 
- 			            localAdjust;
 
- 			        if (!this.isValid()) {
 
- 			            return input != null ? this : NaN;
 
- 			        }
 
- 			        if (input != null) {
 
- 			            if (typeof input === 'string') {
 
- 			                input = offsetFromString(matchShortOffset, input);
 
- 			                if (input === null) {
 
- 			                    return this;
 
- 			                }
 
- 			            } else if (Math.abs(input) < 16 && !keepMinutes) {
 
- 			                input = input * 60;
 
- 			            }
 
- 			            if (!this._isUTC && keepLocalTime) {
 
- 			                localAdjust = getDateOffset(this);
 
- 			            }
 
- 			            this._offset = input;
 
- 			            this._isUTC = true;
 
- 			            if (localAdjust != null) {
 
- 			                this.add(localAdjust, 'm');
 
- 			            }
 
- 			            if (offset !== input) {
 
- 			                if (!keepLocalTime || this._changeInProgress) {
 
- 			                    addSubtract(
 
- 			                        this,
 
- 			                        createDuration(input - offset, 'm'),
 
- 			                        1,
 
- 			                        false
 
- 			                    );
 
- 			                } else if (!this._changeInProgress) {
 
- 			                    this._changeInProgress = true;
 
- 			                    hooks.updateOffset(this, true);
 
- 			                    this._changeInProgress = null;
 
- 			                }
 
- 			            }
 
- 			            return this;
 
- 			        } else {
 
- 			            return this._isUTC ? offset : getDateOffset(this);
 
- 			        }
 
- 			    }
 
- 			    function getSetZone(input, keepLocalTime) {
 
- 			        if (input != null) {
 
- 			            if (typeof input !== 'string') {
 
- 			                input = -input;
 
- 			            }
 
- 			            this.utcOffset(input, keepLocalTime);
 
- 			            return this;
 
- 			        } else {
 
- 			            return -this.utcOffset();
 
- 			        }
 
- 			    }
 
- 			    function setOffsetToUTC(keepLocalTime) {
 
- 			        return this.utcOffset(0, keepLocalTime);
 
- 			    }
 
- 			    function setOffsetToLocal(keepLocalTime) {
 
- 			        if (this._isUTC) {
 
- 			            this.utcOffset(0, keepLocalTime);
 
- 			            this._isUTC = false;
 
- 			            if (keepLocalTime) {
 
- 			                this.subtract(getDateOffset(this), 'm');
 
- 			            }
 
- 			        }
 
- 			        return this;
 
- 			    }
 
- 			    function setOffsetToParsedOffset() {
 
- 			        if (this._tzm != null) {
 
- 			            this.utcOffset(this._tzm, false, true);
 
- 			        } else if (typeof this._i === 'string') {
 
- 			            var tZone = offsetFromString(matchOffset, this._i);
 
- 			            if (tZone != null) {
 
- 			                this.utcOffset(tZone);
 
- 			            } else {
 
- 			                this.utcOffset(0, true);
 
- 			            }
 
- 			        }
 
- 			        return this;
 
- 			    }
 
- 			    function hasAlignedHourOffset(input) {
 
- 			        if (!this.isValid()) {
 
- 			            return false;
 
- 			        }
 
- 			        input = input ? createLocal(input).utcOffset() : 0;
 
- 			        return (this.utcOffset() - input) % 60 === 0;
 
- 			    }
 
- 			    function isDaylightSavingTime() {
 
- 			        return (
 
- 			            this.utcOffset() > this.clone().month(0).utcOffset() ||
 
- 			            this.utcOffset() > this.clone().month(5).utcOffset()
 
- 			        );
 
- 			    }
 
- 			    function isDaylightSavingTimeShifted() {
 
- 			        if (!isUndefined(this._isDSTShifted)) {
 
- 			            return this._isDSTShifted;
 
- 			        }
 
- 			        var c = {},
 
- 			            other;
 
- 			        copyConfig(c, this);
 
- 			        c = prepareConfig(c);
 
- 			        if (c._a) {
 
- 			            other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
 
- 			            this._isDSTShifted =
 
- 			                this.isValid() && compareArrays(c._a, other.toArray()) > 0;
 
- 			        } else {
 
- 			            this._isDSTShifted = false;
 
- 			        }
 
- 			        return this._isDSTShifted;
 
- 			    }
 
- 			    function isLocal() {
 
- 			        return this.isValid() ? !this._isUTC : false;
 
- 			    }
 
- 			    function isUtcOffset() {
 
- 			        return this.isValid() ? this._isUTC : false;
 
- 			    }
 
- 			    function isUtc() {
 
- 			        return this.isValid() ? this._isUTC && this._offset === 0 : false;
 
- 			    }
 
- 			    // ASP.NET json date format regex
 
- 			    var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,
 
- 			        // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
 
- 			        // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
 
- 			        // and further modified to allow for strings containing both week and day
 
- 			        isoRegex =
 
- 			            /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
 
- 			    function createDuration(input, key) {
 
- 			        var duration = input,
 
- 			            // matching against regexp is expensive, do it on demand
 
- 			            match = null,
 
- 			            sign,
 
- 			            ret,
 
- 			            diffRes;
 
- 			        if (isDuration(input)) {
 
- 			            duration = {
 
- 			                ms: input._milliseconds,
 
- 			                d: input._days,
 
- 			                M: input._months,
 
- 			            };
 
- 			        } else if (isNumber(input) || !isNaN(+input)) {
 
- 			            duration = {};
 
- 			            if (key) {
 
- 			                duration[key] = +input;
 
- 			            } else {
 
- 			                duration.milliseconds = +input;
 
- 			            }
 
- 			        } else if ((match = aspNetRegex.exec(input))) {
 
- 			            sign = match[1] === '-' ? -1 : 1;
 
- 			            duration = {
 
- 			                y: 0,
 
- 			                d: toInt(match[DATE]) * sign,
 
- 			                h: toInt(match[HOUR]) * sign,
 
- 			                m: toInt(match[MINUTE]) * sign,
 
- 			                s: toInt(match[SECOND]) * sign,
 
- 			                ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match
 
- 			            };
 
- 			        } else if ((match = isoRegex.exec(input))) {
 
- 			            sign = match[1] === '-' ? -1 : 1;
 
- 			            duration = {
 
- 			                y: parseIso(match[2], sign),
 
- 			                M: parseIso(match[3], sign),
 
- 			                w: parseIso(match[4], sign),
 
- 			                d: parseIso(match[5], sign),
 
- 			                h: parseIso(match[6], sign),
 
- 			                m: parseIso(match[7], sign),
 
- 			                s: parseIso(match[8], sign),
 
- 			            };
 
- 			        } else if (duration == null) {
 
- 			            // checks for null or undefined
 
- 			            duration = {};
 
- 			        } else if (
 
- 			            typeof duration === 'object' &&
 
- 			            ('from' in duration || 'to' in duration)
 
- 			        ) {
 
- 			            diffRes = momentsDifference(
 
- 			                createLocal(duration.from),
 
- 			                createLocal(duration.to)
 
- 			            );
 
- 			            duration = {};
 
- 			            duration.ms = diffRes.milliseconds;
 
- 			            duration.M = diffRes.months;
 
- 			        }
 
- 			        ret = new Duration(duration);
 
- 			        if (isDuration(input) && hasOwnProp(input, '_locale')) {
 
- 			            ret._locale = input._locale;
 
- 			        }
 
- 			        if (isDuration(input) && hasOwnProp(input, '_isValid')) {
 
- 			            ret._isValid = input._isValid;
 
- 			        }
 
- 			        return ret;
 
- 			    }
 
- 			    createDuration.fn = Duration.prototype;
 
- 			    createDuration.invalid = createInvalid$1;
 
- 			    function parseIso(inp, sign) {
 
- 			        // We'd normally use ~~inp for this, but unfortunately it also
 
- 			        // converts floats to ints.
 
- 			        // inp may be undefined, so careful calling replace on it.
 
- 			        var res = inp && parseFloat(inp.replace(',', '.'));
 
- 			        // apply sign while we're at it
 
- 			        return (isNaN(res) ? 0 : res) * sign;
 
- 			    }
 
- 			    function positiveMomentsDifference(base, other) {
 
- 			        var res = {};
 
- 			        res.months =
 
- 			            other.month() - base.month() + (other.year() - base.year()) * 12;
 
- 			        if (base.clone().add(res.months, 'M').isAfter(other)) {
 
- 			            --res.months;
 
- 			        }
 
- 			        res.milliseconds = +other - +base.clone().add(res.months, 'M');
 
- 			        return res;
 
- 			    }
 
- 			    function momentsDifference(base, other) {
 
- 			        var res;
 
- 			        if (!(base.isValid() && other.isValid())) {
 
- 			            return { milliseconds: 0, months: 0 };
 
- 			        }
 
- 			        other = cloneWithOffset(other, base);
 
- 			        if (base.isBefore(other)) {
 
- 			            res = positiveMomentsDifference(base, other);
 
- 			        } else {
 
- 			            res = positiveMomentsDifference(other, base);
 
- 			            res.milliseconds = -res.milliseconds;
 
- 			            res.months = -res.months;
 
- 			        }
 
- 			        return res;
 
- 			    }
 
- 			    // TODO: remove 'name' arg after deprecation is removed
 
- 			    function createAdder(direction, name) {
 
- 			        return function (val, period) {
 
- 			            var dur, tmp;
 
- 			            //invert the arguments, but complain about it
 
- 			            if (period !== null && !isNaN(+period)) {
 
- 			                deprecateSimple(
 
- 			                    name,
 
- 			                    'moment().' +
 
- 			                        name +
 
- 			                        '(period, number) is deprecated. Please use moment().' +
 
- 			                        name +
 
- 			                        '(number, period). ' +
 
- 			                        'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.'
 
- 			                );
 
- 			                tmp = val;
 
- 			                val = period;
 
- 			                period = tmp;
 
- 			            }
 
- 			            dur = createDuration(val, period);
 
- 			            addSubtract(this, dur, direction);
 
- 			            return this;
 
- 			        };
 
- 			    }
 
- 			    function addSubtract(mom, duration, isAdding, updateOffset) {
 
- 			        var milliseconds = duration._milliseconds,
 
- 			            days = absRound(duration._days),
 
- 			            months = absRound(duration._months);
 
- 			        if (!mom.isValid()) {
 
- 			            // No op
 
- 			            return;
 
- 			        }
 
- 			        updateOffset = updateOffset == null ? true : updateOffset;
 
- 			        if (months) {
 
- 			            setMonth(mom, get(mom, 'Month') + months * isAdding);
 
- 			        }
 
- 			        if (days) {
 
- 			            set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
 
- 			        }
 
- 			        if (milliseconds) {
 
- 			            mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
 
- 			        }
 
- 			        if (updateOffset) {
 
- 			            hooks.updateOffset(mom, days || months);
 
- 			        }
 
- 			    }
 
- 			    var add = createAdder(1, 'add'),
 
- 			        subtract = createAdder(-1, 'subtract');
 
- 			    function isString(input) {
 
- 			        return typeof input === 'string' || input instanceof String;
 
- 			    }
 
- 			    // type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined
 
- 			    function isMomentInput(input) {
 
- 			        return (
 
- 			            isMoment(input) ||
 
- 			            isDate(input) ||
 
- 			            isString(input) ||
 
- 			            isNumber(input) ||
 
- 			            isNumberOrStringArray(input) ||
 
- 			            isMomentInputObject(input) ||
 
- 			            input === null ||
 
- 			            input === undefined
 
- 			        );
 
- 			    }
 
- 			    function isMomentInputObject(input) {
 
- 			        var objectTest = isObject(input) && !isObjectEmpty(input),
 
- 			            propertyTest = false,
 
- 			            properties = [
 
- 			                'years',
 
- 			                'year',
 
- 			                'y',
 
- 			                'months',
 
- 			                'month',
 
- 			                'M',
 
- 			                'days',
 
- 			                'day',
 
- 			                'd',
 
- 			                'dates',
 
- 			                'date',
 
- 			                'D',
 
- 			                'hours',
 
- 			                'hour',
 
- 			                'h',
 
- 			                'minutes',
 
- 			                'minute',
 
- 			                'm',
 
- 			                'seconds',
 
- 			                'second',
 
- 			                's',
 
- 			                'milliseconds',
 
- 			                'millisecond',
 
- 			                'ms',
 
- 			            ],
 
- 			            i,
 
- 			            property,
 
- 			            propertyLen = properties.length;
 
- 			        for (i = 0; i < propertyLen; i += 1) {
 
- 			            property = properties[i];
 
- 			            propertyTest = propertyTest || hasOwnProp(input, property);
 
- 			        }
 
- 			        return objectTest && propertyTest;
 
- 			    }
 
- 			    function isNumberOrStringArray(input) {
 
- 			        var arrayTest = isArray(input),
 
- 			            dataTypeTest = false;
 
- 			        if (arrayTest) {
 
- 			            dataTypeTest =
 
- 			                input.filter(function (item) {
 
- 			                    return !isNumber(item) && isString(input);
 
- 			                }).length === 0;
 
- 			        }
 
- 			        return arrayTest && dataTypeTest;
 
- 			    }
 
- 			    function isCalendarSpec(input) {
 
- 			        var objectTest = isObject(input) && !isObjectEmpty(input),
 
- 			            propertyTest = false,
 
- 			            properties = [
 
- 			                'sameDay',
 
- 			                'nextDay',
 
- 			                'lastDay',
 
- 			                'nextWeek',
 
- 			                'lastWeek',
 
- 			                'sameElse',
 
- 			            ],
 
- 			            i,
 
- 			            property;
 
- 			        for (i = 0; i < properties.length; i += 1) {
 
- 			            property = properties[i];
 
- 			            propertyTest = propertyTest || hasOwnProp(input, property);
 
- 			        }
 
- 			        return objectTest && propertyTest;
 
- 			    }
 
- 			    function getCalendarFormat(myMoment, now) {
 
- 			        var diff = myMoment.diff(now, 'days', true);
 
- 			        return diff < -6
 
- 			            ? 'sameElse'
 
- 			            : diff < -1
 
- 			            ? 'lastWeek'
 
- 			            : diff < 0
 
- 			            ? 'lastDay'
 
- 			            : diff < 1
 
- 			            ? 'sameDay'
 
- 			            : diff < 2
 
- 			            ? 'nextDay'
 
- 			            : diff < 7
 
- 			            ? 'nextWeek'
 
- 			            : 'sameElse';
 
- 			    }
 
- 			    function calendar$1(time, formats) {
 
- 			        // Support for single parameter, formats only overload to the calendar function
 
- 			        if (arguments.length === 1) {
 
- 			            if (!arguments[0]) {
 
- 			                time = undefined;
 
- 			                formats = undefined;
 
- 			            } else if (isMomentInput(arguments[0])) {
 
- 			                time = arguments[0];
 
- 			                formats = undefined;
 
- 			            } else if (isCalendarSpec(arguments[0])) {
 
- 			                formats = arguments[0];
 
- 			                time = undefined;
 
- 			            }
 
- 			        }
 
- 			        // We want to compare the start of today, vs this.
 
- 			        // Getting start-of-today depends on whether we're local/utc/offset or not.
 
- 			        var now = time || createLocal(),
 
- 			            sod = cloneWithOffset(now, this).startOf('day'),
 
- 			            format = hooks.calendarFormat(this, sod) || 'sameElse',
 
- 			            output =
 
- 			                formats &&
 
- 			                (isFunction(formats[format])
 
- 			                    ? formats[format].call(this, now)
 
- 			                    : formats[format]);
 
- 			        return this.format(
 
- 			            output || this.localeData().calendar(format, this, createLocal(now))
 
- 			        );
 
- 			    }
 
- 			    function clone() {
 
- 			        return new Moment(this);
 
- 			    }
 
- 			    function isAfter(input, units) {
 
- 			        var localInput = isMoment(input) ? input : createLocal(input);
 
- 			        if (!(this.isValid() && localInput.isValid())) {
 
- 			            return false;
 
- 			        }
 
- 			        units = normalizeUnits(units) || 'millisecond';
 
- 			        if (units === 'millisecond') {
 
- 			            return this.valueOf() > localInput.valueOf();
 
- 			        } else {
 
- 			            return localInput.valueOf() < this.clone().startOf(units).valueOf();
 
- 			        }
 
- 			    }
 
- 			    function isBefore(input, units) {
 
- 			        var localInput = isMoment(input) ? input : createLocal(input);
 
- 			        if (!(this.isValid() && localInput.isValid())) {
 
- 			            return false;
 
- 			        }
 
- 			        units = normalizeUnits(units) || 'millisecond';
 
- 			        if (units === 'millisecond') {
 
- 			            return this.valueOf() < localInput.valueOf();
 
- 			        } else {
 
- 			            return this.clone().endOf(units).valueOf() < localInput.valueOf();
 
- 			        }
 
- 			    }
 
- 			    function isBetween(from, to, units, inclusivity) {
 
- 			        var localFrom = isMoment(from) ? from : createLocal(from),
 
- 			            localTo = isMoment(to) ? to : createLocal(to);
 
- 			        if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
 
- 			            return false;
 
- 			        }
 
- 			        inclusivity = inclusivity || '()';
 
- 			        return (
 
- 			            (inclusivity[0] === '('
 
- 			                ? this.isAfter(localFrom, units)
 
- 			                : !this.isBefore(localFrom, units)) &&
 
- 			            (inclusivity[1] === ')'
 
- 			                ? this.isBefore(localTo, units)
 
- 			                : !this.isAfter(localTo, units))
 
- 			        );
 
- 			    }
 
- 			    function isSame(input, units) {
 
- 			        var localInput = isMoment(input) ? input : createLocal(input),
 
- 			            inputMs;
 
- 			        if (!(this.isValid() && localInput.isValid())) {
 
- 			            return false;
 
- 			        }
 
- 			        units = normalizeUnits(units) || 'millisecond';
 
- 			        if (units === 'millisecond') {
 
- 			            return this.valueOf() === localInput.valueOf();
 
- 			        } else {
 
- 			            inputMs = localInput.valueOf();
 
- 			            return (
 
- 			                this.clone().startOf(units).valueOf() <= inputMs &&
 
- 			                inputMs <= this.clone().endOf(units).valueOf()
 
- 			            );
 
- 			        }
 
- 			    }
 
- 			    function isSameOrAfter(input, units) {
 
- 			        return this.isSame(input, units) || this.isAfter(input, units);
 
- 			    }
 
- 			    function isSameOrBefore(input, units) {
 
- 			        return this.isSame(input, units) || this.isBefore(input, units);
 
- 			    }
 
- 			    function diff(input, units, asFloat) {
 
- 			        var that, zoneDelta, output;
 
- 			        if (!this.isValid()) {
 
- 			            return NaN;
 
- 			        }
 
- 			        that = cloneWithOffset(input, this);
 
- 			        if (!that.isValid()) {
 
- 			            return NaN;
 
- 			        }
 
- 			        zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
 
- 			        units = normalizeUnits(units);
 
- 			        switch (units) {
 
- 			            case 'year':
 
- 			                output = monthDiff(this, that) / 12;
 
- 			                break;
 
- 			            case 'month':
 
- 			                output = monthDiff(this, that);
 
- 			                break;
 
- 			            case 'quarter':
 
- 			                output = monthDiff(this, that) / 3;
 
- 			                break;
 
- 			            case 'second':
 
- 			                output = (this - that) / 1e3;
 
- 			                break; // 1000
 
- 			            case 'minute':
 
- 			                output = (this - that) / 6e4;
 
- 			                break; // 1000 * 60
 
- 			            case 'hour':
 
- 			                output = (this - that) / 36e5;
 
- 			                break; // 1000 * 60 * 60
 
- 			            case 'day':
 
- 			                output = (this - that - zoneDelta) / 864e5;
 
- 			                break; // 1000 * 60 * 60 * 24, negate dst
 
- 			            case 'week':
 
- 			                output = (this - that - zoneDelta) / 6048e5;
 
- 			                break; // 1000 * 60 * 60 * 24 * 7, negate dst
 
- 			            default:
 
- 			                output = this - that;
 
- 			        }
 
- 			        return asFloat ? output : absFloor(output);
 
- 			    }
 
- 			    function monthDiff(a, b) {
 
- 			        if (a.date() < b.date()) {
 
- 			            // end-of-month calculations work correct when the start month has more
 
- 			            // days than the end month.
 
- 			            return -monthDiff(b, a);
 
- 			        }
 
- 			        // difference in months
 
- 			        var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()),
 
- 			            // b is in (anchor - 1 month, anchor + 1 month)
 
- 			            anchor = a.clone().add(wholeMonthDiff, 'months'),
 
- 			            anchor2,
 
- 			            adjust;
 
- 			        if (b - anchor < 0) {
 
- 			            anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
 
- 			            // linear across the month
 
- 			            adjust = (b - anchor) / (anchor - anchor2);
 
- 			        } else {
 
- 			            anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
 
- 			            // linear across the month
 
- 			            adjust = (b - anchor) / (anchor2 - anchor);
 
- 			        }
 
- 			        //check for negative zero, return zero if negative zero
 
- 			        return -(wholeMonthDiff + adjust) || 0;
 
- 			    }
 
- 			    hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
 
- 			    hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
 
- 			    function toString() {
 
- 			        return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
 
- 			    }
 
- 			    function toISOString(keepOffset) {
 
- 			        if (!this.isValid()) {
 
- 			            return null;
 
- 			        }
 
- 			        var utc = keepOffset !== true,
 
- 			            m = utc ? this.clone().utc() : this;
 
- 			        if (m.year() < 0 || m.year() > 9999) {
 
- 			            return formatMoment(
 
- 			                m,
 
- 			                utc
 
- 			                    ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'
 
- 			                    : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ'
 
- 			            );
 
- 			        }
 
- 			        if (isFunction(Date.prototype.toISOString)) {
 
- 			            // native implementation is ~50x faster, use it when we can
 
- 			            if (utc) {
 
- 			                return this.toDate().toISOString();
 
- 			            } else {
 
- 			                return new Date(this.valueOf() + this.utcOffset() * 60 * 1000)
 
- 			                    .toISOString()
 
- 			                    .replace('Z', formatMoment(m, 'Z'));
 
- 			            }
 
- 			        }
 
- 			        return formatMoment(
 
- 			            m,
 
- 			            utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ'
 
- 			        );
 
- 			    }
 
- 			    /**
 
- 			     * Return a human readable representation of a moment that can
 
- 			     * also be evaluated to get a new moment which is the same
 
- 			     *
 
- 			     * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
 
- 			     */
 
- 			    function inspect() {
 
- 			        if (!this.isValid()) {
 
- 			            return 'moment.invalid(/* ' + this._i + ' */)';
 
- 			        }
 
- 			        var func = 'moment',
 
- 			            zone = '',
 
- 			            prefix,
 
- 			            year,
 
- 			            datetime,
 
- 			            suffix;
 
- 			        if (!this.isLocal()) {
 
- 			            func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
 
- 			            zone = 'Z';
 
- 			        }
 
- 			        prefix = '[' + func + '("]';
 
- 			        year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
 
- 			        datetime = '-MM-DD[T]HH:mm:ss.SSS';
 
- 			        suffix = zone + '[")]';
 
- 			        return this.format(prefix + year + datetime + suffix);
 
- 			    }
 
- 			    function format(inputString) {
 
- 			        if (!inputString) {
 
- 			            inputString = this.isUtc()
 
- 			                ? hooks.defaultFormatUtc
 
- 			                : hooks.defaultFormat;
 
- 			        }
 
- 			        var output = formatMoment(this, inputString);
 
- 			        return this.localeData().postformat(output);
 
- 			    }
 
- 			    function from(time, withoutSuffix) {
 
- 			        if (
 
- 			            this.isValid() &&
 
- 			            ((isMoment(time) && time.isValid()) || createLocal(time).isValid())
 
- 			        ) {
 
- 			            return createDuration({ to: this, from: time })
 
- 			                .locale(this.locale())
 
- 			                .humanize(!withoutSuffix);
 
- 			        } else {
 
- 			            return this.localeData().invalidDate();
 
- 			        }
 
- 			    }
 
- 			    function fromNow(withoutSuffix) {
 
- 			        return this.from(createLocal(), withoutSuffix);
 
- 			    }
 
- 			    function to(time, withoutSuffix) {
 
- 			        if (
 
- 			            this.isValid() &&
 
- 			            ((isMoment(time) && time.isValid()) || createLocal(time).isValid())
 
- 			        ) {
 
- 			            return createDuration({ from: this, to: time })
 
- 			                .locale(this.locale())
 
- 			                .humanize(!withoutSuffix);
 
- 			        } else {
 
- 			            return this.localeData().invalidDate();
 
- 			        }
 
- 			    }
 
- 			    function toNow(withoutSuffix) {
 
- 			        return this.to(createLocal(), withoutSuffix);
 
- 			    }
 
- 			    // If passed a locale key, it will set the locale for this
 
- 			    // instance.  Otherwise, it will return the locale configuration
 
- 			    // variables for this instance.
 
- 			    function locale(key) {
 
- 			        var newLocaleData;
 
- 			        if (key === undefined) {
 
- 			            return this._locale._abbr;
 
- 			        } else {
 
- 			            newLocaleData = getLocale(key);
 
- 			            if (newLocaleData != null) {
 
- 			                this._locale = newLocaleData;
 
- 			            }
 
- 			            return this;
 
- 			        }
 
- 			    }
 
- 			    var lang = deprecate(
 
- 			        'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
 
- 			        function (key) {
 
- 			            if (key === undefined) {
 
- 			                return this.localeData();
 
- 			            } else {
 
- 			                return this.locale(key);
 
- 			            }
 
- 			        }
 
- 			    );
 
- 			    function localeData() {
 
- 			        return this._locale;
 
- 			    }
 
- 			    var MS_PER_SECOND = 1000,
 
- 			        MS_PER_MINUTE = 60 * MS_PER_SECOND,
 
- 			        MS_PER_HOUR = 60 * MS_PER_MINUTE,
 
- 			        MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR;
 
- 			    // actual modulo - handles negative numbers (for dates before 1970):
 
- 			    function mod$1(dividend, divisor) {
 
- 			        return ((dividend % divisor) + divisor) % divisor;
 
- 			    }
 
- 			    function localStartOfDate(y, m, d) {
 
- 			        // the date constructor remaps years 0-99 to 1900-1999
 
- 			        if (y < 100 && y >= 0) {
 
- 			            // preserve leap years using a full 400 year cycle, then reset
 
- 			            return new Date(y + 400, m, d) - MS_PER_400_YEARS;
 
- 			        } else {
 
- 			            return new Date(y, m, d).valueOf();
 
- 			        }
 
- 			    }
 
- 			    function utcStartOfDate(y, m, d) {
 
- 			        // Date.UTC remaps years 0-99 to 1900-1999
 
- 			        if (y < 100 && y >= 0) {
 
- 			            // preserve leap years using a full 400 year cycle, then reset
 
- 			            return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
 
- 			        } else {
 
- 			            return Date.UTC(y, m, d);
 
- 			        }
 
- 			    }
 
- 			    function startOf(units) {
 
- 			        var time, startOfDate;
 
- 			        units = normalizeUnits(units);
 
- 			        if (units === undefined || units === 'millisecond' || !this.isValid()) {
 
- 			            return this;
 
- 			        }
 
- 			        startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
 
- 			        switch (units) {
 
- 			            case 'year':
 
- 			                time = startOfDate(this.year(), 0, 1);
 
- 			                break;
 
- 			            case 'quarter':
 
- 			                time = startOfDate(
 
- 			                    this.year(),
 
- 			                    this.month() - (this.month() % 3),
 
- 			                    1
 
- 			                );
 
- 			                break;
 
- 			            case 'month':
 
- 			                time = startOfDate(this.year(), this.month(), 1);
 
- 			                break;
 
- 			            case 'week':
 
- 			                time = startOfDate(
 
- 			                    this.year(),
 
- 			                    this.month(),
 
- 			                    this.date() - this.weekday()
 
- 			                );
 
- 			                break;
 
- 			            case 'isoWeek':
 
- 			                time = startOfDate(
 
- 			                    this.year(),
 
- 			                    this.month(),
 
- 			                    this.date() - (this.isoWeekday() - 1)
 
- 			                );
 
- 			                break;
 
- 			            case 'day':
 
- 			            case 'date':
 
- 			                time = startOfDate(this.year(), this.month(), this.date());
 
- 			                break;
 
- 			            case 'hour':
 
- 			                time = this._d.valueOf();
 
- 			                time -= mod$1(
 
- 			                    time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
 
- 			                    MS_PER_HOUR
 
- 			                );
 
- 			                break;
 
- 			            case 'minute':
 
- 			                time = this._d.valueOf();
 
- 			                time -= mod$1(time, MS_PER_MINUTE);
 
- 			                break;
 
- 			            case 'second':
 
- 			                time = this._d.valueOf();
 
- 			                time -= mod$1(time, MS_PER_SECOND);
 
- 			                break;
 
- 			        }
 
- 			        this._d.setTime(time);
 
- 			        hooks.updateOffset(this, true);
 
- 			        return this;
 
- 			    }
 
- 			    function endOf(units) {
 
- 			        var time, startOfDate;
 
- 			        units = normalizeUnits(units);
 
- 			        if (units === undefined || units === 'millisecond' || !this.isValid()) {
 
- 			            return this;
 
- 			        }
 
- 			        startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
 
- 			        switch (units) {
 
- 			            case 'year':
 
- 			                time = startOfDate(this.year() + 1, 0, 1) - 1;
 
- 			                break;
 
- 			            case 'quarter':
 
- 			                time =
 
- 			                    startOfDate(
 
- 			                        this.year(),
 
- 			                        this.month() - (this.month() % 3) + 3,
 
- 			                        1
 
- 			                    ) - 1;
 
- 			                break;
 
- 			            case 'month':
 
- 			                time = startOfDate(this.year(), this.month() + 1, 1) - 1;
 
- 			                break;
 
- 			            case 'week':
 
- 			                time =
 
- 			                    startOfDate(
 
- 			                        this.year(),
 
- 			                        this.month(),
 
- 			                        this.date() - this.weekday() + 7
 
- 			                    ) - 1;
 
- 			                break;
 
- 			            case 'isoWeek':
 
- 			                time =
 
- 			                    startOfDate(
 
- 			                        this.year(),
 
- 			                        this.month(),
 
- 			                        this.date() - (this.isoWeekday() - 1) + 7
 
- 			                    ) - 1;
 
- 			                break;
 
- 			            case 'day':
 
- 			            case 'date':
 
- 			                time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
 
- 			                break;
 
- 			            case 'hour':
 
- 			                time = this._d.valueOf();
 
- 			                time +=
 
- 			                    MS_PER_HOUR -
 
- 			                    mod$1(
 
- 			                        time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
 
- 			                        MS_PER_HOUR
 
- 			                    ) -
 
- 			                    1;
 
- 			                break;
 
- 			            case 'minute':
 
- 			                time = this._d.valueOf();
 
- 			                time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
 
- 			                break;
 
- 			            case 'second':
 
- 			                time = this._d.valueOf();
 
- 			                time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
 
- 			                break;
 
- 			        }
 
- 			        this._d.setTime(time);
 
- 			        hooks.updateOffset(this, true);
 
- 			        return this;
 
- 			    }
 
- 			    function valueOf() {
 
- 			        return this._d.valueOf() - (this._offset || 0) * 60000;
 
- 			    }
 
- 			    function unix() {
 
- 			        return Math.floor(this.valueOf() / 1000);
 
- 			    }
 
- 			    function toDate() {
 
- 			        return new Date(this.valueOf());
 
- 			    }
 
- 			    function toArray() {
 
- 			        var m = this;
 
- 			        return [
 
- 			            m.year(),
 
- 			            m.month(),
 
- 			            m.date(),
 
- 			            m.hour(),
 
- 			            m.minute(),
 
- 			            m.second(),
 
- 			            m.millisecond(),
 
- 			        ];
 
- 			    }
 
- 			    function toObject() {
 
- 			        var m = this;
 
- 			        return {
 
- 			            years: m.year(),
 
- 			            months: m.month(),
 
- 			            date: m.date(),
 
- 			            hours: m.hours(),
 
- 			            minutes: m.minutes(),
 
- 			            seconds: m.seconds(),
 
- 			            milliseconds: m.milliseconds(),
 
- 			        };
 
- 			    }
 
- 			    function toJSON() {
 
- 			        // new Date(NaN).toJSON() === null
 
- 			        return this.isValid() ? this.toISOString() : null;
 
- 			    }
 
- 			    function isValid$2() {
 
- 			        return isValid(this);
 
- 			    }
 
- 			    function parsingFlags() {
 
- 			        return extend({}, getParsingFlags(this));
 
- 			    }
 
- 			    function invalidAt() {
 
- 			        return getParsingFlags(this).overflow;
 
- 			    }
 
- 			    function creationData() {
 
- 			        return {
 
- 			            input: this._i,
 
- 			            format: this._f,
 
- 			            locale: this._locale,
 
- 			            isUTC: this._isUTC,
 
- 			            strict: this._strict,
 
- 			        };
 
- 			    }
 
- 			    addFormatToken('N', 0, 0, 'eraAbbr');
 
- 			    addFormatToken('NN', 0, 0, 'eraAbbr');
 
- 			    addFormatToken('NNN', 0, 0, 'eraAbbr');
 
- 			    addFormatToken('NNNN', 0, 0, 'eraName');
 
- 			    addFormatToken('NNNNN', 0, 0, 'eraNarrow');
 
- 			    addFormatToken('y', ['y', 1], 'yo', 'eraYear');
 
- 			    addFormatToken('y', ['yy', 2], 0, 'eraYear');
 
- 			    addFormatToken('y', ['yyy', 3], 0, 'eraYear');
 
- 			    addFormatToken('y', ['yyyy', 4], 0, 'eraYear');
 
- 			    addRegexToken('N', matchEraAbbr);
 
- 			    addRegexToken('NN', matchEraAbbr);
 
- 			    addRegexToken('NNN', matchEraAbbr);
 
- 			    addRegexToken('NNNN', matchEraName);
 
- 			    addRegexToken('NNNNN', matchEraNarrow);
 
- 			    addParseToken(
 
- 			        ['N', 'NN', 'NNN', 'NNNN', 'NNNNN'],
 
- 			        function (input, array, config, token) {
 
- 			            var era = config._locale.erasParse(input, token, config._strict);
 
- 			            if (era) {
 
- 			                getParsingFlags(config).era = era;
 
- 			            } else {
 
- 			                getParsingFlags(config).invalidEra = input;
 
- 			            }
 
- 			        }
 
- 			    );
 
- 			    addRegexToken('y', matchUnsigned);
 
- 			    addRegexToken('yy', matchUnsigned);
 
- 			    addRegexToken('yyy', matchUnsigned);
 
- 			    addRegexToken('yyyy', matchUnsigned);
 
- 			    addRegexToken('yo', matchEraYearOrdinal);
 
- 			    addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR);
 
- 			    addParseToken(['yo'], function (input, array, config, token) {
 
- 			        var match;
 
- 			        if (config._locale._eraYearOrdinalRegex) {
 
- 			            match = input.match(config._locale._eraYearOrdinalRegex);
 
- 			        }
 
- 			        if (config._locale.eraYearOrdinalParse) {
 
- 			            array[YEAR] = config._locale.eraYearOrdinalParse(input, match);
 
- 			        } else {
 
- 			            array[YEAR] = parseInt(input, 10);
 
- 			        }
 
- 			    });
 
- 			    function localeEras(m, format) {
 
- 			        var i,
 
- 			            l,
 
- 			            date,
 
- 			            eras = this._eras || getLocale('en')._eras;
 
- 			        for (i = 0, l = eras.length; i < l; ++i) {
 
- 			            switch (typeof eras[i].since) {
 
- 			                case 'string':
 
- 			                    // truncate time
 
- 			                    date = hooks(eras[i].since).startOf('day');
 
- 			                    eras[i].since = date.valueOf();
 
- 			                    break;
 
- 			            }
 
- 			            switch (typeof eras[i].until) {
 
- 			                case 'undefined':
 
- 			                    eras[i].until = +Infinity;
 
- 			                    break;
 
- 			                case 'string':
 
- 			                    // truncate time
 
- 			                    date = hooks(eras[i].until).startOf('day').valueOf();
 
- 			                    eras[i].until = date.valueOf();
 
- 			                    break;
 
- 			            }
 
- 			        }
 
- 			        return eras;
 
- 			    }
 
- 			    function localeErasParse(eraName, format, strict) {
 
- 			        var i,
 
- 			            l,
 
- 			            eras = this.eras(),
 
- 			            name,
 
- 			            abbr,
 
- 			            narrow;
 
- 			        eraName = eraName.toUpperCase();
 
- 			        for (i = 0, l = eras.length; i < l; ++i) {
 
- 			            name = eras[i].name.toUpperCase();
 
- 			            abbr = eras[i].abbr.toUpperCase();
 
- 			            narrow = eras[i].narrow.toUpperCase();
 
- 			            if (strict) {
 
- 			                switch (format) {
 
- 			                    case 'N':
 
- 			                    case 'NN':
 
- 			                    case 'NNN':
 
- 			                        if (abbr === eraName) {
 
- 			                            return eras[i];
 
- 			                        }
 
- 			                        break;
 
- 			                    case 'NNNN':
 
- 			                        if (name === eraName) {
 
- 			                            return eras[i];
 
- 			                        }
 
- 			                        break;
 
- 			                    case 'NNNNN':
 
- 			                        if (narrow === eraName) {
 
- 			                            return eras[i];
 
- 			                        }
 
- 			                        break;
 
- 			                }
 
- 			            } else if ([name, abbr, narrow].indexOf(eraName) >= 0) {
 
- 			                return eras[i];
 
- 			            }
 
- 			        }
 
- 			    }
 
- 			    function localeErasConvertYear(era, year) {
 
- 			        var dir = era.since <= era.until ? +1 : -1;
 
- 			        if (year === undefined) {
 
- 			            return hooks(era.since).year();
 
- 			        } else {
 
- 			            return hooks(era.since).year() + (year - era.offset) * dir;
 
- 			        }
 
- 			    }
 
- 			    function getEraName() {
 
- 			        var i,
 
- 			            l,
 
- 			            val,
 
- 			            eras = this.localeData().eras();
 
- 			        for (i = 0, l = eras.length; i < l; ++i) {
 
- 			            // truncate time
 
- 			            val = this.clone().startOf('day').valueOf();
 
- 			            if (eras[i].since <= val && val <= eras[i].until) {
 
- 			                return eras[i].name;
 
- 			            }
 
- 			            if (eras[i].until <= val && val <= eras[i].since) {
 
- 			                return eras[i].name;
 
- 			            }
 
- 			        }
 
- 			        return '';
 
- 			    }
 
- 			    function getEraNarrow() {
 
- 			        var i,
 
- 			            l,
 
- 			            val,
 
- 			            eras = this.localeData().eras();
 
- 			        for (i = 0, l = eras.length; i < l; ++i) {
 
- 			            // truncate time
 
- 			            val = this.clone().startOf('day').valueOf();
 
- 			            if (eras[i].since <= val && val <= eras[i].until) {
 
- 			                return eras[i].narrow;
 
- 			            }
 
- 			            if (eras[i].until <= val && val <= eras[i].since) {
 
- 			                return eras[i].narrow;
 
- 			            }
 
- 			        }
 
- 			        return '';
 
- 			    }
 
- 			    function getEraAbbr() {
 
- 			        var i,
 
- 			            l,
 
- 			            val,
 
- 			            eras = this.localeData().eras();
 
- 			        for (i = 0, l = eras.length; i < l; ++i) {
 
- 			            // truncate time
 
- 			            val = this.clone().startOf('day').valueOf();
 
- 			            if (eras[i].since <= val && val <= eras[i].until) {
 
- 			                return eras[i].abbr;
 
- 			            }
 
- 			            if (eras[i].until <= val && val <= eras[i].since) {
 
- 			                return eras[i].abbr;
 
- 			            }
 
- 			        }
 
- 			        return '';
 
- 			    }
 
- 			    function getEraYear() {
 
- 			        var i,
 
- 			            l,
 
- 			            dir,
 
- 			            val,
 
- 			            eras = this.localeData().eras();
 
- 			        for (i = 0, l = eras.length; i < l; ++i) {
 
- 			            dir = eras[i].since <= eras[i].until ? +1 : -1;
 
- 			            // truncate time
 
- 			            val = this.clone().startOf('day').valueOf();
 
- 			            if (
 
- 			                (eras[i].since <= val && val <= eras[i].until) ||
 
- 			                (eras[i].until <= val && val <= eras[i].since)
 
- 			            ) {
 
- 			                return (
 
- 			                    (this.year() - hooks(eras[i].since).year()) * dir +
 
- 			                    eras[i].offset
 
- 			                );
 
- 			            }
 
- 			        }
 
- 			        return this.year();
 
- 			    }
 
- 			    function erasNameRegex(isStrict) {
 
- 			        if (!hasOwnProp(this, '_erasNameRegex')) {
 
- 			            computeErasParse.call(this);
 
- 			        }
 
- 			        return isStrict ? this._erasNameRegex : this._erasRegex;
 
- 			    }
 
- 			    function erasAbbrRegex(isStrict) {
 
- 			        if (!hasOwnProp(this, '_erasAbbrRegex')) {
 
- 			            computeErasParse.call(this);
 
- 			        }
 
- 			        return isStrict ? this._erasAbbrRegex : this._erasRegex;
 
- 			    }
 
- 			    function erasNarrowRegex(isStrict) {
 
- 			        if (!hasOwnProp(this, '_erasNarrowRegex')) {
 
- 			            computeErasParse.call(this);
 
- 			        }
 
- 			        return isStrict ? this._erasNarrowRegex : this._erasRegex;
 
- 			    }
 
- 			    function matchEraAbbr(isStrict, locale) {
 
- 			        return locale.erasAbbrRegex(isStrict);
 
- 			    }
 
- 			    function matchEraName(isStrict, locale) {
 
- 			        return locale.erasNameRegex(isStrict);
 
- 			    }
 
- 			    function matchEraNarrow(isStrict, locale) {
 
- 			        return locale.erasNarrowRegex(isStrict);
 
- 			    }
 
- 			    function matchEraYearOrdinal(isStrict, locale) {
 
- 			        return locale._eraYearOrdinalRegex || matchUnsigned;
 
- 			    }
 
- 			    function computeErasParse() {
 
- 			        var abbrPieces = [],
 
- 			            namePieces = [],
 
- 			            narrowPieces = [],
 
- 			            mixedPieces = [],
 
- 			            i,
 
- 			            l,
 
- 			            eras = this.eras();
 
- 			        for (i = 0, l = eras.length; i < l; ++i) {
 
- 			            namePieces.push(regexEscape(eras[i].name));
 
- 			            abbrPieces.push(regexEscape(eras[i].abbr));
 
- 			            narrowPieces.push(regexEscape(eras[i].narrow));
 
- 			            mixedPieces.push(regexEscape(eras[i].name));
 
- 			            mixedPieces.push(regexEscape(eras[i].abbr));
 
- 			            mixedPieces.push(regexEscape(eras[i].narrow));
 
- 			        }
 
- 			        this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
 
- 			        this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i');
 
- 			        this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i');
 
- 			        this._erasNarrowRegex = new RegExp(
 
- 			            '^(' + narrowPieces.join('|') + ')',
 
- 			            'i'
 
- 			        );
 
- 			    }
 
- 			    // FORMATTING
 
- 			    addFormatToken(0, ['gg', 2], 0, function () {
 
- 			        return this.weekYear() % 100;
 
- 			    });
 
- 			    addFormatToken(0, ['GG', 2], 0, function () {
 
- 			        return this.isoWeekYear() % 100;
 
- 			    });
 
- 			    function addWeekYearFormatToken(token, getter) {
 
- 			        addFormatToken(0, [token, token.length], 0, getter);
 
- 			    }
 
- 			    addWeekYearFormatToken('gggg', 'weekYear');
 
- 			    addWeekYearFormatToken('ggggg', 'weekYear');
 
- 			    addWeekYearFormatToken('GGGG', 'isoWeekYear');
 
- 			    addWeekYearFormatToken('GGGGG', 'isoWeekYear');
 
- 			    // ALIASES
 
- 			    addUnitAlias('weekYear', 'gg');
 
- 			    addUnitAlias('isoWeekYear', 'GG');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('weekYear', 1);
 
- 			    addUnitPriority('isoWeekYear', 1);
 
- 			    // PARSING
 
- 			    addRegexToken('G', matchSigned);
 
- 			    addRegexToken('g', matchSigned);
 
- 			    addRegexToken('GG', match1to2, match2);
 
- 			    addRegexToken('gg', match1to2, match2);
 
- 			    addRegexToken('GGGG', match1to4, match4);
 
- 			    addRegexToken('gggg', match1to4, match4);
 
- 			    addRegexToken('GGGGG', match1to6, match6);
 
- 			    addRegexToken('ggggg', match1to6, match6);
 
- 			    addWeekParseToken(
 
- 			        ['gggg', 'ggggg', 'GGGG', 'GGGGG'],
 
- 			        function (input, week, config, token) {
 
- 			            week[token.substr(0, 2)] = toInt(input);
 
- 			        }
 
- 			    );
 
- 			    addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
 
- 			        week[token] = hooks.parseTwoDigitYear(input);
 
- 			    });
 
- 			    // MOMENTS
 
- 			    function getSetWeekYear(input) {
 
- 			        return getSetWeekYearHelper.call(
 
- 			            this,
 
- 			            input,
 
- 			            this.week(),
 
- 			            this.weekday(),
 
- 			            this.localeData()._week.dow,
 
- 			            this.localeData()._week.doy
 
- 			        );
 
- 			    }
 
- 			    function getSetISOWeekYear(input) {
 
- 			        return getSetWeekYearHelper.call(
 
- 			            this,
 
- 			            input,
 
- 			            this.isoWeek(),
 
- 			            this.isoWeekday(),
 
- 			            1,
 
- 			            4
 
- 			        );
 
- 			    }
 
- 			    function getISOWeeksInYear() {
 
- 			        return weeksInYear(this.year(), 1, 4);
 
- 			    }
 
- 			    function getISOWeeksInISOWeekYear() {
 
- 			        return weeksInYear(this.isoWeekYear(), 1, 4);
 
- 			    }
 
- 			    function getWeeksInYear() {
 
- 			        var weekInfo = this.localeData()._week;
 
- 			        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
 
- 			    }
 
- 			    function getWeeksInWeekYear() {
 
- 			        var weekInfo = this.localeData()._week;
 
- 			        return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy);
 
- 			    }
 
- 			    function getSetWeekYearHelper(input, week, weekday, dow, doy) {
 
- 			        var weeksTarget;
 
- 			        if (input == null) {
 
- 			            return weekOfYear(this, dow, doy).year;
 
- 			        } else {
 
- 			            weeksTarget = weeksInYear(input, dow, doy);
 
- 			            if (week > weeksTarget) {
 
- 			                week = weeksTarget;
 
- 			            }
 
- 			            return setWeekAll.call(this, input, week, weekday, dow, doy);
 
- 			        }
 
- 			    }
 
- 			    function setWeekAll(weekYear, week, weekday, dow, doy) {
 
- 			        var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
 
- 			            date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
 
- 			        this.year(date.getUTCFullYear());
 
- 			        this.month(date.getUTCMonth());
 
- 			        this.date(date.getUTCDate());
 
- 			        return this;
 
- 			    }
 
- 			    // FORMATTING
 
- 			    addFormatToken('Q', 0, 'Qo', 'quarter');
 
- 			    // ALIASES
 
- 			    addUnitAlias('quarter', 'Q');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('quarter', 7);
 
- 			    // PARSING
 
- 			    addRegexToken('Q', match1);
 
- 			    addParseToken('Q', function (input, array) {
 
- 			        array[MONTH] = (toInt(input) - 1) * 3;
 
- 			    });
 
- 			    // MOMENTS
 
- 			    function getSetQuarter(input) {
 
- 			        return input == null
 
- 			            ? Math.ceil((this.month() + 1) / 3)
 
- 			            : this.month((input - 1) * 3 + (this.month() % 3));
 
- 			    }
 
- 			    // FORMATTING
 
- 			    addFormatToken('D', ['DD', 2], 'Do', 'date');
 
- 			    // ALIASES
 
- 			    addUnitAlias('date', 'D');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('date', 9);
 
- 			    // PARSING
 
- 			    addRegexToken('D', match1to2);
 
- 			    addRegexToken('DD', match1to2, match2);
 
- 			    addRegexToken('Do', function (isStrict, locale) {
 
- 			        // TODO: Remove "ordinalParse" fallback in next major release.
 
- 			        return isStrict
 
- 			            ? locale._dayOfMonthOrdinalParse || locale._ordinalParse
 
- 			            : locale._dayOfMonthOrdinalParseLenient;
 
- 			    });
 
- 			    addParseToken(['D', 'DD'], DATE);
 
- 			    addParseToken('Do', function (input, array) {
 
- 			        array[DATE] = toInt(input.match(match1to2)[0]);
 
- 			    });
 
- 			    // MOMENTS
 
- 			    var getSetDayOfMonth = makeGetSet('Date', true);
 
- 			    // FORMATTING
 
- 			    addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
 
- 			    // ALIASES
 
- 			    addUnitAlias('dayOfYear', 'DDD');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('dayOfYear', 4);
 
- 			    // PARSING
 
- 			    addRegexToken('DDD', match1to3);
 
- 			    addRegexToken('DDDD', match3);
 
- 			    addParseToken(['DDD', 'DDDD'], function (input, array, config) {
 
- 			        config._dayOfYear = toInt(input);
 
- 			    });
 
- 			    // HELPERS
 
- 			    // MOMENTS
 
- 			    function getSetDayOfYear(input) {
 
- 			        var dayOfYear =
 
- 			            Math.round(
 
- 			                (this.clone().startOf('day') - this.clone().startOf('year')) / 864e5
 
- 			            ) + 1;
 
- 			        return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
 
- 			    }
 
- 			    // FORMATTING
 
- 			    addFormatToken('m', ['mm', 2], 0, 'minute');
 
- 			    // ALIASES
 
- 			    addUnitAlias('minute', 'm');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('minute', 14);
 
- 			    // PARSING
 
- 			    addRegexToken('m', match1to2);
 
- 			    addRegexToken('mm', match1to2, match2);
 
- 			    addParseToken(['m', 'mm'], MINUTE);
 
- 			    // MOMENTS
 
- 			    var getSetMinute = makeGetSet('Minutes', false);
 
- 			    // FORMATTING
 
- 			    addFormatToken('s', ['ss', 2], 0, 'second');
 
- 			    // ALIASES
 
- 			    addUnitAlias('second', 's');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('second', 15);
 
- 			    // PARSING
 
- 			    addRegexToken('s', match1to2);
 
- 			    addRegexToken('ss', match1to2, match2);
 
- 			    addParseToken(['s', 'ss'], SECOND);
 
- 			    // MOMENTS
 
- 			    var getSetSecond = makeGetSet('Seconds', false);
 
- 			    // FORMATTING
 
- 			    addFormatToken('S', 0, 0, function () {
 
- 			        return ~~(this.millisecond() / 100);
 
- 			    });
 
- 			    addFormatToken(0, ['SS', 2], 0, function () {
 
- 			        return ~~(this.millisecond() / 10);
 
- 			    });
 
- 			    addFormatToken(0, ['SSS', 3], 0, 'millisecond');
 
- 			    addFormatToken(0, ['SSSS', 4], 0, function () {
 
- 			        return this.millisecond() * 10;
 
- 			    });
 
- 			    addFormatToken(0, ['SSSSS', 5], 0, function () {
 
- 			        return this.millisecond() * 100;
 
- 			    });
 
- 			    addFormatToken(0, ['SSSSSS', 6], 0, function () {
 
- 			        return this.millisecond() * 1000;
 
- 			    });
 
- 			    addFormatToken(0, ['SSSSSSS', 7], 0, function () {
 
- 			        return this.millisecond() * 10000;
 
- 			    });
 
- 			    addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
 
- 			        return this.millisecond() * 100000;
 
- 			    });
 
- 			    addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
 
- 			        return this.millisecond() * 1000000;
 
- 			    });
 
- 			    // ALIASES
 
- 			    addUnitAlias('millisecond', 'ms');
 
- 			    // PRIORITY
 
- 			    addUnitPriority('millisecond', 16);
 
- 			    // PARSING
 
- 			    addRegexToken('S', match1to3, match1);
 
- 			    addRegexToken('SS', match1to3, match2);
 
- 			    addRegexToken('SSS', match1to3, match3);
 
- 			    var token, getSetMillisecond;
 
- 			    for (token = 'SSSS'; token.length <= 9; token += 'S') {
 
- 			        addRegexToken(token, matchUnsigned);
 
- 			    }
 
- 			    function parseMs(input, array) {
 
- 			        array[MILLISECOND] = toInt(('0.' + input) * 1000);
 
- 			    }
 
- 			    for (token = 'S'; token.length <= 9; token += 'S') {
 
- 			        addParseToken(token, parseMs);
 
- 			    }
 
- 			    getSetMillisecond = makeGetSet('Milliseconds', false);
 
- 			    // FORMATTING
 
- 			    addFormatToken('z', 0, 0, 'zoneAbbr');
 
- 			    addFormatToken('zz', 0, 0, 'zoneName');
 
- 			    // MOMENTS
 
- 			    function getZoneAbbr() {
 
- 			        return this._isUTC ? 'UTC' : '';
 
- 			    }
 
- 			    function getZoneName() {
 
- 			        return this._isUTC ? 'Coordinated Universal Time' : '';
 
- 			    }
 
- 			    var proto = Moment.prototype;
 
- 			    proto.add = add;
 
- 			    proto.calendar = calendar$1;
 
- 			    proto.clone = clone;
 
- 			    proto.diff = diff;
 
- 			    proto.endOf = endOf;
 
- 			    proto.format = format;
 
- 			    proto.from = from;
 
- 			    proto.fromNow = fromNow;
 
- 			    proto.to = to;
 
- 			    proto.toNow = toNow;
 
- 			    proto.get = stringGet;
 
- 			    proto.invalidAt = invalidAt;
 
- 			    proto.isAfter = isAfter;
 
- 			    proto.isBefore = isBefore;
 
- 			    proto.isBetween = isBetween;
 
- 			    proto.isSame = isSame;
 
- 			    proto.isSameOrAfter = isSameOrAfter;
 
- 			    proto.isSameOrBefore = isSameOrBefore;
 
- 			    proto.isValid = isValid$2;
 
- 			    proto.lang = lang;
 
- 			    proto.locale = locale;
 
- 			    proto.localeData = localeData;
 
- 			    proto.max = prototypeMax;
 
- 			    proto.min = prototypeMin;
 
- 			    proto.parsingFlags = parsingFlags;
 
- 			    proto.set = stringSet;
 
- 			    proto.startOf = startOf;
 
- 			    proto.subtract = subtract;
 
- 			    proto.toArray = toArray;
 
- 			    proto.toObject = toObject;
 
- 			    proto.toDate = toDate;
 
- 			    proto.toISOString = toISOString;
 
- 			    proto.inspect = inspect;
 
- 			    if (typeof Symbol !== 'undefined' && Symbol.for != null) {
 
- 			        proto[Symbol.for('nodejs.util.inspect.custom')] = function () {
 
- 			            return 'Moment<' + this.format() + '>';
 
- 			        };
 
- 			    }
 
- 			    proto.toJSON = toJSON;
 
- 			    proto.toString = toString;
 
- 			    proto.unix = unix;
 
- 			    proto.valueOf = valueOf;
 
- 			    proto.creationData = creationData;
 
- 			    proto.eraName = getEraName;
 
- 			    proto.eraNarrow = getEraNarrow;
 
- 			    proto.eraAbbr = getEraAbbr;
 
- 			    proto.eraYear = getEraYear;
 
- 			    proto.year = getSetYear;
 
- 			    proto.isLeapYear = getIsLeapYear;
 
- 			    proto.weekYear = getSetWeekYear;
 
- 			    proto.isoWeekYear = getSetISOWeekYear;
 
- 			    proto.quarter = proto.quarters = getSetQuarter;
 
- 			    proto.month = getSetMonth;
 
- 			    proto.daysInMonth = getDaysInMonth;
 
- 			    proto.week = proto.weeks = getSetWeek;
 
- 			    proto.isoWeek = proto.isoWeeks = getSetISOWeek;
 
- 			    proto.weeksInYear = getWeeksInYear;
 
- 			    proto.weeksInWeekYear = getWeeksInWeekYear;
 
- 			    proto.isoWeeksInYear = getISOWeeksInYear;
 
- 			    proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear;
 
- 			    proto.date = getSetDayOfMonth;
 
- 			    proto.day = proto.days = getSetDayOfWeek;
 
- 			    proto.weekday = getSetLocaleDayOfWeek;
 
- 			    proto.isoWeekday = getSetISODayOfWeek;
 
- 			    proto.dayOfYear = getSetDayOfYear;
 
- 			    proto.hour = proto.hours = getSetHour;
 
- 			    proto.minute = proto.minutes = getSetMinute;
 
- 			    proto.second = proto.seconds = getSetSecond;
 
- 			    proto.millisecond = proto.milliseconds = getSetMillisecond;
 
- 			    proto.utcOffset = getSetOffset;
 
- 			    proto.utc = setOffsetToUTC;
 
- 			    proto.local = setOffsetToLocal;
 
- 			    proto.parseZone = setOffsetToParsedOffset;
 
- 			    proto.hasAlignedHourOffset = hasAlignedHourOffset;
 
- 			    proto.isDST = isDaylightSavingTime;
 
- 			    proto.isLocal = isLocal;
 
- 			    proto.isUtcOffset = isUtcOffset;
 
- 			    proto.isUtc = isUtc;
 
- 			    proto.isUTC = isUtc;
 
- 			    proto.zoneAbbr = getZoneAbbr;
 
- 			    proto.zoneName = getZoneName;
 
- 			    proto.dates = deprecate(
 
- 			        'dates accessor is deprecated. Use date instead.',
 
- 			        getSetDayOfMonth
 
- 			    );
 
- 			    proto.months = deprecate(
 
- 			        'months accessor is deprecated. Use month instead',
 
- 			        getSetMonth
 
- 			    );
 
- 			    proto.years = deprecate(
 
- 			        'years accessor is deprecated. Use year instead',
 
- 			        getSetYear
 
- 			    );
 
- 			    proto.zone = deprecate(
 
- 			        'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/',
 
- 			        getSetZone
 
- 			    );
 
- 			    proto.isDSTShifted = deprecate(
 
- 			        'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information',
 
- 			        isDaylightSavingTimeShifted
 
- 			    );
 
- 			    function createUnix(input) {
 
- 			        return createLocal(input * 1000);
 
- 			    }
 
- 			    function createInZone() {
 
- 			        return createLocal.apply(null, arguments).parseZone();
 
- 			    }
 
- 			    function preParsePostFormat(string) {
 
- 			        return string;
 
- 			    }
 
- 			    var proto$1 = Locale.prototype;
 
- 			    proto$1.calendar = calendar;
 
- 			    proto$1.longDateFormat = longDateFormat;
 
- 			    proto$1.invalidDate = invalidDate;
 
- 			    proto$1.ordinal = ordinal;
 
- 			    proto$1.preparse = preParsePostFormat;
 
- 			    proto$1.postformat = preParsePostFormat;
 
- 			    proto$1.relativeTime = relativeTime;
 
- 			    proto$1.pastFuture = pastFuture;
 
- 			    proto$1.set = set;
 
- 			    proto$1.eras = localeEras;
 
- 			    proto$1.erasParse = localeErasParse;
 
- 			    proto$1.erasConvertYear = localeErasConvertYear;
 
- 			    proto$1.erasAbbrRegex = erasAbbrRegex;
 
- 			    proto$1.erasNameRegex = erasNameRegex;
 
- 			    proto$1.erasNarrowRegex = erasNarrowRegex;
 
- 			    proto$1.months = localeMonths;
 
- 			    proto$1.monthsShort = localeMonthsShort;
 
- 			    proto$1.monthsParse = localeMonthsParse;
 
- 			    proto$1.monthsRegex = monthsRegex;
 
- 			    proto$1.monthsShortRegex = monthsShortRegex;
 
- 			    proto$1.week = localeWeek;
 
- 			    proto$1.firstDayOfYear = localeFirstDayOfYear;
 
- 			    proto$1.firstDayOfWeek = localeFirstDayOfWeek;
 
- 			    proto$1.weekdays = localeWeekdays;
 
- 			    proto$1.weekdaysMin = localeWeekdaysMin;
 
- 			    proto$1.weekdaysShort = localeWeekdaysShort;
 
- 			    proto$1.weekdaysParse = localeWeekdaysParse;
 
- 			    proto$1.weekdaysRegex = weekdaysRegex;
 
- 			    proto$1.weekdaysShortRegex = weekdaysShortRegex;
 
- 			    proto$1.weekdaysMinRegex = weekdaysMinRegex;
 
- 			    proto$1.isPM = localeIsPM;
 
- 			    proto$1.meridiem = localeMeridiem;
 
- 			    function get$1(format, index, field, setter) {
 
- 			        var locale = getLocale(),
 
- 			            utc = createUTC().set(setter, index);
 
- 			        return locale[field](utc, format);
 
- 			    }
 
- 			    function listMonthsImpl(format, index, field) {
 
- 			        if (isNumber(format)) {
 
- 			            index = format;
 
- 			            format = undefined;
 
- 			        }
 
- 			        format = format || '';
 
- 			        if (index != null) {
 
- 			            return get$1(format, index, field, 'month');
 
- 			        }
 
- 			        var i,
 
- 			            out = [];
 
- 			        for (i = 0; i < 12; i++) {
 
- 			            out[i] = get$1(format, i, field, 'month');
 
- 			        }
 
- 			        return out;
 
- 			    }
 
- 			    // ()
 
- 			    // (5)
 
- 			    // (fmt, 5)
 
- 			    // (fmt)
 
- 			    // (true)
 
- 			    // (true, 5)
 
- 			    // (true, fmt, 5)
 
- 			    // (true, fmt)
 
- 			    function listWeekdaysImpl(localeSorted, format, index, field) {
 
- 			        if (typeof localeSorted === 'boolean') {
 
- 			            if (isNumber(format)) {
 
- 			                index = format;
 
- 			                format = undefined;
 
- 			            }
 
- 			            format = format || '';
 
- 			        } else {
 
- 			            format = localeSorted;
 
- 			            index = format;
 
- 			            localeSorted = false;
 
- 			            if (isNumber(format)) {
 
- 			                index = format;
 
- 			                format = undefined;
 
- 			            }
 
- 			            format = format || '';
 
- 			        }
 
- 			        var locale = getLocale(),
 
- 			            shift = localeSorted ? locale._week.dow : 0,
 
- 			            i,
 
- 			            out = [];
 
- 			        if (index != null) {
 
- 			            return get$1(format, (index + shift) % 7, field, 'day');
 
- 			        }
 
- 			        for (i = 0; i < 7; i++) {
 
- 			            out[i] = get$1(format, (i + shift) % 7, field, 'day');
 
- 			        }
 
- 			        return out;
 
- 			    }
 
- 			    function listMonths(format, index) {
 
- 			        return listMonthsImpl(format, index, 'months');
 
- 			    }
 
- 			    function listMonthsShort(format, index) {
 
- 			        return listMonthsImpl(format, index, 'monthsShort');
 
- 			    }
 
- 			    function listWeekdays(localeSorted, format, index) {
 
- 			        return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
 
- 			    }
 
- 			    function listWeekdaysShort(localeSorted, format, index) {
 
- 			        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
 
- 			    }
 
- 			    function listWeekdaysMin(localeSorted, format, index) {
 
- 			        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
 
- 			    }
 
- 			    getSetGlobalLocale('en', {
 
- 			        eras: [
 
- 			            {
 
- 			                since: '0001-01-01',
 
- 			                until: +Infinity,
 
- 			                offset: 1,
 
- 			                name: 'Anno Domini',
 
- 			                narrow: 'AD',
 
- 			                abbr: 'AD',
 
- 			            },
 
- 			            {
 
- 			                since: '0000-12-31',
 
- 			                until: -Infinity,
 
- 			                offset: 1,
 
- 			                name: 'Before Christ',
 
- 			                narrow: 'BC',
 
- 			                abbr: 'BC',
 
- 			            },
 
- 			        ],
 
- 			        dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
 
- 			        ordinal: function (number) {
 
- 			            var b = number % 10,
 
- 			                output =
 
- 			                    toInt((number % 100) / 10) === 1
 
- 			                        ? 'th'
 
- 			                        : b === 1
 
- 			                        ? 'st'
 
- 			                        : b === 2
 
- 			                        ? 'nd'
 
- 			                        : b === 3
 
- 			                        ? 'rd'
 
- 			                        : 'th';
 
- 			            return number + output;
 
- 			        },
 
- 			    });
 
- 			    // Side effect imports
 
- 			    hooks.lang = deprecate(
 
- 			        'moment.lang is deprecated. Use moment.locale instead.',
 
- 			        getSetGlobalLocale
 
- 			    );
 
- 			    hooks.langData = deprecate(
 
- 			        'moment.langData is deprecated. Use moment.localeData instead.',
 
- 			        getLocale
 
- 			    );
 
- 			    var mathAbs = Math.abs;
 
- 			    function abs() {
 
- 			        var data = this._data;
 
- 			        this._milliseconds = mathAbs(this._milliseconds);
 
- 			        this._days = mathAbs(this._days);
 
- 			        this._months = mathAbs(this._months);
 
- 			        data.milliseconds = mathAbs(data.milliseconds);
 
- 			        data.seconds = mathAbs(data.seconds);
 
- 			        data.minutes = mathAbs(data.minutes);
 
- 			        data.hours = mathAbs(data.hours);
 
- 			        data.months = mathAbs(data.months);
 
- 			        data.years = mathAbs(data.years);
 
- 			        return this;
 
- 			    }
 
- 			    function addSubtract$1(duration, input, value, direction) {
 
- 			        var other = createDuration(input, value);
 
- 			        duration._milliseconds += direction * other._milliseconds;
 
- 			        duration._days += direction * other._days;
 
- 			        duration._months += direction * other._months;
 
- 			        return duration._bubble();
 
- 			    }
 
- 			    // supports only 2.0-style add(1, 's') or add(duration)
 
- 			    function add$1(input, value) {
 
- 			        return addSubtract$1(this, input, value, 1);
 
- 			    }
 
- 			    // supports only 2.0-style subtract(1, 's') or subtract(duration)
 
- 			    function subtract$1(input, value) {
 
- 			        return addSubtract$1(this, input, value, -1);
 
- 			    }
 
- 			    function absCeil(number) {
 
- 			        if (number < 0) {
 
- 			            return Math.floor(number);
 
- 			        } else {
 
- 			            return Math.ceil(number);
 
- 			        }
 
- 			    }
 
- 			    function bubble() {
 
- 			        var milliseconds = this._milliseconds,
 
- 			            days = this._days,
 
- 			            months = this._months,
 
- 			            data = this._data,
 
- 			            seconds,
 
- 			            minutes,
 
- 			            hours,
 
- 			            years,
 
- 			            monthsFromDays;
 
- 			        // if we have a mix of positive and negative values, bubble down first
 
- 			        // check: https://github.com/moment/moment/issues/2166
 
- 			        if (
 
- 			            !(
 
- 			                (milliseconds >= 0 && days >= 0 && months >= 0) ||
 
- 			                (milliseconds <= 0 && days <= 0 && months <= 0)
 
- 			            )
 
- 			        ) {
 
- 			            milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
 
- 			            days = 0;
 
- 			            months = 0;
 
- 			        }
 
- 			        // The following code bubbles up values, see the tests for
 
- 			        // examples of what that means.
 
- 			        data.milliseconds = milliseconds % 1000;
 
- 			        seconds = absFloor(milliseconds / 1000);
 
- 			        data.seconds = seconds % 60;
 
- 			        minutes = absFloor(seconds / 60);
 
- 			        data.minutes = minutes % 60;
 
- 			        hours = absFloor(minutes / 60);
 
- 			        data.hours = hours % 24;
 
- 			        days += absFloor(hours / 24);
 
- 			        // convert days to months
 
- 			        monthsFromDays = absFloor(daysToMonths(days));
 
- 			        months += monthsFromDays;
 
- 			        days -= absCeil(monthsToDays(monthsFromDays));
 
- 			        // 12 months -> 1 year
 
- 			        years = absFloor(months / 12);
 
- 			        months %= 12;
 
- 			        data.days = days;
 
- 			        data.months = months;
 
- 			        data.years = years;
 
- 			        return this;
 
- 			    }
 
- 			    function daysToMonths(days) {
 
- 			        // 400 years have 146097 days (taking into account leap year rules)
 
- 			        // 400 years have 12 months === 4800
 
- 			        return (days * 4800) / 146097;
 
- 			    }
 
- 			    function monthsToDays(months) {
 
- 			        // the reverse of daysToMonths
 
- 			        return (months * 146097) / 4800;
 
- 			    }
 
- 			    function as(units) {
 
- 			        if (!this.isValid()) {
 
- 			            return NaN;
 
- 			        }
 
- 			        var days,
 
- 			            months,
 
- 			            milliseconds = this._milliseconds;
 
- 			        units = normalizeUnits(units);
 
- 			        if (units === 'month' || units === 'quarter' || units === 'year') {
 
- 			            days = this._days + milliseconds / 864e5;
 
- 			            months = this._months + daysToMonths(days);
 
- 			            switch (units) {
 
- 			                case 'month':
 
- 			                    return months;
 
- 			                case 'quarter':
 
- 			                    return months / 3;
 
- 			                case 'year':
 
- 			                    return months / 12;
 
- 			            }
 
- 			        } else {
 
- 			            // handle milliseconds separately because of floating point math errors (issue #1867)
 
- 			            days = this._days + Math.round(monthsToDays(this._months));
 
- 			            switch (units) {
 
- 			                case 'week':
 
- 			                    return days / 7 + milliseconds / 6048e5;
 
- 			                case 'day':
 
- 			                    return days + milliseconds / 864e5;
 
- 			                case 'hour':
 
- 			                    return days * 24 + milliseconds / 36e5;
 
- 			                case 'minute':
 
- 			                    return days * 1440 + milliseconds / 6e4;
 
- 			                case 'second':
 
- 			                    return days * 86400 + milliseconds / 1000;
 
- 			                // Math.floor prevents floating point math errors here
 
- 			                case 'millisecond':
 
- 			                    return Math.floor(days * 864e5) + milliseconds;
 
- 			                default:
 
- 			                    throw new Error('Unknown unit ' + units);
 
- 			            }
 
- 			        }
 
- 			    }
 
- 			    // TODO: Use this.as('ms')?
 
- 			    function valueOf$1() {
 
- 			        if (!this.isValid()) {
 
- 			            return NaN;
 
- 			        }
 
- 			        return (
 
- 			            this._milliseconds +
 
- 			            this._days * 864e5 +
 
- 			            (this._months % 12) * 2592e6 +
 
- 			            toInt(this._months / 12) * 31536e6
 
- 			        );
 
- 			    }
 
- 			    function makeAs(alias) {
 
- 			        return function () {
 
- 			            return this.as(alias);
 
- 			        };
 
- 			    }
 
- 			    var asMilliseconds = makeAs('ms'),
 
- 			        asSeconds = makeAs('s'),
 
- 			        asMinutes = makeAs('m'),
 
- 			        asHours = makeAs('h'),
 
- 			        asDays = makeAs('d'),
 
- 			        asWeeks = makeAs('w'),
 
- 			        asMonths = makeAs('M'),
 
- 			        asQuarters = makeAs('Q'),
 
- 			        asYears = makeAs('y');
 
- 			    function clone$1() {
 
- 			        return createDuration(this);
 
- 			    }
 
- 			    function get$2(units) {
 
- 			        units = normalizeUnits(units);
 
- 			        return this.isValid() ? this[units + 's']() : NaN;
 
- 			    }
 
- 			    function makeGetter(name) {
 
- 			        return function () {
 
- 			            return this.isValid() ? this._data[name] : NaN;
 
- 			        };
 
- 			    }
 
- 			    var milliseconds = makeGetter('milliseconds'),
 
- 			        seconds = makeGetter('seconds'),
 
- 			        minutes = makeGetter('minutes'),
 
- 			        hours = makeGetter('hours'),
 
- 			        days = makeGetter('days'),
 
- 			        months = makeGetter('months'),
 
- 			        years = makeGetter('years');
 
- 			    function weeks() {
 
- 			        return absFloor(this.days() / 7);
 
- 			    }
 
- 			    var round = Math.round,
 
- 			        thresholds = {
 
- 			            ss: 44, // a few seconds to seconds
 
- 			            s: 45, // seconds to minute
 
- 			            m: 45, // minutes to hour
 
- 			            h: 22, // hours to day
 
- 			            d: 26, // days to month/week
 
- 			            w: null, // weeks to month
 
- 			            M: 11, // months to year
 
- 			        };
 
- 			    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
 
- 			    function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
 
- 			        return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
 
- 			    }
 
- 			    function relativeTime$1(posNegDuration, withoutSuffix, thresholds, locale) {
 
- 			        var duration = createDuration(posNegDuration).abs(),
 
- 			            seconds = round(duration.as('s')),
 
- 			            minutes = round(duration.as('m')),
 
- 			            hours = round(duration.as('h')),
 
- 			            days = round(duration.as('d')),
 
- 			            months = round(duration.as('M')),
 
- 			            weeks = round(duration.as('w')),
 
- 			            years = round(duration.as('y')),
 
- 			            a =
 
- 			                (seconds <= thresholds.ss && ['s', seconds]) ||
 
- 			                (seconds < thresholds.s && ['ss', seconds]) ||
 
- 			                (minutes <= 1 && ['m']) ||
 
- 			                (minutes < thresholds.m && ['mm', minutes]) ||
 
- 			                (hours <= 1 && ['h']) ||
 
- 			                (hours < thresholds.h && ['hh', hours]) ||
 
- 			                (days <= 1 && ['d']) ||
 
- 			                (days < thresholds.d && ['dd', days]);
 
- 			        if (thresholds.w != null) {
 
- 			            a =
 
- 			                a ||
 
- 			                (weeks <= 1 && ['w']) ||
 
- 			                (weeks < thresholds.w && ['ww', weeks]);
 
- 			        }
 
- 			        a = a ||
 
- 			            (months <= 1 && ['M']) ||
 
- 			            (months < thresholds.M && ['MM', months]) ||
 
- 			            (years <= 1 && ['y']) || ['yy', years];
 
- 			        a[2] = withoutSuffix;
 
- 			        a[3] = +posNegDuration > 0;
 
- 			        a[4] = locale;
 
- 			        return substituteTimeAgo.apply(null, a);
 
- 			    }
 
- 			    // This function allows you to set the rounding function for relative time strings
 
- 			    function getSetRelativeTimeRounding(roundingFunction) {
 
- 			        if (roundingFunction === undefined) {
 
- 			            return round;
 
- 			        }
 
- 			        if (typeof roundingFunction === 'function') {
 
- 			            round = roundingFunction;
 
- 			            return true;
 
- 			        }
 
- 			        return false;
 
- 			    }
 
- 			    // This function allows you to set a threshold for relative time strings
 
- 			    function getSetRelativeTimeThreshold(threshold, limit) {
 
- 			        if (thresholds[threshold] === undefined) {
 
- 			            return false;
 
- 			        }
 
- 			        if (limit === undefined) {
 
- 			            return thresholds[threshold];
 
- 			        }
 
- 			        thresholds[threshold] = limit;
 
- 			        if (threshold === 's') {
 
- 			            thresholds.ss = limit - 1;
 
- 			        }
 
- 			        return true;
 
- 			    }
 
- 			    function humanize(argWithSuffix, argThresholds) {
 
- 			        if (!this.isValid()) {
 
- 			            return this.localeData().invalidDate();
 
- 			        }
 
- 			        var withSuffix = false,
 
- 			            th = thresholds,
 
- 			            locale,
 
- 			            output;
 
- 			        if (typeof argWithSuffix === 'object') {
 
- 			            argThresholds = argWithSuffix;
 
- 			            argWithSuffix = false;
 
- 			        }
 
- 			        if (typeof argWithSuffix === 'boolean') {
 
- 			            withSuffix = argWithSuffix;
 
- 			        }
 
- 			        if (typeof argThresholds === 'object') {
 
- 			            th = Object.assign({}, thresholds, argThresholds);
 
- 			            if (argThresholds.s != null && argThresholds.ss == null) {
 
- 			                th.ss = argThresholds.s - 1;
 
- 			            }
 
- 			        }
 
- 			        locale = this.localeData();
 
- 			        output = relativeTime$1(this, !withSuffix, th, locale);
 
- 			        if (withSuffix) {
 
- 			            output = locale.pastFuture(+this, output);
 
- 			        }
 
- 			        return locale.postformat(output);
 
- 			    }
 
- 			    var abs$1 = Math.abs;
 
- 			    function sign(x) {
 
- 			        return (x > 0) - (x < 0) || +x;
 
- 			    }
 
- 			    function toISOString$1() {
 
- 			        // for ISO strings we do not use the normal bubbling rules:
 
- 			        //  * milliseconds bubble up until they become hours
 
- 			        //  * days do not bubble at all
 
- 			        //  * months bubble up until they become years
 
- 			        // This is because there is no context-free conversion between hours and days
 
- 			        // (think of clock changes)
 
- 			        // and also not between days and months (28-31 days per month)
 
- 			        if (!this.isValid()) {
 
- 			            return this.localeData().invalidDate();
 
- 			        }
 
- 			        var seconds = abs$1(this._milliseconds) / 1000,
 
- 			            days = abs$1(this._days),
 
- 			            months = abs$1(this._months),
 
- 			            minutes,
 
- 			            hours,
 
- 			            years,
 
- 			            s,
 
- 			            total = this.asSeconds(),
 
- 			            totalSign,
 
- 			            ymSign,
 
- 			            daysSign,
 
- 			            hmsSign;
 
- 			        if (!total) {
 
- 			            // this is the same as C#'s (Noda) and python (isodate)...
 
- 			            // but not other JS (goog.date)
 
- 			            return 'P0D';
 
- 			        }
 
- 			        // 3600 seconds -> 60 minutes -> 1 hour
 
- 			        minutes = absFloor(seconds / 60);
 
- 			        hours = absFloor(minutes / 60);
 
- 			        seconds %= 60;
 
- 			        minutes %= 60;
 
- 			        // 12 months -> 1 year
 
- 			        years = absFloor(months / 12);
 
- 			        months %= 12;
 
- 			        // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
 
- 			        s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
 
- 			        totalSign = total < 0 ? '-' : '';
 
- 			        ymSign = sign(this._months) !== sign(total) ? '-' : '';
 
- 			        daysSign = sign(this._days) !== sign(total) ? '-' : '';
 
- 			        hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
 
- 			        return (
 
- 			            totalSign +
 
- 			            'P' +
 
- 			            (years ? ymSign + years + 'Y' : '') +
 
- 			            (months ? ymSign + months + 'M' : '') +
 
- 			            (days ? daysSign + days + 'D' : '') +
 
- 			            (hours || minutes || seconds ? 'T' : '') +
 
- 			            (hours ? hmsSign + hours + 'H' : '') +
 
- 			            (minutes ? hmsSign + minutes + 'M' : '') +
 
- 			            (seconds ? hmsSign + s + 'S' : '')
 
- 			        );
 
- 			    }
 
- 			    var proto$2 = Duration.prototype;
 
- 			    proto$2.isValid = isValid$1;
 
- 			    proto$2.abs = abs;
 
- 			    proto$2.add = add$1;
 
- 			    proto$2.subtract = subtract$1;
 
- 			    proto$2.as = as;
 
- 			    proto$2.asMilliseconds = asMilliseconds;
 
- 			    proto$2.asSeconds = asSeconds;
 
- 			    proto$2.asMinutes = asMinutes;
 
- 			    proto$2.asHours = asHours;
 
- 			    proto$2.asDays = asDays;
 
- 			    proto$2.asWeeks = asWeeks;
 
- 			    proto$2.asMonths = asMonths;
 
- 			    proto$2.asQuarters = asQuarters;
 
- 			    proto$2.asYears = asYears;
 
- 			    proto$2.valueOf = valueOf$1;
 
- 			    proto$2._bubble = bubble;
 
- 			    proto$2.clone = clone$1;
 
- 			    proto$2.get = get$2;
 
- 			    proto$2.milliseconds = milliseconds;
 
- 			    proto$2.seconds = seconds;
 
- 			    proto$2.minutes = minutes;
 
- 			    proto$2.hours = hours;
 
- 			    proto$2.days = days;
 
- 			    proto$2.weeks = weeks;
 
- 			    proto$2.months = months;
 
- 			    proto$2.years = years;
 
- 			    proto$2.humanize = humanize;
 
- 			    proto$2.toISOString = toISOString$1;
 
- 			    proto$2.toString = toISOString$1;
 
- 			    proto$2.toJSON = toISOString$1;
 
- 			    proto$2.locale = locale;
 
- 			    proto$2.localeData = localeData;
 
- 			    proto$2.toIsoString = deprecate(
 
- 			        'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)',
 
- 			        toISOString$1
 
- 			    );
 
- 			    proto$2.lang = lang;
 
- 			    // FORMATTING
 
- 			    addFormatToken('X', 0, 0, 'unix');
 
- 			    addFormatToken('x', 0, 0, 'valueOf');
 
- 			    // PARSING
 
- 			    addRegexToken('x', matchSigned);
 
- 			    addRegexToken('X', matchTimestamp);
 
- 			    addParseToken('X', function (input, array, config) {
 
- 			        config._d = new Date(parseFloat(input) * 1000);
 
- 			    });
 
- 			    addParseToken('x', function (input, array, config) {
 
- 			        config._d = new Date(toInt(input));
 
- 			    });
 
- 			    //! moment.js
 
- 			    hooks.version = '2.29.4';
 
- 			    setHookCallback(createLocal);
 
- 			    hooks.fn = proto;
 
- 			    hooks.min = min;
 
- 			    hooks.max = max;
 
- 			    hooks.now = now;
 
- 			    hooks.utc = createUTC;
 
- 			    hooks.unix = createUnix;
 
- 			    hooks.months = listMonths;
 
- 			    hooks.isDate = isDate;
 
- 			    hooks.locale = getSetGlobalLocale;
 
- 			    hooks.invalid = createInvalid;
 
- 			    hooks.duration = createDuration;
 
- 			    hooks.isMoment = isMoment;
 
- 			    hooks.weekdays = listWeekdays;
 
- 			    hooks.parseZone = createInZone;
 
- 			    hooks.localeData = getLocale;
 
- 			    hooks.isDuration = isDuration;
 
- 			    hooks.monthsShort = listMonthsShort;
 
- 			    hooks.weekdaysMin = listWeekdaysMin;
 
- 			    hooks.defineLocale = defineLocale;
 
- 			    hooks.updateLocale = updateLocale;
 
- 			    hooks.locales = listLocales;
 
- 			    hooks.weekdaysShort = listWeekdaysShort;
 
- 			    hooks.normalizeUnits = normalizeUnits;
 
- 			    hooks.relativeTimeRounding = getSetRelativeTimeRounding;
 
- 			    hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
 
- 			    hooks.calendarFormat = getCalendarFormat;
 
- 			    hooks.prototype = proto;
 
- 			    // currently HTML5 input type only supports 24-hour formats
 
- 			    hooks.HTML5_FMT = {
 
- 			        DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // <input type="datetime-local" />
 
- 			        DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // <input type="datetime-local" step="1" />
 
- 			        DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // <input type="datetime-local" step="0.001" />
 
- 			        DATE: 'YYYY-MM-DD', // <input type="date" />
 
- 			        TIME: 'HH:mm', // <input type="time" />
 
- 			        TIME_SECONDS: 'HH:mm:ss', // <input type="time" step="1" />
 
- 			        TIME_MS: 'HH:mm:ss.SSS', // <input type="time" step="0.001" />
 
- 			        WEEK: 'GGGG-[W]WW', // <input type="week" />
 
- 			        MONTH: 'YYYY-MM', // <input type="month" />
 
- 			    };
 
- 			    return hooks;
 
- 			}))); 
 
- 		} (moment));
 
- 		return moment.exports;
 
- 	}
 
- 	/*!
 
- 	 * Chart.js v2.9.4
 
- 	 * https://www.chartjs.org
 
- 	 * (c) 2020 Chart.js Contributors
 
- 	 * Released under the MIT License
 
- 	 */
 
- 	(function (module, exports) {
 
- 		(function (global, factory) {
 
- 		module.exports = factory(function() { try { return requireMoment(); } catch(e) { } }()) ;
 
- 		}(commonjsGlobal, (function (moment) {
 
- 		moment = moment && moment.hasOwnProperty('default') ? moment['default'] : moment;
 
- 		function createCommonjsModule(fn, module) {
 
- 			return module = { exports: {} }, fn(module, module.exports), module.exports;
 
- 		}
 
- 		function getCjsExportFromNamespace (n) {
 
- 			return n && n['default'] || n;
 
- 		}
 
- 		var colorName = {
 
- 			"aliceblue": [240, 248, 255],
 
- 			"antiquewhite": [250, 235, 215],
 
- 			"aqua": [0, 255, 255],
 
- 			"aquamarine": [127, 255, 212],
 
- 			"azure": [240, 255, 255],
 
- 			"beige": [245, 245, 220],
 
- 			"bisque": [255, 228, 196],
 
- 			"black": [0, 0, 0],
 
- 			"blanchedalmond": [255, 235, 205],
 
- 			"blue": [0, 0, 255],
 
- 			"blueviolet": [138, 43, 226],
 
- 			"brown": [165, 42, 42],
 
- 			"burlywood": [222, 184, 135],
 
- 			"cadetblue": [95, 158, 160],
 
- 			"chartreuse": [127, 255, 0],
 
- 			"chocolate": [210, 105, 30],
 
- 			"coral": [255, 127, 80],
 
- 			"cornflowerblue": [100, 149, 237],
 
- 			"cornsilk": [255, 248, 220],
 
- 			"crimson": [220, 20, 60],
 
- 			"cyan": [0, 255, 255],
 
- 			"darkblue": [0, 0, 139],
 
- 			"darkcyan": [0, 139, 139],
 
- 			"darkgoldenrod": [184, 134, 11],
 
- 			"darkgray": [169, 169, 169],
 
- 			"darkgreen": [0, 100, 0],
 
- 			"darkgrey": [169, 169, 169],
 
- 			"darkkhaki": [189, 183, 107],
 
- 			"darkmagenta": [139, 0, 139],
 
- 			"darkolivegreen": [85, 107, 47],
 
- 			"darkorange": [255, 140, 0],
 
- 			"darkorchid": [153, 50, 204],
 
- 			"darkred": [139, 0, 0],
 
- 			"darksalmon": [233, 150, 122],
 
- 			"darkseagreen": [143, 188, 143],
 
- 			"darkslateblue": [72, 61, 139],
 
- 			"darkslategray": [47, 79, 79],
 
- 			"darkslategrey": [47, 79, 79],
 
- 			"darkturquoise": [0, 206, 209],
 
- 			"darkviolet": [148, 0, 211],
 
- 			"deeppink": [255, 20, 147],
 
- 			"deepskyblue": [0, 191, 255],
 
- 			"dimgray": [105, 105, 105],
 
- 			"dimgrey": [105, 105, 105],
 
- 			"dodgerblue": [30, 144, 255],
 
- 			"firebrick": [178, 34, 34],
 
- 			"floralwhite": [255, 250, 240],
 
- 			"forestgreen": [34, 139, 34],
 
- 			"fuchsia": [255, 0, 255],
 
- 			"gainsboro": [220, 220, 220],
 
- 			"ghostwhite": [248, 248, 255],
 
- 			"gold": [255, 215, 0],
 
- 			"goldenrod": [218, 165, 32],
 
- 			"gray": [128, 128, 128],
 
- 			"green": [0, 128, 0],
 
- 			"greenyellow": [173, 255, 47],
 
- 			"grey": [128, 128, 128],
 
- 			"honeydew": [240, 255, 240],
 
- 			"hotpink": [255, 105, 180],
 
- 			"indianred": [205, 92, 92],
 
- 			"indigo": [75, 0, 130],
 
- 			"ivory": [255, 255, 240],
 
- 			"khaki": [240, 230, 140],
 
- 			"lavender": [230, 230, 250],
 
- 			"lavenderblush": [255, 240, 245],
 
- 			"lawngreen": [124, 252, 0],
 
- 			"lemonchiffon": [255, 250, 205],
 
- 			"lightblue": [173, 216, 230],
 
- 			"lightcoral": [240, 128, 128],
 
- 			"lightcyan": [224, 255, 255],
 
- 			"lightgoldenrodyellow": [250, 250, 210],
 
- 			"lightgray": [211, 211, 211],
 
- 			"lightgreen": [144, 238, 144],
 
- 			"lightgrey": [211, 211, 211],
 
- 			"lightpink": [255, 182, 193],
 
- 			"lightsalmon": [255, 160, 122],
 
- 			"lightseagreen": [32, 178, 170],
 
- 			"lightskyblue": [135, 206, 250],
 
- 			"lightslategray": [119, 136, 153],
 
- 			"lightslategrey": [119, 136, 153],
 
- 			"lightsteelblue": [176, 196, 222],
 
- 			"lightyellow": [255, 255, 224],
 
- 			"lime": [0, 255, 0],
 
- 			"limegreen": [50, 205, 50],
 
- 			"linen": [250, 240, 230],
 
- 			"magenta": [255, 0, 255],
 
- 			"maroon": [128, 0, 0],
 
- 			"mediumaquamarine": [102, 205, 170],
 
- 			"mediumblue": [0, 0, 205],
 
- 			"mediumorchid": [186, 85, 211],
 
- 			"mediumpurple": [147, 112, 219],
 
- 			"mediumseagreen": [60, 179, 113],
 
- 			"mediumslateblue": [123, 104, 238],
 
- 			"mediumspringgreen": [0, 250, 154],
 
- 			"mediumturquoise": [72, 209, 204],
 
- 			"mediumvioletred": [199, 21, 133],
 
- 			"midnightblue": [25, 25, 112],
 
- 			"mintcream": [245, 255, 250],
 
- 			"mistyrose": [255, 228, 225],
 
- 			"moccasin": [255, 228, 181],
 
- 			"navajowhite": [255, 222, 173],
 
- 			"navy": [0, 0, 128],
 
- 			"oldlace": [253, 245, 230],
 
- 			"olive": [128, 128, 0],
 
- 			"olivedrab": [107, 142, 35],
 
- 			"orange": [255, 165, 0],
 
- 			"orangered": [255, 69, 0],
 
- 			"orchid": [218, 112, 214],
 
- 			"palegoldenrod": [238, 232, 170],
 
- 			"palegreen": [152, 251, 152],
 
- 			"paleturquoise": [175, 238, 238],
 
- 			"palevioletred": [219, 112, 147],
 
- 			"papayawhip": [255, 239, 213],
 
- 			"peachpuff": [255, 218, 185],
 
- 			"peru": [205, 133, 63],
 
- 			"pink": [255, 192, 203],
 
- 			"plum": [221, 160, 221],
 
- 			"powderblue": [176, 224, 230],
 
- 			"purple": [128, 0, 128],
 
- 			"rebeccapurple": [102, 51, 153],
 
- 			"red": [255, 0, 0],
 
- 			"rosybrown": [188, 143, 143],
 
- 			"royalblue": [65, 105, 225],
 
- 			"saddlebrown": [139, 69, 19],
 
- 			"salmon": [250, 128, 114],
 
- 			"sandybrown": [244, 164, 96],
 
- 			"seagreen": [46, 139, 87],
 
- 			"seashell": [255, 245, 238],
 
- 			"sienna": [160, 82, 45],
 
- 			"silver": [192, 192, 192],
 
- 			"skyblue": [135, 206, 235],
 
- 			"slateblue": [106, 90, 205],
 
- 			"slategray": [112, 128, 144],
 
- 			"slategrey": [112, 128, 144],
 
- 			"snow": [255, 250, 250],
 
- 			"springgreen": [0, 255, 127],
 
- 			"steelblue": [70, 130, 180],
 
- 			"tan": [210, 180, 140],
 
- 			"teal": [0, 128, 128],
 
- 			"thistle": [216, 191, 216],
 
- 			"tomato": [255, 99, 71],
 
- 			"turquoise": [64, 224, 208],
 
- 			"violet": [238, 130, 238],
 
- 			"wheat": [245, 222, 179],
 
- 			"white": [255, 255, 255],
 
- 			"whitesmoke": [245, 245, 245],
 
- 			"yellow": [255, 255, 0],
 
- 			"yellowgreen": [154, 205, 50]
 
- 		};
 
- 		var conversions = createCommonjsModule(function (module) {
 
- 		/* MIT license */
 
- 		// NOTE: conversions should only return primitive values (i.e. arrays, or
 
- 		//       values that give correct `typeof` results).
 
- 		//       do not use box values types (i.e. Number(), String(), etc.)
 
- 		var reverseKeywords = {};
 
- 		for (var key in colorName) {
 
- 			if (colorName.hasOwnProperty(key)) {
 
- 				reverseKeywords[colorName[key]] = key;
 
- 			}
 
- 		}
 
- 		var convert = module.exports = {
 
- 			rgb: {channels: 3, labels: 'rgb'},
 
- 			hsl: {channels: 3, labels: 'hsl'},
 
- 			hsv: {channels: 3, labels: 'hsv'},
 
- 			hwb: {channels: 3, labels: 'hwb'},
 
- 			cmyk: {channels: 4, labels: 'cmyk'},
 
- 			xyz: {channels: 3, labels: 'xyz'},
 
- 			lab: {channels: 3, labels: 'lab'},
 
- 			lch: {channels: 3, labels: 'lch'},
 
- 			hex: {channels: 1, labels: ['hex']},
 
- 			keyword: {channels: 1, labels: ['keyword']},
 
- 			ansi16: {channels: 1, labels: ['ansi16']},
 
- 			ansi256: {channels: 1, labels: ['ansi256']},
 
- 			hcg: {channels: 3, labels: ['h', 'c', 'g']},
 
- 			apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
 
- 			gray: {channels: 1, labels: ['gray']}
 
- 		};
 
- 		// hide .channels and .labels properties
 
- 		for (var model in convert) {
 
- 			if (convert.hasOwnProperty(model)) {
 
- 				if (!('channels' in convert[model])) {
 
- 					throw new Error('missing channels property: ' + model);
 
- 				}
 
- 				if (!('labels' in convert[model])) {
 
- 					throw new Error('missing channel labels property: ' + model);
 
- 				}
 
- 				if (convert[model].labels.length !== convert[model].channels) {
 
- 					throw new Error('channel and label counts mismatch: ' + model);
 
- 				}
 
- 				var channels = convert[model].channels;
 
- 				var labels = convert[model].labels;
 
- 				delete convert[model].channels;
 
- 				delete convert[model].labels;
 
- 				Object.defineProperty(convert[model], 'channels', {value: channels});
 
- 				Object.defineProperty(convert[model], 'labels', {value: labels});
 
- 			}
 
- 		}
 
- 		convert.rgb.hsl = function (rgb) {
 
- 			var r = rgb[0] / 255;
 
- 			var g = rgb[1] / 255;
 
- 			var b = rgb[2] / 255;
 
- 			var min = Math.min(r, g, b);
 
- 			var max = Math.max(r, g, b);
 
- 			var delta = max - min;
 
- 			var h;
 
- 			var s;
 
- 			var l;
 
- 			if (max === min) {
 
- 				h = 0;
 
- 			} else if (r === max) {
 
- 				h = (g - b) / delta;
 
- 			} else if (g === max) {
 
- 				h = 2 + (b - r) / delta;
 
- 			} else if (b === max) {
 
- 				h = 4 + (r - g) / delta;
 
- 			}
 
- 			h = Math.min(h * 60, 360);
 
- 			if (h < 0) {
 
- 				h += 360;
 
- 			}
 
- 			l = (min + max) / 2;
 
- 			if (max === min) {
 
- 				s = 0;
 
- 			} else if (l <= 0.5) {
 
- 				s = delta / (max + min);
 
- 			} else {
 
- 				s = delta / (2 - max - min);
 
- 			}
 
- 			return [h, s * 100, l * 100];
 
- 		};
 
- 		convert.rgb.hsv = function (rgb) {
 
- 			var rdif;
 
- 			var gdif;
 
- 			var bdif;
 
- 			var h;
 
- 			var s;
 
- 			var r = rgb[0] / 255;
 
- 			var g = rgb[1] / 255;
 
- 			var b = rgb[2] / 255;
 
- 			var v = Math.max(r, g, b);
 
- 			var diff = v - Math.min(r, g, b);
 
- 			var diffc = function (c) {
 
- 				return (v - c) / 6 / diff + 1 / 2;
 
- 			};
 
- 			if (diff === 0) {
 
- 				h = s = 0;
 
- 			} else {
 
- 				s = diff / v;
 
- 				rdif = diffc(r);
 
- 				gdif = diffc(g);
 
- 				bdif = diffc(b);
 
- 				if (r === v) {
 
- 					h = bdif - gdif;
 
- 				} else if (g === v) {
 
- 					h = (1 / 3) + rdif - bdif;
 
- 				} else if (b === v) {
 
- 					h = (2 / 3) + gdif - rdif;
 
- 				}
 
- 				if (h < 0) {
 
- 					h += 1;
 
- 				} else if (h > 1) {
 
- 					h -= 1;
 
- 				}
 
- 			}
 
- 			return [
 
- 				h * 360,
 
- 				s * 100,
 
- 				v * 100
 
- 			];
 
- 		};
 
- 		convert.rgb.hwb = function (rgb) {
 
- 			var r = rgb[0];
 
- 			var g = rgb[1];
 
- 			var b = rgb[2];
 
- 			var h = convert.rgb.hsl(rgb)[0];
 
- 			var w = 1 / 255 * Math.min(r, Math.min(g, b));
 
- 			b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
 
- 			return [h, w * 100, b * 100];
 
- 		};
 
- 		convert.rgb.cmyk = function (rgb) {
 
- 			var r = rgb[0] / 255;
 
- 			var g = rgb[1] / 255;
 
- 			var b = rgb[2] / 255;
 
- 			var c;
 
- 			var m;
 
- 			var y;
 
- 			var k;
 
- 			k = Math.min(1 - r, 1 - g, 1 - b);
 
- 			c = (1 - r - k) / (1 - k) || 0;
 
- 			m = (1 - g - k) / (1 - k) || 0;
 
- 			y = (1 - b - k) / (1 - k) || 0;
 
- 			return [c * 100, m * 100, y * 100, k * 100];
 
- 		};
 
- 		/**
 
- 		 * See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
 
- 		 * */
 
- 		function comparativeDistance(x, y) {
 
- 			return (
 
- 				Math.pow(x[0] - y[0], 2) +
 
- 				Math.pow(x[1] - y[1], 2) +
 
- 				Math.pow(x[2] - y[2], 2)
 
- 			);
 
- 		}
 
- 		convert.rgb.keyword = function (rgb) {
 
- 			var reversed = reverseKeywords[rgb];
 
- 			if (reversed) {
 
- 				return reversed;
 
- 			}
 
- 			var currentClosestDistance = Infinity;
 
- 			var currentClosestKeyword;
 
- 			for (var keyword in colorName) {
 
- 				if (colorName.hasOwnProperty(keyword)) {
 
- 					var value = colorName[keyword];
 
- 					// Compute comparative distance
 
- 					var distance = comparativeDistance(rgb, value);
 
- 					// Check if its less, if so set as closest
 
- 					if (distance < currentClosestDistance) {
 
- 						currentClosestDistance = distance;
 
- 						currentClosestKeyword = keyword;
 
- 					}
 
- 				}
 
- 			}
 
- 			return currentClosestKeyword;
 
- 		};
 
- 		convert.keyword.rgb = function (keyword) {
 
- 			return colorName[keyword];
 
- 		};
 
- 		convert.rgb.xyz = function (rgb) {
 
- 			var r = rgb[0] / 255;
 
- 			var g = rgb[1] / 255;
 
- 			var b = rgb[2] / 255;
 
- 			// assume sRGB
 
- 			r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
 
- 			g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
 
- 			b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
 
- 			var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
 
- 			var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
 
- 			var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
 
- 			return [x * 100, y * 100, z * 100];
 
- 		};
 
- 		convert.rgb.lab = function (rgb) {
 
- 			var xyz = convert.rgb.xyz(rgb);
 
- 			var x = xyz[0];
 
- 			var y = xyz[1];
 
- 			var z = xyz[2];
 
- 			var l;
 
- 			var a;
 
- 			var b;
 
- 			x /= 95.047;
 
- 			y /= 100;
 
- 			z /= 108.883;
 
- 			x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
 
- 			y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
 
- 			z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
 
- 			l = (116 * y) - 16;
 
- 			a = 500 * (x - y);
 
- 			b = 200 * (y - z);
 
- 			return [l, a, b];
 
- 		};
 
- 		convert.hsl.rgb = function (hsl) {
 
- 			var h = hsl[0] / 360;
 
- 			var s = hsl[1] / 100;
 
- 			var l = hsl[2] / 100;
 
- 			var t1;
 
- 			var t2;
 
- 			var t3;
 
- 			var rgb;
 
- 			var val;
 
- 			if (s === 0) {
 
- 				val = l * 255;
 
- 				return [val, val, val];
 
- 			}
 
- 			if (l < 0.5) {
 
- 				t2 = l * (1 + s);
 
- 			} else {
 
- 				t2 = l + s - l * s;
 
- 			}
 
- 			t1 = 2 * l - t2;
 
- 			rgb = [0, 0, 0];
 
- 			for (var i = 0; i < 3; i++) {
 
- 				t3 = h + 1 / 3 * -(i - 1);
 
- 				if (t3 < 0) {
 
- 					t3++;
 
- 				}
 
- 				if (t3 > 1) {
 
- 					t3--;
 
- 				}
 
- 				if (6 * t3 < 1) {
 
- 					val = t1 + (t2 - t1) * 6 * t3;
 
- 				} else if (2 * t3 < 1) {
 
- 					val = t2;
 
- 				} else if (3 * t3 < 2) {
 
- 					val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
 
- 				} else {
 
- 					val = t1;
 
- 				}
 
- 				rgb[i] = val * 255;
 
- 			}
 
- 			return rgb;
 
- 		};
 
- 		convert.hsl.hsv = function (hsl) {
 
- 			var h = hsl[0];
 
- 			var s = hsl[1] / 100;
 
- 			var l = hsl[2] / 100;
 
- 			var smin = s;
 
- 			var lmin = Math.max(l, 0.01);
 
- 			var sv;
 
- 			var v;
 
- 			l *= 2;
 
- 			s *= (l <= 1) ? l : 2 - l;
 
- 			smin *= lmin <= 1 ? lmin : 2 - lmin;
 
- 			v = (l + s) / 2;
 
- 			sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
 
- 			return [h, sv * 100, v * 100];
 
- 		};
 
- 		convert.hsv.rgb = function (hsv) {
 
- 			var h = hsv[0] / 60;
 
- 			var s = hsv[1] / 100;
 
- 			var v = hsv[2] / 100;
 
- 			var hi = Math.floor(h) % 6;
 
- 			var f = h - Math.floor(h);
 
- 			var p = 255 * v * (1 - s);
 
- 			var q = 255 * v * (1 - (s * f));
 
- 			var t = 255 * v * (1 - (s * (1 - f)));
 
- 			v *= 255;
 
- 			switch (hi) {
 
- 				case 0:
 
- 					return [v, t, p];
 
- 				case 1:
 
- 					return [q, v, p];
 
- 				case 2:
 
- 					return [p, v, t];
 
- 				case 3:
 
- 					return [p, q, v];
 
- 				case 4:
 
- 					return [t, p, v];
 
- 				case 5:
 
- 					return [v, p, q];
 
- 			}
 
- 		};
 
- 		convert.hsv.hsl = function (hsv) {
 
- 			var h = hsv[0];
 
- 			var s = hsv[1] / 100;
 
- 			var v = hsv[2] / 100;
 
- 			var vmin = Math.max(v, 0.01);
 
- 			var lmin;
 
- 			var sl;
 
- 			var l;
 
- 			l = (2 - s) * v;
 
- 			lmin = (2 - s) * vmin;
 
- 			sl = s * vmin;
 
- 			sl /= (lmin <= 1) ? lmin : 2 - lmin;
 
- 			sl = sl || 0;
 
- 			l /= 2;
 
- 			return [h, sl * 100, l * 100];
 
- 		};
 
- 		// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
 
- 		convert.hwb.rgb = function (hwb) {
 
- 			var h = hwb[0] / 360;
 
- 			var wh = hwb[1] / 100;
 
- 			var bl = hwb[2] / 100;
 
- 			var ratio = wh + bl;
 
- 			var i;
 
- 			var v;
 
- 			var f;
 
- 			var n;
 
- 			// wh + bl cant be > 1
 
- 			if (ratio > 1) {
 
- 				wh /= ratio;
 
- 				bl /= ratio;
 
- 			}
 
- 			i = Math.floor(6 * h);
 
- 			v = 1 - bl;
 
- 			f = 6 * h - i;
 
- 			if ((i & 0x01) !== 0) {
 
- 				f = 1 - f;
 
- 			}
 
- 			n = wh + f * (v - wh); // linear interpolation
 
- 			var r;
 
- 			var g;
 
- 			var b;
 
- 			switch (i) {
 
- 				default:
 
- 				case 6:
 
- 				case 0: r = v; g = n; b = wh; break;
 
- 				case 1: r = n; g = v; b = wh; break;
 
- 				case 2: r = wh; g = v; b = n; break;
 
- 				case 3: r = wh; g = n; b = v; break;
 
- 				case 4: r = n; g = wh; b = v; break;
 
- 				case 5: r = v; g = wh; b = n; break;
 
- 			}
 
- 			return [r * 255, g * 255, b * 255];
 
- 		};
 
- 		convert.cmyk.rgb = function (cmyk) {
 
- 			var c = cmyk[0] / 100;
 
- 			var m = cmyk[1] / 100;
 
- 			var y = cmyk[2] / 100;
 
- 			var k = cmyk[3] / 100;
 
- 			var r;
 
- 			var g;
 
- 			var b;
 
- 			r = 1 - Math.min(1, c * (1 - k) + k);
 
- 			g = 1 - Math.min(1, m * (1 - k) + k);
 
- 			b = 1 - Math.min(1, y * (1 - k) + k);
 
- 			return [r * 255, g * 255, b * 255];
 
- 		};
 
- 		convert.xyz.rgb = function (xyz) {
 
- 			var x = xyz[0] / 100;
 
- 			var y = xyz[1] / 100;
 
- 			var z = xyz[2] / 100;
 
- 			var r;
 
- 			var g;
 
- 			var b;
 
- 			r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
 
- 			g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
 
- 			b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
 
- 			// assume sRGB
 
- 			r = r > 0.0031308
 
- 				? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
 
- 				: r * 12.92;
 
- 			g = g > 0.0031308
 
- 				? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
 
- 				: g * 12.92;
 
- 			b = b > 0.0031308
 
- 				? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
 
- 				: b * 12.92;
 
- 			r = Math.min(Math.max(0, r), 1);
 
- 			g = Math.min(Math.max(0, g), 1);
 
- 			b = Math.min(Math.max(0, b), 1);
 
- 			return [r * 255, g * 255, b * 255];
 
- 		};
 
- 		convert.xyz.lab = function (xyz) {
 
- 			var x = xyz[0];
 
- 			var y = xyz[1];
 
- 			var z = xyz[2];
 
- 			var l;
 
- 			var a;
 
- 			var b;
 
- 			x /= 95.047;
 
- 			y /= 100;
 
- 			z /= 108.883;
 
- 			x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
 
- 			y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
 
- 			z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
 
- 			l = (116 * y) - 16;
 
- 			a = 500 * (x - y);
 
- 			b = 200 * (y - z);
 
- 			return [l, a, b];
 
- 		};
 
- 		convert.lab.xyz = function (lab) {
 
- 			var l = lab[0];
 
- 			var a = lab[1];
 
- 			var b = lab[2];
 
- 			var x;
 
- 			var y;
 
- 			var z;
 
- 			y = (l + 16) / 116;
 
- 			x = a / 500 + y;
 
- 			z = y - b / 200;
 
- 			var y2 = Math.pow(y, 3);
 
- 			var x2 = Math.pow(x, 3);
 
- 			var z2 = Math.pow(z, 3);
 
- 			y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;
 
- 			x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;
 
- 			z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;
 
- 			x *= 95.047;
 
- 			y *= 100;
 
- 			z *= 108.883;
 
- 			return [x, y, z];
 
- 		};
 
- 		convert.lab.lch = function (lab) {
 
- 			var l = lab[0];
 
- 			var a = lab[1];
 
- 			var b = lab[2];
 
- 			var hr;
 
- 			var h;
 
- 			var c;
 
- 			hr = Math.atan2(b, a);
 
- 			h = hr * 360 / 2 / Math.PI;
 
- 			if (h < 0) {
 
- 				h += 360;
 
- 			}
 
- 			c = Math.sqrt(a * a + b * b);
 
- 			return [l, c, h];
 
- 		};
 
- 		convert.lch.lab = function (lch) {
 
- 			var l = lch[0];
 
- 			var c = lch[1];
 
- 			var h = lch[2];
 
- 			var a;
 
- 			var b;
 
- 			var hr;
 
- 			hr = h / 360 * 2 * Math.PI;
 
- 			a = c * Math.cos(hr);
 
- 			b = c * Math.sin(hr);
 
- 			return [l, a, b];
 
- 		};
 
- 		convert.rgb.ansi16 = function (args) {
 
- 			var r = args[0];
 
- 			var g = args[1];
 
- 			var b = args[2];
 
- 			var value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization
 
- 			value = Math.round(value / 50);
 
- 			if (value === 0) {
 
- 				return 30;
 
- 			}
 
- 			var ansi = 30
 
- 				+ ((Math.round(b / 255) << 2)
 
- 				| (Math.round(g / 255) << 1)
 
- 				| Math.round(r / 255));
 
- 			if (value === 2) {
 
- 				ansi += 60;
 
- 			}
 
- 			return ansi;
 
- 		};
 
- 		convert.hsv.ansi16 = function (args) {
 
- 			// optimization here; we already know the value and don't need to get
 
- 			// it converted for us.
 
- 			return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
 
- 		};
 
- 		convert.rgb.ansi256 = function (args) {
 
- 			var r = args[0];
 
- 			var g = args[1];
 
- 			var b = args[2];
 
- 			// we use the extended greyscale palette here, with the exception of
 
- 			// black and white. normal palette only has 4 greyscale shades.
 
- 			if (r === g && g === b) {
 
- 				if (r < 8) {
 
- 					return 16;
 
- 				}
 
- 				if (r > 248) {
 
- 					return 231;
 
- 				}
 
- 				return Math.round(((r - 8) / 247) * 24) + 232;
 
- 			}
 
- 			var ansi = 16
 
- 				+ (36 * Math.round(r / 255 * 5))
 
- 				+ (6 * Math.round(g / 255 * 5))
 
- 				+ Math.round(b / 255 * 5);
 
- 			return ansi;
 
- 		};
 
- 		convert.ansi16.rgb = function (args) {
 
- 			var color = args % 10;
 
- 			// handle greyscale
 
- 			if (color === 0 || color === 7) {
 
- 				if (args > 50) {
 
- 					color += 3.5;
 
- 				}
 
- 				color = color / 10.5 * 255;
 
- 				return [color, color, color];
 
- 			}
 
- 			var mult = (~~(args > 50) + 1) * 0.5;
 
- 			var r = ((color & 1) * mult) * 255;
 
- 			var g = (((color >> 1) & 1) * mult) * 255;
 
- 			var b = (((color >> 2) & 1) * mult) * 255;
 
- 			return [r, g, b];
 
- 		};
 
- 		convert.ansi256.rgb = function (args) {
 
- 			// handle greyscale
 
- 			if (args >= 232) {
 
- 				var c = (args - 232) * 10 + 8;
 
- 				return [c, c, c];
 
- 			}
 
- 			args -= 16;
 
- 			var rem;
 
- 			var r = Math.floor(args / 36) / 5 * 255;
 
- 			var g = Math.floor((rem = args % 36) / 6) / 5 * 255;
 
- 			var b = (rem % 6) / 5 * 255;
 
- 			return [r, g, b];
 
- 		};
 
- 		convert.rgb.hex = function (args) {
 
- 			var integer = ((Math.round(args[0]) & 0xFF) << 16)
 
- 				+ ((Math.round(args[1]) & 0xFF) << 8)
 
- 				+ (Math.round(args[2]) & 0xFF);
 
- 			var string = integer.toString(16).toUpperCase();
 
- 			return '000000'.substring(string.length) + string;
 
- 		};
 
- 		convert.hex.rgb = function (args) {
 
- 			var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
 
- 			if (!match) {
 
- 				return [0, 0, 0];
 
- 			}
 
- 			var colorString = match[0];
 
- 			if (match[0].length === 3) {
 
- 				colorString = colorString.split('').map(function (char) {
 
- 					return char + char;
 
- 				}).join('');
 
- 			}
 
- 			var integer = parseInt(colorString, 16);
 
- 			var r = (integer >> 16) & 0xFF;
 
- 			var g = (integer >> 8) & 0xFF;
 
- 			var b = integer & 0xFF;
 
- 			return [r, g, b];
 
- 		};
 
- 		convert.rgb.hcg = function (rgb) {
 
- 			var r = rgb[0] / 255;
 
- 			var g = rgb[1] / 255;
 
- 			var b = rgb[2] / 255;
 
- 			var max = Math.max(Math.max(r, g), b);
 
- 			var min = Math.min(Math.min(r, g), b);
 
- 			var chroma = (max - min);
 
- 			var grayscale;
 
- 			var hue;
 
- 			if (chroma < 1) {
 
- 				grayscale = min / (1 - chroma);
 
- 			} else {
 
- 				grayscale = 0;
 
- 			}
 
- 			if (chroma <= 0) {
 
- 				hue = 0;
 
- 			} else
 
- 			if (max === r) {
 
- 				hue = ((g - b) / chroma) % 6;
 
- 			} else
 
- 			if (max === g) {
 
- 				hue = 2 + (b - r) / chroma;
 
- 			} else {
 
- 				hue = 4 + (r - g) / chroma + 4;
 
- 			}
 
- 			hue /= 6;
 
- 			hue %= 1;
 
- 			return [hue * 360, chroma * 100, grayscale * 100];
 
- 		};
 
- 		convert.hsl.hcg = function (hsl) {
 
- 			var s = hsl[1] / 100;
 
- 			var l = hsl[2] / 100;
 
- 			var c = 1;
 
- 			var f = 0;
 
- 			if (l < 0.5) {
 
- 				c = 2.0 * s * l;
 
- 			} else {
 
- 				c = 2.0 * s * (1.0 - l);
 
- 			}
 
- 			if (c < 1.0) {
 
- 				f = (l - 0.5 * c) / (1.0 - c);
 
- 			}
 
- 			return [hsl[0], c * 100, f * 100];
 
- 		};
 
- 		convert.hsv.hcg = function (hsv) {
 
- 			var s = hsv[1] / 100;
 
- 			var v = hsv[2] / 100;
 
- 			var c = s * v;
 
- 			var f = 0;
 
- 			if (c < 1.0) {
 
- 				f = (v - c) / (1 - c);
 
- 			}
 
- 			return [hsv[0], c * 100, f * 100];
 
- 		};
 
- 		convert.hcg.rgb = function (hcg) {
 
- 			var h = hcg[0] / 360;
 
- 			var c = hcg[1] / 100;
 
- 			var g = hcg[2] / 100;
 
- 			if (c === 0.0) {
 
- 				return [g * 255, g * 255, g * 255];
 
- 			}
 
- 			var pure = [0, 0, 0];
 
- 			var hi = (h % 1) * 6;
 
- 			var v = hi % 1;
 
- 			var w = 1 - v;
 
- 			var mg = 0;
 
- 			switch (Math.floor(hi)) {
 
- 				case 0:
 
- 					pure[0] = 1; pure[1] = v; pure[2] = 0; break;
 
- 				case 1:
 
- 					pure[0] = w; pure[1] = 1; pure[2] = 0; break;
 
- 				case 2:
 
- 					pure[0] = 0; pure[1] = 1; pure[2] = v; break;
 
- 				case 3:
 
- 					pure[0] = 0; pure[1] = w; pure[2] = 1; break;
 
- 				case 4:
 
- 					pure[0] = v; pure[1] = 0; pure[2] = 1; break;
 
- 				default:
 
- 					pure[0] = 1; pure[1] = 0; pure[2] = w;
 
- 			}
 
- 			mg = (1.0 - c) * g;
 
- 			return [
 
- 				(c * pure[0] + mg) * 255,
 
- 				(c * pure[1] + mg) * 255,
 
- 				(c * pure[2] + mg) * 255
 
- 			];
 
- 		};
 
- 		convert.hcg.hsv = function (hcg) {
 
- 			var c = hcg[1] / 100;
 
- 			var g = hcg[2] / 100;
 
- 			var v = c + g * (1.0 - c);
 
- 			var f = 0;
 
- 			if (v > 0.0) {
 
- 				f = c / v;
 
- 			}
 
- 			return [hcg[0], f * 100, v * 100];
 
- 		};
 
- 		convert.hcg.hsl = function (hcg) {
 
- 			var c = hcg[1] / 100;
 
- 			var g = hcg[2] / 100;
 
- 			var l = g * (1.0 - c) + 0.5 * c;
 
- 			var s = 0;
 
- 			if (l > 0.0 && l < 0.5) {
 
- 				s = c / (2 * l);
 
- 			} else
 
- 			if (l >= 0.5 && l < 1.0) {
 
- 				s = c / (2 * (1 - l));
 
- 			}
 
- 			return [hcg[0], s * 100, l * 100];
 
- 		};
 
- 		convert.hcg.hwb = function (hcg) {
 
- 			var c = hcg[1] / 100;
 
- 			var g = hcg[2] / 100;
 
- 			var v = c + g * (1.0 - c);
 
- 			return [hcg[0], (v - c) * 100, (1 - v) * 100];
 
- 		};
 
- 		convert.hwb.hcg = function (hwb) {
 
- 			var w = hwb[1] / 100;
 
- 			var b = hwb[2] / 100;
 
- 			var v = 1 - b;
 
- 			var c = v - w;
 
- 			var g = 0;
 
- 			if (c < 1) {
 
- 				g = (v - c) / (1 - c);
 
- 			}
 
- 			return [hwb[0], c * 100, g * 100];
 
- 		};
 
- 		convert.apple.rgb = function (apple) {
 
- 			return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];
 
- 		};
 
- 		convert.rgb.apple = function (rgb) {
 
- 			return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];
 
- 		};
 
- 		convert.gray.rgb = function (args) {
 
- 			return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];
 
- 		};
 
- 		convert.gray.hsl = convert.gray.hsv = function (args) {
 
- 			return [0, 0, args[0]];
 
- 		};
 
- 		convert.gray.hwb = function (gray) {
 
- 			return [0, 100, gray[0]];
 
- 		};
 
- 		convert.gray.cmyk = function (gray) {
 
- 			return [0, 0, 0, gray[0]];
 
- 		};
 
- 		convert.gray.lab = function (gray) {
 
- 			return [gray[0], 0, 0];
 
- 		};
 
- 		convert.gray.hex = function (gray) {
 
- 			var val = Math.round(gray[0] / 100 * 255) & 0xFF;
 
- 			var integer = (val << 16) + (val << 8) + val;
 
- 			var string = integer.toString(16).toUpperCase();
 
- 			return '000000'.substring(string.length) + string;
 
- 		};
 
- 		convert.rgb.gray = function (rgb) {
 
- 			var val = (rgb[0] + rgb[1] + rgb[2]) / 3;
 
- 			return [val / 255 * 100];
 
- 		};
 
- 		});
 
- 		conversions.rgb;
 
- 		conversions.hsl;
 
- 		conversions.hsv;
 
- 		conversions.hwb;
 
- 		conversions.cmyk;
 
- 		conversions.xyz;
 
- 		conversions.lab;
 
- 		conversions.lch;
 
- 		conversions.hex;
 
- 		conversions.keyword;
 
- 		conversions.ansi16;
 
- 		conversions.ansi256;
 
- 		conversions.hcg;
 
- 		conversions.apple;
 
- 		conversions.gray;
 
- 		/*
 
- 			this function routes a model to all other models.
 
- 			all functions that are routed have a property `.conversion` attached
 
- 			to the returned synthetic function. This property is an array
 
- 			of strings, each with the steps in between the 'from' and 'to'
 
- 			color models (inclusive).
 
- 			conversions that are not possible simply are not included.
 
- 		*/
 
- 		function buildGraph() {
 
- 			var graph = {};
 
- 			// https://jsperf.com/object-keys-vs-for-in-with-closure/3
 
- 			var models = Object.keys(conversions);
 
- 			for (var len = models.length, i = 0; i < len; i++) {
 
- 				graph[models[i]] = {
 
- 					// http://jsperf.com/1-vs-infinity
 
- 					// micro-opt, but this is simple.
 
- 					distance: -1,
 
- 					parent: null
 
- 				};
 
- 			}
 
- 			return graph;
 
- 		}
 
- 		// https://en.wikipedia.org/wiki/Breadth-first_search
 
- 		function deriveBFS(fromModel) {
 
- 			var graph = buildGraph();
 
- 			var queue = [fromModel]; // unshift -> queue -> pop
 
- 			graph[fromModel].distance = 0;
 
- 			while (queue.length) {
 
- 				var current = queue.pop();
 
- 				var adjacents = Object.keys(conversions[current]);
 
- 				for (var len = adjacents.length, i = 0; i < len; i++) {
 
- 					var adjacent = adjacents[i];
 
- 					var node = graph[adjacent];
 
- 					if (node.distance === -1) {
 
- 						node.distance = graph[current].distance + 1;
 
- 						node.parent = current;
 
- 						queue.unshift(adjacent);
 
- 					}
 
- 				}
 
- 			}
 
- 			return graph;
 
- 		}
 
- 		function link(from, to) {
 
- 			return function (args) {
 
- 				return to(from(args));
 
- 			};
 
- 		}
 
- 		function wrapConversion(toModel, graph) {
 
- 			var path = [graph[toModel].parent, toModel];
 
- 			var fn = conversions[graph[toModel].parent][toModel];
 
- 			var cur = graph[toModel].parent;
 
- 			while (graph[cur].parent) {
 
- 				path.unshift(graph[cur].parent);
 
- 				fn = link(conversions[graph[cur].parent][cur], fn);
 
- 				cur = graph[cur].parent;
 
- 			}
 
- 			fn.conversion = path;
 
- 			return fn;
 
- 		}
 
- 		var route = function (fromModel) {
 
- 			var graph = deriveBFS(fromModel);
 
- 			var conversion = {};
 
- 			var models = Object.keys(graph);
 
- 			for (var len = models.length, i = 0; i < len; i++) {
 
- 				var toModel = models[i];
 
- 				var node = graph[toModel];
 
- 				if (node.parent === null) {
 
- 					// no possible conversion, or this node is the source model.
 
- 					continue;
 
- 				}
 
- 				conversion[toModel] = wrapConversion(toModel, graph);
 
- 			}
 
- 			return conversion;
 
- 		};
 
- 		var convert = {};
 
- 		var models = Object.keys(conversions);
 
- 		function wrapRaw(fn) {
 
- 			var wrappedFn = function (args) {
 
- 				if (args === undefined || args === null) {
 
- 					return args;
 
- 				}
 
- 				if (arguments.length > 1) {
 
- 					args = Array.prototype.slice.call(arguments);
 
- 				}
 
- 				return fn(args);
 
- 			};
 
- 			// preserve .conversion property if there is one
 
- 			if ('conversion' in fn) {
 
- 				wrappedFn.conversion = fn.conversion;
 
- 			}
 
- 			return wrappedFn;
 
- 		}
 
- 		function wrapRounded(fn) {
 
- 			var wrappedFn = function (args) {
 
- 				if (args === undefined || args === null) {
 
- 					return args;
 
- 				}
 
- 				if (arguments.length > 1) {
 
- 					args = Array.prototype.slice.call(arguments);
 
- 				}
 
- 				var result = fn(args);
 
- 				// we're assuming the result is an array here.
 
- 				// see notice in conversions.js; don't use box types
 
- 				// in conversion functions.
 
- 				if (typeof result === 'object') {
 
- 					for (var len = result.length, i = 0; i < len; i++) {
 
- 						result[i] = Math.round(result[i]);
 
- 					}
 
- 				}
 
- 				return result;
 
- 			};
 
- 			// preserve .conversion property if there is one
 
- 			if ('conversion' in fn) {
 
- 				wrappedFn.conversion = fn.conversion;
 
- 			}
 
- 			return wrappedFn;
 
- 		}
 
- 		models.forEach(function (fromModel) {
 
- 			convert[fromModel] = {};
 
- 			Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});
 
- 			Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});
 
- 			var routes = route(fromModel);
 
- 			var routeModels = Object.keys(routes);
 
- 			routeModels.forEach(function (toModel) {
 
- 				var fn = routes[toModel];
 
- 				convert[fromModel][toModel] = wrapRounded(fn);
 
- 				convert[fromModel][toModel].raw = wrapRaw(fn);
 
- 			});
 
- 		});
 
- 		var colorConvert = convert;
 
- 		var colorName$1 = {
 
- 			"aliceblue": [240, 248, 255],
 
- 			"antiquewhite": [250, 235, 215],
 
- 			"aqua": [0, 255, 255],
 
- 			"aquamarine": [127, 255, 212],
 
- 			"azure": [240, 255, 255],
 
- 			"beige": [245, 245, 220],
 
- 			"bisque": [255, 228, 196],
 
- 			"black": [0, 0, 0],
 
- 			"blanchedalmond": [255, 235, 205],
 
- 			"blue": [0, 0, 255],
 
- 			"blueviolet": [138, 43, 226],
 
- 			"brown": [165, 42, 42],
 
- 			"burlywood": [222, 184, 135],
 
- 			"cadetblue": [95, 158, 160],
 
- 			"chartreuse": [127, 255, 0],
 
- 			"chocolate": [210, 105, 30],
 
- 			"coral": [255, 127, 80],
 
- 			"cornflowerblue": [100, 149, 237],
 
- 			"cornsilk": [255, 248, 220],
 
- 			"crimson": [220, 20, 60],
 
- 			"cyan": [0, 255, 255],
 
- 			"darkblue": [0, 0, 139],
 
- 			"darkcyan": [0, 139, 139],
 
- 			"darkgoldenrod": [184, 134, 11],
 
- 			"darkgray": [169, 169, 169],
 
- 			"darkgreen": [0, 100, 0],
 
- 			"darkgrey": [169, 169, 169],
 
- 			"darkkhaki": [189, 183, 107],
 
- 			"darkmagenta": [139, 0, 139],
 
- 			"darkolivegreen": [85, 107, 47],
 
- 			"darkorange": [255, 140, 0],
 
- 			"darkorchid": [153, 50, 204],
 
- 			"darkred": [139, 0, 0],
 
- 			"darksalmon": [233, 150, 122],
 
- 			"darkseagreen": [143, 188, 143],
 
- 			"darkslateblue": [72, 61, 139],
 
- 			"darkslategray": [47, 79, 79],
 
- 			"darkslategrey": [47, 79, 79],
 
- 			"darkturquoise": [0, 206, 209],
 
- 			"darkviolet": [148, 0, 211],
 
- 			"deeppink": [255, 20, 147],
 
- 			"deepskyblue": [0, 191, 255],
 
- 			"dimgray": [105, 105, 105],
 
- 			"dimgrey": [105, 105, 105],
 
- 			"dodgerblue": [30, 144, 255],
 
- 			"firebrick": [178, 34, 34],
 
- 			"floralwhite": [255, 250, 240],
 
- 			"forestgreen": [34, 139, 34],
 
- 			"fuchsia": [255, 0, 255],
 
- 			"gainsboro": [220, 220, 220],
 
- 			"ghostwhite": [248, 248, 255],
 
- 			"gold": [255, 215, 0],
 
- 			"goldenrod": [218, 165, 32],
 
- 			"gray": [128, 128, 128],
 
- 			"green": [0, 128, 0],
 
- 			"greenyellow": [173, 255, 47],
 
- 			"grey": [128, 128, 128],
 
- 			"honeydew": [240, 255, 240],
 
- 			"hotpink": [255, 105, 180],
 
- 			"indianred": [205, 92, 92],
 
- 			"indigo": [75, 0, 130],
 
- 			"ivory": [255, 255, 240],
 
- 			"khaki": [240, 230, 140],
 
- 			"lavender": [230, 230, 250],
 
- 			"lavenderblush": [255, 240, 245],
 
- 			"lawngreen": [124, 252, 0],
 
- 			"lemonchiffon": [255, 250, 205],
 
- 			"lightblue": [173, 216, 230],
 
- 			"lightcoral": [240, 128, 128],
 
- 			"lightcyan": [224, 255, 255],
 
- 			"lightgoldenrodyellow": [250, 250, 210],
 
- 			"lightgray": [211, 211, 211],
 
- 			"lightgreen": [144, 238, 144],
 
- 			"lightgrey": [211, 211, 211],
 
- 			"lightpink": [255, 182, 193],
 
- 			"lightsalmon": [255, 160, 122],
 
- 			"lightseagreen": [32, 178, 170],
 
- 			"lightskyblue": [135, 206, 250],
 
- 			"lightslategray": [119, 136, 153],
 
- 			"lightslategrey": [119, 136, 153],
 
- 			"lightsteelblue": [176, 196, 222],
 
- 			"lightyellow": [255, 255, 224],
 
- 			"lime": [0, 255, 0],
 
- 			"limegreen": [50, 205, 50],
 
- 			"linen": [250, 240, 230],
 
- 			"magenta": [255, 0, 255],
 
- 			"maroon": [128, 0, 0],
 
- 			"mediumaquamarine": [102, 205, 170],
 
- 			"mediumblue": [0, 0, 205],
 
- 			"mediumorchid": [186, 85, 211],
 
- 			"mediumpurple": [147, 112, 219],
 
- 			"mediumseagreen": [60, 179, 113],
 
- 			"mediumslateblue": [123, 104, 238],
 
- 			"mediumspringgreen": [0, 250, 154],
 
- 			"mediumturquoise": [72, 209, 204],
 
- 			"mediumvioletred": [199, 21, 133],
 
- 			"midnightblue": [25, 25, 112],
 
- 			"mintcream": [245, 255, 250],
 
- 			"mistyrose": [255, 228, 225],
 
- 			"moccasin": [255, 228, 181],
 
- 			"navajowhite": [255, 222, 173],
 
- 			"navy": [0, 0, 128],
 
- 			"oldlace": [253, 245, 230],
 
- 			"olive": [128, 128, 0],
 
- 			"olivedrab": [107, 142, 35],
 
- 			"orange": [255, 165, 0],
 
- 			"orangered": [255, 69, 0],
 
- 			"orchid": [218, 112, 214],
 
- 			"palegoldenrod": [238, 232, 170],
 
- 			"palegreen": [152, 251, 152],
 
- 			"paleturquoise": [175, 238, 238],
 
- 			"palevioletred": [219, 112, 147],
 
- 			"papayawhip": [255, 239, 213],
 
- 			"peachpuff": [255, 218, 185],
 
- 			"peru": [205, 133, 63],
 
- 			"pink": [255, 192, 203],
 
- 			"plum": [221, 160, 221],
 
- 			"powderblue": [176, 224, 230],
 
- 			"purple": [128, 0, 128],
 
- 			"rebeccapurple": [102, 51, 153],
 
- 			"red": [255, 0, 0],
 
- 			"rosybrown": [188, 143, 143],
 
- 			"royalblue": [65, 105, 225],
 
- 			"saddlebrown": [139, 69, 19],
 
- 			"salmon": [250, 128, 114],
 
- 			"sandybrown": [244, 164, 96],
 
- 			"seagreen": [46, 139, 87],
 
- 			"seashell": [255, 245, 238],
 
- 			"sienna": [160, 82, 45],
 
- 			"silver": [192, 192, 192],
 
- 			"skyblue": [135, 206, 235],
 
- 			"slateblue": [106, 90, 205],
 
- 			"slategray": [112, 128, 144],
 
- 			"slategrey": [112, 128, 144],
 
- 			"snow": [255, 250, 250],
 
- 			"springgreen": [0, 255, 127],
 
- 			"steelblue": [70, 130, 180],
 
- 			"tan": [210, 180, 140],
 
- 			"teal": [0, 128, 128],
 
- 			"thistle": [216, 191, 216],
 
- 			"tomato": [255, 99, 71],
 
- 			"turquoise": [64, 224, 208],
 
- 			"violet": [238, 130, 238],
 
- 			"wheat": [245, 222, 179],
 
- 			"white": [255, 255, 255],
 
- 			"whitesmoke": [245, 245, 245],
 
- 			"yellow": [255, 255, 0],
 
- 			"yellowgreen": [154, 205, 50]
 
- 		};
 
- 		/* MIT license */
 
- 		var colorString = {
 
- 		   getRgba: getRgba,
 
- 		   getHsla: getHsla,
 
- 		   getRgb: getRgb,
 
- 		   getHsl: getHsl,
 
- 		   getHwb: getHwb,
 
- 		   getAlpha: getAlpha,
 
- 		   hexString: hexString,
 
- 		   rgbString: rgbString,
 
- 		   rgbaString: rgbaString,
 
- 		   percentString: percentString,
 
- 		   percentaString: percentaString,
 
- 		   hslString: hslString,
 
- 		   hslaString: hslaString,
 
- 		   hwbString: hwbString,
 
- 		   keyword: keyword
 
- 		};
 
- 		function getRgba(string) {
 
- 		   if (!string) {
 
- 		      return;
 
- 		   }
 
- 		   var abbr =  /^#([a-fA-F0-9]{3,4})$/i,
 
- 		       hex =  /^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i,
 
- 		       rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
 
- 		       per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
 
- 		       keyword = /(\w+)/;
 
- 		   var rgb = [0, 0, 0],
 
- 		       a = 1,
 
- 		       match = string.match(abbr),
 
- 		       hexAlpha = "";
 
- 		   if (match) {
 
- 		      match = match[1];
 
- 		      hexAlpha = match[3];
 
- 		      for (var i = 0; i < rgb.length; i++) {
 
- 		         rgb[i] = parseInt(match[i] + match[i], 16);
 
- 		      }
 
- 		      if (hexAlpha) {
 
- 		         a = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;
 
- 		      }
 
- 		   }
 
- 		   else if (match = string.match(hex)) {
 
- 		      hexAlpha = match[2];
 
- 		      match = match[1];
 
- 		      for (var i = 0; i < rgb.length; i++) {
 
- 		         rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
 
- 		      }
 
- 		      if (hexAlpha) {
 
- 		         a = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;
 
- 		      }
 
- 		   }
 
- 		   else if (match = string.match(rgba)) {
 
- 		      for (var i = 0; i < rgb.length; i++) {
 
- 		         rgb[i] = parseInt(match[i + 1]);
 
- 		      }
 
- 		      a = parseFloat(match[4]);
 
- 		   }
 
- 		   else if (match = string.match(per)) {
 
- 		      for (var i = 0; i < rgb.length; i++) {
 
- 		         rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
 
- 		      }
 
- 		      a = parseFloat(match[4]);
 
- 		   }
 
- 		   else if (match = string.match(keyword)) {
 
- 		      if (match[1] == "transparent") {
 
- 		         return [0, 0, 0, 0];
 
- 		      }
 
- 		      rgb = colorName$1[match[1]];
 
- 		      if (!rgb) {
 
- 		         return;
 
- 		      }
 
- 		   }
 
- 		   for (var i = 0; i < rgb.length; i++) {
 
- 		      rgb[i] = scale(rgb[i], 0, 255);
 
- 		   }
 
- 		   if (!a && a != 0) {
 
- 		      a = 1;
 
- 		   }
 
- 		   else {
 
- 		      a = scale(a, 0, 1);
 
- 		   }
 
- 		   rgb[3] = a;
 
- 		   return rgb;
 
- 		}
 
- 		function getHsla(string) {
 
- 		   if (!string) {
 
- 		      return;
 
- 		   }
 
- 		   var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
 
- 		   var match = string.match(hsl);
 
- 		   if (match) {
 
- 		      var alpha = parseFloat(match[4]);
 
- 		      var h = scale(parseInt(match[1]), 0, 360),
 
- 		          s = scale(parseFloat(match[2]), 0, 100),
 
- 		          l = scale(parseFloat(match[3]), 0, 100),
 
- 		          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
 
- 		      return [h, s, l, a];
 
- 		   }
 
- 		}
 
- 		function getHwb(string) {
 
- 		   if (!string) {
 
- 		      return;
 
- 		   }
 
- 		   var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
 
- 		   var match = string.match(hwb);
 
- 		   if (match) {
 
- 		    var alpha = parseFloat(match[4]);
 
- 		      var h = scale(parseInt(match[1]), 0, 360),
 
- 		          w = scale(parseFloat(match[2]), 0, 100),
 
- 		          b = scale(parseFloat(match[3]), 0, 100),
 
- 		          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
 
- 		      return [h, w, b, a];
 
- 		   }
 
- 		}
 
- 		function getRgb(string) {
 
- 		   var rgba = getRgba(string);
 
- 		   return rgba && rgba.slice(0, 3);
 
- 		}
 
- 		function getHsl(string) {
 
- 		  var hsla = getHsla(string);
 
- 		  return hsla && hsla.slice(0, 3);
 
- 		}
 
- 		function getAlpha(string) {
 
- 		   var vals = getRgba(string);
 
- 		   if (vals) {
 
- 		      return vals[3];
 
- 		   }
 
- 		   else if (vals = getHsla(string)) {
 
- 		      return vals[3];
 
- 		   }
 
- 		   else if (vals = getHwb(string)) {
 
- 		      return vals[3];
 
- 		   }
 
- 		}
 
- 		// generators
 
- 		function hexString(rgba, a) {
 
- 		   var a = (a !== undefined && rgba.length === 3) ? a : rgba[3];
 
- 		   return "#" + hexDouble(rgba[0]) 
 
- 		              + hexDouble(rgba[1])
 
- 		              + hexDouble(rgba[2])
 
- 		              + (
 
- 		                 (a >= 0 && a < 1)
 
- 		                 ? hexDouble(Math.round(a * 255))
 
- 		                 : ""
 
- 		              );
 
- 		}
 
- 		function rgbString(rgba, alpha) {
 
- 		   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
 
- 		      return rgbaString(rgba, alpha);
 
- 		   }
 
- 		   return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
 
- 		}
 
- 		function rgbaString(rgba, alpha) {
 
- 		   if (alpha === undefined) {
 
- 		      alpha = (rgba[3] !== undefined ? rgba[3] : 1);
 
- 		   }
 
- 		   return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
 
- 		           + ", " + alpha + ")";
 
- 		}
 
- 		function percentString(rgba, alpha) {
 
- 		   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
 
- 		      return percentaString(rgba, alpha);
 
- 		   }
 
- 		   var r = Math.round(rgba[0]/255 * 100),
 
- 		       g = Math.round(rgba[1]/255 * 100),
 
- 		       b = Math.round(rgba[2]/255 * 100);
 
- 		   return "rgb(" + r + "%, " + g + "%, " + b + "%)";
 
- 		}
 
- 		function percentaString(rgba, alpha) {
 
- 		   var r = Math.round(rgba[0]/255 * 100),
 
- 		       g = Math.round(rgba[1]/255 * 100),
 
- 		       b = Math.round(rgba[2]/255 * 100);
 
- 		   return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
 
- 		}
 
- 		function hslString(hsla, alpha) {
 
- 		   if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
 
- 		      return hslaString(hsla, alpha);
 
- 		   }
 
- 		   return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
 
- 		}
 
- 		function hslaString(hsla, alpha) {
 
- 		   if (alpha === undefined) {
 
- 		      alpha = (hsla[3] !== undefined ? hsla[3] : 1);
 
- 		   }
 
- 		   return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
 
- 		           + alpha + ")";
 
- 		}
 
- 		// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
 
- 		// (hwb have alpha optional & 1 is default value)
 
- 		function hwbString(hwb, alpha) {
 
- 		   if (alpha === undefined) {
 
- 		      alpha = (hwb[3] !== undefined ? hwb[3] : 1);
 
- 		   }
 
- 		   return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
 
- 		           + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
 
- 		}
 
- 		function keyword(rgb) {
 
- 		  return reverseNames[rgb.slice(0, 3)];
 
- 		}
 
- 		// helpers
 
- 		function scale(num, min, max) {
 
- 		   return Math.min(Math.max(min, num), max);
 
- 		}
 
- 		function hexDouble(num) {
 
- 		  var str = num.toString(16).toUpperCase();
 
- 		  return (str.length < 2) ? "0" + str : str;
 
- 		}
 
- 		//create a list of reverse color names
 
- 		var reverseNames = {};
 
- 		for (var name in colorName$1) {
 
- 		   reverseNames[colorName$1[name]] = name;
 
- 		}
 
- 		/* MIT license */
 
- 		var Color = function (obj) {
 
- 			if (obj instanceof Color) {
 
- 				return obj;
 
- 			}
 
- 			if (!(this instanceof Color)) {
 
- 				return new Color(obj);
 
- 			}
 
- 			this.valid = false;
 
- 			this.values = {
 
- 				rgb: [0, 0, 0],
 
- 				hsl: [0, 0, 0],
 
- 				hsv: [0, 0, 0],
 
- 				hwb: [0, 0, 0],
 
- 				cmyk: [0, 0, 0, 0],
 
- 				alpha: 1
 
- 			};
 
- 			// parse Color() argument
 
- 			var vals;
 
- 			if (typeof obj === 'string') {
 
- 				vals = colorString.getRgba(obj);
 
- 				if (vals) {
 
- 					this.setValues('rgb', vals);
 
- 				} else if (vals = colorString.getHsla(obj)) {
 
- 					this.setValues('hsl', vals);
 
- 				} else if (vals = colorString.getHwb(obj)) {
 
- 					this.setValues('hwb', vals);
 
- 				}
 
- 			} else if (typeof obj === 'object') {
 
- 				vals = obj;
 
- 				if (vals.r !== undefined || vals.red !== undefined) {
 
- 					this.setValues('rgb', vals);
 
- 				} else if (vals.l !== undefined || vals.lightness !== undefined) {
 
- 					this.setValues('hsl', vals);
 
- 				} else if (vals.v !== undefined || vals.value !== undefined) {
 
- 					this.setValues('hsv', vals);
 
- 				} else if (vals.w !== undefined || vals.whiteness !== undefined) {
 
- 					this.setValues('hwb', vals);
 
- 				} else if (vals.c !== undefined || vals.cyan !== undefined) {
 
- 					this.setValues('cmyk', vals);
 
- 				}
 
- 			}
 
- 		};
 
- 		Color.prototype = {
 
- 			isValid: function () {
 
- 				return this.valid;
 
- 			},
 
- 			rgb: function () {
 
- 				return this.setSpace('rgb', arguments);
 
- 			},
 
- 			hsl: function () {
 
- 				return this.setSpace('hsl', arguments);
 
- 			},
 
- 			hsv: function () {
 
- 				return this.setSpace('hsv', arguments);
 
- 			},
 
- 			hwb: function () {
 
- 				return this.setSpace('hwb', arguments);
 
- 			},
 
- 			cmyk: function () {
 
- 				return this.setSpace('cmyk', arguments);
 
- 			},
 
- 			rgbArray: function () {
 
- 				return this.values.rgb;
 
- 			},
 
- 			hslArray: function () {
 
- 				return this.values.hsl;
 
- 			},
 
- 			hsvArray: function () {
 
- 				return this.values.hsv;
 
- 			},
 
- 			hwbArray: function () {
 
- 				var values = this.values;
 
- 				if (values.alpha !== 1) {
 
- 					return values.hwb.concat([values.alpha]);
 
- 				}
 
- 				return values.hwb;
 
- 			},
 
- 			cmykArray: function () {
 
- 				return this.values.cmyk;
 
- 			},
 
- 			rgbaArray: function () {
 
- 				var values = this.values;
 
- 				return values.rgb.concat([values.alpha]);
 
- 			},
 
- 			hslaArray: function () {
 
- 				var values = this.values;
 
- 				return values.hsl.concat([values.alpha]);
 
- 			},
 
- 			alpha: function (val) {
 
- 				if (val === undefined) {
 
- 					return this.values.alpha;
 
- 				}
 
- 				this.setValues('alpha', val);
 
- 				return this;
 
- 			},
 
- 			red: function (val) {
 
- 				return this.setChannel('rgb', 0, val);
 
- 			},
 
- 			green: function (val) {
 
- 				return this.setChannel('rgb', 1, val);
 
- 			},
 
- 			blue: function (val) {
 
- 				return this.setChannel('rgb', 2, val);
 
- 			},
 
- 			hue: function (val) {
 
- 				if (val) {
 
- 					val %= 360;
 
- 					val = val < 0 ? 360 + val : val;
 
- 				}
 
- 				return this.setChannel('hsl', 0, val);
 
- 			},
 
- 			saturation: function (val) {
 
- 				return this.setChannel('hsl', 1, val);
 
- 			},
 
- 			lightness: function (val) {
 
- 				return this.setChannel('hsl', 2, val);
 
- 			},
 
- 			saturationv: function (val) {
 
- 				return this.setChannel('hsv', 1, val);
 
- 			},
 
- 			whiteness: function (val) {
 
- 				return this.setChannel('hwb', 1, val);
 
- 			},
 
- 			blackness: function (val) {
 
- 				return this.setChannel('hwb', 2, val);
 
- 			},
 
- 			value: function (val) {
 
- 				return this.setChannel('hsv', 2, val);
 
- 			},
 
- 			cyan: function (val) {
 
- 				return this.setChannel('cmyk', 0, val);
 
- 			},
 
- 			magenta: function (val) {
 
- 				return this.setChannel('cmyk', 1, val);
 
- 			},
 
- 			yellow: function (val) {
 
- 				return this.setChannel('cmyk', 2, val);
 
- 			},
 
- 			black: function (val) {
 
- 				return this.setChannel('cmyk', 3, val);
 
- 			},
 
- 			hexString: function () {
 
- 				return colorString.hexString(this.values.rgb);
 
- 			},
 
- 			rgbString: function () {
 
- 				return colorString.rgbString(this.values.rgb, this.values.alpha);
 
- 			},
 
- 			rgbaString: function () {
 
- 				return colorString.rgbaString(this.values.rgb, this.values.alpha);
 
- 			},
 
- 			percentString: function () {
 
- 				return colorString.percentString(this.values.rgb, this.values.alpha);
 
- 			},
 
- 			hslString: function () {
 
- 				return colorString.hslString(this.values.hsl, this.values.alpha);
 
- 			},
 
- 			hslaString: function () {
 
- 				return colorString.hslaString(this.values.hsl, this.values.alpha);
 
- 			},
 
- 			hwbString: function () {
 
- 				return colorString.hwbString(this.values.hwb, this.values.alpha);
 
- 			},
 
- 			keyword: function () {
 
- 				return colorString.keyword(this.values.rgb, this.values.alpha);
 
- 			},
 
- 			rgbNumber: function () {
 
- 				var rgb = this.values.rgb;
 
- 				return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
 
- 			},
 
- 			luminosity: function () {
 
- 				// http://www.w3.org/TR/WCAG20/#relativeluminancedef
 
- 				var rgb = this.values.rgb;
 
- 				var lum = [];
 
- 				for (var i = 0; i < rgb.length; i++) {
 
- 					var chan = rgb[i] / 255;
 
- 					lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
 
- 				}
 
- 				return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
 
- 			},
 
- 			contrast: function (color2) {
 
- 				// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
 
- 				var lum1 = this.luminosity();
 
- 				var lum2 = color2.luminosity();
 
- 				if (lum1 > lum2) {
 
- 					return (lum1 + 0.05) / (lum2 + 0.05);
 
- 				}
 
- 				return (lum2 + 0.05) / (lum1 + 0.05);
 
- 			},
 
- 			level: function (color2) {
 
- 				var contrastRatio = this.contrast(color2);
 
- 				if (contrastRatio >= 7.1) {
 
- 					return 'AAA';
 
- 				}
 
- 				return (contrastRatio >= 4.5) ? 'AA' : '';
 
- 			},
 
- 			dark: function () {
 
- 				// YIQ equation from http://24ways.org/2010/calculating-color-contrast
 
- 				var rgb = this.values.rgb;
 
- 				var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
 
- 				return yiq < 128;
 
- 			},
 
- 			light: function () {
 
- 				return !this.dark();
 
- 			},
 
- 			negate: function () {
 
- 				var rgb = [];
 
- 				for (var i = 0; i < 3; i++) {
 
- 					rgb[i] = 255 - this.values.rgb[i];
 
- 				}
 
- 				this.setValues('rgb', rgb);
 
- 				return this;
 
- 			},
 
- 			lighten: function (ratio) {
 
- 				var hsl = this.values.hsl;
 
- 				hsl[2] += hsl[2] * ratio;
 
- 				this.setValues('hsl', hsl);
 
- 				return this;
 
- 			},
 
- 			darken: function (ratio) {
 
- 				var hsl = this.values.hsl;
 
- 				hsl[2] -= hsl[2] * ratio;
 
- 				this.setValues('hsl', hsl);
 
- 				return this;
 
- 			},
 
- 			saturate: function (ratio) {
 
- 				var hsl = this.values.hsl;
 
- 				hsl[1] += hsl[1] * ratio;
 
- 				this.setValues('hsl', hsl);
 
- 				return this;
 
- 			},
 
- 			desaturate: function (ratio) {
 
- 				var hsl = this.values.hsl;
 
- 				hsl[1] -= hsl[1] * ratio;
 
- 				this.setValues('hsl', hsl);
 
- 				return this;
 
- 			},
 
- 			whiten: function (ratio) {
 
- 				var hwb = this.values.hwb;
 
- 				hwb[1] += hwb[1] * ratio;
 
- 				this.setValues('hwb', hwb);
 
- 				return this;
 
- 			},
 
- 			blacken: function (ratio) {
 
- 				var hwb = this.values.hwb;
 
- 				hwb[2] += hwb[2] * ratio;
 
- 				this.setValues('hwb', hwb);
 
- 				return this;
 
- 			},
 
- 			greyscale: function () {
 
- 				var rgb = this.values.rgb;
 
- 				// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
 
- 				var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
 
- 				this.setValues('rgb', [val, val, val]);
 
- 				return this;
 
- 			},
 
- 			clearer: function (ratio) {
 
- 				var alpha = this.values.alpha;
 
- 				this.setValues('alpha', alpha - (alpha * ratio));
 
- 				return this;
 
- 			},
 
- 			opaquer: function (ratio) {
 
- 				var alpha = this.values.alpha;
 
- 				this.setValues('alpha', alpha + (alpha * ratio));
 
- 				return this;
 
- 			},
 
- 			rotate: function (degrees) {
 
- 				var hsl = this.values.hsl;
 
- 				var hue = (hsl[0] + degrees) % 360;
 
- 				hsl[0] = hue < 0 ? 360 + hue : hue;
 
- 				this.setValues('hsl', hsl);
 
- 				return this;
 
- 			},
 
- 			/**
 
- 			 * Ported from sass implementation in C
 
- 			 * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
 
- 			 */
 
- 			mix: function (mixinColor, weight) {
 
- 				var color1 = this;
 
- 				var color2 = mixinColor;
 
- 				var p = weight === undefined ? 0.5 : weight;
 
- 				var w = 2 * p - 1;
 
- 				var a = color1.alpha() - color2.alpha();
 
- 				var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
 
- 				var w2 = 1 - w1;
 
- 				return this
 
- 					.rgb(
 
- 						w1 * color1.red() + w2 * color2.red(),
 
- 						w1 * color1.green() + w2 * color2.green(),
 
- 						w1 * color1.blue() + w2 * color2.blue()
 
- 					)
 
- 					.alpha(color1.alpha() * p + color2.alpha() * (1 - p));
 
- 			},
 
- 			toJSON: function () {
 
- 				return this.rgb();
 
- 			},
 
- 			clone: function () {
 
- 				// NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
 
- 				// making the final build way to big to embed in Chart.js. So let's do it manually,
 
- 				// assuming that values to clone are 1 dimension arrays containing only numbers,
 
- 				// except 'alpha' which is a number.
 
- 				var result = new Color();
 
- 				var source = this.values;
 
- 				var target = result.values;
 
- 				var value, type;
 
- 				for (var prop in source) {
 
- 					if (source.hasOwnProperty(prop)) {
 
- 						value = source[prop];
 
- 						type = ({}).toString.call(value);
 
- 						if (type === '[object Array]') {
 
- 							target[prop] = value.slice(0);
 
- 						} else if (type === '[object Number]') {
 
- 							target[prop] = value;
 
- 						} else {
 
- 							console.error('unexpected color value:', value);
 
- 						}
 
- 					}
 
- 				}
 
- 				return result;
 
- 			}
 
- 		};
 
- 		Color.prototype.spaces = {
 
- 			rgb: ['red', 'green', 'blue'],
 
- 			hsl: ['hue', 'saturation', 'lightness'],
 
- 			hsv: ['hue', 'saturation', 'value'],
 
- 			hwb: ['hue', 'whiteness', 'blackness'],
 
- 			cmyk: ['cyan', 'magenta', 'yellow', 'black']
 
- 		};
 
- 		Color.prototype.maxes = {
 
- 			rgb: [255, 255, 255],
 
- 			hsl: [360, 100, 100],
 
- 			hsv: [360, 100, 100],
 
- 			hwb: [360, 100, 100],
 
- 			cmyk: [100, 100, 100, 100]
 
- 		};
 
- 		Color.prototype.getValues = function (space) {
 
- 			var values = this.values;
 
- 			var vals = {};
 
- 			for (var i = 0; i < space.length; i++) {
 
- 				vals[space.charAt(i)] = values[space][i];
 
- 			}
 
- 			if (values.alpha !== 1) {
 
- 				vals.a = values.alpha;
 
- 			}
 
- 			// {r: 255, g: 255, b: 255, a: 0.4}
 
- 			return vals;
 
- 		};
 
- 		Color.prototype.setValues = function (space, vals) {
 
- 			var values = this.values;
 
- 			var spaces = this.spaces;
 
- 			var maxes = this.maxes;
 
- 			var alpha = 1;
 
- 			var i;
 
- 			this.valid = true;
 
- 			if (space === 'alpha') {
 
- 				alpha = vals;
 
- 			} else if (vals.length) {
 
- 				// [10, 10, 10]
 
- 				values[space] = vals.slice(0, space.length);
 
- 				alpha = vals[space.length];
 
- 			} else if (vals[space.charAt(0)] !== undefined) {
 
- 				// {r: 10, g: 10, b: 10}
 
- 				for (i = 0; i < space.length; i++) {
 
- 					values[space][i] = vals[space.charAt(i)];
 
- 				}
 
- 				alpha = vals.a;
 
- 			} else if (vals[spaces[space][0]] !== undefined) {
 
- 				// {red: 10, green: 10, blue: 10}
 
- 				var chans = spaces[space];
 
- 				for (i = 0; i < space.length; i++) {
 
- 					values[space][i] = vals[chans[i]];
 
- 				}
 
- 				alpha = vals.alpha;
 
- 			}
 
- 			values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
 
- 			if (space === 'alpha') {
 
- 				return false;
 
- 			}
 
- 			var capped;
 
- 			// cap values of the space prior converting all values
 
- 			for (i = 0; i < space.length; i++) {
 
- 				capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
 
- 				values[space][i] = Math.round(capped);
 
- 			}
 
- 			// convert to all the other color spaces
 
- 			for (var sname in spaces) {
 
- 				if (sname !== space) {
 
- 					values[sname] = colorConvert[space][sname](values[space]);
 
- 				}
 
- 			}
 
- 			return true;
 
- 		};
 
- 		Color.prototype.setSpace = function (space, args) {
 
- 			var vals = args[0];
 
- 			if (vals === undefined) {
 
- 				// color.rgb()
 
- 				return this.getValues(space);
 
- 			}
 
- 			// color.rgb(10, 10, 10)
 
- 			if (typeof vals === 'number') {
 
- 				vals = Array.prototype.slice.call(args);
 
- 			}
 
- 			this.setValues(space, vals);
 
- 			return this;
 
- 		};
 
- 		Color.prototype.setChannel = function (space, index, val) {
 
- 			var svalues = this.values[space];
 
- 			if (val === undefined) {
 
- 				// color.red()
 
- 				return svalues[index];
 
- 			} else if (val === svalues[index]) {
 
- 				// color.red(color.red())
 
- 				return this;
 
- 			}
 
- 			// color.red(100)
 
- 			svalues[index] = val;
 
- 			this.setValues(space, svalues);
 
- 			return this;
 
- 		};
 
- 		if (typeof window !== 'undefined') {
 
- 			window.Color = Color;
 
- 		}
 
- 		var chartjsColor = Color;
 
- 		function isValidKey(key) {
 
- 			return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1;
 
- 		}
 
- 		/**
 
- 		 * @namespace Chart.helpers
 
- 		 */
 
- 		var helpers = {
 
- 			/**
 
- 			 * An empty function that can be used, for example, for optional callback.
 
- 			 */
 
- 			noop: function() {},
 
- 			/**
 
- 			 * Returns a unique id, sequentially generated from a global variable.
 
- 			 * @returns {number}
 
- 			 * @function
 
- 			 */
 
- 			uid: (function() {
 
- 				var id = 0;
 
- 				return function() {
 
- 					return id++;
 
- 				};
 
- 			}()),
 
- 			/**
 
- 			 * Returns true if `value` is neither null nor undefined, else returns false.
 
- 			 * @param {*} value - The value to test.
 
- 			 * @returns {boolean}
 
- 			 * @since 2.7.0
 
- 			 */
 
- 			isNullOrUndef: function(value) {
 
- 				return value === null || typeof value === 'undefined';
 
- 			},
 
- 			/**
 
- 			 * Returns true if `value` is an array (including typed arrays), else returns false.
 
- 			 * @param {*} value - The value to test.
 
- 			 * @returns {boolean}
 
- 			 * @function
 
- 			 */
 
- 			isArray: function(value) {
 
- 				if (Array.isArray && Array.isArray(value)) {
 
- 					return true;
 
- 				}
 
- 				var type = Object.prototype.toString.call(value);
 
- 				if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {
 
- 					return true;
 
- 				}
 
- 				return false;
 
- 			},
 
- 			/**
 
- 			 * Returns true if `value` is an object (excluding null), else returns false.
 
- 			 * @param {*} value - The value to test.
 
- 			 * @returns {boolean}
 
- 			 * @since 2.7.0
 
- 			 */
 
- 			isObject: function(value) {
 
- 				return value !== null && Object.prototype.toString.call(value) === '[object Object]';
 
- 			},
 
- 			/**
 
- 			 * Returns true if `value` is a finite number, else returns false
 
- 			 * @param {*} value  - The value to test.
 
- 			 * @returns {boolean}
 
- 			 */
 
- 			isFinite: function(value) {
 
- 				return (typeof value === 'number' || value instanceof Number) && isFinite(value);
 
- 			},
 
- 			/**
 
- 			 * Returns `value` if defined, else returns `defaultValue`.
 
- 			 * @param {*} value - The value to return if defined.
 
- 			 * @param {*} defaultValue - The value to return if `value` is undefined.
 
- 			 * @returns {*}
 
- 			 */
 
- 			valueOrDefault: function(value, defaultValue) {
 
- 				return typeof value === 'undefined' ? defaultValue : value;
 
- 			},
 
- 			/**
 
- 			 * Returns value at the given `index` in array if defined, else returns `defaultValue`.
 
- 			 * @param {Array} value - The array to lookup for value at `index`.
 
- 			 * @param {number} index - The index in `value` to lookup for value.
 
- 			 * @param {*} defaultValue - The value to return if `value[index]` is undefined.
 
- 			 * @returns {*}
 
- 			 */
 
- 			valueAtIndexOrDefault: function(value, index, defaultValue) {
 
- 				return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
 
- 			},
 
- 			/**
 
- 			 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
 
- 			 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
 
- 			 * @param {function} fn - The function to call.
 
- 			 * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
 
- 			 * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
 
- 			 * @returns {*}
 
- 			 */
 
- 			callback: function(fn, args, thisArg) {
 
- 				if (fn && typeof fn.call === 'function') {
 
- 					return fn.apply(thisArg, args);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Note(SB) for performance sake, this method should only be used when loopable type
 
- 			 * is unknown or in none intensive code (not called often and small loopable). Else
 
- 			 * it's preferable to use a regular for() loop and save extra function calls.
 
- 			 * @param {object|Array} loopable - The object or array to be iterated.
 
- 			 * @param {function} fn - The function to call for each item.
 
- 			 * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
 
- 			 * @param {boolean} [reverse] - If true, iterates backward on the loopable.
 
- 			 */
 
- 			each: function(loopable, fn, thisArg, reverse) {
 
- 				var i, len, keys;
 
- 				if (helpers.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 (helpers.isObject(loopable)) {
 
- 					keys = Object.keys(loopable);
 
- 					len = keys.length;
 
- 					for (i = 0; i < len; i++) {
 
- 						fn.call(thisArg, loopable[keys[i]], keys[i]);
 
- 					}
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
 
- 			 * @see https://stackoverflow.com/a/14853974
 
- 			 * @param {Array} a0 - The array to compare
 
- 			 * @param {Array} a1 - The array to compare
 
- 			 * @returns {boolean}
 
- 			 */
 
- 			arrayEquals: function(a0, a1) {
 
- 				var 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 instanceof Array && v1 instanceof Array) {
 
- 						if (!helpers.arrayEquals(v0, v1)) {
 
- 							return false;
 
- 						}
 
- 					} else if (v0 !== v1) {
 
- 						// NOTE: two different object instances will never be equal: {x:20} != {x:20}
 
- 						return false;
 
- 					}
 
- 				}
 
- 				return true;
 
- 			},
 
- 			/**
 
- 			 * Returns a deep copy of `source` without keeping references on objects and arrays.
 
- 			 * @param {*} source - The value to clone.
 
- 			 * @returns {*}
 
- 			 */
 
- 			clone: function(source) {
 
- 				if (helpers.isArray(source)) {
 
- 					return source.map(helpers.clone);
 
- 				}
 
- 				if (helpers.isObject(source)) {
 
- 					var target = Object.create(source);
 
- 					var keys = Object.keys(source);
 
- 					var klen = keys.length;
 
- 					var k = 0;
 
- 					for (; k < klen; ++k) {
 
- 						target[keys[k]] = helpers.clone(source[keys[k]]);
 
- 					}
 
- 					return target;
 
- 				}
 
- 				return source;
 
- 			},
 
- 			/**
 
- 			 * The default merger when Chart.helpers.merge is called without merger option.
 
- 			 * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
 
- 			 * @private
 
- 			 */
 
- 			_merger: function(key, target, source, options) {
 
- 				if (!isValidKey(key)) {
 
- 					// We want to ensure we do not copy prototypes over
 
- 					// as this can pollute global namespaces
 
- 					return;
 
- 				}
 
- 				var tval = target[key];
 
- 				var sval = source[key];
 
- 				if (helpers.isObject(tval) && helpers.isObject(sval)) {
 
- 					helpers.merge(tval, sval, options);
 
- 				} else {
 
- 					target[key] = helpers.clone(sval);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Merges source[key] in target[key] only if target[key] is undefined.
 
- 			 * @private
 
- 			 */
 
- 			_mergerIf: function(key, target, source) {
 
- 				if (!isValidKey(key)) {
 
- 					// We want to ensure we do not copy prototypes over
 
- 					// as this can pollute global namespaces
 
- 					return;
 
- 				}
 
- 				var tval = target[key];
 
- 				var sval = source[key];
 
- 				if (helpers.isObject(tval) && helpers.isObject(sval)) {
 
- 					helpers.mergeIf(tval, sval);
 
- 				} else if (!target.hasOwnProperty(key)) {
 
- 					target[key] = helpers.clone(sval);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Recursively deep copies `source` properties into `target` with the given `options`.
 
- 			 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
 
- 			 * @param {object} target - The target object in which all sources are merged into.
 
- 			 * @param {object|object[]} source - Object(s) to merge into `target`.
 
- 			 * @param {object} [options] - Merging options:
 
- 			 * @param {function} [options.merger] - The merge method (key, target, source, options)
 
- 			 * @returns {object} The `target` object.
 
- 			 */
 
- 			merge: function(target, source, options) {
 
- 				var sources = helpers.isArray(source) ? source : [source];
 
- 				var ilen = sources.length;
 
- 				var merge, i, keys, klen, k;
 
- 				if (!helpers.isObject(target)) {
 
- 					return target;
 
- 				}
 
- 				options = options || {};
 
- 				merge = options.merger || helpers._merger;
 
- 				for (i = 0; i < ilen; ++i) {
 
- 					source = sources[i];
 
- 					if (!helpers.isObject(source)) {
 
- 						continue;
 
- 					}
 
- 					keys = Object.keys(source);
 
- 					for (k = 0, klen = keys.length; k < klen; ++k) {
 
- 						merge(keys[k], target, source, options);
 
- 					}
 
- 				}
 
- 				return target;
 
- 			},
 
- 			/**
 
- 			 * Recursively deep copies `source` properties into `target` *only* if not defined in target.
 
- 			 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
 
- 			 * @param {object} target - The target object in which all sources are merged into.
 
- 			 * @param {object|object[]} source - Object(s) to merge into `target`.
 
- 			 * @returns {object} The `target` object.
 
- 			 */
 
- 			mergeIf: function(target, source) {
 
- 				return helpers.merge(target, source, {merger: helpers._mergerIf});
 
- 			},
 
- 			/**
 
- 			 * Applies the contents of two or more objects together into the first object.
 
- 			 * @param {object} target - The target object in which all objects are merged into.
 
- 			 * @param {object} arg1 - Object containing additional properties to merge in target.
 
- 			 * @param {object} argN - Additional objects containing properties to merge in target.
 
- 			 * @returns {object} The `target` object.
 
- 			 */
 
- 			extend: Object.assign || function(target) {
 
- 				return helpers.merge(target, [].slice.call(arguments, 1), {
 
- 					merger: function(key, dst, src) {
 
- 						dst[key] = src[key];
 
- 					}
 
- 				});
 
- 			},
 
- 			/**
 
- 			 * Basic javascript inheritance based on the model created in Backbone.js
 
- 			 */
 
- 			inherits: function(extensions) {
 
- 				var me = this;
 
- 				var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
 
- 					return me.apply(this, arguments);
 
- 				};
 
- 				var Surrogate = function() {
 
- 					this.constructor = ChartElement;
 
- 				};
 
- 				Surrogate.prototype = me.prototype;
 
- 				ChartElement.prototype = new Surrogate();
 
- 				ChartElement.extend = helpers.inherits;
 
- 				if (extensions) {
 
- 					helpers.extend(ChartElement.prototype, extensions);
 
- 				}
 
- 				ChartElement.__super__ = me.prototype;
 
- 				return ChartElement;
 
- 			},
 
- 			_deprecated: function(scope, value, previous, current) {
 
- 				if (value !== undefined) {
 
- 					console.warn(scope + ': "' + previous +
 
- 						'" is deprecated. Please use "' + current + '" instead');
 
- 				}
 
- 			}
 
- 		};
 
- 		var helpers_core = helpers;
 
- 		// DEPRECATIONS
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.helpers.callback instead.
 
- 		 * @function Chart.helpers.callCallback
 
- 		 * @deprecated since version 2.6.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers.callCallback = helpers.callback;
 
- 		/**
 
- 		 * Provided for backward compatibility, use Array.prototype.indexOf instead.
 
- 		 * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
 
- 		 * @function Chart.helpers.indexOf
 
- 		 * @deprecated since version 2.7.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers.indexOf = function(array, item, fromIndex) {
 
- 			return Array.prototype.indexOf.call(array, item, fromIndex);
 
- 		};
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
 
- 		 * @function Chart.helpers.getValueOrDefault
 
- 		 * @deprecated since version 2.7.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers.getValueOrDefault = helpers.valueOrDefault;
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
 
- 		 * @function Chart.helpers.getValueAtIndexOrDefault
 
- 		 * @deprecated since version 2.7.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
 
- 		/**
 
- 		 * Easing functions adapted from Robert Penner's easing equations.
 
- 		 * @namespace Chart.helpers.easingEffects
 
- 		 * @see http://www.robertpenner.com/easing/
 
- 		 */
 
- 		var effects = {
 
- 			linear: function(t) {
 
- 				return t;
 
- 			},
 
- 			easeInQuad: function(t) {
 
- 				return t * t;
 
- 			},
 
- 			easeOutQuad: function(t) {
 
- 				return -t * (t - 2);
 
- 			},
 
- 			easeInOutQuad: function(t) {
 
- 				if ((t /= 0.5) < 1) {
 
- 					return 0.5 * t * t;
 
- 				}
 
- 				return -0.5 * ((--t) * (t - 2) - 1);
 
- 			},
 
- 			easeInCubic: function(t) {
 
- 				return t * t * t;
 
- 			},
 
- 			easeOutCubic: function(t) {
 
- 				return (t = t - 1) * t * t + 1;
 
- 			},
 
- 			easeInOutCubic: function(t) {
 
- 				if ((t /= 0.5) < 1) {
 
- 					return 0.5 * t * t * t;
 
- 				}
 
- 				return 0.5 * ((t -= 2) * t * t + 2);
 
- 			},
 
- 			easeInQuart: function(t) {
 
- 				return t * t * t * t;
 
- 			},
 
- 			easeOutQuart: function(t) {
 
- 				return -((t = t - 1) * t * t * t - 1);
 
- 			},
 
- 			easeInOutQuart: function(t) {
 
- 				if ((t /= 0.5) < 1) {
 
- 					return 0.5 * t * t * t * t;
 
- 				}
 
- 				return -0.5 * ((t -= 2) * t * t * t - 2);
 
- 			},
 
- 			easeInQuint: function(t) {
 
- 				return t * t * t * t * t;
 
- 			},
 
- 			easeOutQuint: function(t) {
 
- 				return (t = t - 1) * t * t * t * t + 1;
 
- 			},
 
- 			easeInOutQuint: function(t) {
 
- 				if ((t /= 0.5) < 1) {
 
- 					return 0.5 * t * t * t * t * t;
 
- 				}
 
- 				return 0.5 * ((t -= 2) * t * t * t * t + 2);
 
- 			},
 
- 			easeInSine: function(t) {
 
- 				return -Math.cos(t * (Math.PI / 2)) + 1;
 
- 			},
 
- 			easeOutSine: function(t) {
 
- 				return Math.sin(t * (Math.PI / 2));
 
- 			},
 
- 			easeInOutSine: function(t) {
 
- 				return -0.5 * (Math.cos(Math.PI * t) - 1);
 
- 			},
 
- 			easeInExpo: function(t) {
 
- 				return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
 
- 			},
 
- 			easeOutExpo: function(t) {
 
- 				return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
 
- 			},
 
- 			easeInOutExpo: function(t) {
 
- 				if (t === 0) {
 
- 					return 0;
 
- 				}
 
- 				if (t === 1) {
 
- 					return 1;
 
- 				}
 
- 				if ((t /= 0.5) < 1) {
 
- 					return 0.5 * Math.pow(2, 10 * (t - 1));
 
- 				}
 
- 				return 0.5 * (-Math.pow(2, -10 * --t) + 2);
 
- 			},
 
- 			easeInCirc: function(t) {
 
- 				if (t >= 1) {
 
- 					return t;
 
- 				}
 
- 				return -(Math.sqrt(1 - t * t) - 1);
 
- 			},
 
- 			easeOutCirc: function(t) {
 
- 				return Math.sqrt(1 - (t = t - 1) * t);
 
- 			},
 
- 			easeInOutCirc: function(t) {
 
- 				if ((t /= 0.5) < 1) {
 
- 					return -0.5 * (Math.sqrt(1 - t * t) - 1);
 
- 				}
 
- 				return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
 
- 			},
 
- 			easeInElastic: function(t) {
 
- 				var s = 1.70158;
 
- 				var p = 0;
 
- 				var a = 1;
 
- 				if (t === 0) {
 
- 					return 0;
 
- 				}
 
- 				if (t === 1) {
 
- 					return 1;
 
- 				}
 
- 				if (!p) {
 
- 					p = 0.3;
 
- 				}
 
- 				{
 
- 					s = p / (2 * Math.PI) * Math.asin(1 / a);
 
- 				}
 
- 				return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
 
- 			},
 
- 			easeOutElastic: function(t) {
 
- 				var s = 1.70158;
 
- 				var p = 0;
 
- 				var a = 1;
 
- 				if (t === 0) {
 
- 					return 0;
 
- 				}
 
- 				if (t === 1) {
 
- 					return 1;
 
- 				}
 
- 				if (!p) {
 
- 					p = 0.3;
 
- 				}
 
- 				{
 
- 					s = p / (2 * Math.PI) * Math.asin(1 / a);
 
- 				}
 
- 				return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
 
- 			},
 
- 			easeInOutElastic: function(t) {
 
- 				var s = 1.70158;
 
- 				var p = 0;
 
- 				var a = 1;
 
- 				if (t === 0) {
 
- 					return 0;
 
- 				}
 
- 				if ((t /= 0.5) === 2) {
 
- 					return 1;
 
- 				}
 
- 				if (!p) {
 
- 					p = 0.45;
 
- 				}
 
- 				{
 
- 					s = p / (2 * Math.PI) * Math.asin(1 / a);
 
- 				}
 
- 				if (t < 1) {
 
- 					return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
 
- 				}
 
- 				return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
 
- 			},
 
- 			easeInBack: function(t) {
 
- 				var s = 1.70158;
 
- 				return t * t * ((s + 1) * t - s);
 
- 			},
 
- 			easeOutBack: function(t) {
 
- 				var s = 1.70158;
 
- 				return (t = t - 1) * t * ((s + 1) * t + s) + 1;
 
- 			},
 
- 			easeInOutBack: function(t) {
 
- 				var 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: function(t) {
 
- 				return 1 - effects.easeOutBounce(1 - t);
 
- 			},
 
- 			easeOutBounce: function(t) {
 
- 				if (t < (1 / 2.75)) {
 
- 					return 7.5625 * t * t;
 
- 				}
 
- 				if (t < (2 / 2.75)) {
 
- 					return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
 
- 				}
 
- 				if (t < (2.5 / 2.75)) {
 
- 					return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
 
- 				}
 
- 				return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
 
- 			},
 
- 			easeInOutBounce: function(t) {
 
- 				if (t < 0.5) {
 
- 					return effects.easeInBounce(t * 2) * 0.5;
 
- 				}
 
- 				return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
 
- 			}
 
- 		};
 
- 		var helpers_easing = {
 
- 			effects: effects
 
- 		};
 
- 		// DEPRECATIONS
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
 
- 		 * @function Chart.helpers.easingEffects
 
- 		 * @deprecated since version 2.7.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers_core.easingEffects = effects;
 
- 		var PI = Math.PI;
 
- 		var RAD_PER_DEG = PI / 180;
 
- 		var DOUBLE_PI = PI * 2;
 
- 		var HALF_PI = PI / 2;
 
- 		var QUARTER_PI = PI / 4;
 
- 		var TWO_THIRDS_PI = PI * 2 / 3;
 
- 		/**
 
- 		 * @namespace Chart.helpers.canvas
 
- 		 */
 
- 		var exports$1 = {
 
- 			/**
 
- 			 * Clears the entire canvas associated to the given `chart`.
 
- 			 * @param {Chart} chart - The chart for which to clear the canvas.
 
- 			 */
 
- 			clear: function(chart) {
 
- 				chart.ctx.clearRect(0, 0, chart.width, chart.height);
 
- 			},
 
- 			/**
 
- 			 * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
 
- 			 * given size (width, height) and the same `radius` for all corners.
 
- 			 * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
 
- 			 * @param {number} x - The x axis of the coordinate for the rectangle starting point.
 
- 			 * @param {number} y - The y axis of the coordinate for the rectangle starting point.
 
- 			 * @param {number} width - The rectangle's width.
 
- 			 * @param {number} height - The rectangle's height.
 
- 			 * @param {number} radius - The rounded amount (in pixels) for the four corners.
 
- 			 * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
 
- 			 */
 
- 			roundedRect: function(ctx, x, y, width, height, radius) {
 
- 				if (radius) {
 
- 					var r = Math.min(radius, height / 2, width / 2);
 
- 					var left = x + r;
 
- 					var top = y + r;
 
- 					var right = x + width - r;
 
- 					var bottom = y + height - r;
 
- 					ctx.moveTo(x, top);
 
- 					if (left < right && top < bottom) {
 
- 						ctx.arc(left, top, r, -PI, -HALF_PI);
 
- 						ctx.arc(right, top, r, -HALF_PI, 0);
 
- 						ctx.arc(right, bottom, r, 0, HALF_PI);
 
- 						ctx.arc(left, bottom, r, HALF_PI, PI);
 
- 					} else if (left < right) {
 
- 						ctx.moveTo(left, y);
 
- 						ctx.arc(right, top, r, -HALF_PI, HALF_PI);
 
- 						ctx.arc(left, top, r, HALF_PI, PI + HALF_PI);
 
- 					} else if (top < bottom) {
 
- 						ctx.arc(left, top, r, -PI, 0);
 
- 						ctx.arc(left, bottom, r, 0, PI);
 
- 					} else {
 
- 						ctx.arc(left, top, r, -PI, PI);
 
- 					}
 
- 					ctx.closePath();
 
- 					ctx.moveTo(x, y);
 
- 				} else {
 
- 					ctx.rect(x, y, width, height);
 
- 				}
 
- 			},
 
- 			drawPoint: function(ctx, style, radius, x, y, rotation) {
 
- 				var type, xOffset, yOffset, size, cornerRadius;
 
- 				var 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 includes circle
 
- 				default:
 
- 					ctx.arc(x, y, radius, 0, DOUBLE_PI);
 
- 					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':
 
- 					// NOTE: the rounded rect implementation changed to use `arc` instead of
 
- 					// `quadraticCurveTo` since it generates better results when rect is
 
- 					// almost a circle. 0.516 (instead of 0.5) produces results with visually
 
- 					// closer proportion to the previous impl and it is inscribed in the
 
- 					// circle with `radius`. For more details, see the following PRs:
 
- 					// https://github.com/chartjs/Chart.js/issues/5597
 
- 					// https://github.com/chartjs/Chart.js/issues/5858
 
- 					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;
 
- 					/* falls through */
 
- 				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;
 
- 					/* falls through */
 
- 				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();
 
- 				ctx.stroke();
 
- 			},
 
- 			/**
 
- 			 * Returns true if the point is inside the rectangle
 
- 			 * @param {object} point - The point to test
 
- 			 * @param {object} area - The rectangle
 
- 			 * @returns {boolean}
 
- 			 * @private
 
- 			 */
 
- 			_isPointInArea: function(point, area) {
 
- 				var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
 
- 				return point.x > area.left - epsilon && point.x < area.right + epsilon &&
 
- 					point.y > area.top - epsilon && point.y < area.bottom + epsilon;
 
- 			},
 
- 			clipArea: function(ctx, area) {
 
- 				ctx.save();
 
- 				ctx.beginPath();
 
- 				ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
 
- 				ctx.clip();
 
- 			},
 
- 			unclipArea: function(ctx) {
 
- 				ctx.restore();
 
- 			},
 
- 			lineTo: function(ctx, previous, target, flip) {
 
- 				var stepped = target.steppedLine;
 
- 				if (stepped) {
 
- 					if (stepped === 'middle') {
 
- 						var midpoint = (previous.x + target.x) / 2.0;
 
- 						ctx.lineTo(midpoint, flip ? target.y : previous.y);
 
- 						ctx.lineTo(midpoint, flip ? previous.y : target.y);
 
- 					} else if ((stepped === 'after' && !flip) || (stepped !== 'after' && flip)) {
 
- 						ctx.lineTo(previous.x, target.y);
 
- 					} else {
 
- 						ctx.lineTo(target.x, previous.y);
 
- 					}
 
- 					ctx.lineTo(target.x, target.y);
 
- 					return;
 
- 				}
 
- 				if (!target.tension) {
 
- 					ctx.lineTo(target.x, target.y);
 
- 					return;
 
- 				}
 
- 				ctx.bezierCurveTo(
 
- 					flip ? previous.controlPointPreviousX : previous.controlPointNextX,
 
- 					flip ? previous.controlPointPreviousY : previous.controlPointNextY,
 
- 					flip ? target.controlPointNextX : target.controlPointPreviousX,
 
- 					flip ? target.controlPointNextY : target.controlPointPreviousY,
 
- 					target.x,
 
- 					target.y);
 
- 			}
 
- 		};
 
- 		var helpers_canvas = exports$1;
 
- 		// DEPRECATIONS
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
 
- 		 * @namespace Chart.helpers.clear
 
- 		 * @deprecated since version 2.7.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers_core.clear = exports$1.clear;
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
 
- 		 * @namespace Chart.helpers.drawRoundedRectangle
 
- 		 * @deprecated since version 2.7.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers_core.drawRoundedRectangle = function(ctx) {
 
- 			ctx.beginPath();
 
- 			exports$1.roundedRect.apply(exports$1, arguments);
 
- 		};
 
- 		var defaults = {
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_set: function(scope, values) {
 
- 				return helpers_core.merge(this[scope] || (this[scope] = {}), values);
 
- 			}
 
- 		};
 
- 		// TODO(v3): remove 'global' from namespace.  all default are global and
 
- 		// there's inconsistency around which options are under 'global'
 
- 		defaults._set('global', {
 
- 			defaultColor: 'rgba(0,0,0,0.1)',
 
- 			defaultFontColor: '#666',
 
- 			defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
 
- 			defaultFontSize: 12,
 
- 			defaultFontStyle: 'normal',
 
- 			defaultLineHeight: 1.2,
 
- 			showLines: true
 
- 		});
 
- 		var core_defaults = defaults;
 
- 		var valueOrDefault = helpers_core.valueOrDefault;
 
- 		/**
 
- 		 * Converts the given font object into a CSS font string.
 
- 		 * @param {object} font - A font object.
 
- 		 * @return {string} The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
 
- 		 * @private
 
- 		 */
 
- 		function toFontString(font) {
 
- 			if (!font || helpers_core.isNullOrUndef(font.size) || helpers_core.isNullOrUndef(font.family)) {
 
- 				return null;
 
- 			}
 
- 			return (font.style ? font.style + ' ' : '')
 
- 				+ (font.weight ? font.weight + ' ' : '')
 
- 				+ font.size + 'px '
 
- 				+ font.family;
 
- 		}
 
- 		/**
 
- 		 * @alias Chart.helpers.options
 
- 		 * @namespace
 
- 		 */
 
- 		var helpers_options = {
 
- 			/**
 
- 			 * Converts the given line height `value` in pixels for a specific font `size`.
 
- 			 * @param {number|string} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
 
- 			 * @param {number} size - The font size (in pixels) used to resolve relative `value`.
 
- 			 * @returns {number} The effective line height in pixels (size * 1.2 if value is invalid).
 
- 			 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
 
- 			 * @since 2.7.0
 
- 			 */
 
- 			toLineHeight: function(value, size) {
 
- 				var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
 
- 				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;
 
- 			},
 
- 			/**
 
- 			 * Converts the given value into a padding object with pre-computed width/height.
 
- 			 * @param {number|object} value - If a number, set the value to all TRBL component,
 
- 			 *  else, if and object, use defined properties and sets undefined ones to 0.
 
- 			 * @returns {object} The padding values (top, right, bottom, left, width, height)
 
- 			 * @since 2.7.0
 
- 			 */
 
- 			toPadding: function(value) {
 
- 				var t, r, b, l;
 
- 				if (helpers_core.isObject(value)) {
 
- 					t = +value.top || 0;
 
- 					r = +value.right || 0;
 
- 					b = +value.bottom || 0;
 
- 					l = +value.left || 0;
 
- 				} else {
 
- 					t = r = b = l = +value || 0;
 
- 				}
 
- 				return {
 
- 					top: t,
 
- 					right: r,
 
- 					bottom: b,
 
- 					left: l,
 
- 					height: t + b,
 
- 					width: l + r
 
- 				};
 
- 			},
 
- 			/**
 
- 			 * Parses font options and returns the font object.
 
- 			 * @param {object} options - A object that contains font options to be parsed.
 
- 			 * @return {object} The font object.
 
- 			 * @todo Support font.* options and renamed to toFont().
 
- 			 * @private
 
- 			 */
 
- 			_parseFont: function(options) {
 
- 				var globalDefaults = core_defaults.global;
 
- 				var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
 
- 				var font = {
 
- 					family: valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily),
 
- 					lineHeight: helpers_core.options.toLineHeight(valueOrDefault(options.lineHeight, globalDefaults.defaultLineHeight), size),
 
- 					size: size,
 
- 					style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle),
 
- 					weight: null,
 
- 					string: ''
 
- 				};
 
- 				font.string = toFontString(font);
 
- 				return font;
 
- 			},
 
- 			/**
 
- 			 * Evaluates the given `inputs` sequentially and returns the first defined value.
 
- 			 * @param {Array} inputs - An array of values, falling back to the last value.
 
- 			 * @param {object} [context] - If defined and the current value is a function, the value
 
- 			 * is called with `context` as first argument and the result becomes the new input.
 
- 			 * @param {number} [index] - If defined and the current value is an array, the value
 
- 			 * at `index` become the new input.
 
- 			 * @param {object} [info] - object to return information about resolution in
 
- 			 * @param {boolean} [info.cacheable] - Will be set to `false` if option is not cacheable.
 
- 			 * @since 2.7.0
 
- 			 */
 
- 			resolve: function(inputs, context, index, info) {
 
- 				var cacheable = true;
 
- 				var 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 && helpers_core.isArray(value)) {
 
- 						value = value[index];
 
- 						cacheable = false;
 
- 					}
 
- 					if (value !== undefined) {
 
- 						if (info && !cacheable) {
 
- 							info.cacheable = false;
 
- 						}
 
- 						return value;
 
- 					}
 
- 				}
 
- 			}
 
- 		};
 
- 		/**
 
- 		 * @alias Chart.helpers.math
 
- 		 * @namespace
 
- 		 */
 
- 		var exports$2 = {
 
- 			/**
 
- 			 * Returns an array of factors sorted from 1 to sqrt(value)
 
- 			 * @private
 
- 			 */
 
- 			_factorize: function(value) {
 
- 				var result = [];
 
- 				var sqrt = Math.sqrt(value);
 
- 				var i;
 
- 				for (i = 1; i < sqrt; i++) {
 
- 					if (value % i === 0) {
 
- 						result.push(i);
 
- 						result.push(value / i);
 
- 					}
 
- 				}
 
- 				if (sqrt === (sqrt | 0)) { // if value is a square number
 
- 					result.push(sqrt);
 
- 				}
 
- 				result.sort(function(a, b) {
 
- 					return a - b;
 
- 				}).pop();
 
- 				return result;
 
- 			},
 
- 			log10: Math.log10 || function(x) {
 
- 				var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
 
- 				// Check for whole powers of 10,
 
- 				// which due to floating point rounding error should be corrected.
 
- 				var powerOf10 = Math.round(exponent);
 
- 				var isPowerOf10 = x === Math.pow(10, powerOf10);
 
- 				return isPowerOf10 ? powerOf10 : exponent;
 
- 			}
 
- 		};
 
- 		var helpers_math = exports$2;
 
- 		// DEPRECATIONS
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.helpers.math.log10 instead.
 
- 		 * @namespace Chart.helpers.log10
 
- 		 * @deprecated since version 2.9.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers_core.log10 = exports$2.log10;
 
- 		var getRtlAdapter = function(rectX, width) {
 
- 			return {
 
- 				x: function(x) {
 
- 					return rectX + rectX + width - x;
 
- 				},
 
- 				setWidth: function(w) {
 
- 					width = w;
 
- 				},
 
- 				textAlign: function(align) {
 
- 					if (align === 'center') {
 
- 						return align;
 
- 					}
 
- 					return align === 'right' ? 'left' : 'right';
 
- 				},
 
- 				xPlus: function(x, value) {
 
- 					return x - value;
 
- 				},
 
- 				leftForLtr: function(x, itemWidth) {
 
- 					return x - itemWidth;
 
- 				},
 
- 			};
 
- 		};
 
- 		var getLtrAdapter = function() {
 
- 			return {
 
- 				x: function(x) {
 
- 					return x;
 
- 				},
 
- 				setWidth: function(w) { // eslint-disable-line no-unused-vars
 
- 				},
 
- 				textAlign: function(align) {
 
- 					return align;
 
- 				},
 
- 				xPlus: function(x, value) {
 
- 					return x + value;
 
- 				},
 
- 				leftForLtr: function(x, _itemWidth) { // eslint-disable-line no-unused-vars
 
- 					return x;
 
- 				},
 
- 			};
 
- 		};
 
- 		var getAdapter = function(rtl, rectX, width) {
 
- 			return rtl ? getRtlAdapter(rectX, width) : getLtrAdapter();
 
- 		};
 
- 		var overrideTextDirection = function(ctx, direction) {
 
- 			var 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;
 
- 			}
 
- 		};
 
- 		var restoreTextDirection = function(ctx) {
 
- 			var original = ctx.prevTextDirection;
 
- 			if (original !== undefined) {
 
- 				delete ctx.prevTextDirection;
 
- 				ctx.canvas.style.setProperty('direction', original[0], original[1]);
 
- 			}
 
- 		};
 
- 		var helpers_rtl = {
 
- 			getRtlAdapter: getAdapter,
 
- 			overrideTextDirection: overrideTextDirection,
 
- 			restoreTextDirection: restoreTextDirection,
 
- 		};
 
- 		var helpers$1 = helpers_core;
 
- 		var easing = helpers_easing;
 
- 		var canvas = helpers_canvas;
 
- 		var options = helpers_options;
 
- 		var math = helpers_math;
 
- 		var rtl = helpers_rtl;
 
- 		helpers$1.easing = easing;
 
- 		helpers$1.canvas = canvas;
 
- 		helpers$1.options = options;
 
- 		helpers$1.math = math;
 
- 		helpers$1.rtl = rtl;
 
- 		function interpolate(start, view, model, ease) {
 
- 			var keys = Object.keys(model);
 
- 			var i, ilen, key, actual, origin, target, type, c0, c1;
 
- 			for (i = 0, ilen = keys.length; i < ilen; ++i) {
 
- 				key = keys[i];
 
- 				target = model[key];
 
- 				// if a value is added to the model after pivot() has been called, the view
 
- 				// doesn't contain it, so let's initialize the view to the target value.
 
- 				if (!view.hasOwnProperty(key)) {
 
- 					view[key] = target;
 
- 				}
 
- 				actual = view[key];
 
- 				if (actual === target || key[0] === '_') {
 
- 					continue;
 
- 				}
 
- 				if (!start.hasOwnProperty(key)) {
 
- 					start[key] = actual;
 
- 				}
 
- 				origin = start[key];
 
- 				type = typeof target;
 
- 				if (type === typeof origin) {
 
- 					if (type === 'string') {
 
- 						c0 = chartjsColor(origin);
 
- 						if (c0.valid) {
 
- 							c1 = chartjsColor(target);
 
- 							if (c1.valid) {
 
- 								view[key] = c1.mix(c0, ease).rgbString();
 
- 								continue;
 
- 							}
 
- 						}
 
- 					} else if (helpers$1.isFinite(origin) && helpers$1.isFinite(target)) {
 
- 						view[key] = origin + (target - origin) * ease;
 
- 						continue;
 
- 					}
 
- 				}
 
- 				view[key] = target;
 
- 			}
 
- 		}
 
- 		var Element = function(configuration) {
 
- 			helpers$1.extend(this, configuration);
 
- 			this.initialize.apply(this, arguments);
 
- 		};
 
- 		helpers$1.extend(Element.prototype, {
 
- 			_type: undefined,
 
- 			initialize: function() {
 
- 				this.hidden = false;
 
- 			},
 
- 			pivot: function() {
 
- 				var me = this;
 
- 				if (!me._view) {
 
- 					me._view = helpers$1.extend({}, me._model);
 
- 				}
 
- 				me._start = {};
 
- 				return me;
 
- 			},
 
- 			transition: function(ease) {
 
- 				var me = this;
 
- 				var model = me._model;
 
- 				var start = me._start;
 
- 				var view = me._view;
 
- 				// No animation -> No Transition
 
- 				if (!model || ease === 1) {
 
- 					me._view = helpers$1.extend({}, model);
 
- 					me._start = null;
 
- 					return me;
 
- 				}
 
- 				if (!view) {
 
- 					view = me._view = {};
 
- 				}
 
- 				if (!start) {
 
- 					start = me._start = {};
 
- 				}
 
- 				interpolate(start, view, model, ease);
 
- 				return me;
 
- 			},
 
- 			tooltipPosition: function() {
 
- 				return {
 
- 					x: this._model.x,
 
- 					y: this._model.y
 
- 				};
 
- 			},
 
- 			hasValue: function() {
 
- 				return helpers$1.isNumber(this._model.x) && helpers$1.isNumber(this._model.y);
 
- 			}
 
- 		});
 
- 		Element.extend = helpers$1.inherits;
 
- 		var core_element = Element;
 
- 		var exports$3 = core_element.extend({
 
- 			chart: null, // the animation associated chart instance
 
- 			currentStep: 0, // the current animation step
 
- 			numSteps: 60, // default number of steps
 
- 			easing: '', // the easing to use for this animation
 
- 			render: null, // render function used by the animation service
 
- 			onAnimationProgress: null, // user specified callback to fire on each step of the animation
 
- 			onAnimationComplete: null, // user specified callback to fire when the animation finishes
 
- 		});
 
- 		var core_animation = exports$3;
 
- 		// DEPRECATIONS
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.Animation instead
 
- 		 * @prop Chart.Animation#animationObject
 
- 		 * @deprecated since version 2.6.0
 
- 		 * @todo remove at version 3
 
- 		 */
 
- 		Object.defineProperty(exports$3.prototype, 'animationObject', {
 
- 			get: function() {
 
- 				return this;
 
- 			}
 
- 		});
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.Animation#chart instead
 
- 		 * @prop Chart.Animation#chartInstance
 
- 		 * @deprecated since version 2.6.0
 
- 		 * @todo remove at version 3
 
- 		 */
 
- 		Object.defineProperty(exports$3.prototype, 'chartInstance', {
 
- 			get: function() {
 
- 				return this.chart;
 
- 			},
 
- 			set: function(value) {
 
- 				this.chart = value;
 
- 			}
 
- 		});
 
- 		core_defaults._set('global', {
 
- 			animation: {
 
- 				duration: 1000,
 
- 				easing: 'easeOutQuart',
 
- 				onProgress: helpers$1.noop,
 
- 				onComplete: helpers$1.noop
 
- 			}
 
- 		});
 
- 		var core_animations = {
 
- 			animations: [],
 
- 			request: null,
 
- 			/**
 
- 			 * @param {Chart} chart - The chart to animate.
 
- 			 * @param {Chart.Animation} animation - The animation that we will animate.
 
- 			 * @param {number} duration - The animation duration in ms.
 
- 			 * @param {boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
 
- 			 */
 
- 			addAnimation: function(chart, animation, duration, lazy) {
 
- 				var animations = this.animations;
 
- 				var i, ilen;
 
- 				animation.chart = chart;
 
- 				animation.startTime = Date.now();
 
- 				animation.duration = duration;
 
- 				if (!lazy) {
 
- 					chart.animating = true;
 
- 				}
 
- 				for (i = 0, ilen = animations.length; i < ilen; ++i) {
 
- 					if (animations[i].chart === chart) {
 
- 						animations[i] = animation;
 
- 						return;
 
- 					}
 
- 				}
 
- 				animations.push(animation);
 
- 				// If there are no animations queued, manually kickstart a digest, for lack of a better word
 
- 				if (animations.length === 1) {
 
- 					this.requestAnimationFrame();
 
- 				}
 
- 			},
 
- 			cancelAnimation: function(chart) {
 
- 				var index = helpers$1.findIndex(this.animations, function(animation) {
 
- 					return animation.chart === chart;
 
- 				});
 
- 				if (index !== -1) {
 
- 					this.animations.splice(index, 1);
 
- 					chart.animating = false;
 
- 				}
 
- 			},
 
- 			requestAnimationFrame: function() {
 
- 				var me = this;
 
- 				if (me.request === null) {
 
- 					// Skip animation frame requests until the active one is executed.
 
- 					// This can happen when processing mouse events, e.g. 'mousemove'
 
- 					// and 'mouseout' events will trigger multiple renders.
 
- 					me.request = helpers$1.requestAnimFrame.call(window, function() {
 
- 						me.request = null;
 
- 						me.startDigest();
 
- 					});
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			startDigest: function() {
 
- 				var me = this;
 
- 				me.advance();
 
- 				// Do we have more stuff to animate?
 
- 				if (me.animations.length > 0) {
 
- 					me.requestAnimationFrame();
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			advance: function() {
 
- 				var animations = this.animations;
 
- 				var animation, chart, numSteps, nextStep;
 
- 				var i = 0;
 
- 				// 1 animation per chart, so we are looping charts here
 
- 				while (i < animations.length) {
 
- 					animation = animations[i];
 
- 					chart = animation.chart;
 
- 					numSteps = animation.numSteps;
 
- 					// Make sure that currentStep starts at 1
 
- 					// https://github.com/chartjs/Chart.js/issues/6104
 
- 					nextStep = Math.floor((Date.now() - animation.startTime) / animation.duration * numSteps) + 1;
 
- 					animation.currentStep = Math.min(nextStep, numSteps);
 
- 					helpers$1.callback(animation.render, [chart, animation], chart);
 
- 					helpers$1.callback(animation.onAnimationProgress, [animation], chart);
 
- 					if (animation.currentStep >= numSteps) {
 
- 						helpers$1.callback(animation.onAnimationComplete, [animation], chart);
 
- 						chart.animating = false;
 
- 						animations.splice(i, 1);
 
- 					} else {
 
- 						++i;
 
- 					}
 
- 				}
 
- 			}
 
- 		};
 
- 		var resolve = helpers$1.options.resolve;
 
- 		var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
 
- 		/**
 
- 		 * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
 
- 		 * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
 
- 		 * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
 
- 		 */
 
- 		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(function(key) {
 
- 				var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
 
- 				var base = array[key];
 
- 				Object.defineProperty(array, key, {
 
- 					configurable: true,
 
- 					enumerable: false,
 
- 					value: function() {
 
- 						var args = Array.prototype.slice.call(arguments);
 
- 						var res = base.apply(this, args);
 
- 						helpers$1.each(array._chartjs.listeners, function(object) {
 
- 							if (typeof object[method] === 'function') {
 
- 								object[method].apply(object, args);
 
- 							}
 
- 						});
 
- 						return res;
 
- 					}
 
- 				});
 
- 			});
 
- 		}
 
- 		/**
 
- 		 * Removes the given array event listener and cleanup extra attached properties (such as
 
- 		 * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
 
- 		 */
 
- 		function unlistenArrayEvents(array, listener) {
 
- 			var stub = array._chartjs;
 
- 			if (!stub) {
 
- 				return;
 
- 			}
 
- 			var listeners = stub.listeners;
 
- 			var index = listeners.indexOf(listener);
 
- 			if (index !== -1) {
 
- 				listeners.splice(index, 1);
 
- 			}
 
- 			if (listeners.length > 0) {
 
- 				return;
 
- 			}
 
- 			arrayEvents.forEach(function(key) {
 
- 				delete array[key];
 
- 			});
 
- 			delete array._chartjs;
 
- 		}
 
- 		// Base class for all dataset controllers (line, bar, etc)
 
- 		var DatasetController = function(chart, datasetIndex) {
 
- 			this.initialize(chart, datasetIndex);
 
- 		};
 
- 		helpers$1.extend(DatasetController.prototype, {
 
- 			/**
 
- 			 * Element type used to generate a meta dataset (e.g. Chart.element.Line).
 
- 			 * @type {Chart.core.element}
 
- 			 */
 
- 			datasetElementType: null,
 
- 			/**
 
- 			 * Element type used to generate a meta data (e.g. Chart.element.Point).
 
- 			 * @type {Chart.core.element}
 
- 			 */
 
- 			dataElementType: null,
 
- 			/**
 
- 			 * Dataset element option keys to be resolved in _resolveDatasetElementOptions.
 
- 			 * A derived controller may override this to resolve controller-specific options.
 
- 			 * The keys defined here are for backward compatibility for legend styles.
 
- 			 * @private
 
- 			 */
 
- 			_datasetElementOptions: [
 
- 				'backgroundColor',
 
- 				'borderCapStyle',
 
- 				'borderColor',
 
- 				'borderDash',
 
- 				'borderDashOffset',
 
- 				'borderJoinStyle',
 
- 				'borderWidth'
 
- 			],
 
- 			/**
 
- 			 * Data element option keys to be resolved in _resolveDataElementOptions.
 
- 			 * A derived controller may override this to resolve controller-specific options.
 
- 			 * The keys defined here are for backward compatibility for legend styles.
 
- 			 * @private
 
- 			 */
 
- 			_dataElementOptions: [
 
- 				'backgroundColor',
 
- 				'borderColor',
 
- 				'borderWidth',
 
- 				'pointStyle'
 
- 			],
 
- 			initialize: function(chart, datasetIndex) {
 
- 				var me = this;
 
- 				me.chart = chart;
 
- 				me.index = datasetIndex;
 
- 				me.linkScales();
 
- 				me.addElements();
 
- 				me._type = me.getMeta().type;
 
- 			},
 
- 			updateIndex: function(datasetIndex) {
 
- 				this.index = datasetIndex;
 
- 			},
 
- 			linkScales: function() {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var chart = me.chart;
 
- 				var scales = chart.scales;
 
- 				var dataset = me.getDataset();
 
- 				var scalesOpts = chart.options.scales;
 
- 				if (meta.xAxisID === null || !(meta.xAxisID in scales) || dataset.xAxisID) {
 
- 					meta.xAxisID = dataset.xAxisID || scalesOpts.xAxes[0].id;
 
- 				}
 
- 				if (meta.yAxisID === null || !(meta.yAxisID in scales) || dataset.yAxisID) {
 
- 					meta.yAxisID = dataset.yAxisID || scalesOpts.yAxes[0].id;
 
- 				}
 
- 			},
 
- 			getDataset: function() {
 
- 				return this.chart.data.datasets[this.index];
 
- 			},
 
- 			getMeta: function() {
 
- 				return this.chart.getDatasetMeta(this.index);
 
- 			},
 
- 			getScaleForId: function(scaleID) {
 
- 				return this.chart.scales[scaleID];
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getValueScaleId: function() {
 
- 				return this.getMeta().yAxisID;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getIndexScaleId: function() {
 
- 				return this.getMeta().xAxisID;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getValueScale: function() {
 
- 				return this.getScaleForId(this._getValueScaleId());
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getIndexScale: function() {
 
- 				return this.getScaleForId(this._getIndexScaleId());
 
- 			},
 
- 			reset: function() {
 
- 				this._update(true);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			destroy: function() {
 
- 				if (this._data) {
 
- 					unlistenArrayEvents(this._data, this);
 
- 				}
 
- 			},
 
- 			createMetaDataset: function() {
 
- 				var me = this;
 
- 				var type = me.datasetElementType;
 
- 				return type && new type({
 
- 					_chart: me.chart,
 
- 					_datasetIndex: me.index
 
- 				});
 
- 			},
 
- 			createMetaData: function(index) {
 
- 				var me = this;
 
- 				var type = me.dataElementType;
 
- 				return type && new type({
 
- 					_chart: me.chart,
 
- 					_datasetIndex: me.index,
 
- 					_index: index
 
- 				});
 
- 			},
 
- 			addElements: function() {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var data = me.getDataset().data || [];
 
- 				var metaData = meta.data;
 
- 				var i, ilen;
 
- 				for (i = 0, ilen = data.length; i < ilen; ++i) {
 
- 					metaData[i] = metaData[i] || me.createMetaData(i);
 
- 				}
 
- 				meta.dataset = meta.dataset || me.createMetaDataset();
 
- 			},
 
- 			addElementAndReset: function(index) {
 
- 				var element = this.createMetaData(index);
 
- 				this.getMeta().data.splice(index, 0, element);
 
- 				this.updateElement(element, index, true);
 
- 			},
 
- 			buildOrUpdateElements: function() {
 
- 				var me = this;
 
- 				var dataset = me.getDataset();
 
- 				var data = dataset.data || (dataset.data = []);
 
- 				// In order to correctly handle data addition/deletion animation (an thus simulate
 
- 				// real-time charts), we need to monitor these data modifications and synchronize
 
- 				// the internal meta data accordingly.
 
- 				if (me._data !== data) {
 
- 					if (me._data) {
 
- 						// This case happens when the user replaced the data array instance.
 
- 						unlistenArrayEvents(me._data, me);
 
- 					}
 
- 					if (data && Object.isExtensible(data)) {
 
- 						listenArrayEvents(data, me);
 
- 					}
 
- 					me._data = data;
 
- 				}
 
- 				// Re-sync meta data in case the user replaced the data array or if we missed
 
- 				// any updates and so make sure that we handle number of datapoints changing.
 
- 				me.resyncElements();
 
- 			},
 
- 			/**
 
- 			 * Returns the merged user-supplied and default dataset-level options
 
- 			 * @private
 
- 			 */
 
- 			_configure: function() {
 
- 				var me = this;
 
- 				me._config = helpers$1.merge(Object.create(null), [
 
- 					me.chart.options.datasets[me._type],
 
- 					me.getDataset(),
 
- 				], {
 
- 					merger: function(key, target, source) {
 
- 						if (key !== '_meta' && key !== 'data') {
 
- 							helpers$1._merger(key, target, source);
 
- 						}
 
- 					}
 
- 				});
 
- 			},
 
- 			_update: function(reset) {
 
- 				var me = this;
 
- 				me._configure();
 
- 				me._cachedDataOpts = null;
 
- 				me.update(reset);
 
- 			},
 
- 			update: helpers$1.noop,
 
- 			transition: function(easingValue) {
 
- 				var meta = this.getMeta();
 
- 				var elements = meta.data || [];
 
- 				var ilen = elements.length;
 
- 				var i = 0;
 
- 				for (; i < ilen; ++i) {
 
- 					elements[i].transition(easingValue);
 
- 				}
 
- 				if (meta.dataset) {
 
- 					meta.dataset.transition(easingValue);
 
- 				}
 
- 			},
 
- 			draw: function() {
 
- 				var meta = this.getMeta();
 
- 				var elements = meta.data || [];
 
- 				var ilen = elements.length;
 
- 				var i = 0;
 
- 				if (meta.dataset) {
 
- 					meta.dataset.draw();
 
- 				}
 
- 				for (; i < ilen; ++i) {
 
- 					elements[i].draw();
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Returns a set of predefined style properties that should be used to represent the dataset
 
- 			 * or the data if the index is specified
 
- 			 * @param {number} index - data index
 
- 			 * @return {IStyleInterface} style object
 
- 			 */
 
- 			getStyle: function(index) {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var dataset = meta.dataset;
 
- 				var style;
 
- 				me._configure();
 
- 				if (dataset && index === undefined) {
 
- 					style = me._resolveDatasetElementOptions(dataset || {});
 
- 				} else {
 
- 					index = index || 0;
 
- 					style = me._resolveDataElementOptions(meta.data[index] || {}, index);
 
- 				}
 
- 				if (style.fill === false || style.fill === null) {
 
- 					style.backgroundColor = style.borderColor;
 
- 				}
 
- 				return style;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_resolveDatasetElementOptions: function(element, hover) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var datasetOpts = me._config;
 
- 				var custom = element.custom || {};
 
- 				var options = chart.options.elements[me.datasetElementType.prototype._type] || {};
 
- 				var elementOptions = me._datasetElementOptions;
 
- 				var values = {};
 
- 				var i, ilen, key, readKey;
 
- 				// Scriptable options
 
- 				var context = {
 
- 					chart: chart,
 
- 					dataset: me.getDataset(),
 
- 					datasetIndex: me.index,
 
- 					hover: hover
 
- 				};
 
- 				for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
 
- 					key = elementOptions[i];
 
- 					readKey = hover ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;
 
- 					values[key] = resolve([
 
- 						custom[readKey],
 
- 						datasetOpts[readKey],
 
- 						options[readKey]
 
- 					], context);
 
- 				}
 
- 				return values;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_resolveDataElementOptions: function(element, index) {
 
- 				var me = this;
 
- 				var custom = element && element.custom;
 
- 				var cached = me._cachedDataOpts;
 
- 				if (cached && !custom) {
 
- 					return cached;
 
- 				}
 
- 				var chart = me.chart;
 
- 				var datasetOpts = me._config;
 
- 				var options = chart.options.elements[me.dataElementType.prototype._type] || {};
 
- 				var elementOptions = me._dataElementOptions;
 
- 				var values = {};
 
- 				// Scriptable options
 
- 				var context = {
 
- 					chart: chart,
 
- 					dataIndex: index,
 
- 					dataset: me.getDataset(),
 
- 					datasetIndex: me.index
 
- 				};
 
- 				// `resolve` sets cacheable to `false` if any option is indexed or scripted
 
- 				var info = {cacheable: !custom};
 
- 				var keys, i, ilen, key;
 
- 				custom = custom || {};
 
- 				if (helpers$1.isArray(elementOptions)) {
 
- 					for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
 
- 						key = elementOptions[i];
 
- 						values[key] = resolve([
 
- 							custom[key],
 
- 							datasetOpts[key],
 
- 							options[key]
 
- 						], context, index, info);
 
- 					}
 
- 				} else {
 
- 					keys = Object.keys(elementOptions);
 
- 					for (i = 0, ilen = keys.length; i < ilen; ++i) {
 
- 						key = keys[i];
 
- 						values[key] = resolve([
 
- 							custom[key],
 
- 							datasetOpts[elementOptions[key]],
 
- 							datasetOpts[key],
 
- 							options[key]
 
- 						], context, index, info);
 
- 					}
 
- 				}
 
- 				if (info.cacheable) {
 
- 					me._cachedDataOpts = Object.freeze(values);
 
- 				}
 
- 				return values;
 
- 			},
 
- 			removeHoverStyle: function(element) {
 
- 				helpers$1.merge(element._model, element.$previousStyle || {});
 
- 				delete element.$previousStyle;
 
- 			},
 
- 			setHoverStyle: function(element) {
 
- 				var dataset = this.chart.data.datasets[element._datasetIndex];
 
- 				var index = element._index;
 
- 				var custom = element.custom || {};
 
- 				var model = element._model;
 
- 				var getHoverColor = helpers$1.getHoverColor;
 
- 				element.$previousStyle = {
 
- 					backgroundColor: model.backgroundColor,
 
- 					borderColor: model.borderColor,
 
- 					borderWidth: model.borderWidth
 
- 				};
 
- 				model.backgroundColor = resolve([custom.hoverBackgroundColor, dataset.hoverBackgroundColor, getHoverColor(model.backgroundColor)], undefined, index);
 
- 				model.borderColor = resolve([custom.hoverBorderColor, dataset.hoverBorderColor, getHoverColor(model.borderColor)], undefined, index);
 
- 				model.borderWidth = resolve([custom.hoverBorderWidth, dataset.hoverBorderWidth, model.borderWidth], undefined, index);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_removeDatasetHoverStyle: function() {
 
- 				var element = this.getMeta().dataset;
 
- 				if (element) {
 
- 					this.removeHoverStyle(element);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_setDatasetHoverStyle: function() {
 
- 				var element = this.getMeta().dataset;
 
- 				var prev = {};
 
- 				var i, ilen, key, keys, hoverOptions, model;
 
- 				if (!element) {
 
- 					return;
 
- 				}
 
- 				model = element._model;
 
- 				hoverOptions = this._resolveDatasetElementOptions(element, true);
 
- 				keys = Object.keys(hoverOptions);
 
- 				for (i = 0, ilen = keys.length; i < ilen; ++i) {
 
- 					key = keys[i];
 
- 					prev[key] = model[key];
 
- 					model[key] = hoverOptions[key];
 
- 				}
 
- 				element.$previousStyle = prev;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			resyncElements: function() {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var data = me.getDataset().data;
 
- 				var numMeta = meta.data.length;
 
- 				var numData = data.length;
 
- 				if (numData < numMeta) {
 
- 					meta.data.splice(numData, numMeta - numData);
 
- 				} else if (numData > numMeta) {
 
- 					me.insertElements(numMeta, numData - numMeta);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			insertElements: function(start, count) {
 
- 				for (var i = 0; i < count; ++i) {
 
- 					this.addElementAndReset(start + i);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			onDataPush: function() {
 
- 				var count = arguments.length;
 
- 				this.insertElements(this.getDataset().data.length - count, count);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			onDataPop: function() {
 
- 				this.getMeta().data.pop();
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			onDataShift: function() {
 
- 				this.getMeta().data.shift();
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			onDataSplice: function(start, count) {
 
- 				this.getMeta().data.splice(start, count);
 
- 				this.insertElements(start, arguments.length - 2);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			onDataUnshift: function() {
 
- 				this.insertElements(0, arguments.length);
 
- 			}
 
- 		});
 
- 		DatasetController.extend = helpers$1.inherits;
 
- 		var core_datasetController = DatasetController;
 
- 		var TAU = Math.PI * 2;
 
- 		core_defaults._set('global', {
 
- 			elements: {
 
- 				arc: {
 
- 					backgroundColor: core_defaults.global.defaultColor,
 
- 					borderColor: '#fff',
 
- 					borderWidth: 2,
 
- 					borderAlign: 'center'
 
- 				}
 
- 			}
 
- 		});
 
- 		function clipArc(ctx, arc) {
 
- 			var startAngle = arc.startAngle;
 
- 			var endAngle = arc.endAngle;
 
- 			var pixelMargin = arc.pixelMargin;
 
- 			var angleMargin = pixelMargin / arc.outerRadius;
 
- 			var x = arc.x;
 
- 			var y = arc.y;
 
- 			// Draw an inner border by cliping the arc and drawing a double-width border
 
- 			// Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
 
- 			ctx.beginPath();
 
- 			ctx.arc(x, y, arc.outerRadius, startAngle - angleMargin, endAngle + angleMargin);
 
- 			if (arc.innerRadius > pixelMargin) {
 
- 				angleMargin = pixelMargin / arc.innerRadius;
 
- 				ctx.arc(x, y, arc.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true);
 
- 			} else {
 
- 				ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2);
 
- 			}
 
- 			ctx.closePath();
 
- 			ctx.clip();
 
- 		}
 
- 		function drawFullCircleBorders(ctx, vm, arc, inner) {
 
- 			var endAngle = arc.endAngle;
 
- 			var i;
 
- 			if (inner) {
 
- 				arc.endAngle = arc.startAngle + TAU;
 
- 				clipArc(ctx, arc);
 
- 				arc.endAngle = endAngle;
 
- 				if (arc.endAngle === arc.startAngle && arc.fullCircles) {
 
- 					arc.endAngle += TAU;
 
- 					arc.fullCircles--;
 
- 				}
 
- 			}
 
- 			ctx.beginPath();
 
- 			ctx.arc(arc.x, arc.y, arc.innerRadius, arc.startAngle + TAU, arc.startAngle, true);
 
- 			for (i = 0; i < arc.fullCircles; ++i) {
 
- 				ctx.stroke();
 
- 			}
 
- 			ctx.beginPath();
 
- 			ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.startAngle + TAU);
 
- 			for (i = 0; i < arc.fullCircles; ++i) {
 
- 				ctx.stroke();
 
- 			}
 
- 		}
 
- 		function drawBorder(ctx, vm, arc) {
 
- 			var inner = vm.borderAlign === 'inner';
 
- 			if (inner) {
 
- 				ctx.lineWidth = vm.borderWidth * 2;
 
- 				ctx.lineJoin = 'round';
 
- 			} else {
 
- 				ctx.lineWidth = vm.borderWidth;
 
- 				ctx.lineJoin = 'bevel';
 
- 			}
 
- 			if (arc.fullCircles) {
 
- 				drawFullCircleBorders(ctx, vm, arc, inner);
 
- 			}
 
- 			if (inner) {
 
- 				clipArc(ctx, arc);
 
- 			}
 
- 			ctx.beginPath();
 
- 			ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.endAngle);
 
- 			ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
 
- 			ctx.closePath();
 
- 			ctx.stroke();
 
- 		}
 
- 		var element_arc = core_element.extend({
 
- 			_type: 'arc',
 
- 			inLabelRange: function(mouseX) {
 
- 				var vm = this._view;
 
- 				if (vm) {
 
- 					return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
 
- 				}
 
- 				return false;
 
- 			},
 
- 			inRange: function(chartX, chartY) {
 
- 				var vm = this._view;
 
- 				if (vm) {
 
- 					var pointRelativePosition = helpers$1.getAngleFromPoint(vm, {x: chartX, y: chartY});
 
- 					var angle = pointRelativePosition.angle;
 
- 					var distance = pointRelativePosition.distance;
 
- 					// Sanitise angle range
 
- 					var startAngle = vm.startAngle;
 
- 					var endAngle = vm.endAngle;
 
- 					while (endAngle < startAngle) {
 
- 						endAngle += TAU;
 
- 					}
 
- 					while (angle > endAngle) {
 
- 						angle -= TAU;
 
- 					}
 
- 					while (angle < startAngle) {
 
- 						angle += TAU;
 
- 					}
 
- 					// Check if within the range of the open/close angle
 
- 					var betweenAngles = (angle >= startAngle && angle <= endAngle);
 
- 					var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
 
- 					return (betweenAngles && withinRadius);
 
- 				}
 
- 				return false;
 
- 			},
 
- 			getCenterPoint: function() {
 
- 				var vm = this._view;
 
- 				var halfAngle = (vm.startAngle + vm.endAngle) / 2;
 
- 				var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
 
- 				return {
 
- 					x: vm.x + Math.cos(halfAngle) * halfRadius,
 
- 					y: vm.y + Math.sin(halfAngle) * halfRadius
 
- 				};
 
- 			},
 
- 			getArea: function() {
 
- 				var vm = this._view;
 
- 				return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
 
- 			},
 
- 			tooltipPosition: function() {
 
- 				var vm = this._view;
 
- 				var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
 
- 				var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
 
- 				return {
 
- 					x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
 
- 					y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
 
- 				};
 
- 			},
 
- 			draw: function() {
 
- 				var ctx = this._chart.ctx;
 
- 				var vm = this._view;
 
- 				var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
 
- 				var arc = {
 
- 					x: vm.x,
 
- 					y: vm.y,
 
- 					innerRadius: vm.innerRadius,
 
- 					outerRadius: Math.max(vm.outerRadius - pixelMargin, 0),
 
- 					pixelMargin: pixelMargin,
 
- 					startAngle: vm.startAngle,
 
- 					endAngle: vm.endAngle,
 
- 					fullCircles: Math.floor(vm.circumference / TAU)
 
- 				};
 
- 				var i;
 
- 				ctx.save();
 
- 				ctx.fillStyle = vm.backgroundColor;
 
- 				ctx.strokeStyle = vm.borderColor;
 
- 				if (arc.fullCircles) {
 
- 					arc.endAngle = arc.startAngle + TAU;
 
- 					ctx.beginPath();
 
- 					ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);
 
- 					ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
 
- 					ctx.closePath();
 
- 					for (i = 0; i < arc.fullCircles; ++i) {
 
- 						ctx.fill();
 
- 					}
 
- 					arc.endAngle = arc.startAngle + vm.circumference % TAU;
 
- 				}
 
- 				ctx.beginPath();
 
- 				ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);
 
- 				ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
 
- 				ctx.closePath();
 
- 				ctx.fill();
 
- 				if (vm.borderWidth) {
 
- 					drawBorder(ctx, vm, arc);
 
- 				}
 
- 				ctx.restore();
 
- 			}
 
- 		});
 
- 		var valueOrDefault$1 = helpers$1.valueOrDefault;
 
- 		var defaultColor = core_defaults.global.defaultColor;
 
- 		core_defaults._set('global', {
 
- 			elements: {
 
- 				line: {
 
- 					tension: 0.4,
 
- 					backgroundColor: defaultColor,
 
- 					borderWidth: 3,
 
- 					borderColor: defaultColor,
 
- 					borderCapStyle: 'butt',
 
- 					borderDash: [],
 
- 					borderDashOffset: 0.0,
 
- 					borderJoinStyle: 'miter',
 
- 					capBezierPoints: true,
 
- 					fill: true, // do we fill in the area between the line and its base axis
 
- 				}
 
- 			}
 
- 		});
 
- 		var element_line = core_element.extend({
 
- 			_type: 'line',
 
- 			draw: function() {
 
- 				var me = this;
 
- 				var vm = me._view;
 
- 				var ctx = me._chart.ctx;
 
- 				var spanGaps = vm.spanGaps;
 
- 				var points = me._children.slice(); // clone array
 
- 				var globalDefaults = core_defaults.global;
 
- 				var globalOptionLineElements = globalDefaults.elements.line;
 
- 				var lastDrawnIndex = -1;
 
- 				var closePath = me._loop;
 
- 				var index, previous, currentVM;
 
- 				if (!points.length) {
 
- 					return;
 
- 				}
 
- 				if (me._loop) {
 
- 					for (index = 0; index < points.length; ++index) {
 
- 						previous = helpers$1.previousItem(points, index);
 
- 						// If the line has an open path, shift the point array
 
- 						if (!points[index]._view.skip && previous._view.skip) {
 
- 							points = points.slice(index).concat(points.slice(0, index));
 
- 							closePath = spanGaps;
 
- 							break;
 
- 						}
 
- 					}
 
- 					// If the line has a close path, add the first point again
 
- 					if (closePath) {
 
- 						points.push(points[0]);
 
- 					}
 
- 				}
 
- 				ctx.save();
 
- 				// Stroke Line Options
 
- 				ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
 
- 				// IE 9 and 10 do not support line dash
 
- 				if (ctx.setLineDash) {
 
- 					ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
 
- 				}
 
- 				ctx.lineDashOffset = valueOrDefault$1(vm.borderDashOffset, globalOptionLineElements.borderDashOffset);
 
- 				ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
 
- 				ctx.lineWidth = valueOrDefault$1(vm.borderWidth, globalOptionLineElements.borderWidth);
 
- 				ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
 
- 				// Stroke Line
 
- 				ctx.beginPath();
 
- 				// First point moves to it's starting position no matter what
 
- 				currentVM = points[0]._view;
 
- 				if (!currentVM.skip) {
 
- 					ctx.moveTo(currentVM.x, currentVM.y);
 
- 					lastDrawnIndex = 0;
 
- 				}
 
- 				for (index = 1; index < points.length; ++index) {
 
- 					currentVM = points[index]._view;
 
- 					previous = lastDrawnIndex === -1 ? helpers$1.previousItem(points, index) : points[lastDrawnIndex];
 
- 					if (!currentVM.skip) {
 
- 						if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
 
- 							// There was a gap and this is the first point after the gap
 
- 							ctx.moveTo(currentVM.x, currentVM.y);
 
- 						} else {
 
- 							// Line to next point
 
- 							helpers$1.canvas.lineTo(ctx, previous._view, currentVM);
 
- 						}
 
- 						lastDrawnIndex = index;
 
- 					}
 
- 				}
 
- 				if (closePath) {
 
- 					ctx.closePath();
 
- 				}
 
- 				ctx.stroke();
 
- 				ctx.restore();
 
- 			}
 
- 		});
 
- 		var valueOrDefault$2 = helpers$1.valueOrDefault;
 
- 		var defaultColor$1 = core_defaults.global.defaultColor;
 
- 		core_defaults._set('global', {
 
- 			elements: {
 
- 				point: {
 
- 					radius: 3,
 
- 					pointStyle: 'circle',
 
- 					backgroundColor: defaultColor$1,
 
- 					borderColor: defaultColor$1,
 
- 					borderWidth: 1,
 
- 					// Hover
 
- 					hitRadius: 1,
 
- 					hoverRadius: 4,
 
- 					hoverBorderWidth: 1
 
- 				}
 
- 			}
 
- 		});
 
- 		function xRange(mouseX) {
 
- 			var vm = this._view;
 
- 			return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;
 
- 		}
 
- 		function yRange(mouseY) {
 
- 			var vm = this._view;
 
- 			return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;
 
- 		}
 
- 		var element_point = core_element.extend({
 
- 			_type: 'point',
 
- 			inRange: function(mouseX, mouseY) {
 
- 				var vm = this._view;
 
- 				return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
 
- 			},
 
- 			inLabelRange: xRange,
 
- 			inXRange: xRange,
 
- 			inYRange: yRange,
 
- 			getCenterPoint: function() {
 
- 				var vm = this._view;
 
- 				return {
 
- 					x: vm.x,
 
- 					y: vm.y
 
- 				};
 
- 			},
 
- 			getArea: function() {
 
- 				return Math.PI * Math.pow(this._view.radius, 2);
 
- 			},
 
- 			tooltipPosition: function() {
 
- 				var vm = this._view;
 
- 				return {
 
- 					x: vm.x,
 
- 					y: vm.y,
 
- 					padding: vm.radius + vm.borderWidth
 
- 				};
 
- 			},
 
- 			draw: function(chartArea) {
 
- 				var vm = this._view;
 
- 				var ctx = this._chart.ctx;
 
- 				var pointStyle = vm.pointStyle;
 
- 				var rotation = vm.rotation;
 
- 				var radius = vm.radius;
 
- 				var x = vm.x;
 
- 				var y = vm.y;
 
- 				var globalDefaults = core_defaults.global;
 
- 				var defaultColor = globalDefaults.defaultColor; // eslint-disable-line no-shadow
 
- 				if (vm.skip) {
 
- 					return;
 
- 				}
 
- 				// Clipping for Points.
 
- 				if (chartArea === undefined || helpers$1.canvas._isPointInArea(vm, chartArea)) {
 
- 					ctx.strokeStyle = vm.borderColor || defaultColor;
 
- 					ctx.lineWidth = valueOrDefault$2(vm.borderWidth, globalDefaults.elements.point.borderWidth);
 
- 					ctx.fillStyle = vm.backgroundColor || defaultColor;
 
- 					helpers$1.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation);
 
- 				}
 
- 			}
 
- 		});
 
- 		var defaultColor$2 = core_defaults.global.defaultColor;
 
- 		core_defaults._set('global', {
 
- 			elements: {
 
- 				rectangle: {
 
- 					backgroundColor: defaultColor$2,
 
- 					borderColor: defaultColor$2,
 
- 					borderSkipped: 'bottom',
 
- 					borderWidth: 0
 
- 				}
 
- 			}
 
- 		});
 
- 		function isVertical(vm) {
 
- 			return vm && vm.width !== undefined;
 
- 		}
 
- 		/**
 
- 		 * Helper function to get the bounds of the bar regardless of the orientation
 
- 		 * @param bar {Chart.Element.Rectangle} the bar
 
- 		 * @return {Bounds} bounds of the bar
 
- 		 * @private
 
- 		 */
 
- 		function getBarBounds(vm) {
 
- 			var x1, x2, y1, y2, half;
 
- 			if (isVertical(vm)) {
 
- 				half = vm.width / 2;
 
- 				x1 = vm.x - half;
 
- 				x2 = vm.x + half;
 
- 				y1 = Math.min(vm.y, vm.base);
 
- 				y2 = Math.max(vm.y, vm.base);
 
- 			} else {
 
- 				half = vm.height / 2;
 
- 				x1 = Math.min(vm.x, vm.base);
 
- 				x2 = Math.max(vm.x, vm.base);
 
- 				y1 = vm.y - half;
 
- 				y2 = vm.y + half;
 
- 			}
 
- 			return {
 
- 				left: x1,
 
- 				top: y1,
 
- 				right: x2,
 
- 				bottom: y2
 
- 			};
 
- 		}
 
- 		function swap(orig, v1, v2) {
 
- 			return orig === v1 ? v2 : orig === v2 ? v1 : orig;
 
- 		}
 
- 		function parseBorderSkipped(vm) {
 
- 			var edge = vm.borderSkipped;
 
- 			var res = {};
 
- 			if (!edge) {
 
- 				return res;
 
- 			}
 
- 			if (vm.horizontal) {
 
- 				if (vm.base > vm.x) {
 
- 					edge = swap(edge, 'left', 'right');
 
- 				}
 
- 			} else if (vm.base < vm.y) {
 
- 				edge = swap(edge, 'bottom', 'top');
 
- 			}
 
- 			res[edge] = true;
 
- 			return res;
 
- 		}
 
- 		function parseBorderWidth(vm, maxW, maxH) {
 
- 			var value = vm.borderWidth;
 
- 			var skip = parseBorderSkipped(vm);
 
- 			var t, r, b, l;
 
- 			if (helpers$1.isObject(value)) {
 
- 				t = +value.top || 0;
 
- 				r = +value.right || 0;
 
- 				b = +value.bottom || 0;
 
- 				l = +value.left || 0;
 
- 			} else {
 
- 				t = r = b = l = +value || 0;
 
- 			}
 
- 			return {
 
- 				t: skip.top || (t < 0) ? 0 : t > maxH ? maxH : t,
 
- 				r: skip.right || (r < 0) ? 0 : r > maxW ? maxW : r,
 
- 				b: skip.bottom || (b < 0) ? 0 : b > maxH ? maxH : b,
 
- 				l: skip.left || (l < 0) ? 0 : l > maxW ? maxW : l
 
- 			};
 
- 		}
 
- 		function boundingRects(vm) {
 
- 			var bounds = getBarBounds(vm);
 
- 			var width = bounds.right - bounds.left;
 
- 			var height = bounds.bottom - bounds.top;
 
- 			var border = parseBorderWidth(vm, width / 2, height / 2);
 
- 			return {
 
- 				outer: {
 
- 					x: bounds.left,
 
- 					y: bounds.top,
 
- 					w: width,
 
- 					h: height
 
- 				},
 
- 				inner: {
 
- 					x: bounds.left + border.l,
 
- 					y: bounds.top + border.t,
 
- 					w: width - border.l - border.r,
 
- 					h: height - border.t - border.b
 
- 				}
 
- 			};
 
- 		}
 
- 		function inRange(vm, x, y) {
 
- 			var skipX = x === null;
 
- 			var skipY = y === null;
 
- 			var bounds = !vm || (skipX && skipY) ? false : getBarBounds(vm);
 
- 			return bounds
 
- 				&& (skipX || x >= bounds.left && x <= bounds.right)
 
- 				&& (skipY || y >= bounds.top && y <= bounds.bottom);
 
- 		}
 
- 		var element_rectangle = core_element.extend({
 
- 			_type: 'rectangle',
 
- 			draw: function() {
 
- 				var ctx = this._chart.ctx;
 
- 				var vm = this._view;
 
- 				var rects = boundingRects(vm);
 
- 				var outer = rects.outer;
 
- 				var inner = rects.inner;
 
- 				ctx.fillStyle = vm.backgroundColor;
 
- 				ctx.fillRect(outer.x, outer.y, outer.w, outer.h);
 
- 				if (outer.w === inner.w && outer.h === inner.h) {
 
- 					return;
 
- 				}
 
- 				ctx.save();
 
- 				ctx.beginPath();
 
- 				ctx.rect(outer.x, outer.y, outer.w, outer.h);
 
- 				ctx.clip();
 
- 				ctx.fillStyle = vm.borderColor;
 
- 				ctx.rect(inner.x, inner.y, inner.w, inner.h);
 
- 				ctx.fill('evenodd');
 
- 				ctx.restore();
 
- 			},
 
- 			height: function() {
 
- 				var vm = this._view;
 
- 				return vm.base - vm.y;
 
- 			},
 
- 			inRange: function(mouseX, mouseY) {
 
- 				return inRange(this._view, mouseX, mouseY);
 
- 			},
 
- 			inLabelRange: function(mouseX, mouseY) {
 
- 				var vm = this._view;
 
- 				return isVertical(vm)
 
- 					? inRange(vm, mouseX, null)
 
- 					: inRange(vm, null, mouseY);
 
- 			},
 
- 			inXRange: function(mouseX) {
 
- 				return inRange(this._view, mouseX, null);
 
- 			},
 
- 			inYRange: function(mouseY) {
 
- 				return inRange(this._view, null, mouseY);
 
- 			},
 
- 			getCenterPoint: function() {
 
- 				var vm = this._view;
 
- 				var x, y;
 
- 				if (isVertical(vm)) {
 
- 					x = vm.x;
 
- 					y = (vm.y + vm.base) / 2;
 
- 				} else {
 
- 					x = (vm.x + vm.base) / 2;
 
- 					y = vm.y;
 
- 				}
 
- 				return {x: x, y: y};
 
- 			},
 
- 			getArea: function() {
 
- 				var vm = this._view;
 
- 				return isVertical(vm)
 
- 					? vm.width * Math.abs(vm.y - vm.base)
 
- 					: vm.height * Math.abs(vm.x - vm.base);
 
- 			},
 
- 			tooltipPosition: function() {
 
- 				var vm = this._view;
 
- 				return {
 
- 					x: vm.x,
 
- 					y: vm.y
 
- 				};
 
- 			}
 
- 		});
 
- 		var elements = {};
 
- 		var Arc = element_arc;
 
- 		var Line = element_line;
 
- 		var Point = element_point;
 
- 		var Rectangle = element_rectangle;
 
- 		elements.Arc = Arc;
 
- 		elements.Line = Line;
 
- 		elements.Point = Point;
 
- 		elements.Rectangle = Rectangle;
 
- 		var deprecated = helpers$1._deprecated;
 
- 		var valueOrDefault$3 = helpers$1.valueOrDefault;
 
- 		core_defaults._set('bar', {
 
- 			hover: {
 
- 				mode: 'label'
 
- 			},
 
- 			scales: {
 
- 				xAxes: [{
 
- 					type: 'category',
 
- 					offset: true,
 
- 					gridLines: {
 
- 						offsetGridLines: true
 
- 					}
 
- 				}],
 
- 				yAxes: [{
 
- 					type: 'linear'
 
- 				}]
 
- 			}
 
- 		});
 
- 		core_defaults._set('global', {
 
- 			datasets: {
 
- 				bar: {
 
- 					categoryPercentage: 0.8,
 
- 					barPercentage: 0.9
 
- 				}
 
- 			}
 
- 		});
 
- 		/**
 
- 		 * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
 
- 		 * @private
 
- 		 */
 
- 		function computeMinSampleSize(scale, pixels) {
 
- 			var min = scale._length;
 
- 			var prev, curr, i, ilen;
 
- 			for (i = 1, ilen = pixels.length; i < ilen; ++i) {
 
- 				min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1]));
 
- 			}
 
- 			for (i = 0, ilen = scale.getTicks().length; i < ilen; ++i) {
 
- 				curr = scale.getPixelForTick(i);
 
- 				min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min;
 
- 				prev = curr;
 
- 			}
 
- 			return min;
 
- 		}
 
- 		/**
 
- 		 * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null,
 
- 		 * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This
 
- 		 * mode currently always generates bars equally sized (until we introduce scriptable options?).
 
- 		 * @private
 
- 		 */
 
- 		function computeFitCategoryTraits(index, ruler, options) {
 
- 			var thickness = options.barThickness;
 
- 			var count = ruler.stackCount;
 
- 			var curr = ruler.pixels[index];
 
- 			var min = helpers$1.isNullOrUndef(thickness)
 
- 				? computeMinSampleSize(ruler.scale, ruler.pixels)
 
- 				: -1;
 
- 			var size, ratio;
 
- 			if (helpers$1.isNullOrUndef(thickness)) {
 
- 				size = min * options.categoryPercentage;
 
- 				ratio = options.barPercentage;
 
- 			} else {
 
- 				// When bar thickness is enforced, category and bar percentages are ignored.
 
- 				// Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
 
- 				// and deprecate barPercentage since this value is ignored when thickness is absolute.
 
- 				size = thickness * count;
 
- 				ratio = 1;
 
- 			}
 
- 			return {
 
- 				chunk: size / count,
 
- 				ratio: ratio,
 
- 				start: curr - (size / 2)
 
- 			};
 
- 		}
 
- 		/**
 
- 		 * Computes an "optimal" category that globally arranges bars side by side (no gap when
 
- 		 * percentage options are 1), based on the previous and following categories. This mode
 
- 		 * generates bars with different widths when data are not evenly spaced.
 
- 		 * @private
 
- 		 */
 
- 		function computeFlexCategoryTraits(index, ruler, options) {
 
- 			var pixels = ruler.pixels;
 
- 			var curr = pixels[index];
 
- 			var prev = index > 0 ? pixels[index - 1] : null;
 
- 			var next = index < pixels.length - 1 ? pixels[index + 1] : null;
 
- 			var percent = options.categoryPercentage;
 
- 			var start, size;
 
- 			if (prev === null) {
 
- 				// first data: its size is double based on the next point or,
 
- 				// if it's also the last data, we use the scale size.
 
- 				prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
 
- 			}
 
- 			if (next === null) {
 
- 				// last data: its size is also double based on the previous point.
 
- 				next = curr + curr - prev;
 
- 			}
 
- 			start = curr - (curr - Math.min(prev, next)) / 2 * percent;
 
- 			size = Math.abs(next - prev) / 2 * percent;
 
- 			return {
 
- 				chunk: size / ruler.stackCount,
 
- 				ratio: options.barPercentage,
 
- 				start: start
 
- 			};
 
- 		}
 
- 		var controller_bar = core_datasetController.extend({
 
- 			dataElementType: elements.Rectangle,
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_dataElementOptions: [
 
- 				'backgroundColor',
 
- 				'borderColor',
 
- 				'borderSkipped',
 
- 				'borderWidth',
 
- 				'barPercentage',
 
- 				'barThickness',
 
- 				'categoryPercentage',
 
- 				'maxBarThickness',
 
- 				'minBarLength'
 
- 			],
 
- 			initialize: function() {
 
- 				var me = this;
 
- 				var meta, scaleOpts;
 
- 				core_datasetController.prototype.initialize.apply(me, arguments);
 
- 				meta = me.getMeta();
 
- 				meta.stack = me.getDataset().stack;
 
- 				meta.bar = true;
 
- 				scaleOpts = me._getIndexScale().options;
 
- 				deprecated('bar chart', scaleOpts.barPercentage, 'scales.[x/y]Axes.barPercentage', 'dataset.barPercentage');
 
- 				deprecated('bar chart', scaleOpts.barThickness, 'scales.[x/y]Axes.barThickness', 'dataset.barThickness');
 
- 				deprecated('bar chart', scaleOpts.categoryPercentage, 'scales.[x/y]Axes.categoryPercentage', 'dataset.categoryPercentage');
 
- 				deprecated('bar chart', me._getValueScale().options.minBarLength, 'scales.[x/y]Axes.minBarLength', 'dataset.minBarLength');
 
- 				deprecated('bar chart', scaleOpts.maxBarThickness, 'scales.[x/y]Axes.maxBarThickness', 'dataset.maxBarThickness');
 
- 			},
 
- 			update: function(reset) {
 
- 				var me = this;
 
- 				var rects = me.getMeta().data;
 
- 				var i, ilen;
 
- 				me._ruler = me.getRuler();
 
- 				for (i = 0, ilen = rects.length; i < ilen; ++i) {
 
- 					me.updateElement(rects[i], i, reset);
 
- 				}
 
- 			},
 
- 			updateElement: function(rectangle, index, reset) {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var dataset = me.getDataset();
 
- 				var options = me._resolveDataElementOptions(rectangle, index);
 
- 				rectangle._xScale = me.getScaleForId(meta.xAxisID);
 
- 				rectangle._yScale = me.getScaleForId(meta.yAxisID);
 
- 				rectangle._datasetIndex = me.index;
 
- 				rectangle._index = index;
 
- 				rectangle._model = {
 
- 					backgroundColor: options.backgroundColor,
 
- 					borderColor: options.borderColor,
 
- 					borderSkipped: options.borderSkipped,
 
- 					borderWidth: options.borderWidth,
 
- 					datasetLabel: dataset.label,
 
- 					label: me.chart.data.labels[index]
 
- 				};
 
- 				if (helpers$1.isArray(dataset.data[index])) {
 
- 					rectangle._model.borderSkipped = null;
 
- 				}
 
- 				me._updateElementGeometry(rectangle, index, reset, options);
 
- 				rectangle.pivot();
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_updateElementGeometry: function(rectangle, index, reset, options) {
 
- 				var me = this;
 
- 				var model = rectangle._model;
 
- 				var vscale = me._getValueScale();
 
- 				var base = vscale.getBasePixel();
 
- 				var horizontal = vscale.isHorizontal();
 
- 				var ruler = me._ruler || me.getRuler();
 
- 				var vpixels = me.calculateBarValuePixels(me.index, index, options);
 
- 				var ipixels = me.calculateBarIndexPixels(me.index, index, ruler, options);
 
- 				model.horizontal = horizontal;
 
- 				model.base = reset ? base : vpixels.base;
 
- 				model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
 
- 				model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
 
- 				model.height = horizontal ? ipixels.size : undefined;
 
- 				model.width = horizontal ? undefined : ipixels.size;
 
- 			},
 
- 			/**
 
- 			 * Returns the stacks based on groups and bar visibility.
 
- 			 * @param {number} [last] - The dataset index
 
- 			 * @returns {string[]} The list of stack IDs
 
- 			 * @private
 
- 			 */
 
- 			_getStacks: function(last) {
 
- 				var me = this;
 
- 				var scale = me._getIndexScale();
 
- 				var metasets = scale._getMatchingVisibleMetas(me._type);
 
- 				var stacked = scale.options.stacked;
 
- 				var ilen = metasets.length;
 
- 				var stacks = [];
 
- 				var i, meta;
 
- 				for (i = 0; i < ilen; ++i) {
 
- 					meta = metasets[i];
 
- 					// stacked   | meta.stack
 
- 					//           | found | not found | undefined
 
- 					// false     |   x   |     x     |     x
 
- 					// true      |       |     x     |
 
- 					// undefined |       |     x     |     x
 
- 					if (stacked === false || stacks.indexOf(meta.stack) === -1 ||
 
- 						(stacked === undefined && meta.stack === undefined)) {
 
- 						stacks.push(meta.stack);
 
- 					}
 
- 					if (meta.index === last) {
 
- 						break;
 
- 					}
 
- 				}
 
- 				return stacks;
 
- 			},
 
- 			/**
 
- 			 * Returns the effective number of stacks based on groups and bar visibility.
 
- 			 * @private
 
- 			 */
 
- 			getStackCount: function() {
 
- 				return this._getStacks().length;
 
- 			},
 
- 			/**
 
- 			 * Returns the stack index for the given dataset based on groups and bar visibility.
 
- 			 * @param {number} [datasetIndex] - The dataset index
 
- 			 * @param {string} [name] - The stack name to find
 
- 			 * @returns {number} The stack index
 
- 			 * @private
 
- 			 */
 
- 			getStackIndex: function(datasetIndex, name) {
 
- 				var stacks = this._getStacks(datasetIndex);
 
- 				var index = (name !== undefined)
 
- 					? stacks.indexOf(name)
 
- 					: -1; // indexOf returns -1 if element is not present
 
- 				return (index === -1)
 
- 					? stacks.length - 1
 
- 					: index;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			getRuler: function() {
 
- 				var me = this;
 
- 				var scale = me._getIndexScale();
 
- 				var pixels = [];
 
- 				var i, ilen;
 
- 				for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
 
- 					pixels.push(scale.getPixelForValue(null, i, me.index));
 
- 				}
 
- 				return {
 
- 					pixels: pixels,
 
- 					start: scale._startPixel,
 
- 					end: scale._endPixel,
 
- 					stackCount: me.getStackCount(),
 
- 					scale: scale
 
- 				};
 
- 			},
 
- 			/**
 
- 			 * Note: pixel values are not clamped to the scale area.
 
- 			 * @private
 
- 			 */
 
- 			calculateBarValuePixels: function(datasetIndex, index, options) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var scale = me._getValueScale();
 
- 				var isHorizontal = scale.isHorizontal();
 
- 				var datasets = chart.data.datasets;
 
- 				var metasets = scale._getMatchingVisibleMetas(me._type);
 
- 				var value = scale._parseValue(datasets[datasetIndex].data[index]);
 
- 				var minBarLength = options.minBarLength;
 
- 				var stacked = scale.options.stacked;
 
- 				var stack = me.getMeta().stack;
 
- 				var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max;
 
- 				var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max;
 
- 				var ilen = metasets.length;
 
- 				var i, imeta, ivalue, base, head, size, stackLength;
 
- 				if (stacked || (stacked === undefined && stack !== undefined)) {
 
- 					for (i = 0; i < ilen; ++i) {
 
- 						imeta = metasets[i];
 
- 						if (imeta.index === datasetIndex) {
 
- 							break;
 
- 						}
 
- 						if (imeta.stack === stack) {
 
- 							stackLength = scale._parseValue(datasets[imeta.index].data[index]);
 
- 							ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min;
 
- 							if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) {
 
- 								start += ivalue;
 
- 							}
 
- 						}
 
- 					}
 
- 				}
 
- 				base = scale.getPixelForValue(start);
 
- 				head = scale.getPixelForValue(start + length);
 
- 				size = head - base;
 
- 				if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
 
- 					size = minBarLength;
 
- 					if (length >= 0 && !isHorizontal || length < 0 && isHorizontal) {
 
- 						head = base - minBarLength;
 
- 					} else {
 
- 						head = base + minBarLength;
 
- 					}
 
- 				}
 
- 				return {
 
- 					size: size,
 
- 					base: base,
 
- 					head: head,
 
- 					center: head + size / 2
 
- 				};
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			calculateBarIndexPixels: function(datasetIndex, index, ruler, options) {
 
- 				var me = this;
 
- 				var range = options.barThickness === 'flex'
 
- 					? computeFlexCategoryTraits(index, ruler, options)
 
- 					: computeFitCategoryTraits(index, ruler, options);
 
- 				var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
 
- 				var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
 
- 				var size = Math.min(
 
- 					valueOrDefault$3(options.maxBarThickness, Infinity),
 
- 					range.chunk * range.ratio);
 
- 				return {
 
- 					base: center - size / 2,
 
- 					head: center + size / 2,
 
- 					center: center,
 
- 					size: size
 
- 				};
 
- 			},
 
- 			draw: function() {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var scale = me._getValueScale();
 
- 				var rects = me.getMeta().data;
 
- 				var dataset = me.getDataset();
 
- 				var ilen = rects.length;
 
- 				var i = 0;
 
- 				helpers$1.canvas.clipArea(chart.ctx, chart.chartArea);
 
- 				for (; i < ilen; ++i) {
 
- 					var val = scale._parseValue(dataset.data[i]);
 
- 					if (!isNaN(val.min) && !isNaN(val.max)) {
 
- 						rects[i].draw();
 
- 					}
 
- 				}
 
- 				helpers$1.canvas.unclipArea(chart.ctx);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_resolveDataElementOptions: function() {
 
- 				var me = this;
 
- 				var values = helpers$1.extend({}, core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments));
 
- 				var indexOpts = me._getIndexScale().options;
 
- 				var valueOpts = me._getValueScale().options;
 
- 				values.barPercentage = valueOrDefault$3(indexOpts.barPercentage, values.barPercentage);
 
- 				values.barThickness = valueOrDefault$3(indexOpts.barThickness, values.barThickness);
 
- 				values.categoryPercentage = valueOrDefault$3(indexOpts.categoryPercentage, values.categoryPercentage);
 
- 				values.maxBarThickness = valueOrDefault$3(indexOpts.maxBarThickness, values.maxBarThickness);
 
- 				values.minBarLength = valueOrDefault$3(valueOpts.minBarLength, values.minBarLength);
 
- 				return values;
 
- 			}
 
- 		});
 
- 		var valueOrDefault$4 = helpers$1.valueOrDefault;
 
- 		var resolve$1 = helpers$1.options.resolve;
 
- 		core_defaults._set('bubble', {
 
- 			hover: {
 
- 				mode: 'single'
 
- 			},
 
- 			scales: {
 
- 				xAxes: [{
 
- 					type: 'linear', // bubble should probably use a linear scale by default
 
- 					position: 'bottom',
 
- 					id: 'x-axis-0' // need an ID so datasets can reference the scale
 
- 				}],
 
- 				yAxes: [{
 
- 					type: 'linear',
 
- 					position: 'left',
 
- 					id: 'y-axis-0'
 
- 				}]
 
- 			},
 
- 			tooltips: {
 
- 				callbacks: {
 
- 					title: function() {
 
- 						// Title doesn't make sense for scatter since we format the data as a point
 
- 						return '';
 
- 					},
 
- 					label: function(item, data) {
 
- 						var datasetLabel = data.datasets[item.datasetIndex].label || '';
 
- 						var dataPoint = data.datasets[item.datasetIndex].data[item.index];
 
- 						return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';
 
- 					}
 
- 				}
 
- 			}
 
- 		});
 
- 		var controller_bubble = core_datasetController.extend({
 
- 			/**
 
- 			 * @protected
 
- 			 */
 
- 			dataElementType: elements.Point,
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_dataElementOptions: [
 
- 				'backgroundColor',
 
- 				'borderColor',
 
- 				'borderWidth',
 
- 				'hoverBackgroundColor',
 
- 				'hoverBorderColor',
 
- 				'hoverBorderWidth',
 
- 				'hoverRadius',
 
- 				'hitRadius',
 
- 				'pointStyle',
 
- 				'rotation'
 
- 			],
 
- 			/**
 
- 			 * @protected
 
- 			 */
 
- 			update: function(reset) {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var points = meta.data;
 
- 				// Update Points
 
- 				helpers$1.each(points, function(point, index) {
 
- 					me.updateElement(point, index, reset);
 
- 				});
 
- 			},
 
- 			/**
 
- 			 * @protected
 
- 			 */
 
- 			updateElement: function(point, index, reset) {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var custom = point.custom || {};
 
- 				var xScale = me.getScaleForId(meta.xAxisID);
 
- 				var yScale = me.getScaleForId(meta.yAxisID);
 
- 				var options = me._resolveDataElementOptions(point, index);
 
- 				var data = me.getDataset().data[index];
 
- 				var dsIndex = me.index;
 
- 				var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
 
- 				var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
 
- 				point._xScale = xScale;
 
- 				point._yScale = yScale;
 
- 				point._options = options;
 
- 				point._datasetIndex = dsIndex;
 
- 				point._index = index;
 
- 				point._model = {
 
- 					backgroundColor: options.backgroundColor,
 
- 					borderColor: options.borderColor,
 
- 					borderWidth: options.borderWidth,
 
- 					hitRadius: options.hitRadius,
 
- 					pointStyle: options.pointStyle,
 
- 					rotation: options.rotation,
 
- 					radius: reset ? 0 : options.radius,
 
- 					skip: custom.skip || isNaN(x) || isNaN(y),
 
- 					x: x,
 
- 					y: y,
 
- 				};
 
- 				point.pivot();
 
- 			},
 
- 			/**
 
- 			 * @protected
 
- 			 */
 
- 			setHoverStyle: function(point) {
 
- 				var model = point._model;
 
- 				var options = point._options;
 
- 				var getHoverColor = helpers$1.getHoverColor;
 
- 				point.$previousStyle = {
 
- 					backgroundColor: model.backgroundColor,
 
- 					borderColor: model.borderColor,
 
- 					borderWidth: model.borderWidth,
 
- 					radius: model.radius
 
- 				};
 
- 				model.backgroundColor = valueOrDefault$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
 
- 				model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor));
 
- 				model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth);
 
- 				model.radius = options.radius + options.hoverRadius;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_resolveDataElementOptions: function(point, index) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var dataset = me.getDataset();
 
- 				var custom = point.custom || {};
 
- 				var data = dataset.data[index] || {};
 
- 				var values = core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments);
 
- 				// Scriptable options
 
- 				var context = {
 
- 					chart: chart,
 
- 					dataIndex: index,
 
- 					dataset: dataset,
 
- 					datasetIndex: me.index
 
- 				};
 
- 				// In case values were cached (and thus frozen), we need to clone the values
 
- 				if (me._cachedDataOpts === values) {
 
- 					values = helpers$1.extend({}, values);
 
- 				}
 
- 				// Custom radius resolution
 
- 				values.radius = resolve$1([
 
- 					custom.radius,
 
- 					data.r,
 
- 					me._config.radius,
 
- 					chart.options.elements.point.radius
 
- 				], context, index);
 
- 				return values;
 
- 			}
 
- 		});
 
- 		var valueOrDefault$5 = helpers$1.valueOrDefault;
 
- 		var PI$1 = Math.PI;
 
- 		var DOUBLE_PI$1 = PI$1 * 2;
 
- 		var HALF_PI$1 = PI$1 / 2;
 
- 		core_defaults._set('doughnut', {
 
- 			animation: {
 
- 				// Boolean - Whether we animate the rotation of the Doughnut
 
- 				animateRotate: true,
 
- 				// Boolean - Whether we animate scaling the Doughnut from the centre
 
- 				animateScale: false
 
- 			},
 
- 			hover: {
 
- 				mode: 'single'
 
- 			},
 
- 			legendCallback: function(chart) {
 
- 				var list = document.createElement('ul');
 
- 				var data = chart.data;
 
- 				var datasets = data.datasets;
 
- 				var labels = data.labels;
 
- 				var i, ilen, listItem, listItemSpan;
 
- 				list.setAttribute('class', chart.id + '-legend');
 
- 				if (datasets.length) {
 
- 					for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {
 
- 						listItem = list.appendChild(document.createElement('li'));
 
- 						listItemSpan = listItem.appendChild(document.createElement('span'));
 
- 						listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];
 
- 						if (labels[i]) {
 
- 							listItem.appendChild(document.createTextNode(labels[i]));
 
- 						}
 
- 					}
 
- 				}
 
- 				return list.outerHTML;
 
- 			},
 
- 			legend: {
 
- 				labels: {
 
- 					generateLabels: function(chart) {
 
- 						var data = chart.data;
 
- 						if (data.labels.length && data.datasets.length) {
 
- 							return data.labels.map(function(label, i) {
 
- 								var meta = chart.getDatasetMeta(0);
 
- 								var style = meta.controller.getStyle(i);
 
- 								return {
 
- 									text: label,
 
- 									fillStyle: style.backgroundColor,
 
- 									strokeStyle: style.borderColor,
 
- 									lineWidth: style.borderWidth,
 
- 									hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,
 
- 									// Extra data used for toggling the correct item
 
- 									index: i
 
- 								};
 
- 							});
 
- 						}
 
- 						return [];
 
- 					}
 
- 				},
 
- 				onClick: function(e, legendItem) {
 
- 					var index = legendItem.index;
 
- 					var chart = this.chart;
 
- 					var i, ilen, meta;
 
- 					for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
 
- 						meta = chart.getDatasetMeta(i);
 
- 						// toggle visibility of index if exists
 
- 						if (meta.data[index]) {
 
- 							meta.data[index].hidden = !meta.data[index].hidden;
 
- 						}
 
- 					}
 
- 					chart.update();
 
- 				}
 
- 			},
 
- 			// The percentage of the chart that we cut out of the middle.
 
- 			cutoutPercentage: 50,
 
- 			// The rotation of the chart, where the first data arc begins.
 
- 			rotation: -HALF_PI$1,
 
- 			// The total circumference of the chart.
 
- 			circumference: DOUBLE_PI$1,
 
- 			// Need to override these to give a nice default
 
- 			tooltips: {
 
- 				callbacks: {
 
- 					title: function() {
 
- 						return '';
 
- 					},
 
- 					label: function(tooltipItem, data) {
 
- 						var dataLabel = data.labels[tooltipItem.index];
 
- 						var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
 
- 						if (helpers$1.isArray(dataLabel)) {
 
- 							// show value on first line of multiline label
 
- 							// need to clone because we are changing the value
 
- 							dataLabel = dataLabel.slice();
 
- 							dataLabel[0] += value;
 
- 						} else {
 
- 							dataLabel += value;
 
- 						}
 
- 						return dataLabel;
 
- 					}
 
- 				}
 
- 			}
 
- 		});
 
- 		var controller_doughnut = core_datasetController.extend({
 
- 			dataElementType: elements.Arc,
 
- 			linkScales: helpers$1.noop,
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_dataElementOptions: [
 
- 				'backgroundColor',
 
- 				'borderColor',
 
- 				'borderWidth',
 
- 				'borderAlign',
 
- 				'hoverBackgroundColor',
 
- 				'hoverBorderColor',
 
- 				'hoverBorderWidth',
 
- 			],
 
- 			// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
 
- 			getRingIndex: function(datasetIndex) {
 
- 				var ringIndex = 0;
 
- 				for (var j = 0; j < datasetIndex; ++j) {
 
- 					if (this.chart.isDatasetVisible(j)) {
 
- 						++ringIndex;
 
- 					}
 
- 				}
 
- 				return ringIndex;
 
- 			},
 
- 			update: function(reset) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var chartArea = chart.chartArea;
 
- 				var opts = chart.options;
 
- 				var ratioX = 1;
 
- 				var ratioY = 1;
 
- 				var offsetX = 0;
 
- 				var offsetY = 0;
 
- 				var meta = me.getMeta();
 
- 				var arcs = meta.data;
 
- 				var cutout = opts.cutoutPercentage / 100 || 0;
 
- 				var circumference = opts.circumference;
 
- 				var chartWeight = me._getRingWeight(me.index);
 
- 				var maxWidth, maxHeight, i, ilen;
 
- 				// If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
 
- 				if (circumference < DOUBLE_PI$1) {
 
- 					var startAngle = opts.rotation % DOUBLE_PI$1;
 
- 					startAngle += startAngle >= PI$1 ? -DOUBLE_PI$1 : startAngle < -PI$1 ? DOUBLE_PI$1 : 0;
 
- 					var endAngle = startAngle + circumference;
 
- 					var startX = Math.cos(startAngle);
 
- 					var startY = Math.sin(startAngle);
 
- 					var endX = Math.cos(endAngle);
 
- 					var endY = Math.sin(endAngle);
 
- 					var contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI$1;
 
- 					var contains90 = (startAngle <= HALF_PI$1 && endAngle >= HALF_PI$1) || endAngle >= DOUBLE_PI$1 + HALF_PI$1;
 
- 					var contains180 = startAngle === -PI$1 || endAngle >= PI$1;
 
- 					var contains270 = (startAngle <= -HALF_PI$1 && endAngle >= -HALF_PI$1) || endAngle >= PI$1 + HALF_PI$1;
 
- 					var minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);
 
- 					var minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout);
 
- 					var maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout);
 
- 					var maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout);
 
- 					ratioX = (maxX - minX) / 2;
 
- 					ratioY = (maxY - minY) / 2;
 
- 					offsetX = -(maxX + minX) / 2;
 
- 					offsetY = -(maxY + minY) / 2;
 
- 				}
 
- 				for (i = 0, ilen = arcs.length; i < ilen; ++i) {
 
- 					arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);
 
- 				}
 
- 				chart.borderWidth = me.getMaxBorderWidth();
 
- 				maxWidth = (chartArea.right - chartArea.left - chart.borderWidth) / ratioX;
 
- 				maxHeight = (chartArea.bottom - chartArea.top - chart.borderWidth) / ratioY;
 
- 				chart.outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
 
- 				chart.innerRadius = Math.max(chart.outerRadius * cutout, 0);
 
- 				chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1);
 
- 				chart.offsetX = offsetX * chart.outerRadius;
 
- 				chart.offsetY = offsetY * chart.outerRadius;
 
- 				meta.total = me.calculateTotal();
 
- 				me.outerRadius = chart.outerRadius - chart.radiusLength * me._getRingWeightOffset(me.index);
 
- 				me.innerRadius = Math.max(me.outerRadius - chart.radiusLength * chartWeight, 0);
 
- 				for (i = 0, ilen = arcs.length; i < ilen; ++i) {
 
- 					me.updateElement(arcs[i], i, reset);
 
- 				}
 
- 			},
 
- 			updateElement: function(arc, index, reset) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var chartArea = chart.chartArea;
 
- 				var opts = chart.options;
 
- 				var animationOpts = opts.animation;
 
- 				var centerX = (chartArea.left + chartArea.right) / 2;
 
- 				var centerY = (chartArea.top + chartArea.bottom) / 2;
 
- 				var startAngle = opts.rotation; // non reset case handled later
 
- 				var endAngle = opts.rotation; // non reset case handled later
 
- 				var dataset = me.getDataset();
 
- 				var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / DOUBLE_PI$1);
 
- 				var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
 
- 				var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
 
- 				var options = arc._options || {};
 
- 				helpers$1.extend(arc, {
 
- 					// Utility
 
- 					_datasetIndex: me.index,
 
- 					_index: index,
 
- 					// Desired view properties
 
- 					_model: {
 
- 						backgroundColor: options.backgroundColor,
 
- 						borderColor: options.borderColor,
 
- 						borderWidth: options.borderWidth,
 
- 						borderAlign: options.borderAlign,
 
- 						x: centerX + chart.offsetX,
 
- 						y: centerY + chart.offsetY,
 
- 						startAngle: startAngle,
 
- 						endAngle: endAngle,
 
- 						circumference: circumference,
 
- 						outerRadius: outerRadius,
 
- 						innerRadius: innerRadius,
 
- 						label: helpers$1.valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
 
- 					}
 
- 				});
 
- 				var model = arc._model;
 
- 				// Set correct angles if not resetting
 
- 				if (!reset || !animationOpts.animateRotate) {
 
- 					if (index === 0) {
 
- 						model.startAngle = opts.rotation;
 
- 					} else {
 
- 						model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
 
- 					}
 
- 					model.endAngle = model.startAngle + model.circumference;
 
- 				}
 
- 				arc.pivot();
 
- 			},
 
- 			calculateTotal: function() {
 
- 				var dataset = this.getDataset();
 
- 				var meta = this.getMeta();
 
- 				var total = 0;
 
- 				var value;
 
- 				helpers$1.each(meta.data, function(element, index) {
 
- 					value = dataset.data[index];
 
- 					if (!isNaN(value) && !element.hidden) {
 
- 						total += Math.abs(value);
 
- 					}
 
- 				});
 
- 				/* if (total === 0) {
 
- 					total = NaN;
 
- 				}*/
 
- 				return total;
 
- 			},
 
- 			calculateCircumference: function(value) {
 
- 				var total = this.getMeta().total;
 
- 				if (total > 0 && !isNaN(value)) {
 
- 					return DOUBLE_PI$1 * (Math.abs(value) / total);
 
- 				}
 
- 				return 0;
 
- 			},
 
- 			// gets the max border or hover width to properly scale pie charts
 
- 			getMaxBorderWidth: function(arcs) {
 
- 				var me = this;
 
- 				var max = 0;
 
- 				var chart = me.chart;
 
- 				var i, ilen, meta, arc, controller, options, borderWidth, hoverWidth;
 
- 				if (!arcs) {
 
- 					// Find the outmost visible dataset
 
- 					for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
 
- 						if (chart.isDatasetVisible(i)) {
 
- 							meta = chart.getDatasetMeta(i);
 
- 							arcs = meta.data;
 
- 							if (i !== me.index) {
 
- 								controller = meta.controller;
 
- 							}
 
- 							break;
 
- 						}
 
- 					}
 
- 				}
 
- 				if (!arcs) {
 
- 					return 0;
 
- 				}
 
- 				for (i = 0, ilen = arcs.length; i < ilen; ++i) {
 
- 					arc = arcs[i];
 
- 					if (controller) {
 
- 						controller._configure();
 
- 						options = controller._resolveDataElementOptions(arc, i);
 
- 					} else {
 
- 						options = arc._options;
 
- 					}
 
- 					if (options.borderAlign !== 'inner') {
 
- 						borderWidth = options.borderWidth;
 
- 						hoverWidth = options.hoverBorderWidth;
 
- 						max = borderWidth > max ? borderWidth : max;
 
- 						max = hoverWidth > max ? hoverWidth : max;
 
- 					}
 
- 				}
 
- 				return max;
 
- 			},
 
- 			/**
 
- 			 * @protected
 
- 			 */
 
- 			setHoverStyle: function(arc) {
 
- 				var model = arc._model;
 
- 				var options = arc._options;
 
- 				var getHoverColor = helpers$1.getHoverColor;
 
- 				arc.$previousStyle = {
 
- 					backgroundColor: model.backgroundColor,
 
- 					borderColor: model.borderColor,
 
- 					borderWidth: model.borderWidth,
 
- 				};
 
- 				model.backgroundColor = valueOrDefault$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
 
- 				model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor));
 
- 				model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth);
 
- 			},
 
- 			/**
 
- 			 * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly
 
- 			 * @private
 
- 			 */
 
- 			_getRingWeightOffset: function(datasetIndex) {
 
- 				var ringWeightOffset = 0;
 
- 				for (var i = 0; i < datasetIndex; ++i) {
 
- 					if (this.chart.isDatasetVisible(i)) {
 
- 						ringWeightOffset += this._getRingWeight(i);
 
- 					}
 
- 				}
 
- 				return ringWeightOffset;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getRingWeight: function(dataSetIndex) {
 
- 				return Math.max(valueOrDefault$5(this.chart.data.datasets[dataSetIndex].weight, 1), 0);
 
- 			},
 
- 			/**
 
- 			 * Returns the sum of all visibile data set weights.  This value can be 0.
 
- 			 * @private
 
- 			 */
 
- 			_getVisibleDatasetWeightTotal: function() {
 
- 				return this._getRingWeightOffset(this.chart.data.datasets.length);
 
- 			}
 
- 		});
 
- 		core_defaults._set('horizontalBar', {
 
- 			hover: {
 
- 				mode: 'index',
 
- 				axis: 'y'
 
- 			},
 
- 			scales: {
 
- 				xAxes: [{
 
- 					type: 'linear',
 
- 					position: 'bottom'
 
- 				}],
 
- 				yAxes: [{
 
- 					type: 'category',
 
- 					position: 'left',
 
- 					offset: true,
 
- 					gridLines: {
 
- 						offsetGridLines: true
 
- 					}
 
- 				}]
 
- 			},
 
- 			elements: {
 
- 				rectangle: {
 
- 					borderSkipped: 'left'
 
- 				}
 
- 			},
 
- 			tooltips: {
 
- 				mode: 'index',
 
- 				axis: 'y'
 
- 			}
 
- 		});
 
- 		core_defaults._set('global', {
 
- 			datasets: {
 
- 				horizontalBar: {
 
- 					categoryPercentage: 0.8,
 
- 					barPercentage: 0.9
 
- 				}
 
- 			}
 
- 		});
 
- 		var controller_horizontalBar = controller_bar.extend({
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getValueScaleId: function() {
 
- 				return this.getMeta().xAxisID;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getIndexScaleId: function() {
 
- 				return this.getMeta().yAxisID;
 
- 			}
 
- 		});
 
- 		var valueOrDefault$6 = helpers$1.valueOrDefault;
 
- 		var resolve$2 = helpers$1.options.resolve;
 
- 		var isPointInArea = helpers$1.canvas._isPointInArea;
 
- 		core_defaults._set('line', {
 
- 			showLines: true,
 
- 			spanGaps: false,
 
- 			hover: {
 
- 				mode: 'label'
 
- 			},
 
- 			scales: {
 
- 				xAxes: [{
 
- 					type: 'category',
 
- 					id: 'x-axis-0'
 
- 				}],
 
- 				yAxes: [{
 
- 					type: 'linear',
 
- 					id: 'y-axis-0'
 
- 				}]
 
- 			}
 
- 		});
 
- 		function scaleClip(scale, halfBorderWidth) {
 
- 			var tickOpts = scale && scale.options.ticks || {};
 
- 			var reverse = tickOpts.reverse;
 
- 			var min = tickOpts.min === undefined ? halfBorderWidth : 0;
 
- 			var max = tickOpts.max === undefined ? halfBorderWidth : 0;
 
- 			return {
 
- 				start: reverse ? max : min,
 
- 				end: reverse ? min : max
 
- 			};
 
- 		}
 
- 		function defaultClip(xScale, yScale, borderWidth) {
 
- 			var halfBorderWidth = borderWidth / 2;
 
- 			var x = scaleClip(xScale, halfBorderWidth);
 
- 			var y = scaleClip(yScale, halfBorderWidth);
 
- 			return {
 
- 				top: y.end,
 
- 				right: x.end,
 
- 				bottom: y.start,
 
- 				left: x.start
 
- 			};
 
- 		}
 
- 		function toClip(value) {
 
- 			var t, r, b, l;
 
- 			if (helpers$1.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
 
- 			};
 
- 		}
 
- 		var controller_line = core_datasetController.extend({
 
- 			datasetElementType: elements.Line,
 
- 			dataElementType: elements.Point,
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_datasetElementOptions: [
 
- 				'backgroundColor',
 
- 				'borderCapStyle',
 
- 				'borderColor',
 
- 				'borderDash',
 
- 				'borderDashOffset',
 
- 				'borderJoinStyle',
 
- 				'borderWidth',
 
- 				'cubicInterpolationMode',
 
- 				'fill'
 
- 			],
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_dataElementOptions: {
 
- 				backgroundColor: 'pointBackgroundColor',
 
- 				borderColor: 'pointBorderColor',
 
- 				borderWidth: 'pointBorderWidth',
 
- 				hitRadius: 'pointHitRadius',
 
- 				hoverBackgroundColor: 'pointHoverBackgroundColor',
 
- 				hoverBorderColor: 'pointHoverBorderColor',
 
- 				hoverBorderWidth: 'pointHoverBorderWidth',
 
- 				hoverRadius: 'pointHoverRadius',
 
- 				pointStyle: 'pointStyle',
 
- 				radius: 'pointRadius',
 
- 				rotation: 'pointRotation'
 
- 			},
 
- 			update: function(reset) {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var line = meta.dataset;
 
- 				var points = meta.data || [];
 
- 				var options = me.chart.options;
 
- 				var config = me._config;
 
- 				var showLine = me._showLine = valueOrDefault$6(config.showLine, options.showLines);
 
- 				var i, ilen;
 
- 				me._xScale = me.getScaleForId(meta.xAxisID);
 
- 				me._yScale = me.getScaleForId(meta.yAxisID);
 
- 				// Update Line
 
- 				if (showLine) {
 
- 					// Compatibility: If the properties are defined with only the old name, use those values
 
- 					if (config.tension !== undefined && config.lineTension === undefined) {
 
- 						config.lineTension = config.tension;
 
- 					}
 
- 					// Utility
 
- 					line._scale = me._yScale;
 
- 					line._datasetIndex = me.index;
 
- 					// Data
 
- 					line._children = points;
 
- 					// Model
 
- 					line._model = me._resolveDatasetElementOptions(line);
 
- 					line.pivot();
 
- 				}
 
- 				// Update Points
 
- 				for (i = 0, ilen = points.length; i < ilen; ++i) {
 
- 					me.updateElement(points[i], i, reset);
 
- 				}
 
- 				if (showLine && line._model.tension !== 0) {
 
- 					me.updateBezierControlPoints();
 
- 				}
 
- 				// Now pivot the point for animation
 
- 				for (i = 0, ilen = points.length; i < ilen; ++i) {
 
- 					points[i].pivot();
 
- 				}
 
- 			},
 
- 			updateElement: function(point, index, reset) {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var custom = point.custom || {};
 
- 				var dataset = me.getDataset();
 
- 				var datasetIndex = me.index;
 
- 				var value = dataset.data[index];
 
- 				var xScale = me._xScale;
 
- 				var yScale = me._yScale;
 
- 				var lineModel = meta.dataset._model;
 
- 				var x, y;
 
- 				var options = me._resolveDataElementOptions(point, index);
 
- 				x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
 
- 				y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
 
- 				// Utility
 
- 				point._xScale = xScale;
 
- 				point._yScale = yScale;
 
- 				point._options = options;
 
- 				point._datasetIndex = datasetIndex;
 
- 				point._index = index;
 
- 				// Desired view properties
 
- 				point._model = {
 
- 					x: x,
 
- 					y: y,
 
- 					skip: custom.skip || isNaN(x) || isNaN(y),
 
- 					// Appearance
 
- 					radius: options.radius,
 
- 					pointStyle: options.pointStyle,
 
- 					rotation: options.rotation,
 
- 					backgroundColor: options.backgroundColor,
 
- 					borderColor: options.borderColor,
 
- 					borderWidth: options.borderWidth,
 
- 					tension: valueOrDefault$6(custom.tension, lineModel ? lineModel.tension : 0),
 
- 					steppedLine: lineModel ? lineModel.steppedLine : false,
 
- 					// Tooltip
 
- 					hitRadius: options.hitRadius
 
- 				};
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_resolveDatasetElementOptions: function(element) {
 
- 				var me = this;
 
- 				var config = me._config;
 
- 				var custom = element.custom || {};
 
- 				var options = me.chart.options;
 
- 				var lineOptions = options.elements.line;
 
- 				var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
 
- 				// The default behavior of lines is to break at null values, according
 
- 				// to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
 
- 				// This option gives lines the ability to span gaps
 
- 				values.spanGaps = valueOrDefault$6(config.spanGaps, options.spanGaps);
 
- 				values.tension = valueOrDefault$6(config.lineTension, lineOptions.tension);
 
- 				values.steppedLine = resolve$2([custom.steppedLine, config.steppedLine, lineOptions.stepped]);
 
- 				values.clip = toClip(valueOrDefault$6(config.clip, defaultClip(me._xScale, me._yScale, values.borderWidth)));
 
- 				return values;
 
- 			},
 
- 			calculatePointY: function(value, index, datasetIndex) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var yScale = me._yScale;
 
- 				var sumPos = 0;
 
- 				var sumNeg = 0;
 
- 				var i, ds, dsMeta, stackedRightValue, rightValue, metasets, ilen;
 
- 				if (yScale.options.stacked) {
 
- 					rightValue = +yScale.getRightValue(value);
 
- 					metasets = chart._getSortedVisibleDatasetMetas();
 
- 					ilen = metasets.length;
 
- 					for (i = 0; i < ilen; ++i) {
 
- 						dsMeta = metasets[i];
 
- 						if (dsMeta.index === datasetIndex) {
 
- 							break;
 
- 						}
 
- 						ds = chart.data.datasets[dsMeta.index];
 
- 						if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id) {
 
- 							stackedRightValue = +yScale.getRightValue(ds.data[index]);
 
- 							if (stackedRightValue < 0) {
 
- 								sumNeg += stackedRightValue || 0;
 
- 							} else {
 
- 								sumPos += stackedRightValue || 0;
 
- 							}
 
- 						}
 
- 					}
 
- 					if (rightValue < 0) {
 
- 						return yScale.getPixelForValue(sumNeg + rightValue);
 
- 					}
 
- 					return yScale.getPixelForValue(sumPos + rightValue);
 
- 				}
 
- 				return yScale.getPixelForValue(value);
 
- 			},
 
- 			updateBezierControlPoints: function() {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var meta = me.getMeta();
 
- 				var lineModel = meta.dataset._model;
 
- 				var area = chart.chartArea;
 
- 				var points = meta.data || [];
 
- 				var i, ilen, model, controlPoints;
 
- 				// Only consider points that are drawn in case the spanGaps option is used
 
- 				if (lineModel.spanGaps) {
 
- 					points = points.filter(function(pt) {
 
- 						return !pt._model.skip;
 
- 					});
 
- 				}
 
- 				function capControlPoint(pt, min, max) {
 
- 					return Math.max(Math.min(pt, max), min);
 
- 				}
 
- 				if (lineModel.cubicInterpolationMode === 'monotone') {
 
- 					helpers$1.splineCurveMonotone(points);
 
- 				} else {
 
- 					for (i = 0, ilen = points.length; i < ilen; ++i) {
 
- 						model = points[i]._model;
 
- 						controlPoints = helpers$1.splineCurve(
 
- 							helpers$1.previousItem(points, i)._model,
 
- 							model,
 
- 							helpers$1.nextItem(points, i)._model,
 
- 							lineModel.tension
 
- 						);
 
- 						model.controlPointPreviousX = controlPoints.previous.x;
 
- 						model.controlPointPreviousY = controlPoints.previous.y;
 
- 						model.controlPointNextX = controlPoints.next.x;
 
- 						model.controlPointNextY = controlPoints.next.y;
 
- 					}
 
- 				}
 
- 				if (chart.options.elements.line.capBezierPoints) {
 
- 					for (i = 0, ilen = points.length; i < ilen; ++i) {
 
- 						model = points[i]._model;
 
- 						if (isPointInArea(model, area)) {
 
- 							if (i > 0 && isPointInArea(points[i - 1]._model, area)) {
 
- 								model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
 
- 								model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
 
- 							}
 
- 							if (i < points.length - 1 && isPointInArea(points[i + 1]._model, area)) {
 
- 								model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
 
- 								model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
 
- 							}
 
- 						}
 
- 					}
 
- 				}
 
- 			},
 
- 			draw: function() {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var meta = me.getMeta();
 
- 				var points = meta.data || [];
 
- 				var area = chart.chartArea;
 
- 				var canvas = chart.canvas;
 
- 				var i = 0;
 
- 				var ilen = points.length;
 
- 				var clip;
 
- 				if (me._showLine) {
 
- 					clip = meta.dataset._model.clip;
 
- 					helpers$1.canvas.clipArea(chart.ctx, {
 
- 						left: clip.left === false ? 0 : area.left - clip.left,
 
- 						right: clip.right === false ? canvas.width : area.right + clip.right,
 
- 						top: clip.top === false ? 0 : area.top - clip.top,
 
- 						bottom: clip.bottom === false ? canvas.height : area.bottom + clip.bottom
 
- 					});
 
- 					meta.dataset.draw();
 
- 					helpers$1.canvas.unclipArea(chart.ctx);
 
- 				}
 
- 				// Draw the points
 
- 				for (; i < ilen; ++i) {
 
- 					points[i].draw(area);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @protected
 
- 			 */
 
- 			setHoverStyle: function(point) {
 
- 				var model = point._model;
 
- 				var options = point._options;
 
- 				var getHoverColor = helpers$1.getHoverColor;
 
- 				point.$previousStyle = {
 
- 					backgroundColor: model.backgroundColor,
 
- 					borderColor: model.borderColor,
 
- 					borderWidth: model.borderWidth,
 
- 					radius: model.radius
 
- 				};
 
- 				model.backgroundColor = valueOrDefault$6(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
 
- 				model.borderColor = valueOrDefault$6(options.hoverBorderColor, getHoverColor(options.borderColor));
 
- 				model.borderWidth = valueOrDefault$6(options.hoverBorderWidth, options.borderWidth);
 
- 				model.radius = valueOrDefault$6(options.hoverRadius, options.radius);
 
- 			},
 
- 		});
 
- 		var resolve$3 = helpers$1.options.resolve;
 
- 		core_defaults._set('polarArea', {
 
- 			scale: {
 
- 				type: 'radialLinear',
 
- 				angleLines: {
 
- 					display: false
 
- 				},
 
- 				gridLines: {
 
- 					circular: true
 
- 				},
 
- 				pointLabels: {
 
- 					display: false
 
- 				},
 
- 				ticks: {
 
- 					beginAtZero: true
 
- 				}
 
- 			},
 
- 			// Boolean - Whether to animate the rotation of the chart
 
- 			animation: {
 
- 				animateRotate: true,
 
- 				animateScale: true
 
- 			},
 
- 			startAngle: -0.5 * Math.PI,
 
- 			legendCallback: function(chart) {
 
- 				var list = document.createElement('ul');
 
- 				var data = chart.data;
 
- 				var datasets = data.datasets;
 
- 				var labels = data.labels;
 
- 				var i, ilen, listItem, listItemSpan;
 
- 				list.setAttribute('class', chart.id + '-legend');
 
- 				if (datasets.length) {
 
- 					for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {
 
- 						listItem = list.appendChild(document.createElement('li'));
 
- 						listItemSpan = listItem.appendChild(document.createElement('span'));
 
- 						listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];
 
- 						if (labels[i]) {
 
- 							listItem.appendChild(document.createTextNode(labels[i]));
 
- 						}
 
- 					}
 
- 				}
 
- 				return list.outerHTML;
 
- 			},
 
- 			legend: {
 
- 				labels: {
 
- 					generateLabels: function(chart) {
 
- 						var data = chart.data;
 
- 						if (data.labels.length && data.datasets.length) {
 
- 							return data.labels.map(function(label, i) {
 
- 								var meta = chart.getDatasetMeta(0);
 
- 								var style = meta.controller.getStyle(i);
 
- 								return {
 
- 									text: label,
 
- 									fillStyle: style.backgroundColor,
 
- 									strokeStyle: style.borderColor,
 
- 									lineWidth: style.borderWidth,
 
- 									hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,
 
- 									// Extra data used for toggling the correct item
 
- 									index: i
 
- 								};
 
- 							});
 
- 						}
 
- 						return [];
 
- 					}
 
- 				},
 
- 				onClick: function(e, legendItem) {
 
- 					var index = legendItem.index;
 
- 					var chart = this.chart;
 
- 					var i, ilen, meta;
 
- 					for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
 
- 						meta = chart.getDatasetMeta(i);
 
- 						meta.data[index].hidden = !meta.data[index].hidden;
 
- 					}
 
- 					chart.update();
 
- 				}
 
- 			},
 
- 			// Need to override these to give a nice default
 
- 			tooltips: {
 
- 				callbacks: {
 
- 					title: function() {
 
- 						return '';
 
- 					},
 
- 					label: function(item, data) {
 
- 						return data.labels[item.index] + ': ' + item.yLabel;
 
- 					}
 
- 				}
 
- 			}
 
- 		});
 
- 		var controller_polarArea = core_datasetController.extend({
 
- 			dataElementType: elements.Arc,
 
- 			linkScales: helpers$1.noop,
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_dataElementOptions: [
 
- 				'backgroundColor',
 
- 				'borderColor',
 
- 				'borderWidth',
 
- 				'borderAlign',
 
- 				'hoverBackgroundColor',
 
- 				'hoverBorderColor',
 
- 				'hoverBorderWidth',
 
- 			],
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getIndexScaleId: function() {
 
- 				return this.chart.scale.id;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getValueScaleId: function() {
 
- 				return this.chart.scale.id;
 
- 			},
 
- 			update: function(reset) {
 
- 				var me = this;
 
- 				var dataset = me.getDataset();
 
- 				var meta = me.getMeta();
 
- 				var start = me.chart.options.startAngle || 0;
 
- 				var starts = me._starts = [];
 
- 				var angles = me._angles = [];
 
- 				var arcs = meta.data;
 
- 				var i, ilen, angle;
 
- 				me._updateRadius();
 
- 				meta.count = me.countVisibleElements();
 
- 				for (i = 0, ilen = dataset.data.length; i < ilen; i++) {
 
- 					starts[i] = start;
 
- 					angle = me._computeAngle(i);
 
- 					angles[i] = angle;
 
- 					start += angle;
 
- 				}
 
- 				for (i = 0, ilen = arcs.length; i < ilen; ++i) {
 
- 					arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);
 
- 					me.updateElement(arcs[i], i, reset);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_updateRadius: function() {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var chartArea = chart.chartArea;
 
- 				var opts = chart.options;
 
- 				var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
 
- 				chart.outerRadius = Math.max(minSize / 2, 0);
 
- 				chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
 
- 				chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
 
- 				me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
 
- 				me.innerRadius = me.outerRadius - chart.radiusLength;
 
- 			},
 
- 			updateElement: function(arc, index, reset) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var dataset = me.getDataset();
 
- 				var opts = chart.options;
 
- 				var animationOpts = opts.animation;
 
- 				var scale = chart.scale;
 
- 				var labels = chart.data.labels;
 
- 				var centerX = scale.xCenter;
 
- 				var centerY = scale.yCenter;
 
- 				// var negHalfPI = -0.5 * Math.PI;
 
- 				var datasetStartAngle = opts.startAngle;
 
- 				var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
 
- 				var startAngle = me._starts[index];
 
- 				var endAngle = startAngle + (arc.hidden ? 0 : me._angles[index]);
 
- 				var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
 
- 				var options = arc._options || {};
 
- 				helpers$1.extend(arc, {
 
- 					// Utility
 
- 					_datasetIndex: me.index,
 
- 					_index: index,
 
- 					_scale: scale,
 
- 					// Desired view properties
 
- 					_model: {
 
- 						backgroundColor: options.backgroundColor,
 
- 						borderColor: options.borderColor,
 
- 						borderWidth: options.borderWidth,
 
- 						borderAlign: options.borderAlign,
 
- 						x: centerX,
 
- 						y: centerY,
 
- 						innerRadius: 0,
 
- 						outerRadius: reset ? resetRadius : distance,
 
- 						startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
 
- 						endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
 
- 						label: helpers$1.valueAtIndexOrDefault(labels, index, labels[index])
 
- 					}
 
- 				});
 
- 				arc.pivot();
 
- 			},
 
- 			countVisibleElements: function() {
 
- 				var dataset = this.getDataset();
 
- 				var meta = this.getMeta();
 
- 				var count = 0;
 
- 				helpers$1.each(meta.data, function(element, index) {
 
- 					if (!isNaN(dataset.data[index]) && !element.hidden) {
 
- 						count++;
 
- 					}
 
- 				});
 
- 				return count;
 
- 			},
 
- 			/**
 
- 			 * @protected
 
- 			 */
 
- 			setHoverStyle: function(arc) {
 
- 				var model = arc._model;
 
- 				var options = arc._options;
 
- 				var getHoverColor = helpers$1.getHoverColor;
 
- 				var valueOrDefault = helpers$1.valueOrDefault;
 
- 				arc.$previousStyle = {
 
- 					backgroundColor: model.backgroundColor,
 
- 					borderColor: model.borderColor,
 
- 					borderWidth: model.borderWidth,
 
- 				};
 
- 				model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
 
- 				model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));
 
- 				model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_computeAngle: function(index) {
 
- 				var me = this;
 
- 				var count = this.getMeta().count;
 
- 				var dataset = me.getDataset();
 
- 				var meta = me.getMeta();
 
- 				if (isNaN(dataset.data[index]) || meta.data[index].hidden) {
 
- 					return 0;
 
- 				}
 
- 				// Scriptable options
 
- 				var context = {
 
- 					chart: me.chart,
 
- 					dataIndex: index,
 
- 					dataset: dataset,
 
- 					datasetIndex: me.index
 
- 				};
 
- 				return resolve$3([
 
- 					me.chart.options.elements.arc.angle,
 
- 					(2 * Math.PI) / count
 
- 				], context, index);
 
- 			}
 
- 		});
 
- 		core_defaults._set('pie', helpers$1.clone(core_defaults.doughnut));
 
- 		core_defaults._set('pie', {
 
- 			cutoutPercentage: 0
 
- 		});
 
- 		// Pie charts are Doughnut chart with different defaults
 
- 		var controller_pie = controller_doughnut;
 
- 		var valueOrDefault$7 = helpers$1.valueOrDefault;
 
- 		core_defaults._set('radar', {
 
- 			spanGaps: false,
 
- 			scale: {
 
- 				type: 'radialLinear'
 
- 			},
 
- 			elements: {
 
- 				line: {
 
- 					fill: 'start',
 
- 					tension: 0 // no bezier in radar
 
- 				}
 
- 			}
 
- 		});
 
- 		var controller_radar = core_datasetController.extend({
 
- 			datasetElementType: elements.Line,
 
- 			dataElementType: elements.Point,
 
- 			linkScales: helpers$1.noop,
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_datasetElementOptions: [
 
- 				'backgroundColor',
 
- 				'borderWidth',
 
- 				'borderColor',
 
- 				'borderCapStyle',
 
- 				'borderDash',
 
- 				'borderDashOffset',
 
- 				'borderJoinStyle',
 
- 				'fill'
 
- 			],
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_dataElementOptions: {
 
- 				backgroundColor: 'pointBackgroundColor',
 
- 				borderColor: 'pointBorderColor',
 
- 				borderWidth: 'pointBorderWidth',
 
- 				hitRadius: 'pointHitRadius',
 
- 				hoverBackgroundColor: 'pointHoverBackgroundColor',
 
- 				hoverBorderColor: 'pointHoverBorderColor',
 
- 				hoverBorderWidth: 'pointHoverBorderWidth',
 
- 				hoverRadius: 'pointHoverRadius',
 
- 				pointStyle: 'pointStyle',
 
- 				radius: 'pointRadius',
 
- 				rotation: 'pointRotation'
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getIndexScaleId: function() {
 
- 				return this.chart.scale.id;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getValueScaleId: function() {
 
- 				return this.chart.scale.id;
 
- 			},
 
- 			update: function(reset) {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var line = meta.dataset;
 
- 				var points = meta.data || [];
 
- 				var scale = me.chart.scale;
 
- 				var config = me._config;
 
- 				var i, ilen;
 
- 				// Compatibility: If the properties are defined with only the old name, use those values
 
- 				if (config.tension !== undefined && config.lineTension === undefined) {
 
- 					config.lineTension = config.tension;
 
- 				}
 
- 				// Utility
 
- 				line._scale = scale;
 
- 				line._datasetIndex = me.index;
 
- 				// Data
 
- 				line._children = points;
 
- 				line._loop = true;
 
- 				// Model
 
- 				line._model = me._resolveDatasetElementOptions(line);
 
- 				line.pivot();
 
- 				// Update Points
 
- 				for (i = 0, ilen = points.length; i < ilen; ++i) {
 
- 					me.updateElement(points[i], i, reset);
 
- 				}
 
- 				// Update bezier control points
 
- 				me.updateBezierControlPoints();
 
- 				// Now pivot the point for animation
 
- 				for (i = 0, ilen = points.length; i < ilen; ++i) {
 
- 					points[i].pivot();
 
- 				}
 
- 			},
 
- 			updateElement: function(point, index, reset) {
 
- 				var me = this;
 
- 				var custom = point.custom || {};
 
- 				var dataset = me.getDataset();
 
- 				var scale = me.chart.scale;
 
- 				var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
 
- 				var options = me._resolveDataElementOptions(point, index);
 
- 				var lineModel = me.getMeta().dataset._model;
 
- 				var x = reset ? scale.xCenter : pointPosition.x;
 
- 				var y = reset ? scale.yCenter : pointPosition.y;
 
- 				// Utility
 
- 				point._scale = scale;
 
- 				point._options = options;
 
- 				point._datasetIndex = me.index;
 
- 				point._index = index;
 
- 				// Desired view properties
 
- 				point._model = {
 
- 					x: x, // value not used in dataset scale, but we want a consistent API between scales
 
- 					y: y,
 
- 					skip: custom.skip || isNaN(x) || isNaN(y),
 
- 					// Appearance
 
- 					radius: options.radius,
 
- 					pointStyle: options.pointStyle,
 
- 					rotation: options.rotation,
 
- 					backgroundColor: options.backgroundColor,
 
- 					borderColor: options.borderColor,
 
- 					borderWidth: options.borderWidth,
 
- 					tension: valueOrDefault$7(custom.tension, lineModel ? lineModel.tension : 0),
 
- 					// Tooltip
 
- 					hitRadius: options.hitRadius
 
- 				};
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_resolveDatasetElementOptions: function() {
 
- 				var me = this;
 
- 				var config = me._config;
 
- 				var options = me.chart.options;
 
- 				var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
 
- 				values.spanGaps = valueOrDefault$7(config.spanGaps, options.spanGaps);
 
- 				values.tension = valueOrDefault$7(config.lineTension, options.elements.line.tension);
 
- 				return values;
 
- 			},
 
- 			updateBezierControlPoints: function() {
 
- 				var me = this;
 
- 				var meta = me.getMeta();
 
- 				var area = me.chart.chartArea;
 
- 				var points = meta.data || [];
 
- 				var i, ilen, model, controlPoints;
 
- 				// Only consider points that are drawn in case the spanGaps option is used
 
- 				if (meta.dataset._model.spanGaps) {
 
- 					points = points.filter(function(pt) {
 
- 						return !pt._model.skip;
 
- 					});
 
- 				}
 
- 				function capControlPoint(pt, min, max) {
 
- 					return Math.max(Math.min(pt, max), min);
 
- 				}
 
- 				for (i = 0, ilen = points.length; i < ilen; ++i) {
 
- 					model = points[i]._model;
 
- 					controlPoints = helpers$1.splineCurve(
 
- 						helpers$1.previousItem(points, i, true)._model,
 
- 						model,
 
- 						helpers$1.nextItem(points, i, true)._model,
 
- 						model.tension
 
- 					);
 
- 					// Prevent the bezier going outside of the bounds of the graph
 
- 					model.controlPointPreviousX = capControlPoint(controlPoints.previous.x, area.left, area.right);
 
- 					model.controlPointPreviousY = capControlPoint(controlPoints.previous.y, area.top, area.bottom);
 
- 					model.controlPointNextX = capControlPoint(controlPoints.next.x, area.left, area.right);
 
- 					model.controlPointNextY = capControlPoint(controlPoints.next.y, area.top, area.bottom);
 
- 				}
 
- 			},
 
- 			setHoverStyle: function(point) {
 
- 				var model = point._model;
 
- 				var options = point._options;
 
- 				var getHoverColor = helpers$1.getHoverColor;
 
- 				point.$previousStyle = {
 
- 					backgroundColor: model.backgroundColor,
 
- 					borderColor: model.borderColor,
 
- 					borderWidth: model.borderWidth,
 
- 					radius: model.radius
 
- 				};
 
- 				model.backgroundColor = valueOrDefault$7(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
 
- 				model.borderColor = valueOrDefault$7(options.hoverBorderColor, getHoverColor(options.borderColor));
 
- 				model.borderWidth = valueOrDefault$7(options.hoverBorderWidth, options.borderWidth);
 
- 				model.radius = valueOrDefault$7(options.hoverRadius, options.radius);
 
- 			}
 
- 		});
 
- 		core_defaults._set('scatter', {
 
- 			hover: {
 
- 				mode: 'single'
 
- 			},
 
- 			scales: {
 
- 				xAxes: [{
 
- 					id: 'x-axis-1',    // need an ID so datasets can reference the scale
 
- 					type: 'linear',    // scatter should not use a category axis
 
- 					position: 'bottom'
 
- 				}],
 
- 				yAxes: [{
 
- 					id: 'y-axis-1',
 
- 					type: 'linear',
 
- 					position: 'left'
 
- 				}]
 
- 			},
 
- 			tooltips: {
 
- 				callbacks: {
 
- 					title: function() {
 
- 						return '';     // doesn't make sense for scatter since data are formatted as a point
 
- 					},
 
- 					label: function(item) {
 
- 						return '(' + item.xLabel + ', ' + item.yLabel + ')';
 
- 					}
 
- 				}
 
- 			}
 
- 		});
 
- 		core_defaults._set('global', {
 
- 			datasets: {
 
- 				scatter: {
 
- 					showLine: false
 
- 				}
 
- 			}
 
- 		});
 
- 		// Scatter charts use line controllers
 
- 		var controller_scatter = controller_line;
 
- 		// NOTE export a map in which the key represents the controller type, not
 
- 		// the class, and so must be CamelCase in order to be correctly retrieved
 
- 		// by the controller in core.controller.js (`controllers[meta.type]`).
 
- 		var controllers = {
 
- 			bar: controller_bar,
 
- 			bubble: controller_bubble,
 
- 			doughnut: controller_doughnut,
 
- 			horizontalBar: controller_horizontalBar,
 
- 			line: controller_line,
 
- 			polarArea: controller_polarArea,
 
- 			pie: controller_pie,
 
- 			radar: controller_radar,
 
- 			scatter: controller_scatter
 
- 		};
 
- 		/**
 
- 		 * Helper function to get relative position for an event
 
- 		 * @param {Event|IEvent} event - The event to get the position for
 
- 		 * @param {Chart} chart - The chart
 
- 		 * @returns {object} the event position
 
- 		 */
 
- 		function getRelativePosition(e, chart) {
 
- 			if (e.native) {
 
- 				return {
 
- 					x: e.x,
 
- 					y: e.y
 
- 				};
 
- 			}
 
- 			return helpers$1.getRelativePosition(e, chart);
 
- 		}
 
- 		/**
 
- 		 * Helper function to traverse all of the visible elements in the chart
 
- 		 * @param {Chart} chart - the chart
 
- 		 * @param {function} handler - the callback to execute for each visible item
 
- 		 */
 
- 		function parseVisibleItems(chart, handler) {
 
- 			var metasets = chart._getSortedVisibleDatasetMetas();
 
- 			var metadata, i, j, ilen, jlen, element;
 
- 			for (i = 0, ilen = metasets.length; i < ilen; ++i) {
 
- 				metadata = metasets[i].data;
 
- 				for (j = 0, jlen = metadata.length; j < jlen; ++j) {
 
- 					element = metadata[j];
 
- 					if (!element._view.skip) {
 
- 						handler(element);
 
- 					}
 
- 				}
 
- 			}
 
- 		}
 
- 		/**
 
- 		 * Helper function to get the items that intersect the event position
 
- 		 * @param {ChartElement[]} items - elements to filter
 
- 		 * @param {object} position - the point to be nearest to
 
- 		 * @return {ChartElement[]} the nearest items
 
- 		 */
 
- 		function getIntersectItems(chart, position) {
 
- 			var elements = [];
 
- 			parseVisibleItems(chart, function(element) {
 
- 				if (element.inRange(position.x, position.y)) {
 
- 					elements.push(element);
 
- 				}
 
- 			});
 
- 			return elements;
 
- 		}
 
- 		/**
 
- 		 * Helper function to get the items nearest to the event position considering all visible items in teh chart
 
- 		 * @param {Chart} chart - the chart to look at elements from
 
- 		 * @param {object} position - the point to be nearest to
 
- 		 * @param {boolean} intersect - if true, only consider items that intersect the position
 
- 		 * @param {function} distanceMetric - function to provide the distance between points
 
- 		 * @return {ChartElement[]} the nearest items
 
- 		 */
 
- 		function getNearestItems(chart, position, intersect, distanceMetric) {
 
- 			var minDistance = Number.POSITIVE_INFINITY;
 
- 			var nearestItems = [];
 
- 			parseVisibleItems(chart, function(element) {
 
- 				if (intersect && !element.inRange(position.x, position.y)) {
 
- 					return;
 
- 				}
 
- 				var center = element.getCenterPoint();
 
- 				var distance = distanceMetric(position, center);
 
- 				if (distance < minDistance) {
 
- 					nearestItems = [element];
 
- 					minDistance = distance;
 
- 				} else if (distance === minDistance) {
 
- 					// Can have multiple items at the same distance in which case we sort by size
 
- 					nearestItems.push(element);
 
- 				}
 
- 			});
 
- 			return nearestItems;
 
- 		}
 
- 		/**
 
- 		 * Get a distance metric function for two points based on the
 
- 		 * axis mode setting
 
- 		 * @param {string} axis - the axis mode. x|y|xy
 
- 		 */
 
- 		function getDistanceMetricForAxis(axis) {
 
- 			var useX = axis.indexOf('x') !== -1;
 
- 			var useY = axis.indexOf('y') !== -1;
 
- 			return function(pt1, pt2) {
 
- 				var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
 
- 				var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
 
- 				return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
 
- 			};
 
- 		}
 
- 		function indexMode(chart, e, options) {
 
- 			var position = getRelativePosition(e, chart);
 
- 			// Default axis for index mode is 'x' to match old behaviour
 
- 			options.axis = options.axis || 'x';
 
- 			var distanceMetric = getDistanceMetricForAxis(options.axis);
 
- 			var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
 
- 			var elements = [];
 
- 			if (!items.length) {
 
- 				return [];
 
- 			}
 
- 			chart._getSortedVisibleDatasetMetas().forEach(function(meta) {
 
- 				var element = meta.data[items[0]._index];
 
- 				// don't count items that are skipped (null data)
 
- 				if (element && !element._view.skip) {
 
- 					elements.push(element);
 
- 				}
 
- 			});
 
- 			return elements;
 
- 		}
 
- 		/**
 
- 		 * @interface IInteractionOptions
 
- 		 */
 
- 		/**
 
- 		 * If true, only consider items that intersect the point
 
- 		 * @name IInterfaceOptions#boolean
 
- 		 * @type Boolean
 
- 		 */
 
- 		/**
 
- 		 * Contains interaction related functions
 
- 		 * @namespace Chart.Interaction
 
- 		 */
 
- 		var core_interaction = {
 
- 			// Helper function for different modes
 
- 			modes: {
 
- 				single: function(chart, e) {
 
- 					var position = getRelativePosition(e, chart);
 
- 					var elements = [];
 
- 					parseVisibleItems(chart, function(element) {
 
- 						if (element.inRange(position.x, position.y)) {
 
- 							elements.push(element);
 
- 							return elements;
 
- 						}
 
- 					});
 
- 					return elements.slice(0, 1);
 
- 				},
 
- 				/**
 
- 				 * @function Chart.Interaction.modes.label
 
- 				 * @deprecated since version 2.4.0
 
- 				 * @todo remove at version 3
 
- 				 * @private
 
- 				 */
 
- 				label: indexMode,
 
- 				/**
 
- 				 * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
 
- 				 * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
 
- 				 * @function Chart.Interaction.modes.index
 
- 				 * @since v2.4.0
 
- 				 * @param {Chart} chart - the chart we are returning items from
 
- 				 * @param {Event} e - the event we are find things at
 
- 				 * @param {IInteractionOptions} options - options to use during interaction
 
- 				 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
 
- 				 */
 
- 				index: indexMode,
 
- 				/**
 
- 				 * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
 
- 				 * If the options.intersect is false, we find the nearest item and return the items in that dataset
 
- 				 * @function Chart.Interaction.modes.dataset
 
- 				 * @param {Chart} chart - the chart we are returning items from
 
- 				 * @param {Event} e - the event we are find things at
 
- 				 * @param {IInteractionOptions} options - options to use during interaction
 
- 				 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
 
- 				 */
 
- 				dataset: function(chart, e, options) {
 
- 					var position = getRelativePosition(e, chart);
 
- 					options.axis = options.axis || 'xy';
 
- 					var distanceMetric = getDistanceMetricForAxis(options.axis);
 
- 					var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
 
- 					if (items.length > 0) {
 
- 						items = chart.getDatasetMeta(items[0]._datasetIndex).data;
 
- 					}
 
- 					return items;
 
- 				},
 
- 				/**
 
- 				 * @function Chart.Interaction.modes.x-axis
 
- 				 * @deprecated since version 2.4.0. Use index mode and intersect == true
 
- 				 * @todo remove at version 3
 
- 				 * @private
 
- 				 */
 
- 				'x-axis': function(chart, e) {
 
- 					return indexMode(chart, e, {intersect: false});
 
- 				},
 
- 				/**
 
- 				 * Point mode returns all elements that hit test based on the event position
 
- 				 * of the event
 
- 				 * @function Chart.Interaction.modes.intersect
 
- 				 * @param {Chart} chart - the chart we are returning items from
 
- 				 * @param {Event} e - the event we are find things at
 
- 				 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
 
- 				 */
 
- 				point: function(chart, e) {
 
- 					var position = getRelativePosition(e, chart);
 
- 					return getIntersectItems(chart, position);
 
- 				},
 
- 				/**
 
- 				 * nearest mode returns the element closest to the point
 
- 				 * @function Chart.Interaction.modes.intersect
 
- 				 * @param {Chart} chart - the chart we are returning items from
 
- 				 * @param {Event} e - the event we are find things at
 
- 				 * @param {IInteractionOptions} options - options to use
 
- 				 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
 
- 				 */
 
- 				nearest: function(chart, e, options) {
 
- 					var position = getRelativePosition(e, chart);
 
- 					options.axis = options.axis || 'xy';
 
- 					var distanceMetric = getDistanceMetricForAxis(options.axis);
 
- 					return getNearestItems(chart, position, options.intersect, distanceMetric);
 
- 				},
 
- 				/**
 
- 				 * x mode returns the elements that hit-test at the current x coordinate
 
- 				 * @function Chart.Interaction.modes.x
 
- 				 * @param {Chart} chart - the chart we are returning items from
 
- 				 * @param {Event} e - the event we are find things at
 
- 				 * @param {IInteractionOptions} options - options to use
 
- 				 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
 
- 				 */
 
- 				x: function(chart, e, options) {
 
- 					var position = getRelativePosition(e, chart);
 
- 					var items = [];
 
- 					var intersectsItem = false;
 
- 					parseVisibleItems(chart, function(element) {
 
- 						if (element.inXRange(position.x)) {
 
- 							items.push(element);
 
- 						}
 
- 						if (element.inRange(position.x, position.y)) {
 
- 							intersectsItem = true;
 
- 						}
 
- 					});
 
- 					// If we want to trigger on an intersect and we don't have any items
 
- 					// that intersect the position, return nothing
 
- 					if (options.intersect && !intersectsItem) {
 
- 						items = [];
 
- 					}
 
- 					return items;
 
- 				},
 
- 				/**
 
- 				 * y mode returns the elements that hit-test at the current y coordinate
 
- 				 * @function Chart.Interaction.modes.y
 
- 				 * @param {Chart} chart - the chart we are returning items from
 
- 				 * @param {Event} e - the event we are find things at
 
- 				 * @param {IInteractionOptions} options - options to use
 
- 				 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
 
- 				 */
 
- 				y: function(chart, e, options) {
 
- 					var position = getRelativePosition(e, chart);
 
- 					var items = [];
 
- 					var intersectsItem = false;
 
- 					parseVisibleItems(chart, function(element) {
 
- 						if (element.inYRange(position.y)) {
 
- 							items.push(element);
 
- 						}
 
- 						if (element.inRange(position.x, position.y)) {
 
- 							intersectsItem = true;
 
- 						}
 
- 					});
 
- 					// If we want to trigger on an intersect and we don't have any items
 
- 					// that intersect the position, return nothing
 
- 					if (options.intersect && !intersectsItem) {
 
- 						items = [];
 
- 					}
 
- 					return items;
 
- 				}
 
- 			}
 
- 		};
 
- 		var extend = helpers$1.extend;
 
- 		function filterByPosition(array, position) {
 
- 			return helpers$1.where(array, function(v) {
 
- 				return v.pos === position;
 
- 			});
 
- 		}
 
- 		function sortByWeight(array, reverse) {
 
- 			return array.sort(function(a, b) {
 
- 				var v0 = reverse ? b : a;
 
- 				var v1 = reverse ? a : b;
 
- 				return v0.weight === v1.weight ?
 
- 					v0.index - v1.index :
 
- 					v0.weight - v1.weight;
 
- 			});
 
- 		}
 
- 		function wrapBoxes(boxes) {
 
- 			var layoutBoxes = [];
 
- 			var i, ilen, box;
 
- 			for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) {
 
- 				box = boxes[i];
 
- 				layoutBoxes.push({
 
- 					index: i,
 
- 					box: box,
 
- 					pos: box.position,
 
- 					horizontal: box.isHorizontal(),
 
- 					weight: box.weight
 
- 				});
 
- 			}
 
- 			return layoutBoxes;
 
- 		}
 
- 		function setLayoutDims(layouts, params) {
 
- 			var i, ilen, layout;
 
- 			for (i = 0, ilen = layouts.length; i < ilen; ++i) {
 
- 				layout = layouts[i];
 
- 				// store width used instead of chartArea.w in fitBoxes
 
- 				layout.width = layout.horizontal
 
- 					? layout.box.fullWidth && params.availableWidth
 
- 					: params.vBoxMaxWidth;
 
- 				// store height used instead of chartArea.h in fitBoxes
 
- 				layout.height = layout.horizontal && params.hBoxMaxHeight;
 
- 			}
 
- 		}
 
- 		function buildLayoutBoxes(boxes) {
 
- 			var layoutBoxes = wrapBoxes(boxes);
 
- 			var left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
 
- 			var right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
 
- 			var top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
 
- 			var bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
 
- 			return {
 
- 				leftAndTop: left.concat(top),
 
- 				rightAndBottom: right.concat(bottom),
 
- 				chartArea: filterByPosition(layoutBoxes, 'chartArea'),
 
- 				vertical: left.concat(right),
 
- 				horizontal: top.concat(bottom)
 
- 			};
 
- 		}
 
- 		function getCombinedMax(maxPadding, chartArea, a, b) {
 
- 			return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
 
- 		}
 
- 		function updateDims(chartArea, params, layout) {
 
- 			var box = layout.box;
 
- 			var maxPadding = chartArea.maxPadding;
 
- 			var newWidth, newHeight;
 
- 			if (layout.size) {
 
- 				// this layout was already counted for, lets first reduce old size
 
- 				chartArea[layout.pos] -= layout.size;
 
- 			}
 
- 			layout.size = layout.horizontal ? box.height : box.width;
 
- 			chartArea[layout.pos] += layout.size;
 
- 			if (box.getPadding) {
 
- 				var boxPadding = box.getPadding();
 
- 				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);
 
- 			}
 
- 			newWidth = params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right');
 
- 			newHeight = params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom');
 
- 			if (newWidth !== chartArea.w || newHeight !== chartArea.h) {
 
- 				chartArea.w = newWidth;
 
- 				chartArea.h = newHeight;
 
- 				// return true if chart area changed in layout's direction
 
- 				var sizes = layout.horizontal ? [newWidth, chartArea.w] : [newHeight, chartArea.h];
 
- 				return sizes[0] !== sizes[1] && (!isNaN(sizes[0]) || !isNaN(sizes[1]));
 
- 			}
 
- 		}
 
- 		function handleMaxPadding(chartArea) {
 
- 			var maxPadding = chartArea.maxPadding;
 
- 			function updatePos(pos) {
 
- 				var 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) {
 
- 			var maxPadding = chartArea.maxPadding;
 
- 			function marginForPositions(positions) {
 
- 				var margin = {left: 0, top: 0, right: 0, bottom: 0};
 
- 				positions.forEach(function(pos) {
 
- 					margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
 
- 				});
 
- 				return margin;
 
- 			}
 
- 			return horizontal
 
- 				? marginForPositions(['left', 'right'])
 
- 				: marginForPositions(['top', 'bottom']);
 
- 		}
 
- 		function fitBoxes(boxes, chartArea, params) {
 
- 			var refitBoxes = [];
 
- 			var i, ilen, layout, box, refit, changed;
 
- 			for (i = 0, ilen = boxes.length; i < ilen; ++i) {
 
- 				layout = boxes[i];
 
- 				box = layout.box;
 
- 				box.update(
 
- 					layout.width || chartArea.w,
 
- 					layout.height || chartArea.h,
 
- 					getMargins(layout.horizontal, chartArea)
 
- 				);
 
- 				if (updateDims(chartArea, params, layout)) {
 
- 					changed = true;
 
- 					if (refitBoxes.length) {
 
- 						// Dimensions changed and there were non full width boxes before this
 
- 						// -> we have to refit those
 
- 						refit = true;
 
- 					}
 
- 				}
 
- 				if (!box.fullWidth) { // fullWidth boxes don't need to be re-fitted in any case
 
- 					refitBoxes.push(layout);
 
- 				}
 
- 			}
 
- 			return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed;
 
- 		}
 
- 		function placeBoxes(boxes, chartArea, params) {
 
- 			var userPadding = params.padding;
 
- 			var x = chartArea.x;
 
- 			var y = chartArea.y;
 
- 			var i, ilen, layout, box;
 
- 			for (i = 0, ilen = boxes.length; i < ilen; ++i) {
 
- 				layout = boxes[i];
 
- 				box = layout.box;
 
- 				if (layout.horizontal) {
 
- 					box.left = box.fullWidth ? userPadding.left : chartArea.left;
 
- 					box.right = box.fullWidth ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w;
 
- 					box.top = y;
 
- 					box.bottom = y + box.height;
 
- 					box.width = box.right - box.left;
 
- 					y = box.bottom;
 
- 				} else {
 
- 					box.left = x;
 
- 					box.right = x + box.width;
 
- 					box.top = chartArea.top;
 
- 					box.bottom = chartArea.top + chartArea.h;
 
- 					box.height = box.bottom - box.top;
 
- 					x = box.right;
 
- 				}
 
- 			}
 
- 			chartArea.x = x;
 
- 			chartArea.y = y;
 
- 		}
 
- 		core_defaults._set('global', {
 
- 			layout: {
 
- 				padding: {
 
- 					top: 0,
 
- 					right: 0,
 
- 					bottom: 0,
 
- 					left: 0
 
- 				}
 
- 			}
 
- 		});
 
- 		/**
 
- 		 * @interface ILayoutItem
 
- 		 * @prop {string} position - The position of the item in the chart layout. Possible values are
 
- 		 * 'left', 'top', 'right', 'bottom', and 'chartArea'
 
- 		 * @prop {number} weight - The weight used to sort the item. Higher weights are further away from the chart area
 
- 		 * @prop {boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
 
- 		 * @prop {function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
 
- 		 * @prop {function} update - Takes two parameters: width and height. Returns size of item
 
- 		 * @prop {function} getPadding -  Returns an object with padding on the edges
 
- 		 * @prop {number} width - Width of item. Must be valid after update()
 
- 		 * @prop {number} height - Height of item. Must be valid after update()
 
- 		 * @prop {number} left - Left edge of the item. Set by layout system and cannot be used in update
 
- 		 * @prop {number} top - Top edge of the item. Set by layout system and cannot be used in update
 
- 		 * @prop {number} right - Right edge of the item. Set by layout system and cannot be used in update
 
- 		 * @prop {number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
 
- 		 */
 
- 		// The layout service is very self explanatory.  It's responsible for the layout within a chart.
 
- 		// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
 
- 		// It is this service's responsibility of carrying out that layout.
 
- 		var core_layouts = {
 
- 			defaults: {},
 
- 			/**
 
- 			 * Register a box to a chart.
 
- 			 * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
 
- 			 * @param {Chart} chart - the chart to use
 
- 			 * @param {ILayoutItem} item - the item to add to be layed out
 
- 			 */
 
- 			addBox: function(chart, item) {
 
- 				if (!chart.boxes) {
 
- 					chart.boxes = [];
 
- 				}
 
- 				// initialize item with default values
 
- 				item.fullWidth = item.fullWidth || false;
 
- 				item.position = item.position || 'top';
 
- 				item.weight = item.weight || 0;
 
- 				item._layers = item._layers || function() {
 
- 					return [{
 
- 						z: 0,
 
- 						draw: function() {
 
- 							item.draw.apply(item, arguments);
 
- 						}
 
- 					}];
 
- 				};
 
- 				chart.boxes.push(item);
 
- 			},
 
- 			/**
 
- 			 * Remove a layoutItem from a chart
 
- 			 * @param {Chart} chart - the chart to remove the box from
 
- 			 * @param {ILayoutItem} layoutItem - the item to remove from the layout
 
- 			 */
 
- 			removeBox: function(chart, layoutItem) {
 
- 				var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
 
- 				if (index !== -1) {
 
- 					chart.boxes.splice(index, 1);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Sets (or updates) options on the given `item`.
 
- 			 * @param {Chart} chart - the chart in which the item lives (or will be added to)
 
- 			 * @param {ILayoutItem} item - the item to configure with the given options
 
- 			 * @param {object} options - the new item options.
 
- 			 */
 
- 			configure: function(chart, item, options) {
 
- 				var props = ['fullWidth', 'position', 'weight'];
 
- 				var ilen = props.length;
 
- 				var i = 0;
 
- 				var prop;
 
- 				for (; i < ilen; ++i) {
 
- 					prop = props[i];
 
- 					if (options.hasOwnProperty(prop)) {
 
- 						item[prop] = options[prop];
 
- 					}
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Fits boxes of the given chart into the given size by having each box measure itself
 
- 			 * then running a fitting algorithm
 
- 			 * @param {Chart} chart - the chart
 
- 			 * @param {number} width - the width to fit into
 
- 			 * @param {number} height - the height to fit into
 
- 			 */
 
- 			update: function(chart, width, height) {
 
- 				if (!chart) {
 
- 					return;
 
- 				}
 
- 				var layoutOptions = chart.options.layout || {};
 
- 				var padding = helpers$1.options.toPadding(layoutOptions.padding);
 
- 				var availableWidth = width - padding.width;
 
- 				var availableHeight = height - padding.height;
 
- 				var boxes = buildLayoutBoxes(chart.boxes);
 
- 				var verticalBoxes = boxes.vertical;
 
- 				var horizontalBoxes = boxes.horizontal;
 
- 				// Essentially we now have any number of boxes on each of the 4 sides.
 
- 				// Our canvas looks like the following.
 
- 				// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
 
- 				// B1 is the bottom axis
 
- 				// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
 
- 				// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
 
- 				// an error will be thrown.
 
- 				//
 
- 				// |----------------------------------------------------|
 
- 				// |                  T1 (Full Width)                   |
 
- 				// |----------------------------------------------------|
 
- 				// |    |    |                 T2                  |    |
 
- 				// |    |----|-------------------------------------|----|
 
- 				// |    |    | C1 |                           | C2 |    |
 
- 				// |    |    |----|                           |----|    |
 
- 				// |    |    |                                     |    |
 
- 				// | L1 | L2 |           ChartArea (C0)            | R1 |
 
- 				// |    |    |                                     |    |
 
- 				// |    |    |----|                           |----|    |
 
- 				// |    |    | C3 |                           | C4 |    |
 
- 				// |    |----|-------------------------------------|----|
 
- 				// |    |    |                 B1                  |    |
 
- 				// |----------------------------------------------------|
 
- 				// |                  B2 (Full Width)                   |
 
- 				// |----------------------------------------------------|
 
- 				//
 
- 				var params = Object.freeze({
 
- 					outerWidth: width,
 
- 					outerHeight: height,
 
- 					padding: padding,
 
- 					availableWidth: availableWidth,
 
- 					vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length,
 
- 					hBoxMaxHeight: availableHeight / 2
 
- 				});
 
- 				var chartArea = extend({
 
- 					maxPadding: extend({}, padding),
 
- 					w: availableWidth,
 
- 					h: availableHeight,
 
- 					x: padding.left,
 
- 					y: padding.top
 
- 				}, padding);
 
- 				setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
 
- 				// First fit vertical boxes
 
- 				fitBoxes(verticalBoxes, chartArea, params);
 
- 				// Then fit horizontal boxes
 
- 				if (fitBoxes(horizontalBoxes, chartArea, params)) {
 
- 					// if the area changed, re-fit vertical boxes
 
- 					fitBoxes(verticalBoxes, chartArea, params);
 
- 				}
 
- 				handleMaxPadding(chartArea);
 
- 				// Finally place the boxes to correct coordinates
 
- 				placeBoxes(boxes.leftAndTop, chartArea, params);
 
- 				// Move to opposite side of chart
 
- 				chartArea.x += chartArea.w;
 
- 				chartArea.y += chartArea.h;
 
- 				placeBoxes(boxes.rightAndBottom, chartArea, params);
 
- 				chart.chartArea = {
 
- 					left: chartArea.left,
 
- 					top: chartArea.top,
 
- 					right: chartArea.left + chartArea.w,
 
- 					bottom: chartArea.top + chartArea.h
 
- 				};
 
- 				// Finally update boxes in chartArea (radial scale for example)
 
- 				helpers$1.each(boxes.chartArea, function(layout) {
 
- 					var box = layout.box;
 
- 					extend(box, chart.chartArea);
 
- 					box.update(chartArea.w, chartArea.h);
 
- 				});
 
- 			}
 
- 		};
 
- 		/**
 
- 		 * Platform fallback implementation (minimal).
 
- 		 * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939
 
- 		 */
 
- 		var platform_basic = {
 
- 			acquireContext: function(item) {
 
- 				if (item && item.canvas) {
 
- 					// Support for any object associated to a canvas (including a context2d)
 
- 					item = item.canvas;
 
- 				}
 
- 				return item && item.getContext('2d') || null;
 
- 			}
 
- 		};
 
- 		var platform_dom = "/*\r\n * DOM element rendering detection\r\n * https://davidwalsh.name/detect-node-insertion\r\n */\r\n@keyframes chartjs-render-animation {\r\n\tfrom { opacity: 0.99; }\r\n\tto { opacity: 1; }\r\n}\r\n\r\n.chartjs-render-monitor {\r\n\tanimation: chartjs-render-animation 0.001s;\r\n}\r\n\r\n/*\r\n * DOM element resizing detection\r\n * https://github.com/marcj/css-element-queries\r\n */\r\n.chartjs-size-monitor,\r\n.chartjs-size-monitor-expand,\r\n.chartjs-size-monitor-shrink {\r\n\tposition: absolute;\r\n\tdirection: ltr;\r\n\tleft: 0;\r\n\ttop: 0;\r\n\tright: 0;\r\n\tbottom: 0;\r\n\toverflow: hidden;\r\n\tpointer-events: none;\r\n\tvisibility: hidden;\r\n\tz-index: -1;\r\n}\r\n\r\n.chartjs-size-monitor-expand > div {\r\n\tposition: absolute;\r\n\twidth: 1000000px;\r\n\theight: 1000000px;\r\n\tleft: 0;\r\n\ttop: 0;\r\n}\r\n\r\n.chartjs-size-monitor-shrink > div {\r\n\tposition: absolute;\r\n\twidth: 200%;\r\n\theight: 200%;\r\n\tleft: 0;\r\n\ttop: 0;\r\n}\r\n";
 
- 		var platform_dom$1 = /*#__PURE__*/Object.freeze({
 
- 		__proto__: null,
 
- 		'default': platform_dom
 
- 		});
 
- 		var stylesheet = getCjsExportFromNamespace(platform_dom$1);
 
- 		var EXPANDO_KEY = '$chartjs';
 
- 		var CSS_PREFIX = 'chartjs-';
 
- 		var CSS_SIZE_MONITOR = CSS_PREFIX + 'size-monitor';
 
- 		var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
 
- 		var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
 
- 		var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];
 
- 		/**
 
- 		 * DOM event types -> Chart.js event types.
 
- 		 * Note: only events with different types are mapped.
 
- 		 * @see https://developer.mozilla.org/en-US/docs/Web/Events
 
- 		 */
 
- 		var EVENT_TYPES = {
 
- 			touchstart: 'mousedown',
 
- 			touchmove: 'mousemove',
 
- 			touchend: 'mouseup',
 
- 			pointerenter: 'mouseenter',
 
- 			pointerdown: 'mousedown',
 
- 			pointermove: 'mousemove',
 
- 			pointerup: 'mouseup',
 
- 			pointerleave: 'mouseout',
 
- 			pointerout: 'mouseout'
 
- 		};
 
- 		/**
 
- 		 * The "used" size is the final value of a dimension property after all calculations have
 
- 		 * been performed. This method uses the computed style of `element` but returns undefined
 
- 		 * if the computed style is not expressed in pixels. That can happen in some cases where
 
- 		 * `element` has a size relative to its parent and this last one is not yet displayed,
 
- 		 * for example because of `display: none` on a parent node.
 
- 		 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
 
- 		 * @returns {number} Size in pixels or undefined if unknown.
 
- 		 */
 
- 		function readUsedSize(element, property) {
 
- 			var value = helpers$1.getStyle(element, property);
 
- 			var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
 
- 			return matches ? Number(matches[1]) : undefined;
 
- 		}
 
- 		/**
 
- 		 * Initializes the canvas style and render size without modifying the canvas display size,
 
- 		 * since responsiveness is handled by the controller.resize() method. The config is used
 
- 		 * to determine the aspect ratio to apply in case no explicit height has been specified.
 
- 		 */
 
- 		function initCanvas(canvas, config) {
 
- 			var style = canvas.style;
 
- 			// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
 
- 			// returns null or '' if no explicit value has been set to the canvas attribute.
 
- 			var renderHeight = canvas.getAttribute('height');
 
- 			var renderWidth = canvas.getAttribute('width');
 
- 			// Chart.js modifies some canvas values that we want to restore on destroy
 
- 			canvas[EXPANDO_KEY] = {
 
- 				initial: {
 
- 					height: renderHeight,
 
- 					width: renderWidth,
 
- 					style: {
 
- 						display: style.display,
 
- 						height: style.height,
 
- 						width: style.width
 
- 					}
 
- 				}
 
- 			};
 
- 			// Force canvas to display as block to avoid extra space caused by inline
 
- 			// elements, which would interfere with the responsive resize process.
 
- 			// https://github.com/chartjs/Chart.js/issues/2538
 
- 			style.display = style.display || 'block';
 
- 			if (renderWidth === null || renderWidth === '') {
 
- 				var displayWidth = readUsedSize(canvas, 'width');
 
- 				if (displayWidth !== undefined) {
 
- 					canvas.width = displayWidth;
 
- 				}
 
- 			}
 
- 			if (renderHeight === null || renderHeight === '') {
 
- 				if (canvas.style.height === '') {
 
- 					// If no explicit render height and style height, let's apply the aspect ratio,
 
- 					// which one can be specified by the user but also by charts as default option
 
- 					// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
 
- 					canvas.height = canvas.width / (config.options.aspectRatio || 2);
 
- 				} else {
 
- 					var displayHeight = readUsedSize(canvas, 'height');
 
- 					if (displayWidth !== undefined) {
 
- 						canvas.height = displayHeight;
 
- 					}
 
- 				}
 
- 			}
 
- 			return canvas;
 
- 		}
 
- 		/**
 
- 		 * Detects support for options object argument in addEventListener.
 
- 		 * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
 
- 		 * @private
 
- 		 */
 
- 		var supportsEventListenerOptions = (function() {
 
- 			var supports = false;
 
- 			try {
 
- 				var options = Object.defineProperty({}, 'passive', {
 
- 					// eslint-disable-next-line getter-return
 
- 					get: function() {
 
- 						supports = true;
 
- 					}
 
- 				});
 
- 				window.addEventListener('e', null, options);
 
- 			} catch (e) {
 
- 				// continue regardless of error
 
- 			}
 
- 			return supports;
 
- 		}());
 
- 		// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
 
- 		// https://github.com/chartjs/Chart.js/issues/4287
 
- 		var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
 
- 		function addListener(node, type, listener) {
 
- 			node.addEventListener(type, listener, eventListenerOptions);
 
- 		}
 
- 		function removeListener(node, type, listener) {
 
- 			node.removeEventListener(type, listener, eventListenerOptions);
 
- 		}
 
- 		function createEvent(type, chart, x, y, nativeEvent) {
 
- 			return {
 
- 				type: type,
 
- 				chart: chart,
 
- 				native: nativeEvent || null,
 
- 				x: x !== undefined ? x : null,
 
- 				y: y !== undefined ? y : null,
 
- 			};
 
- 		}
 
- 		function fromNativeEvent(event, chart) {
 
- 			var type = EVENT_TYPES[event.type] || event.type;
 
- 			var pos = helpers$1.getRelativePosition(event, chart);
 
- 			return createEvent(type, chart, pos.x, pos.y, event);
 
- 		}
 
- 		function throttled(fn, thisArg) {
 
- 			var ticking = false;
 
- 			var args = [];
 
- 			return function() {
 
- 				args = Array.prototype.slice.call(arguments);
 
- 				thisArg = thisArg || this;
 
- 				if (!ticking) {
 
- 					ticking = true;
 
- 					helpers$1.requestAnimFrame.call(window, function() {
 
- 						ticking = false;
 
- 						fn.apply(thisArg, args);
 
- 					});
 
- 				}
 
- 			};
 
- 		}
 
- 		function createDiv(cls) {
 
- 			var el = document.createElement('div');
 
- 			el.className = cls || '';
 
- 			return el;
 
- 		}
 
- 		// Implementation based on https://github.com/marcj/css-element-queries
 
- 		function createResizer(handler) {
 
- 			var maxSize = 1000000;
 
- 			// NOTE(SB) Don't use innerHTML because it could be considered unsafe.
 
- 			// https://github.com/chartjs/Chart.js/issues/5902
 
- 			var resizer = createDiv(CSS_SIZE_MONITOR);
 
- 			var expand = createDiv(CSS_SIZE_MONITOR + '-expand');
 
- 			var shrink = createDiv(CSS_SIZE_MONITOR + '-shrink');
 
- 			expand.appendChild(createDiv());
 
- 			shrink.appendChild(createDiv());
 
- 			resizer.appendChild(expand);
 
- 			resizer.appendChild(shrink);
 
- 			resizer._reset = function() {
 
- 				expand.scrollLeft = maxSize;
 
- 				expand.scrollTop = maxSize;
 
- 				shrink.scrollLeft = maxSize;
 
- 				shrink.scrollTop = maxSize;
 
- 			};
 
- 			var onScroll = function() {
 
- 				resizer._reset();
 
- 				handler();
 
- 			};
 
- 			addListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
 
- 			addListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));
 
- 			return resizer;
 
- 		}
 
- 		// https://davidwalsh.name/detect-node-insertion
 
- 		function watchForRender(node, handler) {
 
- 			var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
 
- 			var proxy = expando.renderProxy = function(e) {
 
- 				if (e.animationName === CSS_RENDER_ANIMATION) {
 
- 					handler();
 
- 				}
 
- 			};
 
- 			helpers$1.each(ANIMATION_START_EVENTS, function(type) {
 
- 				addListener(node, type, proxy);
 
- 			});
 
- 			// #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
 
- 			// is removed then added back immediately (same animation frame?). Accessing the
 
- 			// `offsetParent` property will force a reflow and re-evaluate the CSS animation.
 
- 			// https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
 
- 			// https://github.com/chartjs/Chart.js/issues/4737
 
- 			expando.reflow = !!node.offsetParent;
 
- 			node.classList.add(CSS_RENDER_MONITOR);
 
- 		}
 
- 		function unwatchForRender(node) {
 
- 			var expando = node[EXPANDO_KEY] || {};
 
- 			var proxy = expando.renderProxy;
 
- 			if (proxy) {
 
- 				helpers$1.each(ANIMATION_START_EVENTS, function(type) {
 
- 					removeListener(node, type, proxy);
 
- 				});
 
- 				delete expando.renderProxy;
 
- 			}
 
- 			node.classList.remove(CSS_RENDER_MONITOR);
 
- 		}
 
- 		function addResizeListener(node, listener, chart) {
 
- 			var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
 
- 			// Let's keep track of this added resizer and thus avoid DOM query when removing it.
 
- 			var resizer = expando.resizer = createResizer(throttled(function() {
 
- 				if (expando.resizer) {
 
- 					var container = chart.options.maintainAspectRatio && node.parentNode;
 
- 					var w = container ? container.clientWidth : 0;
 
- 					listener(createEvent('resize', chart));
 
- 					if (container && container.clientWidth < w && chart.canvas) {
 
- 						// If the container size shrank during chart resize, let's assume
 
- 						// scrollbar appeared. So we resize again with the scrollbar visible -
 
- 						// effectively making chart smaller and the scrollbar hidden again.
 
- 						// Because we are inside `throttled`, and currently `ticking`, scroll
 
- 						// events are ignored during this whole 2 resize process.
 
- 						// If we assumed wrong and something else happened, we are resizing
 
- 						// twice in a frame (potential performance issue)
 
- 						listener(createEvent('resize', chart));
 
- 					}
 
- 				}
 
- 			}));
 
- 			// The resizer needs to be attached to the node parent, so we first need to be
 
- 			// sure that `node` is attached to the DOM before injecting the resizer element.
 
- 			watchForRender(node, function() {
 
- 				if (expando.resizer) {
 
- 					var container = node.parentNode;
 
- 					if (container && container !== resizer.parentNode) {
 
- 						container.insertBefore(resizer, container.firstChild);
 
- 					}
 
- 					// The container size might have changed, let's reset the resizer state.
 
- 					resizer._reset();
 
- 				}
 
- 			});
 
- 		}
 
- 		function removeResizeListener(node) {
 
- 			var expando = node[EXPANDO_KEY] || {};
 
- 			var resizer = expando.resizer;
 
- 			delete expando.resizer;
 
- 			unwatchForRender(node);
 
- 			if (resizer && resizer.parentNode) {
 
- 				resizer.parentNode.removeChild(resizer);
 
- 			}
 
- 		}
 
- 		/**
 
- 		 * Injects CSS styles inline if the styles are not already present.
 
- 		 * @param {HTMLDocument|ShadowRoot} rootNode - the node to contain the <style>.
 
- 		 * @param {string} css - the CSS to be injected.
 
- 		 */
 
- 		function injectCSS(rootNode, css) {
 
- 			// https://stackoverflow.com/q/3922139
 
- 			var expando = rootNode[EXPANDO_KEY] || (rootNode[EXPANDO_KEY] = {});
 
- 			if (!expando.containsStyles) {
 
- 				expando.containsStyles = true;
 
- 				css = '/* Chart.js */\n' + css;
 
- 				var style = document.createElement('style');
 
- 				style.setAttribute('type', 'text/css');
 
- 				style.appendChild(document.createTextNode(css));
 
- 				rootNode.appendChild(style);
 
- 			}
 
- 		}
 
- 		var platform_dom$2 = {
 
- 			/**
 
- 			 * When `true`, prevents the automatic injection of the stylesheet required to
 
- 			 * correctly detect when the chart is added to the DOM and then resized. This
 
- 			 * switch has been added to allow external stylesheet (`dist/Chart(.min)?.js`)
 
- 			 * to be manually imported to make this library compatible with any CSP.
 
- 			 * See https://github.com/chartjs/Chart.js/issues/5208
 
- 			 */
 
- 			disableCSSInjection: false,
 
- 			/**
 
- 			 * This property holds whether this platform is enabled for the current environment.
 
- 			 * Currently used by platform.js to select the proper implementation.
 
- 			 * @private
 
- 			 */
 
- 			_enabled: typeof window !== 'undefined' && typeof document !== 'undefined',
 
- 			/**
 
- 			 * Initializes resources that depend on platform options.
 
- 			 * @param {HTMLCanvasElement} canvas - The Canvas element.
 
- 			 * @private
 
- 			 */
 
- 			_ensureLoaded: function(canvas) {
 
- 				if (!this.disableCSSInjection) {
 
- 					// If the canvas is in a shadow DOM, then the styles must also be inserted
 
- 					// into the same shadow DOM.
 
- 					// https://github.com/chartjs/Chart.js/issues/5763
 
- 					var root = canvas.getRootNode ? canvas.getRootNode() : document;
 
- 					var targetNode = root.host ? root : document.head;
 
- 					injectCSS(targetNode, stylesheet);
 
- 				}
 
- 			},
 
- 			acquireContext: function(item, config) {
 
- 				if (typeof item === 'string') {
 
- 					item = document.getElementById(item);
 
- 				} else if (item.length) {
 
- 					// Support for array based queries (such as jQuery)
 
- 					item = item[0];
 
- 				}
 
- 				if (item && item.canvas) {
 
- 					// Support for any object associated to a canvas (including a context2d)
 
- 					item = item.canvas;
 
- 				}
 
- 				// To prevent canvas fingerprinting, some add-ons undefine the getContext
 
- 				// method, for example: https://github.com/kkapsner/CanvasBlocker
 
- 				// https://github.com/chartjs/Chart.js/issues/2807
 
- 				var context = item && item.getContext && item.getContext('2d');
 
- 				// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
 
- 				// inside an iframe or when running in a protected environment. We could guess the
 
- 				// types from their toString() value but let's keep things flexible and assume it's
 
- 				// a sufficient condition if the item has a context2D which has item as `canvas`.
 
- 				// https://github.com/chartjs/Chart.js/issues/3887
 
- 				// https://github.com/chartjs/Chart.js/issues/4102
 
- 				// https://github.com/chartjs/Chart.js/issues/4152
 
- 				if (context && context.canvas === item) {
 
- 					// Load platform resources on first chart creation, to make it possible to
 
- 					// import the library before setting platform options.
 
- 					this._ensureLoaded(item);
 
- 					initCanvas(item, config);
 
- 					return context;
 
- 				}
 
- 				return null;
 
- 			},
 
- 			releaseContext: function(context) {
 
- 				var canvas = context.canvas;
 
- 				if (!canvas[EXPANDO_KEY]) {
 
- 					return;
 
- 				}
 
- 				var initial = canvas[EXPANDO_KEY].initial;
 
- 				['height', 'width'].forEach(function(prop) {
 
- 					var value = initial[prop];
 
- 					if (helpers$1.isNullOrUndef(value)) {
 
- 						canvas.removeAttribute(prop);
 
- 					} else {
 
- 						canvas.setAttribute(prop, value);
 
- 					}
 
- 				});
 
- 				helpers$1.each(initial.style || {}, function(value, key) {
 
- 					canvas.style[key] = value;
 
- 				});
 
- 				// The canvas render size might have been changed (and thus the state stack discarded),
 
- 				// we can't use save() and restore() to restore the initial state. So make sure that at
 
- 				// least the canvas context is reset to the default state by setting the canvas width.
 
- 				// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
 
- 				// eslint-disable-next-line no-self-assign
 
- 				canvas.width = canvas.width;
 
- 				delete canvas[EXPANDO_KEY];
 
- 			},
 
- 			addEventListener: function(chart, type, listener) {
 
- 				var canvas = chart.canvas;
 
- 				if (type === 'resize') {
 
- 					// Note: the resize event is not supported on all browsers.
 
- 					addResizeListener(canvas, listener, chart);
 
- 					return;
 
- 				}
 
- 				var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});
 
- 				var proxies = expando.proxies || (expando.proxies = {});
 
- 				var proxy = proxies[chart.id + '_' + type] = function(event) {
 
- 					listener(fromNativeEvent(event, chart));
 
- 				};
 
- 				addListener(canvas, type, proxy);
 
- 			},
 
- 			removeEventListener: function(chart, type, listener) {
 
- 				var canvas = chart.canvas;
 
- 				if (type === 'resize') {
 
- 					// Note: the resize event is not supported on all browsers.
 
- 					removeResizeListener(canvas);
 
- 					return;
 
- 				}
 
- 				var expando = listener[EXPANDO_KEY] || {};
 
- 				var proxies = expando.proxies || {};
 
- 				var proxy = proxies[chart.id + '_' + type];
 
- 				if (!proxy) {
 
- 					return;
 
- 				}
 
- 				removeListener(canvas, type, proxy);
 
- 			}
 
- 		};
 
- 		// DEPRECATIONS
 
- 		/**
 
- 		 * Provided for backward compatibility, use EventTarget.addEventListener instead.
 
- 		 * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
 
- 		 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
 
- 		 * @function Chart.helpers.addEvent
 
- 		 * @deprecated since version 2.7.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers$1.addEvent = addListener;
 
- 		/**
 
- 		 * Provided for backward compatibility, use EventTarget.removeEventListener instead.
 
- 		 * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
 
- 		 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
 
- 		 * @function Chart.helpers.removeEvent
 
- 		 * @deprecated since version 2.7.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers$1.removeEvent = removeListener;
 
- 		// @TODO Make possible to select another platform at build time.
 
- 		var implementation = platform_dom$2._enabled ? platform_dom$2 : platform_basic;
 
- 		/**
 
- 		 * @namespace Chart.platform
 
- 		 * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
 
- 		 * @since 2.4.0
 
- 		 */
 
- 		var platform = helpers$1.extend({
 
- 			/**
 
- 			 * @since 2.7.0
 
- 			 */
 
- 			initialize: function() {},
 
- 			/**
 
- 			 * Called at chart construction time, returns a context2d instance implementing
 
- 			 * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
 
- 			 * @param {*} item - The native item from which to acquire context (platform specific)
 
- 			 * @param {object} options - The chart options
 
- 			 * @returns {CanvasRenderingContext2D} context2d instance
 
- 			 */
 
- 			acquireContext: function() {},
 
- 			/**
 
- 			 * Called at chart destruction time, releases any resources associated to the context
 
- 			 * previously returned by the acquireContext() method.
 
- 			 * @param {CanvasRenderingContext2D} context - The context2d instance
 
- 			 * @returns {boolean} true if the method succeeded, else false
 
- 			 */
 
- 			releaseContext: function() {},
 
- 			/**
 
- 			 * Registers the specified listener on the given chart.
 
- 			 * @param {Chart} chart - Chart from which to listen for event
 
- 			 * @param {string} type - The ({@link IEvent}) type to listen for
 
- 			 * @param {function} listener - Receives a notification (an object that implements
 
- 			 * the {@link IEvent} interface) when an event of the specified type occurs.
 
- 			 */
 
- 			addEventListener: function() {},
 
- 			/**
 
- 			 * Removes the specified listener previously registered with addEventListener.
 
- 			 * @param {Chart} chart - Chart from which to remove the listener
 
- 			 * @param {string} type - The ({@link IEvent}) type to remove
 
- 			 * @param {function} listener - The listener function to remove from the event target.
 
- 			 */
 
- 			removeEventListener: function() {}
 
- 		}, implementation);
 
- 		core_defaults._set('global', {
 
- 			plugins: {}
 
- 		});
 
- 		/**
 
- 		 * The plugin service singleton
 
- 		 * @namespace Chart.plugins
 
- 		 * @since 2.1.0
 
- 		 */
 
- 		var core_plugins = {
 
- 			/**
 
- 			 * Globally registered plugins.
 
- 			 * @private
 
- 			 */
 
- 			_plugins: [],
 
- 			/**
 
- 			 * This identifier is used to invalidate the descriptors cache attached to each chart
 
- 			 * when a global plugin is registered or unregistered. In this case, the cache ID is
 
- 			 * incremented and descriptors are regenerated during following API calls.
 
- 			 * @private
 
- 			 */
 
- 			_cacheId: 0,
 
- 			/**
 
- 			 * Registers the given plugin(s) if not already registered.
 
- 			 * @param {IPlugin[]|IPlugin} plugins plugin instance(s).
 
- 			 */
 
- 			register: function(plugins) {
 
- 				var p = this._plugins;
 
- 				([]).concat(plugins).forEach(function(plugin) {
 
- 					if (p.indexOf(plugin) === -1) {
 
- 						p.push(plugin);
 
- 					}
 
- 				});
 
- 				this._cacheId++;
 
- 			},
 
- 			/**
 
- 			 * Unregisters the given plugin(s) only if registered.
 
- 			 * @param {IPlugin[]|IPlugin} plugins plugin instance(s).
 
- 			 */
 
- 			unregister: function(plugins) {
 
- 				var p = this._plugins;
 
- 				([]).concat(plugins).forEach(function(plugin) {
 
- 					var idx = p.indexOf(plugin);
 
- 					if (idx !== -1) {
 
- 						p.splice(idx, 1);
 
- 					}
 
- 				});
 
- 				this._cacheId++;
 
- 			},
 
- 			/**
 
- 			 * Remove all registered plugins.
 
- 			 * @since 2.1.5
 
- 			 */
 
- 			clear: function() {
 
- 				this._plugins = [];
 
- 				this._cacheId++;
 
- 			},
 
- 			/**
 
- 			 * Returns the number of registered plugins?
 
- 			 * @returns {number}
 
- 			 * @since 2.1.5
 
- 			 */
 
- 			count: function() {
 
- 				return this._plugins.length;
 
- 			},
 
- 			/**
 
- 			 * Returns all registered plugin instances.
 
- 			 * @returns {IPlugin[]} array of plugin objects.
 
- 			 * @since 2.1.5
 
- 			 */
 
- 			getAll: function() {
 
- 				return this._plugins;
 
- 			},
 
- 			/**
 
- 			 * Calls enabled plugins for `chart` on the specified hook and with the given args.
 
- 			 * This method immediately returns as soon as a plugin explicitly returns false. The
 
- 			 * returned value can be used, for instance, to interrupt the current action.
 
- 			 * @param {Chart} chart - The chart instance for which plugins should be called.
 
- 			 * @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
 
- 			 * @param {Array} [args] - Extra arguments to apply to the hook call.
 
- 			 * @returns {boolean} false if any of the plugins return false, else returns true.
 
- 			 */
 
- 			notify: function(chart, hook, args) {
 
- 				var descriptors = this.descriptors(chart);
 
- 				var ilen = descriptors.length;
 
- 				var i, descriptor, plugin, params, method;
 
- 				for (i = 0; i < ilen; ++i) {
 
- 					descriptor = descriptors[i];
 
- 					plugin = descriptor.plugin;
 
- 					method = plugin[hook];
 
- 					if (typeof method === 'function') {
 
- 						params = [chart].concat(args || []);
 
- 						params.push(descriptor.options);
 
- 						if (method.apply(plugin, params) === false) {
 
- 							return false;
 
- 						}
 
- 					}
 
- 				}
 
- 				return true;
 
- 			},
 
- 			/**
 
- 			 * Returns descriptors of enabled plugins for the given chart.
 
- 			 * @returns {object[]} [{ plugin, options }]
 
- 			 * @private
 
- 			 */
 
- 			descriptors: function(chart) {
 
- 				var cache = chart.$plugins || (chart.$plugins = {});
 
- 				if (cache.id === this._cacheId) {
 
- 					return cache.descriptors;
 
- 				}
 
- 				var plugins = [];
 
- 				var descriptors = [];
 
- 				var config = (chart && chart.config) || {};
 
- 				var options = (config.options && config.options.plugins) || {};
 
- 				this._plugins.concat(config.plugins || []).forEach(function(plugin) {
 
- 					var idx = plugins.indexOf(plugin);
 
- 					if (idx !== -1) {
 
- 						return;
 
- 					}
 
- 					var id = plugin.id;
 
- 					var opts = options[id];
 
- 					if (opts === false) {
 
- 						return;
 
- 					}
 
- 					if (opts === true) {
 
- 						opts = helpers$1.clone(core_defaults.global.plugins[id]);
 
- 					}
 
- 					plugins.push(plugin);
 
- 					descriptors.push({
 
- 						plugin: plugin,
 
- 						options: opts || {}
 
- 					});
 
- 				});
 
- 				cache.descriptors = descriptors;
 
- 				cache.id = this._cacheId;
 
- 				return descriptors;
 
- 			},
 
- 			/**
 
- 			 * Invalidates cache for the given chart: descriptors hold a reference on plugin option,
 
- 			 * but in some cases, this reference can be changed by the user when updating options.
 
- 			 * https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
 
- 			 * @private
 
- 			 */
 
- 			_invalidate: function(chart) {
 
- 				delete chart.$plugins;
 
- 			}
 
- 		};
 
- 		var core_scaleService = {
 
- 			// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
 
- 			// use the new chart options to grab the correct scale
 
- 			constructors: {},
 
- 			// Use a registration function so that we can move to an ES6 map when we no longer need to support
 
- 			// old browsers
 
- 			// Scale config defaults
 
- 			defaults: {},
 
- 			registerScaleType: function(type, scaleConstructor, scaleDefaults) {
 
- 				this.constructors[type] = scaleConstructor;
 
- 				this.defaults[type] = helpers$1.clone(scaleDefaults);
 
- 			},
 
- 			getScaleConstructor: function(type) {
 
- 				return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
 
- 			},
 
- 			getScaleDefaults: function(type) {
 
- 				// Return the scale defaults merged with the global settings so that we always use the latest ones
 
- 				return this.defaults.hasOwnProperty(type) ? helpers$1.merge(Object.create(null), [core_defaults.scale, this.defaults[type]]) : {};
 
- 			},
 
- 			updateScaleDefaults: function(type, additions) {
 
- 				var me = this;
 
- 				if (me.defaults.hasOwnProperty(type)) {
 
- 					me.defaults[type] = helpers$1.extend(me.defaults[type], additions);
 
- 				}
 
- 			},
 
- 			addScalesToLayout: function(chart) {
 
- 				// Adds each scale to the chart.boxes array to be sized accordingly
 
- 				helpers$1.each(chart.scales, function(scale) {
 
- 					// Set ILayoutItem parameters for backwards compatibility
 
- 					scale.fullWidth = scale.options.fullWidth;
 
- 					scale.position = scale.options.position;
 
- 					scale.weight = scale.options.weight;
 
- 					core_layouts.addBox(chart, scale);
 
- 				});
 
- 			}
 
- 		};
 
- 		var valueOrDefault$8 = helpers$1.valueOrDefault;
 
- 		var getRtlHelper = helpers$1.rtl.getRtlAdapter;
 
- 		core_defaults._set('global', {
 
- 			tooltips: {
 
- 				enabled: true,
 
- 				custom: null,
 
- 				mode: 'nearest',
 
- 				position: 'average',
 
- 				intersect: true,
 
- 				backgroundColor: 'rgba(0,0,0,0.8)',
 
- 				titleFontStyle: 'bold',
 
- 				titleSpacing: 2,
 
- 				titleMarginBottom: 6,
 
- 				titleFontColor: '#fff',
 
- 				titleAlign: 'left',
 
- 				bodySpacing: 2,
 
- 				bodyFontColor: '#fff',
 
- 				bodyAlign: 'left',
 
- 				footerFontStyle: 'bold',
 
- 				footerSpacing: 2,
 
- 				footerMarginTop: 6,
 
- 				footerFontColor: '#fff',
 
- 				footerAlign: 'left',
 
- 				yPadding: 6,
 
- 				xPadding: 6,
 
- 				caretPadding: 2,
 
- 				caretSize: 5,
 
- 				cornerRadius: 6,
 
- 				multiKeyBackground: '#fff',
 
- 				displayColors: true,
 
- 				borderColor: 'rgba(0,0,0,0)',
 
- 				borderWidth: 0,
 
- 				callbacks: {
 
- 					// Args are: (tooltipItems, data)
 
- 					beforeTitle: helpers$1.noop,
 
- 					title: function(tooltipItems, data) {
 
- 						var title = '';
 
- 						var labels = data.labels;
 
- 						var labelCount = labels ? labels.length : 0;
 
- 						if (tooltipItems.length > 0) {
 
- 							var item = tooltipItems[0];
 
- 							if (item.label) {
 
- 								title = item.label;
 
- 							} else if (item.xLabel) {
 
- 								title = item.xLabel;
 
- 							} else if (labelCount > 0 && item.index < labelCount) {
 
- 								title = labels[item.index];
 
- 							}
 
- 						}
 
- 						return title;
 
- 					},
 
- 					afterTitle: helpers$1.noop,
 
- 					// Args are: (tooltipItems, data)
 
- 					beforeBody: helpers$1.noop,
 
- 					// Args are: (tooltipItem, data)
 
- 					beforeLabel: helpers$1.noop,
 
- 					label: function(tooltipItem, data) {
 
- 						var label = data.datasets[tooltipItem.datasetIndex].label || '';
 
- 						if (label) {
 
- 							label += ': ';
 
- 						}
 
- 						if (!helpers$1.isNullOrUndef(tooltipItem.value)) {
 
- 							label += tooltipItem.value;
 
- 						} else {
 
- 							label += tooltipItem.yLabel;
 
- 						}
 
- 						return label;
 
- 					},
 
- 					labelColor: function(tooltipItem, chart) {
 
- 						var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
 
- 						var activeElement = meta.data[tooltipItem.index];
 
- 						var view = activeElement._view;
 
- 						return {
 
- 							borderColor: view.borderColor,
 
- 							backgroundColor: view.backgroundColor
 
- 						};
 
- 					},
 
- 					labelTextColor: function() {
 
- 						return this._options.bodyFontColor;
 
- 					},
 
- 					afterLabel: helpers$1.noop,
 
- 					// Args are: (tooltipItems, data)
 
- 					afterBody: helpers$1.noop,
 
- 					// Args are: (tooltipItems, data)
 
- 					beforeFooter: helpers$1.noop,
 
- 					footer: helpers$1.noop,
 
- 					afterFooter: helpers$1.noop
 
- 				}
 
- 			}
 
- 		});
 
- 		var positioners = {
 
- 			/**
 
- 			 * Average mode places the tooltip at the average position of the elements shown
 
- 			 * @function Chart.Tooltip.positioners.average
 
- 			 * @param elements {ChartElement[]} the elements being displayed in the tooltip
 
- 			 * @returns {object} tooltip position
 
- 			 */
 
- 			average: function(elements) {
 
- 				if (!elements.length) {
 
- 					return false;
 
- 				}
 
- 				var i, len;
 
- 				var x = 0;
 
- 				var y = 0;
 
- 				var count = 0;
 
- 				for (i = 0, len = elements.length; i < len; ++i) {
 
- 					var el = elements[i];
 
- 					if (el && el.hasValue()) {
 
- 						var pos = el.tooltipPosition();
 
- 						x += pos.x;
 
- 						y += pos.y;
 
- 						++count;
 
- 					}
 
- 				}
 
- 				return {
 
- 					x: x / count,
 
- 					y: y / count
 
- 				};
 
- 			},
 
- 			/**
 
- 			 * Gets the tooltip position nearest of the item nearest to the event position
 
- 			 * @function Chart.Tooltip.positioners.nearest
 
- 			 * @param elements {Chart.Element[]} the tooltip elements
 
- 			 * @param eventPosition {object} the position of the event in canvas coordinates
 
- 			 * @returns {object} the tooltip position
 
- 			 */
 
- 			nearest: function(elements, eventPosition) {
 
- 				var x = eventPosition.x;
 
- 				var y = eventPosition.y;
 
- 				var minDistance = Number.POSITIVE_INFINITY;
 
- 				var i, len, nearestElement;
 
- 				for (i = 0, len = elements.length; i < len; ++i) {
 
- 					var el = elements[i];
 
- 					if (el && el.hasValue()) {
 
- 						var center = el.getCenterPoint();
 
- 						var d = helpers$1.distanceBetweenPoints(eventPosition, center);
 
- 						if (d < minDistance) {
 
- 							minDistance = d;
 
- 							nearestElement = el;
 
- 						}
 
- 					}
 
- 				}
 
- 				if (nearestElement) {
 
- 					var tp = nearestElement.tooltipPosition();
 
- 					x = tp.x;
 
- 					y = tp.y;
 
- 				}
 
- 				return {
 
- 					x: x,
 
- 					y: y
 
- 				};
 
- 			}
 
- 		};
 
- 		// Helper to push or concat based on if the 2nd parameter is an array or not
 
- 		function pushOrConcat(base, toPush) {
 
- 			if (toPush) {
 
- 				if (helpers$1.isArray(toPush)) {
 
- 					// base = base.concat(toPush);
 
- 					Array.prototype.push.apply(base, toPush);
 
- 				} else {
 
- 					base.push(toPush);
 
- 				}
 
- 			}
 
- 			return base;
 
- 		}
 
- 		/**
 
- 		 * Returns array of strings split by newline
 
- 		 * @param {string} value - The value to split by newline.
 
- 		 * @returns {string[]} value if newline present - Returned from String split() method
 
- 		 * @function
 
- 		 */
 
- 		function splitNewlines(str) {
 
- 			if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
 
- 				return str.split('\n');
 
- 			}
 
- 			return str;
 
- 		}
 
- 		/**
 
- 		 * Private helper to create a tooltip item model
 
- 		 * @param element - the chart element (point, arc, bar) to create the tooltip item for
 
- 		 * @return new tooltip item
 
- 		 */
 
- 		function createTooltipItem(element) {
 
- 			var xScale = element._xScale;
 
- 			var yScale = element._yScale || element._scale; // handle radar || polarArea charts
 
- 			var index = element._index;
 
- 			var datasetIndex = element._datasetIndex;
 
- 			var controller = element._chart.getDatasetMeta(datasetIndex).controller;
 
- 			var indexScale = controller._getIndexScale();
 
- 			var valueScale = controller._getValueScale();
 
- 			return {
 
- 				xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
 
- 				yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
 
- 				label: indexScale ? '' + indexScale.getLabelForIndex(index, datasetIndex) : '',
 
- 				value: valueScale ? '' + valueScale.getLabelForIndex(index, datasetIndex) : '',
 
- 				index: index,
 
- 				datasetIndex: datasetIndex,
 
- 				x: element._model.x,
 
- 				y: element._model.y
 
- 			};
 
- 		}
 
- 		/**
 
- 		 * Helper to get the reset model for the tooltip
 
- 		 * @param tooltipOpts {object} the tooltip options
 
- 		 */
 
- 		function getBaseModel(tooltipOpts) {
 
- 			var globalDefaults = core_defaults.global;
 
- 			return {
 
- 				// Positioning
 
- 				xPadding: tooltipOpts.xPadding,
 
- 				yPadding: tooltipOpts.yPadding,
 
- 				xAlign: tooltipOpts.xAlign,
 
- 				yAlign: tooltipOpts.yAlign,
 
- 				// Drawing direction and text direction
 
- 				rtl: tooltipOpts.rtl,
 
- 				textDirection: tooltipOpts.textDirection,
 
- 				// Body
 
- 				bodyFontColor: tooltipOpts.bodyFontColor,
 
- 				_bodyFontFamily: valueOrDefault$8(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
 
- 				_bodyFontStyle: valueOrDefault$8(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
 
- 				_bodyAlign: tooltipOpts.bodyAlign,
 
- 				bodyFontSize: valueOrDefault$8(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
 
- 				bodySpacing: tooltipOpts.bodySpacing,
 
- 				// Title
 
- 				titleFontColor: tooltipOpts.titleFontColor,
 
- 				_titleFontFamily: valueOrDefault$8(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
 
- 				_titleFontStyle: valueOrDefault$8(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
 
- 				titleFontSize: valueOrDefault$8(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
 
- 				_titleAlign: tooltipOpts.titleAlign,
 
- 				titleSpacing: tooltipOpts.titleSpacing,
 
- 				titleMarginBottom: tooltipOpts.titleMarginBottom,
 
- 				// Footer
 
- 				footerFontColor: tooltipOpts.footerFontColor,
 
- 				_footerFontFamily: valueOrDefault$8(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
 
- 				_footerFontStyle: valueOrDefault$8(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
 
- 				footerFontSize: valueOrDefault$8(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
 
- 				_footerAlign: tooltipOpts.footerAlign,
 
- 				footerSpacing: tooltipOpts.footerSpacing,
 
- 				footerMarginTop: tooltipOpts.footerMarginTop,
 
- 				// Appearance
 
- 				caretSize: tooltipOpts.caretSize,
 
- 				cornerRadius: tooltipOpts.cornerRadius,
 
- 				backgroundColor: tooltipOpts.backgroundColor,
 
- 				opacity: 0,
 
- 				legendColorBackground: tooltipOpts.multiKeyBackground,
 
- 				displayColors: tooltipOpts.displayColors,
 
- 				borderColor: tooltipOpts.borderColor,
 
- 				borderWidth: tooltipOpts.borderWidth
 
- 			};
 
- 		}
 
- 		/**
 
- 		 * Get the size of the tooltip
 
- 		 */
 
- 		function getTooltipSize(tooltip, model) {
 
- 			var ctx = tooltip._chart.ctx;
 
- 			var height = model.yPadding * 2; // Tooltip Padding
 
- 			var width = 0;
 
- 			// Count of all lines in the body
 
- 			var body = model.body;
 
- 			var combinedBodyLength = body.reduce(function(count, bodyItem) {
 
- 				return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
 
- 			}, 0);
 
- 			combinedBodyLength += model.beforeBody.length + model.afterBody.length;
 
- 			var titleLineCount = model.title.length;
 
- 			var footerLineCount = model.footer.length;
 
- 			var titleFontSize = model.titleFontSize;
 
- 			var bodyFontSize = model.bodyFontSize;
 
- 			var footerFontSize = model.footerFontSize;
 
- 			height += titleLineCount * titleFontSize; // Title Lines
 
- 			height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
 
- 			height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
 
- 			height += combinedBodyLength * bodyFontSize; // Body Lines
 
- 			height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
 
- 			height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
 
- 			height += footerLineCount * (footerFontSize); // Footer Lines
 
- 			height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
 
- 			// Title width
 
- 			var widthPadding = 0;
 
- 			var maxLineWidth = function(line) {
 
- 				width = Math.max(width, ctx.measureText(line).width + widthPadding);
 
- 			};
 
- 			ctx.font = helpers$1.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
 
- 			helpers$1.each(model.title, maxLineWidth);
 
- 			// Body width
 
- 			ctx.font = helpers$1.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
 
- 			helpers$1.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
 
- 			// Body lines may include some extra width due to the color box
 
- 			widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
 
- 			helpers$1.each(body, function(bodyItem) {
 
- 				helpers$1.each(bodyItem.before, maxLineWidth);
 
- 				helpers$1.each(bodyItem.lines, maxLineWidth);
 
- 				helpers$1.each(bodyItem.after, maxLineWidth);
 
- 			});
 
- 			// Reset back to 0
 
- 			widthPadding = 0;
 
- 			// Footer width
 
- 			ctx.font = helpers$1.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
 
- 			helpers$1.each(model.footer, maxLineWidth);
 
- 			// Add padding
 
- 			width += 2 * model.xPadding;
 
- 			return {
 
- 				width: width,
 
- 				height: height
 
- 			};
 
- 		}
 
- 		/**
 
- 		 * Helper to get the alignment of a tooltip given the size
 
- 		 */
 
- 		function determineAlignment(tooltip, size) {
 
- 			var model = tooltip._model;
 
- 			var chart = tooltip._chart;
 
- 			var chartArea = tooltip._chart.chartArea;
 
- 			var xAlign = 'center';
 
- 			var yAlign = 'center';
 
- 			if (model.y < size.height) {
 
- 				yAlign = 'top';
 
- 			} else if (model.y > (chart.height - size.height)) {
 
- 				yAlign = 'bottom';
 
- 			}
 
- 			var lf, rf; // functions to determine left, right alignment
 
- 			var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
 
- 			var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
 
- 			var midX = (chartArea.left + chartArea.right) / 2;
 
- 			var midY = (chartArea.top + chartArea.bottom) / 2;
 
- 			if (yAlign === 'center') {
 
- 				lf = function(x) {
 
- 					return x <= midX;
 
- 				};
 
- 				rf = function(x) {
 
- 					return x > midX;
 
- 				};
 
- 			} else {
 
- 				lf = function(x) {
 
- 					return x <= (size.width / 2);
 
- 				};
 
- 				rf = function(x) {
 
- 					return x >= (chart.width - (size.width / 2));
 
- 				};
 
- 			}
 
- 			olf = function(x) {
 
- 				return x + size.width + model.caretSize + model.caretPadding > chart.width;
 
- 			};
 
- 			orf = function(x) {
 
- 				return x - size.width - model.caretSize - model.caretPadding < 0;
 
- 			};
 
- 			yf = function(y) {
 
- 				return y <= midY ? 'top' : 'bottom';
 
- 			};
 
- 			if (lf(model.x)) {
 
- 				xAlign = 'left';
 
- 				// Is tooltip too wide and goes over the right side of the chart.?
 
- 				if (olf(model.x)) {
 
- 					xAlign = 'center';
 
- 					yAlign = yf(model.y);
 
- 				}
 
- 			} else if (rf(model.x)) {
 
- 				xAlign = 'right';
 
- 				// Is tooltip too wide and goes outside left edge of canvas?
 
- 				if (orf(model.x)) {
 
- 					xAlign = 'center';
 
- 					yAlign = yf(model.y);
 
- 				}
 
- 			}
 
- 			var opts = tooltip._options;
 
- 			return {
 
- 				xAlign: opts.xAlign ? opts.xAlign : xAlign,
 
- 				yAlign: opts.yAlign ? opts.yAlign : yAlign
 
- 			};
 
- 		}
 
- 		/**
 
- 		 * Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
 
- 		 */
 
- 		function getBackgroundPoint(vm, size, alignment, chart) {
 
- 			// Background Position
 
- 			var x = vm.x;
 
- 			var y = vm.y;
 
- 			var caretSize = vm.caretSize;
 
- 			var caretPadding = vm.caretPadding;
 
- 			var cornerRadius = vm.cornerRadius;
 
- 			var xAlign = alignment.xAlign;
 
- 			var yAlign = alignment.yAlign;
 
- 			var paddingAndSize = caretSize + caretPadding;
 
- 			var radiusAndPadding = cornerRadius + caretPadding;
 
- 			if (xAlign === 'right') {
 
- 				x -= size.width;
 
- 			} else if (xAlign === 'center') {
 
- 				x -= (size.width / 2);
 
- 				if (x + size.width > chart.width) {
 
- 					x = chart.width - size.width;
 
- 				}
 
- 				if (x < 0) {
 
- 					x = 0;
 
- 				}
 
- 			}
 
- 			if (yAlign === 'top') {
 
- 				y += paddingAndSize;
 
- 			} else if (yAlign === 'bottom') {
 
- 				y -= size.height + paddingAndSize;
 
- 			} else {
 
- 				y -= (size.height / 2);
 
- 			}
 
- 			if (yAlign === 'center') {
 
- 				if (xAlign === 'left') {
 
- 					x += paddingAndSize;
 
- 				} else if (xAlign === 'right') {
 
- 					x -= paddingAndSize;
 
- 				}
 
- 			} else if (xAlign === 'left') {
 
- 				x -= radiusAndPadding;
 
- 			} else if (xAlign === 'right') {
 
- 				x += radiusAndPadding;
 
- 			}
 
- 			return {
 
- 				x: x,
 
- 				y: y
 
- 			};
 
- 		}
 
- 		function getAlignedX(vm, align) {
 
- 			return align === 'center'
 
- 				? vm.x + vm.width / 2
 
- 				: align === 'right'
 
- 					? vm.x + vm.width - vm.xPadding
 
- 					: vm.x + vm.xPadding;
 
- 		}
 
- 		/**
 
- 		 * Helper to build before and after body lines
 
- 		 */
 
- 		function getBeforeAfterBodyLines(callback) {
 
- 			return pushOrConcat([], splitNewlines(callback));
 
- 		}
 
- 		var exports$4 = core_element.extend({
 
- 			initialize: function() {
 
- 				this._model = getBaseModel(this._options);
 
- 				this._lastActive = [];
 
- 			},
 
- 			// Get the title
 
- 			// Args are: (tooltipItem, data)
 
- 			getTitle: function() {
 
- 				var me = this;
 
- 				var opts = me._options;
 
- 				var callbacks = opts.callbacks;
 
- 				var beforeTitle = callbacks.beforeTitle.apply(me, arguments);
 
- 				var title = callbacks.title.apply(me, arguments);
 
- 				var afterTitle = callbacks.afterTitle.apply(me, arguments);
 
- 				var lines = [];
 
- 				lines = pushOrConcat(lines, splitNewlines(beforeTitle));
 
- 				lines = pushOrConcat(lines, splitNewlines(title));
 
- 				lines = pushOrConcat(lines, splitNewlines(afterTitle));
 
- 				return lines;
 
- 			},
 
- 			// Args are: (tooltipItem, data)
 
- 			getBeforeBody: function() {
 
- 				return getBeforeAfterBodyLines(this._options.callbacks.beforeBody.apply(this, arguments));
 
- 			},
 
- 			// Args are: (tooltipItem, data)
 
- 			getBody: function(tooltipItems, data) {
 
- 				var me = this;
 
- 				var callbacks = me._options.callbacks;
 
- 				var bodyItems = [];
 
- 				helpers$1.each(tooltipItems, function(tooltipItem) {
 
- 					var bodyItem = {
 
- 						before: [],
 
- 						lines: [],
 
- 						after: []
 
- 					};
 
- 					pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, tooltipItem, data)));
 
- 					pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
 
- 					pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, tooltipItem, data)));
 
- 					bodyItems.push(bodyItem);
 
- 				});
 
- 				return bodyItems;
 
- 			},
 
- 			// Args are: (tooltipItem, data)
 
- 			getAfterBody: function() {
 
- 				return getBeforeAfterBodyLines(this._options.callbacks.afterBody.apply(this, arguments));
 
- 			},
 
- 			// Get the footer and beforeFooter and afterFooter lines
 
- 			// Args are: (tooltipItem, data)
 
- 			getFooter: function() {
 
- 				var me = this;
 
- 				var callbacks = me._options.callbacks;
 
- 				var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
 
- 				var footer = callbacks.footer.apply(me, arguments);
 
- 				var afterFooter = callbacks.afterFooter.apply(me, arguments);
 
- 				var lines = [];
 
- 				lines = pushOrConcat(lines, splitNewlines(beforeFooter));
 
- 				lines = pushOrConcat(lines, splitNewlines(footer));
 
- 				lines = pushOrConcat(lines, splitNewlines(afterFooter));
 
- 				return lines;
 
- 			},
 
- 			update: function(changed) {
 
- 				var me = this;
 
- 				var opts = me._options;
 
- 				// Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
 
- 				// that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
 
- 				// which breaks any animations.
 
- 				var existingModel = me._model;
 
- 				var model = me._model = getBaseModel(opts);
 
- 				var active = me._active;
 
- 				var data = me._data;
 
- 				// In the case where active.length === 0 we need to keep these at existing values for good animations
 
- 				var alignment = {
 
- 					xAlign: existingModel.xAlign,
 
- 					yAlign: existingModel.yAlign
 
- 				};
 
- 				var backgroundPoint = {
 
- 					x: existingModel.x,
 
- 					y: existingModel.y
 
- 				};
 
- 				var tooltipSize = {
 
- 					width: existingModel.width,
 
- 					height: existingModel.height
 
- 				};
 
- 				var tooltipPosition = {
 
- 					x: existingModel.caretX,
 
- 					y: existingModel.caretY
 
- 				};
 
- 				var i, len;
 
- 				if (active.length) {
 
- 					model.opacity = 1;
 
- 					var labelColors = [];
 
- 					var labelTextColors = [];
 
- 					tooltipPosition = positioners[opts.position].call(me, active, me._eventPosition);
 
- 					var tooltipItems = [];
 
- 					for (i = 0, len = active.length; i < len; ++i) {
 
- 						tooltipItems.push(createTooltipItem(active[i]));
 
- 					}
 
- 					// If the user provided a filter function, use it to modify the tooltip items
 
- 					if (opts.filter) {
 
- 						tooltipItems = tooltipItems.filter(function(a) {
 
- 							return opts.filter(a, data);
 
- 						});
 
- 					}
 
- 					// If the user provided a sorting function, use it to modify the tooltip items
 
- 					if (opts.itemSort) {
 
- 						tooltipItems = tooltipItems.sort(function(a, b) {
 
- 							return opts.itemSort(a, b, data);
 
- 						});
 
- 					}
 
- 					// Determine colors for boxes
 
- 					helpers$1.each(tooltipItems, function(tooltipItem) {
 
- 						labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
 
- 						labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));
 
- 					});
 
- 					// Build the Text Lines
 
- 					model.title = me.getTitle(tooltipItems, data);
 
- 					model.beforeBody = me.getBeforeBody(tooltipItems, data);
 
- 					model.body = me.getBody(tooltipItems, data);
 
- 					model.afterBody = me.getAfterBody(tooltipItems, data);
 
- 					model.footer = me.getFooter(tooltipItems, data);
 
- 					// Initial positioning and colors
 
- 					model.x = tooltipPosition.x;
 
- 					model.y = tooltipPosition.y;
 
- 					model.caretPadding = opts.caretPadding;
 
- 					model.labelColors = labelColors;
 
- 					model.labelTextColors = labelTextColors;
 
- 					// data points
 
- 					model.dataPoints = tooltipItems;
 
- 					// We need to determine alignment of the tooltip
 
- 					tooltipSize = getTooltipSize(this, model);
 
- 					alignment = determineAlignment(this, tooltipSize);
 
- 					// Final Size and Position
 
- 					backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);
 
- 				} else {
 
- 					model.opacity = 0;
 
- 				}
 
- 				model.xAlign = alignment.xAlign;
 
- 				model.yAlign = alignment.yAlign;
 
- 				model.x = backgroundPoint.x;
 
- 				model.y = backgroundPoint.y;
 
- 				model.width = tooltipSize.width;
 
- 				model.height = tooltipSize.height;
 
- 				// Point where the caret on the tooltip points to
 
- 				model.caretX = tooltipPosition.x;
 
- 				model.caretY = tooltipPosition.y;
 
- 				me._model = model;
 
- 				if (changed && opts.custom) {
 
- 					opts.custom.call(me, model);
 
- 				}
 
- 				return me;
 
- 			},
 
- 			drawCaret: function(tooltipPoint, size) {
 
- 				var ctx = this._chart.ctx;
 
- 				var vm = this._view;
 
- 				var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
 
- 				ctx.lineTo(caretPosition.x1, caretPosition.y1);
 
- 				ctx.lineTo(caretPosition.x2, caretPosition.y2);
 
- 				ctx.lineTo(caretPosition.x3, caretPosition.y3);
 
- 			},
 
- 			getCaretPosition: function(tooltipPoint, size, vm) {
 
- 				var x1, x2, x3, y1, y2, y3;
 
- 				var caretSize = vm.caretSize;
 
- 				var cornerRadius = vm.cornerRadius;
 
- 				var xAlign = vm.xAlign;
 
- 				var yAlign = vm.yAlign;
 
- 				var ptX = tooltipPoint.x;
 
- 				var ptY = tooltipPoint.y;
 
- 				var width = size.width;
 
- 				var height = size.height;
 
- 				if (yAlign === 'center') {
 
- 					y2 = ptY + (height / 2);
 
- 					if (xAlign === 'left') {
 
- 						x1 = ptX;
 
- 						x2 = x1 - caretSize;
 
- 						x3 = x1;
 
- 						y1 = y2 + caretSize;
 
- 						y3 = y2 - caretSize;
 
- 					} else {
 
- 						x1 = ptX + width;
 
- 						x2 = x1 + caretSize;
 
- 						x3 = x1;
 
- 						y1 = y2 - caretSize;
 
- 						y3 = y2 + caretSize;
 
- 					}
 
- 				} else {
 
- 					if (xAlign === 'left') {
 
- 						x2 = ptX + cornerRadius + (caretSize);
 
- 						x1 = x2 - caretSize;
 
- 						x3 = x2 + caretSize;
 
- 					} else if (xAlign === 'right') {
 
- 						x2 = ptX + width - cornerRadius - caretSize;
 
- 						x1 = x2 - caretSize;
 
- 						x3 = x2 + caretSize;
 
- 					} else {
 
- 						x2 = vm.caretX;
 
- 						x1 = x2 - caretSize;
 
- 						x3 = x2 + caretSize;
 
- 					}
 
- 					if (yAlign === 'top') {
 
- 						y1 = ptY;
 
- 						y2 = y1 - caretSize;
 
- 						y3 = y1;
 
- 					} else {
 
- 						y1 = ptY + height;
 
- 						y2 = y1 + caretSize;
 
- 						y3 = y1;
 
- 						// invert drawing order
 
- 						var tmp = x3;
 
- 						x3 = x1;
 
- 						x1 = tmp;
 
- 					}
 
- 				}
 
- 				return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
 
- 			},
 
- 			drawTitle: function(pt, vm, ctx) {
 
- 				var title = vm.title;
 
- 				var length = title.length;
 
- 				var titleFontSize, titleSpacing, i;
 
- 				if (length) {
 
- 					var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
 
- 					pt.x = getAlignedX(vm, vm._titleAlign);
 
- 					ctx.textAlign = rtlHelper.textAlign(vm._titleAlign);
 
- 					ctx.textBaseline = 'middle';
 
- 					titleFontSize = vm.titleFontSize;
 
- 					titleSpacing = vm.titleSpacing;
 
- 					ctx.fillStyle = vm.titleFontColor;
 
- 					ctx.font = helpers$1.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
 
- 					for (i = 0; i < length; ++i) {
 
- 						ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFontSize / 2);
 
- 						pt.y += titleFontSize + titleSpacing; // Line Height and spacing
 
- 						if (i + 1 === length) {
 
- 							pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
 
- 						}
 
- 					}
 
- 				}
 
- 			},
 
- 			drawBody: function(pt, vm, ctx) {
 
- 				var bodyFontSize = vm.bodyFontSize;
 
- 				var bodySpacing = vm.bodySpacing;
 
- 				var bodyAlign = vm._bodyAlign;
 
- 				var body = vm.body;
 
- 				var drawColorBoxes = vm.displayColors;
 
- 				var xLinePadding = 0;
 
- 				var colorX = drawColorBoxes ? getAlignedX(vm, 'left') : 0;
 
- 				var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
 
- 				var fillLineOfText = function(line) {
 
- 					ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyFontSize / 2);
 
- 					pt.y += bodyFontSize + bodySpacing;
 
- 				};
 
- 				var bodyItem, textColor, labelColors, lines, i, j, ilen, jlen;
 
- 				var bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
 
- 				ctx.textAlign = bodyAlign;
 
- 				ctx.textBaseline = 'middle';
 
- 				ctx.font = helpers$1.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
 
- 				pt.x = getAlignedX(vm, bodyAlignForCalculation);
 
- 				// Before body lines
 
- 				ctx.fillStyle = vm.bodyFontColor;
 
- 				helpers$1.each(vm.beforeBody, fillLineOfText);
 
- 				xLinePadding = drawColorBoxes && bodyAlignForCalculation !== 'right'
 
- 					? bodyAlign === 'center' ? (bodyFontSize / 2 + 1) : (bodyFontSize + 2)
 
- 					: 0;
 
- 				// Draw body lines now
 
- 				for (i = 0, ilen = body.length; i < ilen; ++i) {
 
- 					bodyItem = body[i];
 
- 					textColor = vm.labelTextColors[i];
 
- 					labelColors = vm.labelColors[i];
 
- 					ctx.fillStyle = textColor;
 
- 					helpers$1.each(bodyItem.before, fillLineOfText);
 
- 					lines = bodyItem.lines;
 
- 					for (j = 0, jlen = lines.length; j < jlen; ++j) {
 
- 						// Draw Legend-like boxes if needed
 
- 						if (drawColorBoxes) {
 
- 							var rtlColorX = rtlHelper.x(colorX);
 
- 							// Fill a white rect so that colours merge nicely if the opacity is < 1
 
- 							ctx.fillStyle = vm.legendColorBackground;
 
- 							ctx.fillRect(rtlHelper.leftForLtr(rtlColorX, bodyFontSize), pt.y, bodyFontSize, bodyFontSize);
 
- 							// Border
 
- 							ctx.lineWidth = 1;
 
- 							ctx.strokeStyle = labelColors.borderColor;
 
- 							ctx.strokeRect(rtlHelper.leftForLtr(rtlColorX, bodyFontSize), pt.y, bodyFontSize, bodyFontSize);
 
- 							// Inner square
 
- 							ctx.fillStyle = labelColors.backgroundColor;
 
- 							ctx.fillRect(rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), bodyFontSize - 2), pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
 
- 							ctx.fillStyle = textColor;
 
- 						}
 
- 						fillLineOfText(lines[j]);
 
- 					}
 
- 					helpers$1.each(bodyItem.after, fillLineOfText);
 
- 				}
 
- 				// Reset back to 0 for after body
 
- 				xLinePadding = 0;
 
- 				// After body lines
 
- 				helpers$1.each(vm.afterBody, fillLineOfText);
 
- 				pt.y -= bodySpacing; // Remove last body spacing
 
- 			},
 
- 			drawFooter: function(pt, vm, ctx) {
 
- 				var footer = vm.footer;
 
- 				var length = footer.length;
 
- 				var footerFontSize, i;
 
- 				if (length) {
 
- 					var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);
 
- 					pt.x = getAlignedX(vm, vm._footerAlign);
 
- 					pt.y += vm.footerMarginTop;
 
- 					ctx.textAlign = rtlHelper.textAlign(vm._footerAlign);
 
- 					ctx.textBaseline = 'middle';
 
- 					footerFontSize = vm.footerFontSize;
 
- 					ctx.fillStyle = vm.footerFontColor;
 
- 					ctx.font = helpers$1.fontString(footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
 
- 					for (i = 0; i < length; ++i) {
 
- 						ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFontSize / 2);
 
- 						pt.y += footerFontSize + vm.footerSpacing;
 
- 					}
 
- 				}
 
- 			},
 
- 			drawBackground: function(pt, vm, ctx, tooltipSize) {
 
- 				ctx.fillStyle = vm.backgroundColor;
 
- 				ctx.strokeStyle = vm.borderColor;
 
- 				ctx.lineWidth = vm.borderWidth;
 
- 				var xAlign = vm.xAlign;
 
- 				var yAlign = vm.yAlign;
 
- 				var x = pt.x;
 
- 				var y = pt.y;
 
- 				var width = tooltipSize.width;
 
- 				var height = tooltipSize.height;
 
- 				var radius = vm.cornerRadius;
 
- 				ctx.beginPath();
 
- 				ctx.moveTo(x + radius, y);
 
- 				if (yAlign === 'top') {
 
- 					this.drawCaret(pt, tooltipSize);
 
- 				}
 
- 				ctx.lineTo(x + width - radius, y);
 
- 				ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
 
- 				if (yAlign === 'center' && xAlign === 'right') {
 
- 					this.drawCaret(pt, tooltipSize);
 
- 				}
 
- 				ctx.lineTo(x + width, y + height - radius);
 
- 				ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
 
- 				if (yAlign === 'bottom') {
 
- 					this.drawCaret(pt, tooltipSize);
 
- 				}
 
- 				ctx.lineTo(x + radius, y + height);
 
- 				ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
 
- 				if (yAlign === 'center' && xAlign === 'left') {
 
- 					this.drawCaret(pt, tooltipSize);
 
- 				}
 
- 				ctx.lineTo(x, y + radius);
 
- 				ctx.quadraticCurveTo(x, y, x + radius, y);
 
- 				ctx.closePath();
 
- 				ctx.fill();
 
- 				if (vm.borderWidth > 0) {
 
- 					ctx.stroke();
 
- 				}
 
- 			},
 
- 			draw: function() {
 
- 				var ctx = this._chart.ctx;
 
- 				var vm = this._view;
 
- 				if (vm.opacity === 0) {
 
- 					return;
 
- 				}
 
- 				var tooltipSize = {
 
- 					width: vm.width,
 
- 					height: vm.height
 
- 				};
 
- 				var pt = {
 
- 					x: vm.x,
 
- 					y: vm.y
 
- 				};
 
- 				// IE11/Edge does not like very small opacities, so snap to 0
 
- 				var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
 
- 				// Truthy/falsey value for empty tooltip
 
- 				var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
 
- 				if (this._options.enabled && hasTooltipContent) {
 
- 					ctx.save();
 
- 					ctx.globalAlpha = opacity;
 
- 					// Draw Background
 
- 					this.drawBackground(pt, vm, ctx, tooltipSize);
 
- 					// Draw Title, Body, and Footer
 
- 					pt.y += vm.yPadding;
 
- 					helpers$1.rtl.overrideTextDirection(ctx, vm.textDirection);
 
- 					// Titles
 
- 					this.drawTitle(pt, vm, ctx);
 
- 					// Body
 
- 					this.drawBody(pt, vm, ctx);
 
- 					// Footer
 
- 					this.drawFooter(pt, vm, ctx);
 
- 					helpers$1.rtl.restoreTextDirection(ctx, vm.textDirection);
 
- 					ctx.restore();
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Handle an event
 
- 			 * @private
 
- 			 * @param {IEvent} event - The event to handle
 
- 			 * @returns {boolean} true if the tooltip changed
 
- 			 */
 
- 			handleEvent: function(e) {
 
- 				var me = this;
 
- 				var options = me._options;
 
- 				var changed = false;
 
- 				me._lastActive = me._lastActive || [];
 
- 				// Find Active Elements for tooltips
 
- 				if (e.type === 'mouseout') {
 
- 					me._active = [];
 
- 				} else {
 
- 					me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
 
- 					if (options.reverse) {
 
- 						me._active.reverse();
 
- 					}
 
- 				}
 
- 				// Remember Last Actives
 
- 				changed = !helpers$1.arrayEquals(me._active, me._lastActive);
 
- 				// Only handle target event on tooltip change
 
- 				if (changed) {
 
- 					me._lastActive = me._active;
 
- 					if (options.enabled || options.custom) {
 
- 						me._eventPosition = {
 
- 							x: e.x,
 
- 							y: e.y
 
- 						};
 
- 						me.update(true);
 
- 						me.pivot();
 
- 					}
 
- 				}
 
- 				return changed;
 
- 			}
 
- 		});
 
- 		/**
 
- 		 * @namespace Chart.Tooltip.positioners
 
- 		 */
 
- 		var positioners_1 = positioners;
 
- 		var core_tooltip = exports$4;
 
- 		core_tooltip.positioners = positioners_1;
 
- 		var valueOrDefault$9 = helpers$1.valueOrDefault;
 
- 		core_defaults._set('global', {
 
- 			elements: {},
 
- 			events: [
 
- 				'mousemove',
 
- 				'mouseout',
 
- 				'click',
 
- 				'touchstart',
 
- 				'touchmove'
 
- 			],
 
- 			hover: {
 
- 				onHover: null,
 
- 				mode: 'nearest',
 
- 				intersect: true,
 
- 				animationDuration: 400
 
- 			},
 
- 			onClick: null,
 
- 			maintainAspectRatio: true,
 
- 			responsive: true,
 
- 			responsiveAnimationDuration: 0
 
- 		});
 
- 		/**
 
- 		 * Recursively merge the given config objects representing the `scales` option
 
- 		 * by incorporating scale defaults in `xAxes` and `yAxes` array items, then
 
- 		 * returns a deep copy of the result, thus doesn't alter inputs.
 
- 		 */
 
- 		function mergeScaleConfig(/* config objects ... */) {
 
- 			return helpers$1.merge(Object.create(null), [].slice.call(arguments), {
 
- 				merger: function(key, target, source, options) {
 
- 					if (key === 'xAxes' || key === 'yAxes') {
 
- 						var slen = source[key].length;
 
- 						var i, type, scale;
 
- 						if (!target[key]) {
 
- 							target[key] = [];
 
- 						}
 
- 						for (i = 0; i < slen; ++i) {
 
- 							scale = source[key][i];
 
- 							type = valueOrDefault$9(scale.type, key === 'xAxes' ? 'category' : 'linear');
 
- 							if (i >= target[key].length) {
 
- 								target[key].push({});
 
- 							}
 
- 							if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {
 
- 								// new/untyped scale or type changed: let's apply the new defaults
 
- 								// then merge source scale to correctly overwrite the defaults.
 
- 								helpers$1.merge(target[key][i], [core_scaleService.getScaleDefaults(type), scale]);
 
- 							} else {
 
- 								// scales type are the same
 
- 								helpers$1.merge(target[key][i], scale);
 
- 							}
 
- 						}
 
- 					} else {
 
- 						helpers$1._merger(key, target, source, options);
 
- 					}
 
- 				}
 
- 			});
 
- 		}
 
- 		/**
 
- 		 * Recursively merge the given config objects as the root options by handling
 
- 		 * default scale options for the `scales` and `scale` properties, then returns
 
- 		 * a deep copy of the result, thus doesn't alter inputs.
 
- 		 */
 
- 		function mergeConfig(/* config objects ... */) {
 
- 			return helpers$1.merge(Object.create(null), [].slice.call(arguments), {
 
- 				merger: function(key, target, source, options) {
 
- 					var tval = target[key] || Object.create(null);
 
- 					var sval = source[key];
 
- 					if (key === 'scales') {
 
- 						// scale config merging is complex. Add our own function here for that
 
- 						target[key] = mergeScaleConfig(tval, sval);
 
- 					} else if (key === 'scale') {
 
- 						// used in polar area & radar charts since there is only one scale
 
- 						target[key] = helpers$1.merge(tval, [core_scaleService.getScaleDefaults(sval.type), sval]);
 
- 					} else {
 
- 						helpers$1._merger(key, target, source, options);
 
- 					}
 
- 				}
 
- 			});
 
- 		}
 
- 		function initConfig(config) {
 
- 			config = config || Object.create(null);
 
- 			// Do NOT use mergeConfig for the data object because this method merges arrays
 
- 			// and so would change references to labels and datasets, preventing data updates.
 
- 			var data = config.data = config.data || {};
 
- 			data.datasets = data.datasets || [];
 
- 			data.labels = data.labels || [];
 
- 			config.options = mergeConfig(
 
- 				core_defaults.global,
 
- 				core_defaults[config.type],
 
- 				config.options || {});
 
- 			return config;
 
- 		}
 
- 		function updateConfig(chart) {
 
- 			var newOptions = chart.options;
 
- 			helpers$1.each(chart.scales, function(scale) {
 
- 				core_layouts.removeBox(chart, scale);
 
- 			});
 
- 			newOptions = mergeConfig(
 
- 				core_defaults.global,
 
- 				core_defaults[chart.config.type],
 
- 				newOptions);
 
- 			chart.options = chart.config.options = newOptions;
 
- 			chart.ensureScalesHaveIDs();
 
- 			chart.buildOrUpdateScales();
 
- 			// Tooltip
 
- 			chart.tooltip._options = newOptions.tooltips;
 
- 			chart.tooltip.initialize();
 
- 		}
 
- 		function nextAvailableScaleId(axesOpts, prefix, index) {
 
- 			var id;
 
- 			var hasId = function(obj) {
 
- 				return obj.id === id;
 
- 			};
 
- 			do {
 
- 				id = prefix + index++;
 
- 			} while (helpers$1.findIndex(axesOpts, hasId) >= 0);
 
- 			return id;
 
- 		}
 
- 		function positionIsHorizontal(position) {
 
- 			return position === 'top' || position === 'bottom';
 
- 		}
 
- 		function compare2Level(l1, l2) {
 
- 			return function(a, b) {
 
- 				return a[l1] === b[l1]
 
- 					? a[l2] - b[l2]
 
- 					: a[l1] - b[l1];
 
- 			};
 
- 		}
 
- 		var Chart = function(item, config) {
 
- 			this.construct(item, config);
 
- 			return this;
 
- 		};
 
- 		helpers$1.extend(Chart.prototype, /** @lends Chart */ {
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			construct: function(item, config) {
 
- 				var me = this;
 
- 				config = initConfig(config);
 
- 				var context = platform.acquireContext(item, config);
 
- 				var canvas = context && context.canvas;
 
- 				var height = canvas && canvas.height;
 
- 				var width = canvas && canvas.width;
 
- 				me.id = helpers$1.uid();
 
- 				me.ctx = context;
 
- 				me.canvas = canvas;
 
- 				me.config = config;
 
- 				me.width = width;
 
- 				me.height = height;
 
- 				me.aspectRatio = height ? width / height : null;
 
- 				me.options = config.options;
 
- 				me._bufferedRender = false;
 
- 				me._layers = [];
 
- 				/**
 
- 				 * Provided for backward compatibility, Chart and Chart.Controller have been merged,
 
- 				 * the "instance" still need to be defined since it might be called from plugins.
 
- 				 * @prop Chart#chart
 
- 				 * @deprecated since version 2.6.0
 
- 				 * @todo remove at version 3
 
- 				 * @private
 
- 				 */
 
- 				me.chart = me;
 
- 				me.controller = me; // chart.chart.controller #inception
 
- 				// Add the chart instance to the global namespace
 
- 				Chart.instances[me.id] = me;
 
- 				// Define alias to the config data: `chart.data === chart.config.data`
 
- 				Object.defineProperty(me, 'data', {
 
- 					get: function() {
 
- 						return me.config.data;
 
- 					},
 
- 					set: function(value) {
 
- 						me.config.data = value;
 
- 					}
 
- 				});
 
- 				if (!context || !canvas) {
 
- 					// The given item is not a compatible context2d element, let's return before finalizing
 
- 					// the chart initialization but after setting basic chart / controller properties that
 
- 					// can help to figure out that the chart is not valid (e.g chart.canvas !== null);
 
- 					// https://github.com/chartjs/Chart.js/issues/2807
 
- 					console.error("Failed to create chart: can't acquire context from the given item");
 
- 					return;
 
- 				}
 
- 				me.initialize();
 
- 				me.update();
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			initialize: function() {
 
- 				var me = this;
 
- 				// Before init plugin notification
 
- 				core_plugins.notify(me, 'beforeInit');
 
- 				helpers$1.retinaScale(me, me.options.devicePixelRatio);
 
- 				me.bindEvents();
 
- 				if (me.options.responsive) {
 
- 					// Initial resize before chart draws (must be silent to preserve initial animations).
 
- 					me.resize(true);
 
- 				}
 
- 				me.initToolTip();
 
- 				// After init plugin notification
 
- 				core_plugins.notify(me, 'afterInit');
 
- 				return me;
 
- 			},
 
- 			clear: function() {
 
- 				helpers$1.canvas.clear(this);
 
- 				return this;
 
- 			},
 
- 			stop: function() {
 
- 				// Stops any current animation loop occurring
 
- 				core_animations.cancelAnimation(this);
 
- 				return this;
 
- 			},
 
- 			resize: function(silent) {
 
- 				var me = this;
 
- 				var options = me.options;
 
- 				var canvas = me.canvas;
 
- 				var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;
 
- 				// the canvas render width and height will be casted to integers so make sure that
 
- 				// the canvas display style uses the same integer values to avoid blurring effect.
 
- 				// Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collapsed
 
- 				var newWidth = Math.max(0, Math.floor(helpers$1.getMaximumWidth(canvas)));
 
- 				var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers$1.getMaximumHeight(canvas)));
 
- 				if (me.width === newWidth && me.height === newHeight) {
 
- 					return;
 
- 				}
 
- 				canvas.width = me.width = newWidth;
 
- 				canvas.height = me.height = newHeight;
 
- 				canvas.style.width = newWidth + 'px';
 
- 				canvas.style.height = newHeight + 'px';
 
- 				helpers$1.retinaScale(me, options.devicePixelRatio);
 
- 				if (!silent) {
 
- 					// Notify any plugins about the resize
 
- 					var newSize = {width: newWidth, height: newHeight};
 
- 					core_plugins.notify(me, 'resize', [newSize]);
 
- 					// Notify of resize
 
- 					if (options.onResize) {
 
- 						options.onResize(me, newSize);
 
- 					}
 
- 					me.stop();
 
- 					me.update({
 
- 						duration: options.responsiveAnimationDuration
 
- 					});
 
- 				}
 
- 			},
 
- 			ensureScalesHaveIDs: function() {
 
- 				var options = this.options;
 
- 				var scalesOptions = options.scales || {};
 
- 				var scaleOptions = options.scale;
 
- 				helpers$1.each(scalesOptions.xAxes, function(xAxisOptions, index) {
 
- 					if (!xAxisOptions.id) {
 
- 						xAxisOptions.id = nextAvailableScaleId(scalesOptions.xAxes, 'x-axis-', index);
 
- 					}
 
- 				});
 
- 				helpers$1.each(scalesOptions.yAxes, function(yAxisOptions, index) {
 
- 					if (!yAxisOptions.id) {
 
- 						yAxisOptions.id = nextAvailableScaleId(scalesOptions.yAxes, 'y-axis-', index);
 
- 					}
 
- 				});
 
- 				if (scaleOptions) {
 
- 					scaleOptions.id = scaleOptions.id || 'scale';
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Builds a map of scale ID to scale object for future lookup.
 
- 			 */
 
- 			buildOrUpdateScales: function() {
 
- 				var me = this;
 
- 				var options = me.options;
 
- 				var scales = me.scales || {};
 
- 				var items = [];
 
- 				var updated = Object.keys(scales).reduce(function(obj, id) {
 
- 					obj[id] = false;
 
- 					return obj;
 
- 				}, {});
 
- 				if (options.scales) {
 
- 					items = items.concat(
 
- 						(options.scales.xAxes || []).map(function(xAxisOptions) {
 
- 							return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
 
- 						}),
 
- 						(options.scales.yAxes || []).map(function(yAxisOptions) {
 
- 							return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
 
- 						})
 
- 					);
 
- 				}
 
- 				if (options.scale) {
 
- 					items.push({
 
- 						options: options.scale,
 
- 						dtype: 'radialLinear',
 
- 						isDefault: true,
 
- 						dposition: 'chartArea'
 
- 					});
 
- 				}
 
- 				helpers$1.each(items, function(item) {
 
- 					var scaleOptions = item.options;
 
- 					var id = scaleOptions.id;
 
- 					var scaleType = valueOrDefault$9(scaleOptions.type, item.dtype);
 
- 					if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
 
- 						scaleOptions.position = item.dposition;
 
- 					}
 
- 					updated[id] = true;
 
- 					var scale = null;
 
- 					if (id in scales && scales[id].type === scaleType) {
 
- 						scale = scales[id];
 
- 						scale.options = scaleOptions;
 
- 						scale.ctx = me.ctx;
 
- 						scale.chart = me;
 
- 					} else {
 
- 						var scaleClass = core_scaleService.getScaleConstructor(scaleType);
 
- 						if (!scaleClass) {
 
- 							return;
 
- 						}
 
- 						scale = new scaleClass({
 
- 							id: id,
 
- 							type: scaleType,
 
- 							options: scaleOptions,
 
- 							ctx: me.ctx,
 
- 							chart: me
 
- 						});
 
- 						scales[scale.id] = scale;
 
- 					}
 
- 					scale.mergeTicksOptions();
 
- 					// TODO(SB): I think we should be able to remove this custom case (options.scale)
 
- 					// and consider it as a regular scale part of the "scales"" map only! This would
 
- 					// make the logic easier and remove some useless? custom code.
 
- 					if (item.isDefault) {
 
- 						me.scale = scale;
 
- 					}
 
- 				});
 
- 				// clear up discarded scales
 
- 				helpers$1.each(updated, function(hasUpdated, id) {
 
- 					if (!hasUpdated) {
 
- 						delete scales[id];
 
- 					}
 
- 				});
 
- 				me.scales = scales;
 
- 				core_scaleService.addScalesToLayout(this);
 
- 			},
 
- 			buildOrUpdateControllers: function() {
 
- 				var me = this;
 
- 				var newControllers = [];
 
- 				var datasets = me.data.datasets;
 
- 				var i, ilen;
 
- 				for (i = 0, ilen = datasets.length; i < ilen; i++) {
 
- 					var dataset = datasets[i];
 
- 					var meta = me.getDatasetMeta(i);
 
- 					var type = dataset.type || me.config.type;
 
- 					if (meta.type && meta.type !== type) {
 
- 						me.destroyDatasetMeta(i);
 
- 						meta = me.getDatasetMeta(i);
 
- 					}
 
- 					meta.type = type;
 
- 					meta.order = dataset.order || 0;
 
- 					meta.index = i;
 
- 					if (meta.controller) {
 
- 						meta.controller.updateIndex(i);
 
- 						meta.controller.linkScales();
 
- 					} else {
 
- 						var ControllerClass = controllers[meta.type];
 
- 						if (ControllerClass === undefined) {
 
- 							throw new Error('"' + meta.type + '" is not a chart type.');
 
- 						}
 
- 						meta.controller = new ControllerClass(me, i);
 
- 						newControllers.push(meta.controller);
 
- 					}
 
- 				}
 
- 				return newControllers;
 
- 			},
 
- 			/**
 
- 			 * Reset the elements of all datasets
 
- 			 * @private
 
- 			 */
 
- 			resetElements: function() {
 
- 				var me = this;
 
- 				helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
 
- 					me.getDatasetMeta(datasetIndex).controller.reset();
 
- 				}, me);
 
- 			},
 
- 			/**
 
- 			* Resets the chart back to it's state before the initial animation
 
- 			*/
 
- 			reset: function() {
 
- 				this.resetElements();
 
- 				this.tooltip.initialize();
 
- 			},
 
- 			update: function(config) {
 
- 				var me = this;
 
- 				var i, ilen;
 
- 				if (!config || typeof config !== 'object') {
 
- 					// backwards compatibility
 
- 					config = {
 
- 						duration: config,
 
- 						lazy: arguments[1]
 
- 					};
 
- 				}
 
- 				updateConfig(me);
 
- 				// plugins options references might have change, let's invalidate the cache
 
- 				// https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
 
- 				core_plugins._invalidate(me);
 
- 				if (core_plugins.notify(me, 'beforeUpdate') === false) {
 
- 					return;
 
- 				}
 
- 				// In case the entire data object changed
 
- 				me.tooltip._data = me.data;
 
- 				// Make sure dataset controllers are updated and new controllers are reset
 
- 				var newControllers = me.buildOrUpdateControllers();
 
- 				// Make sure all dataset controllers have correct meta data counts
 
- 				for (i = 0, ilen = me.data.datasets.length; i < ilen; i++) {
 
- 					me.getDatasetMeta(i).controller.buildOrUpdateElements();
 
- 				}
 
- 				me.updateLayout();
 
- 				// Can only reset the new controllers after the scales have been updated
 
- 				if (me.options.animation && me.options.animation.duration) {
 
- 					helpers$1.each(newControllers, function(controller) {
 
- 						controller.reset();
 
- 					});
 
- 				}
 
- 				me.updateDatasets();
 
- 				// Need to reset tooltip in case it is displayed with elements that are removed
 
- 				// after update.
 
- 				me.tooltip.initialize();
 
- 				// Last active contains items that were previously in the tooltip.
 
- 				// When we reset the tooltip, we need to clear it
 
- 				me.lastActive = [];
 
- 				// Do this before render so that any plugins that need final scale updates can use it
 
- 				core_plugins.notify(me, 'afterUpdate');
 
- 				me._layers.sort(compare2Level('z', '_idx'));
 
- 				if (me._bufferedRender) {
 
- 					me._bufferedRequest = {
 
- 						duration: config.duration,
 
- 						easing: config.easing,
 
- 						lazy: config.lazy
 
- 					};
 
- 				} else {
 
- 					me.render(config);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
 
- 			 * hook, in which case, plugins will not be called on `afterLayout`.
 
- 			 * @private
 
- 			 */
 
- 			updateLayout: function() {
 
- 				var me = this;
 
- 				if (core_plugins.notify(me, 'beforeLayout') === false) {
 
- 					return;
 
- 				}
 
- 				core_layouts.update(this, this.width, this.height);
 
- 				me._layers = [];
 
- 				helpers$1.each(me.boxes, function(box) {
 
- 					// _configure is called twice, once in core.scale.update and once here.
 
- 					// Here the boxes are fully updated and at their final positions.
 
- 					if (box._configure) {
 
- 						box._configure();
 
- 					}
 
- 					me._layers.push.apply(me._layers, box._layers());
 
- 				}, me);
 
- 				me._layers.forEach(function(item, index) {
 
- 					item._idx = index;
 
- 				});
 
- 				/**
 
- 				 * Provided for backward compatibility, use `afterLayout` instead.
 
- 				 * @method IPlugin#afterScaleUpdate
 
- 				 * @deprecated since version 2.5.0
 
- 				 * @todo remove at version 3
 
- 				 * @private
 
- 				 */
 
- 				core_plugins.notify(me, 'afterScaleUpdate');
 
- 				core_plugins.notify(me, 'afterLayout');
 
- 			},
 
- 			/**
 
- 			 * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
 
- 			 * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
 
- 			 * @private
 
- 			 */
 
- 			updateDatasets: function() {
 
- 				var me = this;
 
- 				if (core_plugins.notify(me, 'beforeDatasetsUpdate') === false) {
 
- 					return;
 
- 				}
 
- 				for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
 
- 					me.updateDataset(i);
 
- 				}
 
- 				core_plugins.notify(me, 'afterDatasetsUpdate');
 
- 			},
 
- 			/**
 
- 			 * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
 
- 			 * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
 
- 			 * @private
 
- 			 */
 
- 			updateDataset: function(index) {
 
- 				var me = this;
 
- 				var meta = me.getDatasetMeta(index);
 
- 				var args = {
 
- 					meta: meta,
 
- 					index: index
 
- 				};
 
- 				if (core_plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
 
- 					return;
 
- 				}
 
- 				meta.controller._update();
 
- 				core_plugins.notify(me, 'afterDatasetUpdate', [args]);
 
- 			},
 
- 			render: function(config) {
 
- 				var me = this;
 
- 				if (!config || typeof config !== 'object') {
 
- 					// backwards compatibility
 
- 					config = {
 
- 						duration: config,
 
- 						lazy: arguments[1]
 
- 					};
 
- 				}
 
- 				var animationOptions = me.options.animation;
 
- 				var duration = valueOrDefault$9(config.duration, animationOptions && animationOptions.duration);
 
- 				var lazy = config.lazy;
 
- 				if (core_plugins.notify(me, 'beforeRender') === false) {
 
- 					return;
 
- 				}
 
- 				var onComplete = function(animation) {
 
- 					core_plugins.notify(me, 'afterRender');
 
- 					helpers$1.callback(animationOptions && animationOptions.onComplete, [animation], me);
 
- 				};
 
- 				if (animationOptions && duration) {
 
- 					var animation = new core_animation({
 
- 						numSteps: duration / 16.66, // 60 fps
 
- 						easing: config.easing || animationOptions.easing,
 
- 						render: function(chart, animationObject) {
 
- 							var easingFunction = helpers$1.easing.effects[animationObject.easing];
 
- 							var currentStep = animationObject.currentStep;
 
- 							var stepDecimal = currentStep / animationObject.numSteps;
 
- 							chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
 
- 						},
 
- 						onAnimationProgress: animationOptions.onProgress,
 
- 						onAnimationComplete: onComplete
 
- 					});
 
- 					core_animations.addAnimation(me, animation, duration, lazy);
 
- 				} else {
 
- 					me.draw();
 
- 					// See https://github.com/chartjs/Chart.js/issues/3781
 
- 					onComplete(new core_animation({numSteps: 0, chart: me}));
 
- 				}
 
- 				return me;
 
- 			},
 
- 			draw: function(easingValue) {
 
- 				var me = this;
 
- 				var i, layers;
 
- 				me.clear();
 
- 				if (helpers$1.isNullOrUndef(easingValue)) {
 
- 					easingValue = 1;
 
- 				}
 
- 				me.transition(easingValue);
 
- 				if (me.width <= 0 || me.height <= 0) {
 
- 					return;
 
- 				}
 
- 				if (core_plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
 
- 					return;
 
- 				}
 
- 				// Because of plugin hooks (before/afterDatasetsDraw), datasets can't
 
- 				// currently be part of layers. Instead, we draw
 
- 				// layers <= 0 before(default, backward compat), and the rest after
 
- 				layers = me._layers;
 
- 				for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {
 
- 					layers[i].draw(me.chartArea);
 
- 				}
 
- 				me.drawDatasets(easingValue);
 
- 				// Rest of layers
 
- 				for (; i < layers.length; ++i) {
 
- 					layers[i].draw(me.chartArea);
 
- 				}
 
- 				me._drawTooltip(easingValue);
 
- 				core_plugins.notify(me, 'afterDraw', [easingValue]);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			transition: function(easingValue) {
 
- 				var me = this;
 
- 				for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
 
- 					if (me.isDatasetVisible(i)) {
 
- 						me.getDatasetMeta(i).controller.transition(easingValue);
 
- 					}
 
- 				}
 
- 				me.tooltip.transition(easingValue);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getSortedDatasetMetas: function(filterVisible) {
 
- 				var me = this;
 
- 				var datasets = me.data.datasets || [];
 
- 				var result = [];
 
- 				var i, ilen;
 
- 				for (i = 0, ilen = datasets.length; i < ilen; ++i) {
 
- 					if (!filterVisible || me.isDatasetVisible(i)) {
 
- 						result.push(me.getDatasetMeta(i));
 
- 					}
 
- 				}
 
- 				result.sort(compare2Level('order', 'index'));
 
- 				return result;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getSortedVisibleDatasetMetas: function() {
 
- 				return this._getSortedDatasetMetas(true);
 
- 			},
 
- 			/**
 
- 			 * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
 
- 			 * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
 
- 			 * @private
 
- 			 */
 
- 			drawDatasets: function(easingValue) {
 
- 				var me = this;
 
- 				var metasets, i;
 
- 				if (core_plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
 
- 					return;
 
- 				}
 
- 				metasets = me._getSortedVisibleDatasetMetas();
 
- 				for (i = metasets.length - 1; i >= 0; --i) {
 
- 					me.drawDataset(metasets[i], easingValue);
 
- 				}
 
- 				core_plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
 
- 			},
 
- 			/**
 
- 			 * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
 
- 			 * hook, in which case, plugins will not be called on `afterDatasetDraw`.
 
- 			 * @private
 
- 			 */
 
- 			drawDataset: function(meta, easingValue) {
 
- 				var me = this;
 
- 				var args = {
 
- 					meta: meta,
 
- 					index: meta.index,
 
- 					easingValue: easingValue
 
- 				};
 
- 				if (core_plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
 
- 					return;
 
- 				}
 
- 				meta.controller.draw(easingValue);
 
- 				core_plugins.notify(me, 'afterDatasetDraw', [args]);
 
- 			},
 
- 			/**
 
- 			 * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
 
- 			 * hook, in which case, plugins will not be called on `afterTooltipDraw`.
 
- 			 * @private
 
- 			 */
 
- 			_drawTooltip: function(easingValue) {
 
- 				var me = this;
 
- 				var tooltip = me.tooltip;
 
- 				var args = {
 
- 					tooltip: tooltip,
 
- 					easingValue: easingValue
 
- 				};
 
- 				if (core_plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
 
- 					return;
 
- 				}
 
- 				tooltip.draw();
 
- 				core_plugins.notify(me, 'afterTooltipDraw', [args]);
 
- 			},
 
- 			/**
 
- 			 * Get the single element that was clicked on
 
- 			 * @return An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
 
- 			 */
 
- 			getElementAtEvent: function(e) {
 
- 				return core_interaction.modes.single(this, e);
 
- 			},
 
- 			getElementsAtEvent: function(e) {
 
- 				return core_interaction.modes.label(this, e, {intersect: true});
 
- 			},
 
- 			getElementsAtXAxis: function(e) {
 
- 				return core_interaction.modes['x-axis'](this, e, {intersect: true});
 
- 			},
 
- 			getElementsAtEventForMode: function(e, mode, options) {
 
- 				var method = core_interaction.modes[mode];
 
- 				if (typeof method === 'function') {
 
- 					return method(this, e, options);
 
- 				}
 
- 				return [];
 
- 			},
 
- 			getDatasetAtEvent: function(e) {
 
- 				return core_interaction.modes.dataset(this, e, {intersect: true});
 
- 			},
 
- 			getDatasetMeta: function(datasetIndex) {
 
- 				var me = this;
 
- 				var dataset = me.data.datasets[datasetIndex];
 
- 				if (!dataset._meta) {
 
- 					dataset._meta = {};
 
- 				}
 
- 				var meta = dataset._meta[me.id];
 
- 				if (!meta) {
 
- 					meta = dataset._meta[me.id] = {
 
- 						type: null,
 
- 						data: [],
 
- 						dataset: null,
 
- 						controller: null,
 
- 						hidden: null,			// See isDatasetVisible() comment
 
- 						xAxisID: null,
 
- 						yAxisID: null,
 
- 						order: dataset.order || 0,
 
- 						index: datasetIndex
 
- 					};
 
- 				}
 
- 				return meta;
 
- 			},
 
- 			getVisibleDatasetCount: function() {
 
- 				var count = 0;
 
- 				for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
 
- 					if (this.isDatasetVisible(i)) {
 
- 						count++;
 
- 					}
 
- 				}
 
- 				return count;
 
- 			},
 
- 			isDatasetVisible: function(datasetIndex) {
 
- 				var meta = this.getDatasetMeta(datasetIndex);
 
- 				// meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
 
- 				// the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
 
- 				return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
 
- 			},
 
- 			generateLegend: function() {
 
- 				return this.options.legendCallback(this);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			destroyDatasetMeta: function(datasetIndex) {
 
- 				var id = this.id;
 
- 				var dataset = this.data.datasets[datasetIndex];
 
- 				var meta = dataset._meta && dataset._meta[id];
 
- 				if (meta) {
 
- 					meta.controller.destroy();
 
- 					delete dataset._meta[id];
 
- 				}
 
- 			},
 
- 			destroy: function() {
 
- 				var me = this;
 
- 				var canvas = me.canvas;
 
- 				var i, ilen;
 
- 				me.stop();
 
- 				// dataset controllers need to cleanup associated data
 
- 				for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
 
- 					me.destroyDatasetMeta(i);
 
- 				}
 
- 				if (canvas) {
 
- 					me.unbindEvents();
 
- 					helpers$1.canvas.clear(me);
 
- 					platform.releaseContext(me.ctx);
 
- 					me.canvas = null;
 
- 					me.ctx = null;
 
- 				}
 
- 				core_plugins.notify(me, 'destroy');
 
- 				delete Chart.instances[me.id];
 
- 			},
 
- 			toBase64Image: function() {
 
- 				return this.canvas.toDataURL.apply(this.canvas, arguments);
 
- 			},
 
- 			initToolTip: function() {
 
- 				var me = this;
 
- 				me.tooltip = new core_tooltip({
 
- 					_chart: me,
 
- 					_chartInstance: me, // deprecated, backward compatibility
 
- 					_data: me.data,
 
- 					_options: me.options.tooltips
 
- 				}, me);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			bindEvents: function() {
 
- 				var me = this;
 
- 				var listeners = me._listeners = {};
 
- 				var listener = function() {
 
- 					me.eventHandler.apply(me, arguments);
 
- 				};
 
- 				helpers$1.each(me.options.events, function(type) {
 
- 					platform.addEventListener(me, type, listener);
 
- 					listeners[type] = listener;
 
- 				});
 
- 				// Elements used to detect size change should not be injected for non responsive charts.
 
- 				// See https://github.com/chartjs/Chart.js/issues/2210
 
- 				if (me.options.responsive) {
 
- 					listener = function() {
 
- 						me.resize();
 
- 					};
 
- 					platform.addEventListener(me, 'resize', listener);
 
- 					listeners.resize = listener;
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			unbindEvents: function() {
 
- 				var me = this;
 
- 				var listeners = me._listeners;
 
- 				if (!listeners) {
 
- 					return;
 
- 				}
 
- 				delete me._listeners;
 
- 				helpers$1.each(listeners, function(listener, type) {
 
- 					platform.removeEventListener(me, type, listener);
 
- 				});
 
- 			},
 
- 			updateHoverStyle: function(elements, mode, enabled) {
 
- 				var prefix = enabled ? 'set' : 'remove';
 
- 				var element, i, ilen;
 
- 				for (i = 0, ilen = elements.length; i < ilen; ++i) {
 
- 					element = elements[i];
 
- 					if (element) {
 
- 						this.getDatasetMeta(element._datasetIndex).controller[prefix + 'HoverStyle'](element);
 
- 					}
 
- 				}
 
- 				if (mode === 'dataset') {
 
- 					this.getDatasetMeta(elements[0]._datasetIndex).controller['_' + prefix + 'DatasetHoverStyle']();
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			eventHandler: function(e) {
 
- 				var me = this;
 
- 				var tooltip = me.tooltip;
 
- 				if (core_plugins.notify(me, 'beforeEvent', [e]) === false) {
 
- 					return;
 
- 				}
 
- 				// Buffer any update calls so that renders do not occur
 
- 				me._bufferedRender = true;
 
- 				me._bufferedRequest = null;
 
- 				var changed = me.handleEvent(e);
 
- 				// for smooth tooltip animations issue #4989
 
- 				// the tooltip should be the source of change
 
- 				// Animation check workaround:
 
- 				// tooltip._start will be null when tooltip isn't animating
 
- 				if (tooltip) {
 
- 					changed = tooltip._start
 
- 						? tooltip.handleEvent(e)
 
- 						: changed | tooltip.handleEvent(e);
 
- 				}
 
- 				core_plugins.notify(me, 'afterEvent', [e]);
 
- 				var bufferedRequest = me._bufferedRequest;
 
- 				if (bufferedRequest) {
 
- 					// If we have an update that was triggered, we need to do a normal render
 
- 					me.render(bufferedRequest);
 
- 				} else if (changed && !me.animating) {
 
- 					// If entering, leaving, or changing elements, animate the change via pivot
 
- 					me.stop();
 
- 					// We only need to render at this point. Updating will cause scales to be
 
- 					// recomputed generating flicker & using more memory than necessary.
 
- 					me.render({
 
- 						duration: me.options.hover.animationDuration,
 
- 						lazy: true
 
- 					});
 
- 				}
 
- 				me._bufferedRender = false;
 
- 				me._bufferedRequest = null;
 
- 				return me;
 
- 			},
 
- 			/**
 
- 			 * Handle an event
 
- 			 * @private
 
- 			 * @param {IEvent} event the event to handle
 
- 			 * @return {boolean} true if the chart needs to re-render
 
- 			 */
 
- 			handleEvent: function(e) {
 
- 				var me = this;
 
- 				var options = me.options || {};
 
- 				var hoverOptions = options.hover;
 
- 				var changed = false;
 
- 				me.lastActive = me.lastActive || [];
 
- 				// Find Active Elements for hover and tooltips
 
- 				if (e.type === 'mouseout') {
 
- 					me.active = [];
 
- 				} else {
 
- 					me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
 
- 				}
 
- 				// Invoke onHover hook
 
- 				// Need to call with native event here to not break backwards compatibility
 
- 				helpers$1.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);
 
- 				if (e.type === 'mouseup' || e.type === 'click') {
 
- 					if (options.onClick) {
 
- 						// Use e.native here for backwards compatibility
 
- 						options.onClick.call(me, e.native, me.active);
 
- 					}
 
- 				}
 
- 				// Remove styling for last active (even if it may still be active)
 
- 				if (me.lastActive.length) {
 
- 					me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
 
- 				}
 
- 				// Built in hover styling
 
- 				if (me.active.length && hoverOptions.mode) {
 
- 					me.updateHoverStyle(me.active, hoverOptions.mode, true);
 
- 				}
 
- 				changed = !helpers$1.arrayEquals(me.active, me.lastActive);
 
- 				// Remember Last Actives
 
- 				me.lastActive = me.active;
 
- 				return changed;
 
- 			}
 
- 		});
 
- 		/**
 
- 		 * NOTE(SB) We actually don't use this container anymore but we need to keep it
 
- 		 * for backward compatibility. Though, it can still be useful for plugins that
 
- 		 * would need to work on multiple charts?!
 
- 		 */
 
- 		Chart.instances = {};
 
- 		var core_controller = Chart;
 
- 		// DEPRECATIONS
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart instead.
 
- 		 * @class Chart.Controller
 
- 		 * @deprecated since version 2.6
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		Chart.Controller = Chart;
 
- 		/**
 
- 		 * Provided for backward compatibility, not available anymore.
 
- 		 * @namespace Chart
 
- 		 * @deprecated since version 2.8
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		Chart.types = {};
 
- 		/**
 
- 		 * Provided for backward compatibility, not available anymore.
 
- 		 * @namespace Chart.helpers.configMerge
 
- 		 * @deprecated since version 2.8.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers$1.configMerge = mergeConfig;
 
- 		/**
 
- 		 * Provided for backward compatibility, not available anymore.
 
- 		 * @namespace Chart.helpers.scaleMerge
 
- 		 * @deprecated since version 2.8.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		helpers$1.scaleMerge = mergeScaleConfig;
 
- 		var core_helpers = function() {
 
- 			// -- Basic js utility methods
 
- 			helpers$1.where = function(collection, filterCallback) {
 
- 				if (helpers$1.isArray(collection) && Array.prototype.filter) {
 
- 					return collection.filter(filterCallback);
 
- 				}
 
- 				var filtered = [];
 
- 				helpers$1.each(collection, function(item) {
 
- 					if (filterCallback(item)) {
 
- 						filtered.push(item);
 
- 					}
 
- 				});
 
- 				return filtered;
 
- 			};
 
- 			helpers$1.findIndex = Array.prototype.findIndex ?
 
- 				function(array, callback, scope) {
 
- 					return array.findIndex(callback, scope);
 
- 				} :
 
- 				function(array, callback, scope) {
 
- 					scope = scope === undefined ? array : scope;
 
- 					for (var i = 0, ilen = array.length; i < ilen; ++i) {
 
- 						if (callback.call(scope, array[i], i, array)) {
 
- 							return i;
 
- 						}
 
- 					}
 
- 					return -1;
 
- 				};
 
- 			helpers$1.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
 
- 				// Default to start of the array
 
- 				if (helpers$1.isNullOrUndef(startIndex)) {
 
- 					startIndex = -1;
 
- 				}
 
- 				for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
 
- 					var currentItem = arrayToSearch[i];
 
- 					if (filterCallback(currentItem)) {
 
- 						return currentItem;
 
- 					}
 
- 				}
 
- 			};
 
- 			helpers$1.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
 
- 				// Default to end of the array
 
- 				if (helpers$1.isNullOrUndef(startIndex)) {
 
- 					startIndex = arrayToSearch.length;
 
- 				}
 
- 				for (var i = startIndex - 1; i >= 0; i--) {
 
- 					var currentItem = arrayToSearch[i];
 
- 					if (filterCallback(currentItem)) {
 
- 						return currentItem;
 
- 					}
 
- 				}
 
- 			};
 
- 			// -- Math methods
 
- 			helpers$1.isNumber = function(n) {
 
- 				return !isNaN(parseFloat(n)) && isFinite(n);
 
- 			};
 
- 			helpers$1.almostEquals = function(x, y, epsilon) {
 
- 				return Math.abs(x - y) < epsilon;
 
- 			};
 
- 			helpers$1.almostWhole = function(x, epsilon) {
 
- 				var rounded = Math.round(x);
 
- 				return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x);
 
- 			};
 
- 			helpers$1.max = function(array) {
 
- 				return array.reduce(function(max, value) {
 
- 					if (!isNaN(value)) {
 
- 						return Math.max(max, value);
 
- 					}
 
- 					return max;
 
- 				}, Number.NEGATIVE_INFINITY);
 
- 			};
 
- 			helpers$1.min = function(array) {
 
- 				return array.reduce(function(min, value) {
 
- 					if (!isNaN(value)) {
 
- 						return Math.min(min, value);
 
- 					}
 
- 					return min;
 
- 				}, Number.POSITIVE_INFINITY);
 
- 			};
 
- 			helpers$1.sign = Math.sign ?
 
- 				function(x) {
 
- 					return Math.sign(x);
 
- 				} :
 
- 				function(x) {
 
- 					x = +x; // convert to a number
 
- 					if (x === 0 || isNaN(x)) {
 
- 						return x;
 
- 					}
 
- 					return x > 0 ? 1 : -1;
 
- 				};
 
- 			helpers$1.toRadians = function(degrees) {
 
- 				return degrees * (Math.PI / 180);
 
- 			};
 
- 			helpers$1.toDegrees = function(radians) {
 
- 				return radians * (180 / Math.PI);
 
- 			};
 
- 			/**
 
- 			 * Returns the number of decimal places
 
- 			 * i.e. the number of digits after the decimal point, of the value of this Number.
 
- 			 * @param {number} x - A number.
 
- 			 * @returns {number} The number of decimal places.
 
- 			 * @private
 
- 			 */
 
- 			helpers$1._decimalPlaces = function(x) {
 
- 				if (!helpers$1.isFinite(x)) {
 
- 					return;
 
- 				}
 
- 				var e = 1;
 
- 				var p = 0;
 
- 				while (Math.round(x * e) / e !== x) {
 
- 					e *= 10;
 
- 					p++;
 
- 				}
 
- 				return p;
 
- 			};
 
- 			// Gets the angle from vertical upright to the point about a centre.
 
- 			helpers$1.getAngleFromPoint = function(centrePoint, anglePoint) {
 
- 				var distanceFromXCenter = anglePoint.x - centrePoint.x;
 
- 				var distanceFromYCenter = anglePoint.y - centrePoint.y;
 
- 				var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
 
- 				var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
 
- 				if (angle < (-0.5 * Math.PI)) {
 
- 					angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
 
- 				}
 
- 				return {
 
- 					angle: angle,
 
- 					distance: radialDistanceFromCenter
 
- 				};
 
- 			};
 
- 			helpers$1.distanceBetweenPoints = function(pt1, pt2) {
 
- 				return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
 
- 			};
 
- 			/**
 
- 			 * Provided for backward compatibility, not available anymore
 
- 			 * @function Chart.helpers.aliasPixel
 
- 			 * @deprecated since version 2.8.0
 
- 			 * @todo remove at version 3
 
- 			 */
 
- 			helpers$1.aliasPixel = function(pixelWidth) {
 
- 				return (pixelWidth % 2 === 0) ? 0 : 0.5;
 
- 			};
 
- 			/**
 
- 			 * Returns the aligned pixel value to avoid anti-aliasing blur
 
- 			 * @param {Chart} chart - The chart instance.
 
- 			 * @param {number} pixel - A pixel value.
 
- 			 * @param {number} width - The width of the element.
 
- 			 * @returns {number} The aligned pixel value.
 
- 			 * @private
 
- 			 */
 
- 			helpers$1._alignPixel = function(chart, pixel, width) {
 
- 				var devicePixelRatio = chart.currentDevicePixelRatio;
 
- 				var halfWidth = width / 2;
 
- 				return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
 
- 			};
 
- 			helpers$1.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
 
- 				// Props to Rob Spencer at scaled innovation for his post on splining between points
 
- 				// http://scaledinnovation.com/analytics/splines/aboutSplines.html
 
- 				// This function must also respect "skipped" points
 
- 				var previous = firstPoint.skip ? middlePoint : firstPoint;
 
- 				var current = middlePoint;
 
- 				var next = afterPoint.skip ? middlePoint : afterPoint;
 
- 				var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
 
- 				var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
 
- 				var s01 = d01 / (d01 + d12);
 
- 				var s12 = d12 / (d01 + d12);
 
- 				// If all points are the same, s01 & s02 will be inf
 
- 				s01 = isNaN(s01) ? 0 : s01;
 
- 				s12 = isNaN(s12) ? 0 : s12;
 
- 				var fa = t * s01; // scaling factor for triangle Ta
 
- 				var 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)
 
- 					}
 
- 				};
 
- 			};
 
- 			helpers$1.EPSILON = Number.EPSILON || 1e-14;
 
- 			helpers$1.splineCurveMonotone = function(points) {
 
- 				// This function calculates Bézier control points in a similar way than |splineCurve|,
 
- 				// but preserves monotonicity of the provided data and ensures no local extremums are added
 
- 				// between the dataset discrete points due to the interpolation.
 
- 				// See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
 
- 				var pointsWithTangents = (points || []).map(function(point) {
 
- 					return {
 
- 						model: point._model,
 
- 						deltaK: 0,
 
- 						mK: 0
 
- 					};
 
- 				});
 
- 				// Calculate slopes (deltaK) and initialize tangents (mK)
 
- 				var pointsLen = pointsWithTangents.length;
 
- 				var i, pointBefore, pointCurrent, pointAfter;
 
- 				for (i = 0; i < pointsLen; ++i) {
 
- 					pointCurrent = pointsWithTangents[i];
 
- 					if (pointCurrent.model.skip) {
 
- 						continue;
 
- 					}
 
- 					pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
 
- 					pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
 
- 					if (pointAfter && !pointAfter.model.skip) {
 
- 						var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
 
- 						// In the case of two points that appear at the same x pixel, slopeDeltaX is 0
 
- 						pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
 
- 					}
 
- 					if (!pointBefore || pointBefore.model.skip) {
 
- 						pointCurrent.mK = pointCurrent.deltaK;
 
- 					} else if (!pointAfter || pointAfter.model.skip) {
 
- 						pointCurrent.mK = pointBefore.deltaK;
 
- 					} else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
 
- 						pointCurrent.mK = 0;
 
- 					} else {
 
- 						pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
 
- 					}
 
- 				}
 
- 				// Adjust tangents to ensure monotonic properties
 
- 				var alphaK, betaK, tauK, squaredMagnitude;
 
- 				for (i = 0; i < pointsLen - 1; ++i) {
 
- 					pointCurrent = pointsWithTangents[i];
 
- 					pointAfter = pointsWithTangents[i + 1];
 
- 					if (pointCurrent.model.skip || pointAfter.model.skip) {
 
- 						continue;
 
- 					}
 
- 					if (helpers$1.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
 
- 						pointCurrent.mK = pointAfter.mK = 0;
 
- 						continue;
 
- 					}
 
- 					alphaK = pointCurrent.mK / pointCurrent.deltaK;
 
- 					betaK = pointAfter.mK / pointCurrent.deltaK;
 
- 					squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
 
- 					if (squaredMagnitude <= 9) {
 
- 						continue;
 
- 					}
 
- 					tauK = 3 / Math.sqrt(squaredMagnitude);
 
- 					pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
 
- 					pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
 
- 				}
 
- 				// Compute control points
 
- 				var deltaX;
 
- 				for (i = 0; i < pointsLen; ++i) {
 
- 					pointCurrent = pointsWithTangents[i];
 
- 					if (pointCurrent.model.skip) {
 
- 						continue;
 
- 					}
 
- 					pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
 
- 					pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
 
- 					if (pointBefore && !pointBefore.model.skip) {
 
- 						deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
 
- 						pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
 
- 						pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
 
- 					}
 
- 					if (pointAfter && !pointAfter.model.skip) {
 
- 						deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
 
- 						pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
 
- 						pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
 
- 					}
 
- 				}
 
- 			};
 
- 			helpers$1.nextItem = function(collection, index, loop) {
 
- 				if (loop) {
 
- 					return index >= collection.length - 1 ? collection[0] : collection[index + 1];
 
- 				}
 
- 				return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
 
- 			};
 
- 			helpers$1.previousItem = function(collection, index, loop) {
 
- 				if (loop) {
 
- 					return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
 
- 				}
 
- 				return index <= 0 ? collection[0] : collection[index - 1];
 
- 			};
 
- 			// Implementation of the nice number algorithm used in determining where axis labels will go
 
- 			helpers$1.niceNum = function(range, round) {
 
- 				var exponent = Math.floor(helpers$1.log10(range));
 
- 				var fraction = range / Math.pow(10, exponent);
 
- 				var niceFraction;
 
- 				if (round) {
 
- 					if (fraction < 1.5) {
 
- 						niceFraction = 1;
 
- 					} else if (fraction < 3) {
 
- 						niceFraction = 2;
 
- 					} else if (fraction < 7) {
 
- 						niceFraction = 5;
 
- 					} else {
 
- 						niceFraction = 10;
 
- 					}
 
- 				} else if (fraction <= 1.0) {
 
- 					niceFraction = 1;
 
- 				} else if (fraction <= 2) {
 
- 					niceFraction = 2;
 
- 				} else if (fraction <= 5) {
 
- 					niceFraction = 5;
 
- 				} else {
 
- 					niceFraction = 10;
 
- 				}
 
- 				return niceFraction * Math.pow(10, exponent);
 
- 			};
 
- 			// Request animation polyfill - https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
 
- 			helpers$1.requestAnimFrame = (function() {
 
- 				if (typeof window === 'undefined') {
 
- 					return function(callback) {
 
- 						callback();
 
- 					};
 
- 				}
 
- 				return window.requestAnimationFrame ||
 
- 					window.webkitRequestAnimationFrame ||
 
- 					window.mozRequestAnimationFrame ||
 
- 					window.oRequestAnimationFrame ||
 
- 					window.msRequestAnimationFrame ||
 
- 					function(callback) {
 
- 						return window.setTimeout(callback, 1000 / 60);
 
- 					};
 
- 			}());
 
- 			// -- DOM methods
 
- 			helpers$1.getRelativePosition = function(evt, chart) {
 
- 				var mouseX, mouseY;
 
- 				var e = evt.originalEvent || evt;
 
- 				var canvas = evt.target || evt.srcElement;
 
- 				var boundingRect = canvas.getBoundingClientRect();
 
- 				var touches = e.touches;
 
- 				if (touches && touches.length > 0) {
 
- 					mouseX = touches[0].clientX;
 
- 					mouseY = touches[0].clientY;
 
- 				} else {
 
- 					mouseX = e.clientX;
 
- 					mouseY = e.clientY;
 
- 				}
 
- 				// Scale mouse coordinates into canvas coordinates
 
- 				// by following the pattern laid out by 'jerryj' in the comments of
 
- 				// https://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
 
- 				var paddingLeft = parseFloat(helpers$1.getStyle(canvas, 'padding-left'));
 
- 				var paddingTop = parseFloat(helpers$1.getStyle(canvas, 'padding-top'));
 
- 				var paddingRight = parseFloat(helpers$1.getStyle(canvas, 'padding-right'));
 
- 				var paddingBottom = parseFloat(helpers$1.getStyle(canvas, 'padding-bottom'));
 
- 				var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
 
- 				var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
 
- 				// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
 
- 				// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
 
- 				mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
 
- 				mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
 
- 				return {
 
- 					x: mouseX,
 
- 					y: mouseY
 
- 				};
 
- 			};
 
- 			// Private helper function to convert max-width/max-height values that may be percentages into a number
 
- 			function parseMaxStyle(styleValue, node, parentProperty) {
 
- 				var valueInPixels;
 
- 				if (typeof styleValue === 'string') {
 
- 					valueInPixels = parseInt(styleValue, 10);
 
- 					if (styleValue.indexOf('%') !== -1) {
 
- 						// percentage * size in dimension
 
- 						valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
 
- 					}
 
- 				} else {
 
- 					valueInPixels = styleValue;
 
- 				}
 
- 				return valueInPixels;
 
- 			}
 
- 			/**
 
- 			 * Returns if the given value contains an effective constraint.
 
- 			 * @private
 
- 			 */
 
- 			function isConstrainedValue(value) {
 
- 				return value !== undefined && value !== null && value !== 'none';
 
- 			}
 
- 			/**
 
- 			 * Returns the max width or height of the given DOM node in a cross-browser compatible fashion
 
- 			 * @param {HTMLElement} domNode - the node to check the constraint on
 
- 			 * @param {string} maxStyle - the style that defines the maximum for the direction we are using ('max-width' / 'max-height')
 
- 			 * @param {string} percentageProperty - property of parent to use when calculating width as a percentage
 
- 			 * @see {@link https://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser}
 
- 			 */
 
- 			function getConstraintDimension(domNode, maxStyle, percentageProperty) {
 
- 				var view = document.defaultView;
 
- 				var parentNode = helpers$1._getParentNode(domNode);
 
- 				var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
 
- 				var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
 
- 				var hasCNode = isConstrainedValue(constrainedNode);
 
- 				var hasCContainer = isConstrainedValue(constrainedContainer);
 
- 				var infinity = Number.POSITIVE_INFINITY;
 
- 				if (hasCNode || hasCContainer) {
 
- 					return Math.min(
 
- 						hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
 
- 						hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
 
- 				}
 
- 				return 'none';
 
- 			}
 
- 			// returns Number or undefined if no constraint
 
- 			helpers$1.getConstraintWidth = function(domNode) {
 
- 				return getConstraintDimension(domNode, 'max-width', 'clientWidth');
 
- 			};
 
- 			// returns Number or undefined if no constraint
 
- 			helpers$1.getConstraintHeight = function(domNode) {
 
- 				return getConstraintDimension(domNode, 'max-height', 'clientHeight');
 
- 			};
 
- 			/**
 
- 			 * @private
 
- 		 	 */
 
- 			helpers$1._calculatePadding = function(container, padding, parentDimension) {
 
- 				padding = helpers$1.getStyle(container, padding);
 
- 				return padding.indexOf('%') > -1 ? parentDimension * parseInt(padding, 10) / 100 : parseInt(padding, 10);
 
- 			};
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			helpers$1._getParentNode = function(domNode) {
 
- 				var parent = domNode.parentNode;
 
- 				if (parent && parent.toString() === '[object ShadowRoot]') {
 
- 					parent = parent.host;
 
- 				}
 
- 				return parent;
 
- 			};
 
- 			helpers$1.getMaximumWidth = function(domNode) {
 
- 				var container = helpers$1._getParentNode(domNode);
 
- 				if (!container) {
 
- 					return domNode.clientWidth;
 
- 				}
 
- 				var clientWidth = container.clientWidth;
 
- 				var paddingLeft = helpers$1._calculatePadding(container, 'padding-left', clientWidth);
 
- 				var paddingRight = helpers$1._calculatePadding(container, 'padding-right', clientWidth);
 
- 				var w = clientWidth - paddingLeft - paddingRight;
 
- 				var cw = helpers$1.getConstraintWidth(domNode);
 
- 				return isNaN(cw) ? w : Math.min(w, cw);
 
- 			};
 
- 			helpers$1.getMaximumHeight = function(domNode) {
 
- 				var container = helpers$1._getParentNode(domNode);
 
- 				if (!container) {
 
- 					return domNode.clientHeight;
 
- 				}
 
- 				var clientHeight = container.clientHeight;
 
- 				var paddingTop = helpers$1._calculatePadding(container, 'padding-top', clientHeight);
 
- 				var paddingBottom = helpers$1._calculatePadding(container, 'padding-bottom', clientHeight);
 
- 				var h = clientHeight - paddingTop - paddingBottom;
 
- 				var ch = helpers$1.getConstraintHeight(domNode);
 
- 				return isNaN(ch) ? h : Math.min(h, ch);
 
- 			};
 
- 			helpers$1.getStyle = function(el, property) {
 
- 				return el.currentStyle ?
 
- 					el.currentStyle[property] :
 
- 					document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
 
- 			};
 
- 			helpers$1.retinaScale = function(chart, forceRatio) {
 
- 				var pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
 
- 				if (pixelRatio === 1) {
 
- 					return;
 
- 				}
 
- 				var canvas = chart.canvas;
 
- 				var height = chart.height;
 
- 				var width = chart.width;
 
- 				canvas.height = height * pixelRatio;
 
- 				canvas.width = width * pixelRatio;
 
- 				chart.ctx.scale(pixelRatio, pixelRatio);
 
- 				// If no style has been set on the canvas, the render size is used as display size,
 
- 				// making the chart visually bigger, so let's enforce it to the "correct" values.
 
- 				// See https://github.com/chartjs/Chart.js/issues/3575
 
- 				if (!canvas.style.height && !canvas.style.width) {
 
- 					canvas.style.height = height + 'px';
 
- 					canvas.style.width = width + 'px';
 
- 				}
 
- 			};
 
- 			// -- Canvas methods
 
- 			helpers$1.fontString = function(pixelSize, fontStyle, fontFamily) {
 
- 				return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
 
- 			};
 
- 			helpers$1.longestText = function(ctx, font, arrayOfThings, cache) {
 
- 				cache = cache || {};
 
- 				var data = cache.data = cache.data || {};
 
- 				var gc = cache.garbageCollect = cache.garbageCollect || [];
 
- 				if (cache.font !== font) {
 
- 					data = cache.data = {};
 
- 					gc = cache.garbageCollect = [];
 
- 					cache.font = font;
 
- 				}
 
- 				ctx.font = font;
 
- 				var longest = 0;
 
- 				var ilen = arrayOfThings.length;
 
- 				var i, j, jlen, thing, nestedThing;
 
- 				for (i = 0; i < ilen; i++) {
 
- 					thing = arrayOfThings[i];
 
- 					// Undefined strings and arrays should not be measured
 
- 					if (thing !== undefined && thing !== null && helpers$1.isArray(thing) !== true) {
 
- 						longest = helpers$1.measureText(ctx, data, gc, longest, thing);
 
- 					} else if (helpers$1.isArray(thing)) {
 
- 						// if it is an array lets measure each element
 
- 						// to do maybe simplify this function a bit so we can do this more recursively?
 
- 						for (j = 0, jlen = thing.length; j < jlen; j++) {
 
- 							nestedThing = thing[j];
 
- 							// Undefined strings and arrays should not be measured
 
- 							if (nestedThing !== undefined && nestedThing !== null && !helpers$1.isArray(nestedThing)) {
 
- 								longest = helpers$1.measureText(ctx, data, gc, longest, nestedThing);
 
- 							}
 
- 						}
 
- 					}
 
- 				}
 
- 				var gcLen = gc.length / 2;
 
- 				if (gcLen > arrayOfThings.length) {
 
- 					for (i = 0; i < gcLen; i++) {
 
- 						delete data[gc[i]];
 
- 					}
 
- 					gc.splice(0, gcLen);
 
- 				}
 
- 				return longest;
 
- 			};
 
- 			helpers$1.measureText = function(ctx, data, gc, longest, string) {
 
- 				var textWidth = data[string];
 
- 				if (!textWidth) {
 
- 					textWidth = data[string] = ctx.measureText(string).width;
 
- 					gc.push(string);
 
- 				}
 
- 				if (textWidth > longest) {
 
- 					longest = textWidth;
 
- 				}
 
- 				return longest;
 
- 			};
 
- 			/**
 
- 			 * @deprecated
 
- 			 */
 
- 			helpers$1.numberOfLabelLines = function(arrayOfThings) {
 
- 				var numberOfLines = 1;
 
- 				helpers$1.each(arrayOfThings, function(thing) {
 
- 					if (helpers$1.isArray(thing)) {
 
- 						if (thing.length > numberOfLines) {
 
- 							numberOfLines = thing.length;
 
- 						}
 
- 					}
 
- 				});
 
- 				return numberOfLines;
 
- 			};
 
- 			helpers$1.color = !chartjsColor ?
 
- 				function(value) {
 
- 					console.error('Color.js not found!');
 
- 					return value;
 
- 				} :
 
- 				function(value) {
 
- 					/* global CanvasGradient */
 
- 					if (value instanceof CanvasGradient) {
 
- 						value = core_defaults.global.defaultColor;
 
- 					}
 
- 					return chartjsColor(value);
 
- 				};
 
- 			helpers$1.getHoverColor = function(colorValue) {
 
- 				/* global CanvasPattern */
 
- 				return (colorValue instanceof CanvasPattern || colorValue instanceof CanvasGradient) ?
 
- 					colorValue :
 
- 					helpers$1.color(colorValue).saturate(0.5).darken(0.1).rgbString();
 
- 			};
 
- 		};
 
- 		function abstract() {
 
- 			throw new Error(
 
- 				'This method is not implemented: either no adapter can ' +
 
- 				'be found or an incomplete integration was provided.'
 
- 			);
 
- 		}
 
- 		/**
 
- 		 * Date adapter (current used by the time scale)
 
- 		 * @namespace Chart._adapters._date
 
- 		 * @memberof Chart._adapters
 
- 		 * @private
 
- 		 */
 
- 		/**
 
- 		 * Currently supported unit string values.
 
- 		 * @typedef {('millisecond'|'second'|'minute'|'hour'|'day'|'week'|'month'|'quarter'|'year')}
 
- 		 * @memberof Chart._adapters._date
 
- 		 * @name Unit
 
- 		 */
 
- 		/**
 
- 		 * @class
 
- 		 */
 
- 		function DateAdapter(options) {
 
- 			this.options = options || {};
 
- 		}
 
- 		helpers$1.extend(DateAdapter.prototype, /** @lends DateAdapter */ {
 
- 			/**
 
- 			 * Returns a map of time formats for the supported formatting units defined
 
- 			 * in Unit as well as 'datetime' representing a detailed date/time string.
 
- 			 * @returns {{string: string}}
 
- 			 */
 
- 			formats: abstract,
 
- 			/**
 
- 			 * Parses the given `value` and return the associated timestamp.
 
- 			 * @param {any} value - the value to parse (usually comes from the data)
 
- 			 * @param {string} [format] - the expected data format
 
- 			 * @returns {(number|null)}
 
- 			 * @function
 
- 			 */
 
- 			parse: abstract,
 
- 			/**
 
- 			 * Returns the formatted date in the specified `format` for a given `timestamp`.
 
- 			 * @param {number} timestamp - the timestamp to format
 
- 			 * @param {string} format - the date/time token
 
- 			 * @return {string}
 
- 			 * @function
 
- 			 */
 
- 			format: abstract,
 
- 			/**
 
- 			 * Adds the specified `amount` of `unit` to the given `timestamp`.
 
- 			 * @param {number} timestamp - the input timestamp
 
- 			 * @param {number} amount - the amount to add
 
- 			 * @param {Unit} unit - the unit as string
 
- 			 * @return {number}
 
- 			 * @function
 
- 			 */
 
- 			add: abstract,
 
- 			/**
 
- 			 * Returns the number of `unit` between the given timestamps.
 
- 			 * @param {number} max - the input timestamp (reference)
 
- 			 * @param {number} min - the timestamp to substract
 
- 			 * @param {Unit} unit - the unit as string
 
- 			 * @return {number}
 
- 			 * @function
 
- 			 */
 
- 			diff: abstract,
 
- 			/**
 
- 			 * Returns start of `unit` for the given `timestamp`.
 
- 			 * @param {number} timestamp - the input timestamp
 
- 			 * @param {Unit} unit - the unit as string
 
- 			 * @param {number} [weekday] - the ISO day of the week with 1 being Monday
 
- 			 * and 7 being Sunday (only needed if param *unit* is `isoWeek`).
 
- 			 * @function
 
- 			 */
 
- 			startOf: abstract,
 
- 			/**
 
- 			 * Returns end of `unit` for the given `timestamp`.
 
- 			 * @param {number} timestamp - the input timestamp
 
- 			 * @param {Unit} unit - the unit as string
 
- 			 * @function
 
- 			 */
 
- 			endOf: abstract,
 
- 			// DEPRECATIONS
 
- 			/**
 
- 			 * Provided for backward compatibility for scale.getValueForPixel(),
 
- 			 * this method should be overridden only by the moment adapter.
 
- 			 * @deprecated since version 2.8.0
 
- 			 * @todo remove at version 3
 
- 			 * @private
 
- 			 */
 
- 			_create: function(value) {
 
- 				return value;
 
- 			}
 
- 		});
 
- 		DateAdapter.override = function(members) {
 
- 			helpers$1.extend(DateAdapter.prototype, members);
 
- 		};
 
- 		var _date = DateAdapter;
 
- 		var core_adapters = {
 
- 			_date: _date
 
- 		};
 
- 		/**
 
- 		 * Namespace to hold static tick generation functions
 
- 		 * @namespace Chart.Ticks
 
- 		 */
 
- 		var core_ticks = {
 
- 			/**
 
- 			 * Namespace to hold formatters for different types of ticks
 
- 			 * @namespace Chart.Ticks.formatters
 
- 			 */
 
- 			formatters: {
 
- 				/**
 
- 				 * Formatter for value labels
 
- 				 * @method Chart.Ticks.formatters.values
 
- 				 * @param value the value to display
 
- 				 * @return {string|string[]} the label to display
 
- 				 */
 
- 				values: function(value) {
 
- 					return helpers$1.isArray(value) ? value : '' + value;
 
- 				},
 
- 				/**
 
- 				 * Formatter for linear numeric ticks
 
- 				 * @method Chart.Ticks.formatters.linear
 
- 				 * @param tickValue {number} the value to be formatted
 
- 				 * @param index {number} the position of the tickValue parameter in the ticks array
 
- 				 * @param ticks {number[]} the list of ticks being converted
 
- 				 * @return {string} string representation of the tickValue parameter
 
- 				 */
 
- 				linear: function(tickValue, index, ticks) {
 
- 					// If we have lots of ticks, don't use the ones
 
- 					var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
 
- 					// If we have a number like 2.5 as the delta, figure out how many decimal places we need
 
- 					if (Math.abs(delta) > 1) {
 
- 						if (tickValue !== Math.floor(tickValue)) {
 
- 							// not an integer
 
- 							delta = tickValue - Math.floor(tickValue);
 
- 						}
 
- 					}
 
- 					var logDelta = helpers$1.log10(Math.abs(delta));
 
- 					var tickString = '';
 
- 					if (tickValue !== 0) {
 
- 						var maxTick = Math.max(Math.abs(ticks[0]), Math.abs(ticks[ticks.length - 1]));
 
- 						if (maxTick < 1e-4) { // all ticks are small numbers; use scientific notation
 
- 							var logTick = helpers$1.log10(Math.abs(tickValue));
 
- 							var numExponential = Math.floor(logTick) - Math.floor(logDelta);
 
- 							numExponential = Math.max(Math.min(numExponential, 20), 0);
 
- 							tickString = tickValue.toExponential(numExponential);
 
- 						} else {
 
- 							var numDecimal = -1 * Math.floor(logDelta);
 
- 							numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
 
- 							tickString = tickValue.toFixed(numDecimal);
 
- 						}
 
- 					} else {
 
- 						tickString = '0'; // never show decimal places for 0
 
- 					}
 
- 					return tickString;
 
- 				},
 
- 				logarithmic: function(tickValue, index, ticks) {
 
- 					var remain = tickValue / (Math.pow(10, Math.floor(helpers$1.log10(tickValue))));
 
- 					if (tickValue === 0) {
 
- 						return '0';
 
- 					} else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
 
- 						return tickValue.toExponential();
 
- 					}
 
- 					return '';
 
- 				}
 
- 			}
 
- 		};
 
- 		var isArray = helpers$1.isArray;
 
- 		var isNullOrUndef = helpers$1.isNullOrUndef;
 
- 		var valueOrDefault$a = helpers$1.valueOrDefault;
 
- 		var valueAtIndexOrDefault = helpers$1.valueAtIndexOrDefault;
 
- 		core_defaults._set('scale', {
 
- 			display: true,
 
- 			position: 'left',
 
- 			offset: false,
 
- 			// grid line settings
 
- 			gridLines: {
 
- 				display: true,
 
- 				color: 'rgba(0,0,0,0.1)',
 
- 				lineWidth: 1,
 
- 				drawBorder: true,
 
- 				drawOnChartArea: true,
 
- 				drawTicks: true,
 
- 				tickMarkLength: 10,
 
- 				zeroLineWidth: 1,
 
- 				zeroLineColor: 'rgba(0,0,0,0.25)',
 
- 				zeroLineBorderDash: [],
 
- 				zeroLineBorderDashOffset: 0.0,
 
- 				offsetGridLines: false,
 
- 				borderDash: [],
 
- 				borderDashOffset: 0.0
 
- 			},
 
- 			// scale label
 
- 			scaleLabel: {
 
- 				// display property
 
- 				display: false,
 
- 				// actual label
 
- 				labelString: '',
 
- 				// top/bottom padding
 
- 				padding: {
 
- 					top: 4,
 
- 					bottom: 4
 
- 				}
 
- 			},
 
- 			// label settings
 
- 			ticks: {
 
- 				beginAtZero: false,
 
- 				minRotation: 0,
 
- 				maxRotation: 50,
 
- 				mirror: false,
 
- 				padding: 0,
 
- 				reverse: false,
 
- 				display: true,
 
- 				autoSkip: true,
 
- 				autoSkipPadding: 0,
 
- 				labelOffset: 0,
 
- 				// We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
 
- 				callback: core_ticks.formatters.values,
 
- 				minor: {},
 
- 				major: {}
 
- 			}
 
- 		});
 
- 		/** Returns a new array containing numItems from arr */
 
- 		function sample(arr, numItems) {
 
- 			var result = [];
 
- 			var increment = arr.length / numItems;
 
- 			var i = 0;
 
- 			var len = arr.length;
 
- 			for (; i < len; i += increment) {
 
- 				result.push(arr[Math.floor(i)]);
 
- 			}
 
- 			return result;
 
- 		}
 
- 		function getPixelForGridLine(scale, index, offsetGridLines) {
 
- 			var length = scale.getTicks().length;
 
- 			var validIndex = Math.min(index, length - 1);
 
- 			var lineValue = scale.getPixelForTick(validIndex);
 
- 			var start = scale._startPixel;
 
- 			var end = scale._endPixel;
 
- 			var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
 
- 			var 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;
 
- 				// Return undefined if the pixel is out of the range
 
- 				if (lineValue < start - epsilon || lineValue > end + epsilon) {
 
- 					return;
 
- 				}
 
- 			}
 
- 			return lineValue;
 
- 		}
 
- 		function garbageCollect(caches, length) {
 
- 			helpers$1.each(caches, function(cache) {
 
- 				var gc = cache.gc;
 
- 				var gcLen = gc.length / 2;
 
- 				var i;
 
- 				if (gcLen > length) {
 
- 					for (i = 0; i < gcLen; ++i) {
 
- 						delete cache.data[gc[i]];
 
- 					}
 
- 					gc.splice(0, gcLen);
 
- 				}
 
- 			});
 
- 		}
 
- 		/**
 
- 		 * Returns {width, height, offset} objects for the first, last, widest, highest tick
 
- 		 * labels where offset indicates the anchor point offset from the top in pixels.
 
- 		 */
 
- 		function computeLabelSizes(ctx, tickFonts, ticks, caches) {
 
- 			var length = ticks.length;
 
- 			var widths = [];
 
- 			var heights = [];
 
- 			var offsets = [];
 
- 			var widestLabelSize = 0;
 
- 			var highestLabelSize = 0;
 
- 			var i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel, widest, highest;
 
- 			for (i = 0; i < length; ++i) {
 
- 				label = ticks[i].label;
 
- 				tickFont = ticks[i].major ? tickFonts.major : tickFonts.minor;
 
- 				ctx.font = fontString = tickFont.string;
 
- 				cache = caches[fontString] = caches[fontString] || {data: {}, gc: []};
 
- 				lineHeight = tickFont.lineHeight;
 
- 				width = height = 0;
 
- 				// Undefined labels and arrays should not be measured
 
- 				if (!isNullOrUndef(label) && !isArray(label)) {
 
- 					width = helpers$1.measureText(ctx, cache.data, cache.gc, width, label);
 
- 					height = lineHeight;
 
- 				} else if (isArray(label)) {
 
- 					// if it is an array let's measure each element
 
- 					for (j = 0, jlen = label.length; j < jlen; ++j) {
 
- 						nestedLabel = label[j];
 
- 						// Undefined labels and arrays should not be measured
 
- 						if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {
 
- 							width = helpers$1.measureText(ctx, cache.data, cache.gc, width, nestedLabel);
 
- 							height += lineHeight;
 
- 						}
 
- 					}
 
- 				}
 
- 				widths.push(width);
 
- 				heights.push(height);
 
- 				offsets.push(lineHeight / 2);
 
- 				widestLabelSize = Math.max(width, widestLabelSize);
 
- 				highestLabelSize = Math.max(height, highestLabelSize);
 
- 			}
 
- 			garbageCollect(caches, length);
 
- 			widest = widths.indexOf(widestLabelSize);
 
- 			highest = heights.indexOf(highestLabelSize);
 
- 			function valueAt(idx) {
 
- 				return {
 
- 					width: widths[idx] || 0,
 
- 					height: heights[idx] || 0,
 
- 					offset: offsets[idx] || 0
 
- 				};
 
- 			}
 
- 			return {
 
- 				first: valueAt(0),
 
- 				last: valueAt(length - 1),
 
- 				widest: valueAt(widest),
 
- 				highest: valueAt(highest)
 
- 			};
 
- 		}
 
- 		function getTickMarkLength(options) {
 
- 			return options.drawTicks ? options.tickMarkLength : 0;
 
- 		}
 
- 		function getScaleLabelHeight(options) {
 
- 			var font, padding;
 
- 			if (!options.display) {
 
- 				return 0;
 
- 			}
 
- 			font = helpers$1.options._parseFont(options);
 
- 			padding = helpers$1.options.toPadding(options.padding);
 
- 			return font.lineHeight + padding.height;
 
- 		}
 
- 		function parseFontOptions(options, nestedOpts) {
 
- 			return helpers$1.extend(helpers$1.options._parseFont({
 
- 				fontFamily: valueOrDefault$a(nestedOpts.fontFamily, options.fontFamily),
 
- 				fontSize: valueOrDefault$a(nestedOpts.fontSize, options.fontSize),
 
- 				fontStyle: valueOrDefault$a(nestedOpts.fontStyle, options.fontStyle),
 
- 				lineHeight: valueOrDefault$a(nestedOpts.lineHeight, options.lineHeight)
 
- 			}), {
 
- 				color: helpers$1.options.resolve([nestedOpts.fontColor, options.fontColor, core_defaults.global.defaultFontColor])
 
- 			});
 
- 		}
 
- 		function parseTickFontOptions(options) {
 
- 			var minor = parseFontOptions(options, options.minor);
 
- 			var major = options.major.enabled ? parseFontOptions(options, options.major) : minor;
 
- 			return {minor: minor, major: major};
 
- 		}
 
- 		function nonSkipped(ticksToFilter) {
 
- 			var filtered = [];
 
- 			var item, index, len;
 
- 			for (index = 0, len = ticksToFilter.length; index < len; ++index) {
 
- 				item = ticksToFilter[index];
 
- 				if (typeof item._index !== 'undefined') {
 
- 					filtered.push(item);
 
- 				}
 
- 			}
 
- 			return filtered;
 
- 		}
 
- 		function getEvenSpacing(arr) {
 
- 			var len = arr.length;
 
- 			var 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;
 
- 		}
 
- 		function calculateSpacing(majorIndices, ticks, axisLength, ticksLimit) {
 
- 			var evenMajorSpacing = getEvenSpacing(majorIndices);
 
- 			var spacing = (ticks.length - 1) / ticksLimit;
 
- 			var factors, factor, i, ilen;
 
- 			// If the major ticks are evenly spaced apart, place the minor ticks
 
- 			// so that they divide the major ticks into even chunks
 
- 			if (!evenMajorSpacing) {
 
- 				return Math.max(spacing, 1);
 
- 			}
 
- 			factors = helpers$1.math._factorize(evenMajorSpacing);
 
- 			for (i = 0, ilen = factors.length - 1; i < ilen; i++) {
 
- 				factor = factors[i];
 
- 				if (factor > spacing) {
 
- 					return factor;
 
- 				}
 
- 			}
 
- 			return Math.max(spacing, 1);
 
- 		}
 
- 		function getMajorIndices(ticks) {
 
- 			var result = [];
 
- 			var i, ilen;
 
- 			for (i = 0, ilen = ticks.length; i < ilen; i++) {
 
- 				if (ticks[i].major) {
 
- 					result.push(i);
 
- 				}
 
- 			}
 
- 			return result;
 
- 		}
 
- 		function skipMajors(ticks, majorIndices, spacing) {
 
- 			var count = 0;
 
- 			var next = majorIndices[0];
 
- 			var i, tick;
 
- 			spacing = Math.ceil(spacing);
 
- 			for (i = 0; i < ticks.length; i++) {
 
- 				tick = ticks[i];
 
- 				if (i === next) {
 
- 					tick._index = i;
 
- 					count++;
 
- 					next = majorIndices[count * spacing];
 
- 				} else {
 
- 					delete tick.label;
 
- 				}
 
- 			}
 
- 		}
 
- 		function skip(ticks, spacing, majorStart, majorEnd) {
 
- 			var start = valueOrDefault$a(majorStart, 0);
 
- 			var end = Math.min(valueOrDefault$a(majorEnd, ticks.length), ticks.length);
 
- 			var count = 0;
 
- 			var length, i, tick, 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++) {
 
- 				tick = ticks[i];
 
- 				if (i === next) {
 
- 					tick._index = i;
 
- 					count++;
 
- 					next = Math.round(start + count * spacing);
 
- 				} else {
 
- 					delete tick.label;
 
- 				}
 
- 			}
 
- 		}
 
- 		var Scale = core_element.extend({
 
- 			zeroLineIndex: 0,
 
- 			/**
 
- 			 * Get the padding needed for the scale
 
- 			 * @method getPadding
 
- 			 * @private
 
- 			 * @returns {Padding} the necessary padding
 
- 			 */
 
- 			getPadding: function() {
 
- 				var me = this;
 
- 				return {
 
- 					left: me.paddingLeft || 0,
 
- 					top: me.paddingTop || 0,
 
- 					right: me.paddingRight || 0,
 
- 					bottom: me.paddingBottom || 0
 
- 				};
 
- 			},
 
- 			/**
 
- 			 * Returns the scale tick objects ({label, major})
 
- 			 * @since 2.7
 
- 			 */
 
- 			getTicks: function() {
 
- 				return this._ticks;
 
- 			},
 
- 			/**
 
- 			* @private
 
- 			*/
 
- 			_getLabels: function() {
 
- 				var data = this.chart.data;
 
- 				return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
 
- 			},
 
- 			// These methods are ordered by lifecyle. Utilities then follow.
 
- 			// Any function defined here is inherited by all scale types.
 
- 			// Any function can be extended by the scale type
 
- 			/**
 
- 			 * Provided for backward compatibility, not available anymore
 
- 			 * @function Chart.Scale.mergeTicksOptions
 
- 			 * @deprecated since version 2.8.0
 
- 			 * @todo remove at version 3
 
- 			 */
 
- 			mergeTicksOptions: function() {
 
- 				// noop
 
- 			},
 
- 			beforeUpdate: function() {
 
- 				helpers$1.callback(this.options.beforeUpdate, [this]);
 
- 			},
 
- 			/**
 
- 			 * @param {number} maxWidth - the max width in pixels
 
- 			 * @param {number} maxHeight - the max height in pixels
 
- 			 * @param {object} margins - the space between the edge of the other scales and edge of the chart
 
- 			 *   This space comes from two sources:
 
- 			 *     - padding - space that's required to show the labels at the edges of the scale
 
- 			 *     - thickness of scales or legends in another orientation
 
- 			 */
 
- 			update: function(maxWidth, maxHeight, margins) {
 
- 				var me = this;
 
- 				var tickOpts = me.options.ticks;
 
- 				var sampleSize = tickOpts.sampleSize;
 
- 				var i, ilen, labels, ticks, samplingEnabled;
 
- 				// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
 
- 				me.beforeUpdate();
 
- 				// Absorb the master measurements
 
- 				me.maxWidth = maxWidth;
 
- 				me.maxHeight = maxHeight;
 
- 				me.margins = helpers$1.extend({
 
- 					left: 0,
 
- 					right: 0,
 
- 					top: 0,
 
- 					bottom: 0
 
- 				}, margins);
 
- 				me._ticks = null;
 
- 				me.ticks = null;
 
- 				me._labelSizes = null;
 
- 				me._maxLabelLines = 0;
 
- 				me.longestLabelWidth = 0;
 
- 				me.longestTextCache = me.longestTextCache || {};
 
- 				me._gridLineItems = null;
 
- 				me._labelItems = null;
 
- 				// Dimensions
 
- 				me.beforeSetDimensions();
 
- 				me.setDimensions();
 
- 				me.afterSetDimensions();
 
- 				// Data min/max
 
- 				me.beforeDataLimits();
 
- 				me.determineDataLimits();
 
- 				me.afterDataLimits();
 
- 				// Ticks - `this.ticks` is now DEPRECATED!
 
- 				// Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
 
- 				// and must not be accessed directly from outside this class. `this.ticks` being
 
- 				// around for long time and not marked as private, we can't change its structure
 
- 				// without unexpected breaking changes. If you need to access the scale ticks,
 
- 				// use scale.getTicks() instead.
 
- 				me.beforeBuildTicks();
 
- 				// New implementations should return an array of objects but for BACKWARD COMPAT,
 
- 				// we still support no return (`this.ticks` internally set by calling this method).
 
- 				ticks = me.buildTicks() || [];
 
- 				// Allow modification of ticks in callback.
 
- 				ticks = me.afterBuildTicks(ticks) || ticks;
 
- 				// Ensure ticks contains ticks in new tick format
 
- 				if ((!ticks || !ticks.length) && me.ticks) {
 
- 					ticks = [];
 
- 					for (i = 0, ilen = me.ticks.length; i < ilen; ++i) {
 
- 						ticks.push({
 
- 							value: me.ticks[i],
 
- 							major: false
 
- 						});
 
- 					}
 
- 				}
 
- 				me._ticks = ticks;
 
- 				// Compute tick rotation and fit using a sampled subset of labels
 
- 				// We generally don't need to compute the size of every single label for determining scale size
 
- 				samplingEnabled = sampleSize < ticks.length;
 
- 				labels = me._convertTicksToLabels(samplingEnabled ? sample(ticks, sampleSize) : ticks);
 
- 				// _configure is called twice, once here, once from core.controller.updateLayout.
 
- 				// Here we haven't been positioned yet, but dimensions are correct.
 
- 				// Variables set in _configure are needed for calculateTickRotation, and
 
- 				// it's ok that coordinates are not correct there, only dimensions matter.
 
- 				me._configure();
 
- 				// Tick Rotation
 
- 				me.beforeCalculateTickRotation();
 
- 				me.calculateTickRotation();
 
- 				me.afterCalculateTickRotation();
 
- 				me.beforeFit();
 
- 				me.fit();
 
- 				me.afterFit();
 
- 				// Auto-skip
 
- 				me._ticksToDraw = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(ticks) : ticks;
 
- 				if (samplingEnabled) {
 
- 					// Generate labels using all non-skipped ticks
 
- 					labels = me._convertTicksToLabels(me._ticksToDraw);
 
- 				}
 
- 				me.ticks = labels;   // BACKWARD COMPATIBILITY
 
- 				// IMPORTANT: after this point, we consider that `this.ticks` will NEVER change!
 
- 				me.afterUpdate();
 
- 				// TODO(v3): remove minSize as a public property and return value from all layout boxes. It is unused
 
- 				// make maxWidth and maxHeight private
 
- 				return me.minSize;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_configure: function() {
 
- 				var me = this;
 
- 				var reversePixels = me.options.ticks.reverse;
 
- 				var startPixel, endPixel;
 
- 				if (me.isHorizontal()) {
 
- 					startPixel = me.left;
 
- 					endPixel = me.right;
 
- 				} else {
 
- 					startPixel = me.top;
 
- 					endPixel = me.bottom;
 
- 					// by default vertical scales are from bottom to top, so pixels are reversed
 
- 					reversePixels = !reversePixels;
 
- 				}
 
- 				me._startPixel = startPixel;
 
- 				me._endPixel = endPixel;
 
- 				me._reversePixels = reversePixels;
 
- 				me._length = endPixel - startPixel;
 
- 			},
 
- 			afterUpdate: function() {
 
- 				helpers$1.callback(this.options.afterUpdate, [this]);
 
- 			},
 
- 			//
 
- 			beforeSetDimensions: function() {
 
- 				helpers$1.callback(this.options.beforeSetDimensions, [this]);
 
- 			},
 
- 			setDimensions: function() {
 
- 				var me = this;
 
- 				// Set the unconstrained dimension before label rotation
 
- 				if (me.isHorizontal()) {
 
- 					// Reset position before calculating rotation
 
- 					me.width = me.maxWidth;
 
- 					me.left = 0;
 
- 					me.right = me.width;
 
- 				} else {
 
- 					me.height = me.maxHeight;
 
- 					// Reset position before calculating rotation
 
- 					me.top = 0;
 
- 					me.bottom = me.height;
 
- 				}
 
- 				// Reset padding
 
- 				me.paddingLeft = 0;
 
- 				me.paddingTop = 0;
 
- 				me.paddingRight = 0;
 
- 				me.paddingBottom = 0;
 
- 			},
 
- 			afterSetDimensions: function() {
 
- 				helpers$1.callback(this.options.afterSetDimensions, [this]);
 
- 			},
 
- 			// Data limits
 
- 			beforeDataLimits: function() {
 
- 				helpers$1.callback(this.options.beforeDataLimits, [this]);
 
- 			},
 
- 			determineDataLimits: helpers$1.noop,
 
- 			afterDataLimits: function() {
 
- 				helpers$1.callback(this.options.afterDataLimits, [this]);
 
- 			},
 
- 			//
 
- 			beforeBuildTicks: function() {
 
- 				helpers$1.callback(this.options.beforeBuildTicks, [this]);
 
- 			},
 
- 			buildTicks: helpers$1.noop,
 
- 			afterBuildTicks: function(ticks) {
 
- 				var me = this;
 
- 				// ticks is empty for old axis implementations here
 
- 				if (isArray(ticks) && ticks.length) {
 
- 					return helpers$1.callback(me.options.afterBuildTicks, [me, ticks]);
 
- 				}
 
- 				// Support old implementations (that modified `this.ticks` directly in buildTicks)
 
- 				me.ticks = helpers$1.callback(me.options.afterBuildTicks, [me, me.ticks]) || me.ticks;
 
- 				return ticks;
 
- 			},
 
- 			beforeTickToLabelConversion: function() {
 
- 				helpers$1.callback(this.options.beforeTickToLabelConversion, [this]);
 
- 			},
 
- 			convertTicksToLabels: function() {
 
- 				var me = this;
 
- 				// Convert ticks to strings
 
- 				var tickOpts = me.options.ticks;
 
- 				me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
 
- 			},
 
- 			afterTickToLabelConversion: function() {
 
- 				helpers$1.callback(this.options.afterTickToLabelConversion, [this]);
 
- 			},
 
- 			//
 
- 			beforeCalculateTickRotation: function() {
 
- 				helpers$1.callback(this.options.beforeCalculateTickRotation, [this]);
 
- 			},
 
- 			calculateTickRotation: function() {
 
- 				var me = this;
 
- 				var options = me.options;
 
- 				var tickOpts = options.ticks;
 
- 				var numTicks = me.getTicks().length;
 
- 				var minRotation = tickOpts.minRotation || 0;
 
- 				var maxRotation = tickOpts.maxRotation;
 
- 				var labelRotation = minRotation;
 
- 				var labelSizes, maxLabelWidth, maxLabelHeight, maxWidth, tickWidth, maxHeight, maxLabelDiagonal;
 
- 				if (!me._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !me.isHorizontal()) {
 
- 					me.labelRotation = minRotation;
 
- 					return;
 
- 				}
 
- 				labelSizes = me._getLabelSizes();
 
- 				maxLabelWidth = labelSizes.widest.width;
 
- 				maxLabelHeight = labelSizes.highest.height - labelSizes.highest.offset;
 
- 				// Estimate the width of each grid based on the canvas width, the maximum
 
- 				// label width and the number of tick intervals
 
- 				maxWidth = Math.min(me.maxWidth, me.chart.width - maxLabelWidth);
 
- 				tickWidth = options.offset ? me.maxWidth / numTicks : maxWidth / (numTicks - 1);
 
- 				// Allow 3 pixels x2 padding either side for label readability
 
- 				if (maxLabelWidth + 6 > tickWidth) {
 
- 					tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
 
- 					maxHeight = me.maxHeight - getTickMarkLength(options.gridLines)
 
- 						- tickOpts.padding - getScaleLabelHeight(options.scaleLabel);
 
- 					maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
 
- 					labelRotation = helpers$1.toDegrees(Math.min(
 
- 						Math.asin(Math.min((labelSizes.highest.height + 6) / tickWidth, 1)),
 
- 						Math.asin(Math.min(maxHeight / maxLabelDiagonal, 1)) - Math.asin(maxLabelHeight / maxLabelDiagonal)
 
- 					));
 
- 					labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
 
- 				}
 
- 				me.labelRotation = labelRotation;
 
- 			},
 
- 			afterCalculateTickRotation: function() {
 
- 				helpers$1.callback(this.options.afterCalculateTickRotation, [this]);
 
- 			},
 
- 			//
 
- 			beforeFit: function() {
 
- 				helpers$1.callback(this.options.beforeFit, [this]);
 
- 			},
 
- 			fit: function() {
 
- 				var me = this;
 
- 				// Reset
 
- 				var minSize = me.minSize = {
 
- 					width: 0,
 
- 					height: 0
 
- 				};
 
- 				var chart = me.chart;
 
- 				var opts = me.options;
 
- 				var tickOpts = opts.ticks;
 
- 				var scaleLabelOpts = opts.scaleLabel;
 
- 				var gridLineOpts = opts.gridLines;
 
- 				var display = me._isVisible();
 
- 				var isBottom = opts.position === 'bottom';
 
- 				var isHorizontal = me.isHorizontal();
 
- 				// Width
 
- 				if (isHorizontal) {
 
- 					minSize.width = me.maxWidth;
 
- 				} else if (display) {
 
- 					minSize.width = getTickMarkLength(gridLineOpts) + getScaleLabelHeight(scaleLabelOpts);
 
- 				}
 
- 				// height
 
- 				if (!isHorizontal) {
 
- 					minSize.height = me.maxHeight; // fill all the height
 
- 				} else if (display) {
 
- 					minSize.height = getTickMarkLength(gridLineOpts) + getScaleLabelHeight(scaleLabelOpts);
 
- 				}
 
- 				// Don't bother fitting the ticks if we are not showing the labels
 
- 				if (tickOpts.display && display) {
 
- 					var tickFonts = parseTickFontOptions(tickOpts);
 
- 					var labelSizes = me._getLabelSizes();
 
- 					var firstLabelSize = labelSizes.first;
 
- 					var lastLabelSize = labelSizes.last;
 
- 					var widestLabelSize = labelSizes.widest;
 
- 					var highestLabelSize = labelSizes.highest;
 
- 					var lineSpace = tickFonts.minor.lineHeight * 0.4;
 
- 					var tickPadding = tickOpts.padding;
 
- 					if (isHorizontal) {
 
- 						// A horizontal axis is more constrained by the height.
 
- 						var isRotated = me.labelRotation !== 0;
 
- 						var angleRadians = helpers$1.toRadians(me.labelRotation);
 
- 						var cosRotation = Math.cos(angleRadians);
 
- 						var sinRotation = Math.sin(angleRadians);
 
- 						var labelHeight = sinRotation * widestLabelSize.width
 
- 							+ cosRotation * (highestLabelSize.height - (isRotated ? highestLabelSize.offset : 0))
 
- 							+ (isRotated ? 0 : lineSpace); // padding
 
- 						minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
 
- 						var offsetLeft = me.getPixelForTick(0) - me.left;
 
- 						var offsetRight = me.right - me.getPixelForTick(me.getTicks().length - 1);
 
- 						var paddingLeft, paddingRight;
 
- 						// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
 
- 						// which means that the right padding is dominated by the font height
 
- 						if (isRotated) {
 
- 							paddingLeft = isBottom ?
 
- 								cosRotation * firstLabelSize.width + sinRotation * firstLabelSize.offset :
 
- 								sinRotation * (firstLabelSize.height - firstLabelSize.offset);
 
- 							paddingRight = isBottom ?
 
- 								sinRotation * (lastLabelSize.height - lastLabelSize.offset) :
 
- 								cosRotation * lastLabelSize.width + sinRotation * lastLabelSize.offset;
 
- 						} else {
 
- 							paddingLeft = firstLabelSize.width / 2;
 
- 							paddingRight = lastLabelSize.width / 2;
 
- 						}
 
- 						// Adjust padding taking into account changes in offsets
 
- 						// and add 3 px to move away from canvas edges
 
- 						me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3;
 
- 						me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + 3;
 
- 					} else {
 
- 						// A vertical axis is more constrained by the width. Labels are the
 
- 						// dominant factor here, so get that length first and account for padding
 
- 						var labelWidth = tickOpts.mirror ? 0 :
 
- 							// use lineSpace for consistency with horizontal axis
 
- 							// tickPadding is not implemented for horizontal
 
- 							widestLabelSize.width + tickPadding + lineSpace;
 
- 						minSize.width = Math.min(me.maxWidth, minSize.width + labelWidth);
 
- 						me.paddingTop = firstLabelSize.height / 2;
 
- 						me.paddingBottom = lastLabelSize.height / 2;
 
- 					}
 
- 				}
 
- 				me.handleMargins();
 
- 				if (isHorizontal) {
 
- 					me.width = me._length = chart.width - me.margins.left - me.margins.right;
 
- 					me.height = minSize.height;
 
- 				} else {
 
- 					me.width = minSize.width;
 
- 					me.height = me._length = chart.height - me.margins.top - me.margins.bottom;
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Handle margins and padding interactions
 
- 			 * @private
 
- 			 */
 
- 			handleMargins: function() {
 
- 				var me = this;
 
- 				if (me.margins) {
 
- 					me.margins.left = Math.max(me.paddingLeft, me.margins.left);
 
- 					me.margins.top = Math.max(me.paddingTop, me.margins.top);
 
- 					me.margins.right = Math.max(me.paddingRight, me.margins.right);
 
- 					me.margins.bottom = Math.max(me.paddingBottom, me.margins.bottom);
 
- 				}
 
- 			},
 
- 			afterFit: function() {
 
- 				helpers$1.callback(this.options.afterFit, [this]);
 
- 			},
 
- 			// Shared Methods
 
- 			isHorizontal: function() {
 
- 				var pos = this.options.position;
 
- 				return pos === 'top' || pos === 'bottom';
 
- 			},
 
- 			isFullWidth: function() {
 
- 				return this.options.fullWidth;
 
- 			},
 
- 			// Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
 
- 			getRightValue: function(rawValue) {
 
- 				// Null and undefined values first
 
- 				if (isNullOrUndef(rawValue)) {
 
- 					return NaN;
 
- 				}
 
- 				// isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
 
- 				if ((typeof rawValue === 'number' || rawValue instanceof Number) && !isFinite(rawValue)) {
 
- 					return NaN;
 
- 				}
 
- 				// If it is in fact an object, dive in one more level
 
- 				if (rawValue) {
 
- 					if (this.isHorizontal()) {
 
- 						if (rawValue.x !== undefined) {
 
- 							return this.getRightValue(rawValue.x);
 
- 						}
 
- 					} else if (rawValue.y !== undefined) {
 
- 						return this.getRightValue(rawValue.y);
 
- 					}
 
- 				}
 
- 				// Value is good, return it
 
- 				return rawValue;
 
- 			},
 
- 			_convertTicksToLabels: function(ticks) {
 
- 				var me = this;
 
- 				var labels, i, ilen;
 
- 				me.ticks = ticks.map(function(tick) {
 
- 					return tick.value;
 
- 				});
 
- 				me.beforeTickToLabelConversion();
 
- 				// New implementations should return the formatted tick labels but for BACKWARD
 
- 				// COMPAT, we still support no return (`this.ticks` internally changed by calling
 
- 				// this method and supposed to contain only string values).
 
- 				labels = me.convertTicksToLabels(ticks) || me.ticks;
 
- 				me.afterTickToLabelConversion();
 
- 				// BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
 
- 				for (i = 0, ilen = ticks.length; i < ilen; ++i) {
 
- 					ticks[i].label = labels[i];
 
- 				}
 
- 				return labels;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getLabelSizes: function() {
 
- 				var me = this;
 
- 				var labelSizes = me._labelSizes;
 
- 				if (!labelSizes) {
 
- 					me._labelSizes = labelSizes = computeLabelSizes(me.ctx, parseTickFontOptions(me.options.ticks), me.getTicks(), me.longestTextCache);
 
- 					me.longestLabelWidth = labelSizes.widest.width;
 
- 				}
 
- 				return labelSizes;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_parseValue: function(value) {
 
- 				var start, end, min, max;
 
- 				if (isArray(value)) {
 
- 					start = +this.getRightValue(value[0]);
 
- 					end = +this.getRightValue(value[1]);
 
- 					min = Math.min(start, end);
 
- 					max = Math.max(start, end);
 
- 				} else {
 
- 					value = +this.getRightValue(value);
 
- 					start = undefined;
 
- 					end = value;
 
- 					min = value;
 
- 					max = value;
 
- 				}
 
- 				return {
 
- 					min: min,
 
- 					max: max,
 
- 					start: start,
 
- 					end: end
 
- 				};
 
- 			},
 
- 			/**
 
- 			* @private
 
- 			*/
 
- 			_getScaleLabel: function(rawValue) {
 
- 				var v = this._parseValue(rawValue);
 
- 				if (v.start !== undefined) {
 
- 					return '[' + v.start + ', ' + v.end + ']';
 
- 				}
 
- 				return +this.getRightValue(rawValue);
 
- 			},
 
- 			/**
 
- 			 * Used to get the value to display in the tooltip for the data at the given index
 
- 			 * @param index
 
- 			 * @param datasetIndex
 
- 			 */
 
- 			getLabelForIndex: helpers$1.noop,
 
- 			/**
 
- 			 * Returns the location of the given data point. Value can either be an index or a numerical value
 
- 			 * The coordinate (0, 0) is at the upper-left corner of the canvas
 
- 			 * @param value
 
- 			 * @param index
 
- 			 * @param datasetIndex
 
- 			 */
 
- 			getPixelForValue: helpers$1.noop,
 
- 			/**
 
- 			 * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
 
- 			 * The coordinate (0, 0) is at the upper-left corner of the canvas
 
- 			 * @param pixel
 
- 			 */
 
- 			getValueForPixel: helpers$1.noop,
 
- 			/**
 
- 			 * Returns the location of the tick at the given index
 
- 			 * The coordinate (0, 0) is at the upper-left corner of the canvas
 
- 			 */
 
- 			getPixelForTick: function(index) {
 
- 				var me = this;
 
- 				var offset = me.options.offset;
 
- 				var numTicks = me._ticks.length;
 
- 				var tickWidth = 1 / Math.max(numTicks - (offset ? 0 : 1), 1);
 
- 				return index < 0 || index > numTicks - 1
 
- 					? null
 
- 					: me.getPixelForDecimal(index * tickWidth + (offset ? tickWidth / 2 : 0));
 
- 			},
 
- 			/**
 
- 			 * Utility for getting the pixel location of a percentage of scale
 
- 			 * The coordinate (0, 0) is at the upper-left corner of the canvas
 
- 			 */
 
- 			getPixelForDecimal: function(decimal) {
 
- 				var me = this;
 
- 				if (me._reversePixels) {
 
- 					decimal = 1 - decimal;
 
- 				}
 
- 				return me._startPixel + decimal * me._length;
 
- 			},
 
- 			getDecimalForPixel: function(pixel) {
 
- 				var decimal = (pixel - this._startPixel) / this._length;
 
- 				return this._reversePixels ? 1 - decimal : decimal;
 
- 			},
 
- 			/**
 
- 			 * Returns the pixel for the minimum chart value
 
- 			 * The coordinate (0, 0) is at the upper-left corner of the canvas
 
- 			 */
 
- 			getBasePixel: function() {
 
- 				return this.getPixelForValue(this.getBaseValue());
 
- 			},
 
- 			getBaseValue: function() {
 
- 				var me = this;
 
- 				var min = me.min;
 
- 				var max = me.max;
 
- 				return me.beginAtZero ? 0 :
 
- 					min < 0 && max < 0 ? max :
 
- 					min > 0 && max > 0 ? min :
 
- 					0;
 
- 			},
 
- 			/**
 
- 			 * Returns a subset of ticks to be plotted to avoid overlapping labels.
 
- 			 * @private
 
- 			 */
 
- 			_autoSkip: function(ticks) {
 
- 				var me = this;
 
- 				var tickOpts = me.options.ticks;
 
- 				var axisLength = me._length;
 
- 				var ticksLimit = tickOpts.maxTicksLimit || axisLength / me._tickSize() + 1;
 
- 				var majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
 
- 				var numMajorIndices = majorIndices.length;
 
- 				var first = majorIndices[0];
 
- 				var last = majorIndices[numMajorIndices - 1];
 
- 				var i, ilen, spacing, avgMajorSpacing;
 
- 				// If there are too many major ticks to display them all
 
- 				if (numMajorIndices > ticksLimit) {
 
- 					skipMajors(ticks, majorIndices, numMajorIndices / ticksLimit);
 
- 					return nonSkipped(ticks);
 
- 				}
 
- 				spacing = calculateSpacing(majorIndices, ticks, axisLength, ticksLimit);
 
- 				if (numMajorIndices > 0) {
 
- 					for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
 
- 						skip(ticks, spacing, majorIndices[i], majorIndices[i + 1]);
 
- 					}
 
- 					avgMajorSpacing = numMajorIndices > 1 ? (last - first) / (numMajorIndices - 1) : null;
 
- 					skip(ticks, spacing, helpers$1.isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
 
- 					skip(ticks, spacing, last, helpers$1.isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
 
- 					return nonSkipped(ticks);
 
- 				}
 
- 				skip(ticks, spacing);
 
- 				return nonSkipped(ticks);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_tickSize: function() {
 
- 				var me = this;
 
- 				var optionTicks = me.options.ticks;
 
- 				// Calculate space needed by label in axis direction.
 
- 				var rot = helpers$1.toRadians(me.labelRotation);
 
- 				var cos = Math.abs(Math.cos(rot));
 
- 				var sin = Math.abs(Math.sin(rot));
 
- 				var labelSizes = me._getLabelSizes();
 
- 				var padding = optionTicks.autoSkipPadding || 0;
 
- 				var w = labelSizes ? labelSizes.widest.width + padding : 0;
 
- 				var h = labelSizes ? labelSizes.highest.height + padding : 0;
 
- 				// Calculate space needed for 1 tick in axis direction.
 
- 				return me.isHorizontal()
 
- 					? h * cos > w * sin ? w / cos : h / sin
 
- 					: h * sin < w * cos ? h / cos : w / sin;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_isVisible: function() {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var display = me.options.display;
 
- 				var i, ilen, meta;
 
- 				if (display !== 'auto') {
 
- 					return !!display;
 
- 				}
 
- 				// When 'auto', the scale is visible if at least one associated dataset is visible.
 
- 				for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
 
- 					if (chart.isDatasetVisible(i)) {
 
- 						meta = chart.getDatasetMeta(i);
 
- 						if (meta.xAxisID === me.id || meta.yAxisID === me.id) {
 
- 							return true;
 
- 						}
 
- 					}
 
- 				}
 
- 				return false;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_computeGridLineItems: function(chartArea) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var options = me.options;
 
- 				var gridLines = options.gridLines;
 
- 				var position = options.position;
 
- 				var offsetGridLines = gridLines.offsetGridLines;
 
- 				var isHorizontal = me.isHorizontal();
 
- 				var ticks = me._ticksToDraw;
 
- 				var ticksLength = ticks.length + (offsetGridLines ? 1 : 0);
 
- 				var tl = getTickMarkLength(gridLines);
 
- 				var items = [];
 
- 				var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
 
- 				var axisHalfWidth = axisWidth / 2;
 
- 				var alignPixel = helpers$1._alignPixel;
 
- 				var alignBorderValue = function(pixel) {
 
- 					return alignPixel(chart, pixel, axisWidth);
 
- 				};
 
- 				var borderValue, i, tick, lineValue, alignedLineValue;
 
- 				var tx1, ty1, tx2, ty2, x1, y1, x2, y2, lineWidth, lineColor, borderDash, borderDashOffset;
 
- 				if (position === 'top') {
 
- 					borderValue = alignBorderValue(me.bottom);
 
- 					ty1 = me.bottom - tl;
 
- 					ty2 = borderValue - axisHalfWidth;
 
- 					y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
 
- 					y2 = chartArea.bottom;
 
- 				} else if (position === 'bottom') {
 
- 					borderValue = alignBorderValue(me.top);
 
- 					y1 = chartArea.top;
 
- 					y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
 
- 					ty1 = borderValue + axisHalfWidth;
 
- 					ty2 = me.top + tl;
 
- 				} else if (position === 'left') {
 
- 					borderValue = alignBorderValue(me.right);
 
- 					tx1 = me.right - tl;
 
- 					tx2 = borderValue - axisHalfWidth;
 
- 					x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
 
- 					x2 = chartArea.right;
 
- 				} else {
 
- 					borderValue = alignBorderValue(me.left);
 
- 					x1 = chartArea.left;
 
- 					x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
 
- 					tx1 = borderValue + axisHalfWidth;
 
- 					tx2 = me.left + tl;
 
- 				}
 
- 				for (i = 0; i < ticksLength; ++i) {
 
- 					tick = ticks[i] || {};
 
- 					// autoskipper skipped this tick (#4635)
 
- 					if (isNullOrUndef(tick.label) && i < ticks.length) {
 
- 						continue;
 
- 					}
 
- 					if (i === me.zeroLineIndex && options.offset === offsetGridLines) {
 
- 						// Draw the first index specially
 
- 						lineWidth = gridLines.zeroLineWidth;
 
- 						lineColor = gridLines.zeroLineColor;
 
- 						borderDash = gridLines.zeroLineBorderDash || [];
 
- 						borderDashOffset = gridLines.zeroLineBorderDashOffset || 0.0;
 
- 					} else {
 
- 						lineWidth = valueAtIndexOrDefault(gridLines.lineWidth, i, 1);
 
- 						lineColor = valueAtIndexOrDefault(gridLines.color, i, 'rgba(0,0,0,0.1)');
 
- 						borderDash = gridLines.borderDash || [];
 
- 						borderDashOffset = gridLines.borderDashOffset || 0.0;
 
- 					}
 
- 					lineValue = getPixelForGridLine(me, tick._index || i, offsetGridLines);
 
- 					// Skip if the pixel is out of the range
 
- 					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: tx1,
 
- 						ty1: ty1,
 
- 						tx2: tx2,
 
- 						ty2: ty2,
 
- 						x1: x1,
 
- 						y1: y1,
 
- 						x2: x2,
 
- 						y2: y2,
 
- 						width: lineWidth,
 
- 						color: lineColor,
 
- 						borderDash: borderDash,
 
- 						borderDashOffset: borderDashOffset,
 
- 					});
 
- 				}
 
- 				items.ticksLength = ticksLength;
 
- 				items.borderValue = borderValue;
 
- 				return items;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_computeLabelItems: function() {
 
- 				var me = this;
 
- 				var options = me.options;
 
- 				var optionTicks = options.ticks;
 
- 				var position = options.position;
 
- 				var isMirrored = optionTicks.mirror;
 
- 				var isHorizontal = me.isHorizontal();
 
- 				var ticks = me._ticksToDraw;
 
- 				var fonts = parseTickFontOptions(optionTicks);
 
- 				var tickPadding = optionTicks.padding;
 
- 				var tl = getTickMarkLength(options.gridLines);
 
- 				var rotation = -helpers$1.toRadians(me.labelRotation);
 
- 				var items = [];
 
- 				var i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
 
- 				if (position === 'top') {
 
- 					y = me.bottom - tl - tickPadding;
 
- 					textAlign = !rotation ? 'center' : 'left';
 
- 				} else if (position === 'bottom') {
 
- 					y = me.top + tl + tickPadding;
 
- 					textAlign = !rotation ? 'center' : 'right';
 
- 				} else if (position === 'left') {
 
- 					x = me.right - (isMirrored ? 0 : tl) - tickPadding;
 
- 					textAlign = isMirrored ? 'left' : 'right';
 
- 				} else {
 
- 					x = me.left + (isMirrored ? 0 : tl) + tickPadding;
 
- 					textAlign = isMirrored ? 'right' : 'left';
 
- 				}
 
- 				for (i = 0, ilen = ticks.length; i < ilen; ++i) {
 
- 					tick = ticks[i];
 
- 					label = tick.label;
 
- 					// autoskipper skipped this tick (#4635)
 
- 					if (isNullOrUndef(label)) {
 
- 						continue;
 
- 					}
 
- 					pixel = me.getPixelForTick(tick._index || i) + optionTicks.labelOffset;
 
- 					font = tick.major ? fonts.major : fonts.minor;
 
- 					lineHeight = font.lineHeight;
 
- 					lineCount = isArray(label) ? label.length : 1;
 
- 					if (isHorizontal) {
 
- 						x = pixel;
 
- 						textOffset = position === 'top'
 
- 							? ((!rotation ? 0.5 : 1) - lineCount) * lineHeight
 
- 							: (!rotation ? 0.5 : 0) * lineHeight;
 
- 					} else {
 
- 						y = pixel;
 
- 						textOffset = (1 - lineCount) * lineHeight / 2;
 
- 					}
 
- 					items.push({
 
- 						x: x,
 
- 						y: y,
 
- 						rotation: rotation,
 
- 						label: label,
 
- 						font: font,
 
- 						textOffset: textOffset,
 
- 						textAlign: textAlign
 
- 					});
 
- 				}
 
- 				return items;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_drawGrid: function(chartArea) {
 
- 				var me = this;
 
- 				var gridLines = me.options.gridLines;
 
- 				if (!gridLines.display) {
 
- 					return;
 
- 				}
 
- 				var ctx = me.ctx;
 
- 				var chart = me.chart;
 
- 				var alignPixel = helpers$1._alignPixel;
 
- 				var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
 
- 				var items = me._gridLineItems || (me._gridLineItems = me._computeGridLineItems(chartArea));
 
- 				var width, color, i, ilen, item;
 
- 				for (i = 0, ilen = items.length; i < ilen; ++i) {
 
- 					item = items[i];
 
- 					width = item.width;
 
- 					color = item.color;
 
- 					if (width && color) {
 
- 						ctx.save();
 
- 						ctx.lineWidth = width;
 
- 						ctx.strokeStyle = color;
 
- 						if (ctx.setLineDash) {
 
- 							ctx.setLineDash(item.borderDash);
 
- 							ctx.lineDashOffset = item.borderDashOffset;
 
- 						}
 
- 						ctx.beginPath();
 
- 						if (gridLines.drawTicks) {
 
- 							ctx.moveTo(item.tx1, item.ty1);
 
- 							ctx.lineTo(item.tx2, item.ty2);
 
- 						}
 
- 						if (gridLines.drawOnChartArea) {
 
- 							ctx.moveTo(item.x1, item.y1);
 
- 							ctx.lineTo(item.x2, item.y2);
 
- 						}
 
- 						ctx.stroke();
 
- 						ctx.restore();
 
- 					}
 
- 				}
 
- 				if (axisWidth) {
 
- 					// Draw the line at the edge of the axis
 
- 					var firstLineWidth = axisWidth;
 
- 					var lastLineWidth = valueAtIndexOrDefault(gridLines.lineWidth, items.ticksLength - 1, 1);
 
- 					var borderValue = items.borderValue;
 
- 					var x1, x2, y1, y2;
 
- 					if (me.isHorizontal()) {
 
- 						x1 = alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;
 
- 						x2 = alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;
 
- 						y1 = y2 = borderValue;
 
- 					} else {
 
- 						y1 = alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;
 
- 						y2 = alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;
 
- 						x1 = x2 = borderValue;
 
- 					}
 
- 					ctx.lineWidth = axisWidth;
 
- 					ctx.strokeStyle = valueAtIndexOrDefault(gridLines.color, 0);
 
- 					ctx.beginPath();
 
- 					ctx.moveTo(x1, y1);
 
- 					ctx.lineTo(x2, y2);
 
- 					ctx.stroke();
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_drawLabels: function() {
 
- 				var me = this;
 
- 				var optionTicks = me.options.ticks;
 
- 				if (!optionTicks.display) {
 
- 					return;
 
- 				}
 
- 				var ctx = me.ctx;
 
- 				var items = me._labelItems || (me._labelItems = me._computeLabelItems());
 
- 				var i, j, ilen, jlen, item, tickFont, label, y;
 
- 				for (i = 0, ilen = items.length; i < ilen; ++i) {
 
- 					item = items[i];
 
- 					tickFont = item.font;
 
- 					// Make sure we draw text in the correct color and font
 
- 					ctx.save();
 
- 					ctx.translate(item.x, item.y);
 
- 					ctx.rotate(item.rotation);
 
- 					ctx.font = tickFont.string;
 
- 					ctx.fillStyle = tickFont.color;
 
- 					ctx.textBaseline = 'middle';
 
- 					ctx.textAlign = item.textAlign;
 
- 					label = item.label;
 
- 					y = item.textOffset;
 
- 					if (isArray(label)) {
 
- 						for (j = 0, jlen = label.length; j < jlen; ++j) {
 
- 							// We just make sure the multiline element is a string here..
 
- 							ctx.fillText('' + label[j], 0, y);
 
- 							y += tickFont.lineHeight;
 
- 						}
 
- 					} else {
 
- 						ctx.fillText(label, 0, y);
 
- 					}
 
- 					ctx.restore();
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_drawTitle: function() {
 
- 				var me = this;
 
- 				var ctx = me.ctx;
 
- 				var options = me.options;
 
- 				var scaleLabel = options.scaleLabel;
 
- 				if (!scaleLabel.display) {
 
- 					return;
 
- 				}
 
- 				var scaleLabelFontColor = valueOrDefault$a(scaleLabel.fontColor, core_defaults.global.defaultFontColor);
 
- 				var scaleLabelFont = helpers$1.options._parseFont(scaleLabel);
 
- 				var scaleLabelPadding = helpers$1.options.toPadding(scaleLabel.padding);
 
- 				var halfLineHeight = scaleLabelFont.lineHeight / 2;
 
- 				var position = options.position;
 
- 				var rotation = 0;
 
- 				var scaleLabelX, scaleLabelY;
 
- 				if (me.isHorizontal()) {
 
- 					scaleLabelX = me.left + me.width / 2; // midpoint of the width
 
- 					scaleLabelY = position === 'bottom'
 
- 						? me.bottom - halfLineHeight - scaleLabelPadding.bottom
 
- 						: me.top + halfLineHeight + scaleLabelPadding.top;
 
- 				} else {
 
- 					var isLeft = position === 'left';
 
- 					scaleLabelX = isLeft
 
- 						? me.left + halfLineHeight + scaleLabelPadding.top
 
- 						: me.right - halfLineHeight - scaleLabelPadding.top;
 
- 					scaleLabelY = me.top + me.height / 2;
 
- 					rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
 
- 				}
 
- 				ctx.save();
 
- 				ctx.translate(scaleLabelX, scaleLabelY);
 
- 				ctx.rotate(rotation);
 
- 				ctx.textAlign = 'center';
 
- 				ctx.textBaseline = 'middle';
 
- 				ctx.fillStyle = scaleLabelFontColor; // render in correct colour
 
- 				ctx.font = scaleLabelFont.string;
 
- 				ctx.fillText(scaleLabel.labelString, 0, 0);
 
- 				ctx.restore();
 
- 			},
 
- 			draw: function(chartArea) {
 
- 				var me = this;
 
- 				if (!me._isVisible()) {
 
- 					return;
 
- 				}
 
- 				me._drawGrid(chartArea);
 
- 				me._drawTitle();
 
- 				me._drawLabels();
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_layers: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var tz = opts.ticks && opts.ticks.z || 0;
 
- 				var gz = opts.gridLines && opts.gridLines.z || 0;
 
- 				if (!me._isVisible() || tz === gz || me.draw !== me._draw) {
 
- 					// backward compatibility: draw has been overridden by custom scale
 
- 					return [{
 
- 						z: tz,
 
- 						draw: function() {
 
- 							me.draw.apply(me, arguments);
 
- 						}
 
- 					}];
 
- 				}
 
- 				return [{
 
- 					z: gz,
 
- 					draw: function() {
 
- 						me._drawGrid.apply(me, arguments);
 
- 						me._drawTitle.apply(me, arguments);
 
- 					}
 
- 				}, {
 
- 					z: tz,
 
- 					draw: function() {
 
- 						me._drawLabels.apply(me, arguments);
 
- 					}
 
- 				}];
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getMatchingVisibleMetas: function(type) {
 
- 				var me = this;
 
- 				var isHorizontal = me.isHorizontal();
 
- 				return me.chart._getSortedVisibleDatasetMetas()
 
- 					.filter(function(meta) {
 
- 						return (!type || meta.type === type)
 
- 							&& (isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id);
 
- 					});
 
- 			}
 
- 		});
 
- 		Scale.prototype._draw = Scale.prototype.draw;
 
- 		var core_scale = Scale;
 
- 		var isNullOrUndef$1 = helpers$1.isNullOrUndef;
 
- 		var defaultConfig = {
 
- 			position: 'bottom'
 
- 		};
 
- 		var scale_category = core_scale.extend({
 
- 			determineDataLimits: function() {
 
- 				var me = this;
 
- 				var labels = me._getLabels();
 
- 				var ticksOpts = me.options.ticks;
 
- 				var min = ticksOpts.min;
 
- 				var max = ticksOpts.max;
 
- 				var minIndex = 0;
 
- 				var maxIndex = labels.length - 1;
 
- 				var findIndex;
 
- 				if (min !== undefined) {
 
- 					// user specified min value
 
- 					findIndex = labels.indexOf(min);
 
- 					if (findIndex >= 0) {
 
- 						minIndex = findIndex;
 
- 					}
 
- 				}
 
- 				if (max !== undefined) {
 
- 					// user specified max value
 
- 					findIndex = labels.indexOf(max);
 
- 					if (findIndex >= 0) {
 
- 						maxIndex = findIndex;
 
- 					}
 
- 				}
 
- 				me.minIndex = minIndex;
 
- 				me.maxIndex = maxIndex;
 
- 				me.min = labels[minIndex];
 
- 				me.max = labels[maxIndex];
 
- 			},
 
- 			buildTicks: function() {
 
- 				var me = this;
 
- 				var labels = me._getLabels();
 
- 				var minIndex = me.minIndex;
 
- 				var maxIndex = me.maxIndex;
 
- 				// If we are viewing some subset of labels, slice the original array
 
- 				me.ticks = (minIndex === 0 && maxIndex === labels.length - 1) ? labels : labels.slice(minIndex, maxIndex + 1);
 
- 			},
 
- 			getLabelForIndex: function(index, datasetIndex) {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				if (chart.getDatasetMeta(datasetIndex).controller._getValueScaleId() === me.id) {
 
- 					return me.getRightValue(chart.data.datasets[datasetIndex].data[index]);
 
- 				}
 
- 				return me._getLabels()[index];
 
- 			},
 
- 			_configure: function() {
 
- 				var me = this;
 
- 				var offset = me.options.offset;
 
- 				var ticks = me.ticks;
 
- 				core_scale.prototype._configure.call(me);
 
- 				if (!me.isHorizontal()) {
 
- 					// For backward compatibility, vertical category scale reverse is inverted.
 
- 					me._reversePixels = !me._reversePixels;
 
- 				}
 
- 				if (!ticks) {
 
- 					return;
 
- 				}
 
- 				me._startValue = me.minIndex - (offset ? 0.5 : 0);
 
- 				me._valueRange = Math.max(ticks.length - (offset ? 0 : 1), 1);
 
- 			},
 
- 			// Used to get data value locations.  Value can either be an index or a numerical value
 
- 			getPixelForValue: function(value, index, datasetIndex) {
 
- 				var me = this;
 
- 				var valueCategory, labels, idx;
 
- 				if (!isNullOrUndef$1(index) && !isNullOrUndef$1(datasetIndex)) {
 
- 					value = me.chart.data.datasets[datasetIndex].data[index];
 
- 				}
 
- 				// If value is a data object, then index is the index in the data array,
 
- 				// not the index of the scale. We need to change that.
 
- 				if (!isNullOrUndef$1(value)) {
 
- 					valueCategory = me.isHorizontal() ? value.x : value.y;
 
- 				}
 
- 				if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
 
- 					labels = me._getLabels();
 
- 					value = helpers$1.valueOrDefault(valueCategory, value);
 
- 					idx = labels.indexOf(value);
 
- 					index = idx !== -1 ? idx : index;
 
- 					if (isNaN(index)) {
 
- 						index = value;
 
- 					}
 
- 				}
 
- 				return me.getPixelForDecimal((index - me._startValue) / me._valueRange);
 
- 			},
 
- 			getPixelForTick: function(index) {
 
- 				var ticks = this.ticks;
 
- 				return index < 0 || index > ticks.length - 1
 
- 					? null
 
- 					: this.getPixelForValue(ticks[index], index + this.minIndex);
 
- 			},
 
- 			getValueForPixel: function(pixel) {
 
- 				var me = this;
 
- 				var value = Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange);
 
- 				return Math.min(Math.max(value, 0), me.ticks.length - 1);
 
- 			},
 
- 			getBasePixel: function() {
 
- 				return this.bottom;
 
- 			}
 
- 		});
 
- 		// INTERNAL: static default options, registered in src/index.js
 
- 		var _defaults = defaultConfig;
 
- 		scale_category._defaults = _defaults;
 
- 		var noop = helpers$1.noop;
 
- 		var isNullOrUndef$2 = helpers$1.isNullOrUndef;
 
- 		/**
 
- 		 * Generate a set of linear ticks
 
- 		 * @param generationOptions the options used to generate the ticks
 
- 		 * @param dataRange the range of the data
 
- 		 * @returns {number[]} array of tick values
 
- 		 */
 
- 		function generateTicks(generationOptions, dataRange) {
 
- 			var ticks = [];
 
- 			// To get a "nice" value for the tick spacing, we will use the appropriately named
 
- 			// "nice number" algorithm. See https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
 
- 			// for details.
 
- 			var MIN_SPACING = 1e-14;
 
- 			var stepSize = generationOptions.stepSize;
 
- 			var unit = stepSize || 1;
 
- 			var maxNumSpaces = generationOptions.maxTicks - 1;
 
- 			var min = generationOptions.min;
 
- 			var max = generationOptions.max;
 
- 			var precision = generationOptions.precision;
 
- 			var rmin = dataRange.min;
 
- 			var rmax = dataRange.max;
 
- 			var spacing = helpers$1.niceNum((rmax - rmin) / maxNumSpaces / unit) * unit;
 
- 			var factor, niceMin, niceMax, numSpaces;
 
- 			// Beyond MIN_SPACING floating point numbers being to lose precision
 
- 			// such that we can't do the math necessary to generate ticks
 
- 			if (spacing < MIN_SPACING && isNullOrUndef$2(min) && isNullOrUndef$2(max)) {
 
- 				return [rmin, rmax];
 
- 			}
 
- 			numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
 
- 			if (numSpaces > maxNumSpaces) {
 
- 				// If the calculated num of spaces exceeds maxNumSpaces, recalculate it
 
- 				spacing = helpers$1.niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit;
 
- 			}
 
- 			if (stepSize || isNullOrUndef$2(precision)) {
 
- 				// If a precision is not specified, calculate factor based on spacing
 
- 				factor = Math.pow(10, helpers$1._decimalPlaces(spacing));
 
- 			} else {
 
- 				// If the user specified a precision, round to that number of decimal places
 
- 				factor = Math.pow(10, precision);
 
- 				spacing = Math.ceil(spacing * factor) / factor;
 
- 			}
 
- 			niceMin = Math.floor(rmin / spacing) * spacing;
 
- 			niceMax = Math.ceil(rmax / spacing) * spacing;
 
- 			// If min, max and stepSize is set and they make an evenly spaced scale use it.
 
- 			if (stepSize) {
 
- 				// If very close to our whole number, use it.
 
- 				if (!isNullOrUndef$2(min) && helpers$1.almostWhole(min / spacing, spacing / 1000)) {
 
- 					niceMin = min;
 
- 				}
 
- 				if (!isNullOrUndef$2(max) && helpers$1.almostWhole(max / spacing, spacing / 1000)) {
 
- 					niceMax = max;
 
- 				}
 
- 			}
 
- 			numSpaces = (niceMax - niceMin) / spacing;
 
- 			// If very close to our rounded value, use it.
 
- 			if (helpers$1.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
 
- 				numSpaces = Math.round(numSpaces);
 
- 			} else {
 
- 				numSpaces = Math.ceil(numSpaces);
 
- 			}
 
- 			niceMin = Math.round(niceMin * factor) / factor;
 
- 			niceMax = Math.round(niceMax * factor) / factor;
 
- 			ticks.push(isNullOrUndef$2(min) ? niceMin : min);
 
- 			for (var j = 1; j < numSpaces; ++j) {
 
- 				ticks.push(Math.round((niceMin + j * spacing) * factor) / factor);
 
- 			}
 
- 			ticks.push(isNullOrUndef$2(max) ? niceMax : max);
 
- 			return ticks;
 
- 		}
 
- 		var scale_linearbase = core_scale.extend({
 
- 			getRightValue: function(value) {
 
- 				if (typeof value === 'string') {
 
- 					return +value;
 
- 				}
 
- 				return core_scale.prototype.getRightValue.call(this, value);
 
- 			},
 
- 			handleTickRangeOptions: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var tickOpts = opts.ticks;
 
- 				// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
 
- 				// do nothing since that would make the chart weird. If the user really wants a weird chart
 
- 				// axis, they can manually override it
 
- 				if (tickOpts.beginAtZero) {
 
- 					var minSign = helpers$1.sign(me.min);
 
- 					var maxSign = helpers$1.sign(me.max);
 
- 					if (minSign < 0 && maxSign < 0) {
 
- 						// move the top up to 0
 
- 						me.max = 0;
 
- 					} else if (minSign > 0 && maxSign > 0) {
 
- 						// move the bottom down to 0
 
- 						me.min = 0;
 
- 					}
 
- 				}
 
- 				var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;
 
- 				var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;
 
- 				if (tickOpts.min !== undefined) {
 
- 					me.min = tickOpts.min;
 
- 				} else if (tickOpts.suggestedMin !== undefined) {
 
- 					if (me.min === null) {
 
- 						me.min = tickOpts.suggestedMin;
 
- 					} else {
 
- 						me.min = Math.min(me.min, tickOpts.suggestedMin);
 
- 					}
 
- 				}
 
- 				if (tickOpts.max !== undefined) {
 
- 					me.max = tickOpts.max;
 
- 				} else if (tickOpts.suggestedMax !== undefined) {
 
- 					if (me.max === null) {
 
- 						me.max = tickOpts.suggestedMax;
 
- 					} else {
 
- 						me.max = Math.max(me.max, tickOpts.suggestedMax);
 
- 					}
 
- 				}
 
- 				if (setMin !== setMax) {
 
- 					// We set the min or the max but not both.
 
- 					// So ensure that our range is good
 
- 					// Inverted or 0 length range can happen when
 
- 					// ticks.min is set, and no datasets are visible
 
- 					if (me.min >= me.max) {
 
- 						if (setMin) {
 
- 							me.max = me.min + 1;
 
- 						} else {
 
- 							me.min = me.max - 1;
 
- 						}
 
- 					}
 
- 				}
 
- 				if (me.min === me.max) {
 
- 					me.max++;
 
- 					if (!tickOpts.beginAtZero) {
 
- 						me.min--;
 
- 					}
 
- 				}
 
- 			},
 
- 			getTickLimit: function() {
 
- 				var me = this;
 
- 				var tickOpts = me.options.ticks;
 
- 				var stepSize = tickOpts.stepSize;
 
- 				var maxTicksLimit = tickOpts.maxTicksLimit;
 
- 				var maxTicks;
 
- 				if (stepSize) {
 
- 					maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1;
 
- 				} else {
 
- 					maxTicks = me._computeTickLimit();
 
- 					maxTicksLimit = maxTicksLimit || 11;
 
- 				}
 
- 				if (maxTicksLimit) {
 
- 					maxTicks = Math.min(maxTicksLimit, maxTicks);
 
- 				}
 
- 				return maxTicks;
 
- 			},
 
- 			_computeTickLimit: function() {
 
- 				return Number.POSITIVE_INFINITY;
 
- 			},
 
- 			handleDirectionalChanges: noop,
 
- 			buildTicks: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var tickOpts = opts.ticks;
 
- 				// Figure out what the max number of ticks we can support it is based on the size of
 
- 				// the axis area. For now, we say that the minimum tick spacing in pixels must be 40
 
- 				// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
 
- 				// the graph. Make sure we always have at least 2 ticks
 
- 				var maxTicks = me.getTickLimit();
 
- 				maxTicks = Math.max(2, maxTicks);
 
- 				var numericGeneratorOptions = {
 
- 					maxTicks: maxTicks,
 
- 					min: tickOpts.min,
 
- 					max: tickOpts.max,
 
- 					precision: tickOpts.precision,
 
- 					stepSize: helpers$1.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
 
- 				};
 
- 				var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);
 
- 				me.handleDirectionalChanges();
 
- 				// At this point, we need to update our max and min given the tick values since we have expanded the
 
- 				// range of the scale
 
- 				me.max = helpers$1.max(ticks);
 
- 				me.min = helpers$1.min(ticks);
 
- 				if (tickOpts.reverse) {
 
- 					ticks.reverse();
 
- 					me.start = me.max;
 
- 					me.end = me.min;
 
- 				} else {
 
- 					me.start = me.min;
 
- 					me.end = me.max;
 
- 				}
 
- 			},
 
- 			convertTicksToLabels: function() {
 
- 				var me = this;
 
- 				me.ticksAsNumbers = me.ticks.slice();
 
- 				me.zeroLineIndex = me.ticks.indexOf(0);
 
- 				core_scale.prototype.convertTicksToLabels.call(me);
 
- 			},
 
- 			_configure: function() {
 
- 				var me = this;
 
- 				var ticks = me.getTicks();
 
- 				var start = me.min;
 
- 				var end = me.max;
 
- 				var offset;
 
- 				core_scale.prototype._configure.call(me);
 
- 				if (me.options.offset && ticks.length) {
 
- 					offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
 
- 					start -= offset;
 
- 					end += offset;
 
- 				}
 
- 				me._startValue = start;
 
- 				me._endValue = end;
 
- 				me._valueRange = end - start;
 
- 			}
 
- 		});
 
- 		var defaultConfig$1 = {
 
- 			position: 'left',
 
- 			ticks: {
 
- 				callback: core_ticks.formatters.linear
 
- 			}
 
- 		};
 
- 		var DEFAULT_MIN = 0;
 
- 		var DEFAULT_MAX = 1;
 
- 		function getOrCreateStack(stacks, stacked, meta) {
 
- 			var key = [
 
- 				meta.type,
 
- 				// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
 
- 				stacked === undefined && meta.stack === undefined ? meta.index : '',
 
- 				meta.stack
 
- 			].join('.');
 
- 			if (stacks[key] === undefined) {
 
- 				stacks[key] = {
 
- 					pos: [],
 
- 					neg: []
 
- 				};
 
- 			}
 
- 			return stacks[key];
 
- 		}
 
- 		function stackData(scale, stacks, meta, data) {
 
- 			var opts = scale.options;
 
- 			var stacked = opts.stacked;
 
- 			var stack = getOrCreateStack(stacks, stacked, meta);
 
- 			var pos = stack.pos;
 
- 			var neg = stack.neg;
 
- 			var ilen = data.length;
 
- 			var i, value;
 
- 			for (i = 0; i < ilen; ++i) {
 
- 				value = scale._parseValue(data[i]);
 
- 				if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
 
- 					continue;
 
- 				}
 
- 				pos[i] = pos[i] || 0;
 
- 				neg[i] = neg[i] || 0;
 
- 				if (opts.relativePoints) {
 
- 					pos[i] = 100;
 
- 				} else if (value.min < 0 || value.max < 0) {
 
- 					neg[i] += value.min;
 
- 				} else {
 
- 					pos[i] += value.max;
 
- 				}
 
- 			}
 
- 		}
 
- 		function updateMinMax(scale, meta, data) {
 
- 			var ilen = data.length;
 
- 			var i, value;
 
- 			for (i = 0; i < ilen; ++i) {
 
- 				value = scale._parseValue(data[i]);
 
- 				if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {
 
- 					continue;
 
- 				}
 
- 				scale.min = Math.min(scale.min, value.min);
 
- 				scale.max = Math.max(scale.max, value.max);
 
- 			}
 
- 		}
 
- 		var scale_linear = scale_linearbase.extend({
 
- 			determineDataLimits: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var chart = me.chart;
 
- 				var datasets = chart.data.datasets;
 
- 				var metasets = me._getMatchingVisibleMetas();
 
- 				var hasStacks = opts.stacked;
 
- 				var stacks = {};
 
- 				var ilen = metasets.length;
 
- 				var i, meta, data, values;
 
- 				me.min = Number.POSITIVE_INFINITY;
 
- 				me.max = Number.NEGATIVE_INFINITY;
 
- 				if (hasStacks === undefined) {
 
- 					for (i = 0; !hasStacks && i < ilen; ++i) {
 
- 						meta = metasets[i];
 
- 						hasStacks = meta.stack !== undefined;
 
- 					}
 
- 				}
 
- 				for (i = 0; i < ilen; ++i) {
 
- 					meta = metasets[i];
 
- 					data = datasets[meta.index].data;
 
- 					if (hasStacks) {
 
- 						stackData(me, stacks, meta, data);
 
- 					} else {
 
- 						updateMinMax(me, meta, data);
 
- 					}
 
- 				}
 
- 				helpers$1.each(stacks, function(stackValues) {
 
- 					values = stackValues.pos.concat(stackValues.neg);
 
- 					me.min = Math.min(me.min, helpers$1.min(values));
 
- 					me.max = Math.max(me.max, helpers$1.max(values));
 
- 				});
 
- 				me.min = helpers$1.isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
 
- 				me.max = helpers$1.isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;
 
- 				// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
 
- 				me.handleTickRangeOptions();
 
- 			},
 
- 			// Returns the maximum number of ticks based on the scale dimension
 
- 			_computeTickLimit: function() {
 
- 				var me = this;
 
- 				var tickFont;
 
- 				if (me.isHorizontal()) {
 
- 					return Math.ceil(me.width / 40);
 
- 				}
 
- 				tickFont = helpers$1.options._parseFont(me.options.ticks);
 
- 				return Math.ceil(me.height / tickFont.lineHeight);
 
- 			},
 
- 			// Called after the ticks are built. We need
 
- 			handleDirectionalChanges: function() {
 
- 				if (!this.isHorizontal()) {
 
- 					// We are in a vertical orientation. The top value is the highest. So reverse the array
 
- 					this.ticks.reverse();
 
- 				}
 
- 			},
 
- 			getLabelForIndex: function(index, datasetIndex) {
 
- 				return this._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]);
 
- 			},
 
- 			// Utils
 
- 			getPixelForValue: function(value) {
 
- 				var me = this;
 
- 				return me.getPixelForDecimal((+me.getRightValue(value) - me._startValue) / me._valueRange);
 
- 			},
 
- 			getValueForPixel: function(pixel) {
 
- 				return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
 
- 			},
 
- 			getPixelForTick: function(index) {
 
- 				var ticks = this.ticksAsNumbers;
 
- 				if (index < 0 || index > ticks.length - 1) {
 
- 					return null;
 
- 				}
 
- 				return this.getPixelForValue(ticks[index]);
 
- 			}
 
- 		});
 
- 		// INTERNAL: static default options, registered in src/index.js
 
- 		var _defaults$1 = defaultConfig$1;
 
- 		scale_linear._defaults = _defaults$1;
 
- 		var valueOrDefault$b = helpers$1.valueOrDefault;
 
- 		var log10 = helpers$1.math.log10;
 
- 		/**
 
- 		 * Generate a set of logarithmic ticks
 
- 		 * @param generationOptions the options used to generate the ticks
 
- 		 * @param dataRange the range of the data
 
- 		 * @returns {number[]} array of tick values
 
- 		 */
 
- 		function generateTicks$1(generationOptions, dataRange) {
 
- 			var ticks = [];
 
- 			var tickVal = valueOrDefault$b(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));
 
- 			var endExp = Math.floor(log10(dataRange.max));
 
- 			var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
 
- 			var exp, significand;
 
- 			if (tickVal === 0) {
 
- 				exp = Math.floor(log10(dataRange.minNotZero));
 
- 				significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
 
- 				ticks.push(tickVal);
 
- 				tickVal = significand * Math.pow(10, exp);
 
- 			} else {
 
- 				exp = Math.floor(log10(tickVal));
 
- 				significand = Math.floor(tickVal / Math.pow(10, exp));
 
- 			}
 
- 			var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
 
- 			do {
 
- 				ticks.push(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));
 
- 			var lastTick = valueOrDefault$b(generationOptions.max, tickVal);
 
- 			ticks.push(lastTick);
 
- 			return ticks;
 
- 		}
 
- 		var defaultConfig$2 = {
 
- 			position: 'left',
 
- 			// label settings
 
- 			ticks: {
 
- 				callback: core_ticks.formatters.logarithmic
 
- 			}
 
- 		};
 
- 		// TODO(v3): change this to positiveOrDefault
 
- 		function nonNegativeOrDefault(value, defaultValue) {
 
- 			return helpers$1.isFinite(value) && value >= 0 ? value : defaultValue;
 
- 		}
 
- 		var scale_logarithmic = core_scale.extend({
 
- 			determineDataLimits: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var chart = me.chart;
 
- 				var datasets = chart.data.datasets;
 
- 				var isHorizontal = me.isHorizontal();
 
- 				function IDMatches(meta) {
 
- 					return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
 
- 				}
 
- 				var datasetIndex, meta, value, data, i, ilen;
 
- 				// Calculate Range
 
- 				me.min = Number.POSITIVE_INFINITY;
 
- 				me.max = Number.NEGATIVE_INFINITY;
 
- 				me.minNotZero = Number.POSITIVE_INFINITY;
 
- 				var hasStacks = opts.stacked;
 
- 				if (hasStacks === undefined) {
 
- 					for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
 
- 						meta = chart.getDatasetMeta(datasetIndex);
 
- 						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
 
- 							meta.stack !== undefined) {
 
- 							hasStacks = true;
 
- 							break;
 
- 						}
 
- 					}
 
- 				}
 
- 				if (opts.stacked || hasStacks) {
 
- 					var valuesPerStack = {};
 
- 					for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
 
- 						meta = chart.getDatasetMeta(datasetIndex);
 
- 						var key = [
 
- 							meta.type,
 
- 							// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
 
- 							((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
 
- 							meta.stack
 
- 						].join('.');
 
- 						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
 
- 							if (valuesPerStack[key] === undefined) {
 
- 								valuesPerStack[key] = [];
 
- 							}
 
- 							data = datasets[datasetIndex].data;
 
- 							for (i = 0, ilen = data.length; i < ilen; i++) {
 
- 								var values = valuesPerStack[key];
 
- 								value = me._parseValue(data[i]);
 
- 								// invalid, hidden and negative values are ignored
 
- 								if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden || value.min < 0 || value.max < 0) {
 
- 									continue;
 
- 								}
 
- 								values[i] = values[i] || 0;
 
- 								values[i] += value.max;
 
- 							}
 
- 						}
 
- 					}
 
- 					helpers$1.each(valuesPerStack, function(valuesForType) {
 
- 						if (valuesForType.length > 0) {
 
- 							var minVal = helpers$1.min(valuesForType);
 
- 							var maxVal = helpers$1.max(valuesForType);
 
- 							me.min = Math.min(me.min, minVal);
 
- 							me.max = Math.max(me.max, maxVal);
 
- 						}
 
- 					});
 
- 				} else {
 
- 					for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
 
- 						meta = chart.getDatasetMeta(datasetIndex);
 
- 						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
 
- 							data = datasets[datasetIndex].data;
 
- 							for (i = 0, ilen = data.length; i < ilen; i++) {
 
- 								value = me._parseValue(data[i]);
 
- 								// invalid, hidden and negative values are ignored
 
- 								if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden || value.min < 0 || value.max < 0) {
 
- 									continue;
 
- 								}
 
- 								me.min = Math.min(value.min, me.min);
 
- 								me.max = Math.max(value.max, me.max);
 
- 								if (value.min !== 0) {
 
- 									me.minNotZero = Math.min(value.min, me.minNotZero);
 
- 								}
 
- 							}
 
- 						}
 
- 					}
 
- 				}
 
- 				me.min = helpers$1.isFinite(me.min) ? me.min : null;
 
- 				me.max = helpers$1.isFinite(me.max) ? me.max : null;
 
- 				me.minNotZero = helpers$1.isFinite(me.minNotZero) ? me.minNotZero : null;
 
- 				// Common base implementation to handle ticks.min, ticks.max
 
- 				this.handleTickRangeOptions();
 
- 			},
 
- 			handleTickRangeOptions: function() {
 
- 				var me = this;
 
- 				var tickOpts = me.options.ticks;
 
- 				var DEFAULT_MIN = 1;
 
- 				var DEFAULT_MAX = 10;
 
- 				me.min = nonNegativeOrDefault(tickOpts.min, me.min);
 
- 				me.max = nonNegativeOrDefault(tickOpts.max, me.max);
 
- 				if (me.min === me.max) {
 
- 					if (me.min !== 0 && me.min !== null) {
 
- 						me.min = Math.pow(10, Math.floor(log10(me.min)) - 1);
 
- 						me.max = Math.pow(10, Math.floor(log10(me.max)) + 1);
 
- 					} else {
 
- 						me.min = DEFAULT_MIN;
 
- 						me.max = DEFAULT_MAX;
 
- 					}
 
- 				}
 
- 				if (me.min === null) {
 
- 					me.min = Math.pow(10, Math.floor(log10(me.max)) - 1);
 
- 				}
 
- 				if (me.max === null) {
 
- 					me.max = me.min !== 0
 
- 						? Math.pow(10, Math.floor(log10(me.min)) + 1)
 
- 						: DEFAULT_MAX;
 
- 				}
 
- 				if (me.minNotZero === null) {
 
- 					if (me.min > 0) {
 
- 						me.minNotZero = me.min;
 
- 					} else if (me.max < 1) {
 
- 						me.minNotZero = Math.pow(10, Math.floor(log10(me.max)));
 
- 					} else {
 
- 						me.minNotZero = DEFAULT_MIN;
 
- 					}
 
- 				}
 
- 			},
 
- 			buildTicks: function() {
 
- 				var me = this;
 
- 				var tickOpts = me.options.ticks;
 
- 				var reverse = !me.isHorizontal();
 
- 				var generationOptions = {
 
- 					min: nonNegativeOrDefault(tickOpts.min),
 
- 					max: nonNegativeOrDefault(tickOpts.max)
 
- 				};
 
- 				var ticks = me.ticks = generateTicks$1(generationOptions, me);
 
- 				// At this point, we need to update our max and min given the tick values since we have expanded the
 
- 				// range of the scale
 
- 				me.max = helpers$1.max(ticks);
 
- 				me.min = helpers$1.min(ticks);
 
- 				if (tickOpts.reverse) {
 
- 					reverse = !reverse;
 
- 					me.start = me.max;
 
- 					me.end = me.min;
 
- 				} else {
 
- 					me.start = me.min;
 
- 					me.end = me.max;
 
- 				}
 
- 				if (reverse) {
 
- 					ticks.reverse();
 
- 				}
 
- 			},
 
- 			convertTicksToLabels: function() {
 
- 				this.tickValues = this.ticks.slice();
 
- 				core_scale.prototype.convertTicksToLabels.call(this);
 
- 			},
 
- 			// Get the correct tooltip label
 
- 			getLabelForIndex: function(index, datasetIndex) {
 
- 				return this._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]);
 
- 			},
 
- 			getPixelForTick: function(index) {
 
- 				var ticks = this.tickValues;
 
- 				if (index < 0 || index > ticks.length - 1) {
 
- 					return null;
 
- 				}
 
- 				return this.getPixelForValue(ticks[index]);
 
- 			},
 
- 			/**
 
- 			 * Returns the value of the first tick.
 
- 			 * @param {number} value - The minimum not zero value.
 
- 			 * @return {number} The first tick value.
 
- 			 * @private
 
- 			 */
 
- 			_getFirstTickValue: function(value) {
 
- 				var exp = Math.floor(log10(value));
 
- 				var significand = Math.floor(value / Math.pow(10, exp));
 
- 				return significand * Math.pow(10, exp);
 
- 			},
 
- 			_configure: function() {
 
- 				var me = this;
 
- 				var start = me.min;
 
- 				var offset = 0;
 
- 				core_scale.prototype._configure.call(me);
 
- 				if (start === 0) {
 
- 					start = me._getFirstTickValue(me.minNotZero);
 
- 					offset = valueOrDefault$b(me.options.ticks.fontSize, core_defaults.global.defaultFontSize) / me._length;
 
- 				}
 
- 				me._startValue = log10(start);
 
- 				me._valueOffset = offset;
 
- 				me._valueRange = (log10(me.max) - log10(start)) / (1 - offset);
 
- 			},
 
- 			getPixelForValue: function(value) {
 
- 				var me = this;
 
- 				var decimal = 0;
 
- 				value = +me.getRightValue(value);
 
- 				if (value > me.min && value > 0) {
 
- 					decimal = (log10(value) - me._startValue) / me._valueRange + me._valueOffset;
 
- 				}
 
- 				return me.getPixelForDecimal(decimal);
 
- 			},
 
- 			getValueForPixel: function(pixel) {
 
- 				var me = this;
 
- 				var decimal = me.getDecimalForPixel(pixel);
 
- 				return decimal === 0 && me.min === 0
 
- 					? 0
 
- 					: Math.pow(10, me._startValue + (decimal - me._valueOffset) * me._valueRange);
 
- 			}
 
- 		});
 
- 		// INTERNAL: static default options, registered in src/index.js
 
- 		var _defaults$2 = defaultConfig$2;
 
- 		scale_logarithmic._defaults = _defaults$2;
 
- 		var valueOrDefault$c = helpers$1.valueOrDefault;
 
- 		var valueAtIndexOrDefault$1 = helpers$1.valueAtIndexOrDefault;
 
- 		var resolve$4 = helpers$1.options.resolve;
 
- 		var defaultConfig$3 = {
 
- 			display: true,
 
- 			// Boolean - Whether to animate scaling the chart from the centre
 
- 			animate: true,
 
- 			position: 'chartArea',
 
- 			angleLines: {
 
- 				display: true,
 
- 				color: 'rgba(0,0,0,0.1)',
 
- 				lineWidth: 1,
 
- 				borderDash: [],
 
- 				borderDashOffset: 0.0
 
- 			},
 
- 			gridLines: {
 
- 				circular: false
 
- 			},
 
- 			// label settings
 
- 			ticks: {
 
- 				// Boolean - Show a backdrop to the scale label
 
- 				showLabelBackdrop: true,
 
- 				// String - The colour of the label backdrop
 
- 				backdropColor: 'rgba(255,255,255,0.75)',
 
- 				// Number - The backdrop padding above & below the label in pixels
 
- 				backdropPaddingY: 2,
 
- 				// Number - The backdrop padding to the side of the label in pixels
 
- 				backdropPaddingX: 2,
 
- 				callback: core_ticks.formatters.linear
 
- 			},
 
- 			pointLabels: {
 
- 				// Boolean - if true, show point labels
 
- 				display: true,
 
- 				// Number - Point label font size in pixels
 
- 				fontSize: 10,
 
- 				// Function - Used to convert point labels
 
- 				callback: function(label) {
 
- 					return label;
 
- 				}
 
- 			}
 
- 		};
 
- 		function getTickBackdropHeight(opts) {
 
- 			var tickOpts = opts.ticks;
 
- 			if (tickOpts.display && opts.display) {
 
- 				return valueOrDefault$c(tickOpts.fontSize, core_defaults.global.defaultFontSize) + tickOpts.backdropPaddingY * 2;
 
- 			}
 
- 			return 0;
 
- 		}
 
- 		function measureLabelSize(ctx, lineHeight, label) {
 
- 			if (helpers$1.isArray(label)) {
 
- 				return {
 
- 					w: helpers$1.longestText(ctx, ctx.font, label),
 
- 					h: label.length * lineHeight
 
- 				};
 
- 			}
 
- 			return {
 
- 				w: ctx.measureText(label).width,
 
- 				h: 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
 
- 			};
 
- 		}
 
- 		/**
 
- 		 * Helper function to fit a radial linear scale with point labels
 
- 		 */
 
- 		function fitWithPointLabels(scale) {
 
- 			// Right, this is really confusing and there is a lot of maths going on here
 
- 			// The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
 
- 			//
 
- 			// Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
 
- 			//
 
- 			// Solution:
 
- 			//
 
- 			// We assume the radius of the polygon is half the size of the canvas at first
 
- 			// at each index we check if the text overlaps.
 
- 			//
 
- 			// Where it does, we store that angle and that index.
 
- 			//
 
- 			// After finding the largest index and angle we calculate how much we need to remove
 
- 			// from the shape radius to move the point inwards by that x.
 
- 			//
 
- 			// We average the left and right distances to get the maximum shape radius that can fit in the box
 
- 			// along with labels.
 
- 			//
 
- 			// Once we have that, we can find the centre point for the chart, by taking the x text protrusion
 
- 			// on each side, removing that from the size, halving it and adding the left x protrusion width.
 
- 			//
 
- 			// This will mean we have a shape fitted to the canvas, as large as it can be with the labels
 
- 			// and position it in the most space efficient manner
 
- 			//
 
- 			// https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
 
- 			var plFont = helpers$1.options._parseFont(scale.options.pointLabels);
 
- 			// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
 
- 			// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
 
- 			var furthestLimits = {
 
- 				l: 0,
 
- 				r: scale.width,
 
- 				t: 0,
 
- 				b: scale.height - scale.paddingTop
 
- 			};
 
- 			var furthestAngles = {};
 
- 			var i, textSize, pointPosition;
 
- 			scale.ctx.font = plFont.string;
 
- 			scale._pointLabelSizes = [];
 
- 			var valueCount = scale.chart.data.labels.length;
 
- 			for (i = 0; i < valueCount; i++) {
 
- 				pointPosition = scale.getPointPosition(i, scale.drawingArea + 5);
 
- 				textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i]);
 
- 				scale._pointLabelSizes[i] = textSize;
 
- 				// Add quarter circle to make degree 0 mean top of circle
 
- 				var angleRadians = scale.getIndexAngle(i);
 
- 				var angle = helpers$1.toDegrees(angleRadians) % 360;
 
- 				var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
 
- 				var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
 
- 				if (hLimits.start < furthestLimits.l) {
 
- 					furthestLimits.l = hLimits.start;
 
- 					furthestAngles.l = angleRadians;
 
- 				}
 
- 				if (hLimits.end > furthestLimits.r) {
 
- 					furthestLimits.r = hLimits.end;
 
- 					furthestAngles.r = angleRadians;
 
- 				}
 
- 				if (vLimits.start < furthestLimits.t) {
 
- 					furthestLimits.t = vLimits.start;
 
- 					furthestAngles.t = angleRadians;
 
- 				}
 
- 				if (vLimits.end > furthestLimits.b) {
 
- 					furthestLimits.b = vLimits.end;
 
- 					furthestAngles.b = angleRadians;
 
- 				}
 
- 			}
 
- 			scale.setReductions(scale.drawingArea, furthestLimits, furthestAngles);
 
- 		}
 
- 		function getTextAlignForAngle(angle) {
 
- 			if (angle === 0 || angle === 180) {
 
- 				return 'center';
 
- 			} else if (angle < 180) {
 
- 				return 'left';
 
- 			}
 
- 			return 'right';
 
- 		}
 
- 		function fillText(ctx, text, position, lineHeight) {
 
- 			var y = position.y + lineHeight / 2;
 
- 			var i, ilen;
 
- 			if (helpers$1.isArray(text)) {
 
- 				for (i = 0, ilen = text.length; i < ilen; ++i) {
 
- 					ctx.fillText(text[i], position.x, y);
 
- 					y += lineHeight;
 
- 				}
 
- 			} else {
 
- 				ctx.fillText(text, position.x, y);
 
- 			}
 
- 		}
 
- 		function adjustPointPositionForLabelHeight(angle, textSize, position) {
 
- 			if (angle === 90 || angle === 270) {
 
- 				position.y -= (textSize.h / 2);
 
- 			} else if (angle > 270 || angle < 90) {
 
- 				position.y -= textSize.h;
 
- 			}
 
- 		}
 
- 		function drawPointLabels(scale) {
 
- 			var ctx = scale.ctx;
 
- 			var opts = scale.options;
 
- 			var pointLabelOpts = opts.pointLabels;
 
- 			var tickBackdropHeight = getTickBackdropHeight(opts);
 
- 			var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
 
- 			var plFont = helpers$1.options._parseFont(pointLabelOpts);
 
- 			ctx.save();
 
- 			ctx.font = plFont.string;
 
- 			ctx.textBaseline = 'middle';
 
- 			for (var i = scale.chart.data.labels.length - 1; i >= 0; i--) {
 
- 				// Extra pixels out for some label spacing
 
- 				var extra = (i === 0 ? tickBackdropHeight / 2 : 0);
 
- 				var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
 
- 				// Keep this in loop since we may support array properties here
 
- 				var pointLabelFontColor = valueAtIndexOrDefault$1(pointLabelOpts.fontColor, i, core_defaults.global.defaultFontColor);
 
- 				ctx.fillStyle = pointLabelFontColor;
 
- 				var angleRadians = scale.getIndexAngle(i);
 
- 				var angle = helpers$1.toDegrees(angleRadians);
 
- 				ctx.textAlign = getTextAlignForAngle(angle);
 
- 				adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
 
- 				fillText(ctx, scale.pointLabels[i], pointLabelPosition, plFont.lineHeight);
 
- 			}
 
- 			ctx.restore();
 
- 		}
 
- 		function drawRadiusLine(scale, gridLineOpts, radius, index) {
 
- 			var ctx = scale.ctx;
 
- 			var circular = gridLineOpts.circular;
 
- 			var valueCount = scale.chart.data.labels.length;
 
- 			var lineColor = valueAtIndexOrDefault$1(gridLineOpts.color, index - 1);
 
- 			var lineWidth = valueAtIndexOrDefault$1(gridLineOpts.lineWidth, index - 1);
 
- 			var pointPosition;
 
- 			if ((!circular && !valueCount) || !lineColor || !lineWidth) {
 
- 				return;
 
- 			}
 
- 			ctx.save();
 
- 			ctx.strokeStyle = lineColor;
 
- 			ctx.lineWidth = lineWidth;
 
- 			if (ctx.setLineDash) {
 
- 				ctx.setLineDash(gridLineOpts.borderDash || []);
 
- 				ctx.lineDashOffset = gridLineOpts.borderDashOffset || 0.0;
 
- 			}
 
- 			ctx.beginPath();
 
- 			if (circular) {
 
- 				// Draw circular arcs between the points
 
- 				ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
 
- 			} else {
 
- 				// Draw straight lines connecting each index
 
- 				pointPosition = scale.getPointPosition(0, radius);
 
- 				ctx.moveTo(pointPosition.x, pointPosition.y);
 
- 				for (var i = 1; i < valueCount; i++) {
 
- 					pointPosition = scale.getPointPosition(i, radius);
 
- 					ctx.lineTo(pointPosition.x, pointPosition.y);
 
- 				}
 
- 			}
 
- 			ctx.closePath();
 
- 			ctx.stroke();
 
- 			ctx.restore();
 
- 		}
 
- 		function numberOrZero(param) {
 
- 			return helpers$1.isNumber(param) ? param : 0;
 
- 		}
 
- 		var scale_radialLinear = scale_linearbase.extend({
 
- 			setDimensions: function() {
 
- 				var me = this;
 
- 				// Set the unconstrained dimension before label rotation
 
- 				me.width = me.maxWidth;
 
- 				me.height = me.maxHeight;
 
- 				me.paddingTop = getTickBackdropHeight(me.options) / 2;
 
- 				me.xCenter = Math.floor(me.width / 2);
 
- 				me.yCenter = Math.floor((me.height - me.paddingTop) / 2);
 
- 				me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2;
 
- 			},
 
- 			determineDataLimits: function() {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var min = Number.POSITIVE_INFINITY;
 
- 				var max = Number.NEGATIVE_INFINITY;
 
- 				helpers$1.each(chart.data.datasets, function(dataset, datasetIndex) {
 
- 					if (chart.isDatasetVisible(datasetIndex)) {
 
- 						var meta = chart.getDatasetMeta(datasetIndex);
 
- 						helpers$1.each(dataset.data, function(rawValue, index) {
 
- 							var value = +me.getRightValue(rawValue);
 
- 							if (isNaN(value) || meta.data[index].hidden) {
 
- 								return;
 
- 							}
 
- 							min = Math.min(value, min);
 
- 							max = Math.max(value, max);
 
- 						});
 
- 					}
 
- 				});
 
- 				me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
 
- 				me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
 
- 				// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
 
- 				me.handleTickRangeOptions();
 
- 			},
 
- 			// Returns the maximum number of ticks based on the scale dimension
 
- 			_computeTickLimit: function() {
 
- 				return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
 
- 			},
 
- 			convertTicksToLabels: function() {
 
- 				var me = this;
 
- 				scale_linearbase.prototype.convertTicksToLabels.call(me);
 
- 				// Point labels
 
- 				me.pointLabels = me.chart.data.labels.map(function() {
 
- 					var label = helpers$1.callback(me.options.pointLabels.callback, arguments, me);
 
- 					return label || label === 0 ? label : '';
 
- 				});
 
- 			},
 
- 			getLabelForIndex: function(index, datasetIndex) {
 
- 				return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
 
- 			},
 
- 			fit: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				if (opts.display && opts.pointLabels.display) {
 
- 					fitWithPointLabels(me);
 
- 				} else {
 
- 					me.setCenterPoint(0, 0, 0, 0);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * Set radius reductions and determine new radius and center point
 
- 			 * @private
 
- 			 */
 
- 			setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
 
- 				var me = this;
 
- 				var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
 
- 				var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
 
- 				var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
 
- 				var radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b);
 
- 				radiusReductionLeft = numberOrZero(radiusReductionLeft);
 
- 				radiusReductionRight = numberOrZero(radiusReductionRight);
 
- 				radiusReductionTop = numberOrZero(radiusReductionTop);
 
- 				radiusReductionBottom = numberOrZero(radiusReductionBottom);
 
- 				me.drawingArea = Math.min(
 
- 					Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
 
- 					Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
 
- 				me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
 
- 			},
 
- 			setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
 
- 				var me = this;
 
- 				var maxRight = me.width - rightMovement - me.drawingArea;
 
- 				var maxLeft = leftMovement + me.drawingArea;
 
- 				var maxTop = topMovement + me.drawingArea;
 
- 				var maxBottom = (me.height - me.paddingTop) - bottomMovement - me.drawingArea;
 
- 				me.xCenter = Math.floor(((maxLeft + maxRight) / 2) + me.left);
 
- 				me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top + me.paddingTop);
 
- 			},
 
- 			getIndexAngle: function(index) {
 
- 				var chart = this.chart;
 
- 				var angleMultiplier = 360 / chart.data.labels.length;
 
- 				var options = chart.options || {};
 
- 				var startAngle = options.startAngle || 0;
 
- 				// Start from the top instead of right, so remove a quarter of the circle
 
- 				var angle = (index * angleMultiplier + startAngle) % 360;
 
- 				return (angle < 0 ? angle + 360 : angle) * Math.PI * 2 / 360;
 
- 			},
 
- 			getDistanceFromCenterForValue: function(value) {
 
- 				var me = this;
 
- 				if (helpers$1.isNullOrUndef(value)) {
 
- 					return NaN;
 
- 				}
 
- 				// Take into account half font size + the yPadding of the top value
 
- 				var scalingFactor = me.drawingArea / (me.max - me.min);
 
- 				if (me.options.ticks.reverse) {
 
- 					return (me.max - value) * scalingFactor;
 
- 				}
 
- 				return (value - me.min) * scalingFactor;
 
- 			},
 
- 			getPointPosition: function(index, distanceFromCenter) {
 
- 				var me = this;
 
- 				var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
 
- 				return {
 
- 					x: Math.cos(thisAngle) * distanceFromCenter + me.xCenter,
 
- 					y: Math.sin(thisAngle) * distanceFromCenter + me.yCenter
 
- 				};
 
- 			},
 
- 			getPointPositionForValue: function(index, value) {
 
- 				return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
 
- 			},
 
- 			getBasePosition: function(index) {
 
- 				var me = this;
 
- 				var min = me.min;
 
- 				var max = me.max;
 
- 				return me.getPointPositionForValue(index || 0,
 
- 					me.beginAtZero ? 0 :
 
- 					min < 0 && max < 0 ? max :
 
- 					min > 0 && max > 0 ? min :
 
- 					0);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_drawGrid: function() {
 
- 				var me = this;
 
- 				var ctx = me.ctx;
 
- 				var opts = me.options;
 
- 				var gridLineOpts = opts.gridLines;
 
- 				var angleLineOpts = opts.angleLines;
 
- 				var lineWidth = valueOrDefault$c(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
 
- 				var lineColor = valueOrDefault$c(angleLineOpts.color, gridLineOpts.color);
 
- 				var i, offset, position;
 
- 				if (opts.pointLabels.display) {
 
- 					drawPointLabels(me);
 
- 				}
 
- 				if (gridLineOpts.display) {
 
- 					helpers$1.each(me.ticks, function(label, index) {
 
- 						if (index !== 0) {
 
- 							offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
 
- 							drawRadiusLine(me, gridLineOpts, offset, index);
 
- 						}
 
- 					});
 
- 				}
 
- 				if (angleLineOpts.display && lineWidth && lineColor) {
 
- 					ctx.save();
 
- 					ctx.lineWidth = lineWidth;
 
- 					ctx.strokeStyle = lineColor;
 
- 					if (ctx.setLineDash) {
 
- 						ctx.setLineDash(resolve$4([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));
 
- 						ctx.lineDashOffset = resolve$4([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);
 
- 					}
 
- 					for (i = me.chart.data.labels.length - 1; i >= 0; i--) {
 
- 						offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max);
 
- 						position = me.getPointPosition(i, offset);
 
- 						ctx.beginPath();
 
- 						ctx.moveTo(me.xCenter, me.yCenter);
 
- 						ctx.lineTo(position.x, position.y);
 
- 						ctx.stroke();
 
- 					}
 
- 					ctx.restore();
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_drawLabels: function() {
 
- 				var me = this;
 
- 				var ctx = me.ctx;
 
- 				var opts = me.options;
 
- 				var tickOpts = opts.ticks;
 
- 				if (!tickOpts.display) {
 
- 					return;
 
- 				}
 
- 				var startAngle = me.getIndexAngle(0);
 
- 				var tickFont = helpers$1.options._parseFont(tickOpts);
 
- 				var tickFontColor = valueOrDefault$c(tickOpts.fontColor, core_defaults.global.defaultFontColor);
 
- 				var offset, width;
 
- 				ctx.save();
 
- 				ctx.font = tickFont.string;
 
- 				ctx.translate(me.xCenter, me.yCenter);
 
- 				ctx.rotate(startAngle);
 
- 				ctx.textAlign = 'center';
 
- 				ctx.textBaseline = 'middle';
 
- 				helpers$1.each(me.ticks, function(label, index) {
 
- 					if (index === 0 && !tickOpts.reverse) {
 
- 						return;
 
- 					}
 
- 					offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
 
- 					if (tickOpts.showLabelBackdrop) {
 
- 						width = ctx.measureText(label).width;
 
- 						ctx.fillStyle = tickOpts.backdropColor;
 
- 						ctx.fillRect(
 
- 							-width / 2 - tickOpts.backdropPaddingX,
 
- 							-offset - tickFont.size / 2 - tickOpts.backdropPaddingY,
 
- 							width + tickOpts.backdropPaddingX * 2,
 
- 							tickFont.size + tickOpts.backdropPaddingY * 2
 
- 						);
 
- 					}
 
- 					ctx.fillStyle = tickFontColor;
 
- 					ctx.fillText(label, 0, -offset);
 
- 				});
 
- 				ctx.restore();
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_drawTitle: helpers$1.noop
 
- 		});
 
- 		// INTERNAL: static default options, registered in src/index.js
 
- 		var _defaults$3 = defaultConfig$3;
 
- 		scale_radialLinear._defaults = _defaults$3;
 
- 		var deprecated$1 = helpers$1._deprecated;
 
- 		var resolve$5 = helpers$1.options.resolve;
 
- 		var valueOrDefault$d = helpers$1.valueOrDefault;
 
- 		// Integer constants are from the ES6 spec.
 
- 		var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
 
- 		var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
 
- 		var 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
 
- 			}
 
- 		};
 
- 		var UNITS = Object.keys(INTERVALS);
 
- 		function sorter(a, b) {
 
- 			return a - b;
 
- 		}
 
- 		function arrayUnique(items) {
 
- 			var hash = {};
 
- 			var out = [];
 
- 			var i, ilen, item;
 
- 			for (i = 0, ilen = items.length; i < ilen; ++i) {
 
- 				item = items[i];
 
- 				if (!hash[item]) {
 
- 					hash[item] = true;
 
- 					out.push(item);
 
- 				}
 
- 			}
 
- 			return out;
 
- 		}
 
- 		function getMin(options) {
 
- 			return helpers$1.valueOrDefault(options.time.min, options.ticks.min);
 
- 		}
 
- 		function getMax(options) {
 
- 			return helpers$1.valueOrDefault(options.time.max, options.ticks.max);
 
- 		}
 
- 		/**
 
- 		 * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
 
- 		 * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
 
- 		 * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
 
- 		 * extremity (left + width or top + height). Note that it would be more optimized to directly
 
- 		 * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need
 
- 		 * to create the lookup table. The table ALWAYS contains at least two items: min and max.
 
- 		 *
 
- 		 * @param {number[]} timestamps - timestamps sorted from lowest to highest.
 
- 		 * @param {string} distribution - If 'linear', timestamps will be spread linearly along the min
 
- 		 * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.
 
- 		 * If 'series', timestamps will be positioned at the same distance from each other. In this
 
- 		 * case, only timestamps that break the time linearity are registered, meaning that in the
 
- 		 * best case, all timestamps are linear, the table contains only min and max.
 
- 		 */
 
- 		function buildLookupTable(timestamps, min, max, distribution) {
 
- 			if (distribution === 'linear' || !timestamps.length) {
 
- 				return [
 
- 					{time: min, pos: 0},
 
- 					{time: max, pos: 1}
 
- 				];
 
- 			}
 
- 			var table = [];
 
- 			var items = [min];
 
- 			var 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);
 
- 				}
 
- 			}
 
- 			items.push(max);
 
- 			for (i = 0, ilen = items.length; i < ilen; ++i) {
 
- 				next = items[i + 1];
 
- 				prev = items[i - 1];
 
- 				curr = items[i];
 
- 				// only add points that breaks the scale linearity
 
- 				if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {
 
- 					table.push({time: curr, pos: i / (ilen - 1)});
 
- 				}
 
- 			}
 
- 			return table;
 
- 		}
 
- 		// @see adapted from https://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/
 
- 		function lookup(table, key, value) {
 
- 			var lo = 0;
 
- 			var hi = table.length - 1;
 
- 			var mid, i0, i1;
 
- 			while (lo >= 0 && lo <= hi) {
 
- 				mid = (lo + hi) >> 1;
 
- 				i0 = table[mid - 1] || null;
 
- 				i1 = table[mid];
 
- 				if (!i0) {
 
- 					// given value is outside table (before first item)
 
- 					return {lo: null, hi: i1};
 
- 				} else if (i1[key] < value) {
 
- 					lo = mid + 1;
 
- 				} else if (i0[key] > value) {
 
- 					hi = mid - 1;
 
- 				} else {
 
- 					return {lo: i0, hi: i1};
 
- 				}
 
- 			}
 
- 			// given value is outside table (after last item)
 
- 			return {lo: i1, hi: null};
 
- 		}
 
- 		/**
 
- 		 * Linearly interpolates the given source `value` using the table items `skey` values and
 
- 		 * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')
 
- 		 * returns the position for a timestamp equal to 42. If value is out of bounds, values at
 
- 		 * index [0, 1] or [n - 1, n] are used for the interpolation.
 
- 		 */
 
- 		function interpolate$1(table, skey, sval, tkey) {
 
- 			var range = lookup(table, skey, sval);
 
- 			// Note: the lookup table ALWAYS contains at least 2 items (min and max)
 
- 			var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;
 
- 			var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;
 
- 			var span = next[skey] - prev[skey];
 
- 			var ratio = span ? (sval - prev[skey]) / span : 0;
 
- 			var offset = (next[tkey] - prev[tkey]) * ratio;
 
- 			return prev[tkey] + offset;
 
- 		}
 
- 		function toTimestamp(scale, input) {
 
- 			var adapter = scale._adapter;
 
- 			var options = scale.options.time;
 
- 			var parser = options.parser;
 
- 			var format = parser || options.format;
 
- 			var value = input;
 
- 			if (typeof parser === 'function') {
 
- 				value = parser(value);
 
- 			}
 
- 			// Only parse if its not a timestamp already
 
- 			if (!helpers$1.isFinite(value)) {
 
- 				value = typeof format === 'string'
 
- 					? adapter.parse(value, format)
 
- 					: adapter.parse(value);
 
- 			}
 
- 			if (value !== null) {
 
- 				return +value;
 
- 			}
 
- 			// Labels are in an incompatible format and no `parser` has been provided.
 
- 			// The user might still use the deprecated `format` option for parsing.
 
- 			if (!parser && typeof format === 'function') {
 
- 				value = format(input);
 
- 				// `format` could return something else than a timestamp, if so, parse it
 
- 				if (!helpers$1.isFinite(value)) {
 
- 					value = adapter.parse(value);
 
- 				}
 
- 			}
 
- 			return value;
 
- 		}
 
- 		function parse(scale, input) {
 
- 			if (helpers$1.isNullOrUndef(input)) {
 
- 				return null;
 
- 			}
 
- 			var options = scale.options.time;
 
- 			var value = toTimestamp(scale, scale.getRightValue(input));
 
- 			if (value === null) {
 
- 				return value;
 
- 			}
 
- 			if (options.round) {
 
- 				value = +scale._adapter.startOf(value, options.round);
 
- 			}
 
- 			return value;
 
- 		}
 
- 		/**
 
- 		 * Figures out what unit results in an appropriate number of auto-generated ticks
 
- 		 */
 
- 		function determineUnitForAutoTicks(minUnit, min, max, capacity) {
 
- 			var ilen = UNITS.length;
 
- 			var i, interval, factor;
 
- 			for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
 
- 				interval = INTERVALS[UNITS[i]];
 
- 				factor = interval.steps ? interval.steps : MAX_INTEGER;
 
- 				if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
 
- 					return UNITS[i];
 
- 				}
 
- 			}
 
- 			return UNITS[ilen - 1];
 
- 		}
 
- 		/**
 
- 		 * Figures out what unit to format a set of ticks with
 
- 		 */
 
- 		function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
 
- 			var i, unit;
 
- 			for (i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {
 
- 				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 (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
 
- 				if (INTERVALS[UNITS[i]].common) {
 
- 					return UNITS[i];
 
- 				}
 
- 			}
 
- 		}
 
- 		/**
 
- 		 * Generates a maximum of `capacity` timestamps between min and max, rounded to the
 
- 		 * `minor` unit using the given scale time `options`.
 
- 		 * Important: this method can return ticks outside the min and max range, it's the
 
- 		 * responsibility of the calling code to clamp values if needed.
 
- 		 */
 
- 		function generate(scale, min, max, capacity) {
 
- 			var adapter = scale._adapter;
 
- 			var options = scale.options;
 
- 			var timeOpts = options.time;
 
- 			var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
 
- 			var stepSize = resolve$5([timeOpts.stepSize, timeOpts.unitStepSize, 1]);
 
- 			var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
 
- 			var first = min;
 
- 			var ticks = [];
 
- 			var time;
 
- 			// For 'week' unit, handle the first day of week option
 
- 			if (weekday) {
 
- 				first = +adapter.startOf(first, 'isoWeek', weekday);
 
- 			}
 
- 			// Align first ticks on unit
 
- 			first = +adapter.startOf(first, weekday ? 'day' : minor);
 
- 			// Prevent browser from freezing in case user options request millions of milliseconds
 
- 			if (adapter.diff(max, min, minor) > 100000 * stepSize) {
 
- 				throw min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor;
 
- 			}
 
- 			for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) {
 
- 				ticks.push(time);
 
- 			}
 
- 			if (time === max || options.bounds === 'ticks') {
 
- 				ticks.push(time);
 
- 			}
 
- 			return ticks;
 
- 		}
 
- 		/**
 
- 		 * Returns the start and end offsets from edges in the form of {start, end}
 
- 		 * where each value is a relative width to the scale and ranges between 0 and 1.
 
- 		 * They add extra margins on the both sides by scaling down the original scale.
 
- 		 * Offsets are added when the `offset` option is true.
 
- 		 */
 
- 		function computeOffsets(table, ticks, min, max, options) {
 
- 			var start = 0;
 
- 			var end = 0;
 
- 			var first, last;
 
- 			if (options.offset && ticks.length) {
 
- 				first = interpolate$1(table, 'time', ticks[0], 'pos');
 
- 				if (ticks.length === 1) {
 
- 					start = 1 - first;
 
- 				} else {
 
- 					start = (interpolate$1(table, 'time', ticks[1], 'pos') - first) / 2;
 
- 				}
 
- 				last = interpolate$1(table, 'time', ticks[ticks.length - 1], 'pos');
 
- 				if (ticks.length === 1) {
 
- 					end = last;
 
- 				} else {
 
- 					end = (last - interpolate$1(table, 'time', ticks[ticks.length - 2], 'pos')) / 2;
 
- 				}
 
- 			}
 
- 			return {start: start, end: end, factor: 1 / (start + 1 + end)};
 
- 		}
 
- 		function setMajorTicks(scale, ticks, map, majorUnit) {
 
- 			var adapter = scale._adapter;
 
- 			var first = +adapter.startOf(ticks[0].value, majorUnit);
 
- 			var last = ticks[ticks.length - 1].value;
 
- 			var 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) {
 
- 			var ticks = [];
 
- 			var map = {};
 
- 			var ilen = values.length;
 
- 			var i, value;
 
- 			for (i = 0; i < ilen; ++i) {
 
- 				value = values[i];
 
- 				map[value] = i;
 
- 				ticks.push({
 
- 					value: value,
 
- 					major: false
 
- 				});
 
- 			}
 
- 			// We set the major ticks separately from the above loop because calling startOf for every tick
 
- 			// is expensive when there is a large number of ticks
 
- 			return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
 
- 		}
 
- 		var defaultConfig$4 = {
 
- 			position: 'bottom',
 
- 			/**
 
- 			 * Data distribution along the scale:
 
- 			 * - 'linear': data are spread according to their time (distances can vary),
 
- 			 * - 'series': data are spread at the same distance from each other.
 
- 			 * @see https://github.com/chartjs/Chart.js/pull/4507
 
- 			 * @since 2.7.0
 
- 			 */
 
- 			distribution: 'linear',
 
- 			/**
 
- 			 * Scale boundary strategy (bypassed by min/max time options)
 
- 			 * - `data`: make sure data are fully visible, ticks outside are removed
 
- 			 * - `ticks`: make sure ticks are fully visible, data outside are truncated
 
- 			 * @see https://github.com/chartjs/Chart.js/pull/4556
 
- 			 * @since 2.7.0
 
- 			 */
 
- 			bounds: 'data',
 
- 			adapters: {},
 
- 			time: {
 
- 				parser: false, // false == a pattern string from https://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
 
- 				unit: false, // false == automatic or override with week, month, year, etc.
 
- 				round: false, // none, or override with week, month, year, etc.
 
- 				displayFormat: false, // DEPRECATED
 
- 				isoWeekday: false, // override week start day - see https://momentjs.com/docs/#/get-set/iso-weekday/
 
- 				minUnit: 'millisecond',
 
- 				displayFormats: {}
 
- 			},
 
- 			ticks: {
 
- 				autoSkip: false,
 
- 				/**
 
- 				 * Ticks generation input values:
 
- 				 * - 'auto': generates "optimal" ticks based on scale size and time options.
 
- 				 * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
 
- 				 * - 'labels': generates ticks from user given `data.labels` values ONLY.
 
- 				 * @see https://github.com/chartjs/Chart.js/pull/4507
 
- 				 * @since 2.7.0
 
- 				 */
 
- 				source: 'auto',
 
- 				major: {
 
- 					enabled: false
 
- 				}
 
- 			}
 
- 		};
 
- 		var scale_time = core_scale.extend({
 
- 			initialize: function() {
 
- 				this.mergeTicksOptions();
 
- 				core_scale.prototype.initialize.call(this);
 
- 			},
 
- 			update: function() {
 
- 				var me = this;
 
- 				var options = me.options;
 
- 				var time = options.time || (options.time = {});
 
- 				var adapter = me._adapter = new core_adapters._date(options.adapters.date);
 
- 				// DEPRECATIONS: output a message only one time per update
 
- 				deprecated$1('time scale', time.format, 'time.format', 'time.parser');
 
- 				deprecated$1('time scale', time.min, 'time.min', 'ticks.min');
 
- 				deprecated$1('time scale', time.max, 'time.max', 'ticks.max');
 
- 				// Backward compatibility: before introducing adapter, `displayFormats` was
 
- 				// supposed to contain *all* unit/string pairs but this can't be resolved
 
- 				// when loading the scale (adapters are loaded afterward), so let's populate
 
- 				// missing formats on update
 
- 				helpers$1.mergeIf(time.displayFormats, adapter.formats());
 
- 				return core_scale.prototype.update.apply(me, arguments);
 
- 			},
 
- 			/**
 
- 			 * Allows data to be referenced via 't' attribute
 
- 			 */
 
- 			getRightValue: function(rawValue) {
 
- 				if (rawValue && rawValue.t !== undefined) {
 
- 					rawValue = rawValue.t;
 
- 				}
 
- 				return core_scale.prototype.getRightValue.call(this, rawValue);
 
- 			},
 
- 			determineDataLimits: function() {
 
- 				var me = this;
 
- 				var chart = me.chart;
 
- 				var adapter = me._adapter;
 
- 				var options = me.options;
 
- 				var unit = options.time.unit || 'day';
 
- 				var min = MAX_INTEGER;
 
- 				var max = MIN_INTEGER;
 
- 				var timestamps = [];
 
- 				var datasets = [];
 
- 				var labels = [];
 
- 				var i, j, ilen, jlen, data, timestamp, labelsAdded;
 
- 				var dataLabels = me._getLabels();
 
- 				for (i = 0, ilen = dataLabels.length; i < ilen; ++i) {
 
- 					labels.push(parse(me, dataLabels[i]));
 
- 				}
 
- 				for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
 
- 					if (chart.isDatasetVisible(i)) {
 
- 						data = chart.data.datasets[i].data;
 
- 						// Let's consider that all data have the same format.
 
- 						if (helpers$1.isObject(data[0])) {
 
- 							datasets[i] = [];
 
- 							for (j = 0, jlen = data.length; j < jlen; ++j) {
 
- 								timestamp = parse(me, data[j]);
 
- 								timestamps.push(timestamp);
 
- 								datasets[i][j] = timestamp;
 
- 							}
 
- 						} else {
 
- 							datasets[i] = labels.slice(0);
 
- 							if (!labelsAdded) {
 
- 								timestamps = timestamps.concat(labels);
 
- 								labelsAdded = true;
 
- 							}
 
- 						}
 
- 					} else {
 
- 						datasets[i] = [];
 
- 					}
 
- 				}
 
- 				if (labels.length) {
 
- 					min = Math.min(min, labels[0]);
 
- 					max = Math.max(max, labels[labels.length - 1]);
 
- 				}
 
- 				if (timestamps.length) {
 
- 					timestamps = ilen > 1 ? arrayUnique(timestamps).sort(sorter) : timestamps.sort(sorter);
 
- 					min = Math.min(min, timestamps[0]);
 
- 					max = Math.max(max, timestamps[timestamps.length - 1]);
 
- 				}
 
- 				min = parse(me, getMin(options)) || min;
 
- 				max = parse(me, getMax(options)) || max;
 
- 				// In case there is no valid min/max, set limits based on unit time option
 
- 				min = min === MAX_INTEGER ? +adapter.startOf(Date.now(), unit) : min;
 
- 				max = max === MIN_INTEGER ? +adapter.endOf(Date.now(), unit) + 1 : max;
 
- 				// Make sure that max is strictly higher than min (required by the lookup table)
 
- 				me.min = Math.min(min, max);
 
- 				me.max = Math.max(min + 1, max);
 
- 				// PRIVATE
 
- 				me._table = [];
 
- 				me._timestamps = {
 
- 					data: timestamps,
 
- 					datasets: datasets,
 
- 					labels: labels
 
- 				};
 
- 			},
 
- 			buildTicks: function() {
 
- 				var me = this;
 
- 				var min = me.min;
 
- 				var max = me.max;
 
- 				var options = me.options;
 
- 				var tickOpts = options.ticks;
 
- 				var timeOpts = options.time;
 
- 				var timestamps = me._timestamps;
 
- 				var ticks = [];
 
- 				var capacity = me.getLabelCapacity(min);
 
- 				var source = tickOpts.source;
 
- 				var distribution = options.distribution;
 
- 				var i, ilen, timestamp;
 
- 				if (source === 'data' || (source === 'auto' && distribution === 'series')) {
 
- 					timestamps = timestamps.data;
 
- 				} else if (source === 'labels') {
 
- 					timestamps = timestamps.labels;
 
- 				} else {
 
- 					timestamps = generate(me, min, max, capacity);
 
- 				}
 
- 				if (options.bounds === 'ticks' && timestamps.length) {
 
- 					min = timestamps[0];
 
- 					max = timestamps[timestamps.length - 1];
 
- 				}
 
- 				// Enforce limits with user min/max options
 
- 				min = parse(me, getMin(options)) || min;
 
- 				max = parse(me, getMax(options)) || max;
 
- 				// Remove ticks outside the min/max range
 
- 				for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
 
- 					timestamp = timestamps[i];
 
- 					if (timestamp >= min && timestamp <= max) {
 
- 						ticks.push(timestamp);
 
- 					}
 
- 				}
 
- 				me.min = min;
 
- 				me.max = max;
 
- 				// PRIVATE
 
- 				// determineUnitForFormatting relies on the number of ticks so we don't use it when
 
- 				// autoSkip is enabled because we don't yet know what the final number of ticks will be
 
- 				me._unit = timeOpts.unit || (tickOpts.autoSkip
 
- 					? determineUnitForAutoTicks(timeOpts.minUnit, me.min, me.max, capacity)
 
- 					: determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max));
 
- 				me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined
 
- 					: determineMajorUnit(me._unit);
 
- 				me._table = buildLookupTable(me._timestamps.data, min, max, distribution);
 
- 				me._offsets = computeOffsets(me._table, ticks, min, max, options);
 
- 				if (tickOpts.reverse) {
 
- 					ticks.reverse();
 
- 				}
 
- 				return ticksFromTimestamps(me, ticks, me._majorUnit);
 
- 			},
 
- 			getLabelForIndex: function(index, datasetIndex) {
 
- 				var me = this;
 
- 				var adapter = me._adapter;
 
- 				var data = me.chart.data;
 
- 				var timeOpts = me.options.time;
 
- 				var label = data.labels && index < data.labels.length ? data.labels[index] : '';
 
- 				var value = data.datasets[datasetIndex].data[index];
 
- 				if (helpers$1.isObject(value)) {
 
- 					label = me.getRightValue(value);
 
- 				}
 
- 				if (timeOpts.tooltipFormat) {
 
- 					return adapter.format(toTimestamp(me, label), timeOpts.tooltipFormat);
 
- 				}
 
- 				if (typeof label === 'string') {
 
- 					return label;
 
- 				}
 
- 				return adapter.format(toTimestamp(me, label), timeOpts.displayFormats.datetime);
 
- 			},
 
- 			/**
 
- 			 * Function to format an individual tick mark
 
- 			 * @private
 
- 			 */
 
- 			tickFormatFunction: function(time, index, ticks, format) {
 
- 				var me = this;
 
- 				var adapter = me._adapter;
 
- 				var options = me.options;
 
- 				var formats = options.time.displayFormats;
 
- 				var minorFormat = formats[me._unit];
 
- 				var majorUnit = me._majorUnit;
 
- 				var majorFormat = formats[majorUnit];
 
- 				var tick = ticks[index];
 
- 				var tickOpts = options.ticks;
 
- 				var major = majorUnit && majorFormat && tick && tick.major;
 
- 				var label = adapter.format(time, format ? format : major ? majorFormat : minorFormat);
 
- 				var nestedTickOpts = major ? tickOpts.major : tickOpts.minor;
 
- 				var formatter = resolve$5([
 
- 					nestedTickOpts.callback,
 
- 					nestedTickOpts.userCallback,
 
- 					tickOpts.callback,
 
- 					tickOpts.userCallback
 
- 				]);
 
- 				return formatter ? formatter(label, index, ticks) : label;
 
- 			},
 
- 			convertTicksToLabels: function(ticks) {
 
- 				var labels = [];
 
- 				var i, ilen;
 
- 				for (i = 0, ilen = ticks.length; i < ilen; ++i) {
 
- 					labels.push(this.tickFormatFunction(ticks[i].value, i, ticks));
 
- 				}
 
- 				return labels;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			getPixelForOffset: function(time) {
 
- 				var me = this;
 
- 				var offsets = me._offsets;
 
- 				var pos = interpolate$1(me._table, 'time', time, 'pos');
 
- 				return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);
 
- 			},
 
- 			getPixelForValue: function(value, index, datasetIndex) {
 
- 				var me = this;
 
- 				var time = null;
 
- 				if (index !== undefined && datasetIndex !== undefined) {
 
- 					time = me._timestamps.datasets[datasetIndex][index];
 
- 				}
 
- 				if (time === null) {
 
- 					time = parse(me, value);
 
- 				}
 
- 				if (time !== null) {
 
- 					return me.getPixelForOffset(time);
 
- 				}
 
- 			},
 
- 			getPixelForTick: function(index) {
 
- 				var ticks = this.getTicks();
 
- 				return index >= 0 && index < ticks.length ?
 
- 					this.getPixelForOffset(ticks[index].value) :
 
- 					null;
 
- 			},
 
- 			getValueForPixel: function(pixel) {
 
- 				var me = this;
 
- 				var offsets = me._offsets;
 
- 				var pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
 
- 				var time = interpolate$1(me._table, 'pos', pos, 'time');
 
- 				// DEPRECATION, we should return time directly
 
- 				return me._adapter._create(time);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getLabelSize: function(label) {
 
- 				var me = this;
 
- 				var ticksOpts = me.options.ticks;
 
- 				var tickLabelWidth = me.ctx.measureText(label).width;
 
- 				var angle = helpers$1.toRadians(me.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
 
- 				var cosRotation = Math.cos(angle);
 
- 				var sinRotation = Math.sin(angle);
 
- 				var tickFontSize = valueOrDefault$d(ticksOpts.fontSize, core_defaults.global.defaultFontSize);
 
- 				return {
 
- 					w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation),
 
- 					h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation)
 
- 				};
 
- 			},
 
- 			/**
 
- 			 * Crude approximation of what the label width might be
 
- 			 * @private
 
- 			 */
 
- 			getLabelWidth: function(label) {
 
- 				return this._getLabelSize(label).w;
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			getLabelCapacity: function(exampleTime) {
 
- 				var me = this;
 
- 				var timeOpts = me.options.time;
 
- 				var displayFormats = timeOpts.displayFormats;
 
- 				// pick the longest format (milliseconds) for guestimation
 
- 				var format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
 
- 				var exampleLabel = me.tickFormatFunction(exampleTime, 0, ticksFromTimestamps(me, [exampleTime], me._majorUnit), format);
 
- 				var size = me._getLabelSize(exampleLabel);
 
- 				var capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h);
 
- 				if (me.options.offset) {
 
- 					capacity--;
 
- 				}
 
- 				return capacity > 0 ? capacity : 1;
 
- 			}
 
- 		});
 
- 		// INTERNAL: static default options, registered in src/index.js
 
- 		var _defaults$4 = defaultConfig$4;
 
- 		scale_time._defaults = _defaults$4;
 
- 		var scales = {
 
- 			category: scale_category,
 
- 			linear: scale_linear,
 
- 			logarithmic: scale_logarithmic,
 
- 			radialLinear: scale_radialLinear,
 
- 			time: scale_time
 
- 		};
 
- 		var FORMATS = {
 
- 			datetime: 'MMM D, YYYY, h:mm:ss a',
 
- 			millisecond: 'h:mm:ss.SSS a',
 
- 			second: 'h:mm:ss a',
 
- 			minute: 'h:mm a',
 
- 			hour: 'hA',
 
- 			day: 'MMM D',
 
- 			week: 'll',
 
- 			month: 'MMM YYYY',
 
- 			quarter: '[Q]Q - YYYY',
 
- 			year: 'YYYY'
 
- 		};
 
- 		core_adapters._date.override(typeof moment === 'function' ? {
 
- 			_id: 'moment', // DEBUG ONLY
 
- 			formats: function() {
 
- 				return FORMATS;
 
- 			},
 
- 			parse: function(value, format) {
 
- 				if (typeof value === 'string' && typeof format === 'string') {
 
- 					value = moment(value, format);
 
- 				} else if (!(value instanceof moment)) {
 
- 					value = moment(value);
 
- 				}
 
- 				return value.isValid() ? value.valueOf() : null;
 
- 			},
 
- 			format: function(time, format) {
 
- 				return moment(time).format(format);
 
- 			},
 
- 			add: function(time, amount, unit) {
 
- 				return moment(time).add(amount, unit).valueOf();
 
- 			},
 
- 			diff: function(max, min, unit) {
 
- 				return moment(max).diff(moment(min), unit);
 
- 			},
 
- 			startOf: function(time, unit, weekday) {
 
- 				time = moment(time);
 
- 				if (unit === 'isoWeek') {
 
- 					return time.isoWeekday(weekday).valueOf();
 
- 				}
 
- 				return time.startOf(unit).valueOf();
 
- 			},
 
- 			endOf: function(time, unit) {
 
- 				return moment(time).endOf(unit).valueOf();
 
- 			},
 
- 			// DEPRECATIONS
 
- 			/**
 
- 			 * Provided for backward compatibility with scale.getValueForPixel().
 
- 			 * @deprecated since version 2.8.0
 
- 			 * @todo remove at version 3
 
- 			 * @private
 
- 			 */
 
- 			_create: function(time) {
 
- 				return moment(time);
 
- 			},
 
- 		} : {});
 
- 		core_defaults._set('global', {
 
- 			plugins: {
 
- 				filler: {
 
- 					propagate: true
 
- 				}
 
- 			}
 
- 		});
 
- 		var mappers = {
 
- 			dataset: function(source) {
 
- 				var index = source.fill;
 
- 				var chart = source.chart;
 
- 				var meta = chart.getDatasetMeta(index);
 
- 				var visible = meta && chart.isDatasetVisible(index);
 
- 				var points = (visible && meta.dataset._children) || [];
 
- 				var length = points.length || 0;
 
- 				return !length ? null : function(point, i) {
 
- 					return (i < length && points[i]._view) || null;
 
- 				};
 
- 			},
 
- 			boundary: function(source) {
 
- 				var boundary = source.boundary;
 
- 				var x = boundary ? boundary.x : null;
 
- 				var y = boundary ? boundary.y : null;
 
- 				if (helpers$1.isArray(boundary)) {
 
- 					return function(point, i) {
 
- 						return boundary[i];
 
- 					};
 
- 				}
 
- 				return function(point) {
 
- 					return {
 
- 						x: x === null ? point.x : x,
 
- 						y: y === null ? point.y : y,
 
- 					};
 
- 				};
 
- 			}
 
- 		};
 
- 		// @todo if (fill[0] === '#')
 
- 		function decodeFill(el, index, count) {
 
- 			var model = el._model || {};
 
- 			var fill = model.fill;
 
- 			var target;
 
- 			if (fill === undefined) {
 
- 				fill = !!model.backgroundColor;
 
- 			}
 
- 			if (fill === false || fill === null) {
 
- 				return false;
 
- 			}
 
- 			if (fill === true) {
 
- 				return 'origin';
 
- 			}
 
- 			target = parseFloat(fill, 10);
 
- 			if (isFinite(target) && Math.floor(target) === target) {
 
- 				if (fill[0] === '-' || fill[0] === '+') {
 
- 					target = index + target;
 
- 				}
 
- 				if (target === index || target < 0 || target >= count) {
 
- 					return false;
 
- 				}
 
- 				return target;
 
- 			}
 
- 			switch (fill) {
 
- 			// compatibility
 
- 			case 'bottom':
 
- 				return 'start';
 
- 			case 'top':
 
- 				return 'end';
 
- 			case 'zero':
 
- 				return 'origin';
 
- 			// supported boundaries
 
- 			case 'origin':
 
- 			case 'start':
 
- 			case 'end':
 
- 				return fill;
 
- 			// invalid fill values
 
- 			default:
 
- 				return false;
 
- 			}
 
- 		}
 
- 		function computeLinearBoundary(source) {
 
- 			var model = source.el._model || {};
 
- 			var scale = source.el._scale || {};
 
- 			var fill = source.fill;
 
- 			var target = null;
 
- 			var horizontal;
 
- 			if (isFinite(fill)) {
 
- 				return null;
 
- 			}
 
- 			// Backward compatibility: until v3, we still need to support boundary values set on
 
- 			// the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
 
- 			// controllers might still use it (e.g. the Smith chart).
 
- 			if (fill === 'start') {
 
- 				target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;
 
- 			} else if (fill === 'end') {
 
- 				target = model.scaleTop === undefined ? scale.top : model.scaleTop;
 
- 			} else if (model.scaleZero !== undefined) {
 
- 				target = model.scaleZero;
 
- 			} else if (scale.getBasePixel) {
 
- 				target = scale.getBasePixel();
 
- 			}
 
- 			if (target !== undefined && target !== null) {
 
- 				if (target.x !== undefined && target.y !== undefined) {
 
- 					return target;
 
- 				}
 
- 				if (helpers$1.isFinite(target)) {
 
- 					horizontal = scale.isHorizontal();
 
- 					return {
 
- 						x: horizontal ? target : null,
 
- 						y: horizontal ? null : target
 
- 					};
 
- 				}
 
- 			}
 
- 			return null;
 
- 		}
 
- 		function computeCircularBoundary(source) {
 
- 			var scale = source.el._scale;
 
- 			var options = scale.options;
 
- 			var length = scale.chart.data.labels.length;
 
- 			var fill = source.fill;
 
- 			var target = [];
 
- 			var start, end, center, i, point;
 
- 			if (!length) {
 
- 				return null;
 
- 			}
 
- 			start = options.ticks.reverse ? scale.max : scale.min;
 
- 			end = options.ticks.reverse ? scale.min : scale.max;
 
- 			center = scale.getPointPositionForValue(0, start);
 
- 			for (i = 0; i < length; ++i) {
 
- 				point = fill === 'start' || fill === 'end'
 
- 					? scale.getPointPositionForValue(i, fill === 'start' ? start : end)
 
- 					: scale.getBasePosition(i);
 
- 				if (options.gridLines.circular) {
 
- 					point.cx = center.x;
 
- 					point.cy = center.y;
 
- 					point.angle = scale.getIndexAngle(i) - Math.PI / 2;
 
- 				}
 
- 				target.push(point);
 
- 			}
 
- 			return target;
 
- 		}
 
- 		function computeBoundary(source) {
 
- 			var scale = source.el._scale || {};
 
- 			if (scale.getPointPositionForValue) {
 
- 				return computeCircularBoundary(source);
 
- 			}
 
- 			return computeLinearBoundary(source);
 
- 		}
 
- 		function resolveTarget(sources, index, propagate) {
 
- 			var source = sources[index];
 
- 			var fill = source.fill;
 
- 			var visited = [index];
 
- 			var target;
 
- 			if (!propagate) {
 
- 				return fill;
 
- 			}
 
- 			while (fill !== false && visited.indexOf(fill) === -1) {
 
- 				if (!isFinite(fill)) {
 
- 					return fill;
 
- 				}
 
- 				target = sources[fill];
 
- 				if (!target) {
 
- 					return false;
 
- 				}
 
- 				if (target.visible) {
 
- 					return fill;
 
- 				}
 
- 				visited.push(fill);
 
- 				fill = target.fill;
 
- 			}
 
- 			return false;
 
- 		}
 
- 		function createMapper(source) {
 
- 			var fill = source.fill;
 
- 			var type = 'dataset';
 
- 			if (fill === false) {
 
- 				return null;
 
- 			}
 
- 			if (!isFinite(fill)) {
 
- 				type = 'boundary';
 
- 			}
 
- 			return mappers[type](source);
 
- 		}
 
- 		function isDrawable(point) {
 
- 			return point && !point.skip;
 
- 		}
 
- 		function drawArea(ctx, curve0, curve1, len0, len1) {
 
- 			var i, cx, cy, r;
 
- 			if (!len0 || !len1) {
 
- 				return;
 
- 			}
 
- 			// building first area curve (normal)
 
- 			ctx.moveTo(curve0[0].x, curve0[0].y);
 
- 			for (i = 1; i < len0; ++i) {
 
- 				helpers$1.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);
 
- 			}
 
- 			if (curve1[0].angle !== undefined) {
 
- 				cx = curve1[0].cx;
 
- 				cy = curve1[0].cy;
 
- 				r = Math.sqrt(Math.pow(curve1[0].x - cx, 2) + Math.pow(curve1[0].y - cy, 2));
 
- 				for (i = len1 - 1; i > 0; --i) {
 
- 					ctx.arc(cx, cy, r, curve1[i].angle, curve1[i - 1].angle, true);
 
- 				}
 
- 				return;
 
- 			}
 
- 			// joining the two area curves
 
- 			ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);
 
- 			// building opposite area curve (reverse)
 
- 			for (i = len1 - 1; i > 0; --i) {
 
- 				helpers$1.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);
 
- 			}
 
- 		}
 
- 		function doFill(ctx, points, mapper, view, color, loop) {
 
- 			var count = points.length;
 
- 			var span = view.spanGaps;
 
- 			var curve0 = [];
 
- 			var curve1 = [];
 
- 			var len0 = 0;
 
- 			var len1 = 0;
 
- 			var i, ilen, index, p0, p1, d0, d1, loopOffset;
 
- 			ctx.beginPath();
 
- 			for (i = 0, ilen = count; i < ilen; ++i) {
 
- 				index = i % count;
 
- 				p0 = points[index]._view;
 
- 				p1 = mapper(p0, index, view);
 
- 				d0 = isDrawable(p0);
 
- 				d1 = isDrawable(p1);
 
- 				if (loop && loopOffset === undefined && d0) {
 
- 					loopOffset = i + 1;
 
- 					ilen = count + loopOffset;
 
- 				}
 
- 				if (d0 && d1) {
 
- 					len0 = curve0.push(p0);
 
- 					len1 = curve1.push(p1);
 
- 				} else if (len0 && len1) {
 
- 					if (!span) {
 
- 						drawArea(ctx, curve0, curve1, len0, len1);
 
- 						len0 = len1 = 0;
 
- 						curve0 = [];
 
- 						curve1 = [];
 
- 					} else {
 
- 						if (d0) {
 
- 							curve0.push(p0);
 
- 						}
 
- 						if (d1) {
 
- 							curve1.push(p1);
 
- 						}
 
- 					}
 
- 				}
 
- 			}
 
- 			drawArea(ctx, curve0, curve1, len0, len1);
 
- 			ctx.closePath();
 
- 			ctx.fillStyle = color;
 
- 			ctx.fill();
 
- 		}
 
- 		var plugin_filler = {
 
- 			id: 'filler',
 
- 			afterDatasetsUpdate: function(chart, options) {
 
- 				var count = (chart.data.datasets || []).length;
 
- 				var propagate = options.propagate;
 
- 				var sources = [];
 
- 				var meta, i, el, source;
 
- 				for (i = 0; i < count; ++i) {
 
- 					meta = chart.getDatasetMeta(i);
 
- 					el = meta.dataset;
 
- 					source = null;
 
- 					if (el && el._model && el instanceof elements.Line) {
 
- 						source = {
 
- 							visible: chart.isDatasetVisible(i),
 
- 							fill: decodeFill(el, i, count),
 
- 							chart: chart,
 
- 							el: el
 
- 						};
 
- 					}
 
- 					meta.$filler = source;
 
- 					sources.push(source);
 
- 				}
 
- 				for (i = 0; i < count; ++i) {
 
- 					source = sources[i];
 
- 					if (!source) {
 
- 						continue;
 
- 					}
 
- 					source.fill = resolveTarget(sources, i, propagate);
 
- 					source.boundary = computeBoundary(source);
 
- 					source.mapper = createMapper(source);
 
- 				}
 
- 			},
 
- 			beforeDatasetsDraw: function(chart) {
 
- 				var metasets = chart._getSortedVisibleDatasetMetas();
 
- 				var ctx = chart.ctx;
 
- 				var meta, i, el, view, points, mapper, color;
 
- 				for (i = metasets.length - 1; i >= 0; --i) {
 
- 					meta = metasets[i].$filler;
 
- 					if (!meta || !meta.visible) {
 
- 						continue;
 
- 					}
 
- 					el = meta.el;
 
- 					view = el._view;
 
- 					points = el._children || [];
 
- 					mapper = meta.mapper;
 
- 					color = view.backgroundColor || core_defaults.global.defaultColor;
 
- 					if (mapper && color && points.length) {
 
- 						helpers$1.canvas.clipArea(ctx, chart.chartArea);
 
- 						doFill(ctx, points, mapper, view, color, el._loop);
 
- 						helpers$1.canvas.unclipArea(ctx);
 
- 					}
 
- 				}
 
- 			}
 
- 		};
 
- 		var getRtlHelper$1 = helpers$1.rtl.getRtlAdapter;
 
- 		var noop$1 = helpers$1.noop;
 
- 		var valueOrDefault$e = helpers$1.valueOrDefault;
 
- 		core_defaults._set('global', {
 
- 			legend: {
 
- 				display: true,
 
- 				position: 'top',
 
- 				align: 'center',
 
- 				fullWidth: true,
 
- 				reverse: false,
 
- 				weight: 1000,
 
- 				// a callback that will handle
 
- 				onClick: function(e, legendItem) {
 
- 					var index = legendItem.datasetIndex;
 
- 					var ci = this.chart;
 
- 					var meta = ci.getDatasetMeta(index);
 
- 					// See controller.isDatasetVisible comment
 
- 					meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
 
- 					// We hid a dataset ... rerender the chart
 
- 					ci.update();
 
- 				},
 
- 				onHover: null,
 
- 				onLeave: null,
 
- 				labels: {
 
- 					boxWidth: 40,
 
- 					padding: 10,
 
- 					// Generates labels shown in the legend
 
- 					// Valid properties to return:
 
- 					// text : text to display
 
- 					// fillStyle : fill of coloured box
 
- 					// strokeStyle: stroke of coloured box
 
- 					// hidden : if this legend item refers to a hidden item
 
- 					// lineCap : cap style for line
 
- 					// lineDash
 
- 					// lineDashOffset :
 
- 					// lineJoin :
 
- 					// lineWidth :
 
- 					generateLabels: function(chart) {
 
- 						var datasets = chart.data.datasets;
 
- 						var options = chart.options.legend || {};
 
- 						var usePointStyle = options.labels && options.labels.usePointStyle;
 
- 						return chart._getSortedDatasetMetas().map(function(meta) {
 
- 							var style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
 
- 							return {
 
- 								text: datasets[meta.index].label,
 
- 								fillStyle: style.backgroundColor,
 
- 								hidden: !chart.isDatasetVisible(meta.index),
 
- 								lineCap: style.borderCapStyle,
 
- 								lineDash: style.borderDash,
 
- 								lineDashOffset: style.borderDashOffset,
 
- 								lineJoin: style.borderJoinStyle,
 
- 								lineWidth: style.borderWidth,
 
- 								strokeStyle: style.borderColor,
 
- 								pointStyle: style.pointStyle,
 
- 								rotation: style.rotation,
 
- 								// Below is extra data used for toggling the datasets
 
- 								datasetIndex: meta.index
 
- 							};
 
- 						}, this);
 
- 					}
 
- 				}
 
- 			},
 
- 			legendCallback: function(chart) {
 
- 				var list = document.createElement('ul');
 
- 				var datasets = chart.data.datasets;
 
- 				var i, ilen, listItem, listItemSpan;
 
- 				list.setAttribute('class', chart.id + '-legend');
 
- 				for (i = 0, ilen = datasets.length; i < ilen; i++) {
 
- 					listItem = list.appendChild(document.createElement('li'));
 
- 					listItemSpan = listItem.appendChild(document.createElement('span'));
 
- 					listItemSpan.style.backgroundColor = datasets[i].backgroundColor;
 
- 					if (datasets[i].label) {
 
- 						listItem.appendChild(document.createTextNode(datasets[i].label));
 
- 					}
 
- 				}
 
- 				return list.outerHTML;
 
- 			}
 
- 		});
 
- 		/**
 
- 		 * Helper function to get the box width based on the usePointStyle option
 
- 		 * @param {object} labelopts - the label options on the legend
 
- 		 * @param {number} fontSize - the label font size
 
- 		 * @return {number} width of the color box area
 
- 		 */
 
- 		function getBoxWidth(labelOpts, fontSize) {
 
- 			return labelOpts.usePointStyle && labelOpts.boxWidth > fontSize ?
 
- 				fontSize :
 
- 				labelOpts.boxWidth;
 
- 		}
 
- 		/**
 
- 		 * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
 
- 		 */
 
- 		var Legend = core_element.extend({
 
- 			initialize: function(config) {
 
- 				var me = this;
 
- 				helpers$1.extend(me, config);
 
- 				// Contains hit boxes for each dataset (in dataset order)
 
- 				me.legendHitBoxes = [];
 
- 				/**
 
- 		 		 * @private
 
- 		 		 */
 
- 				me._hoveredItem = null;
 
- 				// Are we in doughnut mode which has a different data type
 
- 				me.doughnutMode = false;
 
- 			},
 
- 			// These methods are ordered by lifecycle. Utilities then follow.
 
- 			// Any function defined here is inherited by all legend types.
 
- 			// Any function can be extended by the legend type
 
- 			beforeUpdate: noop$1,
 
- 			update: function(maxWidth, maxHeight, margins) {
 
- 				var me = this;
 
- 				// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
 
- 				me.beforeUpdate();
 
- 				// Absorb the master measurements
 
- 				me.maxWidth = maxWidth;
 
- 				me.maxHeight = maxHeight;
 
- 				me.margins = margins;
 
- 				// Dimensions
 
- 				me.beforeSetDimensions();
 
- 				me.setDimensions();
 
- 				me.afterSetDimensions();
 
- 				// Labels
 
- 				me.beforeBuildLabels();
 
- 				me.buildLabels();
 
- 				me.afterBuildLabels();
 
- 				// Fit
 
- 				me.beforeFit();
 
- 				me.fit();
 
- 				me.afterFit();
 
- 				//
 
- 				me.afterUpdate();
 
- 				return me.minSize;
 
- 			},
 
- 			afterUpdate: noop$1,
 
- 			//
 
- 			beforeSetDimensions: noop$1,
 
- 			setDimensions: function() {
 
- 				var me = this;
 
- 				// Set the unconstrained dimension before label rotation
 
- 				if (me.isHorizontal()) {
 
- 					// Reset position before calculating rotation
 
- 					me.width = me.maxWidth;
 
- 					me.left = 0;
 
- 					me.right = me.width;
 
- 				} else {
 
- 					me.height = me.maxHeight;
 
- 					// Reset position before calculating rotation
 
- 					me.top = 0;
 
- 					me.bottom = me.height;
 
- 				}
 
- 				// Reset padding
 
- 				me.paddingLeft = 0;
 
- 				me.paddingTop = 0;
 
- 				me.paddingRight = 0;
 
- 				me.paddingBottom = 0;
 
- 				// Reset minSize
 
- 				me.minSize = {
 
- 					width: 0,
 
- 					height: 0
 
- 				};
 
- 			},
 
- 			afterSetDimensions: noop$1,
 
- 			//
 
- 			beforeBuildLabels: noop$1,
 
- 			buildLabels: function() {
 
- 				var me = this;
 
- 				var labelOpts = me.options.labels || {};
 
- 				var legendItems = helpers$1.callback(labelOpts.generateLabels, [me.chart], me) || [];
 
- 				if (labelOpts.filter) {
 
- 					legendItems = legendItems.filter(function(item) {
 
- 						return labelOpts.filter(item, me.chart.data);
 
- 					});
 
- 				}
 
- 				if (me.options.reverse) {
 
- 					legendItems.reverse();
 
- 				}
 
- 				me.legendItems = legendItems;
 
- 			},
 
- 			afterBuildLabels: noop$1,
 
- 			//
 
- 			beforeFit: noop$1,
 
- 			fit: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var labelOpts = opts.labels;
 
- 				var display = opts.display;
 
- 				var ctx = me.ctx;
 
- 				var labelFont = helpers$1.options._parseFont(labelOpts);
 
- 				var fontSize = labelFont.size;
 
- 				// Reset hit boxes
 
- 				var hitboxes = me.legendHitBoxes = [];
 
- 				var minSize = me.minSize;
 
- 				var isHorizontal = me.isHorizontal();
 
- 				if (isHorizontal) {
 
- 					minSize.width = me.maxWidth; // fill all the width
 
- 					minSize.height = display ? 10 : 0;
 
- 				} else {
 
- 					minSize.width = display ? 10 : 0;
 
- 					minSize.height = me.maxHeight; // fill all the height
 
- 				}
 
- 				// Increase sizes here
 
- 				if (!display) {
 
- 					me.width = minSize.width = me.height = minSize.height = 0;
 
- 					return;
 
- 				}
 
- 				ctx.font = labelFont.string;
 
- 				if (isHorizontal) {
 
- 					// Labels
 
- 					// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
 
- 					var lineWidths = me.lineWidths = [0];
 
- 					var totalHeight = 0;
 
- 					ctx.textAlign = 'left';
 
- 					ctx.textBaseline = 'middle';
 
- 					helpers$1.each(me.legendItems, function(legendItem, i) {
 
- 						var boxWidth = getBoxWidth(labelOpts, fontSize);
 
- 						var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
 
- 						if (i === 0 || lineWidths[lineWidths.length - 1] + width + 2 * labelOpts.padding > minSize.width) {
 
- 							totalHeight += fontSize + labelOpts.padding;
 
- 							lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
 
- 						}
 
- 						// Store the hitbox width and height here. Final position will be updated in `draw`
 
- 						hitboxes[i] = {
 
- 							left: 0,
 
- 							top: 0,
 
- 							width: width,
 
- 							height: fontSize
 
- 						};
 
- 						lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
 
- 					});
 
- 					minSize.height += totalHeight;
 
- 				} else {
 
- 					var vPadding = labelOpts.padding;
 
- 					var columnWidths = me.columnWidths = [];
 
- 					var columnHeights = me.columnHeights = [];
 
- 					var totalWidth = labelOpts.padding;
 
- 					var currentColWidth = 0;
 
- 					var currentColHeight = 0;
 
- 					helpers$1.each(me.legendItems, function(legendItem, i) {
 
- 						var boxWidth = getBoxWidth(labelOpts, fontSize);
 
- 						var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
 
- 						// If too tall, go to new column
 
- 						if (i > 0 && currentColHeight + fontSize + 2 * vPadding > minSize.height) {
 
- 							totalWidth += currentColWidth + labelOpts.padding;
 
- 							columnWidths.push(currentColWidth); // previous column width
 
- 							columnHeights.push(currentColHeight);
 
- 							currentColWidth = 0;
 
- 							currentColHeight = 0;
 
- 						}
 
- 						// Get max width
 
- 						currentColWidth = Math.max(currentColWidth, itemWidth);
 
- 						currentColHeight += fontSize + vPadding;
 
- 						// Store the hitbox width and height here. Final position will be updated in `draw`
 
- 						hitboxes[i] = {
 
- 							left: 0,
 
- 							top: 0,
 
- 							width: itemWidth,
 
- 							height: fontSize
 
- 						};
 
- 					});
 
- 					totalWidth += currentColWidth;
 
- 					columnWidths.push(currentColWidth);
 
- 					columnHeights.push(currentColHeight);
 
- 					minSize.width += totalWidth;
 
- 				}
 
- 				me.width = minSize.width;
 
- 				me.height = minSize.height;
 
- 			},
 
- 			afterFit: noop$1,
 
- 			// Shared Methods
 
- 			isHorizontal: function() {
 
- 				return this.options.position === 'top' || this.options.position === 'bottom';
 
- 			},
 
- 			// Actually draw the legend on the canvas
 
- 			draw: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var labelOpts = opts.labels;
 
- 				var globalDefaults = core_defaults.global;
 
- 				var defaultColor = globalDefaults.defaultColor;
 
- 				var lineDefault = globalDefaults.elements.line;
 
- 				var legendHeight = me.height;
 
- 				var columnHeights = me.columnHeights;
 
- 				var legendWidth = me.width;
 
- 				var lineWidths = me.lineWidths;
 
- 				if (!opts.display) {
 
- 					return;
 
- 				}
 
- 				var rtlHelper = getRtlHelper$1(opts.rtl, me.left, me.minSize.width);
 
- 				var ctx = me.ctx;
 
- 				var fontColor = valueOrDefault$e(labelOpts.fontColor, globalDefaults.defaultFontColor);
 
- 				var labelFont = helpers$1.options._parseFont(labelOpts);
 
- 				var fontSize = labelFont.size;
 
- 				var cursor;
 
- 				// Canvas setup
 
- 				ctx.textAlign = rtlHelper.textAlign('left');
 
- 				ctx.textBaseline = 'middle';
 
- 				ctx.lineWidth = 0.5;
 
- 				ctx.strokeStyle = fontColor; // for strikethrough effect
 
- 				ctx.fillStyle = fontColor; // render in correct colour
 
- 				ctx.font = labelFont.string;
 
- 				var boxWidth = getBoxWidth(labelOpts, fontSize);
 
- 				var hitboxes = me.legendHitBoxes;
 
- 				// current position
 
- 				var drawLegendBox = function(x, y, legendItem) {
 
- 					if (isNaN(boxWidth) || boxWidth <= 0) {
 
- 						return;
 
- 					}
 
- 					// Set the ctx for the box
 
- 					ctx.save();
 
- 					var lineWidth = valueOrDefault$e(legendItem.lineWidth, lineDefault.borderWidth);
 
- 					ctx.fillStyle = valueOrDefault$e(legendItem.fillStyle, defaultColor);
 
- 					ctx.lineCap = valueOrDefault$e(legendItem.lineCap, lineDefault.borderCapStyle);
 
- 					ctx.lineDashOffset = valueOrDefault$e(legendItem.lineDashOffset, lineDefault.borderDashOffset);
 
- 					ctx.lineJoin = valueOrDefault$e(legendItem.lineJoin, lineDefault.borderJoinStyle);
 
- 					ctx.lineWidth = lineWidth;
 
- 					ctx.strokeStyle = valueOrDefault$e(legendItem.strokeStyle, defaultColor);
 
- 					if (ctx.setLineDash) {
 
- 						// IE 9 and 10 do not support line dash
 
- 						ctx.setLineDash(valueOrDefault$e(legendItem.lineDash, lineDefault.borderDash));
 
- 					}
 
- 					if (labelOpts && labelOpts.usePointStyle) {
 
- 						// Recalculate x and y for drawPoint() because its expecting
 
- 						// x and y to be center of figure (instead of top left)
 
- 						var radius = boxWidth * Math.SQRT2 / 2;
 
- 						var centerX = rtlHelper.xPlus(x, boxWidth / 2);
 
- 						var centerY = y + fontSize / 2;
 
- 						// Draw pointStyle as legend symbol
 
- 						helpers$1.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY, legendItem.rotation);
 
- 					} else {
 
- 						// Draw box as legend symbol
 
- 						ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize);
 
- 						if (lineWidth !== 0) {
 
- 							ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize);
 
- 						}
 
- 					}
 
- 					ctx.restore();
 
- 				};
 
- 				var fillText = function(x, y, legendItem, textWidth) {
 
- 					var halfFontSize = fontSize / 2;
 
- 					var xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize);
 
- 					var yMiddle = y + halfFontSize;
 
- 					ctx.fillText(legendItem.text, xLeft, yMiddle);
 
- 					if (legendItem.hidden) {
 
- 						// Strikethrough the text if hidden
 
- 						ctx.beginPath();
 
- 						ctx.lineWidth = 2;
 
- 						ctx.moveTo(xLeft, yMiddle);
 
- 						ctx.lineTo(rtlHelper.xPlus(xLeft, textWidth), yMiddle);
 
- 						ctx.stroke();
 
- 					}
 
- 				};
 
- 				var alignmentOffset = function(dimension, blockSize) {
 
- 					switch (opts.align) {
 
- 					case 'start':
 
- 						return labelOpts.padding;
 
- 					case 'end':
 
- 						return dimension - blockSize;
 
- 					default: // center
 
- 						return (dimension - blockSize + labelOpts.padding) / 2;
 
- 					}
 
- 				};
 
- 				// Horizontal
 
- 				var isHorizontal = me.isHorizontal();
 
- 				if (isHorizontal) {
 
- 					cursor = {
 
- 						x: me.left + alignmentOffset(legendWidth, lineWidths[0]),
 
- 						y: me.top + labelOpts.padding,
 
- 						line: 0
 
- 					};
 
- 				} else {
 
- 					cursor = {
 
- 						x: me.left + labelOpts.padding,
 
- 						y: me.top + alignmentOffset(legendHeight, columnHeights[0]),
 
- 						line: 0
 
- 					};
 
- 				}
 
- 				helpers$1.rtl.overrideTextDirection(me.ctx, opts.textDirection);
 
- 				var itemHeight = fontSize + labelOpts.padding;
 
- 				helpers$1.each(me.legendItems, function(legendItem, i) {
 
- 					var textWidth = ctx.measureText(legendItem.text).width;
 
- 					var width = boxWidth + (fontSize / 2) + textWidth;
 
- 					var x = cursor.x;
 
- 					var y = cursor.y;
 
- 					rtlHelper.setWidth(me.minSize.width);
 
- 					// Use (me.left + me.minSize.width) and (me.top + me.minSize.height)
 
- 					// instead of me.right and me.bottom because me.width and me.height
 
- 					// may have been changed since me.minSize was calculated
 
- 					if (isHorizontal) {
 
- 						if (i > 0 && x + width + labelOpts.padding > me.left + me.minSize.width) {
 
- 							y = cursor.y += itemHeight;
 
- 							cursor.line++;
 
- 							x = cursor.x = me.left + alignmentOffset(legendWidth, lineWidths[cursor.line]);
 
- 						}
 
- 					} else if (i > 0 && y + itemHeight > me.top + me.minSize.height) {
 
- 						x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
 
- 						cursor.line++;
 
- 						y = cursor.y = me.top + alignmentOffset(legendHeight, columnHeights[cursor.line]);
 
- 					}
 
- 					var realX = rtlHelper.x(x);
 
- 					drawLegendBox(realX, y, legendItem);
 
- 					hitboxes[i].left = rtlHelper.leftForLtr(realX, hitboxes[i].width);
 
- 					hitboxes[i].top = y;
 
- 					// Fill the actual label
 
- 					fillText(realX, y, legendItem, textWidth);
 
- 					if (isHorizontal) {
 
- 						cursor.x += width + labelOpts.padding;
 
- 					} else {
 
- 						cursor.y += itemHeight;
 
- 					}
 
- 				});
 
- 				helpers$1.rtl.restoreTextDirection(me.ctx, opts.textDirection);
 
- 			},
 
- 			/**
 
- 			 * @private
 
- 			 */
 
- 			_getLegendItemAt: function(x, y) {
 
- 				var me = this;
 
- 				var i, hitBox, lh;
 
- 				if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
 
- 					// See if we are touching one of the dataset boxes
 
- 					lh = me.legendHitBoxes;
 
- 					for (i = 0; i < lh.length; ++i) {
 
- 						hitBox = lh[i];
 
- 						if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
 
- 							// Touching an element
 
- 							return me.legendItems[i];
 
- 						}
 
- 					}
 
- 				}
 
- 				return null;
 
- 			},
 
- 			/**
 
- 			 * Handle an event
 
- 			 * @private
 
- 			 * @param {IEvent} event - The event to handle
 
- 			 */
 
- 			handleEvent: function(e) {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var type = e.type === 'mouseup' ? 'click' : e.type;
 
- 				var hoveredItem;
 
- 				if (type === 'mousemove') {
 
- 					if (!opts.onHover && !opts.onLeave) {
 
- 						return;
 
- 					}
 
- 				} else if (type === 'click') {
 
- 					if (!opts.onClick) {
 
- 						return;
 
- 					}
 
- 				} else {
 
- 					return;
 
- 				}
 
- 				// Chart event already has relative position in it
 
- 				hoveredItem = me._getLegendItemAt(e.x, e.y);
 
- 				if (type === 'click') {
 
- 					if (hoveredItem && opts.onClick) {
 
- 						// use e.native for backwards compatibility
 
- 						opts.onClick.call(me, e.native, hoveredItem);
 
- 					}
 
- 				} else {
 
- 					if (opts.onLeave && hoveredItem !== me._hoveredItem) {
 
- 						if (me._hoveredItem) {
 
- 							opts.onLeave.call(me, e.native, me._hoveredItem);
 
- 						}
 
- 						me._hoveredItem = hoveredItem;
 
- 					}
 
- 					if (opts.onHover && hoveredItem) {
 
- 						// use e.native for backwards compatibility
 
- 						opts.onHover.call(me, e.native, hoveredItem);
 
- 					}
 
- 				}
 
- 			}
 
- 		});
 
- 		function createNewLegendAndAttach(chart, legendOpts) {
 
- 			var legend = new Legend({
 
- 				ctx: chart.ctx,
 
- 				options: legendOpts,
 
- 				chart: chart
 
- 			});
 
- 			core_layouts.configure(chart, legend, legendOpts);
 
- 			core_layouts.addBox(chart, legend);
 
- 			chart.legend = legend;
 
- 		}
 
- 		var plugin_legend = {
 
- 			id: 'legend',
 
- 			/**
 
- 			 * Backward compatibility: since 2.1.5, the legend is registered as a plugin, making
 
- 			 * Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of
 
- 			 * the plugin, which one will be re-exposed in the chart.js file.
 
- 			 * https://github.com/chartjs/Chart.js/pull/2640
 
- 			 * @private
 
- 			 */
 
- 			_element: Legend,
 
- 			beforeInit: function(chart) {
 
- 				var legendOpts = chart.options.legend;
 
- 				if (legendOpts) {
 
- 					createNewLegendAndAttach(chart, legendOpts);
 
- 				}
 
- 			},
 
- 			beforeUpdate: function(chart) {
 
- 				var legendOpts = chart.options.legend;
 
- 				var legend = chart.legend;
 
- 				if (legendOpts) {
 
- 					helpers$1.mergeIf(legendOpts, core_defaults.global.legend);
 
- 					if (legend) {
 
- 						core_layouts.configure(chart, legend, legendOpts);
 
- 						legend.options = legendOpts;
 
- 					} else {
 
- 						createNewLegendAndAttach(chart, legendOpts);
 
- 					}
 
- 				} else if (legend) {
 
- 					core_layouts.removeBox(chart, legend);
 
- 					delete chart.legend;
 
- 				}
 
- 			},
 
- 			afterEvent: function(chart, e) {
 
- 				var legend = chart.legend;
 
- 				if (legend) {
 
- 					legend.handleEvent(e);
 
- 				}
 
- 			}
 
- 		};
 
- 		var noop$2 = helpers$1.noop;
 
- 		core_defaults._set('global', {
 
- 			title: {
 
- 				display: false,
 
- 				fontStyle: 'bold',
 
- 				fullWidth: true,
 
- 				padding: 10,
 
- 				position: 'top',
 
- 				text: '',
 
- 				weight: 2000         // by default greater than legend (1000) to be above
 
- 			}
 
- 		});
 
- 		/**
 
- 		 * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
 
- 		 */
 
- 		var Title = core_element.extend({
 
- 			initialize: function(config) {
 
- 				var me = this;
 
- 				helpers$1.extend(me, config);
 
- 				// Contains hit boxes for each dataset (in dataset order)
 
- 				me.legendHitBoxes = [];
 
- 			},
 
- 			// These methods are ordered by lifecycle. Utilities then follow.
 
- 			beforeUpdate: noop$2,
 
- 			update: function(maxWidth, maxHeight, margins) {
 
- 				var me = this;
 
- 				// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
 
- 				me.beforeUpdate();
 
- 				// Absorb the master measurements
 
- 				me.maxWidth = maxWidth;
 
- 				me.maxHeight = maxHeight;
 
- 				me.margins = margins;
 
- 				// Dimensions
 
- 				me.beforeSetDimensions();
 
- 				me.setDimensions();
 
- 				me.afterSetDimensions();
 
- 				// Labels
 
- 				me.beforeBuildLabels();
 
- 				me.buildLabels();
 
- 				me.afterBuildLabels();
 
- 				// Fit
 
- 				me.beforeFit();
 
- 				me.fit();
 
- 				me.afterFit();
 
- 				//
 
- 				me.afterUpdate();
 
- 				return me.minSize;
 
- 			},
 
- 			afterUpdate: noop$2,
 
- 			//
 
- 			beforeSetDimensions: noop$2,
 
- 			setDimensions: function() {
 
- 				var me = this;
 
- 				// Set the unconstrained dimension before label rotation
 
- 				if (me.isHorizontal()) {
 
- 					// Reset position before calculating rotation
 
- 					me.width = me.maxWidth;
 
- 					me.left = 0;
 
- 					me.right = me.width;
 
- 				} else {
 
- 					me.height = me.maxHeight;
 
- 					// Reset position before calculating rotation
 
- 					me.top = 0;
 
- 					me.bottom = me.height;
 
- 				}
 
- 				// Reset padding
 
- 				me.paddingLeft = 0;
 
- 				me.paddingTop = 0;
 
- 				me.paddingRight = 0;
 
- 				me.paddingBottom = 0;
 
- 				// Reset minSize
 
- 				me.minSize = {
 
- 					width: 0,
 
- 					height: 0
 
- 				};
 
- 			},
 
- 			afterSetDimensions: noop$2,
 
- 			//
 
- 			beforeBuildLabels: noop$2,
 
- 			buildLabels: noop$2,
 
- 			afterBuildLabels: noop$2,
 
- 			//
 
- 			beforeFit: noop$2,
 
- 			fit: function() {
 
- 				var me = this;
 
- 				var opts = me.options;
 
- 				var minSize = me.minSize = {};
 
- 				var isHorizontal = me.isHorizontal();
 
- 				var lineCount, textSize;
 
- 				if (!opts.display) {
 
- 					me.width = minSize.width = me.height = minSize.height = 0;
 
- 					return;
 
- 				}
 
- 				lineCount = helpers$1.isArray(opts.text) ? opts.text.length : 1;
 
- 				textSize = lineCount * helpers$1.options._parseFont(opts).lineHeight + opts.padding * 2;
 
- 				me.width = minSize.width = isHorizontal ? me.maxWidth : textSize;
 
- 				me.height = minSize.height = isHorizontal ? textSize : me.maxHeight;
 
- 			},
 
- 			afterFit: noop$2,
 
- 			// Shared Methods
 
- 			isHorizontal: function() {
 
- 				var pos = this.options.position;
 
- 				return pos === 'top' || pos === 'bottom';
 
- 			},
 
- 			// Actually draw the title block on the canvas
 
- 			draw: function() {
 
- 				var me = this;
 
- 				var ctx = me.ctx;
 
- 				var opts = me.options;
 
- 				if (!opts.display) {
 
- 					return;
 
- 				}
 
- 				var fontOpts = helpers$1.options._parseFont(opts);
 
- 				var lineHeight = fontOpts.lineHeight;
 
- 				var offset = lineHeight / 2 + opts.padding;
 
- 				var rotation = 0;
 
- 				var top = me.top;
 
- 				var left = me.left;
 
- 				var bottom = me.bottom;
 
- 				var right = me.right;
 
- 				var maxWidth, titleX, titleY;
 
- 				ctx.fillStyle = helpers$1.valueOrDefault(opts.fontColor, core_defaults.global.defaultFontColor); // render in correct colour
 
- 				ctx.font = fontOpts.string;
 
- 				// Horizontal
 
- 				if (me.isHorizontal()) {
 
- 					titleX = left + ((right - left) / 2); // midpoint of the width
 
- 					titleY = top + offset;
 
- 					maxWidth = right - left;
 
- 				} else {
 
- 					titleX = opts.position === 'left' ? left + offset : right - offset;
 
- 					titleY = top + ((bottom - top) / 2);
 
- 					maxWidth = bottom - top;
 
- 					rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
 
- 				}
 
- 				ctx.save();
 
- 				ctx.translate(titleX, titleY);
 
- 				ctx.rotate(rotation);
 
- 				ctx.textAlign = 'center';
 
- 				ctx.textBaseline = 'middle';
 
- 				var text = opts.text;
 
- 				if (helpers$1.isArray(text)) {
 
- 					var y = 0;
 
- 					for (var i = 0; i < text.length; ++i) {
 
- 						ctx.fillText(text[i], 0, y, maxWidth);
 
- 						y += lineHeight;
 
- 					}
 
- 				} else {
 
- 					ctx.fillText(text, 0, 0, maxWidth);
 
- 				}
 
- 				ctx.restore();
 
- 			}
 
- 		});
 
- 		function createNewTitleBlockAndAttach(chart, titleOpts) {
 
- 			var title = new Title({
 
- 				ctx: chart.ctx,
 
- 				options: titleOpts,
 
- 				chart: chart
 
- 			});
 
- 			core_layouts.configure(chart, title, titleOpts);
 
- 			core_layouts.addBox(chart, title);
 
- 			chart.titleBlock = title;
 
- 		}
 
- 		var plugin_title = {
 
- 			id: 'title',
 
- 			/**
 
- 			 * Backward compatibility: since 2.1.5, the title is registered as a plugin, making
 
- 			 * Chart.Title obsolete. To avoid a breaking change, we export the Title as part of
 
- 			 * the plugin, which one will be re-exposed in the chart.js file.
 
- 			 * https://github.com/chartjs/Chart.js/pull/2640
 
- 			 * @private
 
- 			 */
 
- 			_element: Title,
 
- 			beforeInit: function(chart) {
 
- 				var titleOpts = chart.options.title;
 
- 				if (titleOpts) {
 
- 					createNewTitleBlockAndAttach(chart, titleOpts);
 
- 				}
 
- 			},
 
- 			beforeUpdate: function(chart) {
 
- 				var titleOpts = chart.options.title;
 
- 				var titleBlock = chart.titleBlock;
 
- 				if (titleOpts) {
 
- 					helpers$1.mergeIf(titleOpts, core_defaults.global.title);
 
- 					if (titleBlock) {
 
- 						core_layouts.configure(chart, titleBlock, titleOpts);
 
- 						titleBlock.options = titleOpts;
 
- 					} else {
 
- 						createNewTitleBlockAndAttach(chart, titleOpts);
 
- 					}
 
- 				} else if (titleBlock) {
 
- 					core_layouts.removeBox(chart, titleBlock);
 
- 					delete chart.titleBlock;
 
- 				}
 
- 			}
 
- 		};
 
- 		var plugins = {};
 
- 		var filler = plugin_filler;
 
- 		var legend = plugin_legend;
 
- 		var title = plugin_title;
 
- 		plugins.filler = filler;
 
- 		plugins.legend = legend;
 
- 		plugins.title = title;
 
- 		/**
 
- 		 * @namespace Chart
 
- 		 */
 
- 		core_controller.helpers = helpers$1;
 
- 		// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
 
- 		core_helpers();
 
- 		core_controller._adapters = core_adapters;
 
- 		core_controller.Animation = core_animation;
 
- 		core_controller.animationService = core_animations;
 
- 		core_controller.controllers = controllers;
 
- 		core_controller.DatasetController = core_datasetController;
 
- 		core_controller.defaults = core_defaults;
 
- 		core_controller.Element = core_element;
 
- 		core_controller.elements = elements;
 
- 		core_controller.Interaction = core_interaction;
 
- 		core_controller.layouts = core_layouts;
 
- 		core_controller.platform = platform;
 
- 		core_controller.plugins = core_plugins;
 
- 		core_controller.Scale = core_scale;
 
- 		core_controller.scaleService = core_scaleService;
 
- 		core_controller.Ticks = core_ticks;
 
- 		core_controller.Tooltip = core_tooltip;
 
- 		// Register built-in scales
 
- 		core_controller.helpers.each(scales, function(scale, type) {
 
- 			core_controller.scaleService.registerScaleType(type, scale, scale._defaults);
 
- 		});
 
- 		// Load to register built-in adapters (as side effects)
 
- 		// Loading built-in plugins
 
- 		for (var k in plugins) {
 
- 			if (plugins.hasOwnProperty(k)) {
 
- 				core_controller.plugins.register(plugins[k]);
 
- 			}
 
- 		}
 
- 		core_controller.platform.initialize();
 
- 		var src = core_controller;
 
- 		if (typeof window !== 'undefined') {
 
- 			window.Chart = core_controller;
 
- 		}
 
- 		// DEPRECATIONS
 
- 		/**
 
- 		 * Provided for backward compatibility, not available anymore
 
- 		 * @namespace Chart.Chart
 
- 		 * @deprecated since version 2.8.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		core_controller.Chart = core_controller;
 
- 		/**
 
- 		 * Provided for backward compatibility, not available anymore
 
- 		 * @namespace Chart.Legend
 
- 		 * @deprecated since version 2.1.5
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		core_controller.Legend = plugins.legend._element;
 
- 		/**
 
- 		 * Provided for backward compatibility, not available anymore
 
- 		 * @namespace Chart.Title
 
- 		 * @deprecated since version 2.1.5
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		core_controller.Title = plugins.title._element;
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.plugins instead
 
- 		 * @namespace Chart.pluginService
 
- 		 * @deprecated since version 2.1.5
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		core_controller.pluginService = core_controller.plugins;
 
- 		/**
 
- 		 * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
 
- 		 * effect, instead simply create/register plugins via plain JavaScript objects.
 
- 		 * @interface Chart.PluginBase
 
- 		 * @deprecated since version 2.5.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		core_controller.PluginBase = core_controller.Element.extend({});
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.helpers.canvas instead.
 
- 		 * @namespace Chart.canvasHelpers
 
- 		 * @deprecated since version 2.6.0
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		core_controller.canvasHelpers = core_controller.helpers.canvas;
 
- 		/**
 
- 		 * Provided for backward compatibility, use Chart.layouts instead.
 
- 		 * @namespace Chart.layoutService
 
- 		 * @deprecated since version 2.7.3
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		core_controller.layoutService = core_controller.layouts;
 
- 		/**
 
- 		 * Provided for backward compatibility, not available anymore.
 
- 		 * @namespace Chart.LinearScaleBase
 
- 		 * @deprecated since version 2.8
 
- 		 * @todo remove at version 3
 
- 		 * @private
 
- 		 */
 
- 		core_controller.LinearScaleBase = scale_linearbase;
 
- 		/**
 
- 		 * Provided for backward compatibility, instead we should create a new Chart
 
- 		 * by setting the type in the config (`new Chart(id, {type: '{chart-type}'}`).
 
- 		 * @deprecated since version 2.8.0
 
- 		 * @todo remove at version 3
 
- 		 */
 
- 		core_controller.helpers.each(
 
- 			[
 
- 				'Bar',
 
- 				'Bubble',
 
- 				'Doughnut',
 
- 				'Line',
 
- 				'PolarArea',
 
- 				'Radar',
 
- 				'Scatter'
 
- 			],
 
- 			function(klass) {
 
- 				core_controller[klass] = function(ctx, cfg) {
 
- 					return new core_controller(ctx, core_controller.helpers.merge(cfg || {}, {
 
- 						type: klass.charAt(0).toLowerCase() + klass.slice(1)
 
- 					}));
 
- 				};
 
- 			}
 
- 		);
 
- 		return src;
 
- 		}))); 
 
- 	} (Chart$1));
 
- 	var ChartExports = Chart$1.exports;
 
- 	var Chart = /*@__PURE__*/getDefaultExportFromCjs(ChartExports);
 
- 	// Modify horizontalBar so that each dataset (fragments, timeRanges) draws on the same row (level, track or buffer)
 
- 	Chart.controllers.horizontalBar.prototype.calculateBarValuePixels = function (datasetIndex, index, options) {
 
- 	  var chart = this.chart;
 
- 	  var scale = this._getValueScale();
 
- 	  var datasets = chart.data.datasets;
 
- 	  if (!datasets) {
 
- 	    throw new Error("Chart datasets are " + datasets);
 
- 	  }
 
- 	  scale._parseValue = scaleParseValue;
 
- 	  var obj = datasets[datasetIndex].data[index];
 
- 	  var value = scale._parseValue(obj);
 
- 	  var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max;
 
- 	  var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max;
 
- 	  var base = scale.getPixelForValue(start);
 
- 	  var head = scale.getPixelForValue(start + length);
 
- 	  var size = head - base;
 
- 	  return {
 
- 	    size: size,
 
- 	    base: base,
 
- 	    head: head,
 
- 	    center: head + size / 2
 
- 	  };
 
- 	};
 
- 	Chart.controllers.horizontalBar.prototype.calculateBarIndexPixels = function (datasetIndex, index, ruler, options) {
 
- 	  var rowHeight = options.barThickness;
 
- 	  var size = rowHeight * options.categoryPercentage;
 
- 	  var center = ruler.start + (datasetIndex * rowHeight + rowHeight / 2);
 
- 	  return {
 
- 	    base: center - size / 2,
 
- 	    head: center + size / 2,
 
- 	    center: center,
 
- 	    size: size
 
- 	  };
 
- 	};
 
- 	Chart.controllers.horizontalBar.prototype.draw = function () {
 
- 	  var rects = this.getMeta().data;
 
- 	  var len = rects.length;
 
- 	  var dataset = this.getDataset();
 
- 	  if (len !== dataset.data.length) {
 
- 	    // View does not match dataset (wait for redraw)
 
- 	    return;
 
- 	  }
 
- 	  var chart = this.chart;
 
- 	  var scale = this._getValueScale();
 
- 	  scale._parseValue = scaleParseValue;
 
- 	  var ctx = chart.ctx;
 
- 	  var chartArea = chart.chartArea;
 
- 	  Chart.helpers.canvas.clipArea(ctx, chartArea);
 
- 	  if (!this.lineHeight) {
 
- 	    this.lineHeight = Math.ceil(ctx.measureText('0').actualBoundingBoxAscent) + 2;
 
- 	  }
 
- 	  var lineHeight = this.lineHeight;
 
- 	  var range = 0;
 
- 	  for (var i = 0; i < len; ++i) {
 
- 	    var rect = rects[i];
 
- 	    var view = rect._view;
 
- 	    if (!intersects(view.base, view.x, chartArea.left, chartArea.right)) {
 
- 	      // Do not draw elements outside of the chart's viewport
 
- 	      continue;
 
- 	    }
 
- 	    var obj = dataset.data[i];
 
- 	    var val = scale._parseValue(obj);
 
- 	    if (!isNaN(val.min) && !isNaN(val.max)) {
 
- 	      var dataType = obj.dataType;
 
- 	      var stats = obj.stats;
 
- 	      var isPart = dataType === 'part';
 
- 	      var isFragmentHint = dataType === 'fragmentHint';
 
- 	      var isFragment = dataType === 'fragment' || isPart || isFragmentHint;
 
- 	      var isCue = dataType === 'cue';
 
- 	      if (isCue) {
 
- 	        view.y += view.height * 0.5 * (i % 2) - view.height * 0.25;
 
- 	      } else if (isPart) {
 
- 	        view.height -= 22;
 
- 	      }
 
- 	      var bounds = boundingRects(view);
 
- 	      var drawText = bounds.w > lineHeight * 1.5 && !isFragmentHint;
 
- 	      if (isFragment || isCue) {
 
- 	        if (drawText) {
 
- 	          view.borderWidth = 1;
 
- 	          if (i === 0) {
 
- 	            view.borderSkipped = false;
 
- 	          }
 
- 	        } else {
 
- 	          range = range || scale.getValueForPixel(chartArea.right) - scale.getValueForPixel(chartArea.left);
 
- 	          if (range > 300 || isCue) {
 
- 	            view.borderWidth = 0;
 
- 	          }
 
- 	        }
 
- 	        if (isFragmentHint) {
 
- 	          view.borderWidth = 0;
 
- 	          view.backgroundColor = 'rgba(0, 0, 0, 0.1)';
 
- 	        } else {
 
- 	          view.backgroundColor = "rgba(0, 0, 0, " + (0.05 + i % 2 / 12) + ")";
 
- 	        }
 
- 	      }
 
- 	      rect.draw();
 
- 	      if (isFragment) {
 
- 	        if (!stats) {
 
- 	          stats = {};
 
- 	        }
 
- 	        if (isPart) {
 
- 	          ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
 
- 	          ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);
 
- 	        }
 
- 	        if (stats.aborted) {
 
- 	          ctx.fillStyle = 'rgba(100, 0, 0, 0.3)';
 
- 	          ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);
 
- 	        }
 
- 	        if (stats.loaded && stats.total) {
 
- 	          ctx.fillStyle = 'rgba(50, 20, 100, 0.3)';
 
- 	          ctx.fillRect(bounds.x, bounds.y, bounds.w * stats.loaded / stats.total, bounds.h);
 
- 	        }
 
- 	      } else if (isCue) {
 
- 	        if (obj.active) {
 
- 	          ctx.fillStyle = 'rgba(100, 100, 10, 0.4)';
 
- 	          ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);
 
- 	        }
 
- 	      }
 
- 	      if (drawText) {
 
- 	        var start = val.start; // obj.start;
 
- 	        ctx.fillStyle = 'rgb(0, 0, 0)';
 
- 	        if (stats) {
 
- 	          var snBounds = _extends({}, bounds);
 
- 	          if (obj.cc) {
 
- 	            var ccLabel = "cc:" + obj.cc;
 
- 	            var ccWidth = Math.min(ctx.measureText(ccLabel).width + 2, snBounds.w / 2 - 2);
 
- 	            if (ccWidth) {
 
- 	              ctx.fillText(ccLabel, snBounds.x + 2, snBounds.y + lineHeight, snBounds.w / 2 - 4);
 
- 	              snBounds.x += ccWidth;
 
- 	              snBounds.w -= ccWidth;
 
- 	            }
 
- 	          }
 
- 	          var snLabel = isPart ? "part: " + obj.index : "sn: " + obj.sn;
 
- 	          var textWidth = Math.min(ctx.measureText(snLabel).width + 2, snBounds.w - 2);
 
- 	          ctx.fillText(snLabel, snBounds.x + snBounds.w - textWidth, snBounds.y + lineHeight, snBounds.w - 4);
 
- 	        }
 
- 	        if (isCue) {
 
- 	          var strLength = Math.min(30, Math.ceil(bounds.w / (lineHeight / 3)));
 
- 	          ctx.fillText(('' + obj.content).slice(0, strLength), bounds.x + 2, bounds.y + bounds.h - 3, bounds.w - 5);
 
- 	        } else if (!isPart) {
 
- 	          var _float = start !== (start | 0);
 
- 	          var fixedDigits = _float ? Math.min(5, Math.max(1, Math.floor(bounds.w / 10 - 1))) : 0;
 
- 	          var startString = hhmmss(start, fixedDigits);
 
- 	          ctx.fillText(startString, bounds.x + 2, bounds.y + bounds.h - 3, bounds.w - 5);
 
- 	        }
 
- 	      }
 
- 	    }
 
- 	  }
 
- 	  Chart.helpers.canvas.unclipArea(chart.ctx);
 
- 	};
 
- 	function applyChartInstanceOverrides(chart) {
 
- 	  Object.keys(chart.scales).forEach(function (axis) {
 
- 	    var scale = chart.scales[axis];
 
- 	    scale._parseValue = scaleParseValue;
 
- 	  });
 
- 	}
 
- 	function scaleParseValue(value) {
 
- 	  if (value === undefined) {
 
- 	    console.warn('Chart values undefined (update chart)');
 
- 	    return {};
 
- 	  }
 
- 	  var start;
 
- 	  var end;
 
- 	  var min;
 
- 	  var max;
 
- 	  if (Array.isArray(value)) {
 
- 	    start = +this.getRightValue(value[0]);
 
- 	    end = +this.getRightValue(value[1]);
 
- 	    min = Math.min(start, end);
 
- 	    max = Math.max(start, end);
 
- 	  } else {
 
- 	    start = +this.getRightValue(value.start);
 
- 	    if ('end' in value) {
 
- 	      end = +this.getRightValue(value.end);
 
- 	    } else {
 
- 	      end = +this.getRightValue(value.start + value.duration);
 
- 	    }
 
- 	    min = Math.min(start, end);
 
- 	    max = Math.max(start, end);
 
- 	  }
 
- 	  return {
 
- 	    min: min,
 
- 	    max: max,
 
- 	    start: start,
 
- 	    end: end
 
- 	  };
 
- 	}
 
- 	function intersects(x1, x2, x3, x4) {
 
- 	  return x2 > x3 && x1 < x4;
 
- 	}
 
- 	function boundingRects(vm) {
 
- 	  var half = vm.height / 2;
 
- 	  var left = Math.min(vm.x, vm.base);
 
- 	  var right = Math.max(vm.x, vm.base);
 
- 	  var top = vm.y - half;
 
- 	  var bottom = vm.y + half;
 
- 	  return {
 
- 	    x: left,
 
- 	    y: top,
 
- 	    w: right - left,
 
- 	    h: bottom - top
 
- 	  };
 
- 	}
 
- 	function hhmmss(value, fixedDigits) {
 
- 	  var h = value / 3600 | 0;
 
- 	  var m = (value / 60 | 0) % 60;
 
- 	  var s = value % 60;
 
- 	  return (h + ":" + pad(m, 2) + ":" + pad(s.toFixed(fixedDigits), fixedDigits ? fixedDigits + 3 : 2)).replace(/^(?:0+:?)*(\d.*?)(?:\.0*)?$/, '$1');
 
- 	}
 
- 	function pad(str, length) {
 
- 	  str = '' + str;
 
- 	  while (str.length < length) {
 
- 	    str = '0' + str;
 
- 	  }
 
- 	  return str;
 
- 	}
 
- 	var X_AXIS_SECONDS = 'x-axis-seconds';
 
- 	var TimelineChart = /*#__PURE__*/function () {
 
- 	  function TimelineChart(canvas, chartJsOptions) {
 
- 	    var _this = this;
 
- 	    this.chart = void 0;
 
- 	    this.rafDebounceRequestId = -1;
 
- 	    this.imageDataBuffer = null;
 
- 	    this.media = null;
 
- 	    this.tracksChangeHandler = void 0;
 
- 	    this.cuesChangeHandler = void 0;
 
- 	    this.hidden = true;
 
- 	    this.zoom100 = 60;
 
- 	    var ctx = canvas.getContext('2d');
 
- 	    if (!ctx) {
 
- 	      throw new Error("Could not get CanvasRenderingContext2D from canvas: " + canvas);
 
- 	    }
 
- 	    var chart = this.chart = self.chart = new Chart(ctx, {
 
- 	      type: 'horizontalBar',
 
- 	      data: {
 
- 	        labels: [],
 
- 	        datasets: []
 
- 	      },
 
- 	      options: _extends(getChartOptions(), chartJsOptions),
 
- 	      plugins: [{
 
- 	        afterRender: function afterRender(chart) {
 
- 	          _this.imageDataBuffer = null;
 
- 	          _this.drawCurrentTime();
 
- 	        }
 
- 	      }]
 
- 	    });
 
- 	    applyChartInstanceOverrides(chart);
 
- 	    canvas.ondblclick = function (event) {
 
- 	      var chart = _this.chart;
 
- 	      var chartArea = chart.chartArea;
 
- 	      var element = chart.getElementAtEvent(event);
 
- 	      var pos = Chart.helpers.getRelativePosition(event, chart);
 
- 	      var scale = _this.chartScales[X_AXIS_SECONDS];
 
- 	      // zoom in when double clicking near elements in chart area
 
- 	      if (element.length || pos.x > chartArea.left) {
 
- 	        var amount = event.getModifierState('Shift') ? -1.0 : 0.5;
 
- 	        _this.zoom(scale, pos, amount);
 
- 	      } else {
 
- 	        scale.options.ticks.min = 0;
 
- 	        scale.options.ticks.max = _this.zoom100;
 
- 	      }
 
- 	      _this.update();
 
- 	    };
 
- 	    canvas.onwheel = function (event) {
 
- 	      if (event.deltaMode) {
 
- 	        // exit if wheel is in page or line scrolling mode
 
- 	        return;
 
- 	      }
 
- 	      var chart = _this.chart;
 
- 	      var chartArea = chart.chartArea;
 
- 	      var pos = Chart.helpers.getRelativePosition(event, chart);
 
- 	      // zoom when scrolling over chart elements
 
- 	      if (pos.x > chartArea.left - 11) {
 
- 	        var scale = _this.chartScales[X_AXIS_SECONDS];
 
- 	        if (event.deltaY) {
 
- 	          var direction = -event.deltaY / Math.abs(event.deltaY);
 
- 	          var normal = Math.min(333, Math.abs(event.deltaY)) / 1000;
 
- 	          var ease = 1 - (1 - normal) * (1 - normal);
 
- 	          _this.zoom(scale, pos, ease * direction);
 
- 	        } else if (event.deltaX) {
 
- 	          _this.pan(scale, event.deltaX / 10, scale.min, scale.max);
 
- 	        }
 
- 	        event.preventDefault();
 
- 	      }
 
- 	    };
 
- 	    var moved = false;
 
- 	    var gestureScale = 1;
 
- 	    canvas.onpointerdown = function (downEvent) {
 
- 	      if (!downEvent.isPrimary || gestureScale !== 1) {
 
- 	        return;
 
- 	      }
 
- 	      var chart = _this.chart;
 
- 	      var chartArea = chart.chartArea;
 
- 	      var pos = Chart.helpers.getRelativePosition(downEvent, chart);
 
- 	      // pan when dragging over chart elements
 
- 	      if (pos.x > chartArea.left) {
 
- 	        var scale = _this.chartScales[X_AXIS_SECONDS];
 
- 	        var startX = downEvent.clientX;
 
- 	        var min = scale.min,
 
- 	          max = scale.max;
 
- 	        var xToVal = (max - min) / scale.width;
 
- 	        moved = false;
 
- 	        canvas.setPointerCapture(downEvent.pointerId);
 
- 	        canvas.onpointermove = function (moveEvent) {
 
- 	          if (!downEvent.isPrimary || gestureScale !== 1) {
 
- 	            return;
 
- 	          }
 
- 	          var movedX = startX - moveEvent.clientX;
 
- 	          var movedValue = movedX * xToVal;
 
- 	          moved = moved || Math.abs(movedX) > 8;
 
- 	          _this.pan(scale, movedValue, min, max);
 
- 	        };
 
- 	      }
 
- 	    };
 
- 	    canvas.onpointerup = canvas.onpointercancel = function (upEvent) {
 
- 	      if (canvas.onpointermove) {
 
- 	        canvas.onpointermove = null;
 
- 	        canvas.releasePointerCapture(upEvent.pointerId);
 
- 	      }
 
- 	      if (!moved && upEvent.isPrimary) {
 
- 	        _this.click(upEvent);
 
- 	      }
 
- 	    };
 
- 	    // Gesture events are for iOS and easier to implement than pinch-zoom with multiple pointers for all browsers
 
- 	    // @ts-ignore
 
- 	    canvas.ongesturestart = function (event) {
 
- 	      gestureScale = 1;
 
- 	      event.preventDefault();
 
- 	    };
 
- 	    // @ts-ignore
 
- 	    canvas.ongestureend = function (event) {
 
- 	      gestureScale = 1;
 
- 	    };
 
- 	    // @ts-ignore
 
- 	    canvas.ongesturechange = function (event) {
 
- 	      var chart = _this.chart;
 
- 	      var chartArea = chart.chartArea;
 
- 	      var pos = Chart.helpers.getRelativePosition(event, chart);
 
- 	      // zoom when scrolling over chart elements
 
- 	      if (pos.x > chartArea.left) {
 
- 	        var scale = _this.chartScales[X_AXIS_SECONDS];
 
- 	        var amount = event.scale - gestureScale;
 
- 	        _this.zoom(scale, pos, amount);
 
- 	        gestureScale = event.scale;
 
- 	      }
 
- 	    };
 
- 	  }
 
- 	  var _proto = TimelineChart.prototype;
 
- 	  _proto.click = function click(event) {
 
- 	    // Log object on click and seek to position
 
- 	    var chart = this.chart;
 
- 	    var element = chart.getElementAtEvent(event);
 
- 	    if (element.length && chart.data.datasets) {
 
- 	      var _self$hls;
 
- 	      var dataset = chart.data.datasets[element[0]._datasetIndex];
 
- 	      var obj = dataset.data[element[0]._index];
 
- 	      // eslint-disable-next-line no-console
 
- 	      console.log(obj);
 
- 	      if ((_self$hls = self.hls) != null && _self$hls.media) {
 
- 	        var scale = this.chartScales[X_AXIS_SECONDS];
 
- 	        var pos = Chart.helpers.getRelativePosition(event, chart);
 
- 	        self.hls.media.currentTime = scale.getValueForPixel(pos.x);
 
- 	      }
 
- 	    }
 
- 	  };
 
- 	  _proto.pan = function pan(scale, amount, min, max) {
 
- 	    if (amount === 0) {
 
- 	      return;
 
- 	    }
 
- 	    var pan = amount;
 
- 	    if (amount > 0) {
 
- 	      pan = Math.min(this.zoom100 + 10 - max, amount);
 
- 	    } else {
 
- 	      pan = Math.max(-10 - min, amount);
 
- 	    }
 
- 	    scale.options.ticks.min = min + pan;
 
- 	    scale.options.ticks.max = max + pan;
 
- 	    this.updateOnRepaint();
 
- 	  };
 
- 	  _proto.zoom = function zoom(scale, pos, amount) {
 
- 	    var range = scale.max - scale.min;
 
- 	    var diff = range * amount;
 
- 	    var minPercent = (scale.getValueForPixel(pos.x) - scale.min) / range;
 
- 	    var maxPercent = 1 - minPercent;
 
- 	    var minDelta = diff * minPercent;
 
- 	    var maxDelta = diff * maxPercent;
 
- 	    scale.options.ticks.min = Math.max(-10, scale.min + minDelta);
 
- 	    scale.options.ticks.max = Math.min(this.zoom100 + 10, scale.max - maxDelta);
 
- 	    this.updateOnRepaint();
 
- 	  };
 
- 	  _proto.reset = function reset() {
 
- 	    var scale = this.chartScales[X_AXIS_SECONDS];
 
- 	    scale.options.ticks.min = 0;
 
- 	    scale.options.ticks.max = 60;
 
- 	    var _this$chart$data = this.chart.data,
 
- 	      labels = _this$chart$data.labels,
 
- 	      datasets = _this$chart$data.datasets;
 
- 	    if (labels && datasets) {
 
- 	      labels.length = 0;
 
- 	      datasets.length = 0;
 
- 	      this.resize(datasets);
 
- 	    }
 
- 	  };
 
- 	  _proto.update = function update() {
 
- 	    var _this$chart$ctx;
 
- 	    if (this.hidden || !((_this$chart$ctx = this.chart.ctx) != null && _this$chart$ctx.canvas.width)) {
 
- 	      return;
 
- 	    }
 
- 	    self.cancelAnimationFrame(this.rafDebounceRequestId);
 
- 	    this.chart.update({
 
- 	      duration: 0,
 
- 	      lazy: true
 
- 	    });
 
- 	  };
 
- 	  _proto.updateOnRepaint = function updateOnRepaint() {
 
- 	    var _this2 = this;
 
- 	    if (this.hidden) {
 
- 	      return;
 
- 	    }
 
- 	    self.cancelAnimationFrame(this.rafDebounceRequestId);
 
- 	    this.rafDebounceRequestId = self.requestAnimationFrame(function () {
 
- 	      return _this2.update();
 
- 	    });
 
- 	  };
 
- 	  _proto.resize = function resize(datasets) {
 
- 	    var _this3 = this;
 
- 	    if (this.hidden) {
 
- 	      return;
 
- 	    }
 
- 	    if (datasets != null && datasets.length) {
 
- 	      var _this$chart$canvas;
 
- 	      var scale = this.chartScales[X_AXIS_SECONDS];
 
- 	      var top = this.chart.chartArea.top;
 
- 	      var height = top + datasets.reduce(function (val, dataset) {
 
- 	        return val + dataset.barThickness;
 
- 	      }, 0) + scale.height + 5;
 
- 	      var container = (_this$chart$canvas = this.chart.canvas) == null ? void 0 : _this$chart$canvas.parentElement;
 
- 	      if (container) {
 
- 	        container.style.height = height + "px";
 
- 	      }
 
- 	    }
 
- 	    self.cancelAnimationFrame(this.rafDebounceRequestId);
 
- 	    this.rafDebounceRequestId = self.requestAnimationFrame(function () {
 
- 	      _this3.chart.resize();
 
- 	    });
 
- 	  };
 
- 	  _proto.show = function show() {
 
- 	    this.hidden = false;
 
- 	  };
 
- 	  _proto.hide = function hide() {
 
- 	    this.hidden = true;
 
- 	  };
 
- 	  _proto.updateLevels = function updateLevels(levels, levelSwitched) {
 
- 	    var _this4 = this;
 
- 	    var _this$chart$data2 = this.chart.data,
 
- 	      labels = _this$chart$data2.labels,
 
- 	      datasets = _this$chart$data2.datasets;
 
- 	    if (!labels || !datasets) {
 
- 	      return;
 
- 	    }
 
- 	    var _self$hls2 = self.hls,
 
- 	      loadLevel = _self$hls2.loadLevel,
 
- 	      nextLoadLevel = _self$hls2.nextLoadLevel,
 
- 	      nextAutoLevel = _self$hls2.nextAutoLevel;
 
- 	    // eslint-disable-next-line no-undefined
 
- 	    var currentLevel = levelSwitched !== undefined ? levelSwitched : self.hls.currentLevel;
 
- 	    levels.forEach(function (level, i) {
 
- 	      var index = level.id || i;
 
- 	      labels.push(getLevelName(level, index));
 
- 	      var borderColor = null;
 
- 	      if (currentLevel === i) {
 
- 	        borderColor = 'rgba(32, 32, 240, 1.0)';
 
- 	      } else if (loadLevel === i) {
 
- 	        borderColor = 'rgba(255, 128, 0, 1.0)';
 
- 	      } else if (nextLoadLevel === i) {
 
- 	        borderColor = 'rgba(200, 200, 64, 1.0)';
 
- 	      } else if (nextAutoLevel === i) {
 
- 	        borderColor = 'rgba(160, 0, 160, 1.0)';
 
- 	      }
 
- 	      datasets.push(datasetWithDefaults({
 
- 	        url: Array.isArray(level.url) ? level.url[level.urlId || 0] : level.url,
 
- 	        trackType: 'level',
 
- 	        borderColor: borderColor,
 
- 	        level: index
 
- 	      }));
 
- 	      if (level.details) {
 
- 	        _this4.updateLevelOrTrack(level.details);
 
- 	      }
 
- 	    });
 
- 	    this.resize(datasets);
 
- 	  };
 
- 	  _proto.updateAudioTracks = function updateAudioTracks(audioTracks) {
 
- 	    var _this5 = this;
 
- 	    var _this$chart$data3 = this.chart.data,
 
- 	      labels = _this$chart$data3.labels,
 
- 	      datasets = _this$chart$data3.datasets;
 
- 	    if (!labels || !datasets) {
 
- 	      return;
 
- 	    }
 
- 	    var audioTrack = self.hls.audioTrack;
 
- 	    audioTracks.forEach(function (track, i) {
 
- 	      labels.push(getAudioTrackName(track, i));
 
- 	      datasets.push(datasetWithDefaults({
 
- 	        url: track.url,
 
- 	        trackType: 'audioTrack',
 
- 	        borderColor: audioTrack === i ? 'rgba(32, 32, 240, 1.0)' : null,
 
- 	        audioTrack: i
 
- 	      }));
 
- 	      if (track.details) {
 
- 	        _this5.updateLevelOrTrack(track.details);
 
- 	      }
 
- 	    });
 
- 	    this.resize(datasets);
 
- 	  };
 
- 	  _proto.updateSubtitleTracks = function updateSubtitleTracks(subtitles) {
 
- 	    var _this6 = this;
 
- 	    var _this$chart$data4 = this.chart.data,
 
- 	      labels = _this$chart$data4.labels,
 
- 	      datasets = _this$chart$data4.datasets;
 
- 	    if (!labels || !datasets) {
 
- 	      return;
 
- 	    }
 
- 	    var subtitleTrack = self.hls.subtitleTrack;
 
- 	    subtitles.forEach(function (track, i) {
 
- 	      labels.push(getSubtitlesName(track, i));
 
- 	      datasets.push(datasetWithDefaults({
 
- 	        url: track.url,
 
- 	        trackType: 'subtitleTrack',
 
- 	        borderColor: subtitleTrack === i ? 'rgba(32, 32, 240, 1.0)' : null,
 
- 	        subtitleTrack: i
 
- 	      }));
 
- 	      if (track.details) {
 
- 	        _this6.updateLevelOrTrack(track.details);
 
- 	      }
 
- 	    });
 
- 	    this.resize(datasets);
 
- 	  };
 
- 	  _proto.removeType = function removeType(trackType) {
 
- 	    var _this$chart$data5 = this.chart.data,
 
- 	      labels = _this$chart$data5.labels,
 
- 	      datasets = _this$chart$data5.datasets;
 
- 	    if (!labels || !datasets) {
 
- 	      return;
 
- 	    }
 
- 	    var i = datasets.length;
 
- 	    while (i--) {
 
- 	      if (datasets[i].trackType === trackType) {
 
- 	        datasets.splice(i, 1);
 
- 	        labels.splice(i, 1);
 
- 	      }
 
- 	    }
 
- 	  };
 
- 	  _proto.updateLevelOrTrack = function updateLevelOrTrack(details) {
 
- 	    var targetduration = details.targetduration,
 
- 	      totalduration = details.totalduration,
 
- 	      url = details.url;
 
- 	    var datasets = this.chart.data.datasets;
 
- 	    var levelDataSet = arrayFind(datasets, function (dataset) {
 
- 	      return stripDeliveryDirectives(url) === stripDeliveryDirectives(dataset.url || '');
 
- 	    });
 
- 	    if (!levelDataSet) {
 
- 	      levelDataSet = arrayFind(datasets, function (dataset) {
 
- 	        var _details$fragments$;
 
- 	        return ((_details$fragments$ = details.fragments[0]) == null ? void 0 : _details$fragments$.level) === dataset.level;
 
- 	      });
 
- 	    }
 
- 	    if (!levelDataSet) {
 
- 	      return;
 
- 	    }
 
- 	    var data = levelDataSet.data;
 
- 	    data.length = 0;
 
- 	    if (details.fragments) {
 
- 	      details.fragments.forEach(function (fragment) {
 
- 	        // TODO: keep track of initial playlist start and duration so that we can show drift and pts offset
 
- 	        // (Make that a feature of hls.js v1.0.0 fragments)
 
- 	        var chartFragment = _extends({
 
- 	          dataType: 'fragment'
 
- 	        }, fragment,
 
- 	        // Remove loader references for GC
 
- 	        {
 
- 	          loader: null
 
- 	        });
 
- 	        data.push(chartFragment);
 
- 	      });
 
- 	    }
 
- 	    if (details.partList) {
 
- 	      details.partList.forEach(function (part) {
 
- 	        var chartPart = _extends({
 
- 	          dataType: 'part',
 
- 	          start: part.fragment.start + part.fragOffset
 
- 	        }, part, {
 
- 	          fragment: _extends({}, part.fragment, {
 
- 	            loader: null
 
- 	          })
 
- 	        });
 
- 	        data.push(chartPart);
 
- 	      });
 
- 	      if (details.fragmentHint) {
 
- 	        var chartFragment = _extends({
 
- 	          dataType: 'fragmentHint'
 
- 	        }, details.fragmentHint,
 
- 	        // Remove loader references for GC
 
- 	        {
 
- 	          loader: null
 
- 	        });
 
- 	        data.push(chartFragment);
 
- 	      }
 
- 	    }
 
- 	    var start = getPlaylistStart(details);
 
- 	    this.maxZoom = this.zoom100 = Math.max(start + totalduration + targetduration * 3, this.zoom100);
 
- 	    this.updateOnRepaint();
 
- 	  }
 
- 	  // @ts-ignore
 
- 	  ;
 
- 	  _proto.updateFragment = function updateFragment(data) {
 
- 	    var datasets = this.chart.data.datasets;
 
- 	    var frag = data.frag;
 
- 	    var levelDataSet = arrayFind(datasets, function (dataset) {
 
- 	      return frag.baseurl === dataset.url;
 
- 	    });
 
- 	    if (!levelDataSet) {
 
- 	      levelDataSet = arrayFind(datasets, function (dataset) {
 
- 	        return frag.level === dataset.level;
 
- 	      });
 
- 	    }
 
- 	    if (!levelDataSet) {
 
- 	      return;
 
- 	    }
 
- 	    // eslint-disable-next-line no-restricted-properties
 
- 	    var fragData = arrayFind(levelDataSet.data, function (fragData) {
 
- 	      return fragData.relurl === frag.relurl && fragData.sn === frag.sn;
 
- 	    });
 
- 	    if (fragData && fragData !== frag) {
 
- 	      _extends(fragData, frag);
 
- 	    }
 
- 	    this.updateOnRepaint();
 
- 	  };
 
- 	  _proto.updateSourceBuffers = function updateSourceBuffers(tracks, media) {
 
- 	    var _this7 = this;
 
- 	    var _this$chart$data6 = this.chart.data,
 
- 	      labels = _this$chart$data6.labels,
 
- 	      datasets = _this$chart$data6.datasets;
 
- 	    if (!labels || !datasets) {
 
- 	      return;
 
- 	    }
 
- 	    var trackTypes = Object.keys(tracks).sort(function (type) {
 
- 	      return type === 'video' ? 1 : -1;
 
- 	    });
 
- 	    var mediaBufferData = [];
 
- 	    this.removeSourceBuffers();
 
- 	    this.media = media;
 
- 	    trackTypes.forEach(function (type) {
 
- 	      var track = tracks[type];
 
- 	      var data = [];
 
- 	      var sourceBuffer = track.buffer;
 
- 	      var backgroundColor = {
 
- 	        video: 'rgba(0, 0, 255, 0.2)',
 
- 	        audio: 'rgba(128, 128, 0, 0.2)',
 
- 	        audiovideo: 'rgba(128, 128, 255, 0.2)'
 
- 	      }[type];
 
- 	      labels.unshift(type + " buffer (" + track.id + ")");
 
- 	      datasets.unshift(datasetWithDefaults({
 
- 	        data: data,
 
- 	        categoryPercentage: 0.5,
 
- 	        backgroundColor: backgroundColor,
 
- 	        sourceBuffer: sourceBuffer
 
- 	      }));
 
- 	      sourceBuffer.addEventListener('update', function () {
 
- 	        try {
 
- 	          replaceTimeRangeTuples(sourceBuffer.buffered, data);
 
- 	        } catch (error) {
 
- 	          // eslint-disable-next-line no-console
 
- 	          console.warn(error);
 
- 	          return;
 
- 	        }
 
- 	        replaceTimeRangeTuples(media.buffered, mediaBufferData);
 
- 	        _this7.update();
 
- 	      });
 
- 	    });
 
- 	    if (trackTypes.length === 0) {
 
- 	      media.onprogress = function () {
 
- 	        replaceTimeRangeTuples(media.buffered, mediaBufferData);
 
- 	        _this7.update();
 
- 	      };
 
- 	    }
 
- 	    labels.unshift('media buffer');
 
- 	    datasets.unshift(datasetWithDefaults({
 
- 	      data: mediaBufferData,
 
- 	      categoryPercentage: 0.5,
 
- 	      backgroundColor: 'rgba(0, 255, 0, 0.2)',
 
- 	      media: media
 
- 	    }));
 
- 	    media.ontimeupdate = function () {
 
- 	      return _this7.drawCurrentTime();
 
- 	    };
 
- 	    // TextTrackList
 
- 	    var textTracks = media.textTracks;
 
- 	    this.tracksChangeHandler = this.tracksChangeHandler || function (e) {
 
- 	      return _this7.setTextTracks(e.currentTarget);
 
- 	    };
 
- 	    textTracks.removeEventListener('addtrack', this.tracksChangeHandler);
 
- 	    textTracks.removeEventListener('removetrack', this.tracksChangeHandler);
 
- 	    textTracks.removeEventListener('change', this.tracksChangeHandler);
 
- 	    textTracks.addEventListener('addtrack', this.tracksChangeHandler);
 
- 	    textTracks.addEventListener('removetrack', this.tracksChangeHandler);
 
- 	    textTracks.addEventListener('change', this.tracksChangeHandler);
 
- 	    this.setTextTracks(textTracks);
 
- 	    this.resize(datasets);
 
- 	  };
 
- 	  _proto.removeSourceBuffers = function removeSourceBuffers() {
 
- 	    var _this$chart$data7 = this.chart.data,
 
- 	      labels = _this$chart$data7.labels,
 
- 	      datasets = _this$chart$data7.datasets;
 
- 	    if (!labels || !datasets) {
 
- 	      return;
 
- 	    }
 
- 	    var i = datasets.length;
 
- 	    while (i--) {
 
- 	      if ((labels[0] || '').toString().indexOf('buffer') > -1) {
 
- 	        datasets.splice(i, 1);
 
- 	        labels.splice(i, 1);
 
- 	      }
 
- 	    }
 
- 	  };
 
- 	  _proto.setTextTracks = function setTextTracks(textTracks) {
 
- 	    var _this8 = this;
 
- 	    var _this$chart$data8 = this.chart.data,
 
- 	      labels = _this$chart$data8.labels,
 
- 	      datasets = _this$chart$data8.datasets;
 
- 	    if (!labels || !datasets) {
 
- 	      return;
 
- 	    }
 
- 	    this.removeType('textTrack');
 
- 	    [].forEach.call(textTracks, function (textTrack, i) {
 
- 	      // Uncomment to disable rending of subtitle/caption cues in the timeline
 
- 	      // if (textTrack.kind === 'subtitles' || textTrack.kind === 'captions') {
 
- 	      //   return;
 
- 	      // }
 
- 	      var data = [];
 
- 	      labels.push((textTrack.name || textTrack.label) + " " + textTrack.kind + " (" + textTrack.mode + ")");
 
- 	      datasets.push(datasetWithDefaults({
 
- 	        data: data,
 
- 	        categoryPercentage: 0.5,
 
- 	        url: '',
 
- 	        trackType: 'textTrack',
 
- 	        borderColor: textTrack.mode !== 'hidden' === i ? 'rgba(32, 32, 240, 1.0)' : null,
 
- 	        textTrack: i
 
- 	      }));
 
- 	      _this8.cuesChangeHandler = _this8.cuesChangeHandler || function (e) {
 
- 	        return _this8.updateTextTrackCues(e.currentTarget);
 
- 	      };
 
- 	      textTrack._data = data;
 
- 	      textTrack.removeEventListener('cuechange', _this8.cuesChangeHandler);
 
- 	      textTrack.addEventListener('cuechange', _this8.cuesChangeHandler);
 
- 	      _this8.updateTextTrackCues(textTrack);
 
- 	    });
 
- 	    this.resize(datasets);
 
- 	  };
 
- 	  _proto.updateTextTrackCues = function updateTextTrackCues(textTrack) {
 
- 	    var data = textTrack._data;
 
- 	    if (!data) {
 
- 	      return;
 
- 	    }
 
- 	    var activeCues = textTrack.activeCues,
 
- 	      cues = textTrack.cues;
 
- 	    data.length = 0;
 
- 	    if (!cues) {
 
- 	      return;
 
- 	    }
 
- 	    var length = cues.length;
 
- 	    var activeLength = 0;
 
- 	    var activeMin = Infinity;
 
- 	    var activeMax = 0;
 
- 	    if (activeCues) {
 
- 	      activeLength = activeCues.length;
 
- 	      for (var i = 0; i < activeLength; i++) {
 
- 	        var cue = activeCues[i];
 
- 	        if (!cue && activeCues.item) {
 
- 	          cue = activeCues.item(i);
 
- 	        }
 
- 	        if (cue) {
 
- 	          activeMin = Math.min(activeMin, cue.startTime);
 
- 	          activeMax = cue.endTime ? Math.max(activeMax, cue.endTime) : activeMax;
 
- 	        } else {
 
- 	          activeLength--;
 
- 	        }
 
- 	      }
 
- 	    }
 
- 	    var _loop = function _loop() {
 
- 	      var cue = cues[_i];
 
- 	      if (!cue && cues.item) {
 
- 	        cue = cues.item(_i);
 
- 	      }
 
- 	      if (!cue) {
 
- 	        return 1; // continue
 
- 	      }
 
- 	      var start = cue.startTime;
 
- 	      var end = cue.endTime;
 
- 	      var content = getCueLabel(cue);
 
- 	      var active = false;
 
- 	      if (activeLength && end >= activeMin && start <= activeMax) {
 
- 	        active = [].some.call(activeCues, function (activeCue) {
 
- 	          return cuesMatch(activeCue, cue);
 
- 	        });
 
- 	      }
 
- 	      data.push({
 
- 	        start: start,
 
- 	        end: end,
 
- 	        content: content,
 
- 	        active: active,
 
- 	        dataType: 'cue'
 
- 	      });
 
- 	    };
 
- 	    for (var _i = 0; _i < length; _i++) {
 
- 	      if (_loop()) continue;
 
- 	    }
 
- 	    this.updateOnRepaint();
 
- 	  };
 
- 	  _proto.drawCurrentTime = function drawCurrentTime() {
 
- 	    var _self$hls3;
 
- 	    var chart = this.chart;
 
- 	    if ((_self$hls3 = self.hls) != null && _self$hls3.media && chart.data.datasets.length) {
 
- 	      var currentTime = self.hls.media.currentTime;
 
- 	      var scale = this.chartScales[X_AXIS_SECONDS];
 
- 	      var ctx = chart.ctx;
 
- 	      if (this.hidden || !ctx || !ctx.canvas.width) {
 
- 	        return;
 
- 	      }
 
- 	      var chartArea = chart.chartArea;
 
- 	      var x = scale.getPixelForValue(currentTime);
 
- 	      ctx.restore();
 
- 	      ctx.save();
 
- 	      this.drawLineX(ctx, x, chartArea);
 
- 	      if (x > chartArea.left && x < chartArea.right) {
 
- 	        ctx.fillStyle = this.getCurrentTimeColor(self.hls.media);
 
- 	        var y = chartArea.top + chart.data.datasets[0].barThickness + 1;
 
- 	        ctx.fillText(hhmmss(currentTime, 5), x + 2, y, 100);
 
- 	      }
 
- 	      ctx.restore();
 
- 	    }
 
- 	  };
 
- 	  _proto.getCurrentTimeColor = function getCurrentTimeColor(video) {
 
- 	    if (!video.readyState || video.ended) {
 
- 	      return 'rgba(0, 0, 0, 0.9)';
 
- 	    }
 
- 	    if (video.seeking || video.readyState < 3) {
 
- 	      return 'rgba(255, 128, 0, 0.9)';
 
- 	    }
 
- 	    if (video.paused) {
 
- 	      return 'rgba(128, 0, 255, 0.9)';
 
- 	    }
 
- 	    return 'rgba(0, 0, 255, 0.9)';
 
- 	  };
 
- 	  _proto.drawLineX = function drawLineX(ctx, x, chartArea) {
 
- 	    if (!this.imageDataBuffer) {
 
- 	      var devicePixelRatio = self.devicePixelRatio || 1;
 
- 	      this.imageDataBuffer = ctx.getImageData(0, 0, chartArea.right * devicePixelRatio, chartArea.bottom * devicePixelRatio);
 
- 	    } else {
 
- 	      ctx.fillStyle = '#ffffff';
 
- 	      ctx.fillRect(0, 0, chartArea.right, chartArea.bottom);
 
- 	      ctx.putImageData(this.imageDataBuffer, 0, 0);
 
- 	    }
 
- 	    if (x > chartArea.left && x < chartArea.right) {
 
- 	      ctx.lineWidth = 1;
 
- 	      ctx.strokeStyle = this.getCurrentTimeColor(self.hls.media); // alpha '0.5'
 
- 	      ctx.beginPath();
 
- 	      ctx.moveTo(x, chartArea.top);
 
- 	      ctx.lineTo(x, chartArea.bottom);
 
- 	      ctx.stroke();
 
- 	    }
 
- 	  };
 
- 	  _createClass(TimelineChart, [{
 
- 	    key: "chartScales",
 
- 	    get: function get() {
 
- 	      return this.chart.scales;
 
- 	    }
 
- 	  }, {
 
- 	    key: "minZoom",
 
- 	    get: function get() {
 
- 	      var scale = this.chartScales[X_AXIS_SECONDS];
 
- 	      if (scale) {
 
- 	        return scale.options.ticks.min;
 
- 	      }
 
- 	      return 1;
 
- 	    }
 
- 	    // @ts-ignore
 
- 	  }, {
 
- 	    key: "maxZoom",
 
- 	    get: function get() {
 
- 	      var scale = this.chartScales[X_AXIS_SECONDS];
 
- 	      if (scale) {
 
- 	        return scale.options.ticks.max;
 
- 	      }
 
- 	      return this.zoom100;
 
- 	    }
 
- 	    // @ts-ignore
 
- 	    ,
 
- 	    set: function set(x) {
 
- 	      var currentZoom = this.maxZoom;
 
- 	      var newZoom = Math.max(x, currentZoom);
 
- 	      if (currentZoom === 60 && newZoom !== currentZoom) {
 
- 	        var scale = this.chartScales[X_AXIS_SECONDS];
 
- 	        scale.options.ticks.max = newZoom;
 
- 	      }
 
- 	    }
 
- 	  }]);
 
- 	  return TimelineChart;
 
- 	}();
 
- 	function stripDeliveryDirectives(url) {
 
- 	  if (url === '') {
 
- 	    return url;
 
- 	  }
 
- 	  try {
 
- 	    var webUrl = new self.URL(url);
 
- 	    webUrl.searchParams.delete('_HLS_msn');
 
- 	    webUrl.searchParams.delete('_HLS_part');
 
- 	    webUrl.searchParams.delete('_HLS_skip');
 
- 	    webUrl.searchParams.sort();
 
- 	    return webUrl.href;
 
- 	  } catch (e) {
 
- 	    return url.replace(/[?&]_HLS_(?:msn|part|skip)=[^?&]+/g, '');
 
- 	  }
 
- 	}
 
- 	function datasetWithDefaults(options) {
 
- 	  return _extends({
 
- 	    data: [],
 
- 	    xAxisID: X_AXIS_SECONDS,
 
- 	    barThickness: 35,
 
- 	    categoryPercentage: 1
 
- 	  }, options);
 
- 	}
 
- 	function getPlaylistStart(details) {
 
- 	  var _details$fragments;
 
- 	  return (_details$fragments = details.fragments) != null && _details$fragments.length ? details.fragments[0].start : 0;
 
- 	}
 
- 	function getLevelName(level, index) {
 
- 	  var _level$attrs;
 
- 	  var label = '(main playlist)';
 
- 	  if ((_level$attrs = level.attrs) != null && _level$attrs.BANDWIDTH) {
 
- 	    label = getMainLevelAttribute(level) + "@" + level.attrs.BANDWIDTH;
 
- 	    if (level.name) {
 
- 	      label = label + " (" + level.name + ")";
 
- 	    }
 
- 	  } else if (level.name) {
 
- 	    label = level.name;
 
- 	  }
 
- 	  return label + " L-" + index;
 
- 	}
 
- 	function getMainLevelAttribute(level) {
 
- 	  return level.attrs.RESOLUTION || level.attrs.CODECS || level.attrs.AUDIO;
 
- 	}
 
- 	function getAudioTrackName(track, index) {
 
- 	  var label = track.lang ? track.name + "/" + track.lang : track.name;
 
- 	  return label + " (" + (track.groupId || track.attrs['GROUP-ID']) + ") A-" + index;
 
- 	}
 
- 	function getSubtitlesName(track, index) {
 
- 	  var label = track.lang ? track.name + "/" + track.lang : track.name;
 
- 	  return label + " (" + (track.groupId || track.attrs['GROUP-ID']) + ") S-" + index;
 
- 	}
 
- 	function replaceTimeRangeTuples(timeRanges, data) {
 
- 	  data.length = 0;
 
- 	  var length = timeRanges.length;
 
- 	  for (var i = 0; i < length; i++) {
 
- 	    data.push([timeRanges.start(i), timeRanges.end(i)]);
 
- 	  }
 
- 	}
 
- 	function cuesMatch(cue1, cue2) {
 
- 	  return cue1.startTime === cue2.startTime && cue1.endTime === cue2.endTime && cue1.text === cue2.text && cue1.data === cue2.data && JSON.stringify(cue1.value) === JSON.stringify(cue2.value);
 
- 	}
 
- 	function getCueLabel(cue) {
 
- 	  if (cue.text) {
 
- 	    return cue.text;
 
- 	  }
 
- 	  var result = parseDataCue(cue);
 
- 	  return JSON.stringify(result);
 
- 	}
 
- 	function parseDataCue(cue) {
 
- 	  var data = {};
 
- 	  var value = cue.value;
 
- 	  if (value) {
 
- 	    if (value.info) {
 
- 	      var collection = data[value.key];
 
- 	      if (collection !== Object(collection)) {
 
- 	        collection = {};
 
- 	        data[value.key] = collection;
 
- 	      }
 
- 	      collection[value.info] = value.data;
 
- 	    } else {
 
- 	      data[value.key] = value.data;
 
- 	    }
 
- 	  }
 
- 	  return data;
 
- 	}
 
- 	function getChartOptions() {
 
- 	  return {
 
- 	    animation: {
 
- 	      duration: 0
 
- 	    },
 
- 	    elements: {
 
- 	      rectangle: {
 
- 	        borderWidth: 1,
 
- 	        borderColor: 'rgba(20, 20, 20, 1)'
 
- 	      }
 
- 	    },
 
- 	    events: ['click', 'touchstart'],
 
- 	    hover: {
 
- 	      mode: null,
 
- 	      animationDuration: 0
 
- 	    },
 
- 	    legend: {
 
- 	      display: false
 
- 	    },
 
- 	    maintainAspectRatio: false,
 
- 	    responsiveAnimationDuration: 0,
 
- 	    scales: {
 
- 	      // TODO: additional xAxes for PTS and PDT
 
- 	      xAxes: [{
 
- 	        id: X_AXIS_SECONDS,
 
- 	        ticks: {
 
- 	          beginAtZero: true,
 
- 	          sampleSize: 0,
 
- 	          maxRotation: 0,
 
- 	          callback: function callback(tickValue, i, ticks) {
 
- 	            if (i === 0 || i === ticks.length - 1) {
 
- 	              return tickValue ? '' : '0';
 
- 	            } else {
 
- 	              return hhmmss(tickValue, 2);
 
- 	            }
 
- 	          }
 
- 	        }
 
- 	      }],
 
- 	      yAxes: [{
 
- 	        gridLines: {
 
- 	          display: false
 
- 	        }
 
- 	      }]
 
- 	    },
 
- 	    tooltips: {
 
- 	      enabled: false
 
- 	    }
 
- 	  };
 
- 	}
 
- 	function arrayFind(array, predicate) {
 
- 	  var len = array.length >>> 0;
 
- 	  if (typeof predicate !== 'function') {
 
- 	    throw TypeError('predicate must be a function');
 
- 	  }
 
- 	  var thisArg = arguments[2];
 
- 	  var k = 0;
 
- 	  while (k < len) {
 
- 	    var kValue = array[k];
 
- 	    if (predicate.call(thisArg, kValue, k, array)) {
 
- 	      return kValue;
 
- 	    }
 
- 	    k++;
 
- 	  }
 
- 	  // eslint-disable-next-line no-undefined
 
- 	  return undefined;
 
- 	}
 
- 	/* global $, Hls, null */
 
- 	var STORAGE_KEYS = {
 
- 	  Editor_Persistence: 'hlsjs:config-editor-persist',
 
- 	  Hls_Config: 'hlsjs:config',
 
- 	  volume: 'hlsjs:volume',
 
- 	  demo_tabs: 'hlsjs:demo-tabs'
 
- 	};
 
- 	var testStreams = testStreams$1;
 
- 	var defaultTestStreamUrl = testStreams[Object.keys(testStreams)[0]].url;
 
- 	var sourceURL = decodeURIComponent(getURLParam('src', defaultTestStreamUrl));
 
- 	var demoConfig = getURLParam('demoConfig', null);
 
- 	if (demoConfig) {
 
- 	  demoConfig = JSON.parse(atob(demoConfig));
 
- 	} else {
 
- 	  demoConfig = {};
 
- 	}
 
- 	var hlsjsDefaults = {
 
- 	  debug: true,
 
- 	  enableWorker: true,
 
- 	  lowLatencyMode: true,
 
- 	  backBufferLength: 60 * 1.5
 
- 	};
 
- 	var enableStreaming = getDemoConfigPropOrDefault('enableStreaming', true);
 
- 	var autoRecoverError = getDemoConfigPropOrDefault('autoRecoverError', true);
 
- 	var levelCapping = getDemoConfigPropOrDefault('levelCapping', -1);
 
- 	var limitMetrics = getDemoConfigPropOrDefault('limitMetrics', -1);
 
- 	var dumpfMP4 = getDemoConfigPropOrDefault('dumpfMP4', false);
 
- 	var stopOnStall = getDemoConfigPropOrDefault('stopOnStall', false);
 
- 	var bufferingIdx = -1;
 
- 	var selectedTestStream = null;
 
- 	var video = document.querySelector('#video');
 
- 	var startTime = Date.now();
 
- 	var lastSeekingIdx;
 
- 	var lastStartPosition;
 
- 	var lastDuration;
 
- 	var lastAudioTrackSwitchingIdx;
 
- 	var hls;
 
- 	var url;
 
- 	var events;
 
- 	var stats;
 
- 	var tracks;
 
- 	var fmp4Data;
 
- 	var configPersistenceEnabled = false;
 
- 	var configEditor = null;
 
- 	var chart;
 
- 	var resizeAsyncCallbackId = -1;
 
- 	var requestAnimationFrame = self.requestAnimationFrame || self.setTimeout;
 
- 	var cancelAnimationFrame = self.cancelAnimationFrame || self.clearTimeout;
 
- 	var resizeHandlers = [];
 
- 	var resize = function resize() {
 
- 	  cancelAnimationFrame(resizeAsyncCallbackId);
 
- 	  resizeAsyncCallbackId = requestAnimationFrame(function () {
 
- 	    resizeHandlers.forEach(function (handler) {
 
- 	      handler();
 
- 	    });
 
- 	  });
 
- 	};
 
- 	self.onresize = resize;
 
- 	if (self.screen && self.screen.orientation) {
 
- 	  self.screen.orientation.onchange = resize;
 
- 	}
 
- 	var playerResize = function playerResize() {
 
- 	  var bounds = video.getBoundingClientRect();
 
- 	  $('#currentSize').html(Math.round(bounds.width * 10) / 10 + " x " + Math.round(bounds.height * 10) / 10);
 
- 	  if (video.videoWidth && video.videoHeight) {
 
- 	    $('#currentResolution').html(video.videoWidth + " x " + video.videoHeight);
 
- 	  }
 
- 	};
 
- 	resizeHandlers.push(playerResize);
 
- 	$(document).ready(function () {
 
- 	  setupConfigEditor();
 
- 	  chart = setupTimelineChart();
 
- 	  Object.keys(testStreams).forEach(function (key, index) {
 
- 	    var stream = testStreams[key];
 
- 	    var option = new Option(stream.description, key);
 
- 	    $('#streamSelect').append(option);
 
- 	    if (stream.url === sourceURL) {
 
- 	      document.querySelector('#streamSelect').selectedIndex = index + 1;
 
- 	    }
 
- 	  });
 
- 	  var videoWidth = video.style.width;
 
- 	  if (videoWidth) {
 
- 	    $('#videoSize option').each(function (i, option) {
 
- 	      if (option.value === videoWidth) {
 
- 	        document.querySelector('#videoSize').selectedIndex = i;
 
- 	        $('#bufferedCanvas').width(videoWidth);
 
- 	        resize();
 
- 	        return false;
 
- 	      }
 
- 	    });
 
- 	  }
 
- 	  $('#streamSelect').change(function () {
 
- 	    var key = $('#streamSelect').val() || Object.keys(testStreams)[0];
 
- 	    selectedTestStream = testStreams[key];
 
- 	    var streamUrl = selectedTestStream.url;
 
- 	    $('#streamURL').val(streamUrl);
 
- 	    loadSelectedStream();
 
- 	  });
 
- 	  $('#streamURL').change(function () {
 
- 	    selectedTestStream = null;
 
- 	    loadSelectedStream();
 
- 	  });
 
- 	  $('#videoSize').change(function () {
 
- 	    $('#video').width($('#videoSize').val());
 
- 	    $('#bufferedCanvas').width($('#videoSize').val());
 
- 	    checkBuffer();
 
- 	    resize();
 
- 	  });
 
- 	  $('#enableStreaming').click(function () {
 
- 	    enableStreaming = this.checked;
 
- 	    loadSelectedStream();
 
- 	  });
 
- 	  $('#autoRecoverError').click(function () {
 
- 	    autoRecoverError = this.checked;
 
- 	    onDemoConfigChanged();
 
- 	  });
 
- 	  $('#stopOnStall').click(function () {
 
- 	    stopOnStall = this.checked;
 
- 	    onDemoConfigChanged();
 
- 	  });
 
- 	  $('#dumpfMP4').click(function () {
 
- 	    dumpfMP4 = this.checked;
 
- 	    $('.btn-dump').toggle(dumpfMP4);
 
- 	    onDemoConfigChanged();
 
- 	  });
 
- 	  $('#limitMetrics').change(function () {
 
- 	    limitMetrics = this.value;
 
- 	    onDemoConfigChanged();
 
- 	  });
 
- 	  $('#levelCapping').change(function () {
 
- 	    levelCapping = this.value;
 
- 	    onDemoConfigChanged();
 
- 	  });
 
- 	  $('#limitMetrics').val(limitMetrics);
 
- 	  $('#enableStreaming').prop('checked', enableStreaming);
 
- 	  $('#autoRecoverError').prop('checked', autoRecoverError);
 
- 	  $('#stopOnStall').prop('checked', stopOnStall);
 
- 	  $('#dumpfMP4').prop('checked', dumpfMP4);
 
- 	  $('#levelCapping').val(levelCapping);
 
- 	  // If cloudflare pages build link to branch
 
- 	  // If not a stable tag link to npm
 
- 	  // otherwise link to github tag
 
- 	  function getVersionLink(version) {
 
- 	    var noneStable = version.includes('-');
 
- 	    if (noneStable) {
 
- 	      return "https://www.npmjs.com/package/hls.js/v/" + encodeURIComponent(version);
 
- 	    } else {
 
- 	      return "https://github.com/video-dev/hls.js/releases/tag/v" + encodeURIComponent(version);
 
- 	    }
 
- 	  }
 
- 	  var version = Hls.version;
 
- 	  if (version) {
 
- 	    var $a = $('<a />').attr('target', '_blank').attr('rel', 'noopener noreferrer').attr('href', getVersionLink(version)).text('v' + version);
 
- 	    $('.title').append(' ').append($a);
 
- 	  }
 
- 	  $('#streamURL').val(sourceURL);
 
- 	  var volumeSettings = JSON.parse(localStorage.getItem(STORAGE_KEYS.volume)) || {
 
- 	    volume: 0.05,
 
- 	    muted: false
 
- 	  };
 
- 	  video.volume = volumeSettings.volume;
 
- 	  video.muted = volumeSettings.muted;
 
- 	  $('.btn-dump').toggle(dumpfMP4);
 
- 	  $('#toggleButtons').show();
 
- 	  $('#metricsButtonWindow').toggle(self.windowSliding);
 
- 	  $('#metricsButtonFixed').toggle(!self.windowSliding);
 
- 	  loadSelectedStream();
 
- 	  var tabIndexesCSV = localStorage.getItem(STORAGE_KEYS.demo_tabs);
 
- 	  if (tabIndexesCSV === null) {
 
- 	    tabIndexesCSV = '0,1,2';
 
- 	  }
 
- 	  if (tabIndexesCSV) {
 
- 	    tabIndexesCSV.split(',').forEach(function (indexString) {
 
- 	      toggleTab($('.demo-tab-btn')[parseInt(indexString) || 0], true);
 
- 	    });
 
- 	  }
 
- 	  $(self).on('popstate', function () {
 
- 	    self.location.reload();
 
- 	  });
 
- 	});
 
- 	function setupGlobals() {
 
- 	  self.events = events = {
 
- 	    url: url,
 
- 	    t0: self.performance.now(),
 
- 	    load: [],
 
- 	    buffer: [],
 
- 	    video: [],
 
- 	    level: [],
 
- 	    bitrate: []
 
- 	  };
 
- 	  lastAudioTrackSwitchingIdx = undefined;
 
- 	  lastSeekingIdx = undefined;
 
- 	  bufferingIdx = -1;
 
- 	  // actual values, only on window
 
- 	  self.recoverDecodingErrorDate = null;
 
- 	  self.recoverSwapAudioCodecDate = null;
 
- 	  self.fmp4Data = fmp4Data = {
 
- 	    audio: [],
 
- 	    video: []
 
- 	  };
 
- 	  self.onClickBufferedRange = onClickBufferedRange;
 
- 	  self.updateLevelInfo = updateLevelInfo;
 
- 	  self.onDemoConfigChanged = onDemoConfigChanged;
 
- 	  self.createfMP4 = createfMP4;
 
- 	  self.goToMetricsPermaLink = goToMetricsPermaLink;
 
- 	  self.toggleTab = toggleTab;
 
- 	  self.toggleTabClick = toggleTabClick;
 
- 	  self.applyConfigEditorValue = applyConfigEditorValue;
 
- 	}
 
- 	function trimArray(target, limit) {
 
- 	  if (limit < 0) {
 
- 	    return;
 
- 	  }
 
- 	  while (target.length > limit) {
 
- 	    target.shift();
 
- 	  }
 
- 	}
 
- 	function trimEventHistory() {
 
- 	  var x = limitMetrics;
 
- 	  if (x < 0) {
 
- 	    return;
 
- 	  }
 
- 	  trimArray(events.load, x);
 
- 	  trimArray(events.buffer, x);
 
- 	  trimArray(events.video, x);
 
- 	  trimArray(events.level, x);
 
- 	  trimArray(events.bitrate, x);
 
- 	}
 
- 	function loadSelectedStream() {
 
- 	  $('#statusOut,#errorOut').empty();
 
- 	  if (!Hls.isSupported()) {
 
- 	    handleUnsupported();
 
- 	    return;
 
- 	  }
 
- 	  url = $('#streamURL').val();
 
- 	  setupGlobals();
 
- 	  hideCanvas();
 
- 	  if (hls) {
 
- 	    hls.destroy();
 
- 	    clearInterval(hls.bufferTimer);
 
- 	    hls = null;
 
- 	  }
 
- 	  if (!enableStreaming) {
 
- 	    logStatus('Streaming disabled');
 
- 	    return;
 
- 	  }
 
- 	  logStatus('Loading ' + url);
 
- 	  // Extending both a demo-specific config and the user config which can override all
 
- 	  var hlsConfig = $.extend({}, hlsjsDefaults, getEditorValue({
 
- 	    parse: true
 
- 	  }));
 
- 	  if (selectedTestStream && selectedTestStream.config) {
 
- 	    console.info('[loadSelectedStream] extending hls config with stream-specific config: ', selectedTestStream.config);
 
- 	    $.extend(hlsConfig, selectedTestStream.config);
 
- 	    updateConfigEditorValue(hlsConfig);
 
- 	  }
 
- 	  onDemoConfigChanged(true);
 
- 	  console.log('Using Hls.js config:', hlsConfig);
 
- 	  self.hls = hls = new Hls(hlsConfig);
 
- 	  logStatus('Loading manifest and attaching video element...');
 
- 	  var expiredTracks = [].filter.call(video.textTracks, function (track) {
 
- 	    return track.kind !== 'metadata';
 
- 	  });
 
- 	  if (expiredTracks.length) {
 
- 	    var kinds = expiredTracks.map(function (track) {
 
- 	      return track.kind;
 
- 	    }).filter(function (kind, index, self) {
 
- 	      return self.indexOf(kind) === index;
 
- 	    });
 
- 	    logStatus("Replacing video element to remove " + kinds.join(' and ') + " text tracks");
 
- 	    var videoWithExpiredTextTracks = video;
 
- 	    video = videoWithExpiredTextTracks.cloneNode(false);
 
- 	    video.removeAttribute('src');
 
- 	    video.volume = videoWithExpiredTextTracks.volume;
 
- 	    video.muted = videoWithExpiredTextTracks.muted;
 
- 	    videoWithExpiredTextTracks.parentNode.insertBefore(video, videoWithExpiredTextTracks);
 
- 	    videoWithExpiredTextTracks.parentNode.removeChild(videoWithExpiredTextTracks);
 
- 	  }
 
- 	  addChartEventListeners(hls);
 
- 	  addVideoEventListeners(video);
 
- 	  hls.loadSource(url);
 
- 	  hls.autoLevelCapping = levelCapping;
 
- 	  hls.attachMedia(video);
 
- 	  hls.on(Hls.Events.MEDIA_ATTACHED, function () {
 
- 	    logStatus('Media element attached');
 
- 	    bufferingIdx = -1;
 
- 	    events.video.push({
 
- 	      time: self.performance.now() - events.t0,
 
- 	      type: 'Media attached'
 
- 	    });
 
- 	    trimEventHistory();
 
- 	  });
 
- 	  hls.on(Hls.Events.MEDIA_DETACHED, function () {
 
- 	    logStatus('Media element detached');
 
- 	    clearInterval(hls.bufferTimer);
 
- 	    bufferingIdx = -1;
 
- 	    tracks = [];
 
- 	    events.video.push({
 
- 	      time: self.performance.now() - events.t0,
 
- 	      type: 'Media detached'
 
- 	    });
 
- 	    trimEventHistory();
 
- 	  });
 
- 	  hls.on(Hls.Events.DESTROYING, function () {
 
- 	    clearInterval(hls.bufferTimer);
 
- 	  });
 
- 	  hls.on(Hls.Events.BUFFER_RESET, function () {
 
- 	    clearInterval(hls.bufferTimer);
 
- 	  });
 
- 	  hls.on(Hls.Events.FRAG_PARSING_INIT_SEGMENT, function (eventName, data) {
 
- 	    showCanvas();
 
- 	    events.video.push({
 
- 	      time: self.performance.now() - events.t0,
 
- 	      type: data.id + ' init segment'
 
- 	    });
 
- 	    trimEventHistory();
 
- 	  });
 
- 	  hls.on(Hls.Events.FRAG_PARSING_METADATA, function (eventName, data) {
 
- 	    // console.log("Id3 samples ", data.samples);
 
- 	  });
 
- 	  hls.on(Hls.Events.LEVEL_SWITCHING, function (eventName, data) {
 
- 	    events.level.push({
 
- 	      time: self.performance.now() - events.t0,
 
- 	      id: data.level,
 
- 	      bitrate: Math.round(hls.levels[data.level].bitrate / 1000)
 
- 	    });
 
- 	    trimEventHistory();
 
- 	    updateLevelInfo();
 
- 	  });
 
- 	  hls.on(Hls.Events.MANIFEST_PARSED, function (eventName, data) {
 
- 	    events.load.push({
 
- 	      type: 'manifest',
 
- 	      name: '',
 
- 	      start: 0,
 
- 	      end: data.levels.length,
 
- 	      time: data.stats.loading.start - events.t0,
 
- 	      latency: data.stats.loading.first - data.stats.loading.start,
 
- 	      load: data.stats.loading.end - data.stats.loading.first,
 
- 	      duration: data.stats.loading.end - data.stats.loading.first
 
- 	    });
 
- 	    trimEventHistory();
 
- 	    self.refreshCanvas();
 
- 	  });
 
- 	  hls.on(Hls.Events.MANIFEST_PARSED, function (eventName, data) {
 
- 	    logStatus(hls.levels.length + " quality levels found");
 
- 	    logStatus('Manifest successfully loaded');
 
- 	    stats = {
 
- 	      levelNb: data.levels.length,
 
- 	      levelParsed: 0
 
- 	    };
 
- 	    trimEventHistory();
 
- 	    updateLevelInfo();
 
- 	  });
 
- 	  hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, function (eventName, data) {
 
- 	    logStatus('No of audio tracks found: ' + data.audioTracks.length);
 
- 	    updateAudioTrackInfo();
 
- 	  });
 
- 	  hls.on(Hls.Events.AUDIO_TRACK_SWITCHING, function (eventName, data) {
 
- 	    logStatus('Audio track switching...');
 
- 	    updateAudioTrackInfo();
 
- 	    events.video.push({
 
- 	      time: self.performance.now() - events.t0,
 
- 	      type: 'audio switching',
 
- 	      name: '@' + data.id
 
- 	    });
 
- 	    trimEventHistory();
 
- 	    lastAudioTrackSwitchingIdx = events.video.length - 1;
 
- 	  });
 
- 	  hls.on(Hls.Events.AUDIO_TRACK_SWITCHED, function (eventName, data) {
 
- 	    logStatus('Audio track switched');
 
- 	    updateAudioTrackInfo();
 
- 	    var event = {
 
- 	      time: self.performance.now() - events.t0,
 
- 	      type: 'audio switched',
 
- 	      name: '@' + data.id
 
- 	    };
 
- 	    if (lastAudioTrackSwitchingIdx !== undefined) {
 
- 	      events.video[lastAudioTrackSwitchingIdx].duration = event.time - events.video[lastAudioTrackSwitchingIdx].time;
 
- 	      lastAudioTrackSwitchingIdx = undefined;
 
- 	    }
 
- 	    events.video.push(event);
 
- 	    trimEventHistory();
 
- 	  });
 
- 	  hls.on(Hls.Events.LEVEL_LOADED, function (eventName, data) {
 
- 	    events.isLive = data.details.live;
 
- 	    var event = {
 
- 	      type: 'level',
 
- 	      id: data.level,
 
- 	      start: data.details.startSN,
 
- 	      end: data.details.endSN,
 
- 	      time: data.stats.loading.start - events.t0,
 
- 	      latency: data.stats.loading.first - data.stats.loading.start,
 
- 	      load: data.stats.loading.end - data.stats.loading.first,
 
- 	      parsing: data.stats.parsing.end - data.stats.loading.end,
 
- 	      duration: data.stats.loading.end - data.stats.loading.first
 
- 	    };
 
- 	    var parsingDuration = data.stats.parsing.end - data.stats.loading.end;
 
- 	    if (stats.levelParsed) {
 
- 	      this.sumLevelParsingMs += parsingDuration;
 
- 	    } else {
 
- 	      this.sumLevelParsingMs = parsingDuration;
 
- 	    }
 
- 	    stats.levelParsed++;
 
- 	    stats.levelParsingUs = Math.round(1000 * this.sumLevelParsingMs / stats.levelParsed);
 
- 	    // console.log('parsing level duration :' + stats.levelParsingUs + 'us,count:' + stats.levelParsed);
 
- 	    events.load.push(event);
 
- 	    trimEventHistory();
 
- 	    self.refreshCanvas();
 
- 	  });
 
- 	  hls.on(Hls.Events.AUDIO_TRACK_LOADED, function (eventName, data) {
 
- 	    events.isLive = data.details.live;
 
- 	    var event = {
 
- 	      type: 'audio track',
 
- 	      id: data.id,
 
- 	      start: data.details.startSN,
 
- 	      end: data.details.endSN,
 
- 	      time: data.stats.loading.start - events.t0,
 
- 	      latency: data.stats.loading.first - data.stats.loading.start,
 
- 	      load: data.stats.loading.end - data.stats.loading.first,
 
- 	      parsing: data.stats.parsing.end - data.stats.loading.end,
 
- 	      duration: data.stats.loading.end - data.stats.loading.first
 
- 	    };
 
- 	    events.load.push(event);
 
- 	    trimEventHistory();
 
- 	    self.refreshCanvas();
 
- 	  });
 
- 	  hls.on(Hls.Events.FRAG_BUFFERED, function (eventName, data) {
 
- 	    var stats = data.part && data.part.stats && data.part.stats.loaded ? data.part.stats : data.frag.stats;
 
- 	    if (data.stats.aborted) {
 
- 	      console.assert('Aborted request being buffered.', data);
 
- 	      return;
 
- 	    }
 
- 	    var event = {
 
- 	      type: data.frag.type + (data.part ? ' part' : ' fragment'),
 
- 	      id: data.frag.level,
 
- 	      id2: data.frag.sn,
 
- 	      id3: data.part ? data.part.index : undefined,
 
- 	      time: data.stats.loading.start - events.t0,
 
- 	      latency: data.stats.loading.first - data.stats.loading.start,
 
- 	      load: data.stats.loading.end - data.stats.loading.first,
 
- 	      parsing: data.stats.parsing.end - data.stats.loading.end,
 
- 	      buffer: data.stats.buffering.end - data.stats.parsing.end,
 
- 	      duration: data.stats.buffering.end - data.stats.loading.first,
 
- 	      bw: Math.round(8 * data.stats.total / (data.stats.buffering.end - data.stats.loading.start)),
 
- 	      // bandwidth of this fragment
 
- 	      ewma: Math.round(hls.bandwidthEstimate / 1000),
 
- 	      // estimated bandwidth
 
- 	      size: data.stats.total
 
- 	    };
 
- 	    events.load.push(event);
 
- 	    events.bitrate.push({
 
- 	      time: self.performance.now() - events.t0,
 
- 	      bitrate: event.bw,
 
- 	      ewma: event.ewma,
 
- 	      duration: data.frag.duration,
 
- 	      level: event.id
 
- 	    });
 
- 	    if (events.buffer.length === 0) {
 
- 	      events.buffer.push({
 
- 	        time: 0,
 
- 	        buffer: 0,
 
- 	        pos: 0
 
- 	      });
 
- 	    }
 
- 	    clearInterval(hls.bufferTimer);
 
- 	    hls.bufferTimer = self.setInterval(checkBuffer, 100);
 
- 	    trimEventHistory();
 
- 	    self.refreshCanvas();
 
- 	    updateLevelInfo();
 
- 	    var latency = data.stats.loading.first - data.stats.loading.start;
 
- 	    var parsing = data.stats.parsing.end - data.stats.loading.end;
 
- 	    var process = data.stats.buffering.end - data.stats.loading.start;
 
- 	    var bitrate = Math.round(8 * data.stats.total / (data.stats.buffering.end - data.stats.loading.first));
 
- 	    if (stats.fragBuffered) {
 
- 	      stats.fragMinLatency = Math.min(stats.fragMinLatency, latency);
 
- 	      stats.fragMaxLatency = Math.max(stats.fragMaxLatency, latency);
 
- 	      stats.fragMinProcess = Math.min(stats.fragMinProcess, process);
 
- 	      stats.fragMaxProcess = Math.max(stats.fragMaxProcess, process);
 
- 	      stats.fragMinKbps = Math.min(stats.fragMinKbps, bitrate);
 
- 	      stats.fragMaxKbps = Math.max(stats.fragMaxKbps, bitrate);
 
- 	      stats.autoLevelCappingMin = Math.min(stats.autoLevelCappingMin, hls.autoLevelCapping);
 
- 	      stats.autoLevelCappingMax = Math.max(stats.autoLevelCappingMax, hls.autoLevelCapping);
 
- 	      stats.fragBuffered++;
 
- 	    } else {
 
- 	      stats.fragMinLatency = stats.fragMaxLatency = latency;
 
- 	      stats.fragMinProcess = stats.fragMaxProcess = process;
 
- 	      stats.fragMinKbps = stats.fragMaxKbps = bitrate;
 
- 	      stats.fragBuffered = 1;
 
- 	      stats.fragBufferedBytes = 0;
 
- 	      stats.autoLevelCappingMin = stats.autoLevelCappingMax = hls.autoLevelCapping;
 
- 	      this.sumLatency = 0;
 
- 	      this.sumKbps = 0;
 
- 	      this.sumProcess = 0;
 
- 	      this.sumParsing = 0;
 
- 	    }
 
- 	    stats.fraglastLatency = latency;
 
- 	    this.sumLatency += latency;
 
- 	    stats.fragAvgLatency = Math.round(this.sumLatency / stats.fragBuffered);
 
- 	    stats.fragLastProcess = process;
 
- 	    this.sumProcess += process;
 
- 	    this.sumParsing += parsing;
 
- 	    stats.fragAvgProcess = Math.round(this.sumProcess / stats.fragBuffered);
 
- 	    stats.fragLastKbps = bitrate;
 
- 	    this.sumKbps += bitrate;
 
- 	    stats.fragAvgKbps = Math.round(this.sumKbps / stats.fragBuffered);
 
- 	    stats.fragBufferedBytes += data.stats.total;
 
- 	    stats.fragparsingKbps = Math.round(8 * stats.fragBufferedBytes / this.sumParsing);
 
- 	    stats.fragparsingMs = Math.round(this.sumParsing);
 
- 	    stats.autoLevelCappingLast = hls.autoLevelCapping;
 
- 	  });
 
- 	  hls.on(Hls.Events.LEVEL_SWITCHED, function (eventName, data) {
 
- 	    var event = {
 
- 	      time: self.performance.now() - events.t0,
 
- 	      type: 'level switched',
 
- 	      name: data.level
 
- 	    };
 
- 	    events.video.push(event);
 
- 	    trimEventHistory();
 
- 	    self.refreshCanvas();
 
- 	    updateLevelInfo();
 
- 	  });
 
- 	  hls.on(Hls.Events.FRAG_CHANGED, function (eventName, data) {
 
- 	    var event = {
 
- 	      time: self.performance.now() - events.t0,
 
- 	      type: 'frag changed',
 
- 	      name: data.frag.sn + ' @ ' + data.frag.level
 
- 	    };
 
- 	    events.video.push(event);
 
- 	    trimEventHistory();
 
- 	    self.refreshCanvas();
 
- 	    updateLevelInfo();
 
- 	    stats.tagList = data.frag.tagList;
 
- 	    var level = data.frag.level;
 
- 	    var autoLevel = hls.autoLevelEnabled;
 
- 	    if (stats.levelStart === undefined) {
 
- 	      stats.levelStart = level;
 
- 	    }
 
- 	    stats.fragProgramDateTime = data.frag.programDateTime;
 
- 	    stats.fragStart = data.frag.start;
 
- 	    if (autoLevel) {
 
- 	      if (stats.fragChangedAuto) {
 
- 	        stats.autoLevelMin = Math.min(stats.autoLevelMin, level);
 
- 	        stats.autoLevelMax = Math.max(stats.autoLevelMax, level);
 
- 	        stats.fragChangedAuto++;
 
- 	        if (this.levelLastAuto && level !== stats.autoLevelLast) {
 
- 	          stats.autoLevelSwitch++;
 
- 	        }
 
- 	      } else {
 
- 	        stats.autoLevelMin = stats.autoLevelMax = level;
 
- 	        stats.autoLevelSwitch = 0;
 
- 	        stats.fragChangedAuto = 1;
 
- 	        this.sumAutoLevel = 0;
 
- 	      }
 
- 	      this.sumAutoLevel += level;
 
- 	      stats.autoLevelAvg = Math.round(1000 * this.sumAutoLevel / stats.fragChangedAuto) / 1000;
 
- 	      stats.autoLevelLast = level;
 
- 	    } else {
 
- 	      if (stats.fragChangedManual) {
 
- 	        stats.manualLevelMin = Math.min(stats.manualLevelMin, level);
 
- 	        stats.manualLevelMax = Math.max(stats.manualLevelMax, level);
 
- 	        stats.fragChangedManual++;
 
- 	        if (!this.levelLastAuto && level !== stats.manualLevelLast) {
 
- 	          stats.manualLevelSwitch++;
 
- 	        }
 
- 	      } else {
 
- 	        stats.manualLevelMin = stats.manualLevelMax = level;
 
- 	        stats.manualLevelSwitch = 0;
 
- 	        stats.fragChangedManual = 1;
 
- 	      }
 
- 	      stats.manualLevelLast = level;
 
- 	    }
 
- 	    this.levelLastAuto = autoLevel;
 
- 	  });
 
- 	  hls.on(Hls.Events.FRAG_LOAD_EMERGENCY_ABORTED, function (eventName, data) {
 
- 	    if (stats) {
 
- 	      if (stats.fragLoadEmergencyAborted === undefined) {
 
- 	        stats.fragLoadEmergencyAborted = 1;
 
- 	      } else {
 
- 	        stats.fragLoadEmergencyAborted++;
 
- 	      }
 
- 	    }
 
- 	  });
 
- 	  hls.on(Hls.Events.FRAG_DECRYPTED, function (eventName, data) {
 
- 	    if (!stats.fragDecrypted) {
 
- 	      stats.fragDecrypted = 0;
 
- 	      this.totalDecryptTime = 0;
 
- 	      stats.fragAvgDecryptTime = 0;
 
- 	    }
 
- 	    stats.fragDecrypted++;
 
- 	    this.totalDecryptTime += data.stats.tdecrypt - data.stats.tstart;
 
- 	    stats.fragAvgDecryptTime = this.totalDecryptTime / stats.fragDecrypted;
 
- 	  });
 
- 	  hls.on(Hls.Events.ERROR, function (eventName, data) {
 
- 	    console.warn('Error event:', data);
 
- 	    switch (data.details) {
 
- 	      case Hls.ErrorDetails.MANIFEST_LOAD_ERROR:
 
- 	        try {
 
- 	          $('#errorOut').html('Cannot load <a href="' + data.context.url + '">' + url + '</a><br>HTTP response code:' + data.response.code + ' <br>' + data.response.text);
 
- 	          if (data.response.code === 0) {
 
- 	            $('#errorOut').append('This might be a CORS issue, consider installing <a href="https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi">Allow-Control-Allow-Origin</a> Chrome Extension');
 
- 	          }
 
- 	        } catch (err) {
 
- 	          $('#errorOut').html('Cannot load <a href="' + data.context.url + '">' + url + '</a><br>Response body: ' + data.response.text);
 
- 	        }
 
- 	        break;
 
- 	      case Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT:
 
- 	        logError('Timeout while loading manifest');
 
- 	        break;
 
- 	      case Hls.ErrorDetails.MANIFEST_PARSING_ERROR:
 
- 	        logError('Error while parsing manifest:' + data.reason);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.LEVEL_EMPTY_ERROR:
 
- 	        logError('Loaded level contains no fragments ' + data.level + ' ' + data.url);
 
- 	        // handleLevelError demonstrates how to remove a level that errors followed by a downswitch
 
- 	        // handleLevelError(data);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.LEVEL_LOAD_ERROR:
 
- 	        logError('Error while loading level playlist ' + data.context.level + ' ' + data.url);
 
- 	        // handleLevelError demonstrates how to remove a level that errors followed by a downswitch
 
- 	        // handleLevelError(data);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.LEVEL_LOAD_TIMEOUT:
 
- 	        logError('Timeout while loading level playlist ' + data.context.level + ' ' + data.url);
 
- 	        // handleLevelError demonstrates how to remove a level that errors followed by a downswitch
 
- 	        // handleLevelError(data);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.LEVEL_SWITCH_ERROR:
 
- 	        logError('Error while trying to switch to level ' + data.level);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.FRAG_LOAD_ERROR:
 
- 	        logError('Error while loading fragment ' + data.frag.url);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.FRAG_LOAD_TIMEOUT:
 
- 	        logError('Timeout while loading fragment ' + data.frag.url);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.FRAG_LOOP_LOADING_ERROR:
 
- 	        logError('Fragment-loop loading error');
 
- 	        break;
 
- 	      case Hls.ErrorDetails.FRAG_DECRYPT_ERROR:
 
- 	        logError('Decrypting error:' + data.reason);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.FRAG_PARSING_ERROR:
 
- 	        logError('Parsing error:' + data.reason);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.KEY_LOAD_ERROR:
 
- 	        logError('Error while loading key ' + data.frag.decryptdata.uri);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.KEY_LOAD_TIMEOUT:
 
- 	        logError('Timeout while loading key ' + data.frag.decryptdata.uri);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.BUFFER_APPEND_ERROR:
 
- 	        logError('Buffer append error');
 
- 	        break;
 
- 	      case Hls.ErrorDetails.BUFFER_ADD_CODEC_ERROR:
 
- 	        logError('Buffer add codec error for ' + data.mimeType + ':' + data.error.message);
 
- 	        break;
 
- 	      case Hls.ErrorDetails.BUFFER_APPENDING_ERROR:
 
- 	        logError('Buffer appending error');
 
- 	        break;
 
- 	      case Hls.ErrorDetails.BUFFER_STALLED_ERROR:
 
- 	        logError('Buffer stalled error');
 
- 	        if (stopOnStall) {
 
- 	          hls.stopLoad();
 
- 	          video.pause();
 
- 	        }
 
- 	        break;
 
- 	    }
 
- 	    if (data.fatal) {
 
- 	      console.error("Fatal error : " + data.details);
 
- 	      switch (data.type) {
 
- 	        case Hls.ErrorTypes.MEDIA_ERROR:
 
- 	          logError("A media error occurred: " + data.details);
 
- 	          handleMediaError();
 
- 	          break;
 
- 	        case Hls.ErrorTypes.NETWORK_ERROR:
 
- 	          logError("A network error occurred: " + data.details);
 
- 	          break;
 
- 	        default:
 
- 	          logError("An unrecoverable error occurred: " + data.details);
 
- 	          hls.destroy();
 
- 	          break;
 
- 	      }
 
- 	    }
 
- 	    if (!stats) {
 
- 	      stats = {};
 
- 	    }
 
- 	    // track all errors independently
 
- 	    if (stats[data.details] === undefined) {
 
- 	      stats[data.details] = 1;
 
- 	    } else {
 
- 	      stats[data.details] += 1;
 
- 	    }
 
- 	    // track fatal error
 
- 	    if (data.fatal) {
 
- 	      if (stats.fatalError === undefined) {
 
- 	        stats.fatalError = 1;
 
- 	      } else {
 
- 	        stats.fatalError += 1;
 
- 	      }
 
- 	    }
 
- 	    $('#statisticsOut').text(JSON.stringify(sortObject(stats), null, '\t'));
 
- 	  });
 
- 	  hls.on(Hls.Events.BUFFER_CREATED, function (eventName, data) {
 
- 	    tracks = data.tracks;
 
- 	  });
 
- 	  hls.on(Hls.Events.BUFFER_APPENDING, function (eventName, data) {
 
- 	    if (dumpfMP4) {
 
- 	      fmp4Data[data.type].push(data.data);
 
- 	    }
 
- 	  });
 
- 	  hls.on(Hls.Events.FPS_DROP, function (eventName, data) {
 
- 	    var event = {
 
- 	      time: self.performance.now() - events.t0,
 
- 	      type: 'frame drop',
 
- 	      name: data.currentDropped + '/' + data.currentDecoded
 
- 	    };
 
- 	    events.video.push(event);
 
- 	    trimEventHistory();
 
- 	    if (stats) {
 
- 	      if (stats.fpsDropEvent === undefined) {
 
- 	        stats.fpsDropEvent = 1;
 
- 	      } else {
 
- 	        stats.fpsDropEvent++;
 
- 	      }
 
- 	      stats.fpsTotalDroppedFrames = data.totalDroppedFrames;
 
- 	    }
 
- 	  });
 
- 	}
 
- 	function addVideoEventListeners(video) {
 
- 	  video.removeEventListener('resize', handleVideoEvent);
 
- 	  video.removeEventListener('seeking', handleVideoEvent);
 
- 	  video.removeEventListener('seeked', handleVideoEvent);
 
- 	  video.removeEventListener('pause', handleVideoEvent);
 
- 	  video.removeEventListener('play', handleVideoEvent);
 
- 	  video.removeEventListener('canplay', handleVideoEvent);
 
- 	  video.removeEventListener('canplaythrough', handleVideoEvent);
 
- 	  video.removeEventListener('ended', handleVideoEvent);
 
- 	  video.removeEventListener('playing', handleVideoEvent);
 
- 	  video.removeEventListener('error', handleVideoEvent);
 
- 	  video.removeEventListener('loadedmetadata', handleVideoEvent);
 
- 	  video.removeEventListener('loadeddata', handleVideoEvent);
 
- 	  video.removeEventListener('durationchange', handleVideoEvent);
 
- 	  video.removeEventListener('volumechange', handleVolumeEvent);
 
- 	  video.addEventListener('resize', handleVideoEvent);
 
- 	  video.addEventListener('seeking', handleVideoEvent);
 
- 	  video.addEventListener('seeked', handleVideoEvent);
 
- 	  video.addEventListener('pause', handleVideoEvent);
 
- 	  video.addEventListener('play', handleVideoEvent);
 
- 	  video.addEventListener('canplay', handleVideoEvent);
 
- 	  video.addEventListener('canplaythrough', handleVideoEvent);
 
- 	  video.addEventListener('ended', handleVideoEvent);
 
- 	  video.addEventListener('playing', handleVideoEvent);
 
- 	  video.addEventListener('error', handleVideoEvent);
 
- 	  video.addEventListener('loadedmetadata', handleVideoEvent);
 
- 	  video.addEventListener('loadeddata', handleVideoEvent);
 
- 	  video.addEventListener('durationchange', handleVideoEvent);
 
- 	  video.addEventListener('volumechange', handleVolumeEvent);
 
- 	}
 
- 	function handleUnsupported() {
 
- 	  if (navigator.userAgent.toLowerCase().indexOf('firefox') !== -1) {
 
- 	    logStatus('You are using Firefox, it looks like MediaSource is not enabled,<br>please ensure the following keys are set appropriately in <b>about:config</b><br>media.mediasource.enabled=true<br>media.mediasource.mp4.enabled=true<br><b>media.mediasource.whitelist=false</b>');
 
- 	  } else {
 
- 	    logStatus('Your Browser does not support MediaSourceExtension / MP4 mediasource');
 
- 	  }
 
- 	}
 
- 	function handleVideoEvent(evt) {
 
- 	  var data = '';
 
- 	  switch (evt.type) {
 
- 	    case 'durationchange':
 
- 	      if (evt.target.duration - lastDuration <= 0.5) {
 
- 	        // some browsers report several duration change events with almost the same value ... avoid spamming video events
 
- 	        return;
 
- 	      }
 
- 	      lastDuration = evt.target.duration;
 
- 	      data = Math.round(evt.target.duration * 1000);
 
- 	      break;
 
- 	    case 'resize':
 
- 	      data = evt.target.videoWidth + '/' + evt.target.videoHeight;
 
- 	      playerResize();
 
- 	      break;
 
- 	    case 'loadedmetadata':
 
- 	    case 'loadeddata':
 
- 	    case 'canplay':
 
- 	    case 'canplaythrough':
 
- 	    case 'ended':
 
- 	    case 'seeking':
 
- 	    case 'seeked':
 
- 	    case 'play':
 
- 	    case 'playing':
 
- 	      lastStartPosition = evt.target.currentTime;
 
- 	    case 'pause':
 
- 	    case 'waiting':
 
- 	    case 'stalled':
 
- 	    case 'error':
 
- 	      data = Math.round(evt.target.currentTime * 1000);
 
- 	      if (evt.type === 'error') {
 
- 	        var errorTxt;
 
- 	        var mediaError = evt.currentTarget.error;
 
- 	        switch (mediaError.code) {
 
- 	          case mediaError.MEDIA_ERR_ABORTED:
 
- 	            errorTxt = 'You aborted the video playback';
 
- 	            break;
 
- 	          case mediaError.MEDIA_ERR_DECODE:
 
- 	            errorTxt = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support';
 
- 	            handleMediaError();
 
- 	            break;
 
- 	          case mediaError.MEDIA_ERR_NETWORK:
 
- 	            errorTxt = 'A network error caused the video download to fail part-way';
 
- 	            break;
 
- 	          case mediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
 
- 	            errorTxt = 'The video could not be loaded, either because the server or network failed or because the format is not supported';
 
- 	            break;
 
- 	        }
 
- 	        if (mediaError.message) {
 
- 	          errorTxt += ' - ' + mediaError.message;
 
- 	        }
 
- 	        logStatus(errorTxt);
 
- 	        console.error(errorTxt);
 
- 	      }
 
- 	      break;
 
- 	  }
 
- 	  var event = {
 
- 	    time: self.performance.now() - events.t0,
 
- 	    type: evt.type,
 
- 	    name: data
 
- 	  };
 
- 	  events.video.push(event);
 
- 	  if (evt.type === 'seeking') {
 
- 	    lastSeekingIdx = events.video.length - 1;
 
- 	  }
 
- 	  if (evt.type === 'seeked') {
 
- 	    events.video[lastSeekingIdx].duration = event.time - events.video[lastSeekingIdx].time;
 
- 	  }
 
- 	  trimEventHistory();
 
- 	}
 
- 	function handleVolumeEvent() {
 
- 	  localStorage.setItem(STORAGE_KEYS.volume, JSON.stringify({
 
- 	    muted: video.muted,
 
- 	    volume: video.volume
 
- 	  }));
 
- 	}
 
- 	function handleMediaError() {
 
- 	  if (autoRecoverError) {
 
- 	    var now = self.performance.now();
 
- 	    if (!self.recoverDecodingErrorDate || now - self.recoverDecodingErrorDate > 3000) {
 
- 	      self.recoverDecodingErrorDate = self.performance.now();
 
- 	      $('#statusOut').append(', trying to recover media error.');
 
- 	      hls.recoverMediaError();
 
- 	    } else {
 
- 	      if (!self.recoverSwapAudioCodecDate || now - self.recoverSwapAudioCodecDate > 3000) {
 
- 	        self.recoverSwapAudioCodecDate = self.performance.now();
 
- 	        $('#statusOut').append(', trying to swap audio codec and recover media error.');
 
- 	        hls.swapAudioCodec();
 
- 	        hls.recoverMediaError();
 
- 	      } else {
 
- 	        $('#statusOut').append(', cannot recover. Last media error recovery failed.');
 
- 	      }
 
- 	    }
 
- 	  }
 
- 	}
 
- 	function timeRangesToString(r) {
 
- 	  var log = '';
 
- 	  for (var i = 0; i < r.length; i++) {
 
- 	    log += '[' + r.start(i) + ', ' + r.end(i) + ']';
 
- 	    log += ' ';
 
- 	  }
 
- 	  return log;
 
- 	}
 
- 	function checkBuffer() {
 
- 	  var canvas = document.querySelector('#bufferedCanvas');
 
- 	  var ctx = canvas.getContext('2d');
 
- 	  var r = video.buffered;
 
- 	  var seekableEnd = getSeekableEnd();
 
- 	  var bufferingDuration;
 
- 	  if (r) {
 
- 	    ctx.fillStyle = 'black';
 
- 	    if (!canvas.width || canvas.width !== video.clientWidth) {
 
- 	      canvas.width = video.clientWidth;
 
- 	    }
 
- 	    ctx.fillRect(0, 0, canvas.width, canvas.height);
 
- 	    var pos = video.currentTime;
 
- 	    var bufferLen = 0;
 
- 	    ctx.fillStyle = 'gray';
 
- 	    for (var i = 0; i < r.length; i++) {
 
- 	      var start = r.start(i) / seekableEnd * canvas.width;
 
- 	      var end = r.end(i) / seekableEnd * canvas.width;
 
- 	      ctx.fillRect(start, 2, Math.max(2, end - start), 11);
 
- 	      if (pos >= r.start(i) && pos < r.end(i)) {
 
- 	        // play position is inside this buffer TimeRange, retrieve end of buffer position and buffer length
 
- 	        bufferLen = r.end(i) - pos;
 
- 	      }
 
- 	    }
 
- 	    // check if we are in buffering / or playback ended state
 
- 	    if (bufferLen <= 0.1 && video.paused === false && pos - lastStartPosition > 0.5) {
 
- 	      if (lastDuration - pos <= 0.5 && events.isLive === false) ; else {
 
- 	        // we are not at the end of the playlist ... real buffering
 
- 	        if (bufferingIdx !== -1) {
 
- 	          bufferingDuration = self.performance.now() - events.t0 - events.video[bufferingIdx].time;
 
- 	          events.video[bufferingIdx].duration = bufferingDuration;
 
- 	          events.video[bufferingIdx].name = bufferingDuration;
 
- 	        } else {
 
- 	          events.video.push({
 
- 	            type: 'buffering',
 
- 	            time: self.performance.now() - events.t0
 
- 	          });
 
- 	          trimEventHistory();
 
- 	          // we are in buffering state
 
- 	          bufferingIdx = events.video.length - 1;
 
- 	        }
 
- 	      }
 
- 	    }
 
- 	    if (bufferLen > 0.1 && bufferingIdx !== -1) {
 
- 	      bufferingDuration = self.performance.now() - events.t0 - events.video[bufferingIdx].time;
 
- 	      events.video[bufferingIdx].duration = bufferingDuration;
 
- 	      events.video[bufferingIdx].name = bufferingDuration;
 
- 	      // we are out of buffering state
 
- 	      bufferingIdx = -1;
 
- 	    }
 
- 	    // update buffer/position for current Time
 
- 	    var event = {
 
- 	      time: self.performance.now() - events.t0,
 
- 	      buffer: Math.round(bufferLen * 1000),
 
- 	      pos: Math.round(pos * 1000)
 
- 	    };
 
- 	    var bufEvents = events.buffer;
 
- 	    var bufEventLen = bufEvents.length;
 
- 	    if (bufEventLen > 1) {
 
- 	      var event0 = bufEvents[bufEventLen - 2];
 
- 	      var event1 = bufEvents[bufEventLen - 1];
 
- 	      var slopeBuf0 = (event0.buffer - event1.buffer) / (event0.time - event1.time);
 
- 	      var slopeBuf1 = (event1.buffer - event.buffer) / (event1.time - event.time);
 
- 	      var slopePos0 = (event0.pos - event1.pos) / (event0.time - event1.time);
 
- 	      var slopePos1 = (event1.pos - event.pos) / (event1.time - event.time);
 
- 	      // compute slopes. if less than 30% difference, remove event1
 
- 	      if ((slopeBuf0 === slopeBuf1 || Math.abs(slopeBuf0 / slopeBuf1 - 1) <= 0.3) && (slopePos0 === slopePos1 || Math.abs(slopePos0 / slopePos1 - 1) <= 0.3)) {
 
- 	        bufEvents.pop();
 
- 	      }
 
- 	    }
 
- 	    events.buffer.push(event);
 
- 	    trimEventHistory();
 
- 	    self.refreshCanvas();
 
- 	    if ($('#statsDisplayTab').is(':visible')) {
 
- 	      var log = "Duration: " + video.duration + "\nBuffered: " + timeRangesToString(video.buffered) + "\nSeekable: " + timeRangesToString(video.seekable) + "\nPlayed: " + timeRangesToString(video.played) + "\n";
 
- 	      if (hls.media) {
 
- 	        for (var type in tracks) {
 
- 	          log += "Buffer for " + type + " contains:" + timeRangesToString(tracks[type].buffer.buffered) + "\n";
 
- 	        }
 
- 	        var videoPlaybackQuality = video.getVideoPlaybackQuality;
 
- 	        if (videoPlaybackQuality && typeof videoPlaybackQuality === typeof Function) {
 
- 	          log += "Dropped frames: " + video.getVideoPlaybackQuality().droppedVideoFrames + "\n";
 
- 	          log += "Corrupted frames: " + video.getVideoPlaybackQuality().corruptedVideoFrames + "\n";
 
- 	        } else if (video.webkitDroppedFrameCount) {
 
- 	          log += "Dropped frames: " + video.webkitDroppedFrameCount + "\n";
 
- 	        }
 
- 	      }
 
- 	      log += "TTFB Estimate: " + hls.ttfbEstimate.toFixed(3) + "\n";
 
- 	      log += "Bandwidth Estimate: " + hls.bandwidthEstimate.toFixed(3) + "\n";
 
- 	      if (events.isLive) {
 
- 	        log += 'Live Stats:\n' + ("  Max Latency: " + hls.maxLatency + "\n") + ("  Target Latency: " + hls.targetLatency.toFixed(3) + "\n") + ("  Latency: " + hls.latency.toFixed(3) + "\n") + ("  Drift: " + hls.drift.toFixed(3) + " (edge advance rate)\n") + ("  Edge Stall: " + hls.latencyController.edgeStalled.toFixed(3) + " (playlist refresh over target duration/part)\n") + ("  Playback rate: " + video.playbackRate.toFixed(2) + "\n");
 
- 	        if (stats.fragProgramDateTime) {
 
- 	          var currentPDT = stats.fragProgramDateTime + (video.currentTime - stats.fragStart) * 1000;
 
- 	          log += "  Program Date Time: " + new Date(currentPDT).toISOString();
 
- 	          var pdtLatency = (Date.now() - currentPDT) / 1000;
 
- 	          if (pdtLatency > 0) {
 
- 	            log += " (" + pdtLatency.toFixed(3) + " seconds ago)";
 
- 	          }
 
- 	        }
 
- 	      }
 
- 	      $('#bufferedOut').text(log);
 
- 	      $('#statisticsOut').text(JSON.stringify(sortObject(stats), null, '\t'));
 
- 	    }
 
- 	    ctx.fillStyle = 'blue';
 
- 	    var x = video.currentTime / seekableEnd * canvas.width;
 
- 	    ctx.fillRect(x, 0, 2, 15);
 
- 	  } else if (ctx.fillStyle !== 'black') {
 
- 	    ctx.fillStyle = 'black';
 
- 	    ctx.fillRect(0, 0, canvas.width, canvas.height);
 
- 	  }
 
- 	}
 
- 	function showCanvas() {
 
- 	  self.showMetrics();
 
- 	  $('#bufferedOut').show();
 
- 	  $('#bufferedCanvas').show();
 
- 	}
 
- 	function hideCanvas() {
 
- 	  self.hideMetrics();
 
- 	  $('#bufferedOut').hide();
 
- 	  $('#bufferedCanvas').hide();
 
- 	}
 
- 	function getMetrics() {
 
- 	  var json = JSON.stringify(events);
 
- 	  var jsonpacked = main.pack(json);
 
- 	  // console.log('packing JSON from ' + json.length + ' to ' + jsonpacked.length + ' bytes');
 
- 	  return btoa(jsonpacked);
 
- 	}
 
- 	self.copyMetricsToClipBoard = function () {
 
- 	  copyTextToClipboard(getMetrics());
 
- 	};
 
- 	self.goToMetrics = function () {
 
- 	  var url = document.URL;
 
- 	  url = url.slice(0, url.lastIndexOf('/') + 1) + 'metrics.html';
 
- 	  self.open(url, '_blank');
 
- 	};
 
- 	function goToMetricsPermaLink() {
 
- 	  var url = document.URL;
 
- 	  var b64 = getMetrics();
 
- 	  url = url.slice(0, url.lastIndexOf('/') + 1) + 'metrics.html#data=' + b64;
 
- 	  self.open(url, '_blank');
 
- 	}
 
- 	function onClickBufferedRange(event) {
 
- 	  var canvas = document.querySelector('#bufferedCanvas');
 
- 	  var target = (event.clientX - canvas.offsetLeft) / canvas.width * getSeekableEnd();
 
- 	  video.currentTime = target;
 
- 	}
 
- 	function getSeekableEnd() {
 
- 	  if (isFinite(video.duration)) {
 
- 	    return video.duration;
 
- 	  }
 
- 	  if (video.seekable.length) {
 
- 	    return video.seekable.end(video.seekable.length - 1);
 
- 	  }
 
- 	  return 0;
 
- 	}
 
- 	function getLevelButtonHtml(key, levels, onclickReplace, autoEnabled) {
 
- 	  var onclickAuto = (key + "=-1").replace(/^(\w+)=([^=]+)$/, onclickReplace);
 
- 	  var codecs = levels.reduce(function (uniqueCodecs, level) {
 
- 	    var levelCodecs = codecs2label(level.attrs.CODECS);
 
- 	    if (levelCodecs && uniqueCodecs.indexOf(levelCodecs) === -1) {
 
- 	      uniqueCodecs.push(levelCodecs);
 
- 	    }
 
- 	    return uniqueCodecs;
 
- 	  }, []);
 
- 	  return "<button type=\"button\" class=\"btn btn-sm " + (autoEnabled ? 'btn-primary' : 'btn-success') + "\" onclick=\"" + onclickAuto + "\">auto</button>" + levels.map(function (level, i) {
 
- 	    var enabled = hls[key] === i;
 
- 	    var onclick = (key + "=" + i).replace(/^(\w+)=(\w+)$/, onclickReplace);
 
- 	    var label = level2label(levels[i], i, codecs);
 
- 	    return "<button type=\"button\" class=\"btn btn-sm " + (enabled ? 'btn-primary' : 'btn-success') + "\" onclick=\"" + onclick + "\">" + label + "</button>";
 
- 	  }).join('');
 
- 	}
 
- 	function updateLevelInfo() {
 
- 	  var levels = hls.levels;
 
- 	  if (!levels) {
 
- 	    return;
 
- 	  }
 
- 	  var htmlCurrentLevel = getLevelButtonHtml('currentLevel', levels, 'hls.$1=$2', hls.autoLevelEnabled);
 
- 	  var htmlNextLevel = getLevelButtonHtml('nextLevel', levels, 'hls.$1=$2', hls.autoLevelEnabled);
 
- 	  var htmlLoadLevel = getLevelButtonHtml('loadLevel', levels, 'hls.$1=$2', hls.autoLevelEnabled);
 
- 	  var htmlCapLevel = getLevelButtonHtml('autoLevelCapping', levels, 'levelCapping=hls.$1=$2;updateLevelInfo();onDemoConfigChanged();', hls.autoLevelCapping === -1);
 
- 	  if ($('#currentLevelControl').html() !== htmlCurrentLevel) {
 
- 	    $('#currentLevelControl').html(htmlCurrentLevel);
 
- 	  }
 
- 	  if ($('#nextLevelControl').html() !== htmlNextLevel) {
 
- 	    $('#nextLevelControl').html(htmlNextLevel);
 
- 	  }
 
- 	  if ($('#loadLevelControl').html() !== htmlLoadLevel) {
 
- 	    $('#loadLevelControl').html(htmlLoadLevel);
 
- 	  }
 
- 	  if ($('#levelCappingControl').html() !== htmlCapLevel) {
 
- 	    $('#levelCappingControl').html(htmlCapLevel);
 
- 	  }
 
- 	}
 
- 	function updateAudioTrackInfo() {
 
- 	  var buttonTemplate = '<button type="button" class="btn btn-sm ';
 
- 	  var buttonEnabled = 'btn-primary" ';
 
- 	  var buttonDisabled = 'btn-success" ';
 
- 	  var html1 = '';
 
- 	  var audioTrackId = hls.audioTrack;
 
- 	  var len = hls.audioTracks.length;
 
- 	  var track = hls.audioTracks[audioTrackId];
 
- 	  for (var i = 0; i < len; i++) {
 
- 	    html1 += buttonTemplate;
 
- 	    if (audioTrackId === i) {
 
- 	      html1 += buttonEnabled;
 
- 	    } else {
 
- 	      html1 += buttonDisabled;
 
- 	    }
 
- 	    html1 += 'onclick="hls.audioTrack=' + i + '">' + hls.audioTracks[i].name + '</button>';
 
- 	  }
 
- 	  $('#audioTrackLabel').text(track ? track.lang || track.name : 'None selected');
 
- 	  $('#audioTrackControl').html(html1);
 
- 	}
 
- 	function codecs2label(levelCodecs) {
 
- 	  if (levelCodecs) {
 
- 	    return levelCodecs.replace(/([ah]vc.)[^,;]+/, '$1').replace('mp4a.40.2', 'mp4a');
 
- 	  }
 
- 	  return '';
 
- 	}
 
- 	function level2label(level, i, manifestCodecs) {
 
- 	  var levelCodecs = codecs2label(level.attrs.CODECS);
 
- 	  var levelNameInfo = level.name ? "\"" + level.name + "\": " : '';
 
- 	  var codecInfo = levelCodecs && manifestCodecs.length > 1 ? " / " + levelCodecs : '';
 
- 	  if (level.height) {
 
- 	    return i + " (" + levelNameInfo + level.height + "p / " + Math.round(level.bitrate / 1024) + "kb" + codecInfo + ")";
 
- 	  }
 
- 	  if (level.bitrate) {
 
- 	    return i + " (" + levelNameInfo + Math.round(level.bitrate / 1024) + "kb" + codecInfo + ")";
 
- 	  }
 
- 	  if (codecInfo) {
 
- 	    return i + " (" + levelNameInfo + levelCodecs + ")";
 
- 	  }
 
- 	  if (level.name) {
 
- 	    return i + " (" + level.name + ")";
 
- 	  }
 
- 	  return "" + i;
 
- 	}
 
- 	function getDemoConfigPropOrDefault(propName, defaultVal) {
 
- 	  return typeof demoConfig[propName] !== 'undefined' ? demoConfig[propName] : defaultVal;
 
- 	}
 
- 	function getURLParam(sParam, defaultValue) {
 
- 	  var sPageURL = self.location.search.substring(1);
 
- 	  var sURLVariables = sPageURL.split('&');
 
- 	  for (var i = 0; i < sURLVariables.length; i++) {
 
- 	    var sParameterName = sURLVariables[i].split('=');
 
- 	    if (sParameterName[0] === sParam) {
 
- 	      return sParameterName[1] === 'undefined' ? undefined : sParameterName[1] === 'false' ? false : sParameterName[1];
 
- 	    }
 
- 	  }
 
- 	  return defaultValue;
 
- 	}
 
- 	function onDemoConfigChanged(firstLoad) {
 
- 	  demoConfig = {
 
- 	    enableStreaming: enableStreaming,
 
- 	    autoRecoverError: autoRecoverError,
 
- 	    stopOnStall: stopOnStall,
 
- 	    dumpfMP4: dumpfMP4,
 
- 	    levelCapping: levelCapping,
 
- 	    limitMetrics: limitMetrics
 
- 	  };
 
- 	  if (configPersistenceEnabled) {
 
- 	    persistEditorValue();
 
- 	  }
 
- 	  var serializedDemoConfig = btoa(JSON.stringify(demoConfig));
 
- 	  var baseURL = document.URL.split('?')[0];
 
- 	  var streamURL = $('#streamURL').val();
 
- 	  var permalinkURL = baseURL + "?src=" + encodeURIComponent(streamURL) + "&demoConfig=" + serializedDemoConfig;
 
- 	  $('#StreamPermalink').html("<a href=\"" + permalinkURL + "\">" + permalinkURL + "</a>");
 
- 	  if (!firstLoad && self.location.href !== permalinkURL) {
 
- 	    self.history.pushState(null, null, permalinkURL);
 
- 	  }
 
- 	}
 
- 	function onConfigPersistenceChanged(event) {
 
- 	  configPersistenceEnabled = event.target.checked;
 
- 	  localStorage.setItem(STORAGE_KEYS.Editor_Persistence, JSON.stringify(configPersistenceEnabled));
 
- 	  if (configPersistenceEnabled) {
 
- 	    persistEditorValue();
 
- 	  } else {
 
- 	    localStorage.removeItem(STORAGE_KEYS.Hls_Config);
 
- 	  }
 
- 	}
 
- 	function getEditorValue(options) {
 
- 	  options = $.extend({
 
- 	    parse: false
 
- 	  }, options || {});
 
- 	  var value = configEditor.session.getValue();
 
- 	  if (options.parse) {
 
- 	    try {
 
- 	      value = JSON.parse(value);
 
- 	    } catch (e) {
 
- 	      console.warn('[getEditorValue] could not parse editor value', e);
 
- 	      value = {};
 
- 	    }
 
- 	  }
 
- 	  return value;
 
- 	}
 
- 	function getPersistedHlsConfig() {
 
- 	  var value = localStorage.getItem(STORAGE_KEYS.Hls_Config);
 
- 	  if (value === null) {
 
- 	    return value;
 
- 	  }
 
- 	  try {
 
- 	    value = JSON.parse(value);
 
- 	  } catch (e) {
 
- 	    console.warn('[getPersistedHlsConfig] could not hls config json', e);
 
- 	    value = {};
 
- 	  }
 
- 	  return value;
 
- 	}
 
- 	function persistEditorValue() {
 
- 	  localStorage.setItem(STORAGE_KEYS.Hls_Config, getEditorValue());
 
- 	}
 
- 	function setupConfigEditor() {
 
- 	  configEditor = self.ace.edit('config-editor');
 
- 	  configEditor.setTheme('ace/theme/github');
 
- 	  configEditor.session.setMode('ace/mode/json');
 
- 	  var contents = hlsjsDefaults;
 
- 	  var shouldRestorePersisted = JSON.parse(localStorage.getItem(STORAGE_KEYS.Editor_Persistence)) === true;
 
- 	  if (shouldRestorePersisted) {
 
- 	    $.extend(contents, getPersistedHlsConfig());
 
- 	  }
 
- 	  var elPersistence = document.querySelector('#config-persistence');
 
- 	  elPersistence.addEventListener('change', onConfigPersistenceChanged);
 
- 	  elPersistence.checked = shouldRestorePersisted;
 
- 	  configPersistenceEnabled = shouldRestorePersisted;
 
- 	  updateConfigEditorValue(contents);
 
- 	}
 
- 	function setupTimelineChart() {
 
- 	  var canvas = document.querySelector('#timeline-chart');
 
- 	  var chart = new TimelineChart(canvas, {
 
- 	    responsive: false
 
- 	  });
 
- 	  resizeHandlers.push(function () {
 
- 	    chart.resize();
 
- 	  });
 
- 	  chart.resize();
 
- 	  return chart;
 
- 	}
 
- 	function addChartEventListeners(hls) {
 
- 	  var updateLevelOrTrack = function updateLevelOrTrack(eventName, data) {
 
- 	    chart.updateLevelOrTrack(data.details);
 
- 	  };
 
- 	  var updateFragment = function updateFragment(eventName, data) {
 
- 	    if (data.stats) {
 
- 	      // Convert 0.x stats to partial v1 stats
 
- 	      var _data$stats = data.stats,
 
- 	        retry = _data$stats.retry,
 
- 	        loaded = _data$stats.loaded,
 
- 	        total = _data$stats.total,
 
- 	        trequest = _data$stats.trequest,
 
- 	        tfirst = _data$stats.tfirst,
 
- 	        tload = _data$stats.tload;
 
- 	      if (trequest && tload) {
 
- 	        data.frag.stats = {
 
- 	          loaded: loaded,
 
- 	          retry: retry,
 
- 	          total: total,
 
- 	          loading: {
 
- 	            start: trequest,
 
- 	            first: tfirst,
 
- 	            end: tload
 
- 	          }
 
- 	        };
 
- 	      }
 
- 	    }
 
- 	    chart.updateFragment(data);
 
- 	  };
 
- 	  var updateChart = function updateChart() {
 
- 	    chart.update();
 
- 	  };
 
- 	  hls.on(Hls.Events.MANIFEST_LOADING, function () {
 
- 	    chart.reset();
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.MANIFEST_PARSED, function (eventName, data) {
 
- 	    var levels = data.levels;
 
- 	    chart.removeType('level');
 
- 	    chart.removeType('audioTrack');
 
- 	    chart.removeType('subtitleTrack');
 
- 	    chart.updateLevels(levels);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.BUFFER_CREATED, function (eventName, _ref) {
 
- 	    var tracks = _ref.tracks;
 
- 	    chart.updateSourceBuffers(tracks, hls.media);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.BUFFER_RESET, function () {
 
- 	    chart.removeSourceBuffers();
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.LEVELS_UPDATED, function (eventName, _ref2) {
 
- 	    var levels = _ref2.levels;
 
- 	    chart.removeType('level');
 
- 	    chart.updateLevels(levels);
 
- 	  });
 
- 	  hls.on(Hls.Events.LEVEL_SWITCHED, function (eventName, _ref3) {
 
- 	    var level = _ref3.level;
 
- 	    chart.removeType('level');
 
- 	    chart.updateLevels(hls.levels, level);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.LEVEL_LOADING, function () {
 
- 	    // TODO: mutate level datasets
 
- 	    // Update loadLevel
 
- 	    chart.removeType('level');
 
- 	    chart.updateLevels(hls.levels);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.LEVEL_UPDATED, function (eventName, _ref4) {
 
- 	    var details = _ref4.details;
 
- 	    chart.updateLevelOrTrack(details);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, function (eventName, _ref5) {
 
- 	    var audioTracks = _ref5.audioTracks;
 
- 	    chart.removeType('audioTrack');
 
- 	    chart.updateAudioTracks(audioTracks);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, function (eventName, _ref6) {
 
- 	    var subtitleTracks = _ref6.subtitleTracks;
 
- 	    chart.removeType('subtitleTrack');
 
- 	    chart.updateSubtitleTracks(subtitleTracks);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.AUDIO_TRACK_SWITCHED, function (eventName) {
 
- 	    // TODO: mutate level datasets
 
- 	    chart.removeType('audioTrack');
 
- 	    chart.updateAudioTracks(hls.audioTracks);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.SUBTITLE_TRACK_SWITCH, function (eventName) {
 
- 	    // TODO: mutate level datasets
 
- 	    chart.removeType('subtitleTrack');
 
- 	    chart.updateSubtitleTracks(hls.subtitleTracks);
 
- 	  }, chart);
 
- 	  hls.on(Hls.Events.AUDIO_TRACK_LOADED, updateLevelOrTrack, chart);
 
- 	  hls.on(Hls.Events.SUBTITLE_TRACK_LOADED, updateLevelOrTrack, chart);
 
- 	  hls.on(Hls.Events.LEVEL_PTS_UPDATED, updateLevelOrTrack, chart);
 
- 	  hls.on(Hls.Events.FRAG_LOADED, updateFragment, chart);
 
- 	  hls.on(Hls.Events.FRAG_PARSED, updateFragment, chart);
 
- 	  hls.on(Hls.Events.FRAG_CHANGED, updateFragment, chart);
 
- 	  hls.on(Hls.Events.BUFFER_APPENDING, updateChart, chart);
 
- 	  hls.on(Hls.Events.BUFFER_APPENDED, updateChart, chart);
 
- 	  hls.on(Hls.Events.BUFFER_FLUSHED, updateChart, chart);
 
- 	}
 
- 	function updateConfigEditorValue(obj) {
 
- 	  var json = JSON.stringify(obj, null, 2);
 
- 	  configEditor.session.setValue(json);
 
- 	}
 
- 	function applyConfigEditorValue() {
 
- 	  onDemoConfigChanged();
 
- 	  loadSelectedStream();
 
- 	}
 
- 	function createfMP4(type) {
 
- 	  if (fmp4Data[type].length) {
 
- 	    var blob = new Blob([arrayConcat(fmp4Data[type])], {
 
- 	      type: 'application/octet-stream'
 
- 	    });
 
- 	    var filename = type + '-' + new Date().toISOString() + '.mp4';
 
- 	    self.saveAs(blob, filename);
 
- 	    // $('body').append('<a download="hlsjs-' + filename + '" href="' + self.URL.createObjectURL(blob) + '">Download ' + filename + ' track</a><br>');
 
- 	  } else if (!dumpfMP4) {
 
- 	    console.error('Check "Dump transmuxed fMP4 data" first to make appended media available for saving.');
 
- 	  }
 
- 	}
 
- 	function arrayConcat(inputArray) {
 
- 	  var totalLength = inputArray.reduce(function (prev, cur) {
 
- 	    return prev + cur.length;
 
- 	  }, 0);
 
- 	  var result = new Uint8Array(totalLength);
 
- 	  var offset = 0;
 
- 	  inputArray.forEach(function (element) {
 
- 	    result.set(element, offset);
 
- 	    offset += element.length;
 
- 	  });
 
- 	  return result;
 
- 	}
 
- 	function hideAllTabs() {
 
- 	  $('.demo-tab-btn').css('background-color', '');
 
- 	  $('.demo-tab').hide();
 
- 	}
 
- 	function toggleTabClick(btn) {
 
- 	  toggleTab(btn);
 
- 	  var tabIndexes = $('.demo-tab-btn').toArray().map(function (el, i) {
 
- 	    return $('#' + $(el).data('tab')).is(':visible') ? i : null;
 
- 	  }).filter(function (i) {
 
- 	    return i !== null;
 
- 	  });
 
- 	  localStorage.setItem(STORAGE_KEYS.demo_tabs, tabIndexes.join(','));
 
- 	}
 
- 	function toggleTab(btn, dontHideOpenTabs) {
 
- 	  var tabElId = $(btn).data('tab');
 
- 	  // eslint-disable-next-line no-restricted-globals
 
- 	  var modifierPressed = dontHideOpenTabs || self.event && (self.event.metaKey || self.event.shiftKey);
 
- 	  if (!modifierPressed) {
 
- 	    hideAllTabs();
 
- 	  }
 
- 	  if (modifierPressed) {
 
- 	    $("#" + tabElId).toggle();
 
- 	  } else {
 
- 	    $("#" + tabElId).show();
 
- 	  }
 
- 	  $(btn).css('background-color', $("#" + tabElId).is(':visible') ? 'orange' : '');
 
- 	  if (!$('#statsDisplayTab').is(':visible')) {
 
- 	    self.hideMetrics();
 
- 	  }
 
- 	  if (hls) {
 
- 	    if ($('#timelineTab').is(':visible')) {
 
- 	      chart.show();
 
- 	      chart.resize(chart.chart.data ? chart.chart.data.datasets : null);
 
- 	    } else {
 
- 	      chart.hide();
 
- 	    }
 
- 	  }
 
- 	}
 
- 	function appendLog(textElId, message) {
 
- 	  var el = $('#' + textElId);
 
- 	  var logText = el.text();
 
- 	  if (logText.length) {
 
- 	    logText += '\n';
 
- 	  }
 
- 	  var timestamp = (Date.now() - startTime) / 1000;
 
- 	  var newMessage = timestamp + ' | ' + message;
 
- 	  logText += newMessage;
 
- 	  // update
 
- 	  el.text(logText);
 
- 	  var element = el[0];
 
- 	  element.scrollTop = element.scrollHeight - element.clientHeight;
 
- 	}
 
- 	function logStatus(message) {
 
- 	  appendLog('statusOut', message);
 
- 	}
 
- 	function logError(message) {
 
- 	  appendLog('errorOut', message);
 
- 	}
 
- }));
 
- //# sourceMappingURL=hls-demo.js.map
 
 
  |