From 06e8d4cb78b24bcd7f254e7e4f25a0354199c6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=BChl?= Date: Wed, 8 Apr 2026 18:21:36 +0200 Subject: [PATCH] docs: add README with screenshot Co-Authored-By: Claude Opus 4.6 --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ docs/screenshot.png | Bin 0 -> 25803 bytes 2 files changed, 40 insertions(+) create mode 100644 README.md create mode 100644 docs/screenshot.png diff --git a/README.md b/README.md new file mode 100644 index 0000000..b2d369e --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# Kimai Heatmap Plugin + +A GitHub-style activity heatmap for your [Kimai](https://www.kimai.org/) dashboard. See where your time went at a glance. + +![Activity Heatmap](docs/screenshot.png) + +## Features + +- Calendar heatmap showing daily tracked hours over the past year +- Project filter dropdown +- Click any day to jump to that day's timesheet +- Streak counter and summary stats (total hours, daily average, busiest day) +- Weekend visual distinction +- Respects your configured start-of-week preference +- Works with light and dark themes +- Responsive — scrollable on small screens, resizes with the browser + +## Installation + +Copy the plugin into your Kimai `var/plugins/` directory: + +```bash +cd /path/to/kimai +git clone https://github.com/toph/kimai-heatmap.git var/plugins/KimaiHeatmapBundle +bin/console kimai:reload +``` + +## Development + +Requires [Nix](https://nixos.org/): + +```bash +nix develop +process-compose up # starts MariaDB + Kimai +npm test # run JS tests +``` + +## License + +MIT diff --git a/docs/screenshot.png b/docs/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..339a9627b204274103033d59f333b0881554dce3 GIT binary patch literal 25803 zcmeFZbyU_{*Dh>eU{Dew-6;r2cS$JSt)xhE( zXFtMw-t)ch8Rz@s`^NcWkFke?d;Qj$Ypyx3dChArKUrz9`*$AQxpL*oeF(Mp%6I!F_!lZPiRmj>h_6V92r4>guP5A!)+`zD?#?s2$M&$`+b$vgZC>OWFKuC} zUF`=>o9`!|zy550?Q@x|&?b4m0EUyyQscL#CfD=B@bS~;`i)84q^gvGj_k!P&n;~& ziTt21JImts8ciQ?`wYo%3tYK|_Vx-A@s+E;|5w~!;I1x1=2>##pZ^N};M&y&eDA;i z=wE+NEO^bg0*O12R`}u|0v)feU-~%)xolCiiOH-p4e}m~lJ~zq2*$!7?)mXU-u7`e z25kNs3X=+}2I2b)e?Tnzz{8p;ifYZeF}^{A@+X=tE8;rprH^L#3y6_QpASZST9xlG z5HdeG*kZHpe~8C!{!Z#=w1HB>H{nZjdPC8pj$v8jT&7;vN>!v?<8*^*DCX0uVn@W? zifOWE8g(>B>gR4@8YU(txrk}U%cjbB_w_yU1Ji~UIkxTNUN(fHLUBMv5Rz72G#-<6 zF=Cxt4bA#L*mue8+En1dWK$4<%AG8!L1UY|=S);e2kXB!&5i^W9)zr(oh2h(`jW@n z;^8PAcf4d67lE3sJ_EOI=DFL>`t3MJZ$Vapr}CgM;5?H{s2MY)-qctCo@ja_l!Jm12ixh z30!x3N!&Fw;>?OV+0vNvYWCFQObc7HoHm!!lgv^14nApFe!Ic8S-mr=Aj4}QMqnGh zUN+@cI_b2kgb3;)^nbiyH|c0}ybx!xRyt-5EAi~OIG244Fqe&1s-$}}Cf&UI#XH^n zQ-j*hX534kJl~}K2#M}{PWd7lO++hSyXK8kdV>Mw85)fB^X#h&&iv`hHD2uw0$2yr zUc&>KVFLT{SGVvj-?{>mki6+nmr3%AJT-laoOoK;$AE8Je{NB zhl>$9HU#mX9rz{k|N45}EWvgVZdNwICUSaq(9G|h5)h?nErAw*5vb<0m|$-jrDX?K zQqdX+;+VP3y_!?Bwo$c-(yiluikRMUK8iyg4Gxy{=D}Uv2HX zpp+)z*Wr48x^FjP5H&Iz%x_-reZRiU5?j)TT6P+%J3F^Ba&PNIA*Bx(E zv4KgAf_*f(%TWIE*!fxDBZHZ(lbvpj=g*(}7D_WUV%ichidbNRwL!hl@#Z zLAO@Q=T@@w&BJ8)9Lx2nLSU1Qi)wXlr{8&5=2b?WH*3t`jo3w;i}5g0ru_jGosoPu z1l{pSx0@lCWDJF$h+k=+Gtq|FA15IfypR$fJXq@0-T3T7c;}sn9Q<+F_>aQdBmQ)GulvOcs#`kf?5R?0 zBjhglqGC+k&j~k?oaXK?>MjKmYJ4K*u_x`Ddt8yA1$X#y<>Qwo?pE! z$>B{sO@4Jit}RH7_EBbrlED#J@|*Ls{kpL_!_3O8E;U7ZXKm6IFC6Ux?#*hJCp`1v z3h!h?U$)6p3T0!#{MTrl(!TJ8$o9jZi%x`ZfP+ljBh4|5qydiW;|C*k=ck)yXNQXx zj4I8{6p?gfF#kKWp)nMq!dO_3ah9c6xs2)mTw^71k6xoDWv!w;ayh+(EOmsKpH10w z`+Q8>6?!GQ1)KMlDS>Q-MCS+1f~NYtlmrU#&Kni=tI$jsmNVve`(!L|bX=^Q`6jyK zUU}nk<-EzYU$Ci@NzN^@0bb~{^r3IEAU0p|*gL=1-r-Mr9%AlH@GCXPBRu@};_$2rClTz3Nmtc0aWbpxN} zjYxb~3eg4fc+6Zn8Lq)-0)rgo4w^brL4P}%AL+q1OW6@eU&SM{uwYKwA#?;q;j+DO zLD6v=oxCE&?C3DdAGfqI@Anauw|&Wo*+7-#Sl%C8ZZVFup^_qsSY}{~I+d;lQIUC^ zszcsxA1>cPqg(d%+TCJ)DiWswB^C4-z0yA+iNGx+r<~}pmXE{b3$Z5Oweq*W==mQx zrSg4eS}*P^C0gv06LL+JTZV!v|71o>;zr2wYJ~p_8li~PHg4F_{)@S#vuF{`L)WLL z)!<{>sri~K^|T;KPK(%{{`5rsuEL54L7Q0ZgSRUwtEDRF66|y_T^A0uw>dM?(o+$=+gXrgZTHKI)X$>XEc#+3xw2%v9)fOd4G>M55>_6JFVv zu*%?c>iAI7FGnlsE8i117a0CbTPGg{f-zyjJ}CElOF0*!Q%>)O&ntD4vc)*ip2wyl z2~O3z3hPT<+lYsC8Q1lt2EU~iN@tX2s5{vvxzisK9rm-wN79B}hKQ#Z{?+69EjwCs z8y~4U7tLga&4FG?R~Pc<7%WGlbKwfoxEubqi1tx|xF5MIr$R4(3IDOH3x+bro67n$@^4>S zqDZ~wb)~BH@J7BCZ)*k4h z)niN?@xlmP5n&$p{(!3fDj@Vm#%~SM7QB~oN-#r3T3E` zJyU?SAy`aFpY!;^CFw~x`3*#AXO$^ z(ak%?Rk-%=KZWqU$9H7ng*#$xcP||MtG8|V0b<{0NxNKjc!9}a1%=}XUC3l;pn~zO z*f4s5eCexqsNP1?;nOf)D&2Zc!6YZTqcQ#j6`(Z0l)l2G!XdAH`wu&T|NV3fCRv%p zL~*GurH%({viwqw_NTef-U{r4N!s%3NnR=#WI4c^ro|meE}38hOmfw&Dg0t>BJjx) ztm%8mw$Ps^6wF{k<_go$=?9vtm%jRc%J3dS!15|#mu(~PDfDac^&>SClkAe>;`jXX znFbxvOlA?dqoboQ+yNwhDeMzi9AoqlN$Jvr(K5(9gh*k&6U))@i1}A^*B*?f;c*0J_FgXfX&yY}Hm`PN+0}@9b>!j22K}`R-*KB^qE)33 zUR(R6lhHuhL-6Pp6HYce4bBC>d;JJ_Y1;CeM|UoqnWq@Q*U1o+W*!%+_*idnVvH+e zy)T~MKoQ{5;x!T)7ryF|M)Ee=BsMSY^9BD9AOk+bDsS-v`+}c+G6wN1HZ9wj`hwT= zh=ZdZ*dJGX<3CPYy7CA@l`7hfjT^Pc=BpD`_QwiP3ASE$epcEebXV&-H z?v{(8WS1UT3*|^}xZqXkgx%Ok^-h-w$oQWh*X;ga4d6unmJ-C(2Aw6w>R;~&+)uWk zitBfA9d^S7R8xCr$D3mq&*|k9YPWqhD;5czw;FNQmr{Zg=j=bCUs&N%^w)xEvbD)u zNreWHnhl0Y22ChLM@zHaYcX}Tx+eLh@%N*%+)1d>VFWM1G`QD65p=(|48oLx;Rczb zE%DnBq+UOSib@TKX)mbYzKdQnAF0trUO1@Z?mA{SX0|?Rl3xOF_5@(=^q~5Dy<#zu z?Qkw^48lG36Sh$apqd2y!Qff^S?!>@$w(LXrfH26B6i70uQ{j$OIh_BsELW3w_B;8 zLg^l&2b7DOe9nMFSkEcyDh%d78#atFz~(;q>1l!;ca8ZZm7c8CnTy2~Hk9+Hd59zqqB!JR=Fkh#R_!?s8Its^2 zQl@mWB#hYfcx!*ea$hqF=Ny`b+u^)fc5Z1Q|LL;KgBsy(>O1ADc~v)iRS9GILb|2c zC!YEWMw|jFWCScx+gET4<4+HMO6IXO+dNi7A-F%UB5W2I5ml;Y_z3@r%gHj%-lAAy z$#Qz!;Gnkc2%0YqEy)6{xEt8}($l>$A8IuSnAw;>ECJX>*U-jsP$U`y2(DAU&!*q< zk$AyvCvIwZCV-J}l4dJ|c~Dg^@Ygw!%P)`9qoFz!(ib5m^vvmtU;s#QFI-{ndhoc}zoJ^e_uHxgdjM1Ab5LWf~3 z*iC!kjDj`yGg#ZWOD}^}=Sp-y@ImrU#Y!+ze6p)#1d()zKp#^FI9yLoG@HpO2q|W? zot9JWn9^sXBu|ge_dl%rqLZ198mE_xnO8mbt=_f|XU_&;8H4I-hJ80+A_P@w?@0U! z%da50AT>ph+U!S>+USIn+DLjnN3UQ7|4rU_HdpwFbbh+3z?Ez>{IJ<(t&#zSDBVphiCLQF=>!5bw%ueMf!i?qvskF`d*L z7oYcu$<~!rDl`i=Q_?yk{aqeGA6L2q*(aBZ)U7WP!5#u=HmLj$&hogeCrIXY%^Ngh zzPTPu`%F9N*)=d9_X^%3(0~58B;2fet4S%Kq7C&^_?RvDycUNajq99-DFFJJcJ4B9iA;iPG78v$NKmFZm zz9$DTJVKhi&p!Ur{h*%cq0_~9Dg+{=L4s`~mdblZo=Eo^dH&k-v*Yz3?u~)~hRO_$ zhImqg%HuTVwmOlK-XZ#YKq^?SS?@0OmJaI%cvU%EzlCy7r-8K}QTUhXmI)WT1^{W)I{)|>qQXm1;SLxKn3dohQbaABk z427>;gbD}%3bLuzAGQDRQNX;fs4pePAaP+GSCE)Na3wUo>)*0mPgg0-4u}-Q&scfZ zKM$F}r%A9{1f{g&rQhBm21xM=Y5rx*W&y@@dXUa@VUR1=ZlD1idL=~V5+clC2WhXy zPl5144!YuT4dkXfZ(Hd8JTL&t^v4PG`Brq-9W>p%A3y4}zoBH&6n^VMA{F=~drhx7 zu*kw2r3g2TNOj4X|M0{l&Q5^e#LTQDGBWa4I!_58P1AA<8%j&r`iM@G*FM)j8|`4Z zM_VjE75Gr?XnrikZ2Vx$t2Qd?qDj%fbZ=xH$@C5#?Qg2Q?&X#52&AJK>P=}zf{R}~ zRKy>duZngZ?Iq;cY!}#n?pzAd&FjJ5X1-*W`{H09-zG?gU0A3`6F|5oCwyraivoe` zfNN)cnf~Jf$mUK~>1saWwWt{PBOM{Xe&MPiB(qUJS&P+O?4Q49A+}jZ7v3j%*krp{kBnvduv5 zws;$PR)9R^vJ*&P`Sq$Dz(s8O$Nr{@tT_$V;O7#P+KKLGj!^zyM|D5&?Bv<$5Y;u! zu;&FRVefeAeDYZ^p&7`?0@1>0@z!nLZ}c4Xyzk=~8YS390$B9?H=2O5cHPlHex>Oq z#H9l|IS8a(DjJ57N=ra9j>@s%$Be3ZaydPjvce+;u=ycNC z9LQBrtXI~u9Uva$dJfR2Fj}?33no!{&0>Z%K%ui){uHPJX315_*Y>TDc9P8r0$gj= zT4DS52N=icNp6)|E?bRkFTcM1a#SNAlY$TpgBtE6BjE1XdT7&%vp7ts%~!d~}42BnMhJhagLKa#s{nY2@$)9g17OE>}iY-8Z7X)jm;RcR{XuWsBX}kM%=M(0@CVLt0 z*K`4gUiQuN)~)7sKu!8|vQN3}fo6lZQCgDQ(Y1{IaTS+e-)`B>_)*>D%gxQDG{^Yr zuPU)5vGm$J#;kN?t)L#|?mG(r;)_!w)!QarcBEE^@{HApGQy^C6rF_`-KU z(tJ0Je&zjj8W7m*q9y}Vk{BN9GEiqE(WK=@e-4?Ej@b}?!MB@u!&7H_WiPq?UxMGv zyqfHZmh0aG{P-OqH9VxclX=Fw8B(q~a2g~6r5&4!AwnHQKQ?5q9G@8M~Po8z8zB17olz(RTLxReS z?0T$a@$2X1u7F?OYop75pJ2!N7yx0{=x{>ky$u}pe`x{M;6K0eg2T;bK3@LwV1;@? zKTOJS%&aUS0oKLI*7>xLTrf@Dqp*Xy9mz*TjH>qRXth9Z!ZZ`?d_aY@k1e3iiy*6f zL*9JR0a{Hk!FYV9rO(s2oV24zuWgv9j-xz}KtF^Zm7oge-hBCl!)%}(;Qqa&7)lhnau%Kwa7%GA zQ^6m9+l!kzp%h5~>~hVXUgYS~$0u@%@?wlSpwKDEOh*WGRRu-7;ca2Nt*|sJk*g=x zRV$LaroC4K4(H9Ps3(ybI>2Y@n}Q!|+w_XQ3X{bnn~73KDs$12)hN#VEENZ={N(oO z)ai!(H$rd_a(@m#|GB)BmncPHOS!-mxA>Ik4NUmm1_-He07Kbg9Hm`nwvZ!q)}w-l z?=^oIn9Osz8EC9E+iRHiyKcI1uDau~(0_J%yzl!8@I~koKeON8%)`c*Ko9jW#u&6B z<(!YTp;$1ln8!Xo>~=S&%P9~le^3Ap?U?KS1kRmE;dD{0pm@7^%=zaON_4V&pxb0Q zw*l&f5~yBT4{1>xRTJUOHi)Q z*qi+K0r)DMyMS?oS-xyA2R?$zQ>-ynW-*1O)?@lmq-r1#bzpN1Etuj$tfxn+~1d{>_rzqu|# zDyl0}wJtg86(u~jq$}N=iWxJ+#FgrPx~lW47Xy_5w{JLvMIo^mnVjj9JC26m4Fa*} zB+F+7$uANJiWD)QuWP^l>_z!Tn#`AzAZpa@c)fnhks!4nIS@1qtjKOjqxkb7ecDP! z2*i%&`@TQ-Wg-MP3N6R{k#71~-Yf&uaO9ZHlPy1!3ixOj6|2_asEW|XTgov% zvh)Z#j}VKpT@-Hiocpv^vp@Nb=@>+m2SMG&9)l>=O&^m-xXd#HW=Bt;c%uxg{59kN zi=ChXlg_Ugw4fiGURjpT4Ki-;?c0i5D^CqFe2$i8-67AG;%Kp)8in%R;NaJ^-5R|4 z=2revzy^QjIjdM!P2mINYAw4F3g6=wyJ^e}v;?XI`9t1G8(b0{#$A{JP%o2%rkn5B z^njg{ohvb?6D{H3^;~|Op{rV}q*y*HgH8X7W=d9-mYX&m@}x4&A1KV9D({}F3nT1v zd3ooDl~n9TM=C#UeY&qR^1i9;#QPaGOsf;N^4#oUI!Cvo>vuy8nAYLF%FvYiI-&+8 z@RYB<8$B!06uJx%5l=olMWSlDB8hV6RpOM?ehnZZ=a!!en19AjA%H-lh$Cz;WLY8%C(iJAuNLm4shFBJBNQ z*H-9pQ;qX}X>RE#EyvR6T94LSxs+#KsJJcObH#6d$9R%ax@LOr&@fV;H>)|FD99?n z7sZ&1RcT1cZt5m$8M_icYoD5YlIK&vG zwCne0*Cy5jlsLFfF>Du095i3?w=J3?2blLSmX|N(LA6C0fq!_RV!L`<1eDtWx08}D z^<`erUTqlv61qw}H4N7?af{=#$SMBO$2}Ck-)q2l*O6yld#^E&HL7aoXXp5QS4}rF zYt->1XSav}R(7!b+LU2-QF_f>XVRTQM`rA7)gAquJ*PIUwOGUsckzs0R9Q`5O`5~X zi^&rPI^BEBK`ZsR&UvUt!Muw@1*KGIu#&BnZR74M{uG!zO-sg%x(rjlVr{oR7=#fz zQ(CyLabg>p79O36b|`hzM)Ee(Mp?Z#Q^cVD-YwCaxbyh)Un2;0MBGM;$)0@e@0;jE znT3hdjk&tEOt!rcoIZS)k4?>$h-4wlXuwo23H+LP;mo-(cPadRbe~1h6xhhMkHRQ$ zz&jNsd;^%@lq%lx9YmI~f$k$tXWGKPBc&lJ?692EFs7T@nH1)xpvj|++cQQKfijgnGQc00}$Wz>)We#U$5RmVzO^0upb5_o&Mv;k4qs{ z%S}Afmq+(E*e4xQ0`b_p07|{90hAWsyDP~YKfG(vbPGm{X*UwlH~+yeG>2O^*ICv{ z%0{JYwMRb+U%}7TY|zvTz7ed&6jX4(K{HHjL7HosTmv8^Plqvp3n5)nX*d7*H~?~3 zkf6#G2qNt|n3{)0akMZ^4Itr|UNG;VH!6{NGm*Oshd)h78DJhqBUH4F0rKf4Qex$s zj+sM)9Tq^=L<3DF9y$p%MaKnI8SVHUo^0m!wL45IymY`O(a`pTmVjnQ0%&pCff^xB zWCBPnUPHX7ZwJIn3wH3HpX{*dHuw?`hLcZ%@>3FzS>JcUy8W@>Fb&iNu>0w83vemj z@%&kDT)wkZkS=V$B3szTC0Rg&IV!)4ZYSG4=MQ$ppD0ReXbXsLFUvP1@bu+0z0Twl zT?ANlMv-xVz!p7YUpklZwVnY14$0K)Ox*SNF8XB-bGgd8W*DRQO@(oVlZrq zI+&lIWn^t3chC4mxBCP}w;R2W7Vel=lPKZ}O+3Vz?YbVXWEP zW5mp2`V79Du1E%uTm+){Ac+qkZBajo7fY-yn~wt+Hhy*$vjJZ>&v$Aco6c#}G=S)gL$;(QJGUv{T1P$q8C3Vm#h&Cq>JnYh=~7B_P(TKBvu3zlQ8 zHv;pYXZw4k;Mp}W(&ELDa$7@kW?n(Nc!wqC0G$*zKqlOgTHjVg3?|fMjm;CUH^8Y} zL8#mrSvGP+t?bM@?}Tq8qus6QtCZ&hB0Wu>0r=?3)CzCPN}@;y2&_fnh3RPjC&s~S z&@O2tUf9T1SL<7Fq6SPAL>98dp6N3XC@0<^X}s|yvgqeD zes&kU4N>r>w7PRp3_iL_Gc?QLyzSH^lw-{s&$}*V^?0Y4UHM#j6IW@UTo-7W6H?J) z$e2~UQrCDKihhL~SxYfl_}_g=Z}hG2_pWK8X8+*^K}G))H^ACZlnN#WQH2%v10f}| z3NJG$Y`I{Y{x%K6TX_5p)J0X>AYfFbqIt7YKK}u2nF_+@k+2~aY~6^}=`~{uf0LN> z8u(F}Q+Gxs6*`EEEA(D1nxVav-6B{fOj|EH;M-~c_9E52c-@MBEv|^raocGP+DO0? zrIklIj^bszo7h!Xu&Ce_s$Or=`;b@-zc->_w7oE9gN?qsYf%&kVtnd9!)XRfv1v>i zuBNE2Bf?kJf_WTy^++xbw^LI-ng|7sJhp)8XalKg4nsBGyx|<4yFz~%s-E-rd3iNp z>KK5vE?nE%D$hJoWldnnp5pFb_?!cJNjKAH&hElmOGmypixZK#{jdtdQ_ z7zU_2%m5FKRn0TKtm>#oaNT!c60<$fR-aV4f@V*yXn?cPv0kq`aaNe7aJ!hj5#D3E zE(H(HfYo{u9&b40aI!_3IV=R8Oy*4eKJ=Y~*v^H1tV`hJP_|&UBl=^i4}}YTnWB>g zwmy(`Cnu27$v7+Edv*>^VjlZ)4H=p5TL!TF{29`MkU<_=~suQT>KrkW!N5f4pE_tJ*N`YZTgRX(sB&Ors}yjF)y z#UY$Yk(tUGu{DMpadb?t-@I3V{D5+pHakbRnb0{Wx8VC7kA8^!<6bWg>jb5F#T-M$ z97dc;UWIANfb!}uH4w4e;*wL)1C)S?AACuN&Jb8mMPD=th`|Oj`Z}rz`caxLIB+tK zn{l}{G<)c_T}fsB(PLmo_=NrSdK4Ca8%Dyn0?2kbZpw%%&2v(P zyK8wHtvSat%Txf&l0SUSi!ZA-nCI`Wx@7%cz5Qm*{-_v{t3IFwozcu7u`NI$;|!Hc zq|N{|tOKQ838V@(uR$nR0RgUO#uyN7o1G$tP|5SFHn^%l>)H&o4hsQWIR=`o()#9O z+}H6aD^9*CHwewe5c7gW0PTzhQQQlr(K)!$e`$lsNftl}{(yU{;lcX5y9@_rm}U>j8Kp&0*&VsL2tK`|*Qx0OfzUzP~_zh2n${kb}fC z5F0FjSS#u-g`^ZrAP}s`c}HhI!UDUa*sGRGEvw7<2%H%X8aO_k42VtIsC3&4GX0`C z$28W!z4qp=3W21P(WT*MOwq9_b4r z9$YS)3<4lPW&^T;n;vOZFi^L(KsR*`M(2ToS{D?PnGhzQc1s|&0oNi@pr$&M`Ug^S zZa0sBlS`Qeq8+GzT>9w0Qz~Fm1F97qnctCwY54CAab2(j*#MT4-j!IL=tx$_zPc~M zth)isfFeeLpu6LJ4;SOM8IZ!40_0gn^jXnHnn)l9+>tN^gzx=i8Hr|Q1bPJ2w=hhw zRVIZ|P`Y#$9tkSHpIrkU3KHt?(^G4P{VMFg5j$|1R2az#Q+y-XMa9TKX$Rt&xD14V zGJ$g$aW`o4rK};lu?iw`4hE10ifBQ3H#EQF4Fmt|N2==Rax?geKPxtmZCVQ=J1?n10Wo;SNaS$0DMitC+ zszF+;hJ)DI%Zy4F%$q)3N2om4sq>{MWn%alBBy{(RSCn_RrFe1POy~IpiXf9OlzD> z+COobt-|T1j{k!%%``i6fsJh}t&Lel>6-tHlf(uUGKEx@!>;&LEN#HBu1;@9b6KZW@Xf6 zcNtxk0kVM3wto$>Yx$7YdnqD9Kx%4vWE%D&P zFXM^)H^FRN`v?BYP1vBg{Oc!h=#%g26Q{c2$Lx{9K4vfRph3^54>lika>;;Y%h+^= zm5uV{Hp6~@&F-JC!Eu=W`6&*Q7!gSpn$ls)rwUP}9LFDEmPj#F7A2*M!HZBa7rTBB zpmJ!rIlA1(iH%51QGb0h>>cz;aS{D9>euGz%WCet?>hdI@BJ~=|NFiF9eY+d$)?@A z)Y!iP>2B|Z4_!Vox1b|4uPSB*U?{R#GjQ#3kSN}7^R6QxZ&z3}I5DjRPZc`u;D>Y6}C{39ByE(ih@)VWh=M~U-m@sYmNJ1bl-TR5h*1WWp6%;^s z^V8jV9rfT~jget9AXixU+sy-X?g+lr*~HmsHJ1s?aSVlj+#Dy%+QvnXIVMT*#(;tA zUS9xL>>hl@E)vT1ao~DI&hG{@B!rG-L|(3;}=M1xfAVfRYU=5V8ydNrNJsuqRc6l>F~n&{I(;6Q#aZfvYysvNu{` z0>f*fE@C!^03f#@Aw%S7>REl5heFDnB$w)&!zZ@SKk_St)2{;RPXee>E}+m%j}9~J zJPN4O1GT0X`=Ags#{bjir4!0Ubo;hwdWtRB7y(e1b~iU3NSoHPvh$ezDz09?IefI5 z9~@1$>JEa!gPS20M*t&){_PRGC<*DBfVuNCOwiLC@fM^0!V$z{8^kK(bVMDgC1;L+ zX%)fSs1)j`Vo90V!Cj>>(24T_b)RSz*%I&!sgM6v&j`3f`tI-pRJ5c>xXJ4jtu0-r z_6M=q&9_9&KJdS@U>qE1!FrMR-8ujba!maCZ^yBqZ>Gft4z9;Z10}Gu*D3%fM}wW{ zH~q&=aqk}TJ2Rf-R(3kg~#O#rww@ znuPN1j-I7%L8*6u^EUvgce#@4)Dp#Ow}Hp2N(H zXpr^TGkRxfcnzU)BK&K02>(;v{0X>ey`Bmvbz5i~xtdpWWGYq@;Cg2-^BrdLuIF3k zd$Qt;1_Ip!$TXeVzBdX+C^==Et=hJwif_m5(o=#TQk(OD+Sr*_Z%R)EB!25wjZ+t_ zb~gF76il^L)kRFR>r6)85EqxvgC&DG&A~oKzG%!Styb#?;UxxL8h<<}w`+F~?+n})@w*KimNaEs9}i2T=oO0r zOc=LoxflL?a%C}FwKPPRC>1hg`fDiP;{(tfRke*xg2@xcC9P(T0}4BIB4kA9zq9}) z{NIM?vwf5rhU|d>XH}Uj=JsLeu&VT6-4SmPNB-ECe}_kaJ`C%RqBF<`g`@nVI;ph8PTpMeNH zgtJ+55f_{x!e)O*GIv=_rZQ&`Nz5Ep@aZi4bL4YiIcJFQ0I>Ze3-~BOM!#79-u-U- zHXgliVeF0K5dfZ==7Unxw7z~sfx$65DPMQw8OSN5*_f;G$$*ds-Up!5Mw>>%My`>3 zGfn$CDQFq^`u=<2%Kv){f0p%+>;C7y)1GAOc$v{aCI8jBs5ACIyWN2>H!)#3jd}9w z-F*VKABKsqWKm5YDP0uR5%-isl!$Abu5XO2+u4;sS9Vg-s^qR=B?^z>I+3^(Pu?j? zUa?oar>ivVgPMzKRUns}TI2w)Qb`1f2GEcT-A#zUILnbyv}Xfko>)0tWFHI79PlLo zuOEK0g*leT(*@<$`6g>}-ruI)11u&;uDD`wj&xP?GgHkv&>;c`JNI#E(Z`uj>0O70 z-dgi4ZHc~}ZL{J|+cRJ0#>7p>esR=+AQz5j;QvLmN);5MT&ibd5gieiyh09EJ;oVT_03-9HEKT95jb}SkCvH;&o)so!Ss!Mu0v2 zHHUzLH+1ZPf#x6%IgTH1=wBEqV4eQy*n2_e9VyJX4kN`czPlU-zehU7ccypvYotKH z5jDL7=wm%lX%Tb1jU`CeN*X?XGE)9eVPa}T(kLjCu+w?3stt@nyfgfzIb?UPQKGdh zWO%k^_QdH3kZ?xy4uJW5N0t9O8-Vy#wf%t%P~94n7svWMLV0gA&LVkOpD%^f>l0M% zfRQ#AhxNYwHIg|Xn^>@U{#QG%%YByy#c3tp!f;p#jB+EUnUXi?3l*cZWNlyrp%~#J zl;5nO-3PoUAQ^4<=A__%ZJy&%*~s>vUIfPKWP8;!>GGhFat9ZS28mZX1{%qYznSpv z-y=b_BK&7-oUSwAv7v>fsKzVMv%9n9{X@=;sfk+wTFQl`K5rY0(!#^GY(>uNXeGaG zM!v_f{g*GTLU9Kg2_gq90P)zH2kO(ly3WW;W4$g#_S{>Dqh^cg&JZVAvTEajMmpvM zot1xiWf0^8|7EYt5Eop4O9YcGw+4iTT9Cn;Lz)i}yHIBUaw5o^ego&6zYa>`nOSM| z-yS{?%t~L0fF^B3dT#ZLzW*vg#TuZeyXZ)@p31)MhFS4g7=C$4Prw|%%WjiiDvA(bN!dgul9!kC5EMnPs2$NSiNKEl?ePDm z*?*wJ9#E=|`D~7q%T`Ut_T(~0w-!-)q_59VW z1@BlB|Nf^EsU?HlfLy~G_NgKDMYShU$DklFfkd{DmM~59ES>)}6O=&OY^S?@iwgtS zlU%m_5&%01sT`FME+2g68m53skN}$(keH*1&Kn~JC4h4d{JKEJPebr3m-H0e*Dp&t zT{9}33w^%8SJU*!WH_2hkJ8C}Hjo{~_7S&T4gpY%?E!XpL{UM?pxy@+_1y+^cL`jf zCfi?}XZ$Vp1>N66L09OW8FazPG~jV*0igf7N~he8$GMyd9ab{a*PtsGKsM8ctzpX4 zo&Bbbj(Y;SYIZmuRR&1kM?-*#nEt_kI0@OPXn_Kg2ZPJkT=&7Ks!JF zw|Y!w?aLNpZ%it9Kxl-%s6!Xew7{biJlc`BQUh2)aB-{b2HwU*)joM$cI4JR5OUpu z=Y0tbejvkRm28d5Irs6&5X~u&5tgYdQnZPw0;RddTBoSx^Msl$ryNmkh15*By4Ejt*(Xkpd;TnrhY4 zI@-tJd5coel0Z7{{y`SZqYL?w>Z0Nlc;cdCP|JP-<(N4CZ1iUgB&2{YZ?d zC(B4qwb93C+$P6!1SYsohbhP16QvvutWEG#Fm6yV8NnF!YS_7k)v?uUpI^hER_B=l z;!re+k0~U#gx^gA4QzbN*3z0N0gyx1s}H9q*r@|*x5#R?sf6($Y?2}@QDMCU--eS7 zQssHRRC;4()@cUrhs{p`x6v3YetI&ItVDDKhfL%nREg}PHO8=pu|Wm$S?}w zeB5R2JO8BhQ1zw9jd%6Q%*ENma1I&W51%_Iqa@=qb5?^( zfhDKlt_6yjCV125#ir8kvvoQg*qea(ceaCSi?@1_*Db-5NnLi3@aRo;E;jxhPINVS z{tSK)t7`3-=;gMznu&b)T8&Hn0Y;L}*>;qNU;Hak>JqXu&~JP( zM;)c2?&|RE2F@@b+t@;0cbP=52^lQaS^r}09mAr6NBoMMjSQsm^9CYbS`h)(H0Zhl zxE$)>tiJ(Vq!hRg3kL#Y8|XvJmZ$pnX;pf2+ZpS4PO3uB+(6^wh9O8X?%FJsCyqde zEb{ybbtYjU&Z(S8rZr3`=p;2t`wb9t2{~x*ZO?_ti~?=3&{LT>!bf$579(*DxuM$< z(XA*q??1wPFJP$iNCD#!cqN7Z`^}FF_x)}%W#GGyA}yP~FaXkAjd_<%@KDRQ(ujr^ zr^F3Ux=2D8E%N*3-X(Dn>}Tn|XyHY@IZHq9Gb^i;ZiEYp1m ze+zo8i*3yG!J6zTHIqtvyxb%MBLBentkqN+&tvrM!7S1F!(?|y6TdZOgc8A1i#PQ` zJGE@#PpN$KNewW576xxu^cc($=ws`^`_;+06@DCj>3ne-60LaLKb6%DU6DPKqq7)L7*EOR$m9VN;fxroWe&-kV@~DP_|hX zsb*AMN{CS8rHIu%G-TZZ{<+l*Q~% zCWiRH()ENuD!iU{QE^iiQ%F}DrNk|dK<4oQ2D5rRg(dmI9DOTtl!IL8jy)v4H4+I5 z!B%HwTpv_

GwPC~Cze)wQGIA6e*( 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 wL)g|cBoyKSd_^0lmHu