From 9a9d9e7447e88943745a66458dfb4bbc9c6f6fd7 Mon Sep 17 00:00:00 2001 From: Joe Julian Date: Thu, 23 Apr 2026 21:42:52 -0700 Subject: [PATCH] Add Firefox extension icons and gap review --- TODO.md | 94 +++++++++++++++++- browser/extension/icons/icon-128.png | Bin 0 -> 6053 bytes browser/extension/icons/icon-16.png | Bin 0 -> 1113 bytes browser/extension/icons/icon-32.png | Bin 0 -> 1815 bytes browser/extension/icons/icon-48.png | Bin 0 -> 2521 bytes browser/extension/icons/icon-96.png | Bin 0 -> 4700 bytes browser/extension/manifest.firefox.json | 20 +++- .../archlinux/keepassgo-git/PKGBUILD.tmpl | 10 ++ 8 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 browser/extension/icons/icon-128.png create mode 100644 browser/extension/icons/icon-16.png create mode 100644 browser/extension/icons/icon-32.png create mode 100644 browser/extension/icons/icon-48.png create mode 100644 browser/extension/icons/icon-96.png diff --git a/TODO.md b/TODO.md index bd73621..feef56d 100644 --- a/TODO.md +++ b/TODO.md @@ -130,6 +130,98 @@ These are important, but they should likely move behind a dedicated settings gea - Accessibility preferences: future display-density, contrast, reduced-motion, or keyboard-focus tuning should live under settings. +## Upstream Gap Review + +This section tracks explicit feature gaps against the source-level behavior of: + +- KeePass 2.57.1 +- KeePassHttp +- Keepass2Android + +These are not speculative enhancements. They are parity gaps relative to the +stated product requirement to cover the practical feature surface of those +upstream tools where it fits KeePassGO's security model. + +### Stage 1 + +- Android autofill parity/completeness: + close the remaining gaps in Android autofill behavior, including broader + page/app detection coverage, stronger approval and visibility UX, and more + reliable fill behavior across real-world apps and browsers. +- Android fallback fill workflows: + provide a non-autofill fallback comparable in usefulness to KP2A's keyboard + and share-driven workflows for apps and browsers that do not cooperate with + platform autofill. +- Browser extension save/update: + add the browser-side save/update-credential workflow after successful form + submission, not only lookup and fill. +- Search and matching controls: + browser/API result behavior does not yet expose KeePassHttp-style controls + such as best-match-only, scheme matching, and sort preferences as a finished + product surface. +- Unlock-request workflow: + KeePassHttp has an explicit locked-database browser flow; KeePassGO still + needs a polished browser-visible locked/unlock request experience. +- Android share/intents: + browser/app share-driven lookup and open flows comparable to KP2A are not + implemented as a full user workflow. + +### Stage 2 + +- OTP/TOTP: + implement real OTP/TOTP support, including storage conventions compatible + with common KeePass ecosystems and usable display/copy/fill workflows. +- TOTP product surface: + KP2A exposes TOTP directly in entry and list UX; KeePassGO does not. +- Browser-returned field breadth: + KeePassHttp can return string fields for browser consumers; KeePassGO does + not yet have a finished policy and browser UX for rich field return. +- Placeholder and field-reference parity: + KeePass-style placeholder expansion, field references, and related command + and URL override behavior are not implemented as a product surface. +- Offline/work-offline flow: + KP2A has explicit offline/cache-oriented remote-file workflows that are more + mature than KeePassGO's current user-facing remote behavior. + +### Stage 3 + +- Desktop automation: + implement desktop login automation comparable in practical capability to + KeePass auto-type, or replace it with a demonstrably superior workflow that + covers global invocation, selected-entry invocation, window targeting, and + field sequencing. +- Trigger system: + KeePass-style event/condition/action triggers are not implemented. +- Import/export breadth: + KDBX load/save exists, but KeePass-style breadth for CSV/XML/HTML and other + exchange formats is still missing. +- Multi-database lookup: + KeePassHttp can search across all opened databases when configured; KeePassGO + does not yet have an equivalent multi-vault lookup model. +- Remote backend breadth: + KP2A supports far more remote/file backends than KeePassGO currently does; + KeePassGO is still effectively WebDAV-first. +- Plugin/extensibility model: + KeePassGO has integrations, but not a first-class plugin model comparable to + KeePass. +- Plugin ecosystem replacements: + QR transfer, keyboard transport, and related mobile integration equivalents + do not exist in KeePassGO. +- Emergency and recovery utilities: + emergency-sheet/key-file-backup style flows are not implemented. + +### Immediate Product Questions + +- Desktop automation: + decide whether KeePassGO will implement true auto-type, or a different + security model that still satisfies the practical workflows KeePass users + expect. +- OTP model: + decide the canonical KeePassGO representation for TOTP/HOTP so desktop, + Android, gRPC, and browser workflows can all target the same semantics. +- Remote breadth: + decide which non-WebDAV backends are in product scope after WebDAV. + ### Exit Criteria - The main workflow screens prioritize opening, browsing, copying, editing, and synchronizing credentials. @@ -269,7 +361,7 @@ Exit criteria: - Tests cover clear/reset transitions. - `go test ./...` passes. -### Segment 10: Template CRUD UI +### Segment 10 (stage 3): Template CRUD UI Scope: - Create template. diff --git a/browser/extension/icons/icon-128.png b/browser/extension/icons/icon-128.png new file mode 100644 index 0000000000000000000000000000000000000000..8602f7703005aa62b26af2b138356308882ae1a5 GIT binary patch literal 6053 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 K?7gy0)c*j87%Kk& literal 0 HcmV?d00001 diff --git a/browser/extension/icons/icon-16.png b/browser/extension/icons/icon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..e976c5ec62a12d31c2943e2c51e96bbc106cee3f GIT binary patch literal 1113 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=IjczVPIg~6W|l#3RGb4mu%~kn2=L9Y1Xm{Gnd-=CA$Qt zdj-ea`zD>}*KrQcY|eE}t)FA#o08YPDyL(4R_l_)%4s@yNkBCaD{|VG<#sI3?Od7Bw7@Ma$KDSr4pf{{H`_fT z-_|?9As_|lFOU}h6wk<~ z<@LLdkDk4nzhd+2_aAFpdpv^TY<&~U8YjGZ_u;_ta{+OM2TojgeRIdN(-@Py-CZU>WWEowg|omTvY3HEwjG2S z`=5SH1q!m4c>21szhaSKWVfhY&OZw%q*~${QIe8al4_M)lnSI6j0}v-bPY^&4GlvK z%&ZK}tc)zQ4GgRd3>KFJF`;P4%}>cptHiD0lIE*@Kn)sj8%i>BQ;SOya|_^lj7&ld z46O{ztxU}zmMpdE6$I*$1nCLRPb(=;EJ|f4FE7{2%*!rLPAo{(%P&fw{mw=TsOYh$ zi(`ny<>Z6}7UsxEjvEnj+i&aBC? zuQgl1u-nluFRsqfu`V%iqau4i!{rrAwyfE+XwjxsyN=D^);N$G6div5!i^hO?p(?` z#Vqo`G&}qKi#M;{y?krD{Q)!Ahv=xt+h6==Se(3e?jB=GcLT%z#gjL8ub#b|{fItK zlhYxkd2#pb0`@mHXf!uSY~R7s!_71)=#r6u7=!G3!~4vC^}2!HW$<+Mb6Mw<&;$S{ CCbvld literal 0 HcmV?d00001 diff --git a/browser/extension/icons/icon-32.png b/browser/extension/icons/icon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..c1faec1cc1914af67115b99145fe2d432f750df2 GIT binary patch literal 1815 zcmZ{lc{CJy8^?b$cGhDh>qSo6y8@HZ2^eZ0DzJJ0QbP6d<7s30l=as0I0_R$b~#%b8Tx#B_qKso8KAsKUPxC2vwXk}|5u*fS95ip2-CZ2m>og`W~6Me8m z9LgJyJ6J#mp`!;!oP{HiP6#~|QV*qLpou`B5Qq|@BlLfOz+j(SzES@l7&^V!dH|gI zH-UI75JwYUzxLrPI;M-Lc}dftdc5W%nli%g7E7F9K(TmQXwa*pKv$B^8!1vW-*%m{*p_Bwo9Zj zgve0l%S^?YI1o*YWx#mbDu!x6SdNIlT*UX4S5Jl{0)nCQ@f<*|4r$S5=P4DXHqhua zW6h74Z5q$}`0dJ;EIQxhGW4U+q{w~Vx>6boWUbjO`UL;NCsxi0xmrvfy_0u%bzYAB0i_6M}6$0mFP#u(FS+kiYMaT4;lE?4rs%)V}+ zOAqkd<$tk{C7;ahO<2h3?oNWrd#}c-j38X*#Inc66py#Ej|Z`6zY$S}t`}Z~*ZPhK z$1yjKjgsQ9G$T3s=+x2h*l11BZ$eb01JtvsbdEbms*X|O2`=zuX?uXl;+GSB^RF92 zf8STPOwaE?ektK`GdM?wv$hrUm2POxIz7NyD}^X0T^DQZ|CoaX9_P1Fd8lzemoQ~Z zu04Eu?*$+RwB`KD*)Mn`w&`^Y4Fho!HS=2oc+N_Y#|9&>X@jxih1Vz>B8I)HU+dBvz7e;(xv{%O zE6K(nRp?t)?wdbwz=7&rQz1_f(4Pn~Dv)~>dGx2OKAm+tNlLb6ZpsKl7A=`(z8y(G zJ6qht7-Ntc|0s0Ho6DfrWmP+7eNqccSvR7b+YHyQhq^A2z$h7O(Qm$WX7q->#1N79ZwsqX;@pdjlR&h~E-IB#uRDAJJ zNymSX_j;;cntxBO%l9~}{@w^g^&FBKD!6NCB4IpLG81*Ydd9O#)!23E_SVX1UzX7T zq$Xk@Xza%I-(YnO`Ct2gKF^(o6c~jAHJv>qthRj-z?BQ>p>A(TV%m>R=H;knpN{`@_2gTj%fgUG8`}wV*q1W*lGcl&HpI#%thwL}qRN7n24J{-SiHzITh$ z>duK3?>MA_{SDXcoin4G(oLJvqc*}voG%s4=j_SnERf=9+i}iy4B2l3*Q_rqP(-2A zY1d=W?3+7fsnnDn_Y<~3>d?$ngU-sHa}rvgnk%3R6mb@I7k+idKqlKOL^P& heZkB92kS@UmdfwCST19(=kP-SD+@dGYE#cU{{a^jLOTEe literal 0 HcmV?d00001 diff --git a/browser/extension/icons/icon-48.png b/browser/extension/icons/icon-48.png new file mode 100644 index 0000000000000000000000000000000000000000..2144944d779fe3a01a70a858484791f5a0c8a8b4 GIT binary patch literal 2521 zcmZ{mc{J4PAIHBl#+b3hSTEsPlAW<+7s)b2F(Gc$*v1lJj55}-FWEw}-ANNhV=Efj z$|Oq{MSf+f5h7`DF^LkUJDuM-_nhA!zw?~ud7tzCd|sdTAJ6m0lk0lgL5N?59{>O$ zN0cp^tH@s)2IZdTz`NO8Q3ybxT>v2dC;$*M0N@ALB7O#dSZ?DA1^~<|06;3LrpL{K zTY&nXal0X0_Y?4jkJ-5+Io8KNFy^nBQt#yO(fC`iM)eHgZ~GJhztzH68=9h zrM~i*3#k2@fDerbioyFuME%R?8@eO)%#g-r$Bh0PQg2p(;4;#`n6r^s{8c|(5ODSC zRh`hwmtq3^qJnfHalzH=7BT<;OL4S4;T|&kcjcvg_h9Lfl#TB3%CQ$~ydvs1B?R1S ztrawN3}<*~ikKl!p~jZm(`O2Xg~L|)4g&r2?+-ggXc)cAaT$80B%0~P5A#fw9IK~a zz+~ez$6ls5}$ewA{|8e`*tZWPZq#1yICzT-r^wL5n=+-ls-ToF{ew<>le#y3P}Tx zjwjYCf|}oSNw6FKp^bc>Ktgmd<|q<0nZ6f351ka;=QDxUK;9AEf4ahW>oRyw z0#w*!e-_Vwzh^dW$oUiGGR?+30!oq4f5*U~0r zG5W5@yu2V_gtMT!is)P87fL{@!0X{U8;-7zXN!HW*4(9(ns{L&29dUVLi35R6j4 z+j4rdpe+(hSR|KRdY!9*b-p#)oIqi(37Df|>qi6^$^p{yE=wFN;kXM|K-k<1Jy;=s z|JLTSJhxE;#jppuox6jT#$=?f_azow+=xqRUhtH*W*8nRA#_+h$%v+*tldT(T$~)W zWc>afRRMfZ7d~ZAT&C;}r~tpR4CZD=zlN52?^^Tpev@DLQBWOFl9>mv;{=HlR(*xM zF~J`Q>4p$EwLuhq7+AAP%x{=JLZyNyUsVPE{1D)L%czn~JLX(vLTX|#-Ci?c#m{#X zRQ9(wvP}s+aOtwYh!K>sI5gTSNL0A>k2JDc9hwDNl;BXP8d+}9F0$stzEGYLV@~v| zIc@$FIW=QGA4U*MRqEaqJLSBEwg>1P-^R4p4}~A36v@U)dq8sR1?w_mo60xu-!0u7 zH4!7aikqQ*@%SBk%kbX@o5(|=INzK1{KWgkb2D;B_E#H1{od~6oX`MgJcWY2`a*QJ zmIZ5gdRh^O_KG_rN>`kf>j$HKkM|}YYr3he<5^vntQqSgrLIzx+L|P6GBIH!l;YZky2>!%;&cfa-_damyT5`&|%rE@vo3gKc(xa zNE+`_nbY2cz6bj^c2|GppBJnuosCA$kWvWGnl_379|mvjU7C=04NtOTNY!Yt{2!SS z=5g)!T-IaPK~r1Ls>_7~Gn_j4TA2xvvkw|u9BZlkg^Pu9)=$LkK>LQr5PY0;>`z)#`IqbL*q}QWCC`MVF(yYd=CKZ{%+CISUdn`2DejYx zfQz;xDIRCAxDxgQF3B-CLauoFVLo3EkhQ?olv1i;EScBvly&ZdHYGIVraKgNgg%vt z-xioj%*(xdj^NKx?^8;xOF)`b2217HRLJ6L7_jM6wBxS&yv0#=L}(OE z3|=4|sN^>F2fHNICr!&eCt5QO6nz<6swVSLZ7&Axc*|6J`J7_)#o=u&A4Plout5Vr zrMAy=_P#H_6vGF%57CsFrOI`ew7PyCclQ|DI$|RI@$~`9-2%Zj_naI0u>&qkF)Kw+ zy+PjkG<_sec3-NpxnJjV)$q#FE%JT8WMryJBVusi_u7DHJwl~aa)+2|$a|8iG!p*C z)B>;!grs+O6`uW)ze}-oC+amBCI=S`0E6IH9ZN5_ZSQ=* zxF8e^QR9O-8IBj>FK4{Zj#n(l-$|+4|K10MfEoAyT5kWCpzqZ!uhqdfX81N?UVDXd znyewYeU*9wTa3xTD`mL}`VS(JHfC|{4_;)RO4t+Hc|?Fr#JKW%OSI#+j70%uQB9PR zOq)G;DkeJoFmt@LuX1Tb_p!Z~lo$38qjMkTG`GEXu2t%x{PG{~zH^E?Z)o?n;{s8^(Pknb$+AvdT(G zKBO(}h@kgnHM0bs40A!8hOruPwToz>E54+zSf-jOA}k^swQafa(ooJt0FgUPgg@yn zOpiGKv8T7IJbXAde02M}{~#Z~aq3C>HTo_B1OuV-`p98zZ?MTl)KFpm+lel)`+~4< z+$%B^_fT$TspaL7sa=I0U{?{}26r4CG=GkMp|<*b1)4RWOWGC1o`KrAA#Ca-><-cc zysIr3@3rb@#7vq(k{@cp*0jYYwnt+t7vzF(J(H=nvyeuU((|zbZjHyokArqT+g^-*|#fkY??h8zdR+ zuG=D=l|>=(A(^gasu?1y#JCh<`Pq?sUwBGxKsi|#7qf}`QJF=sT1=7Ufh^lrt}x&Z zOEKIaIHc#k7O-pRDwLcMVM-8Zj!XE&f)mnmeup*>RG{fknA>@GODs8mFYo7f9ja;# zSi&j3hv~wtr_W;_cW!@lYffzCQRE1Q^Uabs4p;cuCpv@pca}CdHF15C6S0$DMRt8W z1snnju&vAN&W?@v-SBUxY}^W`D3nvYhd6DsXiv!Q^qIRd#`3J5#;V~=1J$xB`0qIOOhfFCyi5E20ZoDrdrUjTp?3IOxVYLl*!uqegh}4tZA1dk ze=~SGxS%nfmM(7ppQMhA0e^YO;&U0q-)B2@n5g4zc&MrYcN-9MigK#|qDMXqqWi=uN!9pG zLF9IH$vY@7Bk0Ks481gm0^|1zz&K#|rXb+WFF%mSsK50fN)2H_vPSb!)$^4Mg_zd0MJ)+?UR zcmlF+f(^7WUg^^N$M%%abE|1_$A@TDeTGL;C&(GyDcc_&_>3(&2enKrhDe;ng;Lf5 z--6~tk3(`hg6QtrYwKF4l5jZZuu(G7g9KaGb)WB_aoLVrvgTQA0LXtyAnic)Sn)vF zf>1d2u$M}f@)VGmFU}zQ01)4??w+C58xfNBbSV^lb7Briq9IG6O*+~uf{Y72?V!lF z8umA0Xxbmf_hBQPyF@Ib_O(r_#`(kDZ)KZd>wev#*Y40`(Nx#r`jBV@6d`UDA&U{F z&L9Ez88{|aZ}es$K8iwkmw7(j8FO~&5iuoIK7v}4+;b?vM1SmmWukZ&b>~^qSGC(K znQ7lL36<5UvC$z%kzft7!jUn>eSsw5ZgtyhvP4|SO2lh2Y~!1r_u=mpb5{92%O zzh2AhjU!aFAAOr)*V1~$RszxP6sh&gm z_xMZV7nRiPDEhprb=h}hxFF+mG!$pXXA*Xpf!Lm5h31&1EItrW0kB!8u0Rd=`dtMC?|*bb07j57LJ0v%I9KuYNPiUtk|;I6WAk zqOKIfWZQZW7XDcixNsI7$?9zNSsMIal4)OwY?kRN1 z8f_TU)BF?il#|th4rRn!&PX=v7LemNqD;R1{UMljyuHHe+Kf||Oq~|*S-bb9_H@VP zh|?gIiBtuaq&v@V>cR5V%v~tmKq^$fQ%>xan`HNeuTD5s>&c+4SpZtZWDB?o!L59{ zN*fW?t=xDuZ9XLB`f^I!R$Lc7Q+f{L6(~2Q16FMb2b;m~r3*4N$Bc$75jZ3}QtNy? z4~SK*H0>tMaUmM3hFHymvxlAv7B!Rv`xYXYe#A3QIV{$?f|RAD>FmO4p1eDf&NLgPI%kR` zPNWc`(&5caJFuE>-KvlIP{0EU3k75^&Gr7xZN@-oV5yHYD!uC0d#BA;&dTqzPT|rE zNx>>kAr>-JE<1N`P*WUO97Jw8{*;RuNFRzQu$S=UIlm7wQB^?Z3_7em(5C~MI60P; zqWtljHw-$2&o1I1xi5s|7ku1)y`N56`n`o}KM!VvmQISlF{?|RcWo?NPTMrgQl^Wd zV*Rlc^mi|biA{6wwBmaT$(N8ZJNAc3A5*_<)RJVX&P;bTHNZm)b@W7OxoP%Rnoj$G zh&yG-qR*zQMc$+dKSBDQDRj6#kIh0Os1RxPSuqTzzzKD!nhL+-6BerfoUwuLoi|8O6 z@BdBTk@^6%K0{80ZbFEc!**o3Ce6IpORPE%+_0jX6?hwVAs@#(0hxK>%V?_Lyxx`Q z{ph_EUo7D5Sl?B+z_#38Pd<+F7HMPEdWlo}=&kbfsp$m~`&3;~ZPlqJe_HJi(Wu~E z=LW)exdIm+KPnnn1&||fwubJ;Eqww|W>UiV zH7>}p%HXuIzpR|Oqqz!KM`xy@xl$=xRZa0K1#g-mw<`^;QD2q~BLm4)G~gkj zqgA^(FlXafJyeD@RlHC{SSK^QxW1&e+&_Y@AtXi7TLD~oM^2a<$mJ3SAfAcs?a~R7 zN-@N0YNvfAscaA8B!I(ntnm|pcX*@yCNlDkbuM$;qXBiB2W!dKoARZ|yA?ui^D4P=@h`sRlehpYvTTEkZ z`JI{RK;PnBY}hXL8V54D!&Evw>A6mEq?Z@hAVex|LEERO^Rix918xytP*9bXb}xNz zn_xD2Dv!U5#NTB-kS&fNV&i&Gxvc3lGO4oRPQ-r3ctNUp$)z@$$35Y#TQi1*Fthm!s*lcRPD<{8mS=hd;<&P= zc${{tqV!g6txtp09Gx_`~ZkiF|!O4|s ze<_U(iWc^LH9furel&YypsFuckWf(2mQJYn{5mfEKC|$rNfXS(L1cjcNP_6s864XM zMLc;ga0P*#5t-|xH5|A50^PeAc5*|Bf5@C#|hx z*Pf{ev6CE3&_u^~v5Jzl@(X@-trkkR`THI`%E9c?(zv-~8zFQNEF9n9$lUEtFX#Lv z+rO&sHKFs~+g3AqmpLM?;+hdgbEBpfnjc^rfMPnO_WJ})7Z^Lk9-QLDVX-yQMaEm_ z|(8ECxShw?S&x>x4G2-gEf$oLU5NppVM!l-eqYjZ)pv? zM>%->O9Q!ucgb>+n{-uMHU?z2A^F9Gvo4t1`!z_E2`;(4PcV>6l;d;Wim|we(98Ei zQi$pRdH!IoANE{gHXydXUfoi4yE@Ly=oDRUw{5yPuUc=x{n+MLgY(h-?_0_(vt@u` z1eH#(4bw)ny5$%*`ZWS^asj*uWqTdVo0n7{w=z5X!DcidnMltO?e%H}&prF*oYD$a zUkvkMw9Ot0&_@Arxg^$$kJG&p4e)mhzanD4H}N;G6w+NOCMlv)#Ri%sy|X+gvsd8@ zFS@1YV*TX>IIu29_8yc}pKfB~5r5;t5yYuV;YsrFb=1#l_*TGG#}Y5P62_&a*gIT@ zPAN=PVPjxth}AQGp(dS~kHp95A{qW1n)j0L4gcz|4Q&S{uB@@dQZbWJb+erP*x_t$ z#xA$Dt0~u?h8L(!e&~K&welTZ7j#2gzf3B5wdR<{zzUO9QK1cIp%}_o2D?hHy+)evCH~fX}qc{ z#yV=Es%s$QS1rNMsDwKPdBO@*=oFFBsOBHf8o9%=arkKQehs~K^!%=W$R?((JEkZK z`l^U?<;CMR#a~;4HF&<)aWKZNpIV)|T(dJRlrmy1(BJeI?`5-CEI9HKuHiIWY3c5k zhiBFE5B;8hX`64mCfAh-6tBivgE{nR7pgUbQJ#@C6*4L|Y0(jJ?L+a-(w`%>w&fj_|1Q0mjcB z6+n3O_JmqqU-2yVKeAb{eZJHo#2%CA8gy-^>~yC(MGpJ`M!R3-hN3er=HC*8d3}yH zx;=R$4@!o9)O>jqMgU)h*g0N>*&Vj#L~YeLT*6lbv!Nrh3m2_#4dlF}z4{Ji*=OAk_ZNz3+%aciGcZnAnT_}YvqIv|iww)s@2#0~Xuc3Ya5%^B!1gwA z0vvuyjLbLl`pEMayW(tG%OTD=-T&~XDZ?&zj;}}y%2b~tbx?E#hbQ{xXs-o>p@T|T z@sl|9E$Xc06+7rVq?cz%8pw~LS{f{;hKl#e?(qoyOO;dLGBFO{l8iv; zQw8EHn6gLBER5S+V+>~E)Hx8d14>|Kz!m*TJ&$)*g#@R=&cT~Mk956fND4Ti{k^#g zew+`LZ<=0Rgzs7T_M2|z