From 3cd053988ccbbc730f34637469aa385a4eac82f4 Mon Sep 17 00:00:00 2001 From: Zaine Arch Date: Sat, 9 May 2026 16:37:08 +0100 Subject: [PATCH] confused --- ...n-shot-2025-11-10-at-18-02-10-fullpage.png | Bin 0 -> 72287 bytes assets/scripts/notes.js | 66 +++++++++-- assets/styles/style.css | 69 +++++++++-- authoring_server.py | 111 +++++++++++++----- blogs/blogs-list.org | 0 home/backlog.org | 6 +- home/notes.org | 7 ++ lima/index.md | 5 + posts/career/career-list.org | 6 +- posts/posts-list.org | 7 +- recently-updated.org | 28 ++--- requirements.txt | 1 + sitemap.org | 24 +--- tags/learning.org | 6 +- tags/notes.org | 6 +- tests/test_authoring_server.py | 71 +++++++++++ 16 files changed, 310 insertions(+), 103 deletions(-) create mode 100644 assets/images/hzone/2026-05-09-screen-shot-2025-11-10-at-18-02-10-fullpage.png mode change 100755 => 100644 blogs/blogs-list.org mode change 100755 => 100644 home/backlog.org mode change 100755 => 100644 lima/index.md diff --git a/assets/images/hzone/2026-05-09-screen-shot-2025-11-10-at-18-02-10-fullpage.png b/assets/images/hzone/2026-05-09-screen-shot-2025-11-10-at-18-02-10-fullpage.png new file mode 100644 index 0000000000000000000000000000000000000000..3aba68e65c75c92f23e4813469ba5f588df0ad03 GIT binary patch literal 72287 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

