From 00fd49c79b972a531c402847007ada4ba20691d8 Mon Sep 17 00:00:00 2001 From: Lilfade Date: Thu, 26 Jun 2025 05:21:21 -0500 Subject: [PATCH] stuff is working again --- app/config.py | 3 + nip.zip | Bin 260345 -> 260803 bytes plugins/auth/routes.py | 6 +- plugins/core_ui/templates/core_ui/base.html | 34 ++-- plugins/media/routes.py | 25 ++- plugins/plant/models.py | 14 ++ plugins/plant/routes.py | 180 +++++++++++------ plugins/plant/templates/plant/card.html | 144 +++++++++++++ plugins/plant/templates/plant/detail.html | 211 +++++++++++++++----- plugins/plant/templates/plant/edit.html | 119 +++++------ plugins/plant/templates/plant/index.html | 8 +- plugins/utility/routes.py | 167 ++++++++++------ 12 files changed, 639 insertions(+), 272 deletions(-) create mode 100644 plugins/plant/templates/plant/card.html diff --git a/app/config.py b/app/config.py index 59d7a6f..40f6e1c 100644 --- a/app/config.py +++ b/app/config.py @@ -40,3 +40,6 @@ class Config: STANDARD_IMG_SIZE = tuple( map(int, os.getenv('STANDARD_IMG_SIZE', '300x200').split('x')) ) + + PLANT_CARDS_BASE_URL = "https://plant.cards" + ALLOW_REGISTRATION = False diff --git a/nip.zip b/nip.zip index 922fc06e92da9349a4e961135d828f98af9c1904..44a807a9cf4c47ced43e72a7ffd51a2328de8045 100644 GIT binary patch delta 19162 zcmZ5|1z1(h_BUrAQW{C=l#)gyr3LAh?vzv-+&!Us_On z0HBV?6yQQIiV2t_7_$W~pom7gup9=Wu_X;a{!5P|%l!{Mbv*M6GVr|}KoK7;K!704 zmu<&KG+w>|-047n z!cq<+?dh=7WPD7I+K*v0=~AZmt)gL>zgvQk8J^gDwa`tQyh#BKK9{^2*TRyFa{pBM<&2V3+d%G&{KF!9`fXm& zJ6NWCc&6TQq``uKU-6f~bv*7d(t9-k%WtD!QB(6v6T5X^X$MhE%X~XOCj~SmjbIfd z^A5f4h&(X~UFk4=u8z53pf9NVyDckgYTo7{`XNcu(I%eOA&8OBYWnb4vG$3 zyzZz@SG3d;ukJKKF8!9&>d`!j$?-%Zn^9p&S2E@2v^1~J?OJ)(O32mW%1YLszzy8a z^NHRA6P-6)d+bk?#O>6gLyf#B%@$a&byAvx?)}8rdE{%j_GMuSUEtU3$G84D&DuZH zV1m`ob-WMI=lfQ%0>7V}X5;5_fo=w=GMv(FP@S4xJQ=AzF;uD}EvzvsF~Je(;I5b( zw4F2Pc@=@dqsQ^u^H1)3eyK6V%41NMm^BWgKym97;L1bBEO!s0zKxWyGPR~ZLsc3I zIyvZQd-%{4XIYhX`%PPBs8^RX`?uq~6WCj|km0esRfj-BsvLq4`J|eHRYralAqLhZ zJbmNofUl_#@vo9%ja!3R9CI)>G&M;4T+`Jl<#_i!Vvm!N=S5s6ejZBR#y2?|;DfBCZieR|? zI3e^6Mh{WNhbVa|M!ET(<-VEVBbj*6EM3K|WWzSjLzBhCJRHTi7(j8)Ux~*HN{Y?i zd5}0l^+E%v6TqZA$A2h>z8^UKRCN&BDmNSL5Pi0lTyJGtVX)30 zgVBl;?SnTp-N%C#YDHfYonOK^+z1N@&Tf7(sDMGP{h(tZ^er|H*5RV)Q*_A|2|t$e zkg5>+n2HA!(XM*jBO!73em^QAsU*vtcvOm{+g*oL3zBe+TBIsCeNMXJF^NvD?|#vM z)QGWNUFvADVgciD9uqeS^&={YU&Xd|L%9%7V|kaH`8jNMx!lm!14_$Gp`H&*njUQ; z5%-p7%cy2Tef45*?U?>CRMB2+y~lExWiW~f-!Ihbv_~&`^o3> zqJg*584K7Fw0ic6`sLMly?oy^Tf}Zf3Ww^@YX!v4mB%2Ic~sqNdvqsH)DpgiE#hHk zL<_#x)i#q?UVysVln(#WlA`Z-@@8J9kT)Wq!a`|y%gMGoXs7-do6(*^5yq|QqfS1( zsY&}o;7W((2&}ku!wFDoDYffRsE|)EaTBVN^rvQOSzH)Acs%*W=Css3UZ;vt*NqjM6g!&ap*S?~x zVQTv6+Sa&EzQZ9R;;wODvw{Veg;)(TFr4McA&*(+-e(RIelt80oSRpICWzrIq|sEX z?4J$eHe#v{a^;U;T1Dwchi> z^>+FA&&9#j!^56sW8BXa$4#|R;-j@xVTp%!gY`0o#j6$~j{Hd3og}dBzT*g#b*{XP zP5=J$&hyhsqgfy>tcB)Q!cY%<2T4+MX@9J&4&R(2M1BTx-w_EUN>IYgx7 zlSnuI(OxgWr-JG2q-F%Ny0l=E=m)8`RKAy+=90ZuD|IWnTEVJEJnq-^vkx7t>xc>) zJ)B@c;`*;k`xT1fpJ*h)I9MioWGi=&pCni{$lq&yO+tn0$o|cih_zH}ul<>GR{=ro zFe>gyzxlEhGKFTbc9f8qL`9GzdccSF;T4}zOgWC)jfvH>`LUNV*)GXNtL`acIKkB- z4(m7l!t4|4SmkY)e_RFIwP;K{D_1k_%iJ!c`UJ2Iu$Z!zMMni4!D8`A`O309mD0D- zcF#P^o9H}Vdc8ECNi7P>8ch0zl0EqNOpT72y3&Y&U;o&{>6Z4%Ud=a*1MS_k%HWH< zt`22v@p{$8^e}~z*i<@v(z6siH`8=mN%9YRPcR4c=zpvLW7gHIO6PGO_+aW%6hN7Do50xYHf^XEsRjK;@9`Glmmvt<`4+!4vtzgHdd5@Cq_u)b zcLgV2reEY^+Mo4fb&ct+NT_~&b<7qpHPRSO@LD&_J3J{b*SP&nKEv`Zp8YuN=Y-`E z8ma5lb{@H0^!`dArrdKueo6vk{S_|bA4=|(+E4iXv3|i4yq}Fc;d-@xB1FJc&|MD| zXJXSj4UIPXVeZT>P4Bx<^98Fa6N=v@fObv1W=^AF^PIBHY&wo{jUqgm^1jXe_sfb0 zWZ6a{0(cG+MfWoB-kI?S`9zvBdh`i-8NbmrwGj8uza4%(n_Nko#?tkhE6r^9$#64% zIAFRP9B8i&v%m`+eTSSyUjKgn&w2LI$Z7p+G51s+zi5Yp&tIbyMRUW9P~^#s=C@e< zG;%Qcuy()Jah6u^r=E0}SXS;Th+J&n=0+|Q1;HBQ+EL@91CXD78ExbatwMcDF?6CJ zzF%>z>_;Uu;vG8T?P+&lPf7l2>(}>1&PsJRpL!H!HJEtmtp~;>Pshx9`n#FBs@u`& zG*z(=3Z3GbbTRa`vMoRImSTTw4o=Xv(v_4@|LVnB56>ojAr(6Idv4~zHt$>p1?pA< zKJOMLszawBg;3)CnDPuW?0pjb^#iou6r#*%&{~~O$5i@{39j7@C1c~q&xV(>q9}Fi zD_e{Md@5mzZ=%1bhAeZtE9G(HzZVkbOfnqE5`4O6J}Q_{8l6lXRj8+YM3AjNW?Rdh zrfpD8VKK4XRkRo^lRD>aK1p%eGfDdkr?uyezW>XFrVaI0msgloSY1ffSVO{|3i2D~ zhZR29l~Ki4in#m56_&0oUuwRfQ?j>+MNAQ=sCu=)9PSf&ieR0@*(ZSuI4R!Y2l)XF z=m$HIIA~$k&Itxv{4k;KGvD^*)&6({i8jkd^^0MD;68se^#ju;M+x$=s4_4esew`` z9p^21c`OG`NOx3@mbmJn=l}$Z`zzk_+6$vdb*$9Fx7=%A7_G54wgT^;yy;h-&;MPr zHvVm37?#%a;*Vulc9vm0s+IdAA-hL27=Ls~wT5|V%#EdY_L{jXk~}i%I41Jt8?nR+ zmmAQe@-e5PqlDluD#eUj%xSl1YG03kFBAPZX?fiAVe8}LoHN}EC>V30r}_!e?n zVnJSMq5s{oCt>Xw#kAh^5!-fm*jkjip}X66B>C@`sz}{sM66xajYV<4AJ3$mXFBc_ z?LGda;n*O0ZdE+Lc@jHd^fl=QC3h-3kj!n=Rm35Om$FvgJ4sP^cJVv_*FPI(FX&Ol zE5O)7?Z1C{C3d~Ah<0NugA%cH{7^$`<>_M7FifTr7Zin^S@TIc(c_0{5@PFG+lA6u z|A>i5nU`{Wl@ns~>I}C^Tu)_1IC zAEiE)HmlMQQ{3y!dzWW6AvIA7OU_7sv8(!sWjm@UVgh@jV=H8S_s^5pJaI_BDFrps{83w|t<}1u>kLORYDk27k+c=t?S8^5RkobkmevmKM z^7=Gj6nQ8VV*02iMKjkwgG_4P_`U9VQmb89Cu2{RwO7%&@%E_5cWW|^_^fEAwK8*| z3LM`xs&Ld-n^%>ef0I8sPYc^)?=Z-_KN~U2Z0B;D_h?V=OUL`J@17en*^cvmWD4c zUZ$cfR({-rFnMQ6)$CY#-3L@r(qB9i8C)JNd8;aQFLSf33jBGN6+apTqX^5-QAsdL z`#?BhVId#cJ&Mkt)H|{~5@hc!n`LS_SD=<%{X~TIp;?=DSdj1h>Ss*d@cg#rFpMz| zUHNwUtRG4$7wVGQQXJ(x$)pkOAucPbGJKZ?hw?IUw2QBWP;(Re4`0TP94~XDIJ<^{ zVjbB8uRf(&L%@=rILWWsu#$pgqKDZf_p%7&9}u34kYGb^(nvXkc6S-9$BLhqhB5aC z1F0pRH22H+9@JQ&z9Qo)%VqANKkHf=yb*i(?8QyKCar=SQPIAdviG}(ORe$7qD&o( zWL1Y!uyBWoAzD#B1YfoWRrfC_I~$Voz;-pWjfU<1kcG&C3JeOPzMnMl#(FTN!MPrGaS^c*jf<5gCd}p84!z9rVdt@{@w$#oD`)!$T5{t4UtxRp3? zzP5kQz|3Q7ha+(QOKF{0^#`GZbyir(SgxaCk)wW|qXO@MtraNyK7`66>ijh_P2ije zDixX86MT{5q$n2StuF82?VXrrEDbe-32ob?CqpZ_syQ$NQjylUS$ zejsR#tNspe?Q8W96&TLa_0@;XVB$8HLk)Iux{q9YDr705L29Q-{ajr5ovqm!FSUwf z6aNgJr&1t~qOOQTMwOcn7{*}NGogF|U1XVS=GmmMZ(U5?SXjofMV~Y!GYavobw89x zY4~BNr*+b|o$21QG=Qkc2&rDJ=R4Ksp*z)tvz~K~dW9N7KrBoM{ zGar+E{1E%bA{qCscdogF=y++l{W}R?u0Y?LKd*<7zD_y@(o+_slJmT6wKo>ROWF2W z+1i@YuV}FU#~c#dy$=^&3P-V?ENfL^C2`5Pw$SVyJ zn8ig-Bn`-1yudufTMt$;QNpbr_KkN%gG_(c>rDS3lP8^_ zHl=H7ntGYqsx$qhAu#R+CC9+wVdMVix*{^|!qN((Ok(-`Ijp98@9lLdY8dqSI`84J z8%&oG4XXLutt~>hK?{iRx#AbSn3!L$WG-F$k;kzIxf!M{klOP}#=oN#vF?xTLvo%D zmV-m|8OuN=c|a`Ri39ufTGCNYC#dY*5m3nw91eoV{YoR@O=EMRN}ZtJ}t<*F{CBN{b*6j zeSY(pBe1kQgVT)0)c+05Sd>rByS0XzjGi~7zR-=!XAiT~`hJqqTe^%TvVUOxz^}SP z4O1YPT&GA(>5#OyAuAjFnQTmBR%$P8utptP#nD97Kr}JU6zHI5rJpdB5NsYXAvEh) zvir@v{k?9{REcJ(sZss?F}9hg@UtJv*}v7F*LtTC+oWnNG~P^}?l--7=(h22<-RNbdX#G3de$;17IJOOI%3&icPOB!lOLs}^v*J>OvMX^U+VRxhlCf9c&Xz_RZJd-9%~eL;6xaajsP*y|Q5cl+!>wTs*447wV%SLys zHjclg5yxdqUcIE^h4DLgDxx{+dnY5>iy^Zt{%bWG>2%T*a)QWwDMJZWPa1w_57?;8 zTtJGBeP0c&86-ZC&WmEjyjC-MYd%yTxrv2S_)A{hWYjyJgUi;I!Z4*#S+OoYHea10 zQlbwpvYm*Zf;u*+GKd|E;U`QzSM(*~kFA10~}9l`aIv#B^DbBD8o%rTsmdvfHTRk8L($r731#6Tb;~xZB6%pPD!j7Mk!y zm*2C|>2uS*!R^7OwF(Yy8kG>$E18*6pDTO|m11(835+#WYwO12_p#EjukwbN+{DjJ zLhFAj;^zkp3yPGqe zv(}@h1G0b4PHIo9n&J0YsJ%Ka{>)i<}!=vZE9x%kI6RoKq?nejGS z-QF5smAPqj=dQo`vgLLGY(zK|J$+$vIzE-0>xkavRMj+xhL)sXl*jD+=33C~&5x)s zHwyHlE<$v<53a^CJSo<{E|&6I4$a0si^+%Xo;$SAkK*VgF)WtL&B)}=IbSXzh`=`1I(m`z_{+({v!TF zm?IWN)-8;JD{s4~%3^ix<m)5qqW{W^zjUzE2P{ymg!~E$MEp<(m8X`w621izaigROjvc9(m;j4hk0cnrjDc zTswa2xt6;}GEbBF@+<5q-OpEe5%L7cG$RmsgO}`|>osX6e#<(WsNi!jj=M;NwRbUP znI^TPX$n$=Nwya4_PW!~zKz>vtJ8co_j^z@H7iWIYb}gh;)%~-(pN$r`2qSD839hX z1dAsz1UV!p?-OH`j34uusQ3EUV}~p0q`o)CenxLrKMVWDz zF|=dc_{Ub>(wn2JiIFv>1!3|93KU;si_QJb*>X14egrjJ3l6{$a`WTnN6r)>CY!rv? zX>bc43Hd~%TDp|LzD%P#>i*(?>(lZRTicqRbA#mU)_(uz$yLL-_vzA@?7`;vrsR5u zj4bXR_gf$JuNe?r*s*Sj=1XPO^D13y%$#6K6ATi^^sVwmv-}H&Q^5c-fO>dtz`9~9 zUg%BlXBFF%Z$xaghY=A-OBbh?B$3BW<-Rwgqn8RZa+*)6VZ4J~1?;J5T)!})(vW;v z^PJwiPFk#QcNz@w;}O#=U8Bu(`GD4J%-h|y7-K|UCzxD> zqR!3e6vK(oX&B_`d5Z?p((vX6_HVB!KfmC!q00KR{sC+CRRt{8R;!$=RhRm>%?SA| zPf1ORE4m|0pF|Sv=-!Bq1gTAqu;Po@Aa-mOS)tDR@GlkON~cYdasX6h>X)<~N7ZyR zJHA8e7xPMiv)7Y57E;7uTeFWPsnalz1RelzoTknfn_n=-r zgO3pK2-!N6fKUt&2;H`Kg z=CA7Ctq!|%z*@&&@Q|?hj#CoZ3o}&Lb-_R{jtLM)d%oxej-&oPNBuH7W z1?l_ziK(_lb_rdJMDITB)}2OnI(=I7{c31kN#1|Pr*VoW!p!NOR{u@I_#kwV59UxR zu~Cavq>xp|-ny}KVl=6CYYaO#E$S*t6@4!G!DBl@P!4)`~_S1x5EURs-G-J=~AP& z&A|tOon`Y>%I2(GeTBwmlZ*2n8{MxoeyD5w_yY^{)`%V%&*BZiUO(VD?k6~o98BR( z9On+}??ndc&AqeH2bBKs!dBHpe3x5r^b z@9kjbS#N*J{d^QU_{%|8OTB)GNxlcFvf8Ne(v_}HHYsAIW~)|`>b>~0=ap(gSP}g1 zDUc<-QhIs4Sm^)kMul=vs&(@s$>R9^WQwQ9AH!tNR%XqC@hCIP5hxj-(Y5zINl{e| z=1E}A!SoG+MN;7JF!a7FwPZI`^msui<#@>nlT&HGqNBpLovblw%U{}){$d)(c&i}S zs!-Ys6W4u2V&H`Q_z{|}XeBI3d~J3ufQ*I4AvTh~YVX zcowna1l`9II1pouZsXV0OLy!JHgjfX$Yf?XLSoVm*(7Q^4xxBw^(g znMaPhTXSj~30mJ_XaJ2|N_Jv(5+s4wwuXgjfVl29?%>0&|)mFzsiKqJkJlZ4To zStyi!aVh;HRnJl%2qSbAq-Za0{e%)q7<(&7_vv&BpvRNONLD6WMr-WpB)p-V^U1xY zdK^Mh&sBK%$*r+(sV?Difw56%;|i-0_X(Ka=;oR9(&%UMhVgKXcHm3K=OigFh9bss z<1qj1i{=0DAUieGzGtIfSmuDA-Dw01oX+R=(E(09-pERQnmlM7QeJp^JVIOe2c_W; z3e;rjEq?W9ZW5|t?9K4Jk9x~z)2^R649A?WOgi@uJ*nxC(#>O9koqlg^Gh8fXjAtd z|8k7lGiuq(Qk%`2NV`hf7rSlwKIyLPBy5eeii+*1nuS)_VJ6JE(a>4N{8Fj`_A5M- zlz-)Yjg`&4#jIQ(R3{sc+r;EUCbiK|hPnqG>B>cwkVfWYMQvh#ZAv!Gg`HkWHKFh1 zB~F9H3M*?WnOkodcy`&s6^kXX2f5^{2FAV@OI^gL0Z$XE660^OhiEye8h$s|mViA8 zo#|3H5VFO$m5itydkO7^Yfqc~VZ)c7Nc%Gie#o~LwlgOjW+qgGWsZ7JuRYJe??Y#L z%w75_H7&0rp*`9C9lDf(T5fT5hcNR);(HOpQ)8OWv2g>M1rC46IM4Y_-d`_c}ay6Wf&6(xrXGQ2j{jbqfHu#_JmL-&s^v2rA8z{Ils->X5 z&(2YEoW0O`j`PIK^h>_C%F(N!PtNp)?NKkek8II?6lbLWR9bs^*lNo6IQ_BwY-NUc zL?+2(hh(``&l7N?{wO9tz@kpLkNbzg?cp=W z^z6NR2}DYhEUkyz)4?Pe1A0hyBnP#F&V1acV4P6gyu6)Eoz1m6E{Ems<1dQ1MwIG` z=@lH=F9vJh90oBv=}6?Jpj`p_SHXnw5zK9Zgz`qYN8E2QLy#V+00K_OFpe9PG9MD! zVx>fUlE8{iVUbLu@-wVzS^9fc59@~Wv>EuLV@{P*3Zyz6+3V*B@r^`ghHK~M8pr1v zpX3Vcb0?qMX#IJ8`ugY6bKaX>wSsOMwXU^;pSSsHi&8!vA zpO8GxYE<-XeINDg#1GqkQn;kW@ww5s;UMRDVB3+6PU}+>?^ZK*f^z>d2w zK<~8v>3a&22JJo}-jKu%jHvff<29GU02a(1F1X<`|ec7d!nn( zD3$Do`ouU}zI82C=9qy3zStf^bAolNv)?Y=Zy23+_O6y%NB4MV_ITTe_Zy!U@iw52 z<#RWnNZpc>{)T#AacBKWr1~WQ{CO~T``O0ntFifyq4dd32h;|oELas0)+I?8?bA!0 zV$z44HV&Ly4xA5=Y9dfQ)Ur7B6q#I&k|T}C23=*pxfWmZZx~{ZD-`PoF%jYH6@5x5u-=GvtF5`Zf0xo3g zHt*Sc%-3$cc=M_Wx&!n6!N|j?=oIl$c>M`=VLE!=qhQw&T$PwN_66cMI_SqH2{Lq< zaj(TgIT*K9Z(}3Tnq4czPmDhi=zT2D*YUWt<>EEV!JQI)0I6jp@IR4!`xa&LmcRGV zJ>d9Q5m)cJST$i+38viRKM*U^?b=00hcN@%9I=vbSOmAg-krd>h*8N-kX-^y{y6vv zPSq0H8+x)-(IgaMWh?tp*fh`LKEOzHD<(7u4{o`-^7D(~n=(HT?Ykafq@ddoxVX_} z9XRwft#@%e-Zgx>=~dFw$>w1l(tv9omjWr6+>HzO`jiIreJW8U+l zZEGtPzf1qKA){f~)Z^`o2g{J*naTAfe%oEn+os8xo2HC~_xm;yTfZffv>BY7_kz%r zqCCzM$oga$-g^2@5Lp)-6Mpm&I14L;pr(l%eV=IsZ@SPi-Tgz~zN++>k<6b0lva&7 z$}Gdpf~9>G1yazTWxh`cO%Y_6LRJ{Ix+3qUxICpEkB%ZO*Gg2DxY&-IZj~r|XXT=s&%8l%{sHi1wPJuAHEd+B2rb zH3$(|C6da7NuZ*lN`@5D;HTM-5y>a|Y2if6fvxm9im11N7#PTZkl^>GD=lUDqmQ<> zuL_{IUZHgH*deEv(%c2_Bpejqo2V$pmVS@96-8aRKIYhIqYV=OsmWj#9A*4dJeeXa z5<4E|8VeO9;F%vv6_YZmDlz)v9`cZ>Kp?!n6xjv~)*DM3aT;2qdZ+o5 z7}yJ1{nc)Fy0WG~cCmPVE`klF4E~>)1p45wClPN^u#P^(H=21P?e^rlO8bSDghGDb zAg@z|!ro@`7)h71JiW=m2k931jyBZa>g~y8iHG}+%{EA~Tg}AI<6gcP@gOhpNeaJmCNr`shzO^|TbqhR=IHmoY6 zHK4TM#~8R|W_o0}ok{BYIoWNq_P48ymXK=vdSFtsataE~Kv7@y^0kYWLucT9i31c~ zG2advx#N|5nxj`qc?Lw}7dXQsej<_VCiR+a*Ht{|${n9)%q_i~-`+=tjt_dV1TMie zvGh!98)u!fB+Tnv?TRIK2ddrG0;ZUgm%}g)&?XWl7iv?rJK~t06xTl?=PpkPHA(+z?v_ z(Lq4lb&v)`kqP__7BYhv3vGfpBgU?pAd`qvm8$VhhzX(v!ew!QmIII`1jWNaNFbs{ zq^fWhVvZ;h0q_5Wm?PwP{e-+kP;LB#EZ)iK*@SG}m2y<>LVo>I)Nu$wh5luT7Zacc zjrZUtOq@X25S-9cNIeu$%Yl+CX#=L^0}nvIYB!n0L^hJYKQ z(g!Rx1BMXhp#E!4ra7R70$1Ax1r*Z-gg_n(pb)|T(*l@5K}=ZHZU^M!VEsK!^qx@y zaheERK7ta1v0i}qe|0$a0<;jE3f=(e-ON_LK*e3b43!_Cju?FH2e2cY0%pR1=D!eV z=@0b(SF7PbxRaF=AXuPr03d#+z}EmE7PxDQ2LYN81oe9=2^&zg22Sl54q$_1?*Lpd zvz1;aNi|9cOEcwHwCl+=)X(izvWzDQae1E{*(bU z2u_-EKoh~~Q4SFNqwaS=~Y%4BVW%)%JM+utQK`4+8mjxmh<1Fx?rkI`WSZnxgl6sna=?)bVhM(DhtaG7XbJ0g;rKWVFvJ_;;Qh@^EKqkHO8ak+ z=2rj*gqonz8Ze5`iEbT8yVI%d7m#?T6Cx0Awg8cT51>Hqthzk_D$(wm4HtmS-5m(! z`k(cxcMa^^rJp=9RO0S75`_WnLP*iM2i>}xQ5p-{ikJ}t8+up2W{C~8KoIp~LpAO) zjt(DMiv=}cnF1Fnp^C5)FFl+8d?sGZJI+2PY#h>XwiBIx!SL0=J${O#>@kD~%W%Y1 zJit`dBDS(xHS@W;JXV`HwQ2KN(3?2QxVTgE>9D%FNIAT4k&T0cYrp=oknRRLmW1x8 zY8naUkTF$)r`i~=)tuZ)b~0F2MzGa2xdFC~MAnnEVAwZF*2ybStznjexi@*6PBv>mS%xc$pireYm~zA&>-2vK6$rJ8}xLvl6qg%u0Q6m z@D=O{6cTxdjp^qRiJKikxrr;K$2ULnqj7SHzRAdTD#!84l&j`u^X~5_QSVc20Z-gJR{h zu(D_=o_eLw;j0j&q1qh!KOl)%A`(S*=at9qam*+1@R*OBE=M^`_OruXCi5HHFC46>Qmk1McAf~D>=W_e3+j%2&y@^N+i7?rWEb=6 zLSa1$WgGIE9=FI;Nx`Mf!d(vEt)^wGpzVjKy^B3opy~d^6#tKp(N^e_H`x~wRE6O^ zEcwQlg1@TO2lVjXyjD5H+HB%QH63HZA#0C>bqp}o3+!YOW0k#Exea1Iw9-tKruf~- z5{{ADwYAz2{cQS=ZG8S(N&;E~OBZG~_L2x6&_c2?F zAlrF*p~j@I9YyRni6a9|NP_e2dY{|PrNHbL7K38lXl4l-cP>&n4A@Os2Az8CMy^& z8QArurM4`KGR->@E8&-OO$TW_59u?h@?m1t5UL4(nww@VbjHeG_Mc+y1RjrPG8!xC8+;3yLLIt>q`=>bd(vb!G0_CcAvUv@@-w9+lKnfjKgo+81dO7J>}{o z8WZspOF_I|U6^tKub>m3nIDB7J!>oAVC{IoebR{EW{y20v;3RRx#+pLMr(zVv~fx~ z?6gUphk#E5MGtb@Ekd7ZEW$7A{=*1(rOcX*Kl%(B)7d>8q~vE};DG$(>zQ|(X}OSG zdAQeyhr@(_h6M33eeQD%l5W@eeH_|r4!J+r#=Q4ZD)OO??h8V(Q>kSN?=QbmRN3Su zoCM7HY6CP;QS83^vxJt>^}ojJZNUAqR05M#ZB$i`$v?gr_@uMxD#)8F&pA&9U1lwS@G6CRM;8^05@-w?y5M#`tgjVQ4A zHsPD1r!NfC-4~edRp1xeO35O3SEEBxO`}Q+hwP~?_Dl*}^Ab0kET4Q(THgkn*w+QG zE_cQP)kcEoE4oW~>|`Hf8jhG6HR`vumHklxkoyzAR#N)MAX5Nab}qRF*#ryEvpdV8 zU4+9uEu9LB4=~430{AgA6d!*t&naMI{?Of%6}W{xL?+9kb6}RQ`fG1^l&H8syU^^M z^Y3n`o4-ja2o(wGCkg1!05wHC%~lzpmv@ioB_`SsUgNNW^J$$z5xjQ&)7XBXrBpTqz z@XtHMfB8xd&b>L-0ZLMmTlSKd@>e+_KyM(hz~|KOtn`&R?3P zt$$fLLGva!GO+hALIgH9!Tm6JbcgsI!nuT-|8kvzj?GYQDAyST>_34#0-Jw8=|Pef zC=Rf52}ZO)Y3{tE-vW1o-0#1LCv+DH0K;w}bf9xP+zZ03@VE#=0MMWnY6QTC>RX}4 zz)Jw6Y=asCWXPcJ-|Gb#INJsvSA75qw?nO@sEV4K4{tpH(^^Bzz1oLp(J2T7xV!T`48OG1yuqr{^{iC z!MB_K`EVNbZa9s#(H$$1;eX(=zwo^I9UNf>P=KmsaM^f0@VFLP+`$Isa9iLiaRV5Z z{~}l*LQ{D9;)4DYP;~I92QKOSe+l5$y#U5v{tpWxx&CY1QZIa#bnm|elptjvR1&yA zbZh`UpT8gzNbU_V-RaNK4;TOD%^mFA4^;tPz`&M%s5&$o27uyzaIYck)E+k{Ls04_(thY$fV8iL#elJ6P_n<S zU)GOvK*1kSec&PoO!#|k`3kB{!M}Nn$%EgV;L8sWvaQ7i~f-Z}28QI;%PC0dC$rB)TJ(J1Ys`zTKHldX-uImIp68sG!{_2W5B5$B2p(o|svG9^x_G-AIqHAM7u_gF zeS_?CQymoyNjx%$bWWzi>jEPy=_QNwz{6oL2&nP$zDcT+S|<7FB-Z9B)=a_Km|x;9ALzWq zS&XUZN&xekY1og1FW?P6Kpp|*3;vz(;R?!T6s;{{=J9VfK3nft?(p~JwUHu)4(sq{sj5PTPt#B(aaIM!YG_z_lGef-Vx?_tox@)7gWNes<&xtNkIqr0#5Oj@v5wmKT%0W0NCT;k z+mAFF?GA^@+2rK0$6#J8PNr1pEUEU|8xC_tEgoIP^OTo%p^a3IWA;WTm$U;@hy!qg10X4`PI)w- zgnkW_FJgX01GjK=;u7)Cu7S9Cg6+6pcQE7L-O>YFF?7n;Z>a;wf*3J69vHx+Q~rd$ z01dQ32sylSatkDLcmcKa19WjXg51bT8XQs47krEqpC$MkL>AISWwDTjt;YcDKPLRA zJpVDVX;VNYMIdY3;$sXXZNbxaLS(@~djk(y&^Hf5|Bpe{mIP8Q0m=U_!=u;IFfayJ zCoa%73UtKRi6ggrdrcnq!A=gzzhW2k70Lga1*Uk7RMoS<68}>iI@5s>KtWnC+UrIr zR|^&nwqfX0Jg#FR~<{Hgkeqb_Dun|Ske5A-3BJIrWBKoA?8Sxc zj1bY)f=bJ?p|FbWZ@XVzt1L8Xc5R1keQcibbMAd&L!HWeEl~EEDO+ToUV_f}s)oE8 zV>@oPH~KxBj#b>A^CQ2^gq|gPA-bl-46m?w_l90<0i8pB1s3&DQZ1tznus!IcGHf4 zG8N~P>=R*P_(@)D&&Pq-GabI>iB-n$H5aL2cWg?iIkU9O`SaZ33x)aOPU=$U?A=e8 ziXkI?vzjvg(1BMyCM!D3qFK!hYVlvzNpA_fq6PP@?wFSGABBmjS-6bT@%;YtpxB+g zJd={I=Stu434s;M8Fi|4ViyiW*W=IvEtBXhSrb$8S8xu7DiicpIRlM1>Iq4|BZ!`S z^+_~EPmTa&d~UywA^kF@_`JPZ&|X1TxpGdm zU?XCxVR07#pZ1Vtd*v56(5#!V`}wCIKjNC` zXxoFY+}`{?I@(y-%-gs4TledmF&2@Vo%~_Treh-KFOxQlY*)Ea%e!KX+)>-SCgfxlbp9@2AnEiHW?UOQWWvez=e(HY(aCUAKLiRlal&R`>+u@K|;J;9eY}rvTuf zE@FM;^kOP&rM3^pIGRcE^GRq{TlN*Ge&fi?7y#dNb_k*`^eVT+W$D!*4J+RW{Nlby zS;a6U7QSZ^&2ZO5`|B_EcR7@_(&vv}x}MDaeDNlJR+-B2hkSJWco5HrSZ%bv`e+J{ zt#CWvd=!FL7noOn`Op&sQzE8xoy2iAm%?OJl-qC@Rjqz{f6sj9&f0!2k5|pDrMhh+ zkIjt_K4?pzAlI5DtFKn(7nDmw1~9h|X>l%X(=!U~Yyg`9kD29EH!7Q#i}ycI4o>hb4OldT7YrqFBbK z!R~h-ljME561)gJx-)Fldvre!HJf}1XHW4RLwo1Rx8e5AdHL<{TeEKsF$AkK#%UJ` z1KOVAw6^cyjjHzEf86o4-q^9!z=E^{t2Hvb3T1NYJEK2Q;S&csS0lqrxId;`q))NQgG4|yX|`_I+Z|8-uRnR+u7w6doKGCiI<7<1d~<=3FYz<-s$}n z63(e3tq;8(i0;zTqxwr*SKg(%BmiXZJ2Jp4N0}wiXBxcT_L41jz4F0aV{%)S`Z#9x z{nqxaLPGB^-+Kb*Dm8o3^x`d9Q3kSmq-SlHGhnR;$e_XaI0Qd zl3@98kr&(;JeJ^c70l?$I}vO98#H#S^8@jR!01=l2fk9l4{!?gm8=5J`l8iSKCxN* zKag(uvhvEPRp-9EMTVch|J|T-#dCVmI7+yKx98gwM!4?!f+>nkEj96-`$r5qesh~; znt)d+)}`{Jwkqw@(!-x$pG#wxxNl<7Grj+S-kt7Q6l;v1h&4#)Xv=MD9VA~`mbyAc z?W>W?+FPJF8henDRQ#JV$w@nr`^BO&<>W@q7%X3e@IDOkQ zE5c$=R@ze{lL{C-;B`5u7tNjSS!3(;`nhm{Dxv$PrXSljR%k>(Kh`d`(7GKfIsyK? zLCGP1ol6YW)+W!2+`80xuU!VSOG9?VQaa%FQt3Vey0T`mYlH}oWJ3T2rfBs8!mLq` z+a45T8B<+e&cT_x_$Ek6>obL)8HN<2OYKy0-nxIZPPcOBceipJCg6$xSifSRA{~~U z^D)rKBxYL;T+uGKmuJxaZuY2BCdrgAIqk`N4(w|<%YEEFlO~^qsf38EgnuE-b zg$zrLaDN+m!b6MnEe(?NGkH-evm`|$*{@5J?A_8E-&e?%D2+u@U)!mti!Qo4`xfEo zO-kf{vkPV1p`3Uvy`BFit{Zq*tihb6ky755H^dk$RfX)YP z$C(eVMoVF<^}ghkbePWy47u)%;?OxfE9;jUb%SM_rMaYxm7l)lOm+SfZ_=o^ru)E% z)lL57Qdn~1n#Au37Qo|WHIKe| zI{a?+EOe|a^5*L1O0{;rV=IX7mOsXCg{kHM^fB0 zwv9m!BcE$uJUp`g?x&(%94feG+>9-`trQy>FM33>Y-{99=CO#A$l|SLZ{LRMpL3V% zD<>Wfq5@B)9r5SJzZPzHm50NL_X?|(twIvbXr^;0aDF&Xy7cr5STbGNQi<)%zBq}r zbM1Y~hSLcqj5IEJ%;lO?4or{;P&r2vQ1}EA>1=Xza4DLH-d>t+4sm52e3+RrU*w%j z`#faN_HB-OkoU}0#>iYnpiaRDhNecj8R0>PDlU*zKz@JvmCPu&DY;!+R#>?ZL zNqw=aEspMCBu(cpxkKBiKVL8AAMV4>=3sznn9|(GDYw%20l!qO)Q0H~_s37WE`^aU z_gU^KaX%h8T5qT~GbsH-PCJ>KA1`QTpg$PnzNK&NaXu}a2fqM!^+=hmwurk5?h`&_ zOlLBfm~HkrxV0eXo5Q~{1SdVOF4HJLQ*#F2%=bNJkwP0NXF$q)Kbk(5y`p)q$qa@?ku zoq`DK1ReD7rnUK;^WaRT%LR*vBJ&u-m2Zhp@;?7)MEl#29+_}PE|Jpzv$@F4kn(6X zyZzPYM=yGg;b8$kMcfV1aDKi4{?u3qHksBfLMfl%Pe1;lQ&qsgTvGjB%z%f2BF=?^ zqN)I*lAv7wePo}2N>&itt$VdFB51D}MuMBirelfNVOm~4A=(VYM)2>LR#i|2ER!7I zVuk2ALCPEIq8We#j&(=J^54&@7mhuZOoBE6HwyX(23R!7BgQ*;Pvn`IL!;T`Gfn07 z`6$FSH-9A!w=_@>T<=)$DeZw<~nb@*rkb^EEHEAc~fFqSh_+j3M;nYX&Oe8EF@X9BF=G zQ7L?(nautVd@EVp;o@7NJPbj4BWkX_#0Sx@WZp--Vc>dBnEy^Qh{I$)T5t{L%=j|; z(R0%LP`GArzKK8vrTPTL+^qtCBvUhh~}Z7PJn3RJ{PJz#bKSifSDO0A0j^yF?#8?G@5e$g@hea6An?#ikIc*HZD5TpD4%JTE@i$OXG#QnkZ_zT>%9zc{2B&GQ!#ont#C#mC0W zl$m5hci2T~U*m}ybQ>Yux|Nh3tnah5#*O#W6+}EPO1~c7BgHg{Jk;%QXlHDgIzRo3ozP0YL z`OVe9@m=6LllVpx=W1by*INw&&%oZ zD5pc(Om|i*r{f~ZYCo|IK|NwTVDe&z^fLpA&=Gqh1+J#0_%~rPB>1Ri8|v0n^9TW31_m}=yo>;Au-{+I6^Fjbm^SevZ%!o!GcMg3x^f^0KfU%U%v$?jAA z>3u{|bZPeN7Ry~BiWI-R7`y;~bz|)4-H-74qCdH@F_z5kG~CMJp=BSVv&ej`gVOZC zo_n^%X{~!&Qx}wVh8d>{)lQ=UTn=kN2d6!%s2qVsjCp*4WC}xc?{U5|8d(l} zcd3w#_bZJx{z$Yzr4cGW97qZ6o{?ERryc40LOd8DzB@2}`lJe}9S zc>;P&WPfg6`smD;)tePv6fP#W1SSN+Ax)L?H7kSJeD|+~9xg?0F8QhYNfyxZ)bUdH zPAR|cnSaU)&24MVKk}NMNmlZFbtDdA_LBuE1cb~Krt9|0_OTZEqIkSR;<4}Yp5Knd z{KTSuPi#GSMVM9T34|l>$07Ee>T9mM6#IKqCD$hbcHXvvJ1S#koM!j^a^vuc;q`om zabz~9pcs?rb(BZq4DyVR1SpgO z&=LvSDsc}KNbm`@Q-5A`9$NID5a6Z>d73Z&u3>61FqvP<v{<7>c|k+`K5RQRANkeZ>dEH6TgW7tCU9A7BQyL#)bUOX+<_sl*1 zk}-X5^zg>;b^mmW=uhOBE|a(0xNWsWuxliL_cZx)KY6<+sh84e`$E>zW__pmMd0ap zV3mQ#VRqo|BP*Tyzdsh|(q9Z^YdZC%Y8M>MQNr(@n>%HAmOd}Enc$eQP$_~B^(Pyq zxpIExa7vc1vT~x*%bLnRBS!r4(=bFYixKm>S{KXfl+Sg zoCMe^n+EU491StdJ*a5Ms_O4g{c7`J2co(p)>WoRju}0YGY2{8O8IR>JfDa900gW| zA-~hxnKD1WPN{R=3RTvRe={QNaWOm>Ca_#7x7pphW<-D4y~54?P20i_&d);``AtUT zaMfE?zfwZWRID8VLNq!kIrE4>g9<1DOUEM_E{WkVG9EF;9IM?)e|ak{GPK@ z_BkxhpdYQd+CGmtjAqk#tAzs8oHu*9xd}U^ax=EGGy=K*r2Kp&jGBel>5H3{;PbevGY*aS-w0 zTkqk1cW4&fNVw&YqEKCx#5z>Uj~04C7fMuP}MkTDN-5G8MTLQqnF+EBgUH ztdQ^SWNc-ToLg2ysBk0WEa#klJgr!s$`p&HC#)R%av9&?%XI?@E-E+}VDvEd$Gs_rz$|`vy)< z*=exg5E1DYv57}g&9AU*-&Rk3Pu^ZYJX!%3ar_+m3CnrZXW|KOgARPf-t_+curd0q zxkOEEZS~iftk*|^uJZgBByNh_e>JGzt!_Fw{~RUxDB|hc6Lm{s!%wh+>^6#*-p92N z&lc9FT>gA*Rb9k#m$e^OWQa?(nX&p%MX+X}Q7)-EL-iJ)-1PEnu7ES~;B|W;c5kZn z>ZfgwEjN0ZPZUwe;d6XkcXC>Y87Dr)%G%?y;(d>+#xmIC4$9`~uLX1GChz!@JvExG z7Q83p6m+{>+h(c%&X@BLJo;lI%Mapet&fXEb7Md4w^vlaY=O6%y4Cod{Q-?W#DuJq z7{j~O7S`I+$y7}%ywZ3?z9R>1 zY3{>|p$tu@dKcrb@aM`}uT|>{4-aN0n&20n#j|hGY!^R>AJ-6%y*8xQt^G1iJ8DhP z=;Cs+G8-1XS=SJHyv?Lqr@n-WVthksWoJ%3(+4G_{TP_B!9t1R zsd+LV;V0os1&OcSdV4LT5!V!>cu84j7GprIrTy#9DW?{dMd17?rrkl^D6t2H z$|^=ep6)O{kYRj)_eH9oqx+kOht%R)@VPzy|c|ckNv=@T^nFVfBvXe0sVQ0@ptxj zY9-MnQ1~kSAjR7+L|+FbJpJiQh!Ph*+p?4|1pb{^Vr}xpH1+0sn+PoSq=1JAv zI~y0Quc~)6*eMjNleg2(5bO=(n9CYc!k#nzrnxB+QS{8Ai|O-u)a62^b#dNYnNv;F zZ@#cS^#-g5E%?||!wMAA#x#{UE4n)oT~lNg7(GW7eZNFX2&9a*iUgLDayL7$HI|>n z*3zIm%gn?792djA4JZS?OPH}sK}8u~D4F@Wj5@MLLgaY3^qWuBKE9NK3|e~dW^d`I z+hBz~nWGJfAfGyX+eX11ce>#BcOf|KZ}E^8i=FFgVZ-=+sUj_f^Uo5G1-}it-+nKRd!B~MxV))7X5V}Q?0oGHS@xXkB z_xx&RzK`S;>~|6&?v$1cQfhW=#TORe&{;SmK85j3gjl)qI%tOb^H|>Yi>dyI+a>d) zQJi7lA0ASDd!w5&+>4q0Fzy-CP&eCEgrf!KJs!EU_VoR;j&I++vX2ZMet=eKKS!_T5YEq|1!M3xDup9X&|p zk*kB-hSP>yGudYI-fowwSh*2n;>Y&{X#QvYqB3w|$&^~Mm$;G5vFY6&0z5HgOFI|a=I*HWxL|BPG>V#+dogO|r|bQM+xns`<5=|Fk8&g=GT&ct z#4dXIM-s&2MUp3@JF`pKG+AKN#<)x#pAFjTS`CoCBQnaYH!-vz`p~UwUwD^u69YRu zPbFBGS>xAp1<$O-v>`Hr3ZZVC$t(UxepLOraBC`U+mvE`j|a2t=QPQSu&0$+_qg+S zBOT|u6{HL-hA?_u2j|mZt0YNS__IZ4YGgAil^mUwT~lbe*T5)A6lEL(gAXZ1NrY zO!zDFhb+qum|=26sPscHHMe1H39CGb=5v`hFICoLhX0-TqOU z+(NfzAx2ZbWOTHjuKtC?!dzz4TtbFY{&sB;zT7F1fkm>_=3*|>5Sv)iwitTH@1-Y} zaD#W}s_|bs4$Lzn7RMoV&Ci$HvvZ61mrrp&4>#?6I7@ zEUfCt^Y($=y1BG#w8iUQ!u^ujvutN8A`5sd8_u}FlcD%6q95^l5L!F5U7pU+pdPSdgWZx_aC|FZg(g z==A(hBb&soGF>i{3)W?x_eZgPQakp7D~i(bg=%=He_|!|Ao`W}x%T*2v&cR0Re$hX zUM`K&V_4>!_ZYEF=FwrE`d+X9uDNwaP}7#g2t6|B7q3SjS?i;_2KNWpMEA zWt)F=bH?y}%Of1@i&o0r)K~7iQ^^DUvG;jCVGVCRnDs?f`$2w8^^G4%)1a+azGz?8~^GXsb4%~>bOyNf!52UBUgIX2&_6< z3M%@1xV?jsYT;Dg*p9{&e#EZo20pw^WeV*cYlMmZAiw; zU3X4xRLZ7RvpQb0>$c3XS2b&|{F+JYT;`xrCbEpn4((d3Hc=Q)>@>Tp%@vnEr}XA6 z4i|gfm}H%#?(*f!Ig%MP*!m(aCq@+-Nb*M7{KIR=Z^pRgH85l{d`gey7IF_Be~HOz z$5j8*uX}JQfPc23PM1=W`6%Um=db=8V_&`K(Z~Gct<&1S*2tzpO0tdV4NCb`##bo5 zV9OVliN3RppAX&^_}!zO-_Q6GZa+PxX+DBoZe>+Bd?Fx}z#3lOYNMX`He%Dz3|;Gk zWW2k9Nov}z%Adbgcb|LDXnD<$!!0xnp|x$mX#IF0>FwQPbL)t_@edI=-jwBhedp^! zfAvi!Yc6#MIA%`**IY$4a+FM_hr_R6ZmP;VV!{?G-u(==-&-rQJ>qwVC%FRmcrlwE z$ZGIJKMLPd^*vHJ-;ud0e&;4G(jQ+IZ{XvZ|9Ow;N$if&IgWGKoEY~rPPnZaPowmP zcO79$Y$JhO^WjGI`@NVrBlg5f;Z`QzkZ(jL{;K(N_C1F~Y_C3ynP5vS`Fw}B3K%>M z;`g#a*-Dxo{UmVwc}FrrTu3z9yut3cVahdkdk%cG^~Y#Iy{dHOOPMFX3&C@?F_tHd zowf$DTm~9b${P|HqIlLOeZ%ld=8%i3s|)6n$@pm*@xQ~U&+Zk+J$wc~dueS|oToT9 zj00Q5Ao~SpW?DqdPGvt8Bn> zhtDvi%AlG`eQJ)fPB+7qYPOO=$k(-wa;fkO12gr|=K27BN|ikot@zT{tAo+6io@-E zXvxfhu2nC{(d9#bE_3R!!{sTx^1E*x2keK$;@s{~K z(beM34xpLpP|IcPV21=e39%)>0W5RV;!@w4sC+aV{-P=OM($VEr)4-dd+a65^g`u# z&lR;99^1mxzB;opD(!vraWAE+28CS;(SuzSRt#Oi=)V}O$aNs+0o=$taa~p82#4aE@@u4 zwE4E>#dKJF0H^lql*O>cyj}pfeEKm;J+Qem!hAMXDd#!PlB!lHoMU#*A1PTd+!krH~yC2#0~spJfpurA~}p^uDn z`^YXlc}$uxIm9<&`grg_G0Ntb(c#$C_{(KKyxAUy%F@x75sW^2iR#BDIl{p-+blR`KlaGqv;GlZ zo%k@(OP!Bu)#mZr!_`HaMRtMP&uZRAY-9AB71+`km?b}-%n2md{Hkf98#3HSpZtUI z*nf1nd2W5QmaDMndpGQLfyUSSzN3=`Jf5WHKa;BVA{7ekw6+Z4f2Vp@`RM4>MGQ1V z4MypY4F>DUN!D7uYai+_85S(rr73y78W}sT^5nG*ZaYJfJh)y}d|20hv8A45`^dY# za;lPYEneylcs`Op`teWVtHeL{Ppuy1eoY&pHw)%>kPu7Q@{}xfQcG!Oza8|lVhPEy~QTwj*S>gJZ8PSjf-5S>y?IS-@pAO;9*=yT7 ziYUlK*Am-PN}TkIfH4h1{|Ly*2|4UI3}8rPa+bI z>D+?a6I?Oiuh;rqib2ML>A*f=u$*W~>mAAkVEE%3tf@!(*CIJ}nHnAA>_O|3+-%h9 z#^3C+LiT2|T*i4MxX`0EEHc~LM-!X&k#^ynbjr_AQq$$h>aFyW(^*Z7A9PI>m^QO5 z+;%^eJl9ek42Q3hDd?<>kCWPN8%KR}w$#JGuXao-xa?1K9Vn`H;V4RJTCAA6pfk{( z@_styjh@WTmF*s-K9TKlYCYfZT{^T%#>iuD{gxy$cZL_4R?V?K z^IQ)vw7{sZYU#nN2(>=pVcnU%uLHvT<_dY@jP!owjNcc2pFPPw$E5DeAq(95-jNYb zW7J_>kfmSon{+3W@hNQL2Uf>;Ue~+ARO8aheqQd7*kRxC9(hM?&2&1NTY|cTcc>Zp z9^ki}k(R)xEL+fLp1AY42sdruk_~@)O@5kwL~buIV!aA~n79}r)5prn=-?6+b`+JK ze`KQ9G+ZJRE+WNhFkFF+IcFvyzS1~%rK56GEVMQN{GyX|L`@<31yuw z*2jOpx{-g7iYA^AZCs0UDF~$D&)jn`jxSWy5_X+kl`Fez z?}kO&M)_uTMY*KVo+b;i-o?GdTX_@~D2Xl}_-Co0uCMU?g_c)g*!|T6r{Vbdskk(^ z?R~%llv~?*_3_cd4S1 z_2o6;6ZbQxFXQOww5Q<8Q*hgenTlJ_g$;hV1^yV(JO2CK?qj0pS%>$uxGU^0!H?e@ z2C}aQC+E)}*Pe%66+2h{5gZ-gr{QF)DOJrSl}rBOStI%A$3@)xM z*UOdse#`U>W;dC@#TeG`QZVuAy*5cF|If38OHNa7;;@h_-?s`6q=Ry3#9t}4wLXYn z5(v_|omx@ixEcG6dhm9A8yGqJ{eyU5fX24=fwbQM@!Hnf51e|YS$q`xAlMrL71My| zIr1jBSlQ}^`O%R108jA6r;{y{?#sI?KHEP2^~^H--HVGa7fVWu{8@FYo)FcFvIoj^ z#QfSIO=-Dmk$lc;_k&|4u=1OgS}iY=a)j%0Q&aSvGP5GCH1>cvBUP$rpC$?7?i@4` ztk}sF$@c#xzQ1#aApOR;6`<^ca3;ar+(cSTJ)=b(X@1T0#m-YBI1S-mu zb{#?{Sc4R0l5d&4A`|6`doJB&atX7(KW9v3Tf{UyPmh!V=TTHjRz0=xv{2;<;b3^VoJ3Af8+eD7hzWpfd|VO0}Y&LnyT zSqj6Y+MZC^G@5$AcJn^FJw6}6#Gy$4b%kAyZz`!q!I~*nZu?h>$tA&Sq&wyNK6?#Q zM1A>6^3(Y1uVj+#n5UxGUy>ajrZ)U$VBeXpyx6Gwfw6hY1t6vSahk{DD0)hRx>DC_PTf7 zjhZAvNMPSRF9pXKy(Le`Dsb~$`C|JxG*=<}#Cmi-{5AP%AHD3acIS0R zR1RIoBC{5rN8-B0>bm^aIH_a$x2yE4MbZY04t5VX#=fZaQ6ys|NkuP)>K+PH9g5ic%bXUo={guQ^K(vndQ7Mt`La)^^petP7Rr#DT9a|=jft#Lry&mwe~;OIg?4== zBO%D}=QceG${kgRrVyZpB4-fi=#eKe8r}ok$OH2sHLzvmF@4)wSO$PRF;CP0(?UWv z4X_5}RR-u@Gi(~!hSdVIzvip*YJrWTBTJgyu$RaZgpkDrt@Xp2K!RDVs?P&3e>_lP zTC0j{4rYRmdwu3(=!2By_2Cd`p$WVV84!WkP}2{X5K{E{57;YYx0Wlg1>{|eD*0{L z76>LI4(|*8gl*hhB49j(p@T?<>w6QB{0U4D$rW${s|TTaRS*-RD+DN^s~Uu@w&$?N zNF^)JVQgg%Yqp zc0oo3h@gT#h-(Ya=z!ZdO4u?2uR%sqovL|8Acr4hK$L>D06y@#2dLo%(1mtwH#U?3 z2WX(aXoODZuK*mVK^F)^%2dz;Yyf1b)&OuuL$dLj0s|1eKk$zwY%MTc=)M{71Pvk6 z5)Ep40f<25W*+03F1PFet-m0 z2PS_Y0U0P&^?`s6>_!J#gbqWs2wIzUgw=_`z%8g@2qc75q5%w~hp#WeKtG!h#vvNH z{u@$clp-K92Gx;CA)e0& zg6na4`x)RtQdX4}00TGj0}6rOn@c=Mmr-^i{Q0&5phtF;Q2}TmIe%9GL^t$!UjeZj zWfiLs(RrP&^;JOJjcX7w$p!h;0vSkd<~l$hSqP{D%)uXsOxvvk)=-fG$D0BA8|%+n zfTu7p5|PSMZ2;>3n|-(t!8ZW2%BvG-ys=RH8}J>;kMkXHyWtP&1%z(q7K8ye{V@yx z)}R@pzsLcg;3g2oh5?ovwarElY8%n&RE>=QG#LMd{k?0&@gbfWpa5yr!VFM)6Z>&X z0OtSb)vyAjB6ToW1zsba0`;!}!$|1UI*@wP;o~jf!%c@szg}(wV*ia@aSOuB*gL>& z$Y%#&LUQKp0A4o+-Pr>uktIm#Cop!C7j(Y>tN&HC<`+>ja7^zyue63N^>2Hp0p)pvPlTelMvQ?U{=-){xd$DE!`Bp1`##BUtOJ~c>k>`Tzz%80?n9G@%- z95nau)u?_MFnDj=ZJsWD_oVl&&IEG`dNGb-;0rh-`01 zy5kkxk-5W_RR3XCFv!Vf+N2z>m=LO^Atg4*0^?+RImJ7npD*A;W8v^?yeIWD^D`c0 ze%+yGB=;m)Io3Nz^j^g`{8Q~Dg(Ggv6WWjWATjiw#x(U-`*&C& zyWNjuxR#Q|h^CAzgVyYAV?LRElh^2N;3w`Ij%O1NtE~Q{V^x#{783i_kern{%}*+m zk$vP*7B|gw7u;hMh&|HnXTGya8A$aaNQ>lF`-jHO^wu(G@=>9QU!AKf=c(*{Wi^NX z)^MRr&E=LXT3@d(R?T1RUk21m^_bu%t^MV48SE1ICdTN<8Y(82QQo7t&TGQE`^PS$ zPbZ8zul}}|pm;P{_iI1BsdQA~Ckwy*V_ZX7845I(CipN-kDuOi3=Q6^tm2G+{Z(B| zR_+(24w;gCVggA5DyJVrPL4;|mgqG9L1G+!a&iww-AoZ56I43;$<&yJJ9n_#h`S1{ zV==1n37!bIfOB){p+wjn-ZVaZS}PnA{5^ZlT(jO(z@yJM)cBlSi2ehQcRXfy6jMdI zP2-@}eR!?*d{ols@l9P8>>R%@F+uY}vgu|S!*|P`31%feF|1VF?tLZYU`M%Iyg1AO zPg0xFj*~EMef+0=?ajXHuWiQVFf%<&r=CLYfxP1dLh@t`p&oNI;^gn0J|UUd3p0$K zB=68%8Bp{hD#uKCU!sU@h8jL`*0VLCSWR=iH*_{R)7cQ|Rj}JrUENC%E=E~b{{?vvM z7EaSU^eu5|jbUo>sBb|0S%E0?waSqVPnllpeX%;2kgiDeDizgmezhQmv8?CX z>8|5N(BZ7syECdW>&m`Ra><0MpGBS>N$C8zLUd9zY9Hn9!pttdec6!ho>D3esSR9- z-$3cXQs@KuMTgu^edAX6q?5^BL{CVc*6b?K6Bp*;ceR;$=Y@Y@obfa!kXIaG$6*w5 zOi$J)DA~3-5gj&8^KW|p`EgnH^Am_j@PXw!Hnc21^yPwGI>wb3dl>`X#6P#o~YtCGIJ zsj$l#KfMSjU%>~6zuvp!`b~<>KMCC;lW^D_lkZay=3w!i)^26vrve)&(T5Im`oV7l zy+&xp56=DkqOxnHs8+6M>+8-AT9SI2@)K>k5_i*Y2iRW>oR<{|^WG`C^2hC%gQIMs zRhVwPknfi9S7TTEoZ2sWJe=d0Uo0%pmNr2rcQt;jbpJuPjomA4iNHZFSlR7B>z>5D zKZBf?Z}wTw3FjJhp4@-%vxUkY?P8wJ#!kl5gLU#l=M=Rg2kZ(a{Yphqa7%AYU6{w~}r@NIaBL23=7kFcf1^EVgx zxQTvLsGMeL=6auEa9uey0?cp68YqDlX60WWVDg!Mp=8-}m?pwG?5LD&d9!$xul*nl{&n}*^VPz#U_yQy4GfEOd(V;h)M>9jE|kG~Tp`)`Lm_chhx+0jV=oUk~yC5&s~! z8bEEpqVuL1DO|7tB!=1>Kw6-y_Xb96FWImAB!(m#5pYf4HS7*(&s;xAA?!KCrEZ)i zgiw{GYlIxqY(gl|fUJ;0+$%8b>%9UAG}Z)i0k@ZLxDYTYbiWy)_S^puF6e7BLXP3) z|In~(BgAvIAYjGa|A9kW5Pc}^-yl~9FbW8*^_ukv+HXblb?XF12pKFPlyPbWDS_gD z;Fl)|VYfab+~+fj*tn)lfwv%d6^M(vEBWg8HK#Gqg?!RO*CTP`>4G+p5wy92L4$3G zSF&0}K^q2eLeJVk9uSTKKr{fNh7d{&b+se>vxNe!w}bk?2LO87fq1&!h88@+?CuLY5!TqyTqAG55A*;O&4}1@ zUI!iI*M;c#;0AgOonP0IHUA+%#+!3D$OR5){{tb1FJ%zXi^Mv@=BsXmj`cc_S}#H! z8(n}9+B!nGsc#ms2Q=>i@d2C{*KMTNyIO>=@(^wHJqQ=NB4J`^y9eR;HN6{tg>Q(8 zp7Biu*A$`mf6kr$hUkdXgcy6zeuTjj-cVRSsE&BU2A~!=BG!>c(+_}@peh`I_I!Z5HxT?9BK85GQr~On z|Ax`@0K$MJA82s!pLqdd9Ym-p?0bVCBMC78Jiws;HR1xu1wyhzpbqdc5P~80G1uuK z1sotN#(;9rHAsKGU%vA{ognq?8%F5c91P73gK7ZIJBWJ(d;w^LLg6Ez9!M7kKn>vl z+l{guqX-AIM?g*AtA1t z#K{;#SQ~x=(Lgg}pd!c-gCwAVWX3@iuqYOQBvKGTa`h7tMRz6<5jHZ8NENiWfAIf? zSa|}Z1-;(?ga4aaJYZ%r5|X^;<^dTq0H`?=F-pk9jhsXnV3PsmPl8$mm019ay^XVl zm967_6B{dN=_|rR+*62Ta?OTbPJz0BL=F@+jqoKhMK-1o-cI-jL3BqAJt_ogA-ieB zKy~L`6FR|Cp~z{F3Zk0pdo-$32h>tpi3nH*;f6Vpzd=BV+L=a$I$+D&9wR-0(b!;!2Zidl^+PH zsx?r{A|iCceju`cejb5*Mk36RRUN{!d)?9X9}oaO-*^_$S3lpm*bl#KYZ!_BRnBgUA>uzyw(_ z1zNTs$!(Agf^UH`fY8o$g&n%wMZ^Mf8o9HL&`*2!8g>Gn>|HBDbCWQLIf5Aay^Zii z>Ob&*7Qfj+!0&!uQ#%9EziznxGumVqAynn}4gCKYO>#Y@;i6qgHvR!1y$gW;W?gIo-VUoc+$ z_m+u*!utQb0S(h2Y5&hGL2WAF@W%8%ADOk8n^d3%cz$B`W$smDo^GfMjDUU(puI;w z0quPX69R{V)n}lPmo`|H)AS7>UW6l5&;QTN5zJkF%+m`4m|Y+h``RzST9+wc`o%BI zUQBMlVfC-fiA=FU(;L156Xu!V>5skwOVTGsSAKbQlUEUKoz`@!tPw5NW$%}-!!O}Jxv_fO_<&i)C^3_-4rF22+M te+Nd1@Gqd@jB}W$znIIcG(GGW&~rC{y#4clCC9Q~%;IbtmofuelK_7pl5hY3 diff --git a/plugins/auth/routes.py b/plugins/auth/routes.py index fbed437..7502d08 100644 --- a/plugins/auth/routes.py +++ b/plugins/auth/routes.py @@ -1,4 +1,4 @@ -from flask import Blueprint, render_template, request, redirect, url_for, flash +from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app from flask_login import login_user, logout_user, login_required from werkzeug.security import check_password_hash from app import db @@ -29,6 +29,10 @@ def logout(): @bp.route('/register', methods=['GET', 'POST']) def register(): + if not current_app.config.get('ALLOW_REGISTRATION', True): + flash('Registration is currently closed.', 'warning') + return redirect(url_for('auth.login')) + if request.method == 'POST': email = request.form['email'] password = request.form['password'] diff --git a/plugins/core_ui/templates/core_ui/base.html b/plugins/core_ui/templates/core_ui/base.html index b71f2f8..f4b691f 100644 --- a/plugins/core_ui/templates/core_ui/base.html +++ b/plugins/core_ui/templates/core_ui/base.html @@ -2,6 +2,8 @@ + + {% block title %}Nature In Pots Community{% endblock %} +{% endblock %} diff --git a/plugins/plant/templates/plant/detail.html b/plugins/plant/templates/plant/detail.html index 63caacf..d70d8bd 100644 --- a/plugins/plant/templates/plant/detail.html +++ b/plugins/plant/templates/plant/detail.html @@ -1,71 +1,176 @@ {% extends 'core_ui/base.html' %} - {% block title %} {{ plant.common_name.name if plant.common_name else "Unnamed Plant" }} – Nature In Pots {% endblock %} {% block content %} -
-
-
- {% set featured = plant.featured_media or plant.media|first %} - Image of {{ plant.common_name.name if plant.common_name else 'Plant' }} -
+ +
+ {% if prev_uuid %} + ← Previous + {% else %} +
+ {% endif %} + {% if next_uuid %} + Next → + {% else %} +
+ {% endif %} +
-
-

+
+
+

{{ plant.common_name.name if plant.common_name else "Unnamed Plant" }} + ({{ plant.uuid }})

- {% if plant.scientific_name %} -
- {{ plant.scientific_name.name }} -
+ {% if current_user.id == plant.owner_id %} + Edit {% endif %} +
+
+
+
Type
+
{{ plant.plant_type }}
-

- {{ plant.notes or "No description provided." }} -

+
Scientific Name
+
{{ plant.scientific_name.name }}
- {% if plant.mother_uuid %} -

- Parent: - - {{ plant.mother_uuid }} - -

- {% endif %} +
Mother UUID
+
+ {% if plant.mother_uuid %} + + {{ plant.mother_uuid }} + + {% else %} + N/A + {% endif %} +
-
- Edit - Back to List +
Notes
+
{{ plant.notes or '—' }}
+
+ + + + {% if plant.media %} +
Images
+
+ {% for m in plant.media %} +
+ + {{ m.filename }} + +
+ {% endfor %} +
+ {% else %} +

No images uploaded yet.

+ {% endif %} + + {% if current_user.id == plant.owner_id %} +
+
Generate Cuttings
+
+ +
+ + +
+
+ +
+
+ + {% if children %} +
+
Child Plants
+ + {% if children|length > 6 %} + + {% else %} +
+ {% for c in children %} +
+
+
+ {% if c.media %} + {% set first_media = c.media[0] %} + + {{ first_media.filename }} + + {% else %} +
+ {% endif %} +
+ + +
+
+ {% endfor %} +
+ {% endif %} + {% endif %} + {% endif %}
- {% if plant.media|length > (1 if plant.featured_media else 0) %} -
-

Additional Images

-
- {% for img in plant.media if img != featured %} - Plant image - {% endfor %} -
- {% endif %} -
+ ← Back to list {% endblock %} diff --git a/plugins/plant/templates/plant/edit.html b/plugins/plant/templates/plant/edit.html index a5ab9d2..b10ec6a 100644 --- a/plugins/plant/templates/plant/edit.html +++ b/plugins/plant/templates/plant/edit.html @@ -72,10 +72,12 @@ {# ——— Existing Images & Featured Toggle ——— #}

Existing Images

-
+ {{ form.csrf_token }}
{% for media in plant.media_items %} @@ -84,32 +86,43 @@ Plant Image
- {# Featured radio driven off media.featured #} -
+ {# — featured toggle — #} + - -
+
+ + +
+ - {# Rotate button #} + {# — rotate button — #} - {# Delete checkbox #} + {# — delete checkbox — #}
- +
+
- {% else %} -

No images uploaded yet.

{% endfor %}
- -{% endblock %} -{% block scripts %} - {{ super() }} - + }); + {% endblock %} diff --git a/plugins/plant/templates/plant/index.html b/plugins/plant/templates/plant/index.html index 1694249..8ae6472 100644 --- a/plugins/plant/templates/plant/index.html +++ b/plugins/plant/templates/plant/index.html @@ -148,17 +148,13 @@ data-name="{{ plant.common_name.name|lower }}" data-type="{{ plant.plant_type|lower }}">
- {% set featured = plant.featured_media %} + {# Determine featured image: first any marked featured, else first media #} + {% set featured = plant.media|selectattr('featured')|first %} {% if not featured and plant.media %} {% set featured = plant.media[0] %} {% endif %} - {# pick featured → first media if no explicit featured #} - {% set featured = plant.featured_media %} - {% if not featured and plant.media %} - {% set featured = plant.media[0] %} - {% endif %} 10: try: font = ImageFont.truetype(font_path, font_size) except OSError: font = ImageFont.load_default() - if draw.textlength(text, font=font) <= label_px - 20: + if draw.textlength(name, font=font) <= label_px - 20: break font_size -= 1 - while draw.textlength(text, font=font) > label_px - 20 and len(text) > 1: - text = text[:-1] - if len(text) < len((name or '').strip()): - text += "…" - x = (label_px - draw.textlength(text, font=font)) // 2 - y = label_px + 20 - draw.text((x, y), text, font=font, fill="black") + + if draw.textlength(name, font=font) > label_px - 20: + while draw.textlength(name + "…", font=font) > label_px - 20 and len(name) > 1: + name = name[:-1] + name += "…" + + # Draw text centered + text_x = (label_px - draw.textlength(name, font=font)) // 2 + text_y = 370 + draw.text((text_x, text_y), name, font=font, fill="black") buf = io.BytesIO() label_img.save(buf, format='PNG', dpi=(dpi, dpi)) buf.seek(0) - return send_file(buf, mimetype='image/png', download_name=download_filename, as_attachment=True) + + return send_file( + buf, + mimetype='image/png', + as_attachment=True, + download_name=filename + ) -@bp.route('//download_qr', methods=['GET']) +@bp.route('/download_qr/', methods=['GET']) +@login_required def download_qr(uuid_val): - p = Plant.query.filter_by(uuid=uuid_val).first_or_404() - if not p.short_id: + # Private “Direct QR” → f/ on plant.cards + p = Plant.query.filter_by(uuid=uuid_val, owner_id=current_user.id).first_or_404() + if not getattr(p, 'short_id', None): p.short_id = Plant.generate_short_id() db.session.commit() - qr_url = f'https://plant.cards/{p.short_id}' + + base = current_app.config.get('PLANT_CARDS_BASE_URL', 'https://plant.cards') + qr_url = f"{base}/f/{p.short_id}" filename = f"{p.short_id}.png" - return generate_label_with_name( - qr_url, - p.common_name.name or p.scientific_name, - filename - ) + return generate_label_with_name(qr_url, p.common_name.name, filename) -@bp.route('//download_qr_card', methods=['GET']) +@bp.route('/download_qr_card/', methods=['GET']) def download_qr_card(uuid_val): + # Public “Card QR” → / on plant.cards p = Plant.query.filter_by(uuid=uuid_val).first_or_404() - if not p.short_id: + if not getattr(p, 'short_id', None): p.short_id = Plant.generate_short_id() db.session.commit() - qr_url = f'https://plant.cards/{p.short_id}' + + base = current_app.config.get('PLANT_CARDS_BASE_URL', 'https://plant.cards') + qr_url = f"{base}/{p.short_id}" filename = f"{p.short_id}_card.png" - return generate_label_with_name( - qr_url, - p.common_name.name or p.scientific_name, - filename - ) + return generate_label_with_name(qr_url, p.common_name.name, filename)