j>6ra_Klo6#N^jfZxglsvNdd?upaSZh%g^n{mYQ;+Cudl6h@OeEqEb6Z
z@-jA&0x67A=?DE}<7}Cpn-gKpEG!k>YTS}?INliopf~WoRXnFQ;6w)fZ6IF}C2htB?z
zv9P#F!S+1*{(af^T7Y^H93uQchxq5{Q}=<;ZS({3dq7jItg(18+!nqEAQg#)pVxc>
z!K|mXE?K6Ry|duvs)?@KaTS5Gc~aMtg*ShAAp~MG#iRTYXN)^e3(RF>#ZK&%cD#@`
z_-1?^JKin77D9;R6c?@W(K;?PZ5P=7RKu*?WtIJ80!C%SQ+BS=&3*C%OStxo3P<;?
zzu|a?x5JjoeLh6z4Cxzh>cFsu2ZuVVQ_BeIs
zw|@TH%Wkze#@+2#oaSDaBD=gz!7PXRz^vHP$(saylua5dQ#pLeVia5Ue)_$F{y=N*
zZ{Yy5Hn?Oi$F5{pHvFlUDzm7ni^j(_z7haf64}>NCy!#?2ICZ%*_N~6ZQW5g|61pp
zXs4}d?oq9Kj0Du6?Y02Mk&iVzp!G~g7&CrS)N^H|{@2x#id)R4FQT{1JG
zJdxxZmVc_Wa#comudkyRE)oLF(oi2(-l#T<67CZV
zGdG_&St@sb!B)=m{?tC?Cv1W;1~dK>Je>9(&+6+6F?oPo3Tkf3aXzN<0r6(VdTybi
zn!jV5@H5hTA%o0L$bo%4RwmLID-Y!Z0otbXyvCbw`dXMw7nCIkQ1+boVnr~8h${e+
z>emq{Blu3<-G*5EN?rp|gB0OQCZkqgEA~nyXCIemfidPyp2^tl=&m>M2o1bDnEofl
z7V9U9hFvE(0cpvk$fUJtH-tk>dU9C+_jW_5d5rLK+|O|_^v>v|-^Go^T(}OO<7uYD
z{vq4B_3Vz1o^(517M!KwsLRzIVP`Ie*1n`+5*e)>MQQ*-BthE?l^{gg&=8lM}
z3mZrpY>9@~$a5MVv_aJUNQyb1DArmC8D+9(H+8tv6Jo^d`WIm?jZgZ>b6K6QKZp%!
zB`P$OYeys%frq?Ecz1jVAB{o_ew<4yEk%i5_VLXO`5jHNo~0@%g9T+8Jh1^&7l1Cn
zO^0AD=G
zcW{#}>cHaMoKj1i6Mj_rqQzEGDk^kXmY5|l6d;I{U)Mz}E3ENstu{0OZYbiun&@x{
zHZey-C96AGRbX?GoFm#&x4pvzYi
zQ9_ntnFeurnQi3ePxl9K#0Y4BE;5nZ
zwDdV~MQYhl=<+wNy(jRf^QkeU2C<0}+Z=4BD5{oCTs84?L!vf~{Y|v^Uc8J~<+n$O
z!8|Uihgq!A!fyx}#Xc{bz!Dtq?0`3yO{@Pxd2Jf3O4b4!_F2~
z?1kAaQmU|as!JW^!x<#mSd-FGJ_gmm0oS7R
zYq=ecMhe#|iDbm=!_+`6Q9krDvhTnvR1(ovVG=m!>sq&YK>9}e#gCB=~fb%=1CLJ%eP
zg*s1
z%e)|K_($aY@VKN9r@e|7U#xInV7|6!%OALl{f__v#}>~bEb86C!cy0`&^GTh@~9}8
zR4(KTrPztqQSg(Gy>jn0+>F3153Oa5!Zo3Eo-0r~9)*hY$(Y2e0^)gBP+HQQdv1lX
zMqbG|Gyw~aeR?g77N_(~Tpua~O&M|E4okjRy6Gd!cGer}3ps1<;Ak$w3Cf79h`grw
zoWx}zeszFksxu@sabH5mTMfKMc_!S#2Xy}cM}sntQ{{(;?9#b%9`C%UTw9Ew8gw^{
z$KZ`0cbjRs-h2Md20`Eg#(hTb;oe1wIV4;5W69rBQ$F!qQY#6z#$^{;QEzqpS>l))
z(~W90IB=p5{3e1T^0^=;WV*t2hG=l#s&ee-R>t5p^T6?uJZk7DDKpu7Lg<75=b=7F
z?OpH3h2}CI?$iL@9hWK}i1HDuOw{xWE64RKbF?w
z4tr$pi3eUSDftc4)6muXAU%9f8_Q*N9ESv2yai_nhx$aLBKW!{x#s$6Hx|3CUezy_
zDwZd8UVKqIxvFT)aWrOaObVCZd@pk$IT)KgJqiq6iBulrCnPQ!(CPd=lW&o1$xiqf
zEyy?-f=aJB0KmYn9wLDg=nB7t;~fDJ4lHUB1DiD~w6xCSheM@o@uV$LuOY!KTiab~
z-Y-IKDS~i>0B-q8I09&l74DCAHok>RQoeSc!r55XSEGM5wMrj6xfI&S98a1@I1Klh
z9B@j04L=1t?xZnha!uyi3xOuUc}K4P+zr$LyW6gR=1s9xu_px>Y7;63L7CjoPQHFE
zo==g9)%uH`jC~Xz6whu}Jp~26@*ZXL`u-+j!S5b|nYBY|L&A1nD*}fWPvr>0e0J?8Pu%&g=ne?3k4}l6h^=>#Y`e@`cuqiPJRWsi5P)OFZAlt>2P>S*mrh64aYk;rCdU
zT9gMJ3SO#2YkY|swhPn)$R7T!w+s;Iq8Tn~v*n4$`_>F-($j{OmRYh
zTyk8aEw=P;j2v!tN||Iy>IcLxzDtQGeZ0QX#)%M6zR|_Qj0T;+qU&+z2s>!GgBB~zvTX5xfvAAX$)
zx77oqD9_Ne-yJ+sSymls(dKSr%B5%)WW!hoT7GxI)ZarNjY<76Bd%ntJg3!qauYYe
zl4UjJ;b@-B-Bs=MVKjUra5@R~7M9lGgFqiIMqbM;93JzK$bGC<1Fc!%JN9Wx>PSQk
z%{Icd_ZYnToUL`E1sgoj{7bs}efL>ml;GL&yQf0Yxmb_6+O;@%H{fR5xwE|d$r(;P
zj|Sqdg+3BWC{0Zu>GIk4Plo?FIk`=UXT88n`lKk~h$UfKqDKd1XFJ8lauWeL29YV|
zM%lg;x7{$@0!A2lNKRUxr$S`;M7b`M!Ag+isR4(EdhzS(sug(^q{;B#V)UHe3dFJLp#tkW
zX9g=5?_}CRNrhaxHDBg;7EFq9xxWuUj4;39p#_@%1%tMsSb#i?{j5gMRdX9x+gT0o
z$Ed58S%a~t^Yz7gZ0pIKi4&jyK#}Ka-ntv>89;N{ZkqS|dmuohTPRS;qj35W+wN|M
zd%AR{)Q)Y3dxtzH4s01?dq3@S4Elm;+%BY&K!t$3_MvBY+DTb_nM$;0cqhhx_9w8`i@+
zIBPSVP7TDR7p9ey2_zTYgSGEjv!^NEmvmLlqAs6?u26Dl!NQ-C$3kXlB!`xsy9E#o
z3l>LZ9P5JDath6jxutPfrM092l#NvSXqazi9VSKBi3KiMR=cC&XkWOCEK>rh9V)cA
zbFd|AU>KN!Aq`*+Nm;97@HXzf``{7ke2GlM*WbtYi5WC%Jx^U;@&~rP`_FnkKJaw~%^wfvNUJRPYH1q!Sd3$@
zjY((2U(`LV!YW93)r3^Eke1Ti5+mDw#$iv%cnv!?eanFt*OG`>!+`1h-py|uz_B#C
zbma!$`-3`EI=OY6YqUwJ?XVT$pwL)eOHt5z?8k|2Zc)p(3fyD-=KlkxgT8nz36M
z5i8K;=yqG3BP28J!C#G8axIE?E!+vsv-_vdFUI9!56X!*QAzU}89y-g5}mu38{+C^7)3mxZ`dR~1Z
z8q7A8;C%ag2QJ^e5GUAhn{X|E)4d1_`k3;VItv2QtchhZO7WdQBD0$}?XDAH$!GYr
z+#gktw!pz*lA#d1zE
z=e#An$jp@ex|;HZP>WE$W{eM%tu4HunahE11oV}8P9_Pv7fjzSDEauS&JVd)#jY!~
zUL}q36D3Fu222jb%=o*}^jP#pJcqzP9DM%9idFJlcE`fB7+Q9;Dp&4|NwJojIx+m+
zE>3z7=Ba@g*K~JE6{aj*o=PFHh)q^y^`(?;g)i4)KL@L12h4uFM#{my6S2h?%BLlg
zM*R=>7<8htT}%AA(98)ZP9p(<90Wb!c&zOBo;X=d(8NXKm2E*CtXZ2Ig8X3AWoBS^
zj`VCMTx}olwjH>UG{@;M?_mS->6BCwRFXzdI-k2C
zsmA#0qzI?-Tw)^=fvKLpk?y>)ogGnmL+OQ>3Wu7w;4NFKv|&!eOkCU1_Mp3d@{nvJ
z7a?GA9b~?3f3TDY+Q@GD@j@Ym5kRK}j75^9vC^QQ7{LLQ;ly1Z^Y
zjBvZBGEvI0)k6uC;M`MIJ2+TJpw9$iJsW#QxzK!%ms~Jd<`q-VKo2c%)Azfs$T8zb
zb3GLz&|#J!-gZ&<9WK4Yfc3m+tUdY73)1^?z-uonaQh-G)r
zn#1N-gRlD8rC47H*!)5NZUlwvmXGXh%RGBp5mW^ZMkDwl)5|QYJJ<(=HHe^8ouNqR
zYCD!WU^}QO8!j7P(r8`+#UQ4CVlDlm4lwmR=(srvqp6cXwLGkAAoV!@eSh608~C0N
zQn<8WE~jIyzHsiqTN}9@g7?+}wLE^@s}o#Jbb4Xu(`0j$AyK(uP|brDKjCA$w??nU
zoH6tqqjUF>wg7aCqdcsd*rAk!9hKNFzEz8BBuKPYZx{VH*Ib}aW*=CuL3X)umpX~oeyV!@eqs$HqQ^>zI
z4{xw1)7xwz+qwZV8C&^*aqubtVM38xo<(a?dmdwZibgH?<8SaiMPhgtzpn%F{`cD5
z!5F@XBYo6R;p)2+^}HLs&zI59&(o|Wp-yFJ+yIzAdZ1Mz_s09vJgVraJlvFsyxYUM
z_2VB40(E!yjB`_8wOt!jupjvX)patxgbZL)Y7$wvu6-&Ibs^!`A2_>7$Vs3X_#Wd|
z{_4}d#+aep2=Dk@wG4qDz#|hm0|V8@_biA>{_;lOPvp4?6rhXEdbk0*&d@fM_Y0Em*V)erxXq^7E
zyrPdW8F=XlIRxjWI(Vt*ohh%Nge;$Xe>#f(-^b-NAi78SZX^Xvh7D9
z7L_P7)C*_^Lb;VWF+56Ehxp8M&=;lbTSb`D3?8e4qU-^^#jfyLU(8CZu!E<9vpRVN
z-j+Ry8@*<&Ni=FL@(EF6W_=(lD}nA@9llf
zMf#=_qWyFbnC|sQa%Z99Hn4rGir(MDe2_vwiy7AcJ2=MU_?So5hC4cKThW=aLjeo3``U$`GoIdLplR9+sDMi2|z4toTlt;N{#d6>=GZuRc`HK<5ygefQjc|5ki2|IicITTAz6H!aFT|q3mV+
zwg?|V5{O%QM&qoNXgPs(=!T;I!m7pc-+v<0!{%{p4$O_EDiDI9oJ%6xNl6mer2;0>
z`(BF6aH4O@W-TvacbVfWKWfMqk3Bb~IB-W^f2;r{V~iHKSiQ?!7?
zIJkbx_VW#-x3};;hoA0H7U?bdE$bLU1f9dt`PV21+9WVCVuU@#82FwVQGGlx8{6XN
z4=VLfCUPn5xsB;ELMmr=9`wtv755nYu|F1Qr=4EuB#E`^>qLFuOiCtM@!7S>0bDyj
z4%Skv2N}0_r!n=zD%t_jBrm9k+GF#&S^J
z{|l&ivN@k94R%iG(!GA|sYR5kEYTppONf=h;)`xSE&A@m#OqP*GFGKWerAdRD<(w<
zc`ZWb<^9E@XS6ixkVfK@$^EO>I^8j>DK@bdfj*#^(EtThv{kPo1YK?>$=|nqdqXxC
zzbdso#gr}hg7)|^_1LHQVpcH;&QVSRADf-k@cEJTL~Az&&&Pk6n1_plnCM`ZLV5#<
z>IVGUy(^5PY=9gG4fOy%WYwp(VjVIpcYZr(GW7}Q3>Bg6oc24Cv7Vja(=xU!npIbz
z%W*`miqCaB^SKM(?zzc=lhSjmBmN;x(|_RI4v*wdcnG$vYbQIEj1`tePqV6y|ilf#+Esd2*YwL5T#Nl?)%Kjr;+$CRBSbk)bmsO;Mf?hlEo>v#kG_?^Kc
z1n!g;!-ddA$k;@Eh96ZSku|HXY>}V!`#L_0cDp=cKa?fJr$k2m?u3@g9_E;kB=qqu
z&FEkzR<%#6SU{7}m!2{z`a1(ZgtY=!w37qlNblK}=ambscr2-@OQEaU3#WUoia>=5
zgaNv?9}d9OoOVXo8sO$0K6V??C+`l{ixR3{zr6I!seQ~!5D3&zClA6!Ak)u|BwlH$sP2Yu$&^!1kg{8=%{ejWWQQHwyv#o
zY+lnC0jP`(U?PsekxV+1*+rv2nGR(L?OE2>8-{bfya{nSsYk5d`K>H#l1{Q5=2HHy
z0?K5~%=ZTXH|%~iu8)>A-fLg{b5v8A#Ecz97EpgY
zqGxyX9^nGtlJTo6bL(Xg0Z1@+k$A~V3E5KCZo}{y9z-LEw4%cf>L{P|ERbM4i
zL8aOc=bT17LmIn_`Ig7s*`_u<)W(F${ftc|f0-qhIX)UTjVAH1*)Mx~Oe;WK4uXoM
zC{Op;K&XUc*gC}xz|A6}(e`;IpJiPVKiiKzSANY$C_F6VvRB}wO
zdWAwCzGy(j@)aW_xVcuDI%H0vi#^FJOlT)Hd?G;{Qm)2}#Tuyfjh2tKi(8
z8L92VM`^l$S=yHkKr9_>(?Je<3_<|Pl3o@=jOuvyVqgHpNkps(2QY4}nB
zFf{~u-oX!YHIisN$EKH#+SuzeV%Uh+`bz1Sg8r}>ZQ>2Cd>psjn+mC
z9I9nYt>hPw>vE-3g37dwmNWpfsh>N6(gY#8GokiK;`c*lM0rh4*XHufdR1=s=Dddy
zBSra$&w31Yw9@_c%h#pW9(+l1-5yUj_O}vLQf2Udt0=zkRx;h|N1t43WtC><0karu
z&DL=tF+wQcQoOvh*fl#(hz$gY4Fz%A1v8B-ZAUr#J|o9*q}CQFTR@WKfk-EB>GZVg
z^r3O3ug^g+t&!a_ocnq8kv`n}5%P41b8?(D4qNs^By=PWDsjeajy$0JDy-P!4wZ~K
zST01&f*tB*E2oP!Hk}y?9QsKW4mmx~_;}9BRyl(reUsz}3HT@vp#h428SRG;J}0N9
zQ9pNq7*+u>ERJt^xJjx)+I7MuiIiOHZZMThx?#!G2OyS5HJx2q988`5%KLq&;yrN|
zlak8aRkrx9iOahpj*jf#-4CQ3sqyuZiE>i7}s@8NAi7tz9eoJ;!ODn1sNs
z%z2p_W$qun$h>~(JZ5WX>#syTP#F)@_t4tgjjPCYdRssRczPz$+4Zwc$z>i`Xo6
zYCF3AY3t|93LJKWtJclHSA~7q*n^zFXvKk&ZOMB?+~E{
z3>A;`?o6jzcUM@gUMCioiG_~nX?fWmY`qF`a`8tH)5PX_IcCv64vWntdp3UjxHbAFNPG+pM?~mK=l^aw(Z~{qn;lDl9bh~Ms$UvA9wxzr%V`29XQbFtSNW8x$2#IQJYldr1cKw5i>V1!_r#fJ@T*s5;)EYqU
zCQW692@+AHk-yyk4H$|V{p4}Wa$LHN%UdCAJP=Z^szMDd4}*T~W$WLU@hp^Vw3R+Y
zHzs<@ueW^R1nv;aOg{m1Su2sxc_#GlH%{GZe=C~l$;o8g
z-5j}jF6pT{u}^*&TJu2fF~5-kWc@h^LeP?99*sh0U}MW5)==JbTON>G5&T%R4X#96
zA3QZyP`z$HdPic4+WgAPM%mjgLfszrId-}j$_x?ser-9b|fX@L>%(1{&2
z>KT~va!s&Q!xUYGK9Y3JxyTEisMRsx9R~L-ufXg|I;AFd*5Q(U9NIiOpku1_I=1qw
z-c?Y~fa@~;_Ucb8i89No2K)K8FZU=9I@K{rqs5ct;jKI-pmTSq!`^ZnUTjzPHI<{X
zv8UIe7@?B
zd%gY*O*aLiFYA2o9S}O6u{js0f77}o8v&=T{dSGT``M84a$p@Y@d6=gG4#DaxBg~
zpm}%eRv#7TMM?v?iw~|ms1?n-be0Br38yM>i!THQo_+G>ve5z}J0|Vm=o8nhB9U)C
zC2@4~IBi}glQbn#Zj&x4QodtW@P(0^Yr$`Xm~PzKllMhWVDeJbW
z*rlfhiOo?#*BGX?81(Pf>DrmL?1(%_X3XobGAr7A!(oRxMYTTu;em0=ZaChO%aId6
z-AxK=4LT0}kXd`0;!N8wrKWtNj*9~WsumfRc2#`AS#LtruC@NG0iNO*g6i&;rkmB}
zt>~RPFFB|CNvI^wm-fZ5UiX38bC81!DHW67|z+o2~5Sr1Mb6Vh(
zF=uUH!D)djPFYe?Yj6N{y7)|&1P$%)hd-Qu03YbH2}U*VituR==kRx)UEC1fuvH%-
zx?{%H0)8Z1SS|5i(Df|R7%8^<{@5+`6Q_nlLa9@FAa}jX>qEJXQ^{}u`MEzdW3BPR
zA>&Aw_5y?YyMZC<&9&
z8Id@ZdiYBYj(QD>OJm^xqWbK}cfo-nBiK7E?NVHZvbWZ=z>Wm?h5Zrwf;Fi2TCKyY7V=2i6d6AI4WZR#J=QzfO4f$dL+_*O8=q=
zs>$VE1uT_Tp;I(whj-3sBs$?f`C@6}&z{rOZrV=0m#TxGVl~8Eq4}2o&SynwWPM=+
zZwbwKcx-q0`Xj`)3*zUx#Aw8N*_ddy&N2$I8d2(x40ZW7Tek{MyLw*kRaqDNI`N|+Iq!H}y!Tf^K8twks_UDf5ODqMK=qyIz(8F{ABifL@6yxDZr
z!J{>k(e0}7YJ|wy%?etpBK!kkL1hloQ>4*V=q$A`n%cq8MDpbnH+XiR8;H6
z9NcNif4P=dLub$~STW}Og;=>3s)(3ac%hUMLU-Tg2e6`3JS1XSuv2@J6E^vOwE(b@
zmUWlBp15Zd1ux@7&+-ZPUSw)5^Jh=^Z!*Ihe;9fQ+7;h_HKUu4n(u}xIk76`zej{x
z;0J>OPhYe8rID75oo1?yeHqtLaH_iq`T2v#@d4`6USSqmeFQ%Z&mb&kd=s+dfz)n`
z^M`0_sdm9dsu;8E>0FJgb-j=BR$(#}D^KnW(8*!-`3fmae%U@i+OYag-tC?q{QU{q
z9G8XLhl8Qs_mCDmO)-a=i_mNi(!K~)jZj^+EHkg%y8Yu)MnR^w^j^JErQ4ln_g@~&
zo(a@-WtCo=-KIq6waHI&~rO&CYpc5RS{g{p`#Jv(j&b?SX
z+Regb`_x_jQ*Rl4q3ug7>uypye`v-eBlqOx37!8tB%aO`h~on{Zm;yH(nJ5l{1X7Gw35f)3h}}Bt+q86zXs?z0)B@
z(B`Yxnt{+@_h3F~q*ZYEv&v7|zYId|m^MXaMqgML{1ERjn5tS4ryBg0M>l51ET3-N
zs?vNoWY-CGNrL!yhQ&J87a6~V3|Onr8RUF82)y_#kNq5Qt}pn`tNQfJXygq46Y$|+
zw`m|uPs74o-6ZcF>n_TpP(%Hq?s!q`Mx+1ZFYkq+lSJ)9_AOZGYE-LFv)I*%^>x^=
z_at|oMF7Q?APs79>-<#V3mU!C$Lf3Rr?ouq6};qPKAk7bct%fzX0^>TrFd;fy-5!z=9iv^w}1MxnE#I&4-@*sPQhoKrIzP*+|PY@{!{pd8*r{ncCgU%CXRIJ$A#AB
zlAu&%{SlX=?!!pmJR@ASWJhG!zBPk^fFFR>`W{=a(6Xh8wlD`T#Dmvu(hEcFp2_?VCV
zvnVD6wf5VdW6Qy=<|T=I%#0?OO{_WdhkB#+U0bHa2GcX!CkK@mo;9}CbLCv7
z_xNTV*mcyc^CoOyrmRVtHbHQ>Tf^l0dgDt2r#re|C4$+RLz5B&(>MF+I-xFf7MZ-$9PBLeozUmK_
z4eEsGn7%}{a!n0C>0;HQH!EI4Yh{){R$WqCa@wC(sbDo_qw&41EV^t|0fFC{|`Rj=v8;YLJJ{-~#
zM_~q+cwz}xepqD4mm0jD>0z#pHFz(a`C$Brv9z+)fKxm_Ht<9PI+X~~vqfZ6$c8;6
zI^oR(mO>LDiNw=Qev7LQx;3lTikmluyHenMo5xp*4FTcZD=s_
z1I1;t53DDf)l!O!FE0JjxHXJg{UrD75uvzf+U-w1NzSo#I$d48ESg9Raa#6!_3@8L
zuXe@AQu8;e_34v$wf_YY`FMul64A|@Dg7`R(%b2@K1MPMZFIy6b%JF
z-y0dOkeU)ZTU2(oxAA95=!dVK+^bLhN*Fy_{}W>;hG3@AtOm!OX%P^Y`8x5G^gGrhkDR;I;24)1Qx3k}8vCEroe
zn!Zv17Or0$P^|w|9e;P;xH$=uI63N-x!wD6e>VgVN@$#`EJJluf4Z^iz@p5#b<_+E|Kn(kPd03Te_vBrI8+BRAN9tQlvo;
zDJco1j#5fWH#3SzHw+E;;P?Ic-uo}y`@ElLe&9UMF#DXfUu*5xT6^u+QB%Pjyx5d&
zy}L_o>!fk)fFD!ohNdXe^PBL{IXn{hVj4R!a#z@=B#Jf#E$@N0OTXhnj^^q7$)>=z
zwW1}8coX-<=O)fm0JqUBwpoQ}m~DKD$AKM{)IC8g8K?qRg8XYP)wD0qVwu*;&P8kR
z^$YD(e;jusIm)Bn0);@3(pNnsm7GckUXXZgb0Ch1?};nxF;&^jcqgxb5ow?PC7Tx>
zS9?S?jPgGtjq(dZR%meV;CbR?-1~tEN0|9!)oCFF5Ld`eJ+-2y(zLoZ9%tlfMiwM2
zDH9$Qyf7FiSdDimUX=cY1$pOgZWf$KG#*-Qnf_OV2s%Ori
zI>_!&9X9=YgL>E4$7_l?A6Oc?ewdj%J=U!P?mxlBspfS7gA&JJ|0%Ha50jDI1Yh6_
zk-GRjm;UIym%Zs4Ys-RYeKRvX38h!;LhNU*en6c_Y7snaa
z3ezqAkZlIa_p<@ZMh;QozqmL4QN9Dw93ComDe~!x$hirDuV%+wedEPX-4zTp=kFl5
zhUtqH2qT^qR4AD~6QM}GRUcMeP#Yxj)l5*gHWZJ~#sTpFe|xGOz-4;uS||;H$CkSp
zPf<>{vYnr~j7a`lLM&eMsW&CLxC{QhhE!VAY-w&4ot15-*Qp=|FVyea^;5QC8T#T2
zaqcZOrh}sdNP4%~Wx{pu&Wg`tA$!hFusc$XWJtL}s`uzgtH#;f$@#P@p5_wdiaOcf
zOhUR96pNnMFOm$w>D&(FN@S82`S6m$8#{oW2XSSbJ1a%c}UhMW>s
z;pu=5#F=|(=Y#-AaxsU#3cbrxSU1R<4
zq;x(_7JP}`DrG}O1s3QrgApQ~f
z9QH{`XGkHY7oRcC;CBShWW`VU2zse9``*(Wc-37-B1q=?^NVQJK1*UG&vk~{g$qQIXFKn$OiAsv!M&)
z{0Jv;<}rz-__PKf)CmEol&_oFf-=o;a*G-wwHQ4QCf
z@e6?l!d*3VcoF|*Uv%;47mC!r$&Wz0r`{*04+fszxAlz+cfnv^UN-Vh&2QGVv=&r4
z5e>gM(Yw3`^-T~*la@)KFi8d|aX~9oW+l&I0^_0Zn)=g9Ty{ho+y-0vD`cM@lUBD3
zPTUl)_W()Ybop0#5d1?zxB2nrA69Pvn0tc$_|gF`G_hsa%)%I{0GV^VZogMMduCFe
z44l!|j!LM+lU3kOd1prSNdq2${Y=LWY3sv73rQOTYj+4Kw1T5GDVu^%=S}5w?IoU2
z8xj3FzPiC65rfq0Hq30i-_U*M!iXldBqoNi-LFKnB3*#SvM;yrxzVn*{e;is40Zmz
zcNENmxsmLb(;r~6lIi`_h(X52z6T2EFwl+?Ks8~VKob|!Mm$1}(Rc6yb}}M+b$*P*
zo=h&5`?bq%|17xt3k9X{7pZY)OX>I@n)xR?{f;ZKy^#q-hK^Ngm7lD+zryF9tE&sz
zd|k50!gmF6-Y^G>8#P~@ZLCdJ(Svd?M)48bpkj(cs*c1j5RcB^UgF~#@FqP5ETf^3
zsAL=D+z_(c*Y~%>vP`ilugU(rQMepqUEj!>(YwtctsLx4i^#2@*Xp(n?*_&p-Vj0nTa<_~NJmUh|upIwz~ZDJ~Y#i*oW{ri&}F&2e_rwZ!157Qp$
z%=mT@yesGS(1YE3=UCy~@lgBY363jQ%{B|uYU!rsjB`sL{&yM?A-U3u)f{fIHvx&e*Z*CJH9d<@O0#lPEv&dP$xt!UmiYtdCnAshBnSP
z(cf!3H0Vj7caALi9eQikfhIE3BV3-@
z>2Bq?(nPLOhsd2ORJ447)jme3&p)*usSQxYF#e>=tsh<|1QLPdv{QO*aSD_Qq6}QAJej-=Od8f01f{|W}
zg0#E1e0Sc6Lp?|%mnq)VlEy>^-L9YmCugN?#W0%
z^B^Btsx)*=O`i~j#e?j=jDLLv5dpPvSsD(+PQ;CdoS%prYv93N+%-l1@ra~GEb)bJ
zE^>xYyotWKTM_@&M;KH@gzo+2v@dPF?~>&E5@oi(gDMt-nZgc4UyQ6Mk)yn#L^u#r
zD81P3rGZvlu|>vqn5~WiQ~B$0&1}zfwD9_KV-X|%8$zNH4U0sQG9`=Wagv?V17YCwObR
zt78{cIviK`u;dNVTULkA-m(JbI5$Umg6R
z3Awf$4PAV|-Dqg6!7}_u;L-1VL=rE>4hgUZEEKn_dj}S!`Ba7a1aLA%qwp(}6>~mT
z{tR{!w=eM*9L=e$k=hMKdp(nSvyI=1eTaK!kFUZPHQW|C6^oQt;T3G>@#YXt{)_!I
z6eg5Pp{por$LCt8n#l0u2Y3F!V(8Ao?lF^)Eu>|$jt~?%;(Di=uy3p0?XMZoS+t5g
z$i{7(dWr279{&30Ri)-(+#0&~Ayw+^XIJXqg-*Qfcnr%z#t*DDD-fIAK
zD=HLZ+nA@<-xeNm<{9Z>8NTZ2cUoCwRdzj2mzAxTQ{V8>OjI%yf&1`c%JJr1V
zjnHo)aZFDk7Zi3$1|{2)XhkdAd8r0&7rj~#Q-T6|$VJ5?36ZbUM;r;}eOlxdVkSpR
z1q7N~^W)@FT*>g6JI&=y
zgy5?de+j2NTnRzf0WQPAb^R7{${IZmleP4TQ6Q?zZNG~CFmH}*`O`2~#-V$K?<5=V
z)GHQ?C*u3_O)8i?_PT?~5T-=E&*hbp`6-8YQ@M10-$dbF#=s{(3m!yGzqjj*-UD^K
zQVn(QM}bS=@Cy#Ae!{LzkM0+{8?j81M``xo0vymkQ+AZNi(a8K!fzYt-_6U`WeK@X
zpOFTvPlWWlkELrZRDK-;PWRi6&w(SVg!4e;lNEDiiVxb8oLnS}Z*$M-JuHh9*6(v(
z4t*w|vHU9B!LTc1pMJ{3Ie&E-JCUdWDjcrp0>iPz$J^l^#s<_y&j;hXcrWRZ8m0~W
zy=}LD=9;OTOYaeFf7tBU7>mX_PV?#1nbtfzWZd7V9($)o8gjI5{C!Jir}bdkwKTVR
zr~Nz=loJPEFuTW9rqHFQv@v?t{Z*Qy`r~oUkA*GxzO}C5&4LSKQLDd=tz$i?@4#
z&7sJyY0&K1EV=7@8S~K(_A(lEdAmLQDLXf;2FVlZjF`p=tKWk#=J%=$Wgxwj_+pnB}7YJlCq%EKpl&@)~xBZ|3yLeKuBu
zZlCZ_tfjEWziY#I5j&HDTw!71Cf}B7;k4U+8;8;b2p{=(u)X=3uMUCf1W60QZTE)v
zWPKC%O7Us*(sJiN*{+;=Al#9@?J5Zi`8=jJ-BgjniNRU1#plU@2#&P879@r&wL6}!
zNnd&SL!CC}Kz4_(Wa|8n_8%lec*0$_Bcg4qwfG*
z685sfdjbc~;=y(0hM;XPwD_H^Ef3VbVphn5A1}NC72`6d9)}KM@h`MxN_w4`O
zjILsOtRoc=O34Y4p}w#oa|z$@@+p
zaCBURQZ^by>EueMgJ4SbT==rrMX8q-9&rYCj{nW}(nYny-^vEp;hFUfYujTEgOs2%
zI-BCp&K8s?k`~$lhc4ddY>QzES_AFJe=W1#;nQU8UI`E!vNB}}>H{7!OhGs&iAwrN
zDcn@9`Ww!Cnev>_mqeeqrG|FE36n56Mzcue`}F4HV*>Q~xEIWy-G8WOlu-HFK;y{oF~+)5dAidiea-G1
z6g?DUgddLln5;l~bzEjelQ6oGS_%vt6{A`TwG#K_a6_F3E~U#!gs)g9)@TFRy47EK
zX3Ggxbl;z2YV>G<*2j448JCbwlA+ykVvp^CE9Iie9m~+^_oJNwo+w{g$8u8tA!(^xC2qG*h%
zs=obrCq?lYtLd~R)p)gyLOZA!=Laf8a<(La@`R#bCc_GXP9T+Q##62DM>+tHwrh+>
z47y*)>EF~%Y{T(mp
zbh9!|*Vv^`uQ17lc;D!-dZQKbBFBSt0CF>VkBlK@y-ACqlXK?ei;B1gWStp%EMC(>
z8H#s*qHZsgT0d$z#5SAma{KB8t>(I6Q+v5U6%?6iQ}8XVP5A-9Z_7-L1g2pSGxPmU?;1(judaavku1}vhL+?rU&
ztEtR81@}3O0Z@JL8z^Mii{#ET`wZ{6#LV3!Jn*wayWd?%65O)dMOw3-wz`-|wBY7@pTj51;5i
z`i)CL$yn|Lw_l!v*ozFxDWiHj5rX8G_?Gs<_RssMkulTMuHXTk)1;3QvJ>dh0&ArORPwD;*ND&6WE4s(R1bG9HWs9x(QUCvg__5f9pzh@u`e(
zdgxnSrhebIVy+bZf*q|0m)A)O_b|L?_>^}R>-<4qpATNiy-APK74p=Wf;j>ggSkOD
z$2-|xi~Hrp%<#ixX52EkCr8TTyx6)i@?DzUH*}ZnF^C;wsl43Ct-7gsCo(HQg%$GaQk7XfyaK?+K0kmdo
zl|KU{_n-Pjuxap9O}qnkkoXpH8gASa9_(~$rOLEHrcq@~7&guDe5loH>#>zBtO9E9
z`WUrmHDV+3Yh*>=#{8m{-O}ffcf>Wkqdb0qI-h*Fg$P_?I-}JsOS8AAWOg;*Q4Q|5
zmAU<(nwV0P=R))0s1~iHr&WCT`-tl+TwS-0Jm4I38$QG{x5E}Dv7CcXw?>#s1CKs-6Qn7`#Yk--G92LS!gkOglw>-owNsz^zWKbq
zrW#yMBomkw+BJ@jug-TQJ!-znGwtvc
z6!y#s-TwTFPJG?)I${_7mBFWr99OeER|e4z&X7l}{L2RP)1CdAh^lgXqL0)3sjSMV
z;4*$x$qH@sj6B}qk6-Wz+}5Wj#?HC1CTzKcH3IAirP?=*>t2kuq@64RhatOt;{oL_
zdXEfkTKO{Ul%}i$t#ze-VM|QgVr7`w<0n}q+$`u{U*H{p8nhXEOTF~33Cuy}1!jaU5>g#lN2
z;$X5Q0`NAnM=FrT%BIUL3RTn2i0WJX%W9sx|mv`PsT$C?ej(Xm9rnjG
zvX`Yi_Yg+{Z_&MXCz!CAaC+___T7)0cLm(MBjEL|laX1fPkU$xbQ@d0JzL5t>eP
z!h8Go<7)Rm-U=r@#Jd^;ju~(n@GrV|D|Cm7gQ#S5u^MsOw}0s~YC|w3K0hqVUWGq=
z{==e%qYm7&ZjC`y5O+T1qpV<^4YkIEDwzi@xoj#K-Ssj=QZ4f~(t-u^2b_l@$piYU
z4?q2I@uzLf)~MkqB=}{6bNOl*n*_GFM^;9Xi2GQWXf$jA&nkU==w=^IBlzU5Yr6H*
z>V^8uPrV9=6=KIixp=v1Be^$}oE1h^!%${g-1PDLKq?3$9fY4>5Nfg6z^37dq((uw
z>_hA#4yMR#E5<0?6e>xJ>xw`T<3V-GwhKVAmy#BP1Xyv}p~Ic#0Lj+LDHr-pbnVYP
z3GDKMKxA=MTt7#A-&3amo%>%O4FoXk=Hhm&h!y2uYDL?K3n5*O3=XL(hbfU*+)v8y
zFmZErsApX_^n?T7(*j3twjuiZ$AE6|rgW7xJ}=Mh$!z1~iKImxy=Hx+l8g6Bk|^pZ
zlJ(J#Hi8^Cnk=xDqvGq%eUcN2-NIj{G6UEo9K2&`Ur~|yq0{5K)nt?&@979!+jSv%
z>Tqr_drB#m%_Sg`AgZszw;CHljnJFkqaKke=&*aF0*{4r#e>a3m(^lcxUw!ZPL^P2
zM~(UmRG?H1pHL6jIV4To-1cNH>@g-~)?V!A!omAbif{y9dCj|J@UdoE=Ez{kh_3e__XL%R-{8@wrrYP;SXin
zKitGoVm8-5N@}3I{5`IjV+DS2GIqrSy6(50-aQ!(48J5^u11&J#25J9nY&{
zZxQ6EpTKTlr;w!@S`{q{773LA$(oqYcecF%yR-;{Dea<=@n=j10$pOZs7=|su8Sao
zSn|A#*T3ncaNPA8tIwX(h_-Lki6orcI|#&z5PKEnEi=MxU~qVk*^P$amxcX9WLnm{
z%S8_-aW>aE)|lgPq7!MV(CKoM&&<;bEzH_qiHh0=yO}HmY+o^?EmUh|H6;U{0KM^?
z4_G4NDC4=p%JHPhTEpL*O3YUvp|Pj&3oK!M?UaojmcKevaxnloqrv4|$6|A>xQ~G(
z4zIQ4;{@Qy9}2BfdU9%7zc-O?!IvVRyILLN!a9dY(#J)Ap`M0v^Ja9bDMux~DQ`ab
zXRKtaTNnL8Vt$-80rU|8Y{@ilU1!u53mQ1il@$h8B=h#*j8IRD
zlpcper}Huk?n14g7q35^GvpI6JV@(E=YoVn18L%{WU(&t?RZ*iyZUBVD(E2po<<$4
zl-O5Sd=^lX^|ty1P71bE@=;IzrVFyhM-5#RvDvs`p(7oAUE@t~e&^#<8
zcHoEJ03!xr{TsT_fz4F*L6kOH4U9oWc3jX75u)GyjCl+nqtc^El(d{QeN}w2#nicw57IvUHE;l
z1T^Sgv^~kcY5RWl((#@A8a>F88?*2kk~oDo)|B~I*c&EkY)$!NYy>Hh`|m`FqIlOe
za%wOdHjtrvK)@>;5*AIP#KRhnB`jMnG|f|Tkq*DnzeY{U{^d*qi5pnaMPe&u)v#f@
zxacg!Pfn{_Z9hu?ttTo|ltCyE_YyU5nTXzMWXy3Yv9r!44s)xz$B}RiwfE=351$=vnos~w&u335A55;fabS;8*UHHDKYU0PAWsSZE#%e$IT`DhL_rK<7?@pG6e*Xe$
zeUo{7&ITV`?-zEjGqtr%>I45UFvbSZyWe>dx`^|I5-z{xY%0$TjiKOkR}f9&GyU25n
zt@@g_C-4W
zOiL&vuHRv7STwW$HalsS*TAoe#SM|cx)x>7$mtD-ZsN8&OS!Gf6=n5~oU}eE)Si}D
z;pfuG>n#2)O%gOFBvvmd9N*TaN-p|~bok1=>VRV8{4bUg>%=&VEj{|7{c@GXidzBR
z$J?*v*QS(zoA`nKHWoD=Aiip^V99{7Ffn#JHp5Ggr*6Mc%AbG25t2k|tb-g}JYh`D
z*!kThf9>plcPS97=v*X!VDWxa=t4``I0%1wiz9tHNU5MJfs-OmKFD($JYvv%=OepQ
z&-I8@(=ZiYS&Qh~aXln4hY4q>e
z2t4`Lcwg^RO5cF7Px*6@9D&BQjA^oNWcBM-%O2g69d5
zzU_bRL_tZ_0u8mR9#+kI4R?}%b9sN{wb%e2paDoLYa9zl7u!8%GdYPM*ZN~JVW}8s
zU(`rByW&MRlDK>T;LLPX5QFG&CZ*JH#5@OSkTy2S*O~eJal#W_#(Q6?p%Ors08qU7
zw{xb*pj{QJfH#RV)YG-)uI$<_7fa!pV&U}vkukA)ZvFMf?^%&8h^<&EuRwd|A0ffH
zE;=>RwRMxD8K;l0F9^)&rJyJItYvej%a3g(ZAFV@8@8SwLWIp%)oow?a=`?Dj^g<|0Mj
zxMbjNS6pg+SEq8BK(zA;xp*M72Gm42BDWv?eFp4!AK6vO;%_RY
zEwz!+xT_O5FnDWVE>Vm@WZeAY-;~jsw(R!5`;;DAu2DKc;B_lEp@gf#P1@TqpsI%1
z^3ngnA(#lt;0b8(HWM9#yz%V!bdVCYt(a=_n?Lp3ddD;}h5c%XM
zQp(bZw_JZF@EaX)9C@yO{&iWjs~k8&wr^)Jq|UA!clFT@)=KGz1g%kc9C)L-fpX>i
zx$_z}J$JYw2ds(ZtOw;uMCidaV(AxHwElfU>_yH)04SgsqvY{S1ba{nIz>smz*(m43DBl{?AhUXx)?A~8%8Q2_xTtZhU%*b
z7*s1`t4hOXHn7n#U6p-;u=otw@YGm5<|#_Yq>Uq5Iw*ho_e}RcTYivVn@FoQ>2RY`Fe&VssG%@<^OG$Rvci?D3$2KDc10N
zm`s%dKbjfRFD;fbk(~J`lpIV{)`y24b6B`MO-hxNU(4!Bx|Ab+wQK+&l$R6NIFshc
z&`rv3y~Sg>OM_*oP7>^18&Px=h1KVAmUxldXRMLT=sFaOBHvpba_pXU^0>4F8k`YkHTRO6
zw=`viHZ%_zENNGX_){<2N>+Sc2&bl3Ppys{>c01>0~hNSWC*4fF++w1wswRx{cp@_J9(Z!Ka!
zX5)eo_g$STg!g_Rp3HM^9i}^XH)#DqXoxhZdQlIS`R9{%$r|6{&-GZ|K7rMkV}j?1
z%miCdAC82&!xeeLaW^Ic8)lTLj&xke>Q>0
z1nTAY9>Lo-QKsBn`;`y2v<7rpxURz>tt#4Q!E&L4S&%0aG!tXLXUy`&x2J}B!lpj=
zgbUOCR&kY2hST|Rl_ufI
zb8*Eb4qRQl&Ky4|RBE-NrnjiMjHLhIRVJ_Dmf#B5DcUHp-rSP`t3Nd3vdjJL=Cy$4
z!BrI4-n{W7LYLKoF(Gfm@ogBDHJ5lOCdKmKGZIvu0C
z`b!|0Blwp7jxbPEnDCb%pc$=XFr*4Q$07x%5gZ|fz`-69();KGTUKn>1`Rmu*3<~u
zr|;~*9Y7AmXX5tokP4SO=fCfQ$5~$D&t-&Wue#1L1}%E4yA?!Wp>Qz}RT`52d?97j
z?px#074#`_81lo8=f1LmTr2S*GyvKN+ZN%t8Sv&)(hF`J96!Op%~IpvZ_l
Ry?L>ihKjE8$A`Ah{}f)XSeyHMCQ45pw47@ezC1sY&~-W!x|72?
zqpev%=x%GFa)R4wA@TrFt@ak|iW^=PlueK%Vddf(}S6upe64$jvWF|X>T6j0mmSP$W?nOZGHfhi0^
zq$3U2|2?B(_M>m7R{F(|I6AS(?U+J#FQzK#aBC3ouw>ccxaJFO$?RRe^h+CK)Xf%2
zO+1ndo}mZBxupaNskjZ2f7Te$S_1rM!=2U>Ey-O^eUWDYx3g`qq~Jv8sX1cgxsADU
z#le}Nr6dNb$RpOOa{p#>5vN<9Rykg5qIK^aO)^svVb@JNW3TL`*~
z5DHQ}o=Sq#qUds(E=}cjPS;DE)$Gm=0&jpXI<2kHA*WIjz}d3UGy-?P0Ye#92m;+w
zP_&Y58Z`vuQlUp}=~62^3sE(xTuwECccGC3A$s7=eor&(81PI;f;vegW)eVA0z4qg
zIxeS6opAOR5+q8qG>f%dA#9G}vv+WZtVqx;&00v{t)h#rTJAC|tmlKr;ei%ZO)duo
zC|b={kZ^@!bkej`?gjK2#IVU=ofREN;KNroOD140Sb*%5I>+FAh7R7vaibi;MoNCv
zo-x{hAH;N=7&AI|JiU&DmmNn(e#97Q(93MW4gl3d^px{7n%b{sPo+_~3_(yW63h8|
zKD|!k>p@;nJ(NNrin#8j1a9oxub*f^O-S$U#dzsFv5GI=+aS?xJ<9XzP3xoL`_`Sp
ztOWMB6-s#k9=4!K6wkjCKOTrjB+69iB@DrTqP`Gboz8p(US`#N9L4A+U==Uf&3rJ$
z^lJClp;a3BixRoKQL?`#%QzdH@@EQW!hrp|#VO|?nrHPp*Zx5Ix9)FN`vd!^_VFn1
z0Z2!
zz(u0FTh6FqzCYb{L1CyfL$TN*GUuvxK;15qG=i!otJX4v<4r#0vfGdVk
zrrRI*!@)|ru-#o!lg_+0v<(9rWtwD(W;sQd4#X9Wsul3ElRox1jk#>taJ(pu+XSB;
zFH;%Ef~zHoiBFUg@Evuw?X?uIL(ijBC1L=N(A2H{Qalvh9akLDAHbWk)HPP4BsF==
z+}+(teBB%-TowS2IE`K<(ahuROeXw#08d9>vT5~LM1}gpjw{!}$?lrMchPs5P$b
zDSM`xqN9|i_Vn1@5hKpetINnOJon`->|ho(mmiRq^{@A)9X#P0xxnHr*meD4%rWMPfPl
zQR~RQne<7sLslcrc!m(nG3=Y-(PLY7q*Ju;%{7Wj6(cKTc25>Oa&K9xpU+CPI$LdI
zm3XZp7K9UzW2P}m1NqpcU&e_#`$^3WFMA%}F-IgElZ)4H-}fQ^4?y^Pt5wBQ*tI_c
DJv^ZF
diff --git a/karakeep/rootfs/etc/cont-init.d/90-folders.sh b/karakeep/rootfs/etc/cont-init.d/90-folders.sh
deleted file mode 100755
index 864dd25ea..000000000
--- a/karakeep/rootfs/etc/cont-init.d/90-folders.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/command/with-contenv bashio
-# shellcheck shell=bash
-set -e
-
-bashio::log.info "Creating folders"
-
-mkdir -p \
- /data/cache \
- /data/chrome \
- /config/meili \
- /usr/src/chrome/extensions
-
-if id chrome &>/dev/null; then
- chown -R chrome:chrome /data/cache /data/chrome /usr/src/chrome/extensions
-fi
diff --git a/karakeep/rootfs/etc/cont-init.d/91-secrets.sh b/karakeep/rootfs/etc/cont-init.d/91-secrets.sh
deleted file mode 100755
index b22cfd2e7..000000000
--- a/karakeep/rootfs/etc/cont-init.d/91-secrets.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/with-contenv bashio
-# shellcheck shell=bash
-set -e
-
-generate_secret() {
- # Avoid SIGPIPE from `tr` when `head` terminates early under pipefail.
- (
- set +o pipefail 2>/dev/null || true
- tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 64
- )
-}
-
-set_option() {
- local key="$1"
- local value="$2"
-
- # Store permanently in Home Assistant add-on options
- bashio::addon.option "${key}" "${value}"
-
- # Export into current process
- export "${key}=${value}"
-
- # Export into s6 so all services inherit it
- if [ -d /var/run/s6/container_environment ]; then
- printf "%s" "${value}" > "/var/run/s6/container_environment/${key}"
- fi
-}
-
-load_option() {
- local key="$1"
- local value
-
- value="$(bashio::config "${key}")"
- export "${key}=${value}"
-
- if [ -d /var/run/s6/container_environment ]; then
- printf "%s" "${value}" > "/var/run/s6/container_environment/${key}"
- fi
-}
-
-for key in MEILI_MASTER_KEY NEXTAUTH_SECRET; do
- if bashio::config.has_value "${key}"; then
- bashio::log.info "Using existing ${key}"
- load_option "${key}"
- else
- bashio::log.warning "${key} not set, generating persistent secret"
- value="$(generate_secret)"
- set_option "${key}" "${value}"
- fi
-done
diff --git a/karakeep/rootfs/etc/cont-init.d/92-chrome-extensions.sh b/karakeep/rootfs/etc/cont-init.d/92-chrome-extensions.sh
deleted file mode 100755
index 4df7b761f..000000000
--- a/karakeep/rootfs/etc/cont-init.d/92-chrome-extensions.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/command/with-contenv bashio
-# shellcheck shell=bash
-set -e
-
-EXTENSIONS_DIR="${CHROME_EXTENSIONS_DIR:-/usr/src/chrome/extensions}"
-bashio::log.info "Refreshing Chromium extensions in ${EXTENSIONS_DIR}"
-
-mkdir -p "${EXTENSIONS_DIR}"
-
-download_extension() {
- local name="$1"
- local extension_id="$2"
- local crx_path rc
-
- crx_path="$(mktemp)"
-
- if ! curl -fsSL \
- "https://clients2.google.com/service/update2/crx?response=redirect&prodversion=120.0&acceptformat=crx2,crx3&x=id%3D${extension_id}%26installsource%3Dondemand%26uc" \
- -o "${crx_path}"; then
- rm -f "${crx_path}"
- bashio::log.warning "Failed to download extension ${name}. Continuing without refresh."
- return 0
- fi
-
- rm -rf "${EXTENSIONS_DIR:?}/${name}"
- mkdir -p "${EXTENSIONS_DIR}/${name}"
-
- rc=0
- unzip -q "${crx_path}" -d "${EXTENSIONS_DIR}/${name}" || rc=$?
- rm -f "${crx_path}"
-
- # unzip may return 1 even though files extracted (common with CRX zip metadata)
- if [ "${rc}" -ne 0 ] && [ "${rc}" -ne 1 ]; then
- bashio::log.warning "Failed to unzip extension ${name} (rc=${rc}). Continuing."
- return 0
- fi
-
- return 0
-}
-
-download_extension "i-dont-care-about-cookies" "fllaojicojecljbmefodhfapmkghcbnh"
-download_extension "ublock-origin" "cjpalhdlnbpafiamejdnhcphjbkeiagm"
-
-if id chrome &>/dev/null; then
- chown -R chrome:chrome "${EXTENSIONS_DIR}"
-fi
diff --git a/karakeep/rootfs/etc/fonts/local.conf b/karakeep/rootfs/etc/fonts/local.conf
new file mode 100644
index 000000000..ed6c08b91
--- /dev/null
+++ b/karakeep/rootfs/etc/fonts/local.conf
@@ -0,0 +1,31 @@
+
+
+
+
+
+ sans-serif
+
+ Main sans-serif font name goes here
+ Noto Color Emoji
+ Noto Emoji
+
+
+
+
+ serif
+
+ Main serif font name goes here
+ Noto Color Emoji
+ Noto Emoji
+
+
+
+
+ monospace
+
+ Main monospace font name goes here
+ Noto Color Emoji
+ Noto Emoji
+
+
+
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/nginx/includes/mime.types b/karakeep/rootfs/etc/nginx/includes/mime.types
new file mode 100644
index 000000000..c23021204
--- /dev/null
+++ b/karakeep/rootfs/etc/nginx/includes/mime.types
@@ -0,0 +1,96 @@
+types {
+ text/html html htm shtml;
+ text/css css;
+ text/xml xml;
+ image/gif gif;
+ image/jpeg jpeg jpg;
+ application/javascript js;
+ application/atom+xml atom;
+ application/rss+xml rss;
+
+ text/mathml mml;
+ text/plain txt;
+ text/vnd.sun.j2me.app-descriptor jad;
+ text/vnd.wap.wml wml;
+ text/x-component htc;
+
+ image/png png;
+ image/svg+xml svg svgz;
+ image/tiff tif tiff;
+ image/vnd.wap.wbmp wbmp;
+ image/webp webp;
+ image/x-icon ico;
+ image/x-jng jng;
+ image/x-ms-bmp bmp;
+
+ font/woff woff;
+ font/woff2 woff2;
+
+ application/java-archive jar war ear;
+ application/json json;
+ application/mac-binhex40 hqx;
+ application/msword doc;
+ application/pdf pdf;
+ application/postscript ps eps ai;
+ application/rtf rtf;
+ application/vnd.apple.mpegurl m3u8;
+ application/vnd.google-earth.kml+xml kml;
+ application/vnd.google-earth.kmz kmz;
+ application/vnd.ms-excel xls;
+ application/vnd.ms-fontobject eot;
+ application/vnd.ms-powerpoint ppt;
+ application/vnd.oasis.opendocument.graphics odg;
+ application/vnd.oasis.opendocument.presentation odp;
+ application/vnd.oasis.opendocument.spreadsheet ods;
+ application/vnd.oasis.opendocument.text odt;
+ application/vnd.openxmlformats-officedocument.presentationml.presentation
+ pptx;
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
+ xlsx;
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document
+ docx;
+ application/vnd.wap.wmlc wmlc;
+ application/x-7z-compressed 7z;
+ application/x-cocoa cco;
+ application/x-java-archive-diff jardiff;
+ application/x-java-jnlp-file jnlp;
+ application/x-makeself run;
+ application/x-perl pl pm;
+ application/x-pilot prc pdb;
+ application/x-rar-compressed rar;
+ application/x-redhat-package-manager rpm;
+ application/x-sea sea;
+ application/x-shockwave-flash swf;
+ application/x-stuffit sit;
+ application/x-tcl tcl tk;
+ application/x-x509-ca-cert der pem crt;
+ application/x-xpinstall xpi;
+ application/xhtml+xml xhtml;
+ application/xspf+xml xspf;
+ application/zip zip;
+
+ application/octet-stream bin exe dll;
+ application/octet-stream deb;
+ application/octet-stream dmg;
+ application/octet-stream iso img;
+ application/octet-stream msi msp msm;
+
+ audio/midi mid midi kar;
+ audio/mpeg mp3;
+ audio/ogg ogg;
+ audio/x-m4a m4a;
+ audio/x-realaudio ra;
+
+ video/3gpp 3gpp 3gp;
+ video/mp2t ts;
+ video/mp4 mp4;
+ video/mpeg mpeg mpg;
+ video/quicktime mov;
+ video/webm webm;
+ video/x-flv flv;
+ video/x-m4v m4v;
+ video/x-mng mng;
+ video/x-ms-asf asx asf;
+ video/x-ms-wmv wmv;
+ video/x-msvideo avi;
+}
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/nginx/includes/proxy_params.conf b/karakeep/rootfs/etc/nginx/includes/proxy_params.conf
new file mode 100644
index 000000000..7aa69699a
--- /dev/null
+++ b/karakeep/rootfs/etc/nginx/includes/proxy_params.conf
@@ -0,0 +1,15 @@
+proxy_http_version 1.1;
+proxy_ignore_client_abort off;
+proxy_read_timeout 86400s;
+proxy_redirect off;
+proxy_send_timeout 86400s;
+proxy_max_temp_file_size 0;
+
+proxy_set_header Accept-Encoding "";
+proxy_set_header Connection $connection_upgrade;
+proxy_set_header Host $http_host;
+proxy_set_header Upgrade $http_upgrade;
+proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+proxy_set_header X-Forwarded-Proto $scheme;
+proxy_set_header X-NginX-Proxy true;
+proxy_set_header X-Real-IP $remote_addr;
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/nginx/includes/resolver.conf b/karakeep/rootfs/etc/nginx/includes/resolver.conf
new file mode 100644
index 000000000..be0943d63
--- /dev/null
+++ b/karakeep/rootfs/etc/nginx/includes/resolver.conf
@@ -0,0 +1 @@
+resolver 127.0.0.11 ipv6=off;
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/nginx/includes/server_params.conf b/karakeep/rootfs/etc/nginx/includes/server_params.conf
new file mode 100644
index 000000000..f67263b2c
--- /dev/null
+++ b/karakeep/rootfs/etc/nginx/includes/server_params.conf
@@ -0,0 +1,6 @@
+root /dev/null;
+server_name $hostname;
+
+add_header X-Content-Type-Options nosniff;
+add_header X-XSS-Protection "1; mode=block";
+add_header X-Robots-Tag none;
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/nginx/includes/ssl_params.conf b/karakeep/rootfs/etc/nginx/includes/ssl_params.conf
new file mode 100644
index 000000000..adb5185f2
--- /dev/null
+++ b/karakeep/rootfs/etc/nginx/includes/ssl_params.conf
@@ -0,0 +1,8 @@
+ssl_protocols TLSv1.2 TLSv1.3;
+ssl_prefer_server_ciphers off;
+ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
+ssl_session_timeout 10m;
+ssl_session_cache shared:SSL:10m;
+ssl_session_tickets off;
+#ssl_stapling on;
+#ssl_stapling_verify on;
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/nginx/nginx.conf b/karakeep/rootfs/etc/nginx/nginx.conf
new file mode 100644
index 000000000..cb593fd2a
--- /dev/null
+++ b/karakeep/rootfs/etc/nginx/nginx.conf
@@ -0,0 +1,52 @@
+# Run nginx in foreground.
+daemon off;
+
+# This is run inside Docker.
+user root;
+
+# Pid storage location.
+pid /var/run/nginx.pid;
+
+# Set number of worker processes.
+worker_processes 1;
+
+# Enables the use of JIT for regular expressions to speed-up their processing.
+pcre_jit on;
+
+# Write error log to the add-on log.
+error_log /proc/1/fd/1 error;
+
+# Load allowed environment vars
+env HASSIO_TOKEN;
+
+# Load dynamic modules.
+include /etc/nginx/modules/*.conf;
+
+# Max num of simultaneous connections by a worker process.
+events {
+ worker_connections 512;
+}
+
+http {
+ include /etc/nginx/includes/mime.types;
+
+ access_log off;
+ client_max_body_size 4G;
+ default_type application/octet-stream;
+ gzip on;
+ keepalive_timeout 65;
+ sendfile on;
+ server_tokens off;
+ tcp_nodelay on;
+ tcp_nopush on;
+
+ map $http_upgrade $connection_upgrade {
+ default upgrade;
+ '' close;
+ }
+
+ include /etc/nginx/includes/resolver.conf;
+ include /etc/nginx/includes/upstream.conf;
+
+ include /etc/nginx/servers/*.conf;
+}
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-web/dependencies.d/svc-chrome b/karakeep/rootfs/etc/nginx/servers/.gitkeep
similarity index 100%
rename from karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-web/dependencies.d/svc-chrome
rename to karakeep/rootfs/etc/nginx/servers/.gitkeep
diff --git a/karakeep/rootfs/etc/nginx/templates/direct.gtpl b/karakeep/rootfs/etc/nginx/templates/direct.gtpl
new file mode 100644
index 000000000..2c8d137a1
--- /dev/null
+++ b/karakeep/rootfs/etc/nginx/templates/direct.gtpl
@@ -0,0 +1,31 @@
+server {
+ {{ if not .ssl }}
+ listen {{ .port }} default_server;
+ {{ else }}
+ listen {{ .port }} default_server ssl;
+ {{ end }}
+
+ include /etc/nginx/includes/server_params.conf;
+ include /etc/nginx/includes/proxy_params.conf;
+
+ {{ if .ssl }}
+ include /etc/nginx/includes/ssl_params.conf;
+
+ ssl_certificate {{ .certfile }};
+ ssl_certificate_key {{ .keyfile }};
+ {{ end }}
+
+ location / {
+ {{ if .ingress_user }}
+ set $ingress_user "";
+
+ if ($remote_addr = 172.30.32.2) {
+ set $ingress_user {{ .ingress_user }};
+ }
+
+ proxy_set_header X-WebAuth-User $ingress_user;
+ {{ end }}
+
+ proxy_pass {{ .protocol }}://backend;
+ }
+}
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/nginx/templates/upstream.gtpl b/karakeep/rootfs/etc/nginx/templates/upstream.gtpl
new file mode 100644
index 000000000..d37ee59f9
--- /dev/null
+++ b/karakeep/rootfs/etc/nginx/templates/upstream.gtpl
@@ -0,0 +1,3 @@
+upstream backend {
+ server 127.0.0.1:{{ .port }};
+}
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-web/dependencies.d/svc-meilisearch b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/dependencies.d/base
similarity index 100%
rename from karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-web/dependencies.d/svc-meilisearch
rename to karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/dependencies.d/base
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/run b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/run
new file mode 100644
index 000000000..e3fba3022
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/run
@@ -0,0 +1,59 @@
+#!/command/with-contenv bash
+# shellcheck shell=bash
+
+set -e
+
+echo " Loading env variables:"
+
+OPTIONS_SOURCE=/data/options.json
+
+while read -r -d $'\0' key && read -r value; do
+
+ line="$key=$value"
+
+ # log redacted config
+ case "$key" in
+ *PASS*|*SECRET*|*KEY*|*TOKEN*)
+ echo " $key=******"
+ ;;
+ *)
+ echo " $line"
+ ;;
+ esac
+
+ export $key=$value
+
+ # set .env
+ echo "$line" >> /.env || true
+
+ # set /etc/environment
+ echo "$line" >> /etc/environment
+
+ # For s6
+ if [ -d /var/run/s6/container_environment ]; then
+ printf "%s" "$value" > /var/run/s6/container_environment/"$key"
+ fi
+
+ echo "export $line" >> ~/.bashrc
+done < <(
+ jq -r '
+ reduce to_entries[] as $item (
+ {};
+ if $item.value | type == "object" then
+ . + $item.value
+ else
+ . + { ($item.key): $item.value }
+ end
+ )
+ | to_entries[]
+ | "\(.key)\u0000\(.value|tostring)"
+ ' "$OPTIONS_SOURCE"
+)
+
+if [ -n "$TZ" ] && [ -f /etc/localtime ]; then
+ if [ -f /usr/share/zoneinfo/"$TZ" ]; then
+ echo "Timezone set to $TZ"
+ ln -snf /usr/share/zoneinfo/"$TZ" /etc/localtime
+ echo "$TZ" >/etc/timezone
+ fi
+fi
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/type b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/type
new file mode 100644
index 000000000..3d92b15f2
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/type
@@ -0,0 +1 @@
+oneshot
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/up b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/up
new file mode 100644
index 000000000..b6f7a938e
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-addon-config/up
@@ -0,0 +1 @@
+/etc/s6-overlay/s6-rc.d/init-addon-config/run
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-workers/dependencies.d/svc-chrome b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-db-migration/dependencies.d/init-folders
similarity index 100%
rename from karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-workers/dependencies.d/svc-chrome
rename to karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-db-migration/dependencies.d/init-folders
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-workers/dependencies.d/svc-meilisearch b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-db-migration/dependencies.d/svc-chrome
similarity index 100%
rename from karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-workers/dependencies.d/svc-meilisearch
rename to karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-db-migration/dependencies.d/svc-chrome
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-db-migration/dependencies.d/svc-meilisearch b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-db-migration/dependencies.d/svc-meilisearch
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/dependencies.d/init-addon-config b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/dependencies.d/init-addon-config
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/run b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/run
new file mode 100644
index 000000000..eb00b6a41
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/run
@@ -0,0 +1,8 @@
+#!/command/with-contenv bash
+# shellcheck shell=bash
+
+set -e
+
+if [ ! -d "$DATA_DIR" ]; then
+ mkdir -p "$DATA_DIR"
+fi
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/type b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/type
new file mode 100644
index 000000000..3d92b15f2
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/type
@@ -0,0 +1 @@
+oneshot
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/up b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/up
new file mode 100644
index 000000000..1fd74db37
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-folders/up
@@ -0,0 +1 @@
+/etc/s6-overlay/s6-rc.d/init-folders/run
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/dependencies.d/init-addon-config b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/dependencies.d/init-addon-config
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run
new file mode 100644
index 000000000..8203b6a4f
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run
@@ -0,0 +1,49 @@
+#!/command/with-contenv bashio
+# shellcheck shell=bash
+
+set -e
+
+OPTIONS_SOURCE=/data/options.json
+
+service_port=${SERVICE_PORT:-80}
+service_protocol=${SERVICE_PROTOCOL:-http}
+nginx_port=${NGINX_PORT:-8080}
+certfile="/ssl/$(jq -r '.certfile' $OPTIONS_SOURCE)"
+keyfile="/ssl/$(jq -r '.keyfile' $OPTIONS_SOURCE)"
+ingress_user=$(jq -r '.ingress_user' $OPTIONS_SOURCE)
+
+# Generate upstream configuration
+printf '{ "port": "%s" }' "$service_port" \
+ | tempio \
+ -template /etc/nginx/templates/upstream.gtpl \
+ -out /etc/nginx/includes/upstream.conf
+
+if jq -e '.ssl == true' $OPTIONS_SOURCE > /dev/null; then
+ # Require certfile and keyfile
+ #bashio::config.require 'certfile'
+ #bashio::config.require 'keyfile'
+
+ # If certfile or keyfile does not exist, generate self-signed cert
+ if [ ! -f "$certfile" ] || [ ! -f "$keyfile" ]; then
+ bashio::log.warning "SSL is enabled, but either certfile, keyfile or both are missing. Falling back to a self-signed certificate..."
+
+ certfile="/data/ssl/fullchain.pem"
+ keyfile="/data/ssl/privkey.pem"
+
+ /usr/local/bin/ssl-check-generate.sh "$certfile" "$keyfile" true
+ else
+ /usr/local/bin/ssl-check-generate.sh "$certfile" "$keyfile" false
+ fi
+fi
+
+printf '{
+ "certfile": "%s",
+ "keyfile": "%s",
+ "port": "%s",
+ "protocol": "%s",
+ "ssl": %s,
+ "ingress_user": "%s"
+}' "$certfile" "$keyfile" "$nginx_port" "$service_protocol" "$(jq -r '.ssl' $OPTIONS_SOURCE)" "$ingress_user" \
+ | tempio \
+ -template /etc/nginx/templates/direct.gtpl \
+ -out /etc/nginx/servers/direct.conf
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/type b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/type
new file mode 100644
index 000000000..3d92b15f2
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/type
@@ -0,0 +1 @@
+oneshot
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/up b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/up
new file mode 100644
index 000000000..60ba159c2
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/up
@@ -0,0 +1 @@
+/etc/s6-overlay/s6-rc.d/init-nginx/run
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/dependencies.d/init-folders b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/dependencies.d/init-folders
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/run b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/run
index e13702a2e..5f5a1108b 100644
--- a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/run
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/run
@@ -1,21 +1,148 @@
-#!/command/with-contenv bashio
+#!/bin/bash
# shellcheck shell=bash
-set -e
+set -euo pipefail
-EXTENSIONS_DIR="${CHROME_EXTENSIONS_DIR:-/usr/src/chrome/extensions}"
+############################
+# Configurable directories #
+############################
-extensions=()
-for extension in "${EXTENSIONS_DIR}/i-dont-care-about-cookies" "${EXTENSIONS_DIR}/ublock-origin"; do
- if [ -d "$extension" ]; then
- extensions+=("$extension")
+CHROME_CACHE_DIR="/data/cache"
+CHROME_PROFILE_DIR="/data/chrome-profile"
+EXT_BASE_DIR="/data/extensions"
+
+# Extension IDs (Chrome Web Store)
+# uBlock Origin (MV2): cjpalhdlnbpafiamejdnhcphjbkeiagm
+# I don't care about cookies: fihnjjcciajhdojfnbdddfaoknhalnja
+UBLOCK_ID="cjpalhdlnbpafiamejdnhcphjbkeiagm"
+IDCAC_ID="fihnjjcciajhdojfnbdddfaoknhalnja"
+
+UBLOCK_DIR="${EXT_BASE_DIR}/ublock"
+IDCAC_DIR="${EXT_BASE_DIR}/idontcareaboutcookies"
+
+#################################
+# Ensure persistent writable FS #
+#################################
+
+mkdir -p "$CHROME_CACHE_DIR" "$CHROME_PROFILE_DIR" "$EXT_BASE_DIR"
+chown -R chrome:chrome "$CHROME_CACHE_DIR" "$CHROME_PROFILE_DIR" "$EXT_BASE_DIR"
+
+########################
+# Helper: download CRX #
+########################
+
+need_bin() {
+ local b="$1"
+ if ! command -v "$b" >/dev/null 2>&1; then
+ echo "Missing required binary: $b"
+ exit 1
fi
-done
+}
-extension_flag=""
-if [ ${#extensions[@]} -gt 0 ]; then
- extension_flag="--load-extension=$(IFS=,; echo "${extensions[*]}")"
-fi
+crx_to_zip() {
+ # CRX2/CRX3 contains a header before the ZIP payload.
+ # We locate the first ZIP local-file header "PK\003\004" and write from there.
+ local crx="$1"
+ local zip="$2"
+
+ python3 - "$crx" "$zip" <<'PY'
+import sys
+
+crx_path, zip_path = sys.argv[1], sys.argv[2]
+with open(crx_path, "rb") as f:
+ data = f.read()
+
+sig = b"PK\x03\x04"
+i = data.find(sig)
+if i == -1:
+ raise SystemExit("Could not find ZIP signature in CRX (PK\\x03\\x04).")
+
+with open(zip_path, "wb") as f:
+ f.write(data[i:])
+PY
+}
+
+download_and_unpack_extension() {
+ local ext_id="$1"
+ local out_dir="$2"
+ local name="$3"
+
+ # Skip if already unpacked
+ if [ -f "${out_dir}/manifest.json" ]; then
+ return 0
+ fi
+
+ need_bin python3
+ need_bin curl
+ need_bin unzip
+
+ mkdir -p "$out_dir"
+ chown -R chrome:chrome "$out_dir"
+
+ local tmpdir
+ tmpdir="$(mktemp -d)"
+ # shellcheck disable=SC2064
+ trap "rm -rf '$tmpdir'" EXIT
+
+ local crx="${tmpdir}/${name}.crx"
+ local zip="${tmpdir}/${name}.zip"
+
+ # CWS update endpoint (works for most public extensions)
+ # Note: prodversion is just a hint; keep it reasonably recent.
+ local url
+ url="https://clients2.google.com/service/update2/crx?response=redirect&prodversion=120.0.0.0&acceptformat=crx2,crx3&x=id%3D${ext_id}%26installsource%3Dondemand%26uc"
+
+ echo "Downloading ${name} (${ext_id})..."
+ curl -fsSL "$url" -o "$crx"
+
+ echo "Unpacking ${name}..."
+ crx_to_zip "$crx" "$zip"
+
+ # Unzip into a clean directory
+ rm -rf "${out_dir:?}/"*
+ unzip -q "$zip" -d "$out_dir"
+
+ chown -R chrome:chrome "$out_dir"
+
+ # Basic validation
+ if [ ! -f "${out_dir}/manifest.json" ]; then
+ echo "Failed to unpack ${name}: manifest.json not found in ${out_dir}"
+ exit 1
+ fi
+
+ rm -rf "$tmpdir"
+ trap - EXIT
+}
+
+#########################
+# Download extensions #
+#########################
+
+download_and_unpack_extension "$UBLOCK_ID" "$UBLOCK_DIR" "ublock-origin"
+download_and_unpack_extension "$IDCAC_ID" "$IDCAC_DIR" "i-dont-care-about-cookies"
+
+EXTENSIONS="${UBLOCK_DIR},${IDCAC_DIR}"
+
+#########################
+# Start Chromium #
+#########################
cd /usr/src/chrome
-exec su chrome -c "chromium-browser --headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222 --hide-scrollbars --disable-crash-reporter --no-crash-upload --user-data-dir=/data/chrome ${extension_flag}"
+# Use exec so s6 can manage the process; avoid backgrounding and /dev/null-ing
+exec su chrome -c "
+ chromium-browser \
+ --headless=new \
+ --no-sandbox \
+ --disable-gpu \
+ --disable-dev-shm-usage \
+ --disable-crash-reporter \
+ --no-crash-upload \
+ --hide-scrollbars \
+ --remote-debugging-address=0.0.0.0 \
+ --remote-debugging-port=9222 \
+ --user-data-dir='${CHROME_PROFILE_DIR}' \
+ --disk-cache-dir='${CHROME_CACHE_DIR}' \
+ --disable-extensions-except='${EXTENSIONS}' \
+ --load-extension='${EXTENSIONS}' \
+ about:blank
+"
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/type b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/type
index 5883cff0c..1780f9f44 100644
--- a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/type
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/type
@@ -1 +1 @@
-longrun
+longrun
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/up b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/up
new file mode 100644
index 000000000..ea0dde696
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-chrome/up
@@ -0,0 +1 @@
+/etc/s6-overlay/s6-rc.d/svc-chrome/run
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/dependencies.d/init-folders b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/dependencies.d/init-folders
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/run b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/run
index 9af8cd43d..a5e5681b3 100644
--- a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/run
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/run
@@ -1,7 +1,12 @@
-#!/command/with-contenv bashio
+#!/command/with-contenv bash
# shellcheck shell=bash
+
set -e
-mkdir -p "${MEILI_DIR}"
+if [ ! -d "$MEILI_DIR" ]; then
+ mkdir -p "$MEILI_DIR"
+fi
-exec /bin/meilisearch --db-path "${MEILI_DIR}" --no-analytics --experimental-dumpless-upgrade
+cd "$MEILI_DIR"
+
+exec /bin/meilisearch --no-analytics --experimental-dumpless-upgrade
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/type b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/type
index 5883cff0c..1780f9f44 100644
--- a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/type
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/type
@@ -1 +1 @@
-longrun
+longrun
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/up b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/up
new file mode 100644
index 000000000..a3be200b9
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-meilisearch/up
@@ -0,0 +1 @@
+/etc/s6-overlay/s6-rc.d/svc-meilisearch/run
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/dependencies.d/init-nginx b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/dependencies.d/init-nginx
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/run b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/run
new file mode 100644
index 000000000..96acd5752
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/run
@@ -0,0 +1,9 @@
+#!/command/with-contenv bashio
+# shellcheck shell=bash
+
+set -e
+
+bashio::net.wait_for "$SERVICE_PORT" localhost 900
+
+bashio::log.info "Starting NGinx..."
+exec nginx
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/type b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/type
new file mode 100644
index 000000000..1780f9f44
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/type
@@ -0,0 +1 @@
+longrun
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/up b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/up
new file mode 100644
index 000000000..e0a24bcc0
--- /dev/null
+++ b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/svc-nginx/up
@@ -0,0 +1 @@
+/etc/s6-overlay/s6-rc.d/svc-nginx/run
\ No newline at end of file
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/init-addon-config b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/init-addon-config
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/init-nginx b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/init-nginx
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/svc-nginx b/karakeep/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/svc-nginx
new file mode 100644
index 000000000..e69de29bb
diff --git a/karakeep/rootfs/usr/local/bin/ssl-check-generate.sh b/karakeep/rootfs/usr/local/bin/ssl-check-generate.sh
new file mode 100644
index 000000000..d18267890
--- /dev/null
+++ b/karakeep/rootfs/usr/local/bin/ssl-check-generate.sh
@@ -0,0 +1,47 @@
+#!/command/with-contenv bashio
+# shellcheck shell=bash
+
+set -e
+
+# Check for required arguments
+if [ $# -ne 3 ]; then
+ bashio::log.error "[ssl-check-generate.sh] missing: "
+ exit 1
+fi
+
+bashio::log.debug "SSL Certificate check"
+
+renew_days=90
+
+certfile="$1"
+keyfile="$2"
+selfsigned=${3:-true}
+
+if [ ! -f "$certfile" ] || [ ! -f "$keyfile" ]; then
+ if [ "$selfsigned" = "true" ]; then
+ /usr/local/bin/ssl-keygen.sh "$certfile" "$keyfile"
+ exit 0
+ else
+ bashio::log.error "[ssl-check-generate.sh] either certfile, keyfile, or both are missing"
+ exit 1
+ fi
+fi
+
+enddate=$(openssl x509 -enddate -noout -in "$certfile" 2>/dev/null || true)
+if [ -n "$enddate" ]; then
+ expiry_date=$(echo "$enddate" | cut -d= -f2 | sed 's/ GMT$//')
+ expiry_ts=$(date -d "$expiry_date" +%s)
+ now_ts=$(date +%s)
+ days_left=$(( (expiry_ts - now_ts) / 86400 ))
+
+ if [ "$days_left" -le "$renew_days" ]; then
+ bashio::log.info "Self-signed cert expiring in $days_left days, regenerating..."
+ /usr/local/bin/ssl-keygen.sh "$certfile" "$keyfile"
+ fi
+else
+ bashio::log.error "Unable to determine ssl certificate expiry date"
+fi
+
+if pgrep -x nginx >/dev/null 2>&1; then
+ nginx -s reload
+fi
\ No newline at end of file
diff --git a/karakeep/rootfs/usr/local/bin/ssl-keygen.sh b/karakeep/rootfs/usr/local/bin/ssl-keygen.sh
new file mode 100644
index 000000000..da821340d
--- /dev/null
+++ b/karakeep/rootfs/usr/local/bin/ssl-keygen.sh
@@ -0,0 +1,57 @@
+#!/command/with-contenv bashio
+# shellcheck shell=bash
+
+set -e
+
+# Check for required arguments
+if [ $# -ne 2 ]; then
+ bashio::log.error "[ssl-keygen.sh] missing: "
+ exit 1
+fi
+
+certfile="$1"
+keyfile="$2"
+
+[ -f "$certfile" ] && rm -f "$certfile"
+[ -f "$keyfile" ] && rm -f "$keyfile"
+
+mkdir -p "$(dirname "$certfile")" && mkdir -p "$(dirname "$keyfile")"
+
+if ! hostname="$(bashio::info.hostname 2> /dev/null)" || [ -z "$hostname" ]; then
+ hostname="homeassistant"
+fi
+tmp_openssl_cfg=$(mktemp)
+trap 'rm -f "$tmp_openssl_cfg"' EXIT
+
+cat > "$tmp_openssl_cfg" <