ZY2f4=eJ1*& zD}E553M@RMt@?-flg0Cwlx-hnf9t${$1PUNi(jb`uf@A{ALT*Q+sMSdfTavQM@eYG ze=H<9ZAkNae=a1;EUz>ICuTA3n1bWOGViqFne3qOxz#DlIAbr%Bq&Ef&Lb7&G^pOi z``)u9r3%WnIrmfKTQZ@;{yEv?*676fxVJ}3nUQ5CK@o~%Fq{u$!++idc&pjs6}1#y zl`akF*4vU;Gk6y@V!<;d0T@CQ$89Yl%ijLoPOXncKZ|uskfygZ;Z_HRU5@81D8!zN zm5^ZsQlw+7A&!)fSEP-JV36sG; z0j7${52&N3m0Lz#&o{s|`B?Wz5Cq%ih_9&iQp!Oaba93?f#=F+7t6Fh=7xU6_VSG! z^&Z-s*xOD#EaEE84u|h~4?3Znw;J>BYHnqFG7r#SjKB<4KitiWl^E{-YH&+`Xriuj z$d~9*V9(T+D|=1Pqp)&x44A#9xl$w zWP*XFh_~2+C+`Bnean;ZD_#iMAS?VkJqrot8-Tie2qPTv`wbAx-vXBKBwAlhn-PHS z!`c$LZ(TFP1%JVxL#(w`qKjlN!zw4Up|08<*R-F21RFS(I)AN3lew3P1SElO%gTXJ zy}oy-gIRGKR2pPQQ=2H6;0oLtWy>qfU6gl6VyI}WSh{3nIu6y;-;`yCV1kFgE-0ex z;F#3LO;3AnuJ6)m%bLeP;YZ+KxeY2x->W|O!W)=0{me@YI0dYBX`US~ypV%mON$(J z_c9a)_bYfSG4!fV4rd$#NU{7~ouTv{KkY6YA|a5Ik!ov2FOb||L&t*sKKvsJqBU19 zr33%|)zmK=We!hazsisct#zn+AUCI>UW8JYYx$C&i(DxX+fJ$8?>T<>J;t&4wzFn$ z!RiHrO1q(>(?QXT_i=oU{aRH0_q1Qcfr(FKg1{_`=QRR);W`E<+9UKsa7<8t2iQ{J zvi53ITPEdYz214whDBiSGV<uY)*1>*N_(T?Ri(#YAP&o zNPE-DY#U>s>lX{vc}JZDO0`K)yjrio=KRWT#sK8(WwzfpBto@l{xC2QCGi?qbSNGP z>b!GIn}Vq!?6ii!%F)6^1Hc4OWkYc$6>0^Eu?{-S^k8?sJHn^8t)zl6fMK+c3wRHH zc=B3#J8vlyLh*z;fx0l;zlU%V%0OTf8kf$|{Iv-n8rDZ9W~Ua2N~sZ@KOi^uEVaEb z3U-k_a!Io^DPf}Y19h=RU>dmeW)u_L@fx9aZL1tyWI4b)FdTBRLI%~EGTrDISHnf* zdGOK*ZUwno@hpo#lt>=JPIYU!%{4F+GVKo|3&_6ZY8+&eYbh20E)b{WIZJi5`G5#n zOs}7K9rdk$I>n$z$1gSZvJNv#CqB~VZOmhq7@;Dpos0P4nv%U9l6OY33BkK=oqH0r zi`9;I|H2lxXLl!%wvH5@PL!TI?RkJ*&hHf&S+(5R#)uzUzND&f-A<&T&R=JO-?2L# z1D7N^f$iMWoh>|Oq>{2HwVAf>k#QUP)dIXojX31FfMA{O&`hF${ehhyPV23CXESh;x9xZWLiDz~hB9fAYI zG=|YzL&~#eWh`x`z)rWB_lJqm-BY`59+IPG{GHQ3myQ1$WxQ+qB_EGhNP{aHOvMFt z@?Fwm+ueL(^cqy}#3V-gqao(~hJ%3kULGz=Drxe-4e5I8#d11m3#d2y96wa9T&bgs zg{nh#7A~14wfe~|sSf|q0_?0$9AU7lBVU^n-9^Vii1$La;L6> zAg9oVpOc=+oM4(HIEWztTtOA>MqE!PWrUb#0o(s zY_n{zUY+lA-mj{|U`Pi=sU45%HE0Qx!oYR(+fCn0Yi;H#i3M6p5?R|;mGui(I%H1@ z#6tWl8j4ySh|&@>Wr(lU&2B~YwPRF zbO+u-mGnzDB1OOPvS=+O*!wK)q6h{xdmx{lsd4UIf)-@fEL<-rjoT__ zu0gRwm3bhha>a2^8JopJ6NV`33PKHIiWAB9yQjSH*C4Xr_G%q#kr(HrnX(vfu@UJ9 zCT%dlFh6p5)t5X<=Ie*?)5TUr&1A@=b;bk%Q3>m#iAeonc?bEE#>j zLJz3N!Ob#str3Q6iY~EPWTPhY^j-*(;vn;@Gt3FQ8SAe>)NWAb)srlIGIPiKtQ7Z* zr%P=Rk+?(}{#pd*wfKR5HRLZpHiJ!Qzoc)w<2S7QJK(b6Ztv7l^X6&udNFRxg84GIWWh(nvx%`U;J8Yt#G4|HWG!3+fdbL2BwORb zTYJTy=BpP+0?rUv;&X8(G0Fe_S&5%``P1g8v*jOf9EeHySdAzcazYy}@;3D93fegd zUnk%Uc!`=L6c?RFIr>-bE&9o6_W!0riLh*NZsF=N^DBz8UJ>!J<(&<6lS zO;7cT04U|7`18WmTYHUOwg85w2VlyNFaenCzn1}Q!SPU$&gJ0Ezbc6Tl*!>Mz}WQ# zrPd?IvXyC?yFbKU7{2mhTw1$JkjA3GxW3BNy;e2l!Omi;?|7MImsd8bI02u|1^`VD zhhGdB{tMK<1NqGovifpL{vFy)889-Ib1L_LE4@G;Ao$A#@nPqF15=OKfW*y6@qB34 zpW6pV;2~{Se~bA&IRNVapWpcRto8q&xpJMqwgjrWei^TJasp?PCxJ%JvZ>8dJasSM zN6-uRn|S?{r4#q@Ix9c#vkcpvv}g+=t4`pvUhw&;^efbSW#Hx6a}Iw%-lXZG>S?=j zYfM#NrhMFlu(C)WI3YMl2a#4B7)Kv9KR!%LVB=@I6H-6e)bSexXn8rK)L!y*Q7l*Uv!T{En5{MPxa^xaMAp>sJ^Szh#Fmn3vF!Yy?+~Z&4 z_9cyl7M&69Ac~6ftnTtGjupUi?UF8dNCl=G{E}E5F4`8&cwyrHi9&ufgdMq5lKT2% zC_ZUp)Of?6JkW*sYeZD}XwTo^)Lr zF6Ut77Q8gS2w;4}C8pvNpgy2C(VW1Dkwu)*Q$;%u!{chy#ejKXPB`i@9_KBINECTq zyxg`YetI-8Y+%o=Mb(W5_(x1Ui^z6=37>*WgSOs>J2=T%@Cl1lpM!kkXMM7QPSc{k z4LzyTNzCLm>sun00_cINPDamB;24kkkti4FJ4(s~d_4sKeXAbg!RNqXiGYR;Ll+b~;@);I`sj z-0(}Ox!Vr$z8$V>Y^esrX|L3oyqF{MH3kgFhcEBh53`*-aVwSpPWS*&(+rjNAyERpx9*H6rc?97hCnMQ!JC7)aBdK4&kXNOeA;JD67D& z`!inU&CPD&+4ZZ7V@S!mRBTx9z5w;}X%A}?WqIP=Hw&^ko@%?{3yEt<_nkJ{)L>+l zgGETQy6S$zDr?!T@%|3^?GM%%(1MI8&dodQ_{% zW|1&uMNf*z;m^Sul;z=lHX%7zsjjTm8A9Wd*jn$k51mKvS|QT&>HECrjt#G1wYv6J z_Om^54sT8>c}{oT8K6fB*z4$Q%Y|Q0K!zZS3%+`O`xJ7bc2H?wJOflC*_&)p41<>S7fS%~8hZ;IL+T6i(} zyKf0uMkRf|nEFW2s;;Sb( z%=?91JQ&?pi+yz4NI1VXX44B2sh`uUwOJwt-Fuf_4EGH(6!e^m%Z4MM&vcq8@7S9F zZsZ`}lPw9J^OLMt-dneKs?uJU=}MPs)xC?*y=Nu29ejWvYAo3hAbJW&tq)VqZI^u_ z&hKi~c@|s0iVYZUh|NB^tihanXu4}!MU6BZgYvpHFTWv$z=p)v#q)U?2{EN!sZ?_# zmI(1F>pC?zCr-jaSjM6HZYF^kEZ5B!R2}rzsdsm5zEsupGGno7VZo1>ap~01)Ir_3 zaO+Nu+_Bh%tB`1Ql7Rg}>YICme5>&m5kJkWw(tn#!ohvEwYMhR`HO9McxT3NuIwbG zFYZRfgO$8NSRS*ctBmQTKG$1#>$h*ROl%wL#$~@|N4{u1fBE{4(`ok!$K!3uk<3No z93_ktQg;j~PIc;gVT+Wr9Hj95DvB@?`EC1;K{Wr^=MR9n20{f+AB8riuPaknvoa}m z@3(aPMEXw6$5mu3ShEs>YsW=7O04kC3i}bB&0anu$*i}s@TXwoC`G4=i!bg|y@L*F z!%+qZ0V{-WBERi7>B3lU!-KE9M4WiwoT|_cMcywuK)e8P9x-%+G4bSO*mi``Hc7$F zoNAWaY~jpA;v>Wx2c^d8X<~cB#M`LzmlCDonDqwiwY^bFHEA3&@ZgLs{>lD;x3kUX zI2+vyimHAMWk9aZUwN|3RFi8OHwhoRriV&YKBR`yUzk>I328kq0Drn{Ky}ZdqEAlj z(KHy1COinD+ z)G?5Ee}IGajVZBT`0E)-5{?Y>8f zNDjo?m@F}V{efJi%{o&C9GY0K&-d{AM@A+UHc`!+WtCpiYOw8Rr<{85%8I6I>AXRC ztuWZLuARcq?j@_w5oF=z)9f`PIQqV$p=&9Km3*<6ml8MBa2lqcd%b$&G@s4n!;1`t zB3-xE6jJM#F>_m+IN1yPMDWxHrh5r7oY-!hlhP;)OlUBEsp}dlmMpP}E8SkxxBrkr zOt*N^J4ZMfZS)%P8oG8lk-!t};@!fM+RHc5d>Po7K08nILy%0(`djXqGyk4=KIs78 zS|zRA`P;V^<9%zSH$owAR@qmZjg}v-3FXq1O-22vn6!OS+qmU}*w;q9mR3tKWLmM` zm*Or-SUrO9X>;e;X$6v@h6iR^f=-t~vA(oY*~J+=SU!{!TZJCPwxq|hXI#g2eF#~1Gq4na^eW9@)Pv#C{r$1pg5JloVN0Mao8ouZ~0_^ckT zJgA_|BH-t4%O^X6N98?IF$*J*<1Q-vPMQ2FZmGzqwu~%wsM@(}D7VxN(aSDgTad_a zgBm|vDJbzut^8Ds8mH_)U4aiL@($#vyrD!ah@`e2gQPUjWcVIyl5>}(slgI0S7W|w zHh$v=G}hBW&Fn-i$ScZzTm3lzRv)s3Q#CDjksyX`mbLbYRj7g?hm>K~b*WEbH~8=4 z!g_z!-50RN8ucGq+3$mlI6(vgIF%8Ua25&GNdHwL<~yR8P{p*VFHRTx z5Di!c#I*H4j!5=GAod{hbV4R(1RVDRnqSY-Mm6PHvtSAwFsX%C<4kXXgvxwBwa%RR z_mpi8Dd;)PuaTo%P5^#5FNI6qIZbn6-bYDXDR>-esY-vhf(THm`wNiA_W2dbHB zc=;NdSGa)S;ZP&wGWL0mzmoTmOUp@M%l=aw2R$O^kmE=1=ohW7KokeFmUA&mrZHE_ zm>Y-6j)mj0)pfX2mDGstqU;96K1g;6r1o!a<)vGf>OQgES*AwJIGB=uwgih+`*Y5r zbb4Kfp)x&Z;edB`ZK1V4>IdcPm9cb7WI)bH!B;Iz*u#xlBn4!iDwgwywrm-}18>_K zjqe^ziLFI_;e64!@Bv9D8CcOO;H?kNYH;uK+#}_zMuWQp z=71cO;S{gIy_&b`TAkJxWpUm8+j1=~z1Xn9IQV1KF-!o1vwWA<4>zUnt+b<^G&;?B z#n2Dj)v5N`V$Zuah$qWpTJ6?VfC1VT8=xPizl}ChK4*Wy#``C;9#sFB6u7hfB5$=y z{^!w)@Tx_%1Ecw73KDRa<=)?HaQ{te5Kf=1fdDch35ZX{rGi!>IQ8;5Z*XttqlR+r ziu4os7RPM=l{5%FPO=2LtKFUp8?8u9-I35@&VPG%26Sbg>h`j!wr$s7T=tY5@vZOnO}Lhl?#;ki4stkhJSswYkPgU912J6NhrBW zs|=+=bg&QBIZ)&V%H4KckRlV1_$%Rv5(+Ktb-OLo@1-@H=`8m>PdJ(J+3NM}3orpe zh`9By^ilt;4Pc zRD%hvAIr26b{BrmCg6P6Q;2HdvWL}+!G0uH%!#4H1$v{8-sFu2`h^ya8pn@LO@&S| z+zt*2-$z{wp6WMG+4POvOm@;M9``Kq-br@#aWyvjIA)JdtX)jdKNM~DK$`iyL&WnX zOeG*4=$VJOR+%U^3qz96Dt&ccfDenbFOpNi^hbhoEE^wRCG2Y>dE*c-F{^SFRz7?v zM5k&Iv0l1yb*?LiWSXqubo5NyVX&}*=Tg9gc2wp0!&UhBf!47T0YXaa7IR-YM33*VU z$hm`$q+fwT+b^lY$nTP0sdrno8W>`=+9H<6bu#%T)A~ij#R;ISXDG6Qb@4_KvDJ{l zE*NMN6#w!&VsC4%s&OMsKBGJsDi!@S!{`|$xtC(x8|R>pFJHW_c_)v};@Ob@IJ=+R z84`R11RI~^GF-T$oMfD$NTYXd+;;Y1%6C%~QG8Y;@_fL_KDG@Ox%5SkuZkpwq*Q3Z zL+9O6yAXM8P_HERmh~wMvR>-P?J9ofS&41HLkk|!Qv@86Tjw#c5cfe1$_{?KA&IEO zME(q%d8f={i(!&|C^wj06pRa2pzM)ntGgUUdX_tKDdd{$ATI%RzBz}6r&Qjp2Vu7r zcDb4(=R=W$QSD-O%K91B*9%0!5LK_6j0ft;u{@=&m%sL$$WTt^2G#nHFYk*aLSA;d zxlEQ1lW0cN;ok7Kce@A*+?gKbW4#{LXIn*OEpmeE_C0vnc#rHuR1LPu)?Rk9?%M>^ zp5C6po-q&?ji%rkTD{lBWl_t*btANlqdgnVbFZJT&Wc5W&o@}YjX-=|F8=0}U=_OF zPeEBmO=ICNxes5?p4}TZbgIl? zPqKNzbdN`-^_K?+-e9(QEr!TsKHgyN(^~k~RKVX}qYDaHhvFLrJ|Qnjg27ATBHp5i z$b2r>t0rn{_H@X88!FWgKUk{aJ5N`6R^Y`ofBI#9ib!(ykii>nY!rDU2lLcpTD3ny zo5{=)vDLvF(D|zh4}xlruDe-R4l_kLo)F$d2%g^6A(Q=Wk=a+?E{$o*n;cW0r630{ zKdXll8PtfqsIOD70Nj20MixfQ1~|5|WeSly1^3DnDJY7M9)7 zCaqkVl$H^+4#OijJ4VJazraAaQjPmlhV*Vb;`4W8v-pucQ5a1(FpiE3*Zd_3ut`nr_T4c5yB3p z#yJb6{`Z@Pfq4ug2(ey&I)(44I_TFWx5tA#e;WOiKuckC+Q#3BAc+8Do_#HI`R^>? zr{)!ClsGSi#@p3DFHr4P2GbgalKT5i23LVYT&3vU{@ZuZJE{L$AELt%i~iFuY-k`X zG(+sH>Bj_#|N4AmA=$O(F7U+#O21+vuyfb6QbWDG4uI znP$=j@SimTyJWTlaD{iP#XnvfL^`rLmi(ADb{}i!s$VNxczKRA9+g~J3rwcveb6Y!}_>ONwQ}{d%x&($y2DYniVBFqtl?B)CFC?LrIE$hef2Eat zL5#%IS2@(oz0Pr(Y0B|EJ(1is4YwBs21XZIiM;t|U+b;G`w<=|n95(%p#b*mK=?UI zK6-^&J`4fm=4imJAqzg}N6Z?1>qXwt#g57wMVwb)u9u$OFk$U0zcy-{ zVg0O!a{H6-h~`S7Ns;@H{QHml%9oxS*KUSKFo-0AVPP78HreBCqUJ^sty0WTQd`wkppkI_gx(o(4Z~JP1tvpVjCcocfmk>cs{1TLHe+h zlL7GFaCON&d+_d8BDU`tHSSqcphF}p?L#b}U$Nl~`qxKRG)J)J2on=-mN&@k;!OR` zx~H-j%`dUz8=9*lxJvxG+p$Qa#{2kxUfMxmVXQdAi~jaR;3oLY!4{3)qqD9+QJNr2 zV>}2n>@*8i6HoZ$>0M-`5fdH@37zz=-FL0h1F6fxSy0;*1FC#(Zf*-ez;qX2?V0<> zyEE%dnkGGW+Ab~RWqzCzr~ab_h$!0~85v2!h#ht(zxWoiFyYi(x%>TPBd|Dh-DXy47tQK0N$^#C~HS$<=r2*;MBaHsg$!LGr>20*AIb((MI|z=?S{Gg2Y(5oC zdEj;r&;rr5ARVZ~irH6ylsPUSJ)d;736Ic9e}W!tfl-aEnxPj1h{*&2PL!yk4{`0l z0(vPq^s+@A*ivW-6(APRL5Gv@QggW{(=MG1J3hJ!0wO@+o`mP2_P&w&+Z&1CRpYL` zlEeu>NvyY1J&gbtZ(YEKh?*1`c*rM!ee)qQr`j@%42D(jA~9sP+XZUzdso?2lTm6% z#Gb-yrEQn0#LQX=C&)B^YCe)pRisr+xs#3rVniW#2SpYypmmK0ybao?N6)MouuoOT z;)VICwWYKE7Zbr)r!N7CF&@6EDsr5ts$3RHfju%D)dD=!Ws3TWMgNODr8sqJLx;N} zsn_g_>jAg2e%$v?aC36BHv&%sbPG;6RHb&i#%07VS!<5{8Uqf(?hq4ion4)+hL=B& z;dSX1&->|LU9jkyDV_x2P6Z;cXE1%r2G3nC3IY%biJI=a$ z=M)U!#Wnz@1xN2Xl+q5@&9w#P7IWL$>u6)K9(Re4v|D=I<8wz>Mn72OCgzS_ceFxQ z*$#9RH;&$L9pu%wKj13wHeYR@)-w(65d+*DH)nrDIrSA`RkL;TfX@J&d2-s^3gH~Z zIR{)8EcMMDE1t>WmpgHD$*>+Dzf?~5q^89IIFR88y=p)ydX~3S8;-j9ZIX*0ZAk~L zXE)yXwvypkc<8eEK&;EoaJ;@adiOQv^9=Jl!D-a92Az_y@pnHX!S81)WaO&rQ8(lb(sO|VNay3~c%^;7 zQb^4%SPSDAiVSk28e)p@E8(nT;F1g)RZwi#E~EMR+uKe_U!eKDZxmV1)OR*2X4ORx z&rw0lY%!Ut$)3T+(aOAygQ2DOr=Gp1N+9O}i0*yPCUthHF&#rkONK+A5IF>^KP$gW z&X4%J7HcpPgzB>&2$>?l{*EKx)c*R)nWW59`{}_51#w1?{VUN|H&$e3+tS0f5Bubq zDvjP9%#H_d1)jU!5<>Y}s1_8jg<`TkGR=jp9tCG)DPTCXa`enDP{jK%H*Em2LCZzo zrJV{5WPWysk+ZFf!Q>m8;NT%;P{BaL50vP4*;AgqJN5*sd%^0-r*Eh(lh4*5cUa_1 zz^wwS2;qf0cutbR@P(YL+ADb>b6ufbTF*6h=$W}e-&sH6Zg9=QhI~v&J_O_{1y1@vdp9 z?WNTdYg!5Si0k7RTH?dq!n&F-r(B$8Tdn|#k=O@Mjzx)UJHcT z+^DM9`}Ssn&m0Kar?mTAL)c@hPu|kCSElaCce`}FYWau@#^Gz zK{5)01dG9-Ef|`AARf;ghNeA{CUO&^4ud7#Ev4-U-uF|f#ZcH#Jf@H;AC9dM=%RsT zHe~qUUi)xi+)pp!&X@C$4myowk8}1tWF1!Ik8KSr9v3Z-UP+QFB_eFRsw&h1IqA-R z!`n3a>)UlC`Wnk%xtMG5UH9;hKESnGjTg@p7w!hv3qlcAMd&*LRIAidFgp6B5pdFQ z9JwQSsr3Bz^I;*m)zGKmO{>2uxYvz!zk0SgDJL%_@K=AI?h9TFn=$cRw;VAUzBw#E z{1&g_KQMiOef7UZp#Mz>hmZ8W>2(arL^Dc}`!n{qLn4gmXJqU&$tM_nk6gBgbWO)j zcI8{`kk)yYe17|kw6wZzyL*LE}j3l~i6 ze{OQM55$=j)ETtdAY^%cTV5uxLTu0C)m5g2IAiw&H}$I@0=_d!z6<6O>KA)8FPgCk z0xtX4qzraUetWOpmM!NbsajI2I!ioUFzBF|Ym+^Ovm&07GWfGr%|jv(2gLUD`!X-C zq|ZYHB_DJ2?B^|osN7rFxTKK*rD&Yppg9-?dbj+QY*j*vPhO)ekHmLIEiPA6z`OL? z(&#||aakk03|yVl_q%F_p;~)=dIKt_#ePGMZ@AHOw~E3}X4Va$A&^A}Rf*eew``kD z`xlIjLgB2m6eW*7PiCcz#&VJ{cfZL}P+KGJBTtfhm6?T>JZOz~Y}#KKE~YgEXX2FS zs*lmqYwyu#!0z)_-)Dcm=%XrOi7EZX`_=oGG_EIEN8nwnmaM52?oB0|WB4=7o9|TY zh=Z!Oy6y#XhxjEG!3)g2TB9#p>q6cxX1MKp3@2_Nm)G8S#*2V`pxRh1c#jQAd-!=7W$jPh0iMb zo*N^pvKv>GJe>BpzRRf1kRH{dz5Cqxp7dR2ZLk1BRd&v61^h4&V#Lkd7XZV*V`t;a8J9ZhgDF zvpyg79wF)yq{q+O#fJ#VE3*#IYvQtWx)z5 z93?=Oz)2E^4T!EE_2VrYs1~ADy=~-*7NF~g9l; z0vCsiRv|pOb@m{xGN)XO0v2|A4Wf}1cFr{%N9uC*Y_tH<#r*p@+&!P8ne6DEGUFMs z@?ntlN*mj4kd(Q3b%R|hZeLEx4I~wR9aHGS1;=t#I%4~LM`8}9ox{px)O?@R@19%k z|Dq}3cg~)S0#{7l()F4_^TGcoqajIP^HIm4%+lo3PusJ3J&3$;$|!G8xMgT6^j59CTS0gO$OCRh{dLsHhYAVQi*QGqdh<9!WMF_Mo|6hj@onh_E4xN;w+d@W<{}~oUC-6`zBZ(EMILb_ zAxI*Ya{0?%Yq*UxYYB(G>)ZWT3>Lg3P9(cw@M&SmW83YwD#Ycr3P9`We@J<6NXmeuj0$ z)CQN%u$nHptcUKeYNY`HqLeR(Cm3-3IWNAA1bd%X^0S!Vr?y~;tE~7_T0o$)p!p|~ z)oXJ65^FBj2%fs73>~8uGc|1ne;QJ)SETHScbb$gpF{4D#BUr)(XSar4ouR(D0qT3 zZ)#qlxcD=`dTX*`aSq#=uQINbp(;!q#Yabx?)>ikyJ+n?lCwe>;gYw(sd-zHE7JXf zb*^$0;>%2ZNhHxEFd5i>20QBo$BvK)h3<0lZwkkua{9@HBMV@5Gci1fX8X+Ke@4B=+pq6i5S3RMVr zq1sHrw|BqKE{tkNW?b7LWVQ6N?qmXTkVrn`An)o~y83o%axDrSmxHTwpKDlSS)*k- zcfeiA(nXegf--VzN?q{@&by{%IvS+#yOzMU+Sj*j4-Z`Q$@K8i`t^)uL0%Sj(K zhY^{xOHm6Z-$by|TMTSTJjx0O)@LJ2XeoG+S?Jzybb~8Fy=qd>V0+D@`e5v+QiTvT zi6n`rL)}Me@-wunLOQm`=03pge7rSGvV)O@*(B|w*-0acPC*p{DV}=eWAqY(x9Rls zb``E}XttJFT`>+%ssAaj&Hj`zJpz3#x*-bbF@2+$_et9Yd!i(nvf+iLaXA@LI@Mq- zZshC=rVPW?$9GWNHBgoHJY_;6dKVa(+doEDi0*b040wx7Pk!`u0(>yt?!Z=>tM-VA-Gog|aUa%JvE zr^c#`n#`?F1fLXGN$>)T)!UsR5jL%3uTS*DgXic*m4Y5(LG*%+l6{aJwUwM`Z~ zD~&l52eV?jg6Zu$pF$o&CeEHaKT4uMt{BZqz~C*d$9zSgfXqjP;+KMWsKgR$9eD!z z@`#ahHLSG+}9zqzDfILt)-YE%|oef1UYd8};1=gA8_#mm#-r5JXjx zg0v2yZlf{y*eiBP5hf#lg;r7K-m+UloT!KjR>tU6{u}q#vS70eATYnVSlAl*?zw7> z0w&8t!I%UaoIe^)XOa5eqUCyL4a<)Y%jeF%Rk`L;ScVV%ISo=V7Y%WlN&^cVt30lO zm9IZoZ+s}eGXf-^uo!L-_7}Pqs>zJ9USgGUb?4fCcMkxDi9k-%`(*7=+gT#X=p`4{ zDt%rKFj>WDMC2aBM>+DHQh5h1N5_bJu8ViIn08r<>s4SCB51L48O&0BM7V&yqq65n z%&+OK{b(pcZbHSlLF58ptdOzXu zJo9ro3!!)-0&I(7484PDAfIlCD0}|_IKNce z+J+4OaAJ*wpRm0AC~Vao|Jv0mjxfyzw7j{6 zI`}&YcB)|d(LoZI|1Ng$h6GO}ND#}R|AOjy@t`G?0!8p=41T>}5SJWf1{wdf`~%qI z8!c}R{s*^`fk!S9^H#3@LE`g-!E^{P5eWQC1O5A#SsnE29K$t%|DYDkK?|o`9^`LN zrSQ~31%-y^-xlyj3QsLWN2!baZ4AW|S2h_awZHiA0-jp%A{jjMpL;5S_j=DB4RZZy z^b5s%y=&>vzY{?c4#wOoC$moRr|G)) zw^QH^0iIgu_0uT-+X%(?)ch6d??f>3Dt7+U zWFM!3{Dh^s(;MU{hS#&Y7t=3mNMHV-;zK9xlzPi&n^}FM4j#KiJ02HgKx$SyYd^M- zk;;93o`S0SS54rHxQ=_DG;D<(?eg_$40=fZOIOIx`{CimG&@4R`Awix=Sr3)KYZsUSZTL&hwFq)Me;N+`9H<$4uSA4-NokOp{Mbj%z;i*8+Y&cZqz$9?|WGfRgAO zttexO0a$tbRW;E*dLXO=YwG&7O19esEQh30TLpo==K&j|LMw2KoM67t7|g#P7XBYh z;oo)r_l?a>0$mf2Y#4^`)6;GA{iMd7an4UUL?bx~4|*)Ajco4n*$2@+oS@CEUZ)dZ ze!l&^hGXG<)F+5B{Il^vAxz&)KBoxvh0SCjn{0fy_lz zj(3tR8n8gNw^WmDfE53chyXzR69C6D)(!4vEW};#ji=ykd~}ld3u6uaZ5X}L`0Z0E zGrQ`)&e5Mm6D)BVe5CL!)}K*Wx_%6O9TvxTwKGy6)$3Qt{%T3HxjholUuZynIpjFO z-qY?JbuE-Aiqi}dzyX1!&Pf3Bui)8_LG8#Hvmk~w;m?Zpl11aF#ZUTICE_O(=KjnJh1A?Xq_GLJiA)uegn`&Ii8$2 z7VZOJd_54CQcuUXYmies0N9{Y%qHFT&>gMa?@2qSZ+PnR_KTV-J=O#B1K(LWOs^PR zAVhjB(3XS5FtN_^1NG5)i(^(v+?8`PzNd}*Ko=jdISKTeR`}#V+u&N$XjKomrm_H% zPzcm-HhFG2>YkHLqbJ}t!Q!(wq4BWy$>GdtA|9@%e~sQi0vfh&W2J6B*3f@t0wh*= z(h*K)jr2LNE&p;WDIO$*I<}7swJ-H`)L~y)S$Vj-F@**bi*&P9Onp!N7^IKk2idR8 z6n6!N-gwu4xt?mnv_HQH(j46f!gr(g<|TevAF=vVko(grTwwT)u91tZ)|yhgBWd=j zGS`P!`T*KS&&QdXxTI!K(LepnvHGo`xsz+kfJyKjMxdRxsnWAf*tU52g-a z&UA^pvjJoVrVl5o9MKx`4Dcv%5CZ(ldmiuYQ?9go`VSdoqCMkguXTS0@!|fU?@n4i z-Eo@j5GsZ$J1Fu+=fnTi)tSdb*}nbXGH!d#*w--jEMsdZyJkp2Bn`4f2H8oGeINT$ z$zJxlRd!0*VkFCCiLqtNma%0p82qlef8XbMJ@?mt{K3n09p`x-bG$#F&q;E-(QxDX z9^8y(z?SGS{;oh*iVQFZbAtq9fhSv^n~XUNnnpXf8h!?^=g@KAt?uY)0Jsp~L^;H= z@WW-j>zF^klO{!m+Iwbb>A}yYgV*1((geJ6FsiJwm`C-pSzkcmTVhRaym*->H`vI@XnFSBe4zSPmxfjBm{l=(ngadXl{6}Dd za7ydl+9+z1MFxQ`{ zUhCQlhdf080IrVZuiI#xnzZ#Iz+Frf-Y1du*ga`?`E2GwUqk=9?2Kb|#EVz-`8}Og zvN5G1KSvadpPjaclLBKFV~aK={a8J zneWNhUE>+pRt|-ylZW0!2OU4F=;LFb84Y1nDPP63xlrt5t+F%@UY~aKcLC8Ps+n|i z=W`A4EtY>7uq`%f_uyi@Q?voAQNPvqTUEY^jM*d~* z3$vkREF+ufR5oeN5R%UmtK3vG6Lls|%>pVF;1d`h)atKu0w z_(R!r!ZzQ-Pu$YM!$L7Q=yhp5m!A(H5!JV`eCL)D3K`}{Beze1w`~05cHmG|!yBj{!AMIamSZkWch@_KD+qLtg#kxbRM5S3t70v_r<8_hLK)v6!`kcO+lk6F-#h=%t-|9sx`#W3v z=V(J745%*LR?f$!!6uU(I&SNJmeAijwOEAeC3~6_@!*9vy{-?d#Yt7JZ9uWu*k5_j zqsJ`gO#2F;86N8+nt+Y{t!Y7}(L0gm=yoXR1_C))-9?Yf&AOe)p;=&;N$htgb>VO5 z3E@#u49$R95p_mPfQWi1Q&_%o!0JtZV4vrybzs}0p9MIw2($4!+>j0>^Kcgc|1SV3 zThF^4(nW~mP79Y6SaTMz@^{jzyGsW@Uq7!;)Bvn^Rf7+Q4JD0ZbJ~lZ-Lab}e+pBY ztC+6oqBm7YWzLngmaI%%HAGWC0sOfWwz{R&?bVV%|L~=fI&HO`n-65pRq~JOU_!Wa zTQzA+W4GVw%$Ufj4la(pQYpjyjpF4bU7ZhxE`vECZ&1QP@c6@40DG~fIhY|?-Xf}< zYL=|z?HgyqKou#fKk@qb8gTP9(-_89gaq>H@VmOfD}7Ag5SMEc*p0v8q!=zwn-WEs z1(MYF*n7XtcO`shh#IAx1&U=_E3Z2ZzH?avAK8Hd`{6o!_7L-m+ zqxf@zRroFwZD`Rjp_5zbB)q2~1Gh%&`66_G!n0l!mrw}lpuw(~Y)joH#vB8tGY?A0 zP6^icR>V$R4zPgMz^Fk8xoJD~g>W&p9oW<3cG3HT) zZR$qj& z>P^-N6217hbnsCgp+u|3Pc^iQRpXvS2g;Sbl(Q$?I8d3XbrNX4e$L5!K^s{JFSwe~ zy^UhP0XAXn#_KDy-RG09#qTfDV78+n`BC;9ubu~^lD1`rvt73V)$xa~(4?-Tx~!1r zR;|{9)!nMse<^OsdN5LR7m1wuhGErHq>So0nN9dG^wnz3HrB zPO?3_y_S{-oO^C0jy2q$bwlK>W@Iv+!CEBh5@94D*^f|ru~?Fs)^SA*4-x0l5Wq69 z@kp`17*w3&VQ}aTPx0rKlC>s)=B`Lk)64?;2K-z=TA+$CvCHk#d>lU?7eZiIpld+* zJ6wV>I^LColLnk}Ei{SYtB}A#nMv3%3OeXxCl=Zr0YO*tE2b+S-^8!Av1>xELp)zh zGn_}fLP{#1^N*p|Li;)R5NQ`3YaHlVSQM4GXqjkavT`x;W}>V4z>zzaGl=qmjSq88 zViC@=4mfTD>~~Cm5Nir1&WG@)NV!!u@P;s#SeJM*zaysFbJ(+d0+|V10ImNHIa-`1 z&z7Z_T+Z*{2%KdH{KMGi7lYa224Yf}B(y}i__bhrtXj#8DNyXQXjdZ5T5^aa3M7z*G2UdRr4XDd-!wn zB3y<9Q!g|Okio^k8avKv1nuM*YWn56?%IJ)j`r#x$;skHb&-)r4()e48%v-Nr_K{! zdx;m?A&OB(nFY%Qw7?KQcJr`GgmA^kX(jv+vq_M?Z)Y&I3hjf8lJ56-Qe9)$3=*k@ zD|+W^LY0&Y-HOB~+=qh~w%m7*iyFgrm*m_+77D){^<=lKF4IEQb5ujjB&_)(bM(}~ zh>7Y5!CFzKsrz-hlWM=LicZKUTvL+Iz;_RbRW|my+-XMsw;=k#79yMHVK;UkNwTyWMHuhw`4aB_8YkcU= z{rimER#~;O-!$kAq9?z(=*V7KzG~HX7+Lh|=`E9*dk}-i^R(UGDX`e~bl|y<9X*r| z83T0E>)r;gevy`l#(C||gQu#(We>*R!PB8Ke;~e08P6KKIfthfvIAQ~$)gNcPhHO3 z5y3~E9R^AII_(&HaLIR#;+_wjj%y@aMxx(qqmqY5VGc36@I!n50d0OIhSF&E#h!BJ zE-R8aCXX!exkoV40L-wM@e612$I9ic}bmJZ#ytW z0BpGbjBBmeg!QpGAlt9JcdwMP;4oAWPtoyO{C6*=C^|?t!@V#^h|8ajv?!hUP# z*6V|Jm|^mERd`9*XzA`DcoE!Uq`5c-P{dQ<)|gWguhTb;4$JCWT#|&uO!43=isx)} zKu&j9VSixMKejZ;RzE{6^BlS|bw0h_|vnC8QtEivhBPrM)hGFE4c$=><#>uLq) zV?S6dT^_ecOVnfCVM(ljnfwOX*3N=}#jtCxaTiPaOZ1xTn#2GKF_l0-f-Ajy%*sf9_>5V=#mDUaE3)SCXy2ucNM%e4Jq~rZ}=0j6w~S4bht~u z_s?5o=*l3rREO@yf z@}tSWo6eWlXa)eiK&Dy3!#%tAX@}d<2USH?VH2Xpw(+sI@~qDK!i{IX`fptRJ4v=N zhWAfbiAbQ4=NpkoY$CBVX_bz|yVFqTCeU^%Oh06S6oj!W5r*$rsThgqqMTPnnK;6E zblC*9VvCw5>4Z#FK6?_?%G`lNwruA~4Q3X`;FpRV5-1M4Lu0wB+5t+9?<1|yP;L8) z2C&sfdPSS2@Aw%=`oY2+SJoeSrm|nnB2Tyq8fqC4i^W2_?&p2sUS$e13}$ zLwvw661(PBrte&uf2lz%AM_X>8qplzS=3aDDLhT(>hj@I`BPItsei*K#h%Ig8G_6V zYx16@>(NhkJ_ugEp%xPqbN&u^8YNtu^z?y@9)D*EZ1^x4^$YyoXuxVSsW9O-{(KVh z?mRN$alcUqV+kNj0dx!Raoj?Om(?v$_{Bjn<2wGHqA*dhx@LVN;9x@^c(H($PgI&m z0T~xg%I99#PVGEhme{$y&6%k%H@&KT=AnoxD<7a{?E2~X zy5TD}*Be74=!n_#;ZR*=1~=!Y0jJjWbnvgDt{?S?lAXMIEIk||3G#q+Vr(`_E5mXd zV;*AM(N;($A989~4X>G~m$m(VQ64@?1-A#fh-zDFOrWBycZyc1rA3>j8~`M6qdL&YFm zm})T}knV+7V=xk^7am_89mv5QD!{2ZLQW5xXOFoh((of7rq zmq4ATFTY2hE2ixfWM#CMxUubfluHF{N0|)2CFFwHg7hs)`lL-5WKsjTIP+Hm3hOy_ z96O+T98zi@AsP9TDQX!U5`)5}81-M9`g1;Oo;eykqBL^ihQu!4l%XB^9ZY=`PoSO1 z^N+k5AQ~=Ky%=6s5NP(r$u-k1)52JA|2rzY;|tmTAw64#DDI0I>~Y6d)hHiEvx?^L z4dWLuVmO zp)GSOT*7vLG3X_1#uSQHfsqM#Dta!l-{OhiKR4rfyMi#k)+Lazs^-B7rYHf&CBmFk z8L3!uu`?<1DJ?@dLJgWIjQvwvK7-i&llk&3;%?m{Mv%*-|4&hY7#7K`a@1jz5u_Jh zEmGWc_$YUVH>>t81G?WUeUr3k0yh`o>7pI5 z7OP4>TK?BDKw-v7(23@~fES_EBmRfoZ?zeV98aRo9{oaP?=AB0^v+D(VSto$fvF=C|UcgVve)J}Iv+7o3mx z+))N;W$UKG+0(I?1|_expX*fMUD`H0Dgzp=@FH07AODcIqj_7Y-RBmyNU{5RtTe`9|#{?5< zRTIZBx&>y41!Ef&y-OuwR|4IIPj6OR*}cFspT*IyMcIZu9=y4Pj1&IV){N45{Nay( z;P+}&_0<^PIl8Y4VbEfBVYWKHN2LCKBmfi5r zD6G#Q(&5$iMofk??zQ=@({G?@LB-q;*qvB!5%SHSuJ&pWZ@E-6f?BTS`k(se$b>-V z`)H(FA#%He4`zQp<`rG7mFO7RaeTL{Y&ZJp@!=P4Ri5gfzH!t}^g@G{uQc&$G=Y<7 z-^Op)D9R#RzMpn;Ab9@$dBgQblcX-qo}v~levgPRwKbj|^!#&u{?;dM>oO0~Z*f4$ zViRl=3F&$)E*Eyo@*c+fn*U$gPGNA7SPCbv!EhgZx@~EX8$G%F^9UvV4-PVg-5U4J z2tPghl7|h^oE|+Ps2sLauN` z@qs7qcASR?tbUJkYOka}yi`c?i#lnLw z42>LME*CkM#YMeO3p~EZ7pBp5lSx4TwoTe5dnA|v9F#yMc+f4iQ3syY)vzP>~V(?@73?@d;Ap>=o ztP~l|A24~IFL*o2EfJZEDMa|P@uhw<72{f?I@x9T(p6@8J5NWB5S8w0K6!**;T$rx z3qiPKwh7GN0(3Zh)Pcj0SW}T1x}nzy@49u#jk@wN+|8+VWfucpNXyVJSkJR%QvBZ_ z<2#wb0va3$1ZQ2DE^#9Zh}RbRmSz^oRdGbIY1X+JPX)U?(HQRcEN_5ZmtSOu+(s;H z(+f?QE|vpmR@3`5S4pwOoFZ-lYf!_#XAKP?OEZ^J>OVSHT0kO~uf23BmYi?M7mwe~ zpFt9SE##{`dv2@~I8@tX|M`4U`*RyFw-IoiNmgNmO2;NkbUm)~H*&;-wJqQRfc@Yn z3V9Nw*r%g}>z-38J-6Qe$4UJknZmLT<(-^nbx>mI_B~*2+v<{T=Vc}odS{7yH-CD7|D_Zde)3@{xgq%CzaD9WSo>i> zzJGQgmz~_?_^Ye*{=g(VrzG{tMbtkEh1mP6Ia-nFo(iBgYX;8*YmWra#7PUIab*2B ziz1!N53&(BrXF!(cSYys(nnhsKgXkSY1TUp% zD48$=dK65^ar?f=o(FJ+j|=b-@DgCsd%kMLV0L?0fH8)k&hU>k0YLFRITc#BufNQ1 z_#03j$2I=?s;_#}OEKWg8*>BbuiRw3mVB9a2* zkuQPtspS}U69oX`B=agcC-ACz-8H5TAmE3HK<8h0>$2;2VPzn6Y^v}(+5hPC+j5uU z__H*f%0Qkdd$}067-Qk9-{(Y>Mx4FFK;LYeu5)RYMA^IAi}5+R7JL-Aozo{6gLU;E z!hxgzBqZ7dP3wI!a^hX6tj~vwPuTZ~ye#}LA;4&q&hh?+F(tE^B3}V8@Pnb4ICQFz z_RnO#OW&pe6o0G0h&wUdq^;@4s0MKxMDq%lhV`&dX#EVH`juzCx-rt_eF1baH2hS1 X`?3rV^L~RW74T( normaliseAuthor(note.author_name)).filter(Boolean)) + ).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" })); + + authorFilter.innerHTML = ''; + + authors.forEach(author => { + const option = document.createElement("option"); + option.value = author; + option.textContent = author; + authorFilter.appendChild(option); + }); + + authorFilter.value = authors.includes(previousValue) ? previousValue : ""; + } + + function renderNotes() { + wall.innerHTML = ""; + + const selectedAuthor = authorFilter ? authorFilter.value : ""; + const notes = selectedAuthor + ? notesCache.filter(note => normaliseAuthor(note.author_name) === selectedAuthor) + : notesCache; + + if (notesCache.length === 0) { + wall.innerHTML = "

No notes yet.

"; + return; + } + + if (notes.length === 0) { + wall.innerHTML = "

No notes for this author.

"; + return; + } + + notes.forEach(note => { + wall.appendChild(renderNote(note)); + }); + } + async function loadNotes() { wall.innerHTML = "

Loading notes…

"; @@ -42,16 +91,9 @@ if (!res.ok) throw new Error("Failed to fetch notes"); const notes = await res.json(); - wall.innerHTML = ""; - - if (notes.length === 0) { - wall.innerHTML = "

No notes yet.

"; - return; - } - - notes.forEach(note => { - wall.appendChild(renderNote(note)); - }); + notesCache = notes; + populateAuthorFilter(notesCache); + renderNotes(); } catch (err) { console.error(err); wall.innerHTML = "

Could not load notes.

"; @@ -98,5 +140,9 @@ form.addEventListener("submit", submitNote); } + if (authorFilter) { + authorFilter.addEventListener("change", renderNotes); + } + loadNotes(); })(); diff --git a/assets/styles/style.css b/assets/styles/style.css index 3131913..37316f2 100755 --- a/assets/styles/style.css +++ b/assets/styles/style.css @@ -443,6 +443,38 @@ body.no-sidenotes { NOTES BOARD ========================= */ +#notes-tools { + display: flex; + align-items: end; + justify-content: flex-end; + gap: 0.65rem; + margin: 1.25rem 0 0; +} + +#notes-tools label { + color: var(--muted); + font-size: 0.75rem; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +#notes-author-filter { + min-width: min(220px, 100%); + border: 1px solid var(--border); + border-radius: 8px; + background: var(--surface); + color: var(--fg); + font: inherit; + font-size: 0.9rem; + line-height: 1.2; + padding: 0.45rem 0.65rem; +} + +#notes-author-filter:focus { + outline: 2px solid color-mix(in oklab, var(--accent) 45%, transparent); + outline-offset: 2px; +} + #notes-wall { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); @@ -458,7 +490,9 @@ body.no-sidenotes { .note { position: relative; padding: 1rem 1rem 0.9rem; - background: --code-bg; + background: var(--surface); + color: var(--fg); + border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08), @@ -466,7 +500,9 @@ body.no-sidenotes { transform: rotate(var(--note-tilt, 0deg)); transition: transform 0.15s ease, - box-shadow 0.15s ease; + box-shadow 0.15s ease, + background-color 0.2s ease, + border-color 0.2s ease; } @@ -511,7 +547,7 @@ body.no-sidenotes { align-items: baseline; font-size: 0.7rem; margin-bottom: 0.5rem; - color: #555; + color: var(--muted); } .note-author { @@ -533,7 +569,7 @@ body.no-sidenotes { font-size: 0.95rem; line-height: 1.45; white-space: pre-wrap; - color: --fg; + color: var(--fg); } /* ========================= @@ -545,6 +581,11 @@ body.no-sidenotes { grid-template-columns: 1fr; } + #notes-tools { + align-items: stretch; + flex-direction: column; + } + .note { transform: none; } @@ -567,7 +608,9 @@ body.no-sidenotes { #notes-form { width: 100%; max-width: 420px; - background: --bg; + background: var(--surface); + color: var(--fg); + border: 1px solid var(--border); padding: 1.25rem 1.25rem 1.1rem; border-radius: 10px; box-shadow: @@ -600,7 +643,7 @@ body.no-sidenotes { font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; - color: #666; + color: var(--muted); margin-bottom: 0.25rem; } @@ -613,12 +656,13 @@ body.no-sidenotes { width: 100%; border: none; background: transparent; + color: var(--fg); font-family: inherit; font-size: 0.95rem; line-height: 1.45; padding: 0.3rem 0; margin-bottom: 0.9rem; - border-bottom: 1px solid #ddd; + border-bottom: 1px solid var(--border); } #notes-form textarea { @@ -630,12 +674,12 @@ body.no-sidenotes { #notes-form input:focus, #notes-form textarea:focus { outline: none; - border-bottom-color: #999; + border-bottom-color: var(--accent); } /* placeholder */ #notes-form ::placeholder { - color: #aaa; + color: var(--muted); } /* ========================= @@ -651,14 +695,15 @@ body.no-sidenotes { text-transform: uppercase; border-radius: 999px; border: none; - background: #222; - color: #fff; + background: var(--fg); + color: var(--bg); cursor: pointer; float: right; } #notes-form button:hover { - background: #000; + background: var(--accent); + color: var(--surface); } #notes-form button:disabled { diff --git a/authoring_server.py b/authoring_server.py index ad93576..bec1ea7 100755 --- a/authoring_server.py +++ b/authoring_server.py @@ -12,14 +12,15 @@ import subprocess import sys import threading import time -import cgi from dataclasses import dataclass, field from datetime import datetime +from email.parser import BytesParser +from email.policy import default as email_default_policy from email.utils import formatdate from http import HTTPStatus from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path -from typing import Any +from typing import Any, Callable from urllib.parse import parse_qs, urlparse @@ -272,12 +273,16 @@ class BuildQueue: job.started_at = time.time() job.message = "Publishing site and search index." self._current = job - ok, message, log = run_build_commands() + def append_log(chunk: str) -> None: + with self._lock: + job.log = (job.log + chunk)[-200000:] + + ok, message, log = run_build_commands(append_log) with self._lock: job.finished_at = time.time() job.ok = ok job.message = message - job.log = log + job.log = log[-200000:] self._recent.append(job) self._recent = self._recent[-20:] self._current = None @@ -643,7 +648,7 @@ def save_upload(filename: str, payload: bytes, page_path: str = "") -> dict[str, absolute_url = f"https://zainezq.com/{rel}" relative_url = relative_asset_path(page_path, rel) is_markdown = page_path.endswith(".md") - insert_text = f"![{target.name}]({relative_url})" if is_markdown else f"[[{relative_url}]]" + insert_text = f"![{target.name}]({absolute_url})" if is_markdown else f"[[{relative_url}]]" return { "url": absolute_url, "relativeUrl": relative_url, @@ -654,7 +659,35 @@ def save_upload(filename: str, payload: bytes, page_path: str = "") -> dict[str, } -def run_build_commands() -> tuple[bool, str, str]: +def parse_upload_form(content_type: str, body: bytes) -> tuple[str, bytes, str]: + if not content_type.lower().startswith("multipart/form-data"): + raise ValueError("Uploads must use multipart/form-data.") + message = BytesParser(policy=email_default_policy).parsebytes( + f"Content-Type: {content_type}\r\nMIME-Version: 1.0\r\n\r\n".encode("utf-8") + body + ) + if not message.is_multipart(): + raise ValueError("Upload form is not multipart.") + + filename = "" + payload = b"" + page_path = "" + for part in message.iter_parts(): + name = part.get_param("name", header="content-disposition") + if name == "attachment": + filename = part.get_filename() or "" + payload = part.get_payload(decode=True) or b"" + elif name == "pagePath": + raw_value = part.get_payload(decode=True) or b"" + page_path = raw_value.decode(part.get_content_charset() or "utf-8", errors="replace") + + if not filename: + raise ValueError("No attachment was uploaded.") + if not payload: + raise ValueError("Attachment is empty.") + return filename, payload, page_path + + +def run_build_commands(log_callback: Callable[[str], None] | None = None) -> tuple[bool, str, str]: venv_python = ROOT / ".venv" / "bin" / "python" venv_pip = ROOT / ".venv" / "bin" / "pip" commands = [["emacs", "-Q", "--script", "build-site.el"]] @@ -667,20 +700,33 @@ def run_build_commands() -> tuple[bool, str, str]: ) commands.append([str(venv_python), "search-index-json.py"]) combined = [] + + def append_log(text: str) -> None: + combined.append(text) + if log_callback: + log_callback(text) + ok = True for command in commands: - combined.append(f"$ {' '.join(command)}\n") - proc = subprocess.run( + append_log(f"$ {' '.join(command)}\n") + env = os.environ.copy() + env["PYTHONUNBUFFERED"] = "1" + proc = subprocess.Popen( command, cwd=ROOT, + env=env, text=True, - stdout=subprocess.PIPE, + bufsize=1, stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, ) - combined.append(proc.stdout) - if proc.returncode != 0: + assert proc.stdout is not None + for line in proc.stdout: + append_log(line) + return_code = proc.wait() + if return_code != 0: ok = False - combined.append(f"\nCommand exited with {proc.returncode}.\n") + append_log(f"\nCommand exited with {return_code}.\n") break message = "Build complete. The site output and search index were regenerated." if ok else "Build failed. Check the log below." return ok, message, "".join(combined) @@ -1058,9 +1104,21 @@ APP_HTML = r""" return String(value).replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[char])); } + function previewImageUrl(src) { + const value = String(src || ""); + if (value.startsWith("https://author.zainezq.com/assets/")) { + return value.replace("https://author.zainezq.com/assets/", "https://zainezq.com/assets/"); + } + const relativeAsset = value.match(/^(?:\.\.\/)+assets\/(.+)$/); + if (relativeAsset) return `https://zainezq.com/assets/${relativeAsset[1]}`; + if (value.startsWith("/assets/")) return `https://zainezq.com${value}`; + if (value.startsWith("assets/")) return `https://zainezq.com/${value}`; + return value; + } + function renderInlineMarkdown(value) { let out = html(value); - out = out.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '$1'); + out = out.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_match, alt, src) => `${alt}`); out = out.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); out = out.replace(/\*\*([^*]+)\*\*/g, '$1'); out = out.replace(/\*([^*]+)\*/g, '$1'); @@ -1173,14 +1231,15 @@ APP_HTML = r""" } async function refreshBuild() { + const wasRunning = Boolean(state.build && state.build.running); try { state.build = await api("/api/build"); renderStatus(); + if (wasRunning && !state.build.running) await refreshPages(); } catch (err) { statusBox.className = "status fail"; statusBox.textContent = `Could not refresh build status: ${err.message}`; } - await refreshPages(); } editor.title.addEventListener("input", () => { @@ -1224,6 +1283,7 @@ APP_HTML = r""" const saved = await api("/api/page", { method: "POST", body: JSON.stringify(payload) }); setForm(saved); saveMessage.textContent = "Saved. Build queued."; + await refreshPages(); await refreshBuild(); } catch (err) { saveMessage.textContent = err.message; @@ -1416,6 +1476,7 @@ APP_HTML = r""" pageLinkPicker.hidden = false; pageLinkSelect.focus(); } + showPageLinkPicker(); function insertSelectedPageLink() { const page = state.pages.find((item) => item.path === pageLinkSelect.value); @@ -1509,24 +1570,12 @@ class Handler(BaseHTTPRequestHandler): def do_POST(self) -> None: if self.path == "/api/upload": try: - form = cgi.FieldStorage( - fp=self.rfile, - headers=self.headers, - environ={ - "REQUEST_METHOD": "POST", - "CONTENT_TYPE": self.headers.get("Content-Type", ""), - }, + length = int(self.headers.get("Content-Length", "0")) + filename, payload, page_path = parse_upload_form( + self.headers.get("Content-Type", ""), + self.rfile.read(length), ) - field = form["attachment"] if "attachment" in form else None - if field is None or not getattr(field, "filename", ""): - raise ValueError("No attachment was uploaded.") - payload = field.file.read() - if not payload: - raise ValueError("Attachment is empty.") - page_path = "" - if "pagePath" in form: - page_path = str(form["pagePath"].value or "") - self.send_json(save_upload(field.filename, payload, page_path)) + self.send_json(save_upload(filename, payload, page_path)) except Exception as exc: self.send_json({"error": str(exc)}, HTTPStatus.BAD_REQUEST) return diff --git a/blogs/blogs-list.org b/blogs/blogs-list.org old mode 100755 new mode 100644 diff --git a/home/backlog.org b/home/backlog.org old mode 100755 new mode 100644 index b8d5498..eae2199 --- a/home/backlog.org +++ b/home/backlog.org @@ -1,16 +1,16 @@ #+TITLE: Backlog #+OPTIONS: num:nil toc:nil #+DATE: <2025-11-08 Sat 11:08> -#+FILETAGS: :emacs:website: -#+NO_SIDENOTES: t +#+filetags: :emacs:website: #+COMMENTS: t #+SLUG: backlog - * TODO - Give lima accounts to all the services - Figure out a solution for the shared calendar - change the font +- Use zero trust cloudflare instead of nginx auth + * DOING - Database permissions (roles, accounts and schemas) - how pipelines work diff --git a/home/notes.org b/home/notes.org index 19f9b63..430821c 100755 --- a/home/notes.org +++ b/home/notes.org @@ -5,6 +5,13 @@ #+SLUG: notes #+BEGIN_EXPORT html +
+ + +
+

Loading notes…

diff --git a/lima/index.md b/lima/index.md old mode 100755 new mode 100644 index ad3430f..ad47b50 --- a/lima/index.md +++ b/lima/index.md @@ -9,3 +9,8 @@ I made quite a few changes. It all started when I realised that not everyone kno - I probably didn’t explain it as well, but you can create folders and files under the `lima-website` directory. The files must have a `.md` extension at the end (markdown). - One other thing, a more personal one: what do you think of all this? am i doing too much? am i doing too little? am i overengineering things? am i forcing you to do something you dont wanna do? these little trinkets work for me, but i’m not sure if it would work for someone else, so at any point if you have reservations, let me know okay? + + +![2026-05-09-screen-shot-2025-11-10-at-18-02-10-fullpage.png](../assets/images/hzone/2026-05-09-screen-shot-2025-11-10-at-18-02-10-fullpage.png) + +This is a test diff --git a/posts/career/career-list.org b/posts/career/career-list.org index dc34d42..4e470f7 100755 --- a/posts/career/career-list.org +++ b/posts/career/career-list.org @@ -13,9 +13,9 @@ See the categories: @@html:Categories@@ - [[file:restful-api.org][Restful API]] @@html:@@ @@html:@@ @@html:@@ ** January 2026 -- [[file:database-permissions.org][Database Permissions, Roles, and Accounts]] @@html:@@ @@html:@@ @@html:@@ - [[file:monitoring-and-logging.org][Monitoring and Logging]] @@html:@@ @@html:@@ @@html:@@ - [[file:pipelines.org][Pipelines and how they work (as well as CI/CD)]] @@html:@@ @@html:@@ @@html:@@ +- [[file:database-permissions.org][Database Permissions, Roles, and Accounts]] @@html:@@ @@html:@@ @@html:@@ ** December 2025 - [[file:probation-objectives.org][Probation Objectives:]] @@html:@@ @@html:@@ @@html:@@ @@ -23,13 +23,13 @@ See the categories: @@html:Categories@@ ** November 2025 - [[file:airflow.org][Datamarts, Airflow and DAG's]] @@html:@@ @@html:@@ @@html:@@ - [[file:normalisation.org][Benefits of Normalisation]] @@html:@@ @@html:@@ @@html:@@ -- [[file:management-of-self.org][Management of self training]] @@html:@@ @@html:@@ @@html:@@ - [[file:wireframe-designs.org][Wireframe Designs]] @@html:@@ @@html:@@ @@html:@@ +- [[file:management-of-self.org][Management of self training]] @@html:@@ @@html:@@ @@html:@@ - [[file:requirements-features.org][Requirements, features, user stories, tasks, walking skeletons]] @@html:@@ @@html:@@ @@html:@@ - [[file:career-intro.org][Career Introduction]] @@html:@@ @@html:@@ - [[file:invest-principles.org][Invest Principles]] @@html:@@ @@html:@@ @@html:@@ -- [[file:retrospectives.org][Retrospectives]] @@html:@@ @@html:@@ @@html:@@ - [[file:lean.org][Lean]] @@html:@@ @@html:@@ @@html:@@ +- [[file:retrospectives.org][Retrospectives]] @@html:@@ @@html:@@ @@html:@@ ** October 2025 - [[file:owasp.org][OWASP Top Ten]] @@html:@@ @@html:@@ @@html:@@ diff --git a/posts/posts-list.org b/posts/posts-list.org index 7deb1b4..25438f7 100644 --- a/posts/posts-list.org +++ b/posts/posts-list.org @@ -4,12 +4,7 @@ See the categories: @@html:Categories@@ * Posts: -- [[file:career/career-list.org][Career List]] @@html:@@ -- [[file:posts-list.sync-conflict-20260509-011812-NE5VEIB.org][Posts List]] @@html:@@ -- [[file:posts-list.sync-conflict-20260509-011752-NE5VEIB.org][Posts List]] @@html:@@ -- [[file:posts-list.sync-conflict-20260509-011732-NE5VEIB.org][Posts List]] @@html:@@ -- [[file:posts-list.sync-conflict-20260509-005434-VT6366A.org][Posts List]] @@html:@@ -- [[file:posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:@@ +- [[file:career/career-list.org][Career List]] @@html:@@ - [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:@@ @@html:@@ @@html:@@ - [[file:career/javascript.org][Understands the Javascript language]] @@html:@@ @@html:@@ @@html:@@ - [[file:career/restful-api.org][Restful API]] @@html:@@ @@html:@@ @@html:@@ diff --git a/recently-updated.org b/recently-updated.org index 68e0d47..0c0f9f9 100644 --- a/recently-updated.org +++ b/recently-updated.org @@ -2,18 +2,13 @@ #+OPTIONS: toc:nil num:nil * Recently Updated (top 26 files) -- [[file:posts/posts-list.sync-conflict-20260509-011812-NE5VEIB.org][Posts List]] @@html:@@ -- [[file:sitemap.sync-conflict-20260509-011812-NE5VEIB.org][Sitemap]] @@html:@@ -- [[file:recently-updated.sync-conflict-20260509-011802-NE5VEIB.org][Recently Updated]] @@html:@@ -- [[file:posts/posts-list.sync-conflict-20260509-011752-NE5VEIB.org][Posts List]] @@html:@@ -- [[file:sitemap.sync-conflict-20260509-011752-NE5VEIB.org][Sitemap]] @@html:@@ -- [[file:posts/posts-list.sync-conflict-20260509-011732-NE5VEIB.org][Posts List]] @@html:@@ -- [[file:sitemap.sync-conflict-20260509-011732-NE5VEIB.org][Sitemap]] @@html:@@ -- [[file:sitemap.sync-conflict-20260509-005434-VT6366A.org][Sitemap]] @@html:@@ -- [[file:posts/posts-list.sync-conflict-20260509-005434-VT6366A.org][Posts List]] @@html:@@ -- [[file:recently-updated.sync-conflict-20260509-005434-VT6366A.org][Recently Updated]] @@html:@@ -- [[file:home/login.org][Login]] @@html:@@ -- [[file:home/guide/setup.org][Setup]] @@html:@@ +- [[file:home/notes.org][Notes]] @@html:@@ +- [[file:home/wird-tracker.org][Wird Tracker]] @@html:@@ +- [[file:home/status.org][Competency Status Board]] @@html:@@ +- [[file:home/services.org][Service]] @@html:@@ +- [[file:home/contact.org][Contact]] @@html:@@ +- [[file:home/guide/wird-tracker-guide.org][Wird Tracker — Technical Guide]] @@html:@@ +- [[file:home/guide/setup.org][Setup]] @@html:@@ - [[file:blogs/2026/05-may/ai-datacamp-08-05.org][AI Datacamp]] @@html:@@ - [[file:blogs/2026/05-may/using-codex-07-05-26.org][Using Codex]] @@html:@@ - [[file:blogs/2026/05-may/03-05-week-review.org][[03-05-2026] - Weekly Review]] @@html:@@ @@ -22,9 +17,14 @@ - [[file:blogs/2026/04-april/april-almost-over-28-04.org][April is almost over...]] @@html:@@ - [[file:blogs/2026/04-april/26-04-week-review.org][[26-04-2026] - Weekly Review]] @@html:@@ - [[file:blogs/2026/04-april/adding-more-wird-22-04-26.org][Adding another Wird]] @@html:@@ -- [[file:home/wird-tracker.org][Wird Tracker]] @@html:@@ - [[file:blogs/2026/04-april/sitting-outside-in-the-sun-21-04-26.org][Sitting in the sun]] @@html:@@ - [[file:blogs/2026/04-april/19-04-week-review.org][[19-04-2026] - Weekly Review]] @@html:@@ - [[file:blogs/2026/04-april/ending-the-week-17-04-26.org][End of week thoughts]] @@html:@@ - [[file:blogs/2026/04-april/16-04-26.org][Rambles]] @@html:@@ -- [[file:posts/posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:@@ +- [[file:blogs/2026/04-april/comparison-14-04.org][Comparison is the thief of joy]] @@html:@@ +- [[file:blogs/2026/04-april/12-04-week-review.org][[12-04-2026] - Weekly Review]] @@html:@@ +- [[file:blogs/2026/04-april/starting-new-rotation-08-04-26.org][Starting new rotation]] @@html:@@ +- [[file:blogs/2026/04-april/action-plan-07-04-26.org][Action plan to change teams]] @@html:@@ +- [[file:blogs/2026/04-april/weekly-target-06-04-26.org][[06-04-2026] - Weekly target]] @@html:@@ +- [[file:blogs/2026/04-april/making-notes-through-org-noter-06-05.org][Making Notes through Org Noter]] @@html:@@ +- [[file:blogs/2026/04-april/05-04-week-review.org][[05-04-2026] - Weekly Review]] @@html:@@ diff --git a/requirements.txt b/requirements.txt index 6f83e94..b8ba271 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ beautifulsoup4 lxml +legacy-cgi diff --git a/sitemap.org b/sitemap.org index 2c74332..e1aef81 100644 --- a/sitemap.org +++ b/sitemap.org @@ -1,25 +1,19 @@ #+TITLE: Sitemap - [[file:index.org][Home]] -- [[file:recently-updated.sync-conflict-20260509-005434-VT6366A.org][Recently Updated]] -- [[file:sitemap.sync-conflict-20260509-005434-VT6366A.org][Sitemap]] -- [[file:sitemap.sync-conflict-20260509-011732-NE5VEIB.org][Sitemap]] -- [[file:sitemap.sync-conflict-20260509-011752-NE5VEIB.org][Sitemap]] -- [[file:recently-updated.sync-conflict-20260509-011802-NE5VEIB.org][Recently Updated]] -- [[file:sitemap.sync-conflict-20260509-011812-NE5VEIB.org][Sitemap]] - [[file:wip.org][Work in progress]] - [[file:recently-updated.org][Recently Updated]] - tags - - [[file:tags/review.sync-conflict-20260328-203248-VT6366A.org][Tag: review]] - [[file:tags/life.sync-conflict-20260417-233423-VT6366A.org][Tag: life]] + - [[file:tags/review.sync-conflict-20260328-203248-VT6366A.org][Tag: review]] - [[file:tags/introduction.org][Tag: introduction]] - [[file:tags/learning.org][Tag: learning]] - [[file:tags/notes.org][Tag: notes]] - [[file:tags/review.org][Tag: review]] - [[file:tags/website.org][Tag: website]] - - [[file:tags/update.org][Tag: update]] - [[file:tags/life.org][Tag: life]] - [[file:tags/education.org][Tag: education]] + - [[file:tags/update.org][Tag: update]] - [[file:tags/insights.org][Tag: insights]] - [[file:tags/emacs.org][Tag: emacs]] - [[file:tags/maths.org][Tag: maths]] @@ -32,28 +26,22 @@ - [[file:lima/lima-list.org][Lima]] - home - [[file:home/countdown.org][Countdown]] - - [[file:home/contact.org][Contact]] - [[file:home/backlog.org][Backlog]] - - [[file:home/notes.org][Notes]] - - [[file:home/services.org][Service]] - [[file:home/status.org][Competency Status Board]] - [[file:home/wird-tracker.org][Wird Tracker]] - - [[file:home/login.org][Login]] + - [[file:home/contact.org][Contact]] + - [[file:home/services.org][Service]] + - [[file:home/notes.org][Notes]] - [[file:home/categories.org][Categories]] - guide - - [[file:home/guide/wird-tracker-guide.org][Wird Tracker — Technical Guide]] - [[file:home/guide/setup.org][Setup]] + - [[file:home/guide/wird-tracker-guide.org][Wird Tracker — Technical Guide]] - blogs - [[file:blogs/blogs-intro.org][Blogs Introduction]] - [[file:blogs/publish-pages.org][How to publish pages using Org Publish]] - [[file:blogs/blogs-list.org][Blogs List]] - posts - [[file:posts/posts-intro.org][Posts Introduction]] - - [[file:posts/posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] - - [[file:posts/posts-list.sync-conflict-20260509-005434-VT6366A.org][Posts List]] - - [[file:posts/posts-list.sync-conflict-20260509-011732-NE5VEIB.org][Posts List]] - - [[file:posts/posts-list.sync-conflict-20260509-011752-NE5VEIB.org][Posts List]] - - [[file:posts/posts-list.sync-conflict-20260509-011812-NE5VEIB.org][Posts List]] - [[file:posts/posts-list.org][Posts List]] - career - [[file:posts/career/solid-principles.org][SOLID Principles]] diff --git a/tags/learning.org b/tags/learning.org index ef43c84..fa15dfe 100755 --- a/tags/learning.org +++ b/tags/learning.org @@ -5,16 +5,16 @@ - [[file:../posts/career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] - [[file:../posts/career/javascript.org][Understands the Javascript language]] - [[file:../posts/career/restful-api.org][Restful API]] -- [[file:../posts/career/database-permissions.org][Database Permissions, Roles, and Accounts]] - [[file:../posts/career/monitoring-and-logging.org][Monitoring and Logging]] - [[file:../posts/career/pipelines.org][Pipelines and how they work (as well as CI/CD)]] +- [[file:../posts/career/database-permissions.org][Database Permissions, Roles, and Accounts]] - [[file:../posts/career/airflow.org][Datamarts, Airflow and DAG's]] - [[file:../posts/career/normalisation.org][Benefits of Normalisation]] -- [[file:../posts/career/management-of-self.org][Management of self training]] - [[file:../posts/career/wireframe-designs.org][Wireframe Designs]] +- [[file:../posts/career/management-of-self.org][Management of self training]] - [[file:../posts/career/requirements-features.org][Requirements, features, user stories, tasks, walking skeletons]] - [[file:../posts/career/invest-principles.org][Invest Principles]] -- [[file:../posts/career/retrospectives.org][Retrospectives]] - [[file:../posts/career/lean.org][Lean]] +- [[file:../posts/career/retrospectives.org][Retrospectives]] - [[file:../posts/career/owasp.org][OWASP Top Ten]] - [[file:../posts/career/solid-principles.org][SOLID Principles]] diff --git a/tags/notes.org b/tags/notes.org index 6d9fc80..3e2f335 100755 --- a/tags/notes.org +++ b/tags/notes.org @@ -5,17 +5,17 @@ - [[file:../posts/career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] - [[file:../posts/career/javascript.org][Understands the Javascript language]] - [[file:../posts/career/restful-api.org][Restful API]] -- [[file:../posts/career/database-permissions.org][Database Permissions, Roles, and Accounts]] - [[file:../posts/career/monitoring-and-logging.org][Monitoring and Logging]] - [[file:../posts/career/pipelines.org][Pipelines and how they work (as well as CI/CD)]] +- [[file:../posts/career/database-permissions.org][Database Permissions, Roles, and Accounts]] - [[file:../posts/career/probation-objectives.org][Probation Objectives:]] - [[file:../posts/career/airflow.org][Datamarts, Airflow and DAG's]] - [[file:../posts/career/normalisation.org][Benefits of Normalisation]] -- [[file:../posts/career/management-of-self.org][Management of self training]] - [[file:../posts/career/wireframe-designs.org][Wireframe Designs]] +- [[file:../posts/career/management-of-self.org][Management of self training]] - [[file:../posts/career/requirements-features.org][Requirements, features, user stories, tasks, walking skeletons]] - [[file:../posts/career/invest-principles.org][Invest Principles]] -- [[file:../posts/career/retrospectives.org][Retrospectives]] - [[file:../posts/career/lean.org][Lean]] +- [[file:../posts/career/retrospectives.org][Retrospectives]] - [[file:../posts/career/owasp.org][OWASP Top Ten]] - [[file:../posts/career/solid-principles.org][SOLID Principles]] diff --git a/tests/test_authoring_server.py b/tests/test_authoring_server.py index 9e314db..69aae75 100755 --- a/tests/test_authoring_server.py +++ b/tests/test_authoring_server.py @@ -103,6 +103,24 @@ class UtilityTests(AuthoringServerTestCase): self.assertEqual(server.image_dimensions(gif, ".gif"), (320, 200)) self.assertIsNone(server.image_dimensions(b"not an image", ".png")) + def test_parse_upload_form_reads_attachment_and_page_path(self): + boundary = "----authoring-test" + content_type = f"multipart/form-data; boundary={boundary}" + body = ( + f"--{boundary}\r\n" + 'Content-Disposition: form-data; name="pagePath"\r\n\r\n' + "lima/index.md\r\n" + f"--{boundary}\r\n" + 'Content-Disposition: form-data; name="attachment"; filename="photo.png"\r\n' + "Content-Type: image/png\r\n\r\n" + ).encode("utf-8") + b"image bytes\r\n" + f"--{boundary}--\r\n".encode("utf-8") + + filename, payload, page_path = server.parse_upload_form(content_type, body) + + self.assertEqual(filename, "photo.png") + self.assertEqual(payload, b"image bytes") + self.assertEqual(page_path, "lima/index.md") + class PageRenderingTests(AuthoringServerTestCase): def test_render_org_writes_metadata_and_body(self): @@ -244,6 +262,22 @@ class PageRenderingTests(AuthoringServerTestCase): self.assertEqual(saved["path"], "assets/images/blogs/2026-05-07-lunch.jpg") self.assertEqual(saved["insertText"], "[[../../../assets/images/blogs/2026-05-07-lunch.jpg]]") + def test_save_upload_inserts_absolute_public_url_for_markdown(self): + with mock.patch.object(server, "datetime") as datetime_mock: + datetime_mock.now.return_value = datetime(2026, 5, 9, 9, 30) + saved = server.save_upload( + "Screen Shot.png", + b"image bytes", + "lima/index.md", + ) + + self.assertEqual(saved["path"], "assets/images/hzone/2026-05-09-screen-shot.png") + self.assertEqual(saved["relativeUrl"], "../assets/images/hzone/2026-05-09-screen-shot.png") + self.assertEqual( + saved["insertText"], + "![2026-05-09-screen-shot.png](https://zainezq.com/assets/images/hzone/2026-05-09-screen-shot.png)", + ) + def test_save_upload_rejects_disallowed_extensions(self): with self.assertRaises(ValueError): server.save_upload("shell.php", b"