From e220b65c8fbd1088a42cee09325a49ae7facaa03 Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 11 Aug 2020 11:19:31 -0400 Subject: [PATCH 01/13] handle various time formats in ticklabelmode period --- src/plots/cartesian/axes.js | 48 ++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index dab9a3ce4e7..787b0cd0c88 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -700,18 +700,44 @@ axes.calcTicks = function calcTicks(ax, opts) { }; if( - !_has('%f') && - !_has('%H') && - !_has('%I') && - !_has('%L') && - !_has('%Q') && - !_has('%S') && - !_has('%s') && - !_has('%X') + !_has('%f') && // microseconds as a decimal number [000000, 999999] + !_has('%L') && // milliseconds as a decimal number [000, 999] + !_has('%Q') && // milliseconds since UNIX epoch + !_has('%s') && // seconds since UNIX epoch + !_has('%S') && // second as a decimal number [00,61] + !_has('%M') && // minute as a decimal number [00,59] + !_has('%H') && // hour (24-hour clock) as a decimal number [00,23] + !_has('%I') && // hour (12-hour clock) as a decimal number [01,12] + !_has('%p') && // either AM or PM + !_has('%X') // the locale’s time, such as %-I:%M:%S %p ) { - if(_has('%x') || _has('%d') || _has('%e') || _has('%j')) definedDelta = ONEDAY; - else if(_has('%B') || _has('%b') || _has('%m')) definedDelta = ONEAVGMONTH; - else if(_has('%Y') || _has('%y')) definedDelta = ONEAVGYEAR; + if( + _has('%d') || // zero-padded day of the month as a decimal number [01,31] + _has('%e') || // space-padded day of the month as a decimal number [ 1,31] + _has('%j') || // day of the year as a decimal number [001,366] + _has('%u') || // Monday-based (ISO 8601) weekday as a decimal number [1,7] + _has('%w') || // Sunday-based weekday as a decimal number [0,6] + _has('%x') // the locale’s date, such as %-m/%-d/%Y + ) definedDelta = ONEDAY; + else if( + _has('%A') || // full weekday name + _has('%a') || // abbreviated weekday name + _has('%U') || // Sunday-based week of the year as a decimal number [00,53] + _has('%V') || // ISO 8601 week of the year as a decimal number [01, 53] + _has('%W') // Monday-based week of the year as a decimal number [00,53] + ) definedDelta = ONEDAY * 7; + else if( + _has('%B') || // full month name + _has('%b') || // abbreviated month name + _has('%m') // month as a decimal number [01,12] + ) definedDelta = ONEAVGMONTH; + else if( + _has('%q') // quarter of the year as a decimal number [1,4] + ) definedDelta = ONEAVGYEAR / 4; + else if( + _has('%Y') || // year with century as a decimal number, such as 1999 + _has('%y') // year without century as a decimal number [00,99] + ) definedDelta = ONEAVGYEAR; } } From 9424347a37c95d660bd2e4b9677a33834c112583 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 09:26:24 -0400 Subject: [PATCH 02/13] move weekdays to ONEDAY bucket --- src/plots/cartesian/axes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 787b0cd0c88..0c1efb3ec17 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -712,6 +712,8 @@ axes.calcTicks = function calcTicks(ax, opts) { !_has('%X') // the locale’s time, such as %-I:%M:%S %p ) { if( + _has('%A') || // full weekday name + _has('%a') || // abbreviated weekday name _has('%d') || // zero-padded day of the month as a decimal number [01,31] _has('%e') || // space-padded day of the month as a decimal number [ 1,31] _has('%j') || // day of the year as a decimal number [001,366] @@ -720,8 +722,6 @@ axes.calcTicks = function calcTicks(ax, opts) { _has('%x') // the locale’s date, such as %-m/%-d/%Y ) definedDelta = ONEDAY; else if( - _has('%A') || // full weekday name - _has('%a') || // abbreviated weekday name _has('%U') || // Sunday-based week of the year as a decimal number [00,53] _has('%V') || // ISO 8601 week of the year as a decimal number [01, 53] _has('%W') // Monday-based week of the year as a decimal number [00,53] From ca993b9d027d94b8021427c91f659335cbde0e7f Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 10:06:40 -0400 Subject: [PATCH 03/13] apply weekly and quarter offsets in periodic labels --- src/plots/cartesian/axes.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index dbea4fd5f96..f4eb2bcdc9b 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -24,7 +24,9 @@ var cleanTicks = require('./clean_ticks'); var constants = require('../../constants/numerical'); var ONEAVGYEAR = constants.ONEAVGYEAR; +var ONEAVGQUARTER = constants.ONEAVGYEAR / 4; var ONEAVGMONTH = constants.ONEAVGMONTH; +var ONEWEEK = constants.ONEDAY * 7; var ONEDAY = constants.ONEDAY; var ONEHOUR = constants.ONEHOUR; var ONEMIN = constants.ONEMIN; @@ -725,7 +727,7 @@ axes.calcTicks = function calcTicks(ax, opts) { _has('%U') || // Sunday-based week of the year as a decimal number [00,53] _has('%V') || // ISO 8601 week of the year as a decimal number [01, 53] _has('%W') // Monday-based week of the year as a decimal number [00,53] - ) definedDelta = ONEDAY * 7; + ) definedDelta = ONEWEEK; else if( _has('%B') || // full month name _has('%b') || // abbreviated month name @@ -733,7 +735,7 @@ axes.calcTicks = function calcTicks(ax, opts) { ) definedDelta = ONEAVGMONTH; else if( _has('%q') // quarter of the year as a decimal number [1,4] - ) definedDelta = ONEAVGYEAR / 4; + ) definedDelta = ONEAVGQUARTER; else if( _has('%Y') || // year with century as a decimal number, such as 1999 _has('%y') // year without century as a decimal number [00,99] @@ -774,8 +776,12 @@ axes.calcTicks = function calcTicks(ax, opts) { var delta = definedDelta || Math.abs(B - A); if(delta >= ONEDAY * 365) { // Years could have days less than ONEAVGYEAR period v += ONEAVGYEAR / 2; + } else if(delta >= ONEAVGQUARTER) { + v += ONEAVGQUARTER / 2; } else if(delta >= ONEDAY * 28) { // Months could have days less than ONEAVGMONTH period v += ONEAVGMONTH / 2; + } else if(delta >= ONEWEEK) { + v += ONEWEEK / 2; } else if(delta >= ONEDAY) { v += ONEDAY / 2; } From 4a87806cc2de10dfd6003d7ced0c36efeb552544 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 10:14:12 -0400 Subject: [PATCH 04/13] declare week and average quarter in milliseconds in numerical constants --- src/constants/numerical.js | 2 ++ src/plots/cartesian/set_convert.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/constants/numerical.js b/src/constants/numerical.js index d44f82ae2ce..8d535a9c2d9 100644 --- a/src/constants/numerical.js +++ b/src/constants/numerical.js @@ -32,7 +32,9 @@ module.exports = { * have the same length */ ONEAVGYEAR: 31557600000, // 365.25 days + ONEAVGQUARTER: 7889400000, // 1/4 of ONEAVGYEAR ONEAVGMONTH: 2629800000, // 1/12 of ONEAVGYEAR + ONEWEEK: 604800000, // 7 * ONEDAY ONEDAY: 86400000, ONEHOUR: 3600000, ONEMIN: 60000, diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index 7dc1a272114..1100cef9340 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -23,6 +23,7 @@ var numConstants = require('../../constants/numerical'); var FP_SAFE = numConstants.FP_SAFE; var BADNUM = numConstants.BADNUM; var LOG_CLIP = numConstants.LOG_CLIP; +var ONEWEEK = numConstants.ONEWEEK; var ONEDAY = numConstants.ONEDAY; var ONEHOUR = numConstants.ONEHOUR; var ONEMIN = numConstants.ONEMIN; @@ -734,7 +735,7 @@ module.exports = function setConvert(ax, fullLayout) { switch(brk.pattern) { case WEEKDAY_PATTERN: - step = 7 * ONEDAY; + step = ONEWEEK; bndDelta = ( (b1 < b0 ? 7 : 0) + From c3e518127a713d0deb8baa2126480dec3b1fe440 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 10:15:44 -0400 Subject: [PATCH 05/13] update baseline --- test/image/baselines/date_axes_period.png | Bin 40884 -> 40750 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/image/baselines/date_axes_period.png b/test/image/baselines/date_axes_period.png index c335091cbec6d28159727250fb6e248ca224d452..991ce21014bcfbf11a415738186b1ce657713e55 100644 GIT binary patch literal 40750 zcmeFZg;!MF-~UZ_H_}~086eU~Bi-Gdg1}JHf>M&wNOyO)AR&T)bO}h8w8XRL`d)fJ z@w@Lo;92)tvu44-oH^(0y+84KzxTXVQIf&Ncz^*12Zt>uE2#zthoA!o2Y-r&0$y2F zQJ;i^qlJ@`6xVmCi7>Td5x5-r`=?tC^LSI%MyN=#}xAr>sIv4)3WPRv%F7i9mO=S1%ME=X1edX=l z!D?-Xefc5(K)%8UE_6)v_i%q60p>`qDkcJ-;;>`?>ot0@zE9=$US^kjKVuB~2{pS(R0x}0*nXp+Ont=OG z!mF*Xfe6DW{D1x-5XvAHXgR(%oWvQAO~EI-)aI41Rj!9mtiz&|{{H6bm%_n9Gv|5I zR5~-9X$FTj*XIx1S>F_Eg(HxZvP8=5)^tsd-*lxsvR>~A#Z>z!2Jif=t9Iz>*H7dz z2{knWTMIYv@g!IYNlDDTVYnaA37H2^x4-2(Ew+dRx*xAeVRD9OGchnc_nTp>>iI$T zWgMCzi4Z~my)_LU0aJpXmv{V3 zX?-N++nHP62|8<4kPa!o+j58B#`@>@9mEKVgG`@;ST4hsB8C_$!OiPic>Dp1MfZ^c zmZn$Rao55!(UeObj5uSjoqF*<-?(}vaVR&Pv42)?w4t0hI*+@egbo`E`s8(>hhma` zp(drwZ~xeZVb&xSL4sa@IuJ>oyRdfq`$C&$RxX}dYGgf~K9bC?m+@KF7KBUj`OdRv6N_ z8PD9~;1N+m9N{>yRZMiV*PSwC(aYR^KU_E4^cp60bGnynhF%AaUVF@qy^km?|K7NO zKTNzT@c86G>aEok60bV1vTM%z3m4_C4X#w$4{@%TZ8}~j>o3#w4|1*;wa1YL=BFMY zQSiK*c0E{O6S(>Etoi-RFP`Xfqr(cTIElGuab_LMV45ikL61zHXg+mXc-NQ*i={q*wzv14IjphiHLrzaKg1p6*5eNZQE~^i)#(mbvWSqvls0H+Am# zBsGfTCwr>$5nY3xD~Y(@uPDUAX-c(BF2C-urmkgqJ>jT)Z>Ra83TVTmt=149(n`jN z;ivZgd(w%A$kdQ~wd-x^3O~}O$4qVW5eUNwoe2p<*_wp92P9=9nGcBol?d!{t z=w^fa6D1ywey87Bb0Y`tu9{W+JzsR$JJ)5aI`Gb1Zw-=o*CB}}r5zh@95vdSE)vqO zeLu*4@)x#!+ng`<{asvbx)04Gip60*&11+~%F9xN*P;ejfu1|Qq%j$8^|uNsr0Z+q zyN4Ww6~p@;Cl@8`%|orfAVh3xeftLkuYMEhh>u|6PWfFdvfzqbejG`CqOeceptlocgryr3cdcZ;+e$h{*?##!80Nd233@VYy7; zMg}%lMmuX*LFI?q*1N{CY}pSbYDaG@4xjZuN+SSE&@~uh)TSeHxq?Xk*yjBL^hZ<) zpW22AziHHiCkvS0T<+r1eQ$BQ2Mvu~zq7G>?UL5M(zg!Vrc$7a3X+cu-e`}l>PBLs z>u!;~==feeh4`uaWGU0SfjY5PMp>bIr=Lm2)bsoL!xzt?=LKCDJQ{1E%E@|~}5Empb$)oQI2 zzmL8a*{`Eqex-6k!byv~`?S@5=DY}Rws6t{yu8ST!%&2r+u3_qS_%?InBwa9D;QsAIYAE0_Aebaqzs5v2 zrnHR{gHdtiLotXaUzw&nw1iN8X8+ru9Ls`OMP2^Ip7~EIa!G_kPAY}YKK;`hi3x$h zbRFCQVL0|;$wyhM(x_bG*<-s&+5X|4<%_-9Tr=Bp{YE7wx%TrpdrgCK->aH}wr=lA z9I9s)=;+6LwPPhK1*|&vp`zjJOEs1XUR&8=6*DFF(v+34YG_3B2jM6JirPSIM=TCh5mM@>kescOv zS)tnOgLz}hZGmX(ydy-nMiLoQ+Mv*CG_|;Ie>~N5f2P{p4jnOwp1}z}Gx(YNjs?e( z*8bgkyz&sZ_p3gY?%NYm*QeV*Mxw}9wMO>L&eJ;5lxFy5nqS{tS$kb=eAuY}ZWIsB zQ#x7AAuAeTnC`dJLX)cB%zT|~E`eAK8LtF7L*I~I=j(Q{1q07TcX_O~lOYbZa=j

j5zqbttTE?%h@)tbj9bsAf3S6t@Ks43Kg4>uS#gfttWNt4fKPkv$oG-LY zw^lko>EUlh{|u+bz@M*Xs!Z)XU5?lKEk}}h+1KBt@$N6wF~S;&zY==C4Y#yMch}q=|E+tNy?&jg2UlOSUbR^$ZTR6z zcQ9KOWydya6(vf^lZ&gLS;K*dsFMfJ?`v$v>6uXQ6zspG3+x=~Jni(kaPs;!%8z)U z65?6rFk3TGtj;n;xg$~3&0txNjU>~Lc3e_gq2}m&HlA|gAf@_1v7(`sxWt%sW^pW0r zM?LMSeSLp>F}yXNJGC;VxMby_{9+_^fpUA$Y9tvymNwN%Z*YW5G4(NToo+A+wy#H^ zwur%eYCSw^7l^3^Z5fwbLgzE)pzmKMf;InBslDM;#qN5IP8l0m(Akyz^Ff9f+1u+g z%Z;JLp;DyPI?G{_CpDj5VF(#Q@s9Du?C{o~hZGhYwtAEZ`_g)!@3CQ$K&lo{q{Ftf zw*&0ZVpxsOuvGyc6#Ppa;0{+K2Ke5Hp$4D<*N9RYZu0>MM7+jGu1PE)W zyUd@w+EOtN*0W?*; zsbotG30n72sEap=uAW_=eK!`aC7+1e#uS=J-jo@sEv@X(6D}NYGM^vex@0Ds#k$D0 zB83E_eQ&UGG+D_dPDdSMD@4oiLj(+ESiSzu6QwNQleeisgNeJYNp6xMS&wbw2&BQn z`0ya#glO9s?<;}25sPxB#u9PU5O2-p_s%;eOj0h5H7w-JRGQb9;^m)f=052=x99gg zSo1a=B@59U&yhlAShC>?!=X}R;K_T^Gc3@0b^>isbGfE7AMA%!29&yv8uTIp5gx)j%LswT}Z zNyEVfkGO+%ZC6dZ+0Gku$~_Q6^8tis*-@`unXAB-Kzz|@*=!LE>EcTpb8Hf6@k>0@ z2Sa6B^8q%!8gN3)TNKjaTc`y%x%DRSEPaWa_#;Yf8CAMy>qt$*Hs@yA^Q1t-Kzc3)^+eVER#P;u3dKOrwDD`=wYMLZW?hRH96+G-JD4OLMz zYZR-^27#!98Wb9Zs>5Aun6@iM^(-*Oa7Fk@4S7LAN6H zePC;cL9?r_UMOCPPIZo}pScp{f$xiPQ&U0dwAy-sxL!%h^?t*S2@wPPacxxHfQi8!V&%gLcsM|9noI`=tU=%dgdmNCVs&^G#h z{ay8^d~Vozz1V60#8hX}#(7yqMNPp1+LD#e{Z_GJV=28h2KG4L;bVwBup}UBR7k2p z7g4II+&rJ+LVXU~wcFiBcF1ox>qcq4j|)L|vvWgQQr2+_yfAr8!q94h9-cD#xV5Wb zb#A&0`}8>n$odPWAbz|IE!-~5dVNyfEK!?0)H^^ah;fX%hGB*xD8=LbsR*m$w)5^< zLD6m15}`X7Idf(x;t72+%XcI^p(oH|6Mj0g-pL9>{j()IisX*ThT-p}+RASu#l9uu z(7miDhiH6KdgA{woRmPqitJb#QUe;jB3wMPq~^~Qa6R=YrFe#R3y}JRacA#V6RL!H zN0VFng74MAIJ~=fHAtq|In`b95ma^IG@+gtZF6Yo!DfBP1DpDk9yNODR|}$~ zl0BAaT3vj5p%3aLU*5@_Q9dgV-s{n2E~Oc8r5F&;Lw4|VRpb6|=Sv&-6aXONFzKI6 z@qf^3lR^N(uwjQo#vfQni-WFW(w{x<_4#k%asVqzK5*-^{Ha^QpMxHji-Jn<;(ZH( z;CCHa+Dvp>KEj|MH89L8CWHqn(($3iR!{9>hq_6K^k_0VB*Z|>>>Fr;EYJPTPSV5tal{qPg%Su13xs8 z@TP~d5+&#mUkALxQq58=_8D3PXZqR42scvZN8=_pm#x2$dj6pZDsq{z>!g9Wu{d`B zRv6?S(|cq>G)-anywqbP*I{)}(PZt-rQ&;~Zq zf^p1AIYYqYHop-^G9wD7${X$OO!2D1)2TD4qQr^_(qk~GXv*DweqnP?WUfNUz@?#we#V1O4n+#W|B4BD5y~JS5SNlmi%Nw8 zuh;Q{Lp@}^(OFyk(SBa}IL#yLFO-QYRN{|S@m5@KE{`92omiaRYh?*wX*jiPGuzJA zSn?p<{4<{rV6DmVCl?8m)yZTMaibCyBoYw>S;FAHvGB`iTy>Ch{b&g41iVjemWeAs zRYk&OK&E11yN0RGlq_#S2hV|&PND}{2)TEr`mN$IexY5bb_IpLfGsqZhTij$jZRulByliqCY7h)|KtTfM-D_DX58kh=CwFGbdf{d^bRQh8ed_KboLL z+felhlMOn8@?;P`%sZJn>|%DPs1H z?KAk@+B!2nsiLVsRJc|&0dL&nPvNz_rwF^jxFRZ;Q}v6UGYRnBgbvswapPvsQ9L@9 zTzavS&>m1da$XXWQ&3R1$5mBRQ=2rA>?{}_suMzyOXGJ=>JCQL-@)a8X*>a@|N3+6^5+|A20+Fh7&nHZ1C>|^_;$G zh;RW7pk1p^yZ0FuGRc>~7}Z2}O%1BLm<)A17h-k|v{)?M2o?nIz|bQ!(fgZPXVjIx zw}h6xZ?FpxFsYdxzIJV5l(C$0A2BDgsedB1g6~YDicd`~0gIcst(A;N17t3cGB)g= zz3+lG6<~tMWT3X99aEY*=5C@#u%w;n$ps*#(}4v?F9WVX2JV|3RN&`Wma*f$^hk*c z^7KT$0w{g)5aJY%;^#OR`EQ^;l87WK%0)>d!{|g1iOQl zGKGCmZoYN(yH;5;AcQh2 zi9LQ5#I@!tQqoNX>4b>HeOo-XV|?}k@g=_tLv0Uo)9PnJ8rNdkbRO|xu>qw>wAc6}wO+qAqq9(V(N z9dWPIw@&!IpiurMK>wl}M^V6ylkIYZ;Z}5pL@cx2mEIoGPDN-L^&=#n@W-{Z9e|=adZ2saI^4@=wbQ2iDy&^?%Ur zKhI&{1p%yt(f?8x!8@XSXoZChkwqlo#sSQoeHy3v_cPYsg1=+i!#d0S?X9obh~PJ; zGWma1$75-bA9MOYaOxMFl+anC2GK}Q1c&xDprfN}=Mh%VxNEruz=hN&N%seC&PbyD z!+@hDp0SfSqtP}&)UfG_`6Kv|zGR7Vr=+B)RhfvxaIhXwH!b0b3FsMIe}|wGT7ZUF z4TLqo5f;pfF_4oQr-gj3>+){e4BT_1;|tN(G@JqG!a0Re>6MXE0YLM$eMUwH^GzyX`P|nl6CHCuVwLYz>{WWpdYl2T415 zW05J8jibPt%*cO1!I)oJVOmH&?H&M^g@{V~?5iYzyHf9nUVdymo<{-{WS(2EPL@ab zsnrPC2Fc-aXXo{xQtD$ls^WH+g|^U#4<9lbclf5$zan&f-@q%392muBmUM(pxo}mO zF6=&}_FVM!X(r{unRQZ2sC-f!#laq3s6tZ1q%>0dM^?x_~bh7BkO2*=|Dx%>BQPf-bWNtQ`8i&uUcW|-SdMjNN$+DEF$d<;>hN??AFa(O zYAzps=hIaizk7y>l_aIUcttSNW*?7$K0T4ee4*(jUkq0H_3`uK8pr)gwLA;9;)#!@ zHc>}K5Tvft%k1Y##TJ>**nT$@u*L#jcJOgP+@|Zfd40NoWo5^dN3C1?N&T+g!BV$q zAqfVJ^-o1 z(QZ){1H+D+w`y$?Ov7iY)ecd5=R4Ys+RI8m z=KXcKL|^y_4%3xi3o&a_@YjEP(NG$}Hc=iB&Sk4odK z0!UQ82VOxz!H@!XdtP+kp;LmJ^+QYfQ`$Gdu)Dd{xzlJ0 zhaN}5UC*NdJ2s7+1R_>F1Fx!;b}TI(yZ*^HQ*o66Zn*}fKO-BwQ5&2SIYsYf+*`fl zDe_-T*^PUk^Nug;=m#S^pYxKoC*X~Hw9Q)afBv$pJsjw$Us*Kac@m~pWy7m|!0oVO zhMoZj&ej8#9UGTBguD;NbHfb$Z_ivW7CncK+T=8LuAFp=U71??wfl6ab|tvsfBg4D)-9m z?YrsTiTuTgN2JuDTTfFFIKnd;oEF(DJMUUvWD4m{Nxp9fEL&aV?$TUNUjAKpA~`At zeX^o*51YiHW7mH@X$UOMciG{B`};nKgG3OG#_v?scBU%Z_qd<5#`o$ZyuZ7~PIj8% zPuDak0>%O|vj%8Lg0``rCJwa_E2v;pzJ*#2HKpZrNi^z&{>gi^FseUP@W!<9FKEvB z0A|nWT(t1tHf#_!xReh^K*6})ez6okRjOV39tRMAwd0zj3t^x0A|1Wm>2h^BwaWH$ zJz{MR5UF*)M4uT^J$p4sK(IDzou%2Ws9JT0>Hj4|kcCsfAt8*~d+9Q1g`Ka(V8~>pMwxEpIEmVZUCGXvG9Q>mWa>!k}fLnnt=r-&gNdQE={+1>4 zJ$S2L1AN8WXO^r4(Ywpufd-I_CJL2lhWXH}oEd&YmA|G?+x&m1GJ|5;f2eX_3-ss7y#aA0AV`!I=s>Ln{@sdIj>m=fpmCc z{p(xr`ttLZ-3oP@J8dH`DS)4u7hBwiUC#+wl!{2d*4cim*qS=*yyrS>`xWhNyE&Ss zZS?xevUxMrz5-hGH4L;|#ThaE5u_h@%|8{n5X@X%j`A-L0^R51#Er?Y;Fr)Cnri|~ zMQ6aMPCZ!J(pQGyXas>$RLhvHJP2Rv9uQrof4;TIq

