From f905444ccf4b4fd01879aec89baee87d794ef22a Mon Sep 17 00:00:00 2001 From: Nickolaj Jepsen Date: Wed, 20 Aug 2025 10:49:33 +0200 Subject: [PATCH] feat: add llm --- modules/programs/default.nix | 3 +- modules/programs/llm.nix | 50 ++++++++++++++++++ ...067db56399fe2fbe8a7518d8db-llm-api-key.age | Bin 0 -> 652 bytes ...da13a1f654ab32cea0102501eb-llm-api-key.age | Bin 495 -> 0 bytes ...c350d513375346f5cab8cbc4ca-llm-api-key.age | Bin 0 -> 575 bytes ...ae3b7c469613cb81ec6a868a96-llm-api-key.age | 8 --- ...322b7240b3eea35ad9dab11832-llm-api-key.age | 9 ---- ...461da4e405ecdef56b69d89-arr-basic-auth.age | 8 --- ...461da4e405ecdef56b69d89-z2m-basic-auth.age | Bin 414 -> 0 bytes ...9c0e5df7cd4a9ff33521c95be9-llm-api-key.age | 8 +++ ...c350d513375346f5cab8cbc4ca-llm-api-key.age | Bin 0 -> 612 bytes ...ae3b7c469613cb81ec6a868a96-llm-api-key.age | Bin 427 -> 0 bytes ...b50ec4995ea64775b8153372e8-llm-api-key.age | Bin 0 -> 681 bytes ...d3be8bc97c3af769254574e9ba-llm-api-key.age | Bin 463 -> 0 bytes secrets/llm-api-key.env.age | Bin 492 -> 734 bytes 15 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 modules/programs/llm.nix create mode 100644 secrets/hosts/bootstrap/.rekey/3d8bcd067db56399fe2fbe8a7518d8db-llm-api-key.age delete mode 100644 secrets/hosts/bootstrap/.rekey/5b9b59da13a1f654ab32cea0102501eb-llm-api-key.age create mode 100644 secrets/hosts/desktop/.rekey/80419ac350d513375346f5cab8cbc4ca-llm-api-key.age delete mode 100644 secrets/hosts/desktop/.rekey/a450ddae3b7c469613cb81ec6a868a96-llm-api-key.age delete mode 100644 secrets/hosts/homelab/.rekey/2441d2322b7240b3eea35ad9dab11832-llm-api-key.age delete mode 100644 secrets/hosts/homelab/.rekey/ce1e98e4b461da4e405ecdef56b69d89-arr-basic-auth.age delete mode 100644 secrets/hosts/homelab/.rekey/ce1e98e4b461da4e405ecdef56b69d89-z2m-basic-auth.age create mode 100644 secrets/hosts/homelab/.rekey/ee08849c0e5df7cd4a9ff33521c95be9-llm-api-key.age create mode 100644 secrets/hosts/laptop/.rekey/80419ac350d513375346f5cab8cbc4ca-llm-api-key.age delete mode 100644 secrets/hosts/laptop/.rekey/a450ddae3b7c469613cb81ec6a868a96-llm-api-key.age create mode 100644 secrets/hosts/work/.rekey/51b170b50ec4995ea64775b8153372e8-llm-api-key.age delete mode 100644 secrets/hosts/work/.rekey/d451ded3be8bc97c3af769254574e9ba-llm-api-key.age diff --git a/modules/programs/default.nix b/modules/programs/default.nix index 9585808..ce787ea 100644 --- a/modules/programs/default.nix +++ b/modules/programs/default.nix @@ -9,5 +9,6 @@ _: { ./neovim.nix ./zellij.nix ./zoxide.nix + ./llm.nix ]; -} \ No newline at end of file +} diff --git a/modules/programs/llm.nix b/modules/programs/llm.nix new file mode 100644 index 0000000..87d0c8d --- /dev/null +++ b/modules/programs/llm.nix @@ -0,0 +1,50 @@ +{pkgs, config, username, pkgsUnstable, ...}: let + llmConfig = if pkgs.stdenv.isDarwin then + "Library/Application Support/io.datasette.llm" + else + ".config/io.datasette.llm"; + pythonEnv = pkgsUnstable.python3.withPackages (pp: with pp; [ + llm + llm-anthropic + llm-gemini + llm-tools-sqlite + llm-fragments-github + llm-cmd + llm-jq + llm-github-copilot + llm-git + ]); + llmPkgWithPlugins = pkgs.writeShellScriptBin "llm" '' + unset PYTHONPATH # Otherwise it breaks in Python devenvs + export $(grep -v '^#' ${config.age.secrets.llm-api-key.path} | xargs) + exec ${pythonEnv}/bin/llm "''${@}" + ''; +in + { + age.secrets.llm-api-key = { + rekeyFile = ../../secrets/llm-api-key.env.age; + mode = "0600"; + owner = username; + }; + + environment.systemPackages = [ + llmPkgWithPlugins + ]; + + fireproof.home-manager = { + home.file = { + "${llmConfig}/templates/cli.yaml".text = builtins.toJSON { + model = "gpt-5-nano"; + prompt = '' + Please help the user with a question regarding the linux cli. + + - Be concise and informative + - If you recommend any commands or tools, make sure to explain their usage. + + This is the users question: + $input + ''; + }; + }; + }; +} diff --git a/secrets/hosts/bootstrap/.rekey/3d8bcd067db56399fe2fbe8a7518d8db-llm-api-key.age b/secrets/hosts/bootstrap/.rekey/3d8bcd067db56399fe2fbe8a7518d8db-llm-api-key.age new file mode 100644 index 0000000000000000000000000000000000000000..3e2da4cf7a9a1433be59f2df39a383941538f9a6 GIT binary patch literal 652 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCUlH1x9w2~>!1t?+R( z4+>66bu=prGs=r}uk;8s3iB_HC@v54%S;N?&WO~nH1sUU4CFHP&$1}d&hsrakE{rH zs{^Un@RkMuAMEC<=98S3Mvn_iTfSe&Y$nBe1(VOOJ2 zsG(S?kgJf-|Vjdi6>XW1G8Cn?STke%!krrz1WazIQ6`Y;z9_(G| z>ReHrW|o;`Y?kNj?-Y<@QeYJ3$yE_$US*Q+o#mevRA`)%Zk!fj8JwJ2nH=Hjon)3> zXjYbL!lkRLtB_pkl2-1Pq@9}P?Q8BFQBdhxT2$_Al&bHP>mQX7RaR+Im{XBuT%4?J z!WH1wpV+VbsPWnBUD|r5A1_ZAhzW1^I4of#9s6sB`}b|L&7;HTo)F7>%(GPe=ZYCC zKm0dWey%@!f9r1WWVWI_JQTm9SbX#9Qpf2!Y^FH(qM}CvOnA3dbzq*cP)~5zhCcK z!mDM04%6Q(_;^H;|Mt_C&I6tqhaJtVKb~oNv$X%`nQzR8zS?n^o>1?-b9Ltv59P=< z`KqLJshwtTpIC2px9c)^_9{a))@!w6=t{li#cO}|aqRxve66$T{07g{q0S2gc6Y50 z%j`6J5|lX2JNMoCmo8WPO!~k6-8;$bw~?C+pU9l~KU&|O>2+LYcfmHKz?d=b#J&|@ zHoQB~EZ)>q%JUVCKHgLo~y+qzl-V|@?4 literal 0 HcmV?d00001 diff --git a/secrets/hosts/bootstrap/.rekey/5b9b59da13a1f654ab32cea0102501eb-llm-api-key.age b/secrets/hosts/bootstrap/.rekey/5b9b59da13a1f654ab32cea0102501eb-llm-api-key.age deleted file mode 100644 index f6aa0dc68a266f6a64d299f7eb893d5e2b9afe2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 495 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCUlH1x9w2~?;w*DuK{ zNDa);&dRaKt}68@NJ=g-&NFoKNzYC5_wdp;%GS;{);A6e3FPu|jI>D4(@qO@4~WQi zOi7M#D+yi@WVjAeq73LV=VQ3H*Uf^euZj@hPlx5=U993cwnUUn|uWg=QT<(ovtP9j5KxvmAeK;Io$ad1TGgCnv=1 z-7bZ#Tq5py?>|G8ZtTN-i`Q=v{kg#;V44&!kDMp#RNwil#hC3k@=mK=$hO!mZ0{1@ netlDKDS2JjJ&FG%E?KEh%~`Rl{Hs(>$8C!cbC3Ta9*eXAB9XCq diff --git a/secrets/hosts/desktop/.rekey/80419ac350d513375346f5cab8cbc4ca-llm-api-key.age b/secrets/hosts/desktop/.rekey/80419ac350d513375346f5cab8cbc4ca-llm-api-key.age new file mode 100644 index 0000000000000000000000000000000000000000..e0b62b1c3ef3f2f83bcf86780123c91e9e95c54e GIT binary patch literal 575 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCR+Ep!ddFINckGdFP! z^h(M%2rn&6GWQC|%Cs~oPc|zxuBa$CGft26EXwxIC=M%iOy_b5%?nC*@+~e3@J`E& z$V*NPGj=l1HwX_cjm%DSw8+eL4JMUcC|h>hwy~IPqWhMky6`@pGG7?dQy3V7nT{e4;2}R_UyBYyWrIo1S{G zk!3?q$mR#rm+g6xv5P}4KbggC_oKM2RyDze4bRtpuz9RGL2sT?kHRrQ`IxJr1@mo- z@*HpNN%L}9!&umw{pY)fi{2(q{%s)?mmllB{Z=~TVSUOZ=u?}5}H zW5)QyQDy61e|7PmcIcD%LlcEvhwex5R)4aSny{+y*v}dlGHY7) b)^$>D^X2|oS+Onmo3eOnvAaR~Mu80g{!;e2 literal 0 HcmV?d00001 diff --git a/secrets/hosts/desktop/.rekey/a450ddae3b7c469613cb81ec6a868a96-llm-api-key.age b/secrets/hosts/desktop/.rekey/a450ddae3b7c469613cb81ec6a868a96-llm-api-key.age deleted file mode 100644 index c0ba5ad..0000000 --- a/secrets/hosts/desktop/.rekey/a450ddae3b7c469613cb81ec6a868a96-llm-api-key.age +++ /dev/null @@ -1,8 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 UqEUow ZTWzzn7Ra3xjMUJkRm+lK+HMdqxCM1XiDneKWk6IoUY -7HIwLVhsJftGWMjhCQddz/MMqnpv7UoR1QzEXUfqVqo --> ;7rhkFK-grease -2fBbpwA7 ---- Dj4NFjzl0zb+Wxl+j2eChRWowe4PAGkag//fwnjiiAs -%ތ?Ŋ$qU1Pk%]C:ODxɭyy,[Dm NZc* p; 3R}"P8  - qUP/0X9q2 h}v!PG#O4hՂl^@^J /2K \ No newline at end of file diff --git a/secrets/hosts/homelab/.rekey/2441d2322b7240b3eea35ad9dab11832-llm-api-key.age b/secrets/hosts/homelab/.rekey/2441d2322b7240b3eea35ad9dab11832-llm-api-key.age deleted file mode 100644 index a9b6907..0000000 --- a/secrets/hosts/homelab/.rekey/2441d2322b7240b3eea35ad9dab11832-llm-api-key.age +++ /dev/null @@ -1,9 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 uxq+Zw f1R1uOBfZIdPn5BQ+5ZniaLhcNIjCJLsSF1k7D8RIls -qJJnInZeCvwBIMm5X1MzhwbGZ/592JqNmtAfbwSCYhw --> }o?y|l-grease cX)/~: `n \j -0E48K80STlC5k6I+c+BXFV/ZaSc3VuYSnnJVrtaqloq8GjOJabQGpz2kJVecRN1y -foetmkjWhOvTB9f5UmMvQhL3G8G4hqjJubwMrTTvW3t3 ---- dtdOrXsFxRkgVsjwAFFe32rOregwJ21fU1wFwwO6+kw -OX6*?DGm#B,3o[&1cnb>(SHu7Ga:ɾHB(V҂0-,@[=s68r9cbG -S+͜" z tҋi׎緄s݁grN:I|` \ No newline at end of file diff --git a/secrets/hosts/homelab/.rekey/ce1e98e4b461da4e405ecdef56b69d89-arr-basic-auth.age b/secrets/hosts/homelab/.rekey/ce1e98e4b461da4e405ecdef56b69d89-arr-basic-auth.age deleted file mode 100644 index 2e79199..0000000 --- a/secrets/hosts/homelab/.rekey/ce1e98e4b461da4e405ecdef56b69d89-arr-basic-auth.age +++ /dev/null @@ -1,8 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 uxq+Zw /8gmkIvDLrzwMr3XyUlVji+st35d1fT6YZDCxSRPWkM -tf9Hl+UAlYUWBvtUsSmVcTkjjrHQa3cUgIKa81xiyYA --> >rf&x@Sl-grease -kUUirnVM0mh3+S9KGWoeL4PhgIXVCd7FQQ+tjwySVoFtJrlFC335TwccCLHaU+nw -l0Hta7Xfj5JGr80AXvhACRN7JkNF0bseJPoCyiG1hPrpspUGh3im9A ---- DJlEK7SM/SUwiYXD/tpfxpEvmpsqchdYSUaZfOe93Fo -yvծ*RNGa̼ {,[zql'p_~|'eO۔v䮕(`3G`BLbΐ6SsWq ZsK>| \ No newline at end of file diff --git a/secrets/hosts/homelab/.rekey/ce1e98e4b461da4e405ecdef56b69d89-z2m-basic-auth.age b/secrets/hosts/homelab/.rekey/ce1e98e4b461da4e405ecdef56b69d89-z2m-basic-auth.age deleted file mode 100644 index d211efbd8f65ea4f1e8e1906109f0bfd01f1b95d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 414 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCSHttixvDpx4eE;946 z@X{}IN~uZ;&-N?N&CiQ)^m8<>aM4dUN-p=+HY^Nv%`fpZG~g=mDt0M%DT}c54NET$ z(ho?_%1AQuDlyRybS|z4_b~Gfa4j@8NYytg@C4armtYpHn_iTfSe&Y$#+4kI7UgYh zQDS16p6L~u?3`5OYh>x@SzaDiSfn4G5>!+Y8SL+yY~=5eXIYsNz8T}U|H^%SmF_$Xy{z-omtGKtE;PE?&;!O?qp`{lI5+P zqMaU@Xb@iR>ReKg=NnpPZtj}tWLR2SmG9~okR8Z1OZJ+l#7B*u=f=sI%N1LcqkDP7 zwl}aQ@P4yy<0w5=s*-jnhwCy^SZB#@#+6JAi#qmA7L{MOBlfbDj(OxA!CO;<-WqjJ z39x)u*JSa)RX@GO0s Itm@`I0EdT@*Z=?k diff --git a/secrets/hosts/homelab/.rekey/ee08849c0e5df7cd4a9ff33521c95be9-llm-api-key.age b/secrets/hosts/homelab/.rekey/ee08849c0e5df7cd4a9ff33521c95be9-llm-api-key.age new file mode 100644 index 0000000..986e89b --- /dev/null +++ b/secrets/hosts/homelab/.rekey/ee08849c0e5df7cd4a9ff33521c95be9-llm-api-key.age @@ -0,0 +1,8 @@ +age-encryption.org/v1 +-> ssh-ed25519 uxq+Zw xJfwiPtM4UuD4jHX7LTnVoJ7WvbRetMbQAMRftWS7G4 +okbXmKw7BNIP01K7yIBQj7Duz4C+186946aozyZgxzU +-> !ZS`7#-grease v{TUL6cR +FatxbUj85d1GQQ +--- 3zSSw89xn4Vr62mDTFLNpDgmSosb2TIKUddCrdfuRzg +׌.4y5j>ט-re{4fyc> \\T{}c=Κ8Q k9|J]*վr #m}:Ǯeܧ5iP~xR>Y:N7Yt.pdE_'yZSCw[{ڼ%԰ Qq=1~u;3Xz玥 +. \AZw6W&Cku-Ӭ䛦 ZzCp);E>[i׏|yB; >GJG4It`#:k+F(>h \ No newline at end of file diff --git a/secrets/hosts/laptop/.rekey/80419ac350d513375346f5cab8cbc4ca-llm-api-key.age b/secrets/hosts/laptop/.rekey/80419ac350d513375346f5cab8cbc4ca-llm-api-key.age new file mode 100644 index 0000000000000000000000000000000000000000..a0555388d2e41014f59d36c9e2e07358ca2261a7 GIT binary patch literal 612 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCR+Ep!ddFIT8aGzv7V z^3kp^HFqp8%J2@4GWO4j(023lvGC0cu81o|hEKYJRH8n5IH80Um4i2`A%Q~^UX+?xoT}h&onTm2r=(z6 z!}nB`<>nV+l*?6`&ZVoXt58+$R&MTR9O-8o<&hoX>=&Hsn3WXb>Jw~G5}0UY zn&+xrrk`9;WocyM$`vFz)%nI3n{YGNyiJu##|2k0-`uhKhor^DHeQvM_!SR~ltZIm zdA`cow7xNa@lpd$hKH*6ycV!u>|f}zq~`MRzPk*2gu+y_U4IA2uDs0SZ~yeh`^eiH zCy0nV_dA`$abM+QY{(+!Z3a^szkHt&tJh<5>NZ2Ny7T1EZyk3STg&b{=2P{0{#5pm zQkKkT;@P4(a}Beeryp(F7NdVdwOc7V>i>(5eX;MH5}xUce9DmM`>`pOO>gG8&4;vE zRM(#?bia~jDigr?u|`VEE;#8zL&>rg%qHhrKA%h5Hh)RPHcr2Qw{MD=mN2}2`9$K1 zSlsd}y5CMYN4yW&b}V+`d#Y zK5nbg|1J19bb7G1VD+bOJbDHdl6Xe$2+Rp^ zGD`C>3U(>=OYzL~ElkXe$_WjNjPfteE-9!oOa|GO6X~y;UX+?xoXQpMZ=P9T;Zc!k zm>8AioSU8K>yuV&Y3@^2RS_JS6>9A4Q=j&=?d6?oV3?lc zo$JF@Y_6Rc=vk4i;pQ9QUY?cVU1gXOkrkn>U+n5*;H~eH=@hD8VNjG& z5nx^xWto-C<*%w56*yt_i==s8+jew{$v->!?(Aybr@CFAzRi1d+jHT`{rA$eSVa8} zIN7!T7HD5^;Let;FB9x$dUJ28;8JzqIej$G{9q6R2ix+gI~d!;o7ZkWT3eE?`Ers{ zgW};yt?JzxomG;BpZ*tw@8uL!df3I~vv00>Wy^;q2m83&ubEq(M4$gCC32(_Y6z}nK9Z6H09-$$u>b%7 diff --git a/secrets/hosts/work/.rekey/51b170b50ec4995ea64775b8153372e8-llm-api-key.age b/secrets/hosts/work/.rekey/51b170b50ec4995ea64775b8153372e8-llm-api-key.age new file mode 100644 index 0000000000000000000000000000000000000000..7674c103d002364a589f93e3ec53826bba794c27 GIT binary patch literal 681 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCR+4Kyw=D_00BE-6m5 zEKCnGHp_}M^R%!G)y_?H_jD@EO7|)V&@T=vFgEdutS~EfG~p_Vi1hT&bkvV1HV@Sg zadZwebTiEG&u|Vfa`X3%Fpmnf2#;{j_xCo-j0D+cpqpNlnpm8w;1iZvkZ0wi;G>(W zRqGiap`cys6l9yFP{);SZjx^5>10$EW^7`a=A2xdoEDyv?-yB^XcQ7=84_er?3I&l z6lju^m*M6SP;8Ww?ot@#S(0PoQdsHY>J-G~UzA(no8@a+W*AZ6Q=F6^Ugm0=mznC4 z;}htXWu6|M72%xflNRaXmQfavW#Cp&oETtfT3H$v5XhygtE*rXQkZQJbal1*gxzQ~7E&gv#x7qHIRe$cJ_jGCF!EE_c zZNAfm_n3DZt(qEb+;=$7oH5|&mgV0}9_;T}#<|5~)259(&2HU)bu^55nMc@$t8dP{ zzwo#F-qRS>-yNNMvwlm8sFe!m%scLM^*Zm;@BgPNEm-cQU$ye#O$N_(X9XsH|GD0X zBRK8F+7p6CVm2Bd)TKgx8D4S=)Ts1LE86%_YL33_5}8RUvgieY}1LlAI4>xb0fMgTJ8P7Idy)|)sM>!wq`$?mb%89@NxDp4k=IbDa-J+ z%u7x2%+Gc8@G=Q4adPx5$x10san3GtH!m&Mw*c8@;2LF88KRqBl$uzas-TmtV4dnv zW8)vdRpsmKX_V~co|{|X=$~mEROA$%RuC5GQBV;O6jqq(UX@j9nrfWr9g*Vb<5`%M7n)bjbwJYPz0H{p z-g8y44v*ic%xGA7_>$to6Q-Nru3dI))k@b!vtYjJxohvuvX5zQ%jAfNlS+NISMX0$ z!K+Ztp8EoO-hA9~q9v+lPw@WLy3ZnObDdS}H=jJg*SV K=G(1~nF|2vleWtM diff --git a/secrets/llm-api-key.env.age b/secrets/llm-api-key.env.age index d138bdd05c55549a20ec8162887e47df1217df03..f77c0cab1107c3c9f6f1487cbd9a9fda4aaab603 100644 GIT binary patch delta 714 zcmaFEe2;a4LcL2)xj|%VN{F9Ha+pt4MQLDJa&fMiah|D?XL195=P?W2GNLWs}vq!SCYrRRKtCM?_yOE!}wnt)Fo@J7U zQ-+COkuO)Op>c$3T2zF&Nw80NkaxL9Zf0pzMY3m>bCqRwL0W2scSvY)d5)o>aUjSt zAKmn#)WqUcg%Icb8e;`zQ-8nWR3|NkGW$d;!*DMBlB%k#pu&tq{nX?@OJ}#NkTRo) zl=S3!%Yq80g3PGmG;^bp&{Ajr5{rT)*PuLiiy%*|X?T9F+;(VuEPc!Xe7t8G6a!X&2q^ulE zLo+AslHe>yu6O3K%Vyi&xf1t@z5H_oOU}MIF=1oVk@rUrtyOxbo3yy+nAoNN7N!5+ZQE0(a=hYrT|j)v zn|Xp=Z*xoQr$orzlg*kkOX=!v<>kD}8n#NymHdmtcL$u=|LuOV{nWyDasI1rCuamE z6xX!n7~j3Si+7X6X1i`z-ZX~BUz@*~rOj;l;okggzd!}w@5$@VbxztIWHiM-XHpi! z!+?KQDZ#<22Hx+qtX+)-c|M75Kcv{&a3P=F`ClAsPSYWuBhDtjt~S13G|4hPu0iLg z=95$3Hw#Q(wj}kaRj_c}%jc<#UUOc?d@^wTvZQMA{{MlReQ)GXhb>BJc)@n*)c!vQ K4N9JgyafQ-P9UoQ delta 470 zcmcb|`i6OeLVZAXaDcmEly8K$fn$+pxxR&qtD!+kQkqGUXNG~Pv1L+Lc$L3%mW!ub zF;_@Qc(J>wrH^@JzDJn9c3zHgPL)frtD9R+R+z7EcxswuV77mDly`23374*&LP2Jk zZh?`hnL?qlk6&21f@4`;zL!g7sJBm~bGoNXxSvUCWxYXYhO1v*UYeIrfvdh*mT!i6 zW@dRvls{K~Seaj9RhnmTlu3Yrk-3+*WqGh~kYPk%uD?;fbC`dcp_x&zhmT>lSw6_J zDCJVuz^V$}^rF{d-FQMXmwPF$+<%DM-+ld4!3*EFx2;lN!=qpOU3|*3o+&wVZtuG~b8)}3U;det5>{#vn77k^SJqW?zcGRecSlz zelE9IH`ng)$UAj*tCQAVsH*<;qoO&=fxUMso1yLmM$M9GFHIBvzfoh{=l@~9YR7Uh QnG*>=CfgVM6}@5v0LmJ&M*si-