=2!;+ 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 I>zopr077r=F#rGn literal 40884 zcmeFZWmuGJ+xAa4(xB4aCDPpu(nEKrpfnv%`*)}T&%}f2nYzc%1UzD2na|J1O&uW3^eeS zZ_jjQ5D;h(l;xy#ea-gs&@+h#&(HDvEDb$9wLaK9Yat{~W-&oU8I(H-MPeI8j}A5D zDWEB!!z#02!on)MB*P!vLuFv2c{E}fV*0%=rTZ7B+vEXdNkE%@Td9xTnm-j)a(PY7 zUETxtyb2NK&QgD<1`!zbLkU{bg6s6aHKPZ@_LbiCG z2`C~lNd5gFhIF9+`+cPzOC(~*17usTf4|QFULxS1-v>YVzc2B>r}ICh^S^cR&l>vQ zHS)jv1Bd#CLWDkW9bxB21$qxUz#_nO)K&UQbP^cfKeY5sadGlR|{P$ljQvk-o{ zo7&*EnvFDuCiu?}g!s}+h1gDg$0p@Sdbu~Je7MqDY}DvPKmuXb$W7|-`>pahSD5oW zeKwZ~!7`6t@xjPj=EQ0Bdhu8kjdv2&PTvhJjw5@r`0O|PBCu1q%_ZDLdg@27e*Z$9 zl+o5EbhLR6{yZs8YIZgocLyvq?lHd#lSVEJzw_KFW>qX1w~+&F2iwlh&ThX(2np4& zN5T*`E)q6U4&w>R=Y27*9cR1>BIY?ZTE9`!=s;#)1>u16DnbZx>)I*~J_Nt*&6_th zK6C-+`!(0|+NCw(kvI5R_8JRWnb*UjM9vADu-3{*RW|V&W3%v73c+o;@+cnk# z;=Q0z&m1k*+5T>#f9`wkwU?kY)ZETz>eoj(uT+yA@gpg+Ib-}+kMZ5oBK?^<3j}I0 z*RsKKfQqV*-#?MXr^q8N(&^O>D2k^x1xvZyXLY%x0#F!xnEg*K9FQ3(=>+~u4~-vcpf*LU8jp$ zwbF@2DVWLDuXDVkv19wGqLI3fd5GDP8$q89!N zL|>X0@n`x=d}Gcn_X=U#Ef^JvfDmFf@%EZ z*joF3k6r!<2`@dE^~yzjz6;wVn{e$wKEyU;y+l37X7f{W=-?sD=EdHey2#7jq69Jj z)3OLsnM%)}zmPo-FJ!yI>bJ&N{n~Yt_T^U>N4$?03|n992NxDvbauV?8ET?7^5+|$ z=ugkvG11;C;`Re$N50DW5v`#$4AFo$9Vwi>*D^C>XI_w@q)xfe>g#m!CavS|YdW60 zdwFy__h&_nKT`uKM^(rw>A;;(>U*JI*sw#WJyx=B(48R+hg>w>dl)BD<7;Lji8CJw2vvB{CI93_uh~# zn~4N#C45xY$}rw&OG)7@eW~?`JC5#oo=KRknlLe58)Z&0w zqNg$S(?wzCy-3B^NbDHh@#KP|H%Hwcon9WU7`k;FE3_VU-E2;4O1^xVv%g3=ytQ#D ziG2ECPmAlw!K-Z{Z>{&KI&_CJh?;x8nd!mvTuQ{vr`Y%Bbd6|Z2Yb;!&mW(}QrO^GYH>x(09!S%rU zig;b&1$9WV3du#^)7)+b=Jh*O9?$uVTz)Lo!zFo+)j2~;|6y&#!UDn{7JlvwEHw^okuTS&R#!X^qV} zRf^nKlg9ZJVN!;{>SQ95m)_aLBlSEKi9PxoDVGV$SUM+Bxbqj4qqWXr^X^yLjZS*= z6R#xB8YtF1o_UgeX1;P3YIhzz`#k&wQ%HWhlUEo#;llrgo5?mDKn^)T1iO;9ag$4O z^ZF~}p#;iGCpvYM4*hq*cYXt&(!3ASXO|Z{{fQxmwT(+pP}B9a4`&N|JQJ&D(^;Wa zDJNZ2;P=UUNMb3&6UEOnXR3`2x~_hb8+Q2Caz9AFV6wscSBca;1{(}E=@q!>TN8ro zsbT1NDp^l#XI@yAYZr4+jIjMHP>z*Ag-}(0c4qpg6?vo~pr%*)E(-mljikf~3wk_1 z?J6cvBqvH-E9qB3-ph#0R2pawj`giy>@OBtIaV9iD=;c|-d*qMnN*AUJt^(z_5V0m zZETN)dHm=1WaUN)3*|r$g$n06G}1Dw+PjmjF+IsP?*leY(`Dpi`aAs&_0e{`&Q6kxT^E$$tH$ zN-|xBb#vBjiDdh->v)c!CMvdqNvT5o|6nw*o#kg4W}IzP~db|LB|k_`cP7PFIe`g1|!StNU9YzuU98-DW`x#tjbd38nC;#2}dT1EWUm-qlhoD<1v0DmWd-L*&}!+KfBk zZW4Y}ft!XT9EbV_NP7k%15{RfW zYE&sse{!Q9oafdY^6SNy0%<27kEsvxwhK^8w#}Fv-h-6}`s+mg_n(rnXn!v`e;gTj zLo`c+<=BO^NSD%4y+j$*SMYownm~m`A%M3I8*R?6d*`F5$?^xzdN10~vnh3$2NXgD-qhC_!d^dFcwa+|rc2ayf`|LAR@;5X+K;-(J)-D3 ztPM+?so;XA>U3|*0XwRmMZer7xClCK9{Jv}Uzczlp@Z>gOw1 zM5XJU5b#(pEiE0B#S<^Oj#lST`dJfU^*mC}#t6|Ir>;aJZ})dJ-lHdSZtVvG(jUy| z6JS-6mm6VEUTi<(zw~AA_$uB!Buz3Zxj>Yp$0%3$-yEH0E7F|ssH3?|+dfqp)^jw6OwnHJ z)!8V|qV=g;#2jp8n0vpG+02e`i1-xh^Vz&(+fVjc-*41Ax8DNwSzU>Cx6u^R_MgM6 z&|wf<3ZXCa1?fgup>x~Kf3AMt?0@$rUk|?TR9UJKSIuM^h{EY(U&30Wgt#H#)#z^^ zaz870ee(Iy@sKY5p{8%AevQda)yYFw^v%~|M2<=&5Gk?H_;iR5EE3g)DB+fX8 zKacG^L{o)D#>MgQSiwv9#dgx;5ZY=2v(JVR%|rsR0_`+Dzra>A+mNcC@4w61xaPjz z6%^TR34Kq}ybQJ)>LSbj$gf4pMC-z|O*{+Ha@PdRt}%%Hs@$DLB`A%dK6oWtFph_R zFM`|Q8*cZt4yV^|dVhdZhwNXRXS1zfZ0Fs2HfN0Miq>06!tCNa7kOtw3~^gQr31jn zYZYo4X2cQg=N?CMJ9hkIc&mO=LdR?ETI*GTo5esPzjj$-s1}>V5+p1_3tvJmGx7=h zwE)c$4+%md=5-_i-E~NLzXKtzX50( z?R~L{A_~8!wtH37)%7NiQdxBZn@2B?f6Vq^BC)f>nw&1AF0OAc)<24g491YeRw(w4 zbKyf21p3dM1~Hej8{bQkp{9#AgQqYPUZZd_)cp6Gn>PLFycNEOt-k{MM#{c_&J&%r zI+xmufnsCrnV#l{N*!c2hVXNr?afa`U0^;$@2IfJ<3Q-{?Y?OW9jrd?98?vEf&^!4MqU__LF)AHAn6G?H^IWNi z%g@J3QRD)uoVMpVYg}&4$tfuxyw#+2d*8-R(1qmlMNPHLQPdz)vF|?&hYW~fd_XxO zFMMil5yyy)CkA`%|0{Er?|Q;9NBZ=;=GJK1>`#o2chD82qh1FN1@B%$e7+nN>YumOFuDuQ0IR;Je*<-M`!?U)4QCH`l-6&L!;J*UM@rd|5gMk+Qa*+VZd z-c(Llyno_daTP1uk%a%GKU&Z#IUWeTpx5~I27?8=MdUQI8f?iH-K zA@7m#b|z51h&GH$V#IL9k4Mcn*)Nd)!_uL%F{_~TkeEKfch~|McYx75yLDnYW|jBL zKmkD??vX~vy8p%DLF{`{*CyWj*eUlr@8^AB(|l&p8epJh(K?n<{q`TwIzWqvRVDOP zggfgWHrQhdVLwXVGK-G`dKb$Flt72PNY{%;~q-H_8iA0zKq%)tzDEYkrfhe}| z7=anWH%w?J#Z@89ry+vnAUZVu;3o#2$1tVOWp>ZG`GBR2IOhe;S4SFu{;vl#HN+Z+HV86Inc@b$3DQyq;oqbZ zdg0Rv6m_xQ-r$zc|7TJn9;+Qb%0pUh*#0)XDSD@n{$F4~5}XLyHNtOL9Dxk@qS(*N zXkuvULP-XEWOm5|$7vGK@TfRGMX%MEib`MO4V+8ovZJudf3=nqRt$C6+?9n%52Q&G zYO7m(vknt7oyg|b=|v;(B^oIq*x-H~mWcLacs-99zotjz`S);@lQ@QMjKJs@&z76r zGsw&Xr=azA!y8vU;&IW(zD-{wiw32ojOy(lg!m+HlOo~mRPlI7(`l$$R+?OMu(BPQUE}XE9j8mm!*?-0ya`3fpjS*tt+gJmxNp85w=D1+<7`#} zGf5cj#u2=p@RQ($AQ(x6gk3t+fN`Q7K?j8qNM%1{c%?Al6PT%z&arcoR50;gHtM>@ zW41!?2>=(bkyMGyGue7|>98>&v>OdQ*?jg1QaruL&W+oN(hT>2=crWbSI>L{&9z7N z-KWL7Jv^deu85o3rmIse)>$Tk!1R)7yAoZLy6QMORk?K z`J?PTgY{0uB=^XOVEMKrg`z8$@m7D5LDI(%VukXg#iwfFU-r%kI0gNdL@PH>QX_LL zX+Wxt;5Sq1wH7Foejqf{e=5{5sXv!yXgMGP4)$0XEE~D@988Y=)IJum1>*OMV{28$ zncm?ZeZ%TwjL~u*A=7EOxm6EL>ulaUZZtl#uv8~ok`MCjtLeJl#UFt|ed#Qipiqmz zPf4`tB^Zg6q9p?)C)RT{rpttVQo|NKA^+)2PRP?gE>?Zs+2WBV^v*C5;uPXe5ZRT> zR>{F}x5!^*{J=jXLT&SsXJarSbaM=%b{N^yx5O0(t4&ZL(h*`NMQwJRR^aqk%#sLd z+eMzUcN}zyc~*&xhu}@%c}n#?p1?k82X&75UEl}O3g`ACC@XR(^TJ~ehQh%}oc+Mg zost|5f~O*OLvfE%va>7Zs6MzXH7MgMoI1Bvsf}4DH9Y^J@QBCab@3gP5WZ<#5*74d z9p`_+=7{sI)Ghzu{X0+COM#{ZYR#=15+T4N!maf|u4L_CrB%nT97+#;vGX_4;qU3BKnQZpz&Chwu%~DkDEe(xKmll>za^`=;Aux|`$l=uo5T8)gPSds* zn3wOd35f7wpCf^56;F5>yl0OqhLaXCQgwQd%S^O0LdSBTMFyE#mC({BBd{KfdR%r{WiS!vQ?Gw7@#QzfD zqMo`Q&h(0B7JkkX^`)9)CF^9B8oG{Oo_Xrn_*vm&acDyAMOabOF9e`V$XHc0MILzGW&KqPdZKb-cO zd37^ixZedap!?kAmAi#}XWT3a5K-;@&dAwFpi+!97^{j%wv1P-X+|CP)H0K9^J%qD z`a+v$7KNrb2Z{5&ELJ+pmXo4T0S+EFATqBe#eT=REI@mIwf3xB491cb|IK+}+s0zq z&QOj}&srn>9J-bIS9#TytDUdnJFkPQ8}+D>w$=RGs;#T^KSzednQuwm+ckDpX>)5@ zeMn_7?wvg}(J4$XJm@b>l(wxgY1M5X9Mek*4?L_!WixB)cuf@h>8jq|cIXS4&C$@A z1jPh(pziLjnB)o?DTdY*ip5o06o3V z?SM=~@ygkKl690eN3(VF_hVUf)L@8J27*{BYHWtb0a98t*RQzfwcGi}iwAiipm4L+m=4w<_HKab=^O%nlTmK9C!2)%h>i^IyCh>Z)hyH zQRIHADu5=*71*4mnp0|)RB7UWhegVf$*3%+S__dHaKjN6-)=gJk$DEEu|^Re9R@O<6X%m3Gxnu8kkqn2K#6@l7U=)qO# zNP{X$U48Ot=-6vx7N~{#YOWAYzY}4>(MJEz4wXI@%cP5cZi022*#%n+RrIQeT{G~B zZsQyIAuu~?uPIeb0@vXjSMRs`mtGMR3vF95Y@I`|*sie2o^Rdtm2jnh0Xq?@Wi#lG ze)qRyg};CT9E%rRV}ZBx!0VmTl5iS+V(#2@LbA!r-P{b9I!5~x8=J!AIsR=l zT)sQaqBrJ#5=*ZIVEIyW+tNkfErPDLG7Nu&7B-NbTA=c-03*#77*nAhxJEmx?ailq z^O_a<)fIErt%lyWwc0$U(WW|S)oVP>4>_v34OC$8G|O#;vB(Wi5ksW+8*Il&{caALZTA;yE0{v}SG^|1Pp*Ew zQ`Oeima7^Uf)Mn&_!DXn_`4(j_o-y`cnwWI0G!@%Vw2hh>B|M{L}ftHwsPFNlELPr z$nhXuPqvQgpEe{l2gXv{Uee(E+vW~%2|QsN(!j5X%jV+H8(k$vC2br0FDy1p1*0=5 zKTf;+KM5H8PSA)x%zN((|NDZZ;M#5_Std{j(@_VVCRagfWg=db8GOu-$%yDaTC7(b z{AyHh7q61y55Q_=i;*ADNH4srE}X!-EJ?zjl)Uf2a*GK)Gr#mYToHC$YA6@`1MBZ% zn7NJwOsy2@z16U0p+dZ_wv*hZ{0*29i1y>;B=LpL5=0L@qF-N3SRDV_9C^D1;GAv_ z!Dt#gGcX{Eh`G&H>To?sG$n5v{+!L5OEeuUH)jAp)~HFECxCo$I3V=%sgx>bT6#JY z37c+`{ktIj7~)n6$EAJ2+r?Ek`Z?Fv#AcAW*HR-&KB2z~fP8Cm!FMBH$mMhV$^c5k ze8vxiia0gJj>E4%<^}X-wLdwj&OGM3QD2|7I6FUFW#{g?`~XLwA}_Y_VRZeC)|(@P zpC7S8DeAVa&-P{&JLF?Y*@8ZUj-SROQw1OUDqI@{S3JV5Vcq`+O@1fzT&D9ilUk;S z{KvaLzcsHm!tiEP`FsvnPOkSpj=h{W^%<0nkidETROuj)!>FMQ2Xx7Zw>_VSsb5`6 zzq-4!Py2~(y!MVG z1$aa=vVyF7(Tto}qy1fVK2_*d&WPKe=iDv*b!rgOeGh9ji2ZbE_00ng__Ktbe|QX` zJu{%Wxm*wa)`S?+X){6y2WYbvgkiGb9lbY`yPfzGli>uCP#%D+C+yDdE`Q+p9d%yJ zNYw#=5sAcZBC1f2+i@t0nyyNE365*4Cj{B);(ai1u@kOg^yzaAj?**iwH~i74p&bO z+mFyz-eVjs=oy$6E3mPY#gdWqDQ++KtWQr*Z@rJA(msPqQNO9s!dv5s^Q1X_2J7qZ zyH%v}8(_p*6KHo`7GPAORhw{ux~+-~QkY3@l84*l(YyaKHLqHt$?S~Z|G~*=|M@{8 zW=Bz>Vxm57pL0cVdY`!SDS1BP1R6eyThsBX&-xC&cRg>qk zYqK&KU2qormhZro8vXKKc2-d|Rp8Y7H29VG{sQgCj+2#Ktlm>h}mu2h( z9KIBU&@KZL6jFzXcC>-1|4AS;Nje)HJM7Bi;32kv$MTT=QfW_}3~RW^!&>@Ajo&{f z_$cEOam*}$NmDjcV``kvWy%(XN3GxI2);LZ6TU<2+XkbNVWEZ6ozV78&s6BK&r(Tz z1!I4*VZEKL(+}WsXk(T)`U4Rg7L|ylP>)Yx1Z&wE%c%S@^$x;;Ux#l9o7su&#@(=s z`h^YVFm#;hnCSKw2aWR;!BK)e6}aP{ZSCGcpon!;J=Xjl8&d0A4&}ug!cVR_gYW)G zkhiQ30juBrGHxIg7bek5h!RBX<~xW@%u>*?q##fRsr}G4e4O9&B7ntp`=HGJjbjC` z^-vkBHIBu&%f1~}ozmj`INBxC!`i|2r5IcuhbgS|cRkBBm>dhARmklwWH=URw3`G( z@leyT^ZQ?L`wJc1r#azDf<3^?jEi09$4I_1W2c(cPI$_i5F)gXxDwa3 z`VS~YisrOwX9)&UOvyJVatz*>V0-}sH9L2v9(iWo*to1-)XDse0zAV+4H`75hqI-wrXtBrj#a(NrWy@n&%2E_th?u2~)?f2U96hdf06#u(wq9u!j6 zpIy1^-feozheEC(3bU|0K%H}AWM-~hhe{ybQ#n&{bc`R<&3A-?s{%MhL{fss~#Lls_;X(T<8cO;U-*?QXQJUF6lzSFyWIY+2e}bkT zfla25G!}!K>mVC!2rII#6%}|db;)Ve@JU;eLV>9E=lG?x#iK>^qsP^mjqg9&GeL8k ztOpQ=KD_~u^eKZvBrLPz&&iks0a2M>92>BCh2MER+3f?vOBxMULnKCf0W?ASh*e6I z&u$!FOn0e`t;#-RLzWz}zgnVBzFsr1GhJG_Ga|J&Krui#RkCr_-xs7NyYk}g^Af*G z0jXcL(g^tyYQfvF$+&;GA;DaHH*&_v{GQ20P z3L+^-8C6oDHpt9N7%!$47Q!MH7hbwGS5c@aa){{ z*5w7QHeL4T>;S$=_mY53wIjy+I@>X_w%6a#6tH7=5x4 zNxnl3H_KW?pnj!>+V>*@kNZxy#>9~G%N|3?bI7EYe#E3%(d+t6r1xc7zRM!s zggghne$eyWs)e5Mwch<7kHpY5UDAz4w*@1(?BNzF;(_l?zhcc6q8{tpl9zF7H zYh3MDa5-MiwTU?+@lG`$_*T@uiT=0G~QpLK2hwceENODCmh1etQ!7 zHzatC(gBYoH=_E!`a4HP6Osv%VkBNnTd4n{2w!#J$~j}h{`~vOydV}bR-&AYgkD>0 z)Zk$GTj|Gcv~g(9`{?HpEU;cIq!hZ(Bv0n)37&eAH#yI1P(}*i2cYdJ;NM_9&pB-Q z@xc6TG+RRSA%;r@Bf5OTlcI5HGg*{9Iqe0rPJiXw>$9+z5#7VAh($TlMl2|eFF(-0 zxDIzn*!9aYm3@bj7(||RX&eLs7G4xIARwEa4rk$zXK)rCMK10IB2Bt}a>uzeq?GxT zK}LkkHEFH@!wjIqb*;Czkp(R)?*|V00>-a%5CX`h2Tf=Iz+()Yoa&4^v!Te}`=e-L zj2h0F^L=HC6UueVQ)pn+Uv+7sX+D=?azsBtk%P0A7zR8u5$Xk7SzKw?6lHLoE=mga@sZ~^B^ztV81(sy6Cya-|ayrW-z5sFfuo zBGOB7IF%)Wgx~{Yl!&Bl2Tgh{i5MIbfrFy782$@E2JJ#};A*B^M^Db9D5Wp>`MdtN z;kt5ms8cWk^>vMWwOd{Q!ruZqLXt&+N>B+B9jrie>zNr) z-DJM2vBkHr$QL3<9lsMsEu*{XMXgCu&g3T@nx4cS; z;lBux@rc!kK4@lQHJ^-sTO8uM0yAKRq;H8Kd~x(V0L3EOz);_FBH0jpf9KTpVEXyP zUJ#}@*rg8xF^cZ8MC=lBq_k(Kq=bsHHodYDNO+G4E37K;P+NOxuK&jHpT*<$llSn~ z1WeEY_a}f{i%}Z+`e4&vbxj?t#$#FdI;=jUs=B?osKi5+piz3( z4s`g|S??)23MuI@!0g6(h&mCUm=amVN>NC~%revcw$cm&sXrX9wqp}&GK1DU&0$z4 z7r#{P4~5{@UPKNaM>reSWFlhBg5yjL7Nj%tw57N={A{llAS6(@cyjUj(Zm$B(T$ z>CiMZ4$^VF#sB1?DA9PsDQZKpnZ?VUuksOMJxYE+|DS;5Pi5mX4a_PcW{omRy}Lb0 zs4719tKjDms=Zt+(cG?Nmff#zXRx^^%Kh4;gSg&_f?<=2MaV1m(p(kz*8k4IuUix%B zl(xS6bG3^Xp4*j48RqXRQALS7^^nw-)t_6>~^(7bL`!`EN>{!&o$jXF8Z zX$Sddo1a9JIvgfwz>ijm;2Sm%;gAuNZwwFPce~!Q;EkS;C;q1nf|~tJ$~~lrzK&WO z$Kmq=gdflmWqC=CsAWIv4;%jF8`G(QwM6HEkq010C0>jc2Yak~?PE+iPDHg?%lAS9 zBxnfNxTIPETKj(m+ghZ+kE52kr2N}}y8s3oY`*n7`?pPUf%oKz$d>b$>j1C$Xm>!! zk6nY!#Q$l@udxCDaFJ5~Pqw?FdIxx{_0Jh9fgK9Y2zU$-fptPYM*d+7}R zw*vVG^M8*Ay+S^g{%F1JaN zZXz2X*OozT5-g6R>egWU?A-x9+gRWAEFlm{OuvXM?K%0E8M*xgEgbVNdXLHBiAeX0 z28-}XyD5*=fZtgw`lyP0UYQFS+AnUFMQ>W@KklE=(X{sC{<$ z$vfO$XXF>RXKfDgG;Jb(@b$%u|B}IF8`Cwj%I**#9r)7D+W0X$2}@c zn9+_3w@3S3$jcvEKB6S{%*{;kX>)wC=s=o;p~q8m&8Mfg}=HNABhqk~RULh`h#OxG(64qvZYrkOGZ11@6E8?i6BJ>2GQsok%ZOW8N zqLmjutzRC;!nEu)&6DVFG!{kn?y84fW+h?k{KEQpBG7}D*$Q4QJnr=Yy198)MiS+u zKk_G#uJaX4;UXo+z4j4L=FJ8@^Sw`P?=Hq-j=XJm4OW|Mi|pzvIWA_)W0sR6o8hC{rp1GxwEAmJ6gy~cZnSmkzQt|2$8ovD9hcQ?j`E|um6eqVJ>JE4 zkQ&AxcwqquQn6wp)f3xM;>Iu@Mn-wFpfkOfn_wXAZw&c%tb@kg{oU5A@OfQo_nk@x z>`ens@7TIi@2SQv)gJd!{iE|;;{!$g8iR%xA1oT)gx(+wx+DioZQjo|dzvcCpI|7A z>BpKP+BB{@lr=veLA(k$qn(|_dKsfSo1-Ex+iYEvXlRK`x@PQ4-KsY;(-!YjzWQoI zJpQ6_)${3AYOchq!M@x93f-BJNhF`wOCX{}%J{Sog8 zqLd@0?_ROFRRpNTjz8?8dogAgLVr**$YR#6S!$-yu7Bt@*WHqV9>#cG4vF5ffHpglL+DnF>sIzJB; zzgox^f$yp#D=-Ma#?vgY&?uokci&_HrK&fn{;u8a>gO&xP_JVV;f04oEn)Hsm=9`N zGX&X)NR_7T-X~yei-Kc&)CAp(l}A~n$cbd8?Dk&vYjuZ4=nK%qzX&^D4;l-O!S_7Q zhv;LX=Sx`x=-438EyF@1PNBMuvfYc-=k~2HqRwUUiF6BE_37cNF@UekdX@TVU^wJ_ zaZQ?_X6U7ra45{&N>r~}t0K(6niayuY2np@^}|9qVa7Xb$zQPsyEguFEplDoV~$}i zCKd9~mQc!Z8C#*3jzEccR+P86M1k1&VzbL4oqP9fQyitJ{_Ma+(4_dqr(f@axsqc% z$Alnjk~z6_r)y~ceNs#N(TQ7i4(w(O))wp9Fc=8QyakEjBUDN2zSu)Ltjd~qk{%UN= zhHhT8%9%pYE!QH7%Ttu@^%14d%6kzDkkXE_J99vGZpsyO&&SG)Tg_VFjNCl?qzm=j zQh~!ilu4wys~!QcMD9uAMJyGa#p73v6a;!m=M(OTsC z?}`_S_iod)EabnS1^+pY>Hv{d?HUu|a?ll-LLy$8;_CttLWaR0rgn*Og$+-ZmY%v|;NjQZwE@M=H_Z9Z!a`Ki*xoF2XnMIN^Zvt*(puyGakQ3QI83 z^4#$y=rzY6m*vsNI3)H^0T51)Qu!FR4Z}DtxUiu0*m;eJocas1*nTqqWR(45S;l%8 zo&<|*)B`1(yKV*ZpuEMdhzFJETCx&@kUOwVm@CziTVqxCq3&LVs-BMr>fsCXlv~k?D=Q zAOuML0XKI2#3J=4&up}`d)I=Hi^`RPG=@x1bM~O*;uL95^8PAO4QQZ1XCoF2lN_>w7TMkAdj+3{Bs@-~<{pOiSFi z-yv+nXUW*Tv-r^7^$}7D=CQ;z(5Zpw)-jkzsXpsL2DiPU&Y(1$9wDa-g*y#zbjBt= zwiD?24Fz&XdcPSM$f};6b)!_;z(`XQ;BoFBmpGPQxT!4aIq5+Qk=S^sPIvIY%q*H8 z`G{nt|2mYPz=Pac--GAH$c1SH3K*G~ZtZeuo9{l+HKU>hD;43Fxr%iGna~ zs1JPj$XERLsw2;P#}c-lAXae$RNQgW_5mD;LN#jNFgO@-$wGg~TZhxQFKGAl(T>O9 zrZ$zgOzMI67`11BomZSmz;ZW^qC2BPj6n9WrX?s3YAq&71P-I!5tORamyj<~a8cj4 z3!Jyf@bRj6jXaS@686XA;wkgsjzZ<7dvSvTJRyZOh#D3*#+?4Q-oAIvHLXMBCtL3S zWC7;;XJ&NyW58`JF-PmL_iQFDP(p|uYmivWI7iSZ=+*3I_;q)!2jeK|S-3RNxP2mr zWRG;TO{-r}eSB)HxKS-=G+92;$`QD&q1{FoZ+gE$+T(}iHKub7&sKb>8Y--AR~&MA z0hh=Hqh-IkcZM)U(T*JV=XmN7*QAv&BhCz19?Go)du?w8kS=NVs4?mp+7qZ3m#An;7MF=#Dvw_5x1w)npH3KBv6K3JoR?YTtvX0u_RLS zDeRd}pqzw!EaSFwg#@KrWk4?s6hgK_aQ{edC3>p5#}04_BS{qqPk5K;Tsb**ynp|6dE zo_rGs+f%{iy!a_(s46a_QLYiM?7Uh&Zg>7htH|)Mjs+^lqYO$(2F0RR#N>=+;SolL_yDQ*wZnT9*oI{Y z4BYWk+yQ|FI=0tler0aq<<*Nyj9i;|@ai(!fiWovU!mankD*<9Ydhrn_0S8hS56yd z^K&;ePhY)`5 z2_f1ZZH&nKV2Kg#IEyH=csIvhQ(`BSl=CS!7Mi``&pK_$Xv<^M-E+~ii9ElaJDjI=A*f!9Ge)& z8U~FW;bFg2>+T;z6hcV!GjYEY8xkUHM4z!V_R{aXS@7U=7QD%K#i9&>5lg%FJN{Fm z!R;*LR?lLZkIbIxbmv6*lqG^O&Fxw9sz{$f6dWtrz6A-J8dGjZp4c{;F1pIX7Le&W z`$?)Z-Y}uZK#;2leuW38olsG7r$1QJH`5~V(Mhd>+^_Dy#qMlnWhz5O=-47%|qsa+}q@Z=Zr1&?RL zw?&!zBrm*PH2{s}Iu!<7FvL(k4ECTd661Hi`#*xgB#V&W7T;{+B-7Xp^sA-!T~^!l zZgaBGv6KDx=BoEpzdJUwgX(Rh5b}`P@{rY#+2ox0(ALi$kxKfBAMJ=(!U#lnbk^9^ zEl@?MCFEc!v{pRWm?-ohg_?=Q4S^PnW<`d|^*%(|cqLQ&M7{->-f87D&osmeyFi9n zB^hAhv|9w!MO=6=3yy{F-OsZ6r9j(tO9nURqRIBG!>f)4UX=LmILs)d8u5+<45bmw zBW}Hl2+HBf%s777$ChlM86L@o3Pe4i+;#T;{}rHi6W@$=0XIO2P)vtE^tE6EiPA}m zjy7Kn9^XD{303?9?C;FoK2t>L1PaYPN1~?b9wAkfoBWYixVZ5 zgpd(0A*3_lLZ7OpvZhT1ZVmGP&lEL<&wo?Y!lLAVTf8r+tyISX9L~pS%SCoA{VCS$ z+4n}Pc&q^I47mg!Q9<$nF0>a|BeZ;>tbG6*mr&B?!k+hw5TybXTgh)aGBUDzpTS}H zLE%7O90Hk+@cx^`ipV_?OoL$!EXWNB|DgZ}v(&D_pL8E|p zMHH>DWKt>8IaX3}P=u9F5YQ`>2|U%zEPhb?S73P?z94-?w^8-)?`~(K5V^gHZA6Ey zJOxom=e#Y$6JP3PXZ8u#vb3n@2sllNj)Ksq9yL@#mEBG!+~{xCdV%jACnT!I4VAds zBx-zSx*Qax{s>>Jcg`YD%un0(Q_tu59JjU+Lg_+lyYWog^73-01KLq=`DZNTx=Y4J z8^q9*;j$AE84a?F#|}4{fCT{x;s~>|r_Z4o46IIq>tKgK3B?vYmmz^TAQ%27WK^-) zU4>h-8Car7U=q#S5!?^$JB@6Lg@RjYo!SGcjT&)KNk51DO<5Zf^K|e%0A$5X#=(na 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 g4Pzopr0Kl3ohX4Qo From 854c8c7fdda2033a31bc6bdae46cfdd9d4323192 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 11:08:56 -0400 Subject: [PATCH 06/13] reuse constants for weeks and quarters --- src/plots/cartesian/axes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index f4eb2bcdc9b..a334231151f 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -24,9 +24,9 @@ var cleanTicks = require('./clean_ticks'); var constants = require('../../constants/numerical'); var ONEAVGYEAR = constants.ONEAVGYEAR; -var ONEAVGQUARTER = constants.ONEAVGYEAR / 4; +var ONEAVGQUARTER = constants.ONEAVGQUARTER; var ONEAVGMONTH = constants.ONEAVGMONTH; -var ONEWEEK = constants.ONEDAY * 7; +var ONEWEEK = constants.ONEWEEK; var ONEDAY = constants.ONEDAY; var ONEHOUR = constants.ONEHOUR; var ONEMIN = constants.ONEMIN; From 7b9391fc643c16cf5bd7e434055ca8fa2a5ea427 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 11:45:55 -0400 Subject: [PATCH 07/13] replace Sunday with Monday for ISO and Monday-based formats --- src/plots/cartesian/axes.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index a334231151f..c9f4d3675fe 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -914,6 +914,13 @@ axes.autoTicks = function(ax, roughDTick) { // this will also move the base tick off 2000-01-01 if dtick is // 2 or 3 days... but that's a weird enough case that we'll ignore it. ax.tick0 = Lib.dateTick0(ax.calendar, true); + + if(/%[uVW]/.test(ax.tickformat)) { + // replace Sunday with Monday for ISO and Monday-based formats + var len = ax.tick0.length; + var lastD = +ax.tick0[len - 1]; + ax.tick0 = ax.tick0.substring(0, len - 2) + String(lastD + 1); + } } else if(roughX2 > ONEHOUR) { ax.dtick = roundDTick(roughDTick, ONEHOUR, roundBase24); } else if(roughX2 > ONEMIN) { From e265f0d1cc681ed2b1842e16acd955782963982e Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 11:55:55 -0400 Subject: [PATCH 08/13] replace multiple incexOf calls with a regex call --- src/plots/cartesian/axes.js | 64 +++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index c9f4d3675fe..0c5536b41e8 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -697,48 +697,50 @@ axes.calcTicks = function calcTicks(ax, opts) { var definedDelta; if(isPeriod && ax.tickformat) { - var _has = function(str) { - return ax.tickformat.indexOf(str) !== -1; - }; - if( - !_has('%f') && // microseconds as a decimal number [000000, 999999] - !_has('%L') && // milliseconds as a decimal number [000, 999] - !_has('%Q') && // milliseconds since UNIX epoch - !_has('%s') && // seconds since UNIX epoch - !_has('%S') && // second as a decimal number [00,61] - !_has('%M') && // minute as a decimal number [00,59] - !_has('%H') && // hour (24-hour clock) as a decimal number [00,23] - !_has('%I') && // hour (12-hour clock) as a decimal number [01,12] - !_has('%p') && // either AM or PM - !_has('%X') // the locale’s time, such as %-I:%M:%S %p + !(/%[fLQsSMHIpX]/.test(ax.tickformat)) + // %f: microseconds as a decimal number [000000, 999999] + // %L: milliseconds as a decimal number [000, 999] + // %Q: milliseconds since UNIX epoch + // %s: seconds since UNIX epoch + // %S: second as a decimal number [00,61] + // %M: minute as a decimal number [00,59] + // %H: hour (24-hour clock) as a decimal number [00,23] + // %I: hour (12-hour clock) as a decimal number [01,12] + // %p: either AM or PM + // %X: the locale’s time, such as %-I:%M:%S %p ) { if( - _has('%A') || // full weekday name - _has('%a') || // abbreviated weekday name - _has('%d') || // zero-padded day of the month as a decimal number [01,31] - _has('%e') || // space-padded day of the month as a decimal number [ 1,31] - _has('%j') || // day of the year as a decimal number [001,366] - _has('%u') || // Monday-based (ISO 8601) weekday as a decimal number [1,7] - _has('%w') || // Sunday-based weekday as a decimal number [0,6] - _has('%x') // the locale’s date, such as %-m/%-d/%Y + /%[Aadejuwx]/.test(ax.tickformat) + // %A: full weekday name + // %a: abbreviated weekday name + // %d: zero-padded day of the month as a decimal number [01,31] + // %e: space-padded day of the month as a decimal number [ 1,31] + // %j: day of the year as a decimal number [001,366] + // %u: Monday-based (ISO 8601) weekday as a decimal number [1,7] + // %w: Sunday-based weekday as a decimal number [0,6] + // %x: the locale’s date, such as %-m/%-d/%Y ) definedDelta = ONEDAY; else if( - _has('%U') || // Sunday-based week of the year as a decimal number [00,53] - _has('%V') || // ISO 8601 week of the year as a decimal number [01, 53] - _has('%W') // Monday-based week of the year as a decimal number [00,53] + /%[UVW]/.test(ax.tickformat) + // %U: Sunday-based week of the year as a decimal number [00,53] + // %V: ISO 8601 week of the year as a decimal number [01, 53] + // %W: Monday-based week of the year as a decimal number [00,53] ) definedDelta = ONEWEEK; else if( - _has('%B') || // full month name - _has('%b') || // abbreviated month name - _has('%m') // month as a decimal number [01,12] + /%[Bbm]/.test(ax.tickformat) + // %B: full month name + // %b: abbreviated month name + // %m: month as a decimal number [01,12] ) definedDelta = ONEAVGMONTH; else if( - _has('%q') // quarter of the year as a decimal number [1,4] + /%[q]/.test(ax.tickformat) + // %q: quarter of the year as a decimal number [1,4] ) definedDelta = ONEAVGQUARTER; else if( - _has('%Y') || // year with century as a decimal number, such as 1999 - _has('%y') // year without century as a decimal number [00,99] + /%[Yy]/.test(ax.tickformat) + // %Y: year with century as a decimal number, such as 1999 + // %y: year without century as a decimal number [00,99] ) definedDelta = ONEAVGYEAR; } } From 40c6df653a32bcb309828f58f5c338dab7176206 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 14:56:28 -0400 Subject: [PATCH 09/13] add jasmine tests for various tickformat using period mode --- test/jasmine/tests/axes_test.js | 237 ++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index f9c7b2a347c..06134882308 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -5196,6 +5196,243 @@ describe('Test axes', function() { }); }); }); + + describe('label positioning using *ticklabelmode*: "period"', function() { + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + function _assert(msg, exp) { + var labelPositions = gd._fullLayout.xaxis._vals.map(function(d) { return d.periodX; }); + expect(labelPositions).withContext(msg).toEqual(exp); + } + + ['%Y', '%y'].forEach(function(tickformat) { + it('should respect yearly tickformat that includes ' + tickformat, function(done) { + Plotly.newPlot(gd, { + data: [{ + x: ['2020-01-01', '2026-01-01'] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + tickformat: tickformat + } + } + }) + .then(function() { + _assert('', [ + 1562079600000, + 1593615600000, + 1625238000000, + 1656774000000, + 1688310000000, + 1719846000000, + 1751468400000, + 1783004400000 + ]); + }) + .catch(failTest) + .then(done); + }); + }); + + it('should respect quarters tickformat that includes %q', function(done) { + Plotly.newPlot(gd, { + data: [{ + x: ['2020-01-01', '2022-01-01'] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + tickformat: '%Y-%q' + } + } + }) + .then(function() { + _assert('', [ + 1573832700000, + 1581781500000, + 1589643900000, + 1597506300000, + 1605455100000, + 1613403900000, + 1621179900000, + 1629042300000, + 1636991100000, + 1644939900000 + ]); + }) + .catch(failTest) + .then(done); + }); + + ['%B', '%b', '%m'].forEach(function(tickformat) { + it('should respect monthly tickformat that includes ' + tickformat, function(done) { + Plotly.newPlot(gd, { + data: [{ + x: ['2020-01-01', '2020-07-01'] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + tickformat: '%q-' + tickformat + } + } + }) + .then(function() { + _assert('', [ + 1576473300000, + 1579151700000, + 1581830100000, + 1584335700000, + 1587014100000, + 1589606100000, + 1592284500000, + 1594876500000 + ]); + }) + .catch(failTest) + .then(done); + }); + }); + + it('should respect Sunday-based week tickformat that includes %U', function(done) { + Plotly.newPlot(gd, { + data: [{ + x: ['2020-02-01', '2020-04-01'] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + tickformat: '%b-%U' + } + } + }) + .then(function() { + _assert('', [ + 1580299200000, + 1580904000000, + 1581508800000, + 1582113600000, + 1582718400000, + 1583323200000, + 1583928000000, + 1584532800000, + 1585137600000, + 1585742400000 + ]); + }) + .catch(failTest) + .then(done); + }); + + ['%V', '%W'].forEach(function(tickformat) { + it('should respect Monday-based week tickformat that includes ' + tickformat, function(done) { + Plotly.newPlot(gd, { + data: [{ + x: ['2020-02-01', '2020-04-01'] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + tickformat: '%b-' + tickformat + } + } + }) + .then(function() { + _assert('', [ + 1580385600000, + 1580990400000, + 1581595200000, + 1582200000000, + 1582804800000, + 1583409600000, + 1584014400000, + 1584619200000, + 1585224000000, + 1585828800000 + ]); + }) + .catch(failTest) + .then(done); + }); + }); + + ['%A', '%a', '%d', '%e', '%j', '%u', '%w', '%x'].forEach(function(tickformat) { + it('should respect daily tickformat that includes ' + tickformat, function(done) { + Plotly.newPlot(gd, { + data: [{ + x: ['2020-01-01', '2020-01-08'] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + tickformat: '%b-' + tickformat + } + } + }) + .then(function() { + _assert('', [ + 1577793600000, + 1577880000000, + 1577966400000, + 1578052800000, + 1578139200000, + 1578225600000, + 1578312000000, + 1578398400000, + 1578484800000 + ]); + }) + .catch(failTest) + .then(done); + }); + }); + + ['%f', '%L', '%Q', '%s', '%S', '%M', '%H', '%I', '%p', '%X'].forEach(function(tickformat) { + it('should respect daily tickformat that includes ' + tickformat, function(done) { + Plotly.newPlot(gd, { + data: [{ + x: ['2020-01-01', '2020-01-02'] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + tickformat: '%a-' + tickformat + } + } + }) + .then(function() { + _assert('', [ + 1577826000000, + 1577836800000, + 1577847600000, + 1577858400000, + 1577869200000, + 1577880000000, + 1577890800000, + 1577901600000, + 1577912400000, + 1577923200000 + ]); + }) + .catch(failTest) + .then(done); + }); + }); + }); }); function getZoomInButton(gd) { From 93990310c408f2cd2d9d13eedc3b77ae4210e761 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 16:08:08 -0400 Subject: [PATCH 10/13] fix issue 5071 --- src/plots/cartesian/axes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 0c5536b41e8..929831f8e16 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -798,7 +798,7 @@ axes.calcTicks = function calcTicks(ax, opts) { } if(removedPreTick0Label) { - for(i = 1; i < ticksOut.length; i++) { + for(i = 0; i < ticksOut.length; i++) { if(ticksOut[i].periodX <= maxRange && ticksOut[i].periodX >= minRange) { // redo first visible tick ax._prevDateHead = ''; From f0f078a17532748e7164e6930bd5f1c9eb2b49ee Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 12 Aug 2020 17:46:23 -0400 Subject: [PATCH 11/13] convert milliseconds to date strings in tests --- test/jasmine/tests/axes_test.js | 133 ++++++++++++++++---------------- 1 file changed, 67 insertions(+), 66 deletions(-) diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 06134882308..cade6ce99e0 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -5207,7 +5207,8 @@ describe('Test axes', function() { afterEach(destroyGraphDiv); function _assert(msg, exp) { - var labelPositions = gd._fullLayout.xaxis._vals.map(function(d) { return d.periodX; }); + var ax = gd._fullLayout.xaxis; + var labelPositions = ax._vals.map(function(d) { return ax.c2d(d.periodX); }); expect(labelPositions).withContext(msg).toEqual(exp); } @@ -5227,14 +5228,14 @@ describe('Test axes', function() { }) .then(function() { _assert('', [ - 1562079600000, - 1593615600000, - 1625238000000, - 1656774000000, - 1688310000000, - 1719846000000, - 1751468400000, - 1783004400000 + '2019-07-02 15:00', + '2020-07-01 15:00', + '2021-07-02 15:00', + '2022-07-02 15:00', + '2023-07-02 15:00', + '2024-07-01 15:00', + '2025-07-02 15:00', + '2026-07-02 15:00' ]); }) .catch(failTest) @@ -5257,16 +5258,16 @@ describe('Test axes', function() { }) .then(function() { _assert('', [ - 1573832700000, - 1581781500000, - 1589643900000, - 1597506300000, - 1605455100000, - 1613403900000, - 1621179900000, - 1629042300000, - 1636991100000, - 1644939900000 + '2019-11-15 15:45', + '2020-02-15 15:45', + '2020-05-16 15:45', + '2020-08-15 15:45', + '2020-11-15 15:45', + '2021-02-15 15:45', + '2021-05-16 15:45', + '2021-08-15 15:45', + '2021-11-15 15:45', + '2022-02-15 15:45' ]); }) .catch(failTest) @@ -5289,14 +5290,14 @@ describe('Test axes', function() { }) .then(function() { _assert('', [ - 1576473300000, - 1579151700000, - 1581830100000, - 1584335700000, - 1587014100000, - 1589606100000, - 1592284500000, - 1594876500000 + '2019-12-16 05:15', + '2020-01-16 05:15', + '2020-02-16 05:15', + '2020-03-16 05:15', + '2020-04-16 05:15', + '2020-05-16 05:15', + '2020-06-16 05:15', + '2020-07-16 05:15' ]); }) .catch(failTest) @@ -5319,16 +5320,16 @@ describe('Test axes', function() { }) .then(function() { _assert('', [ - 1580299200000, - 1580904000000, - 1581508800000, - 1582113600000, - 1582718400000, - 1583323200000, - 1583928000000, - 1584532800000, - 1585137600000, - 1585742400000 + '2020-01-29 12:00', + '2020-02-05 12:00', + '2020-02-12 12:00', + '2020-02-19 12:00', + '2020-02-26 12:00', + '2020-03-04 12:00', + '2020-03-11 12:00', + '2020-03-18 12:00', + '2020-03-25 12:00', + '2020-04-01 12:00' ]); }) .catch(failTest) @@ -5351,16 +5352,16 @@ describe('Test axes', function() { }) .then(function() { _assert('', [ - 1580385600000, - 1580990400000, - 1581595200000, - 1582200000000, - 1582804800000, - 1583409600000, - 1584014400000, - 1584619200000, - 1585224000000, - 1585828800000 + '2020-01-30 12:00', + '2020-02-06 12:00', + '2020-02-13 12:00', + '2020-02-20 12:00', + '2020-02-27 12:00', + '2020-03-05 12:00', + '2020-03-12 12:00', + '2020-03-19 12:00', + '2020-03-26 12:00', + '2020-04-02 12:00' ]); }) .catch(failTest) @@ -5384,15 +5385,15 @@ describe('Test axes', function() { }) .then(function() { _assert('', [ - 1577793600000, - 1577880000000, - 1577966400000, - 1578052800000, - 1578139200000, - 1578225600000, - 1578312000000, - 1578398400000, - 1578484800000 + '2019-12-31 12:00', + '2020-01-01 12:00', + '2020-01-02 12:00', + '2020-01-03 12:00', + '2020-01-04 12:00', + '2020-01-05 12:00', + '2020-01-06 12:00', + '2020-01-07 12:00', + '2020-01-08 12:00' ]); }) .catch(failTest) @@ -5416,16 +5417,16 @@ describe('Test axes', function() { }) .then(function() { _assert('', [ - 1577826000000, - 1577836800000, - 1577847600000, - 1577858400000, - 1577869200000, - 1577880000000, - 1577890800000, - 1577901600000, - 1577912400000, - 1577923200000 + '2019-12-31 21:00', + '2020-01-01', + '2020-01-01 03:00', + '2020-01-01 06:00', + '2020-01-01 09:00', + '2020-01-01 12:00', + '2020-01-01 15:00', + '2020-01-01 18:00', + '2020-01-01 21:00', + '2020-01-02' ]); }) .catch(failTest) From 90ee834ebb929d39ab4e893edf30c32f8f64eae3 Mon Sep 17 00:00:00 2001 From: archmoj Date: Thu, 13 Aug 2020 16:22:54 -0400 Subject: [PATCH 12/13] test label text based on different tick time formats --- test/jasmine/tests/axes_test.js | 87 +++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 15 deletions(-) diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index cade6ce99e0..e9f9e388f4f 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -5206,13 +5206,19 @@ describe('Test axes', function() { afterEach(destroyGraphDiv); - function _assert(msg, exp) { + function _assertPositions(msg, exp) { var ax = gd._fullLayout.xaxis; - var labelPositions = ax._vals.map(function(d) { return ax.c2d(d.periodX); }); - expect(labelPositions).withContext(msg).toEqual(exp); + var positions = ax._vals.map(function(d) { return ax.c2d(d.periodX); }); + expect(positions).withContext(msg).toEqual(exp); } - ['%Y', '%y'].forEach(function(tickformat) { + function _assertLabels(msg, exp) { + var ax = gd._fullLayout.xaxis; + var labels = ax._vals.map(function(d) { return d.text; }); + expect(labels).withContext(msg).toEqual(exp); + } + + ['%Y', '%y'].forEach(function(tickformat, i) { it('should respect yearly tickformat that includes ' + tickformat, function(done) { Plotly.newPlot(gd, { data: [{ @@ -5227,7 +5233,7 @@ describe('Test axes', function() { } }) .then(function() { - _assert('', [ + _assertPositions('', [ '2019-07-02 15:00', '2020-07-01 15:00', '2021-07-02 15:00', @@ -5238,6 +5244,12 @@ describe('Test axes', function() { '2026-07-02 15:00' ]); }) + .then(function() { + _assertLabels('', [ + ['', '2020', '2021', '2022', '2023', '2024', '2025', ''], + ['', '20', '21', '22', '23', '24', '25', ''] + ][i]); + }) .catch(failTest) .then(done); }); @@ -5257,7 +5269,7 @@ describe('Test axes', function() { } }) .then(function() { - _assert('', [ + _assertPositions('', [ '2019-11-15 15:45', '2020-02-15 15:45', '2020-05-16 15:45', @@ -5270,11 +5282,14 @@ describe('Test axes', function() { '2022-02-15 15:45' ]); }) + .then(function() { + _assertLabels('', ['', '2020-1', '2020-2', '2020-3', '2020-4', '2021-1', '2021-2', '2021-3', '2021-4', '']); + }) .catch(failTest) .then(done); }); - ['%B', '%b', '%m'].forEach(function(tickformat) { + ['%B', '%b', '%m'].forEach(function(tickformat, i) { it('should respect monthly tickformat that includes ' + tickformat, function(done) { Plotly.newPlot(gd, { data: [{ @@ -5289,7 +5304,7 @@ describe('Test axes', function() { } }) .then(function() { - _assert('', [ + _assertPositions('', [ '2019-12-16 05:15', '2020-01-16 05:15', '2020-02-16 05:15', @@ -5300,6 +5315,13 @@ describe('Test axes', function() { '2020-07-16 05:15' ]); }) + .then(function() { + _assertLabels('', [ + ['', '1-January', '1-February', '1-March', '2-April', '2-May', '2-June', ''], + ['', '1-Jan', '1-Feb', '1-Mar', '2-Apr', '2-May', '2-Jun', ''], + ['', '1-01', '1-02', '1-03', '2-04', '2-05', '2-06', ''] + ][i]); + }) .catch(failTest) .then(done); }); @@ -5319,7 +5341,7 @@ describe('Test axes', function() { } }) .then(function() { - _assert('', [ + _assertPositions('', [ '2020-01-29 12:00', '2020-02-05 12:00', '2020-02-12 12:00', @@ -5332,11 +5354,14 @@ describe('Test axes', function() { '2020-04-01 12:00' ]); }) + .then(function() { + _assertLabels('', ['Jan-04', 'Feb-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Mar-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13']); + }) .catch(failTest) .then(done); }); - ['%V', '%W'].forEach(function(tickformat) { + ['%V', '%W'].forEach(function(tickformat, i) { it('should respect Monday-based week tickformat that includes ' + tickformat, function(done) { Plotly.newPlot(gd, { data: [{ @@ -5351,7 +5376,7 @@ describe('Test axes', function() { } }) .then(function() { - _assert('', [ + _assertPositions('', [ '2020-01-30 12:00', '2020-02-06 12:00', '2020-02-13 12:00', @@ -5364,12 +5389,18 @@ describe('Test axes', function() { '2020-04-02 12:00' ]); }) + .then(function() { + _assertLabels('', [ + ['Jan-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Feb-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13', 'Mar-14'], + ['Jan-04', 'Feb-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Mar-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13'] + ][i]); + }) .catch(failTest) .then(done); }); }); - ['%A', '%a', '%d', '%e', '%j', '%u', '%w', '%x'].forEach(function(tickformat) { + ['%A', '%a', '%d', '%e', '%j', '%u', '%w', '%x'].forEach(function(tickformat, i) { it('should respect daily tickformat that includes ' + tickformat, function(done) { Plotly.newPlot(gd, { data: [{ @@ -5384,7 +5415,7 @@ describe('Test axes', function() { } }) .then(function() { - _assert('', [ + _assertPositions('', [ '2019-12-31 12:00', '2020-01-01 12:00', '2020-01-02 12:00', @@ -5396,12 +5427,24 @@ describe('Test axes', function() { '2020-01-08 12:00' ]); }) + .then(function() { + _assertLabels('', [ + ['', 'Jan-Wednesday', 'Jan-Thursday', 'Jan-Friday', 'Jan-Saturday', 'Jan-Sunday', 'Jan-Monday', 'Jan-Tuesday', ''], + ['', 'Jan-Wed', 'Jan-Thu', 'Jan-Fri', 'Jan-Sat', 'Jan-Sun', 'Jan-Mon', 'Jan-Tue', ''], + ['', 'Jan-01', 'Jan-02', 'Jan-03', 'Jan-04', 'Jan-05', 'Jan-06', 'Jan-07', ''], + ['', 'Jan- 1', 'Jan- 2', 'Jan- 3', 'Jan- 4', 'Jan- 5', 'Jan- 6', 'Jan- 7', ''], + ['', 'Jan-001', 'Jan-002', 'Jan-003', 'Jan-004', 'Jan-005', 'Jan-006', 'Jan-007', ''], + ['', 'Jan-3', 'Jan-4', 'Jan-5', 'Jan-6', 'Jan-7', 'Jan-1', 'Jan-2', ''], + ['', 'Jan-3', 'Jan-4', 'Jan-5', 'Jan-6', 'Jan-0', 'Jan-1', 'Jan-2', ''], + ['', 'Jan-01/01/2020', 'Jan-01/02/2020', 'Jan-01/03/2020', 'Jan-01/04/2020', 'Jan-01/05/2020', 'Jan-01/06/2020', 'Jan-01/07/2020', ''] + ][i]); + }) .catch(failTest) .then(done); }); }); - ['%f', '%L', '%Q', '%s', '%S', '%M', '%H', '%I', '%p', '%X'].forEach(function(tickformat) { + ['%f', '%L', '%Q', '%s', '%S', '%M', '%H', '%I', '%p', '%X'].forEach(function(tickformat, i) { it('should respect daily tickformat that includes ' + tickformat, function(done) { Plotly.newPlot(gd, { data: [{ @@ -5416,7 +5459,7 @@ describe('Test axes', function() { } }) .then(function() { - _assert('', [ + _assertPositions('', [ '2019-12-31 21:00', '2020-01-01', '2020-01-01 03:00', @@ -5429,6 +5472,20 @@ describe('Test axes', function() { '2020-01-02' ]); }) + .then(function() { + _assertLabels('', [ + ['', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Thu-0'], + ['', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Thu-000'], + ['', 'Wed-1577836800000', 'Wed-1577847600000', 'Wed-1577858400000', 'Wed-1577869200000', 'Wed-1577880000000', 'Wed-1577890800000', 'Wed-1577901600000', 'Wed-1577912400000', 'Thu-1577923200000'], + ['', 'Wed-1577836800', 'Wed-1577847600', 'Wed-1577858400', 'Wed-1577869200', 'Wed-1577880000', 'Wed-1577890800', 'Wed-1577901600', 'Wed-1577912400', 'Thu-1577923200'], + ['', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Thu-00'], + ['', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Thu-00'], + ['', 'Wed-00', 'Wed-03', 'Wed-06', 'Wed-09', 'Wed-12', 'Wed-15', 'Wed-18', 'Wed-21', 'Thu-00'], + ['', 'Wed-12', 'Wed-03', 'Wed-06', 'Wed-09', 'Wed-12', 'Wed-03', 'Wed-06', 'Wed-09', 'Thu-12'], + ['', 'Wed-AM', 'Wed-AM', 'Wed-AM', 'Wed-AM', 'Wed-PM', 'Wed-PM', 'Wed-PM', 'Wed-PM', 'Thu-AM'], + ['', 'Wed-00:00:00', 'Wed-03:00:00', 'Wed-06:00:00', 'Wed-09:00:00', 'Wed-12:00:00', 'Wed-15:00:00', 'Wed-18:00:00', 'Wed-21:00:00', 'Thu-00:00:00'] + ][i]); + }) .catch(failTest) .then(done); }); From 1c94ba99bbe3c9ad7bfd05418f6082b0946a88fb Mon Sep 17 00:00:00 2001 From: archmoj Date: Thu, 13 Aug 2020 17:13:45 -0400 Subject: [PATCH 13/13] merge assert functions --- test/jasmine/tests/axes_test.js | 59 ++++++++++----------------------- 1 file changed, 18 insertions(+), 41 deletions(-) diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index e9f9e388f4f..918a8e96f84 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -5206,16 +5206,14 @@ describe('Test axes', function() { afterEach(destroyGraphDiv); - function _assertPositions(msg, exp) { + function _assert(msg, expPositions, expLabels) { var ax = gd._fullLayout.xaxis; + var positions = ax._vals.map(function(d) { return ax.c2d(d.periodX); }); - expect(positions).withContext(msg).toEqual(exp); - } + expect(positions).withContext(msg).toEqual(expPositions); - function _assertLabels(msg, exp) { - var ax = gd._fullLayout.xaxis; var labels = ax._vals.map(function(d) { return d.text; }); - expect(labels).withContext(msg).toEqual(exp); + expect(labels).withContext(msg).toEqual(expLabels); } ['%Y', '%y'].forEach(function(tickformat, i) { @@ -5233,7 +5231,7 @@ describe('Test axes', function() { } }) .then(function() { - _assertPositions('', [ + _assert('', [ '2019-07-02 15:00', '2020-07-01 15:00', '2021-07-02 15:00', @@ -5242,10 +5240,7 @@ describe('Test axes', function() { '2024-07-01 15:00', '2025-07-02 15:00', '2026-07-02 15:00' - ]); - }) - .then(function() { - _assertLabels('', [ + ], [ ['', '2020', '2021', '2022', '2023', '2024', '2025', ''], ['', '20', '21', '22', '23', '24', '25', ''] ][i]); @@ -5269,7 +5264,7 @@ describe('Test axes', function() { } }) .then(function() { - _assertPositions('', [ + _assert('', [ '2019-11-15 15:45', '2020-02-15 15:45', '2020-05-16 15:45', @@ -5280,10 +5275,7 @@ describe('Test axes', function() { '2021-08-15 15:45', '2021-11-15 15:45', '2022-02-15 15:45' - ]); - }) - .then(function() { - _assertLabels('', ['', '2020-1', '2020-2', '2020-3', '2020-4', '2021-1', '2021-2', '2021-3', '2021-4', '']); + ], ['', '2020-1', '2020-2', '2020-3', '2020-4', '2021-1', '2021-2', '2021-3', '2021-4', '']); }) .catch(failTest) .then(done); @@ -5304,7 +5296,7 @@ describe('Test axes', function() { } }) .then(function() { - _assertPositions('', [ + _assert('', [ '2019-12-16 05:15', '2020-01-16 05:15', '2020-02-16 05:15', @@ -5313,10 +5305,7 @@ describe('Test axes', function() { '2020-05-16 05:15', '2020-06-16 05:15', '2020-07-16 05:15' - ]); - }) - .then(function() { - _assertLabels('', [ + ], [ ['', '1-January', '1-February', '1-March', '2-April', '2-May', '2-June', ''], ['', '1-Jan', '1-Feb', '1-Mar', '2-Apr', '2-May', '2-Jun', ''], ['', '1-01', '1-02', '1-03', '2-04', '2-05', '2-06', ''] @@ -5341,7 +5330,7 @@ describe('Test axes', function() { } }) .then(function() { - _assertPositions('', [ + _assert('', [ '2020-01-29 12:00', '2020-02-05 12:00', '2020-02-12 12:00', @@ -5352,10 +5341,7 @@ describe('Test axes', function() { '2020-03-18 12:00', '2020-03-25 12:00', '2020-04-01 12:00' - ]); - }) - .then(function() { - _assertLabels('', ['Jan-04', 'Feb-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Mar-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13']); + ], ['Jan-04', 'Feb-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Mar-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13']); }) .catch(failTest) .then(done); @@ -5376,7 +5362,7 @@ describe('Test axes', function() { } }) .then(function() { - _assertPositions('', [ + _assert('', [ '2020-01-30 12:00', '2020-02-06 12:00', '2020-02-13 12:00', @@ -5387,10 +5373,7 @@ describe('Test axes', function() { '2020-03-19 12:00', '2020-03-26 12:00', '2020-04-02 12:00' - ]); - }) - .then(function() { - _assertLabels('', [ + ], [ ['Jan-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Feb-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13', 'Mar-14'], ['Jan-04', 'Feb-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Mar-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13'] ][i]); @@ -5415,7 +5398,7 @@ describe('Test axes', function() { } }) .then(function() { - _assertPositions('', [ + _assert('', [ '2019-12-31 12:00', '2020-01-01 12:00', '2020-01-02 12:00', @@ -5425,10 +5408,7 @@ describe('Test axes', function() { '2020-01-06 12:00', '2020-01-07 12:00', '2020-01-08 12:00' - ]); - }) - .then(function() { - _assertLabels('', [ + ], [ ['', 'Jan-Wednesday', 'Jan-Thursday', 'Jan-Friday', 'Jan-Saturday', 'Jan-Sunday', 'Jan-Monday', 'Jan-Tuesday', ''], ['', 'Jan-Wed', 'Jan-Thu', 'Jan-Fri', 'Jan-Sat', 'Jan-Sun', 'Jan-Mon', 'Jan-Tue', ''], ['', 'Jan-01', 'Jan-02', 'Jan-03', 'Jan-04', 'Jan-05', 'Jan-06', 'Jan-07', ''], @@ -5459,7 +5439,7 @@ describe('Test axes', function() { } }) .then(function() { - _assertPositions('', [ + _assert('', [ '2019-12-31 21:00', '2020-01-01', '2020-01-01 03:00', @@ -5470,10 +5450,7 @@ describe('Test axes', function() { '2020-01-01 18:00', '2020-01-01 21:00', '2020-01-02' - ]); - }) - .then(function() { - _assertLabels('', [ + ], [ ['', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Thu-0'], ['', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Thu-000'], ['', 'Wed-1577836800000', 'Wed-1577847600000', 'Wed-1577858400000', 'Wed-1577869200000', 'Wed-1577880000000', 'Wed-1577890800000', 'Wed-1577901600000', 'Wed-1577912400000', 'Thu-1577923200000'],