From 1a797b4b7068e3f917cc98d527f40a262093130f Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Tue, 20 Feb 2024 12:01:40 +0200 Subject: [PATCH] syncthing - migrate library (#2181) * update templates * fix names * update ui * add group * add migration * wrong dir * fix typo * rename * add hostnet test --- library/ix-dev/charts/syncthing/Chart.lock | 8 +- library/ix-dev/charts/syncthing/Chart.yaml | 6 +- library/ix-dev/charts/syncthing/README.md | 4 +- library/ix-dev/charts/syncthing/app-readme.md | 7 +- .../charts/syncthing/charts/common-1.2.9.tgz | Bin 0 -> 63215 bytes .../syncthing/charts/common-2304.0.1.tgz | Bin 4995 -> 0 bytes .../charts/syncthing/ci/basic-values.yaml | 8 + .../charts/syncthing/ci/host-values.yaml | 7 + .../charts/syncthing/ci/test-values.yaml | 16 - .../charts/syncthing/migrations/migrate | 94 ++++ .../ix-dev/charts/syncthing/questions.yaml | 520 ++++++++++++------ .../charts/syncthing/templates/NOTES.txt | 1 + .../charts/syncthing/templates/_migration.tpl | 35 ++ .../syncthing/templates/_persistence.tpl | 26 + .../charts/syncthing/templates/_portal.tpl | 12 + .../charts/syncthing/templates/_service.tpl | 25 + .../charts/syncthing/templates/_syncthing.tpl | 62 +++ .../charts/syncthing/templates/common.yaml | 13 + .../syncthing/templates/deployment.yaml | 98 ---- .../syncthing/templates/pre-install-job.yaml | 32 -- .../charts/syncthing/templates/service.yaml | 11 - .../charts/syncthing/to_keep_versions.md | 4 + .../charts/syncthing/to_keep_versions.yaml | 1 + library/ix-dev/charts/syncthing/values.yaml | 29 + 24 files changed, 693 insertions(+), 326 deletions(-) create mode 100644 library/ix-dev/charts/syncthing/charts/common-1.2.9.tgz delete mode 100644 library/ix-dev/charts/syncthing/charts/common-2304.0.1.tgz create mode 100644 library/ix-dev/charts/syncthing/ci/basic-values.yaml create mode 100644 library/ix-dev/charts/syncthing/ci/host-values.yaml delete mode 100644 library/ix-dev/charts/syncthing/ci/test-values.yaml create mode 100755 library/ix-dev/charts/syncthing/migrations/migrate create mode 100644 library/ix-dev/charts/syncthing/templates/NOTES.txt create mode 100644 library/ix-dev/charts/syncthing/templates/_migration.tpl create mode 100644 library/ix-dev/charts/syncthing/templates/_persistence.tpl create mode 100644 library/ix-dev/charts/syncthing/templates/_portal.tpl create mode 100644 library/ix-dev/charts/syncthing/templates/_service.tpl create mode 100644 library/ix-dev/charts/syncthing/templates/_syncthing.tpl create mode 100644 library/ix-dev/charts/syncthing/templates/common.yaml delete mode 100644 library/ix-dev/charts/syncthing/templates/deployment.yaml delete mode 100644 library/ix-dev/charts/syncthing/templates/pre-install-job.yaml delete mode 100644 library/ix-dev/charts/syncthing/templates/service.yaml create mode 100644 library/ix-dev/charts/syncthing/to_keep_versions.md create mode 100644 library/ix-dev/charts/syncthing/to_keep_versions.yaml diff --git a/library/ix-dev/charts/syncthing/Chart.lock b/library/ix-dev/charts/syncthing/Chart.lock index 007e4ddd80..274788bff2 100644 --- a/library/ix-dev/charts/syncthing/Chart.lock +++ b/library/ix-dev/charts/syncthing/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common - repository: file://../../../common/2304.0.1 - version: 2304.0.1 -digest: sha256:1ed155c6760e1166e2cb75b52bc5e81c6bdf0252c16ff5ede001157077c41670 -generated: "2023-04-24T13:41:41.407776764+03:00" + repository: file://../../../common + version: 1.2.9 +digest: sha256:af1a9a1f87e3e48453c9f25f909f5ebcd7fa6e25162b7b425448ba752bcdbc5c +generated: "2024-02-16T16:11:26.539168004+02:00" diff --git a/library/ix-dev/charts/syncthing/Chart.yaml b/library/ix-dev/charts/syncthing/Chart.yaml index e65ff78ac6..34d1a64ed0 100644 --- a/library/ix-dev/charts/syncthing/Chart.yaml +++ b/library/ix-dev/charts/syncthing/Chart.yaml @@ -3,7 +3,7 @@ description: Syncthing is a continuous file synchronization program. annotations: title: Syncthing type: application -version: 1.0.42 +version: 2.0.0 apiVersion: v2 appVersion: 1.27.3 kubeVersion: '>=1.16.0-0' @@ -13,8 +13,8 @@ maintainers: email: dev@ixsystems.com dependencies: - name: common - repository: file://../../../common/2304.0.1 - version: 2304.0.1 + repository: file://../../../common + version: 1.2.9 home: https://syncthing.net/ icon: https://media.sys.truenas.net/apps/syncthing/icons/icon.svg sources: diff --git a/library/ix-dev/charts/syncthing/README.md b/library/ix-dev/charts/syncthing/README.md index ea0896841d..2003609595 100644 --- a/library/ix-dev/charts/syncthing/README.md +++ b/library/ix-dev/charts/syncthing/README.md @@ -1,5 +1,7 @@ # Syncthing -[syncthing](https://syncthing.net/) is a continuous file synchronization program. It synchronizes files between two or +[Syncthing](https://syncthing.net/) is a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it's transmitted over the internet. + +> **WARNING** Do check out [official docs](https://docs.syncthing.net/users/faq.html#what-things-are-synced) to see what is synced. diff --git a/library/ix-dev/charts/syncthing/app-readme.md b/library/ix-dev/charts/syncthing/app-readme.md index 9f0f625bcf..2003609595 100644 --- a/library/ix-dev/charts/syncthing/app-readme.md +++ b/library/ix-dev/charts/syncthing/app-readme.md @@ -1,6 +1,7 @@ # Syncthing -[syncthing](https://syncthing.net/) is a continuous file synchronization program. It synchronizes files between two or -more computers in real time, safely protected from prying eyes. +[Syncthing](https://syncthing.net/) is a continuous file synchronization program. It synchronizes files between two or +more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose +where it is stored, whether it is shared with some third party, and how it's transmitted over the internet. -> **WARNING** Do check out https://docs.syncthing.net/users/faq.html#what-things-are-synced to see what is synced. +> **WARNING** Do check out [official docs](https://docs.syncthing.net/users/faq.html#what-things-are-synced) to see what is synced. diff --git a/library/ix-dev/charts/syncthing/charts/common-1.2.9.tgz b/library/ix-dev/charts/syncthing/charts/common-1.2.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ee644602d968a1f7360f9a82f183b28327c5603c GIT binary patch literal 63215 zcmV)zK#{*6iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0POwwciT9!D2~t1{wwe}&K;|tCCmGaUnlqLcG79z=_Ee3)BSxn zH!lY!A&Fy(U=xrWPvZambFdNs!9|OerNwi)Ba>JP1)w$*szN*-<8U9~ zxG#5b-^c^g6jMlJoRX6b0BB4TbOO%!ssO*nH#yAj0bd;(FpGafIf-$40;YQ#Fw2TR zcQ+zL!aU9>|N9gqvTDexf&tD!{Qn1U27@?^VFJz|g$W*RjA5Ko7^f&FCmUUW#xPD! zK!m3MzxX4$ClrlIFT~>w08%(cCxGS?ltQurz$8yjz=+a}ob2q}-QD%%CsurCLzEV4 zdxPF*=tKduF;y_{_V#-J*!a@;|I&}#|5KPu5P2j5(6IlH50CcT{eOJ8zuy0=c>W5y zU9c75knCK(IDP)=MQGloOjQ$2aJj?@qRpHvk|gpT;4&$T7tsPEG&~jn|^+Su!CM z<>wcy1-6+9MXCCT#u>eT9_Q@aG`vKNxSW6iOb8OMuHt{A6R`U-X2S_XM93=~Ar1}z zU2utD^m`st^d=2i4MK4ahv+PUgq(mN&``%?geO$iOX4X?5s`lZ5T`MXVe%X$@cs&g zIE}~&*zL=&8OmcEmETj*rv7j!-w$A%OmcKR$`KjiBr3j;2_J#+WtV@+5sc!m1E4+r zh3zpq$>sv*umYOBN@$MyHTbDmpYa$D5rZ#B8748s`MsQP3WsXuCrNUFlQ_IT0q29) zm|o$e2uMOFUlWsWDA z@eaZ0O`6=Z+CRq$67q=A4onh!cag`_I6*`7f`l-ELi|zmh7k+-IWpf86oz=5UF3KW zCrIrIA*WnUQnu11o#dZFn8BMkiD``Vj)qZm0^Yrse?>Xgn~RaL(_epO2*;6lIdI1& zU!09#Iz(zt-f%>{ipdz#a3lboWLbj7D5WsrHHhw%+>?+d;_r$H%n`wpJQP4D@i<=#L2^R?%Ij;9>t2EBX4j^XKQMAI?rMt`z--Nm2z( zhNCx`7IaYxZxVDR7|XA5dP|B48eu|TBYKDP+u~)8I1y9GI!*52JzM2bO4K{anSPFQ zLdBOeoDSll01g+O3s{AannsusJ#}0TI{^V-!3>VmB!&bjv{Rg*Trpt&CKtyx5<9H+d!mpKg4g-v<)ZEl`oiU>y~|HTF}LNH?c z=rbR{U%~Gv3Go;Kiotb0L9b7*z}4C5uP^xL>k&+E!9AV`bs!}aCP|zQ!KY84Clt`r zLcr*8RRladfYU7NZLrqE388p=0)kJU0LA|ojuWui`;AMk;NgJ{TbE#e3^1l9aL;i# z;Y*pd&)->ZI8<~L69BUegfIm+2n_HfjR2&Tss_VMPj>LrWXK6(E+_PSAVwRrCcw>P z2;x-tunn>VL4p7y0RW~TCS-!lt_l?hQZ~IYOnWI(oaQ>*{V)3jLfZ}-f^MMEGz{tn=12HrJ{x?X6?G-wGm#l}3A%$h+W0GA?3i!U91T#;))Zh%ek1<);v+?Q3X}7cqI>{D zBuVcimn`|+`^WBsQD3r@j?Pd{<3Sukx}*kw!^uPeXYN@p^j=Joa(f|6P-&J#yWUTwvGHOC z`ir{8OMkyFFWwfVUtYXbZS(E3!I%O}c+D@Z@!OBI|4=l}61LuUV3vItOwy1u;hhgs zN9fUPe#20`{b%>!X#d!;{~RCh9gg~U$-^s?OPasaiWD+3|#2+GTQ2oYpSN?gNu=S=mj#Qcj+N9{=%K2~EaQH3}OG;^b+8 zVGz7xg`fWfxz)fhnjK|ic9>ZMqkAM8b{U8lH z&X)?)Rbhb=r3~|odQ3Bo-gMdIgrh;%=!s&zFq;5AiN&LAG~V*!qge%|)1PxZHaqM} z@^^^_HXP~{kTq@W8KX6Bo426ns|)5szOaIBcS2D9G{=~NZg+$UeVX79ChQmJb~8xG z9nPbto3BnU&rhHK^x^W&o9ho3r&m|Mzqx!K*kg6A{&gz@6q?dU6x!Iu<1tJlcc@)J zMx|HXu=FaJq%=;{s_MdM9H$&Ze9#XMAY<&~KmMbp1fh^l$o~Nm1|&f!1AFXuiUMaz z#ebU7I_DMN=~$U;cjnMLwqL5{FN4o&8SL%(^MKJG5WJMXI^Z)%(>nZ%3%O36e@cUriX;?rH6B&-!~v|;iU9%l)nsOLh9(#RTd@wfRG|E*?)ecJg! zSvXnmx9FaMlw!(s0K(=yPJxYtZE3-WDFJtg^Kd+&B#w}@Wo%vK_y*o2_u%ZjBT6TT z0#l*LC+P+di>G-G75onm>JUue#*zxyW^vo#t&1)FU--s3_U3Q}Bb1DLWVAEF_%=8( z6`%6=?j4GUBO085U^no5ju4xeZpIH0f)l`B@{>y@x4QC)a}4nsO;KJUxRgd+N5;M_ z(WT7i8iQutWh~>PC1vqaAx={i(yl!8e|pH7oioe`J1+o0;Ru7^cNkMfJDFOl zR8opLRYfqm?}01E3|WaihD4l3Bq%i{87A4VyG+rS#)M$%i{k>aJ+mk-Hp)Go<->GkPPr&li?G|LL?HWVtO$vE@YtHkL4l)%=HJtJ)pU(?t#zOxLC`r%>6 z1L%j%tq4*C{`Zsr+kGU#M6S)%f17$+#=44ffVvG>4- zb}3#B;xr~B6g{qp2Li?*0}!wd0uYQblfqo1K}iraWeO=3mTZsRJ6JL~-qmmDC72Z1 zHmNWxa)9b>i|x&W?&wPPL0(|VM#9!MEP;g?>{t>vt&LgHO_%l2+M?Cgpu?8oMw7f^ zF;Or3tY(}JQ@7bUXXJ+kAJ-iG@Q6FAD1NKl!I*lcppbmF;IOS&m?F_%nh{%UXDQ6r zVKoNB{qn4KrqQ-yufEZmMDo$kf11w!40bU08DN9|_tEjufqnkB*FQQwSfBr`;<0&f z>Yn$}5u{)ce?-JOV_AUTR>~KLM}L>{1^;Er7lOUAHx_&4uokXl1}~LwIvdZlX6|W?$>456yu>^DaBs{Y36pl0lx z&WIx|ySvdCN1_}4%P4J?W5{Er*uTc>m-6*X`Pu|Q9O5J~F?yB=2wmtqRG#uGw+ zfkc8YTIg6tDQ+d(%JMj+0}xyo)1zfu&;{>U&G*`XhEpyny?a952Vm=8I8H&Z4Fc6c z$7ALy0Nc8a)99SAnVP~Rjsh{69fWlkFdQ$> zpU>3$%k$?8_xX0lKHs+JQ&^+j-Bu@BveJD2@^%~vQ#<~*5)pU%Wf}2scaO`6UNf3u zK6gh-QOsyM*cqpEN1gGWG=l9A$ z4GXt{Z9s10j0tC^NXAx1oEk>ZL0qWY(!w#xxdXzRJEm2S;*2{TnClX!;GF>L{Yl`| z=DrRmU~`K}m!KPh;K>9$83uA3opSjxj_mT#C~O}+pg$xXRVVTf58PZ2&If?MkBM+> z*e>}}D8sse-lESZ6V)T=qCfbiU>xD$0lWwQ@gH{4VX5d#S+rt?3Oq9CaL(qZ2d?Dg z^m;vWeg^T!513VW8t}Djpv$(|dfJXt-TKemi>bP8Mgs!x8gRFPz%Tc{j0Zrx<-R1W z$6-80sg2n(Zea;wy6rN`)WFQ;26NPiH!(UUI*=0PO1P`)qzQpmCpHQ>5=|T`a%{Xw z2(lNk5+6LPSh?wlf4R#K@7G3l&5U~C^Z~Z>131mH+*&C1l%Ty}iwD z8ufp9HSc^n(On(nXF0a(H3n(B-9wwYeNukZm@pO@wY zY~s)B1*{4zVByz&JiZ^WgP-<}zy*wdCQsmE6}CA-@s_sqOW`zYz46rN`e(Z{mdHqV&!$?=oohCLZ zB)5!BmNX_ue&*+?tZeDMWw%_+b5*u%%N1p*qAXKbeka9Szkh4-y@jw*?+jaEhih_% z)pnL8dBdvqeD1IoObv#%8BAr>9Sb+Iz)1D4NA2GqYdpB95_^>F68w zjP)&l+cnlC^kt&%C;pK`v@N#-$pWg*R_u*zM85(krFkq(q#EueY}JdR54~fv;d4k~ zVZxSSOnc%z`~H)(tCdTLFJg(w^5%BqFU)a;W)P$eRey#$93z6V&ax}5aT`00aaduc z6Tp`&hw`I@({lS_dVy%b<91Y->>9>nZQD98Gv1v9s-=3Rq_MI2h($eTm5W1$ zPt>bSz77P+O#Zef6%!-a7nU(Q6(p|YUyzzo5ViP5+k^i|c35AkZoy^!)m;xFZC2)u z)aY8vL5n;!nGG?v3RI;SnWJ=!Qm%59jD#x<2L9rtJtheg40S$I(0Zbbqaf{~S11E0Hg4ZG^wnXZ{PG>1&*L5A^xh1(Xxf zx~ZA8J!6+O^#OY`rIfg8qsf$uR%$Sp9F93ol&cO$RfDUE_*7vE)G@Pn`~BSttL3s! zP>a~=Ga4#2jK&wsOWb(x@fDX}*N3Xbcpmpqb>}8dciNrSNm7=?pbJ5;dHLe``IQlo zs+)n$Px9rP%j*xX-@f|k#pOx&X#e;hGD6U2Fw9W~x_^L+H?LpLU{C%|hWW^cu3vJH zbtXj7S%dvh@Q@`L4|!ug%V7aZ9iwi`imMHV#pk6mkLLh&JkC6bKc@a z->P-6w76~4ps^cAdN=;^=IT0F()P6MhAqJJT^6_QS9olXX5&I`;!6TX_x~$sqc=9` zf6|!of@%8ms)3FA-;opld2hGBySvu^R`GC3ulzM2AftE;hA8D(M$#d;hvP(C0$1J| z86<=s^#ita8Nq}hoxnsh2?E&vbAW{xZg8|e}<& z!GS7R^7P`yeN|SK5*Z^LUncu{`;}Z2S8OYG!HbWXNc)iDw9BtFgLigo?}Lul70Lvr z0+1dI6Pek=aX-`Je_B_!$1e<6otvIl?c35tnqyI_8B%F28fQoqte+uOYB@7xx7IjA z)-HZp1ys*0RgIXdS3iL(zK5GIL&i7VY}(DHVLfih_+~k1(G4|YL{g`x9w>V9+h_2{ z1XCxftDs)~YW$P8mLzW8YVw=6o+f_Yn)<7^t|pJ(y85fHuDPR&DvEmY%P-CzEGVnD zH*Zy+pQXQN&a|8!`MamZ@^~_R83$FB{j0&hzE!TF#^tRF)-P^VYB?+1Zfz#gY*+0` z9_h}bc>A<%wOM>vhldTdp~V-yy^Ao{_4JuRY-~~qx8BvCRYpALtl7Z0R~szpe_;X%+4)dpd0Oo3 z?=Q{z-yYNX?DM~)!`=Q`|69c))Fn09faj5%SCQgNr>9qr)}nHZ=^6bPfK3qKn}4B@ z3h$)N;tyf_lLb$}^#}nT(=U|Q8KlLIXOr)36!lJYYIs&9HH>@30yeT(vqIvxx0sdR znw2$Pcq?#s8eWn+4V8;Dm<~%AGc`ep4X!Dw--fPKAc2=K{(N}Y=ytnyzW&{f+c=F* zPB#4=u;pJZNqo~& zF!W%O{K{(w#kfE7Om~c^S;4ya!E~E8bCgCX_pCzIL6E2}#g7i7qIo>-h*8T$quE%` zpsfd>B9hgnxnyc^Wfq$gVMemlm0}HA{ThEc_$ysSX+Wan<|pzM%@VMs(!3g&6TW7~ zcpcxW!lK27$8Y!$o(K_83}6%i2vT$h61E$)C1+*vHovx~lK+i4m|0*8A<#U|=7rt2v_ZRDCCA^;(6@Lr?W| zZkCd?z|XNXaZ?Aa=1wV|mYYI)msM;I$0?-hS;7`tVow>4R@4)bE(of-ra8VA*Yz?S z1?rV>Eiq?=jBqa9B0QVLp5T=c8}*n(#{|UOH@kaPwH@fZIW=|VD(bhSo<5Fh`UTZe zuS(i#t;$!X7P@K;v=k%iQRM$B{cl-ke}8GA|Lq;S`rqOH`u_iF9Fn?8JNIjU z=J$op`<8yzw?5}vt99RjTDR0QzO_EI)`!;m&>~B6tq-mBA@HZrhyH9&mHw9^%BJv? zQW%cLD5cMt>>Trp*0bt`jrTwHkDUAedwWOg`~NF>xUTnFOg1QH8x+&M49&1+HGSDz zBDEv0zd6!awasmk#zw^55K&+JR#jug9os3mwNvm|*G_K#PI_S)_rf$B^kQ77sjsV{ zSwwwZT)=iDsc%<1U6Nq85`3&c?^OH9SxRzCeFj8avi{SF7*+gVhnl7$0>R_uf9)S0 z?UwVu?yvK|uH@ky{lb~-Ww88g`eix$#c%cOTYPWBqeaOq$J3Z`HI$2z#tT3(m=L5R zv%2`?S4H!9s;Y|LZmp2SJYX8-*UF8QsN$7`MJ9>nnV5LgqpjyE{2h<*!_-@Gfu8lm zFVL%TxKJ5YcVEVxc5(!p*QMFXi#SD8#uifTsX)C0m?Sqayp@o${=-XAx@$&%*kW?U zIRU{9#))k)5{-A`M#3WF{n@zOGS^Dex{R_ho5%LO0s4?Ld z!(uiKdq$Nx%zPjSVUn;32nxCbWVkMm4e-EOsm3U*2u8e+6)r^&M`kO-8BhFN*@7Jc zhxe7y9#0IejG0*HN|h_c4El6+z8rh-o(VU@gakJo zkY$0J4#?wxE7ANFsG4o{zcWTw=2QY3^uL4s!$UXz>u&#Ot^cj!@#=qkvX`R-`i}5d zss)}ksexzh^*~;|wtfWr?Fy-ic?FCJIt_+N2AfwNeHR{x9K{ zVeI%ENiDPowoY#dN@;5~Fnk0(uu$$+s0tR%%%}~1i|QQT+H0NePp8wld*$)ex^GMO z`l?hOz;~x#@!+_$LJR)h(Pp4-?wNE}8HlDY0DsWtVCtjSIv- zmKO&H1WxD(=kdQqu8rHj6U(22u?uw+A``1#;sgaC5dT=OH3>xKNO(*Hyr$K_~%P3J%TQvUa&{@(ihXC;rw7$q`_EAOE6g!l;Q0cNXi?4XW?{cKxw~rI%f8c8K{Z4 zpP!IknA6gZ;0Q8`7n0n~(E&=sqV_Gi_t(zycnT@HMfd*7^Ux+b}T51UY>F}>%Rz2>%=PIN=kQOGn$aXIW>OuI^Iu8^a^^CHuN2S5k1CW6JK0>JlWlXq7kjmeW zqirz2IVTU?z<7SK4G2~nkAORzQb6wz26uR?jQAgVP^gHrEcjjIzaR{Ife43(jNjU&V-C<#`+-5OecHhH{YM2;4vtlWmY7`ZoebFpo4kDVCP2VS;a9lH3cT z1}7Br+y3^BxW>0Al{Y8FQsxJCB?*t|ve z9pP3v->HH4yCHi-0sn?XLC33(6VRQyZx zSWJN?^K25l_4qMQOf-j(_DI!~SRfiv3Q~!!PR*5WpM}xFf?B-Jx|GQI_LxRB{U0K3 zu)T!oaKU5X2Kv8$v|rZ$*6}}9^N9O@h)(j9fM4+)B9xy!{1OjG?6)|(fP}=uRP0WE zWS8C-)Dgt`q-b7-VV>O)6i)J(-k%9V-ZR(X%zEUb@`no?HF1Xa16wMS5C=rOWlq-x z(nj%c6o5Vm5_}hczEHHSgRE2>VyQEAPhbo6$#J0+XRYo@u{wqx=u`Tb0D0uq>-9>f zfvRKcSWKTOB&% z4&_`tmCoc!+{kiGv&#uQq_`M=aUut9CR7b4%i}T3@4ch3L+FWeO9Hs!WYL*t*{*#m zX|F=IgbN>oP0OBLf<&FD%4O&6p8pCgo=;p|>o0UWtc<#PhPPKljM zs_nYL`78oY2Z3Zr!k)7Y-vNi16X@(P2dT2V9@g779?acMg#;Cf|SS@bR6eIlXt3V4)h=c z&~rU2Yy=5$)q%itBfCRDz+rA+R$@ZpbSSh-DWz&HQ@4Ja5X{<7kAKBwci0a@=MeIaY~AcWqJYPw(?(KGpl*ibuZ? z4QM+5-RmE?`~PUKzuy0=c$)UVla;`r0U{TIO#ya(kbCqzrJPOwf|4Vk*F^`)U zr*xbB@8|&F91Ic+>Cr(?8CN97<_COiW~iVZ|3*1x0?Z_dxR8FsPiLnnrzny&DdsjZ zID~NuAQ2J`zY0cZ9%mpyFk-?aYl`UpUQfn1C?`d0teqD?Ij(@4doc#qkjkQ)+`)UI z&Of+l6`+7?lQ5(x?=czvj){~~qz9^XKu4JHY*6+E37D!u=zG}wg3FtML~}=7!;VuL z@c$nj1R#*e3p(nK05_m*jUc(m(IEZ^f_?zD70z18Lzp;)cTF|B5C_}2vYJDXwr z*2?$-2Z7D}zp#YPD*`m?f4loG|3BJY`~R-w5e(i~<-a+G@5Lp6VgYF(V9_H!v-vjX zcU9ob>U!&mMjS_F2iP{;FnZ>@=x*tRbw_zZ(^D=dW0(asr8}KECtW|RKiW+^lWuSj zyc@&p{WfCAa2-7TOip+QbS=`Qf2K{(8I> z9=Kgup!m(QNg9HqeR;|3YBJy^u5M5!C1n@~lO$ObPSu8eRg<@RQWvtPJl38=?6nzA zv}T2_x9w^C`%`ZTzX48GD10BfPe|a@7lo?TmUO|1kTL}#<~nMPc9&thi0^6WZ7$7i zsh4PoKEC3P62bp_2fP37cmMHzOa18n=jZN!sy{lP`rAjl59-g&Ky*>ZJ301D=MfHT z54@TXWxi&7oMD4&4=@EV$wn}pj8Ptk0;3@$$h01xQ*JR=_T|5I|JLJP%4|5C1yeA_ zgt7_HwMfr_wvx+Afi6dk-*YsJ{mbB-iYvna65;NCb6;3k#BJCar;h)&X3brP#!i>N z<-KL_8RRHSV2D8QzXK3_2xeP(Uz)IfBTp^=$8;6^f46^7=Kp)gYyQ8Ar_ENz+D_P* ztwGcnA;_-(Q8d6fPq z=6hMzKh@qMw!hjiJw*>KBlK7m{8>7TB5h2H-Z3u0pcoZLh?Yr__xB2B6$V9Ct-+*N zZ!(PZBvjZ5eE^7VwQZ2iaEw!!-{-7hFJ(Wyy@d z7dpaB>nbP3qN|?oellA_%6*M=%U2y6K&j> z`oD_DqW>?_>2k-yEB)NYZY);)wF~|w0xSa5s&1sHQG{b-oSjE`v2tr@P zhQ9TYc)ww3T1vH}?~4V2^=an^@Fq>}IWys=GQb06cgc(3a6nNG z#wZ^mqOO?*Kc;c=Ebs&cv%ri~-kA%k1?*EcMea8ryS7U?ZE%J?EvCV3(69gS7rY6M z``VS@T+-8*v&!t)kp$#i8J+!{>sV7DV38uj%z{S|x$gE%L&BS7htC#xprs5VogboxxX zV1OJA7M4+cF0sTrq_u2^Tb`v_~u`%OKy9RmC9@0FlYDDauB@M z^JUnznE>)c_)R?vN~VqqJp14&L%aYux9GkB8vWADP1_TRX!X8yku06Hl!z~I=p`H_ zS|k&vv07q*z0vtlyu&t^;nP<2>hWy0=j|`1Xe{FG71?-|1CLs`>bj}hhjV?#7okXW zP!ao$SA1&S5h`kzU4T>)nsSzyP+2GA-!OfNKqllNsrDM?XfmDFIY&y^i^Bx#fi&z_)JcF z>bv-H0qMvCyFU1Aq{!vwo&{bxOTW?u1wOnGRp5saJEMG&YNaS>reATIH;ON84_|^= zrG@^_M8e0k{~jD3l;Zy!t>b^M<|*m_Y_^wX1YnJQFNOdymL(elD%C4fjyHvPgMmw! zJT?UWx@+s`JfSS7zG_SB#yidj6NrX;v{lL$Yv&n2sZ0y(>RKM{syWglH*%MN_k+Dm zsFQoYns|fhX!e1~$zw_=4;#ql-v-t=|;)ShASCFvGtt==-z(_1p z5C|0(qR2|rII6PJQ)3GD>tbKR9&CrqWjcy?#D&4QwZ*`s7|Yd!s;0tF0r=r1U)0Lb z<>o(p?bVOIL*JAZ^8c?fSu6o;lmAEg{O|Z^ckTbTlBXp9|GG5a54m){7x`a|<#7%J zQR+Ji{^n8>3!J7domIGq%;AQ_IrgDr9w zCyl&-8G*3+1g~7ucZye(DjDT1_ENADJyjMnS>CzcW7~fQ@kbQBSj-8ef&L%w?Uwxi zj`!E`A6D{M^#5lz*~{|+QETVB-~h#7mdXNlegLOa97iCH6OiFJr6_kJ`B{PROv0#P zatNR=i=|Q8O&d}Q_b`p47@on5_%a*hNYG=_d;Qz_^YhaWXQvlejz6Qx$TS6Ui)(O= z{+_n2>VaEfDnclG@y7%vR?FPA;B6ZJVZN;ojN~;F`CxixTZ<-X{Ko`oH#*aum9UjNat+H>;E=edHd@0>YtSjiLcddmBy_xB5Ilg zxp*sLmwG$mALr?ZSL~VuP}{CO-dj~&cRFAT{lVs%))WGLhjjAJ>qb^?qyaLMq^ka2mQh%4sJwba?w8XnV^GLr!S)c!&vxyH^FRrVa5r)N9JF#Fm!)!8_0+Dn1<|l4KruhVQIv`;G+S*UMkx5GS z{PO&_7nh8no&I$G>-qKhiz_iyMYU?kdnrcKEFJ%Les%uSuP;74fAQP-nd&rPB1GWh zAwXwf$|q?Wr$YdV5UJRv;ww59si?O40Ow%H0|VuqZT>Dtd>I0iPF42>vl7;*mvlWh5Rk`9sE3-H8_Ugsuhs9f2xCKTSR1+`f zYvSeQo3|Gq7H`JeLd7D(nErglmQ;>l#Ql2TT!IKA5gtpfJ)Qv#kfTBtCrliW>C+$u z1EQMX0+qe;aBeRo+0iBII!+L|Clrm#Ywa~oS&=yqaCP+I^2O=%4{u)o`hP!MzIh{w zTCnTgaem8=Xtet!ttW;2ZS?bed|B1(Nh*S*M zIgLOK_MiQ|y;A&_k=qy>lxF#a z*hlm#0Cl6~NJHAoQHDuOv5|puc8{6@9;3Zyb3#Pna5K%&U}-aB6=GzX z>g=k)DbF0nbU8FddEn^7w%yGKx9(ygtQQSFYc|3eGhmqG3OIal*4Z*Oj=yBm`}L!r zCiyRk2PnJ`6ZClbzxMmb$FBUhyT88wy^_b0|MX-pN9fbdeHQ|sF`8uydn1f*O}3Hc z=!!B8I><1gR}|*dViubs*L6_=eMDgZf)S;e{D)W-N+Mw~(a)4$-rtH}T$%j|IgXHuV_l64_e`#29wYsBf6;V!Pr|5|mS{lQQbsU5+ zNl+eupxDhFc^B0Pg1qMrQ@TP|&XnAS-u*Y<2w591kRH({WwiedDqo+y! z%WzH?4FK8{|L0)0l>dAGV4eSaC66Wl@yT9d^f%t#cOm@Akvxv~FG2Y<4$*5kM%((Y zLh>qmPVfS@6(hruu<#+z?SFMTr)tIopcLLDDC+fkj!*BvfuJW#+R}??PXy?R34lPG z3Cdx2oc5eVc3u1G)y@w**G+~aaV{-~WVC9@7PU>A0x!eQ2#mjv@I#fWt&NKZi}DBg0*Kw zP!$)fO})AN>$Zf_hQ(`xuE4QYuZg=>3%H`qx)p4#Vm-v_wd}0t>R!w>K`K^q4Q?w! za(EU<<=Sq!zO6xfS9#S+_b&70j>)-(=Phb1j*1zS{De)Ge*umwhS+>PMI3cA==L z@RG1FFACU`!Aq&0WD5m8CRv7ZQ0i8gfeaLmFrh_r>M!10uUwr|1gB&=Ns`$&SsfE{ zD%k!aJ3oNyNzVP)7!0owy~Ft}!09%KDG0gq8qweZIH7n9Y0Na@d+xGEW$l;(wlDx5 z3<~$89F6f5v5i0Ofh$C*>W4RmK4wWA#x&u+%WUA_E>04w79Y*Ej$245D_}$~)Q!bv zkI^>Iw~0Q&ah9NMw({=rM0k`#aD8^cL4W)FLXaFjjf^@GwqE$FbTYm{c~3@C9BDfb z`>FaQ99$0J4N^V#z%>)?84aHx?#7PqctAytBmzb-%TUUX=C-a70=JVJl&6Skip9^r z?)DFlcKe+kI86v<14ClC#KoaP9ONfqe9|}$U%$Bqa4RpW0)B!d4wsh(N~zE8Dw^jK1!n;>DedK6TWjbITE2F9O=B9v zB>uO$?qfOkk04RHo1>Gf&o88U;;KHp@s}9jsb#l7seL(2YGSF-!U|#4xlq7VxeSFp z!`;?U_k^@-NxDjFDwzgMzf@PTa>rzd=ce7Dq!@X01k=Y{IU5yq0$C&IfUV8abay<` z{Le5>Sc8SWm*faW_WtyiB*40Kx3RJ!7%d2s_T|Q z<`_WuklQ*?oLXR)=#NR9^Nhj?f`oF2O9{B<2t-m3XETxx_N_+&4O<+HZF z597Za%Cg-)c)PE8M*PAwlEhP#B0>TXFcuZd-#nT8B(vQ>cmvmtFNkGTQKpt*o`r!t zdGGk#BrQ7}Uj_A4+vfx!D%K^Tw8NL12n>&N2c&g`bQh@H2P<@v|B|q_UZJ))CM! zyTak^mmGs&5sM5$wD6_iU$Ix&0`PliL0f_9IvyiD@j6x1f~hxZU{U%CSR2@&qi(qZ zBv3#uQIM<|_ctm}79(1gSm{cYyiDm*0lqa2YDP9i3HPr?upV!o2y7u7P9$2d}dd&2H0k(UEudG3g#8=YIH7@3)9!zVE4 zD^a3_jvCk?!H^yu1Z;>jD5WH7FDgF+KNi9=lxIw(3qlM`4MJ-f+Bsa6YqYEbxq455 z3KcFwA*|=lQwQuWGIX~&g@|2%QxP1P7Y!OkXG?1GtU7UetB2t!!7927)2ZctW>wq~ zI91%wtcty`oeK6xR@_?lPHF2KSYPt`I-e%{UlDxgvF?BE?(HA$y7#~K`fLB+l{}XC zcBv+NIg*=RJKu%WW{hUphCtmkE5z91bA+-poRzNF7eLgAU3M8QXB4mfB31Fdt}!1g zpDBjd)N=-0V77ol3YIzgV}b}JCmR5S+2lkRQ?Sw;Bw@MRa%Z7@cVdmc?vUbi?$Q^V@{ z6KB`p;$$@wi*q(of7);;w?}>ESZqaJ*2OlripQYgYjnStNG@fgy=2-*&i0OuToK$U`EB{D@M6Hxj>qG~G;eah z3jalrdawD~Ayl5G5dU2dYkS&p^2{$4yR3~FfG;_RHaJV0HOW@8*`s$46q$7Fy{Him$lOJbx2-UD9Wx7|+0u+%2qnm5bH#9H$h>pvWW~p=gpI&}W>Cc-@hP zR2n~~9ne>YG5q?qNH@87YDr@)Iz+W*7Cb>!TX=N~_AI^h5CMhANii5h8jb)28Ke~D zOL9k?M;e`hgX>zdq#lphwsUgmso#y!(j7eFI>Xe(+Y`VK+D>+Max_FAcl*4%oqXr{ z!7q4nzO!36b?y8BUcGo#Sv;LpRMc(zwn^zmx*O?`?v(EC?iK-wL0S-y?w0OuhVJfe zM7kU1_wl^{wZ4sEb9RPx$9W#taqrxnL~Y$?XME(tl4zUz?TLsU`;J? zspDXB3??bw{+sPYsaFK{>PGH-Ox;NwnYq4$Knol%J5zioY~7@R`RtBL8f%It5gEqE zdo#mirI3iPaO~AjN?|6!9;gNflh^&;gIS`#*Ii!hg%VXCoqw)-Y$Zh^Phm=$X^D-S zo$!==t6j?eZS$jAi|rvXB6oGGTf%C|(|!TAgm9pU*wJEUhmZP`*K`p6eCu@!SM_1@ z9J-qBlP?Ieu@wC4{(t0k- znS`|uq2KgBrkZ>VP*6Q*8|nIIF60#g&isAt1XJ85-viy&dwJeT?52EOyO0s+v4OYh!Owm1(~;8{(23kWpZ8%~9Rt z*`yd^RVsFN8WZiLZ8E8wIX6#cxD=}{erX+fEfn)7Dwp+!clV?VcYgk;Z&3(M_w8^? z=7%v_eB@exNH|@Kq$vr8Y~sgEOBe>ST`_y#_tbTg`V+;}gpq+iYm0dI+^Y}2JQPfV z)2Oe6)%`))riQ`X=dcs4mdfdi>rX@T3#+STspqHo&Y>5&b1_sSrO>6L!AA3WJEZgVRieNrt$)Gth&P7X>MH0RZ5tJXT(V;aDo z3-aNYvlEh;P2jJQ%6X4mb~PLHiKD^dnX_+`WU1hd={1w>I8$yh!yG;{8R%KB<4tD% zCXt^mVsZADW zE8fdthcjTFu>?!$!PJRYFMGcZ_EVi9z~*I9X2)*2eDjhlxcggITaS*o7E_79@LW!A zUfmCGT{kq=cUEX=!A!W7;eIsHg)wf;o!$Z-_obA~ON~)Q-?ZCq7Kh&V&8`VGzpN4+ zE8@|65C9NC@3=4S!5&{0?{$KA`mX5NIawQIE4&@S;pO5JnIK@mu` zq`-sWn7*t7L8c&}me|HL5)(ic!^CCN{Ql`hv+ECTM&&o7@ZId0wv$J#{Q=I5nw^z8 zwocwloAxoPk13v>CLJO^$1d%f^OMa34O>ufqGM}OOOHB2G%mCF?+aSDRrLYNW0GEz zHP&~i#ckqg-$fji`Y$GM?55R$&ZY{}e8A_a2Dxm6Q{tq%KpMw-HTmnftI-IGo#S zSfxFitI)AT!kQ5=6S4axzo|%qK0pQd6rfhEIj#T`6j1k0QM>*eOdIOCbNJWS5p4XD zNXnjbf1p(li+*!>dCKW?fAZ6Dt8irQ3f;d22-&g!db!OL+8YHeEZg6`QJRQWp}C>f zcb|0_&K2_tQ8x9OiZ5_UI(JyW)mG4kxc-XA#HJ~A{cNA~G!H!|DxrdnuteZ&_Wiz= zNOs{sZHm1nZTq30*Li$E9RzY58<1LfPTaUDu+D?X(+wBwMS1KI_uH`)&D)t@_>TTF*)6UE;keU~+*=UycAQwF%#{Q0ek8Uwf;Y2V`RMtu8)WrrbFx5-0 zL&RkC&P~anNljp?s^g-^s|6z1Gc49IA_kP7wKwlz%aG&$32p_;C9U!e23U*LNX52Sjv zIv6%?ll8RkoWzE*i>HV*`Eu(HZTALodSLFD<-b(?`+?^U#jaEu3ZEq0!4hr3)s)xr zv&8NE1Ip|7UkN9NGdVs7qLnj^zoCfl0E;DvuWLi|JMD74{2)62rz#riX6#+X1ZGo! zLQA287fGfR+Y4|)vwiYD5`F%nmfgEARLDTyjd|wBkUupUfRg)ONt~XM^WTE1w@kMF z!vloF`~6^rcVto%q*KN0D4$?hb+XTDoL0qptUSK(&C8i9@)7Fz2kT-)4t*z3c3%`# zruC^VzPO`KUFh7}i~jrg$JvK%TPOKq{wN{auJT^+bEb0V(p6)uEEn?vQEfRYQDAF< zZQ!PE}FZ%lv>wP)5%Zh29ZHuvsGH&Q4!`Uz~dH#8m^ zYt24#jZHfW(oIdxgK}3IEr@03(Ha!;8RL$oGf_6uG*dws-&xDU)>+6^La~tnIXO9|2&15?r8h1 z#`@mZ80Dzkuj3jd6ejtVLoS{P_ix0xAEE~wBeoFeUa%YO8rT#c0bIO57p^Qo^)8mX zFnx_hDvR8y*P=?bu85KZxCRM6Mie0Vn~m1(38xn7fKpe2Vn9rr>nv1HLU#5&nlBQqm0%C{&`FdN}_LK)t)bevTK?1?XJ6Lz$+V zf5Mek>+@FAIJ>e8g`Wtm8Z4aHi`3+Yo(HDZ-RHMV6vYrJwK^1EZj5u%1 zi>nMFC}s!qI*HC9TUgMj%WDRmN5|=Zf&XyBt6OfV2w^XIU2TZ+6|_GdXQ+u?f>FU- zTqqkbeioI%t?N1W3zT!$cg*F775h95B0HUl2EMjTzDIhp47eYn_YoM`Wuau^_=s%g zO-^Cz5H(bz%517jp&Wz4!|~|PlI|9)&BT!>eSy!n|Pdk z*Gf8T#F8Hr=3L!LCOZP^Zr^PAi8994Gri(bKZ~(UfKJmNnRGbuC{~Pian(&4P?u zris(-jebi*Nrx~yOPL8L&3Z3|NHAmc#k5)ZW5d?=>_YdGEW1{TD-@{j_kMSs5HqI* zRX%@ltBRVpK;`;;&D}>VBrRRTO)aF~PPvF6Wq`V0v`^B()0f`qd>8MgWBXd$AoTO# zlldJBdXlx1MBttW5@YvAuOE&;couoLf)twL);erFEk|KwQNL*UvBA~Q`9YM4Nv3h< zzb+B~yZp6_#NZV<$84dG6R)F{1{>XQ1#mr#21jn*V=oF6c|sm&D!=-T|3OV<2lRJ9 zMvn<@bkS?ehVXGPiO+U_c*jQ6-E$1qI#o#o@Et~Fm1z`T(R}Vmi>YrKJ!k%Ve8nt( zm4~gjY5GhH`q(7<_u77z)%f5*+t_JJpS}Uh!!=y0>E1kZZI^*S24oDLHQLvV2)zY4-L;#Z!jYi-={AJu=t6_%KYKeXn+1ADT>U-xBzCY1D z$Xbty?C8~NOBh%=At$eV1L<5h@Bv0erEDG*CiU4ct#_ebuJOYjsU$@+?=;Ky$p`^S zdNG9q_6{ih0Vv1;?%&}e;Q7_dO6Be8BEA{YVFQ*~XnZqmRq2D^2dz+LfCt`k)L+3H zd!3CCaJuX$z=-jK){qmLjBgi^c#=Dcb`G8>^|dz(qi?a=Vsh@l zLojZpE3rT4ap~y`juB|$X9+uzBIHth7z}ip>%20%`R2o`sKlIf_zz3X^O$)M{?dx| z2j}c~^;rLU`b~g~3M`=W)QqPNL-YuoZ)Ot%ouG~wpeucd3Ao9%6cEbI13p z3oc9VJ45^{lV1|68QqT>aT~q-!Al?43tHNkvJ}p!sGid{mW!$MSK~?aC$=lm0xDO5 z-a~>mYi5&eyIdg3=rvIV=S@`T>mK;Q%WDbpj&7v_VRLTEF<_WV7eg8^WP2 zz%MrGh*cs(#&Trh^b!YK&wYc!pmK6vYxiidn~tj;(MK}N!`#x!-cW$lqK!kBL&-ADsMLwOx|?nGgy)ee49)|MZX zZUNh^J77z2RapPObL0CdHRIZCAd#&XGu6;|>7E%nk6aXT10S<072r%ZUm+kN$sMS) zLCnM*I7+JZ5>)i=a>NFR|FgVF$YGyjLwD=-EPTH5#2FFToFREb?`9rR597Ql}{i_swj5X|Lr^+vmca6fPmmD0A~+OMg>8)L*y-M>uvZAE{8k zi5_3H9fD%wB*79I=?e|~-7>4xD3M4}$&k6v(J6|P30QuZ=hsR}RPP9kLy{7DEWb`7+$O<{ z^s)Y&s0_$J^-$ocg*&G<1oax=UYXC(NW#6=SX^&Y5tP`WNFUuk(MbN_Ww$R!k~+FQ zB#Fh(5m`}v8Ie5t+H`sm{74;X{AbQ;BI)BuC23ig=@NL*(yn~oNGGA;yH({I!_t(= z>Jgwr*kLe?I=v70_~~{5jqf@Ho$HdvYV$ID_uHCz>sH$?|2Gp1%Mt6qZ$T8X-B$)r z1fF=xYUq%BUvC!m)njmIT2p3|3ITtgc^co2`Uc*2hEQH4_fFI(b0Mh{Z;5~ZYZW$9 z(iuYKz6}^%hM@EVRfrs)84c_6)BkLpKzFX@xRHhjvGiNJ?$Tw1?;9SZjRmg5 z9zs6hzcuIozUu6VZ$$$>-rg;L-zR^WUx1q>9kKLQQ=*ZY%cw{=HEFnJ7jfi>S$;#| zj8h=3`*K7BGm{oaLJi`Pi6dxK<0^7(4NAL8T_S!MkXyU8-h0#cj>3`g8^_l9)g zaioYT1}4^9_7@|GcN?mMhrZrMm6+Z!5|^eFEkE;q&oH>1-^H8k!BZL19erYMKMG{I zm4!AEyFo%0AT3T7np*OVG=Y?&e_~fp;Y-kosa#LH*RFKt_GXO$FR@#tBpSUYi5U{j#0*m zo)@ORQUn4oQLJYKe>w(-ES|Zh3YUenmf=VFdG)=I`{YUf^_zD;M8bPU!5>IEu42Ax z(0#_udCZ~D7Wa0RZ0ob@L|SUP*ezWILToADRsy2u)>;>O24Bc!ogn~Zr$+z)@eJR2D8^J9asp12BOvBmGt-$$zl!CsSb4fdrnJ|zsVp6;3U z&r|bd|A|pq>=7IVfD`hwls$08(fij$LAYq~hWSkruZhPFGiaX{36cXcBzIeJyRDvh zL@Y=q8$Uc2?0{5$et{-6s}`?af&?ZCe?)zYN+$nK(nk=1{ADs93+oHw1JI6lVhpYZrU(b8Nxy z*nRUm(iEA^3Fs7~C~N}@vItw~z>}oI3usV11AZQJy+jwvdFxKDy;D;J`F&T1)nnM z3{u!0c;}WU+UDFUe*N<#uaA%M%btaei9jSN+f`)NMeVab&dI>}@=~Bz0@@e)Cg3mCD5ql(KVA)-?y!WHlE*+LTeXWGHaNAzkt)Eiz|GBYwcRI zwpci_cpLueF0o3E@=JH}`O}d7sRAvE0ur|G6}=C&q1_kV-8D|Xn0lbU8_!O9Lz!w5O4rT zaTrj{A#5;8+Wi3n`ubIO6ln3Sc}Mu;WeqZty^*Gy-MfscE=b2`^}s7pu7ZF6!9c%Y zyBb?ydI30>x?^&)O^-Chf7vDSTRc@<6El#>zt;tsL7}}Vx_G!@=UPxxpvR3menk)@;9>R$@Y4tJUxDs0G!ob z4!ox#;lG!U`IH|evQ!c#YIEq%u;^D#DI) z@~M^fPGW59TgA!xd0Z`=_X81V;rg|4bf zk{$+QZ41SSKM560r7pXi^#eyCGSaoT8ic7RryoXXDE&Iy0y*qv;%pviNyA5$aKtRU z8}HyKHJ@|l8hw7Q4#6>@9XOXodbqRxAulJ?`CCd-mYgM@l1g?l`xvz6&t%!bKXf7= zVKV1!lh&9j0MU&V2~=T1r8KDoxCG2_{>ZigZXLdcqrlgOE&!bVKBQ-|jab5u;6980 z`2)A?{tM43RG}O53S92)3}2XEvB8H(>0cqe19X$s)(Z_c71tkbPtm_*z=hiPWFq=H z=A|}}s2840D{c-dpWKgxLl;6_e;f^u@brEM9rWOjh4QPngg_oJ$_0qO<&tS_f2kwm zuv?nr?rccg5`{+uR`xm7tZjYpJp~7&FMm&)AXk$EjNN#CT^y$yQT@e=V6dZkOG=DwHkXsDxe z=~$z2d@yQyGl7WCm_IXif9i(n(`jOdolo+&F_fR&(Nh>Ku=xM|q^_63R7dW{OX0rdazDjztvDQnB0_fn((|SIf$9~+3^|i@6sl5cDX~edyHE%8vs(0 zzzv9-(WjgV)Wh3&w({iKep!YQRbx5?Nhvl>gQ!719i%XB*G{;tAC+(%-6c0&u-{%B zqrQ=o-BJY(u)@6;wjnq1e9=(*&`~|HDn2ZOq07rF*_nUz$W->=(9~{!e0=V1?3)ev zqDJ~X88e_jgNI|0CEgcXJv(J)lFpz4U9J1u8zk!wT$T$RwZ7&v>y#^nm zmgS4_qU!AqKFes0^K@L@ZFEGFUaFE|yaAncu@g3Ixa?u#&xTss6$iO4h1ZkGA==wX z+m=_#CYYuJQ?JKoy z)cgYz!zde&Gk1TD3MRM0md?Ze!ybQk59yWBjTKS+>g4ET>Pcz;7=ipZZkH zDEWqH`Fz;LePs~jjN$bgVlQKI!*FWq^3E!n-1nOw*mv!<=iA|hv(yT8_^UwGCM0J9 zmh8_tEo}n!Be-0|+3?z+{yS=}d)aKL-gXDhFG;a5WEBZMo1jb$ucH|l?LVsD+bxcM`Gr9DO zE@Hr7hQ57Qk0!jT1>LL^F#b$ZK$<#qoA!yRgWKZ58X?8S$R18^CIUNeoY>0yvtrew zKW6^T9|$u;-;n3ZX)bK`#B|kaJ1-k%bGd02YZ=EN&Zw7_QLJj7&0>_b|eFr zvw>Tl{t5J~N;b?ghn;3TjE*z^H*ZLdsloFJ3O?DlGyBNTB8#O&l9snOP)`+pcjH5b zMwft9b@D@v#85-vA!;#=^~*3{oBX*RqZxMuQcBVL=%ni;UIXkO{OQ@1UqDFF>$d{b z@|7yP8Jp!8q`-I08BHtOHXHQg2$Cv$m>v|7^9G;ogzLV5xCd6zGgQUA@N>a2*>A^n zqO8>)n;v`^_fbj<&XvW5p~h_-nxYP$xt7jfE9SNBw#&E^pfyfg+dls)X4pvPn$ndx zqPV!K;oj@53OKB1Sjja4lNPxx$tY%{>gfytE@6Jc1pbK>vZXW2uE= zlTYg0f!CbR)}ByXs>zk`m?h5EOh{YDl71q4^&Z!nbU&_*(VKtV2|O;-GMi;6U7lFc z7<#C*leCl>T6_f#h>r)FmALjJWGhtjbLS4!&+`PGc#LIJZl33%!1=#Y*NdTKW~$z* zUUXCD96oRzlHL*OJBH^Hs%lbO2RxOZjOinMlyuzV=lb)_quq%)`*#orUBzXR5)Yi& zXHo)6+1YmbeSeHsZmd$4Zqm^xb*+ag#hPQsJnWwi;@_@{^&tfeNXAF`5F zc|=UEAAbgujVim){rKe}NY$1)9Gn*v6NU5TW%PX;(j{efe&IasSeUC8fwgnq@q#|R zEpLNPs#2e~0yUP=DfdT4?p|nX&6sv4e^t}zveio4m2#5~`1{Ar`g)Y}yCQuCKDmX& z`$PslNYQlHIOLmf5jRg%)B4($7W!wpX0;??n)>oa8z0kT|+! ze4M&t47hG(qP4|6U)^Nq9c*!)dE?s5yVGuSkNQ;*z+JLmKvMS*P<>q_{`2Q)$$JB= zE%ZKss=sM!cEYP3#-}G#2J$hIWrUuR1m$K_G#iJb?p~dGqarjM-Lj9^gwK6=V2?@Ig_rcZXVA4*Uup;Xko? zlk*1~CcF_-;gM0kHlA&~`)3`tz13KOseDrbJ-&xEPe8fc+{Ji$fW|DbkmmMFD^8boscEJ*)HKu2o#Lgh{n1R_E6h;C z!kV6{GBi!cmrjE=jQv7u)8xop{|w6-kJ$UgU86gR(+syL6v+hST?Dy6?t0)-Ukb*u zKO>2brTmmKTb_qD+XlWn#j8udRzFn{4|I}JAK_gO_P6h#X%n~;J}6sx>xEfORGsrs z3>w0ZD?Qw06|_gQ?yhUrxa=th<$fUuUs-gqqU0oApK3gnbK2rdwz8nF`h6f+9}3~R zl^B=mavE9DC2~?Cy|Z*2e=*Sf!u92Jb}C3~STz})lV=CBlSHv^`vXx>#y=E!9073? z)i07cA*Bsr?1S>GSTQ$z=12U>LnynM!Fte>iq=HBh!)z(-^`vKzpL^6p=M7sLbO7g zM6L<5I7dlmj`)gh4bK;~EskPd5xCCP#XkgXd7u}rRMot<@=fTbt%Mj|4-y=(3Hcas zL;h+)KV~;C8R%xR!8Ca2WE*uA_zO>d3Z#yB4jNtDU8nD9d&%h(7K8w%ATR&-w#Yma zP&O+u+0)I2OYy+0Sf2pz{!}$zI#w-tuo@|rw4x}LE8U$6VoF3s&nHLA5|_B1%8`se zLVY;=LeevOk=K~4)$hq`93yyE40mo?7wbX!%*(|I;@B&Gysm6t6IcgxKaD#nGtROU{@&9fHaDT_O?ZPo4Kv1s5faOY$<`>vJS|sv%p%V}&8amzAWsUEa~u=R24591 zNDx#Lk6_-{N{OeQsOF2{$zqF-T;D`2&@P$L_}aW=9nr~Kj8Ecl{>f2m-kR9qFX&4C z!ppyF7b2C(y$z(I@HX>ZVWF@S7ht@_Mz?7bjr^o@#c_Y&!O}BtTdik3hKRxDckYU| zm-u4&@Y0;+pC1v>v+cj029Qf_M!z0JMmdhdk8uuW(o^xw3aRIz+e~un2}HCOO2SKh zu}u3DH&q#AYNIOFb-<9eb>u>xL!mweBD(W*ZLuO?`B?kfQUox>Iu zuRc1-6VLSh#dC5$jzq0)m+~1@`MgG}(Ky6J957i+;TX7`0z>F4ciDs+18;NkP@b9i zW%jtESKPokzpASn<{@W;g{E8I2x>-wMT6E)PLXG(qpr_IZxVWek)t*gsnqdoxn?r{ z&N6m@ZRXe0VBy#>UX0%$5FkyjxmtQ$O#(|D?CKDaw?%e|w%_JAq0R;{@;_|ugWpq| z-nWbMo@a;`?Z9uKu3%dI0E`?}Iz$H?80nP<;Ay?tJ}0`UJZWsTHa^=_LVTbKvjHaR zjh85(QB3h*ltrftzEy%>Lij?8aV58SMi z#GE$K8HQ<6OR>+MSjaea81ARFK<7S5QfT4$4C=Eb(x!DOgdDQma{r1)lKOcGnx*)B zQuK?pGQoL|h-)`!l}TRdL-u4tna>489jQJk9VtwWyG*vL>wRm_v!zS%+O%LjTF2g( zHH!?R@}Q?7TgUEm42$^Pz%J>YdM|j_&}jBkv+q-Z^}X)&s<>{7d`TXBa#x2KX%RDg zwB1OynSsjY+Lj6W7VXywQH#>KcXL)^g(g|gdON|c}?;hp#52L zLG6XckXW0|w?SZagBW-BotY=EH~_S8B_X09P@Cb*)>**a@}Gcz19k8a@4t+C-<}2^ z|3cdIJjYOGq0wZEp^FyL>Lh9xqFwC1e;yG*QxTm&aGi5o@Ow?!4gE^&^*7B+t)-95 zf@gA%CG`*f)j%F$fl<6`?d%^G<;Y3$!5=i~rbKvfyB(ggmL6wLSei+G%b>6T8cI3W zGWF>>lOi}D_9Du~K0-^|%X14+ijhs$4CP;g3f4b{Bq;0r{9vqKdIY2#NAbTX_fXqL{kfyA=$T4u5_|*~D4*r6 z!%v4+i@%;}wB0j0(Pl;_QU6i9ddO%rC`EB=UuZNqDqv845^Wtc25{g^<~-iUiBTFR zfj!&9;jVYD$cEm3M~$Q>z*sF=0^L`H5|1C_@}knu1LH*M^86)X?o?P?T8p8I?gn!rA${W<-T^you!h9J9&SxdwC4=u)5 z0r*Xg9E<7xudVszX^Axyl9VhGH0Ur6;g$0IB}i~F7*SdEpHiEr?+t{D(_;!pIc%3) zaxACSOYFPtIZ=Zkbyx4t8*I{|>F#|g`WMUv0z($m$^O6k;g#%^B?>RTd#@3mvz{hC*ZSHkUP$x=yR zpG3Z0=xd5%aA63jI_bUoMZVhddY{OC|2a{gE=b9*4v_rVe=NFZE5*L(P)JIm@u;13 zWKlnM1mu)E$}>W_DuNXA?Htzz8pUYCuhz3}2c5YnnbYZvd+@52G6;W#IZb|X@BHF> z=`UvxfBI&_P)w)TboSa)Yn4-iMMmLl6B+B*;(>i;E`&MP;sijY8oyusGw$Cy46h3{X5VBE`+M3UWLt>19^`kZ>mQrI{~*a!i* z-_P|?#?ERx^^;fTT(n1Y)IRNt@`O4CxM9`EK-N}7>-NB;WM|bEfR4K2TMo$;?eQy3 zei+_<%!;I#5VKNN8IX2R3ZU4!W zef*V$#`{=QQq;9H6GlM+vE(T@#1uf^sZcV|$a+wr_E}i~ujg!q^^n?HLZ^mHPL_Sl z_Wb_13)RlB`2HVdj>(Rt(Olv6U19oRlFW32Rfbr`tS!mn=-NGDpKm5ZbNUB&0;2+H zgWh86Kr4VEnNsK$sQ&~4O>F`gUQ5^S>pkKK{aHXt-Hn3pRa%pc!U|Y(^YBI+XI~Hz z{xKa+G2(XDh4w+=(hwQ7kKvi; ze^RnG|5_QbZd~kyeZwe0^>Ujnm%{1zP=XAl^7+@`cD*zfYL}{2{$*2rqARJYX{A0o z9uG$Q`B3t1jn^&pOXp5XY_s$L`o64hSrPsQ5&_bTE5HuLI)E!X@^%8cfB1%Q4-s9~ zI|Lca#l3)4{TvHCM7E>OAW&rpT*Yq3!Wo3jk}nBomw~GFq?_ITE7rQD_&M}yL_TV{ zLpWbLTcXXoEFFOTNXM&ekP^ z`B*}1nhU$Q%-0qdEuElTG8)5b>1v5kw>2@dBnEYTZkJziclT6QiS9sG!mAu>|H7R` z*lm@QW)RU=rr;oU$~1x6#OxBm?llpOP3S@JH`|+T?e~;cl*u%Aj2zYRJ}is99c=ZJ zi$dyv<#xyJyYVqvK850`@Sn}5KQ%(xNdps{_$+}!N;1`91S_a#Emg(W%6ya;nP@BA6AnsHZJ_F3Gg)D8G`T3I>RV$GXid64{4wsU|;td2br40_h2 z2G0#^<*;3G&-=}kU+_X8^($dCN!--wlAggC<8F+PHr6$>LzyP=0hLSuV=kY+oT}_u z>e6eV4yfRdl-UsJ&wPF;dmd_1E#9ciuIy)YzG!+YQgrk<1$?NTn`K&sh5X8qAB2gA z8y}o(>gqaKLq3=uryN5g!y13@pXNHaY>X!txN+e&p@l7Yf|G{**4}8@=$wCqN6Hjo z=mAcN?QCQ=9DR`BT|geQ^gH_LZ2a;1twLGsjDWsX5Q|9VBd8hYca$CS3a zQ1_-xWPICwmgnUQui@RATvWs}Ja76iOzf*)5#62nL8htAW#$ZZdw`~O%Kt25#XeA% zJJWaUX_YA2(@x{l9q1awnv)~5^E>7_N60M6 zm##-m>mIukW@>_E*9tVnnErcOK-q=LV){PXm$?ZBHb(+T1Ur_`?dF`?AtQ&0G?eI* zlNoF93spd{k?$M%Y314b22gQVjdsEL4GL}DVht8`KE)4z8?iS#!3cj@(^j-4_dWb5 zqnUVSG2grcrETy0{(h(?*4dt(mAeS>oiYXx5Mog)%0XHU-JA>&&4u_eo(0p z5~&sm0y_5`_r<|~#$f;neiJ7CEa;b8tb zDW(`b9#N&WNshqny1#)4uE+_ttUI@NcM1j&a+PY>(LtB|Thg9)>gIwzr1qFE&hrqQ z6$CkS^&$mqJ`d~yR(OuN|2u}UHg7enqCK`K^~9ngoL>&|gC#>+LrijsO{T=vx3bogP3k1O;l|oFucqizZ@ze0~8ob8CQ$_w8O=v*HbqKxI?kYyaiH zmChOK)XtU*+A5YP7x!o%JhqFjQ(3HE@K1b?X22M78?9^(3c-tze>R@Qg@#qlnUwoN z5WTaA8>ihm)MtG4EAM6r4SsGdTLL6+Rp5t-SqFpM_6Fr(GAqUqsAAjK!VFDpq@ zw4t>2C7rD^9RsDdMMFowg3o1IYv2pO@sBSg{ zRQwxoaB;1f{4e?$0i{Ke?ZS599I*P1LMiFQVfxGA40ujmo;ynHOz?#kuP zOE5G;zgCo%sjwn^iTK8Q*S=Qop~SHv`G2_<<0{MX4Y5En^8p`~T;d*=7z?|u<7ei@ zdx;eH^P(k*UTRjBCvfE4%qJ2lQebPXaTj!c{@;U{IvUK7oKRQ2PcJ(4f7RRplBWYs zko58A3zHj&?AS{NPp8n$R3mELy!rrORW};iC$^9c#Gbz7WOZiUz5VZksRgs(>xR|r zzQl^1nGZ9s6Rnm1FA^)-Vw%51L0 z1Jb0u^&AX?t*S~wWMJ3OYvJec!`m`cxjftEdmPZOfeB!ap@(`F2oa8DzZba1mxnVN zde@3;L%ZFyvDmbi2~fH&$uihvmu8 zVPKm4grAC?g^C*;haht%X&(aN$DrEn2McfUN2#Phx>>ofk1~?Wjb{5%u7-mluE%^F zKdGV-HnC0tmOMru;_rW$0z8T!MB!dWXN_+eI-;?!>r+ZN2l9fvKmF7#oHf|9ez+hD zm+)ji;czkIaQkJC8MZVgbJ>R-;c-jTKnWJ3MYFpg?2{LMerao9S$GvCshf+cm&WOy zUjZ&im!H7s@2K?q(>9FVyIZfWKa|-f@dWmx80T=fiagu4d{X@pC`I$Q;v-@y9DYmq2W3>9Y)%UDz>BaZVSx|s;$(!O#Mr~ zt-_~NTDW33Gj6maHjSV`zFXKj+V+ibh>#qj=t!Is$EEpm4%DAPX~i zn%4VwP6s!A2NUtA=HZ=+20Q(8MARF=v?7^0GYNMT%=X!^C{_3_J8Oq6v9z6!!x2x# z1R{9z8$I&)WUKuz(Ow2rMQ{HL&O71l(|p}G{(v>V5DsD&GMi>gY_PMAhz}vVx;M%; zjzB&odYv`eSDxkl?}FJ^Reb~6h?apl&D@9-H#GT_m#(9~!wFYTOYXQiqr*ys z?h5aFI964W*nDE!Gw%6R7sbu5EG;S!C&F9HRVa62iZC2F`l2P5bmQr&tWymbC>n+6 zCrl-IIxu`hMMf39-2?DH#)Kt*rvLrbAfp=e%@o^K0Ub<9_ixW6@{3yAv?$k{_iFUQ zU-d@zcm4gL+}G&pU_ovxOTL3S!mMn{zj2uK+~!4UVk|Rd#Qys0QNKE%vr^b!&Fy6K zx~y|2h~2~K;KETu<7#sSK*V!_6n+z5QnmeftfV4N+&Ku@yXeXOejKDprAVgZ{;S}G zvVo0@z3ZWt1^)Y@M3fiOkM!g3mzb}zCP99R9lZk6+S}iBsxMzINPXQ&%SoAuZER>+ z8HilVT;9M{%epLpTpyca!DZqMuc+aA_}kK^F(u@1a`K(h+LA|h6qpT+WH!M%m4|s; z@PtXQB`R{Uh{46V+eV7)FR0Gv={lSb9`zm@(d2g*&^eoAbNR*Ld(#J>BY`enP+qje z^Bt!!LTQgrzNI9uRLTCVfKMsJKe5^fF^c0jpY``vl2}%eC6#+-d9@LK3w1n^ROnP$ zwbPCAfmbsqol)mXG4gn|#{Q+$6~=+({{mc=V*x`tL)Oe(&fEd74$ahi&_B>uB6~T7 zhOuV0O|pUniU?;l+z(z61N{Y($5)NLs^sWIf9p>K2PT0H_U4eMx8x;02uesR6S^8M zemvQ+!UDhPD8wvik5$Z8R9ByP3QG~^V|46=&Ve1r-q(8lA}uER$T>3n?`0`cVVKqO zlCW%lQJW>-FD#`2= z-ZyJC2LgrkmO4!OY3i>pReW2_C}+IH#(oIdpxpnC;j&`X zDR+v@KjDD9>DN8uT3uYpH>KJ+-amYVakoKm{R##B@;elIZhB{n506CQ&&_*?FgAQoaUm8!|C~3Doh>Na1dJURD1Q!k9nOF1gQ-Rbj zKx!Eo{!{(FqEb0md+q(Ew1bZp$gNiC_KMsvmr5@+NT0pqj?5u3%dc$ixpAG^ho$r_OnHZyaEh?}p2U)NPZJG&_Mc(U)zG{E0!cytpl)9K zeq$K+0>U(GEu_b9?(nm3)|*4>!~F>- zB#bd^R`^4#u`2kpucOw6-K$6uw{`|f*GL<>lP*qP;a?u=oS`Z-{=Aq8qB$!>6(aa7 z$_Gd_7w0~a)vrGAY1$r$7XB4?m!+jvI?jZ&1B3LXp`inx zGx|USWk~UB*f>tIgTv^cK)8D*xnRU-=rdDGWQj8$bg(b0R9%;bUpg4Qh2-%DR-VTv z8Wb-6m?t&xS0hRZQDy8zC1{Kxsas7Z7HpD>jf?WHKnW}7zspwhk37gA%hF3VDAVv| zGjLWHZlb||{BGWH9R=SYS1~P>QUJZe0ZZf|P)_krdr4W_6>aD*rQi3j0&L3u^EsqA z;g$Zw!G%dR$WGtyC(TY86r^{>rde6BBoWk2&TJtrnpBAn@So*8wxz|z2Ipp)XW+-Q z+Ns}!;vvNP>Bk0x(gPRrcV2YATv z;l<(SxtMZK*<%rTa!P1?t0`d6&(wo$59KBujJ^+o@c(^&wEF^kd;NZ#0z4C*z;=rd z050tB4-F4dW7+FLJ!fuW!47YU`7o@AhB0;pgq)oN8EZOv=*KYro9vn}$>R6yzmRhm zQvL&da((6ch*z$MNH?zKpC@ zvv-7k=SNuL^cMq3LMQCLAfSa(V-wyPCRcz&Pt8)KG2*_2U)yA*V9NVas#!8>OBi$* zMHeSc%B4u&CyV0p$9%{Yi6}s?&ZU|vq>vqulax+O=rrKd@1)8lQ5H!;+16M`vDaar zTzzTvZyK}OQw}yF3acDsWCK{Sd->A@-1&ujf3#IO>If-Kw&W zb)aCB2!nH%63|H*hFIXv*-7)wnvp2H`SnTqww@J6fG~b6TKIIw13y#**viMp;Lh2D ziDaNaaY)*#8d(opsYYDKx$;Q!V?bHfbvI?_pz5=gV# zlg8FKX$T8B`61ySqlvX4?>om$rHyV#h`K{gx_=ooDF?BKX)$0c<%wvxEicJN8=)K4 z0i(srW}F?$Ma`d2`*(xVNLEDPntYi^zU8J=$EoCo z`2oCs<6=|>Xve!T_j1y9LBfqpPR;dJLWRdQ{0x)E!It@1Tc<1aE1lS4zX{0qp^I_}bDt|(EWq#@KB9U4o1+mcf8}!E>AkeSUJ@h9b!+I_E)X7!f zIEjf2hdVo&QEwR2=TokNBxq;Kn$)2>8MHrY%>AZX{{d*?YdQqGsq@=DdQ&Jb0F(fq zI{@)(y>fRZ=DPSOoF?t}P;9I>jUd6qk8c-Pf=wuPWTQ9L@KQ4$p-d>1l)XA1)(wL= z+qxYOL&4v_kh7H%VeyKUo!$GWD^yV6S1AKdZMiR0j~w*P6>%9Hykp%%WDooaVeseU zY@5?~@%UL9m9@=sw*l92R2e-K423zUCuK_onNkvG>4Tp!5qutcQQm)s5|0XqVW!j9 zgq@})XV14mKX+h65b2GW|IAkq>LJ!xWRzA!MYuJjp>#9zXGkK{{-HmTd)fVH?#=bm zCi%3%0cM#b=B0+o^rTUMBh6_RZA-W%1d*a5h|aT z9v(QZ@i?-?X&N7d?qyFvW<`AHvf7IuG}8VWPN*+6!)i zIqprz83cL>^pO3cIDF3llHD6Ztm^Xuo6Gf63z>{DMm`f7WSACNzt5f6a@TtLxoHYT z>nXx-+xp2#F6j9?th)d1UDhi9py0{V>HF7_Yhd76F758sx|ZCyq6OEzR;#M4w~1Z~ zQ8)bl*Yk41fOYTi>AqGabC1)7#dk>1w3vkHhkPj=Jd1d>-f+&eB0TNDz!-w|{~GZM1*4+d3Nd?=v*9 z5DoHfg&ILN!P(hexZWK$Mzrg*4sA!^9C=o@(fQVbEK(8=nQYqajKu161w{foybCBM z0k3}%aKCaa>{=(I6lo#be*E*TCE#S~aK|2${SAQ-QfQt#I)v_S7OYwGF?$%yXyh<0 z%~5)IEF*?M7|!3pG^;F-kEdTxzL4Vp!c=erif*rhdU)a+dA|z!AGz5Hu$ZTF`z5`9HNI*6;uqz+i2eT#D9Hm<= z(!u=2*m)bLlUEFNx4gW1(qB5E9+=A*VC_80R~Jj)#mgjK3hqUOTA%=*Sj@Wq_ia!> z^RN;E`6LOMNS09O2ycmBvkP@_R_mO!5>HC|BE zT7i}q1Jhem+>?g66!^dW{$+99rRFADxmn2<7orf`$B_`Ll8LaiNPjB@q2!14h}#Qf zyP64&)}LkNUyDKm(6}D?I{gFz&tw)UT1bP7n1>=<2`8$}nsoQ@qYE*-*DCzEMb}S_9-zQbW-IjK8R!Z5 zwGiI#{INF$>KvpU7Qi|R6NQ*6@y~fIR=auvw(%BK+@7&3u){wI1B0`J`Q|xwxe-G? zh2He>8@xn<4yLZW4&q`44wMmTCC2^(PXgbHrSOl{kpesdZ9Z;degpFVxaL6yn`IfG zVd%FoKe1Xkt-NLZ6)WtolqcY$uZ7@WO@4^1ROob&C`5`1)nyKsp$Xy7r~e4!Z!FZy zD|QgihyTNoXZ5mDenfS9?yDXguP&qJd%BxhUg#<{~tLvas&p9-Xs5OL@=wGac&S@XxvaUTy!_A;0uFHiNirb%q;xSblK;P zmUx}kF;&P>fE~Uy?N()0LpnEhocdJFIceDuQKJKa+Z*xsL{a~p18AgAp6-if@Hu)8 zu}zGYdNuEs9zGA(qwW=z#ZAuE+Vnd+^L_ZqeE}DW#-Eby8YCz+h#)*FwivE+@os5F z4|~JaP?=9yidzQIcPE$Dq8>csn#mh|)~8F+X2>z)X?;Z;(tX;_Si$mwoN8#+*W z@FBMze5K$J-IjQP^pkmUWkpG~z9VBsVv5wD8it=hwdGH7><^IP@)^s|lH)_WZ4J{-o^uf*+32_m2*tABXRjjg+3Uej zX6U2!emN}oFCs!2?a`s87h1L8E7T51LAd3Hp(p`#O?zm4wyWnSXU#5qa^0&_5m&LN842RVuUv1xQ&Y z<}NKW7$TjC3he2!ay@u;RC+Giu+(16qu*`d`nOnTi1#(`2+}Yn42Zg@K z-VV}etuP18p**jQ|MpxL>8Ei{SrZ7QJKAxMMcn-B#Aj0gf)fgA6N|7>J_L*2ucf(J zy2ADsP>rH~<>|3RV)l+5V?paFnsp4vY<-@Xg@*bTCt3iGs%DfNF(sFOUs8gS<}enJ zw#L(efYI*9LbR)RNJ(LP2L{i1NoBVeHF;JtsTLN@I`_La1L{)o8l`)?Iu5()Lyeod(Vw8HKMcBVc1r+LEsL*Eqx-v^nYtggMYErt_%If+of>i>iE5MU zKOENlVSF_8L~FxUT^3<>eW7!MnpT>zZE1PiEFu4@c@I+Uq^mc_016PZtWnV$|eQnxn*DsaiRYv6q-J}ku?*t zLKqwfx@qrIIc)k~rXC_oNi4kfl8rf9OGk|*{ zR{ZEn0T1O@ZVC>p-|ut_><9V96rKFSK98JE3}K`j0L5YZOHpjJt|Wbt=fcDK z{Tr20#yJcRQ#S@dUx|>($?GMfkok08I!k!%TFy#;2=_D%NvLbmuJ%F%?Z!5Ju2l; zsS^nKPT}xj9b#j>#AK%NUGQz4QcPz8w$R2vE-T_8vpTPbp$C&ln~;K;SnJ0b{|dP1 z)c|fBAxn;1Sv+S=V(UvJRX^2%ZIrI1k1_$j(h#P3()~0?by284LK9ii52s9JI+;om zNu9O|l((r#9ypWD)=5-O70TrCFJHKFzdwJK@#6zn3KQb$sJ{kt7q4zFIAJJw|Xo3ub8s+<#UDUrW;_-}_wvv898>F9V zQT;-&cE@+w|JHeBHZG@eQRf@e$zgfHtMJi)TPydq-fpTb0{Qf)<|)yC{9th9erPgu zCe17OH9z~AfaTV`uyj|~{&g|T|J!vg7h$l}SA(ERv0i8yg^n^-0&SNuF!ne(Lo-NW z;5NpisgI0v$8v`>9GLWo2?HrJ5*F_EM zTn}3AaR3GIuNb}q>dO%DudY>9GClU0KF$mnf`;fiyVH=g(_8)2NEukrK|zl>77al* z-w8vet6h%@PdY7M4AnTHceFR~?<39{q79g0?T6~99ILpXa#ruU^_qnwx`j80&WGHW z{cm}G3Pwi1c(94gL}(O#@||J3OI{_BVNwu>^td6L4p(4P?$hJ(G-9~SrV|;}j0tQs zNE+yyiB$#skn*g{kx}gG!Zlc?`jyFc46;{mZLC{-16<ZCcs66Dvhqf<=tOJF)0kTt4~CrYwn{#!UH(EbuNO4>!^`FC++}N+VO;Yf z`u9jb1VU{DtVzFoX^e!o16?oSbbzAO0u(hMf2eQjBSGBN;>AGl$mUiijY0A)BUf1~&kJ=W-$-9v#W?f;MnSfH02+5d!uMMq6Evua8069?x2<5I9c>uW|}Lokj_kB3sP+m^qc?(|DU=D z@E`9q`QfB!_TjVg@{L&(R0rESQ(?nJYh0M_SUl;doboH3!%b(c$=9f%htcs;G~_yS zgZc5ZyP~*p`Z;sx2~_pnnB_R)qQ_nEX99mI;V!cwcmH#I^C)Cif(zqvZ(<2MI$Lje zh0<3uYI38R@<=@`Pqoc>DiD}PG{Y=m&}9zWE~jk#j#H8Zhk#{Vo!`hFnGc7IRW+zv zoYbT;QO_jei&lYcLmfwJi~T-L0hj*8?);R(;b*NBo$X>Nv< ziOv)`OUH#uY!$!lFo^wIPnneUu!_F})7Gx*1QZRCoqGWkEd^USOeVYgLVXPr66Nk7 z9aF|@5D;*@(>D!r^=@i!-2&;Tqu>j}HDi~FA>MVSWr!m@m9P(SOPOOS#c?O3V5&t_ z*vEwKpt))#x)7&g>{8&@zV=8CChxHhQsE$P;M=y5n+~hlRTglmJ_Z^ z$56=N|5x^aD`#hs2-_Pe^$3qHkQ7!&NYCOKs**h2o=P5{N8E+JIoyV)-^;(mBn^WX zRf9EibakawD%C0OXPa+nYoe&v4!O zfr*Wdf=H!d%=Pg(pWuKyQlw*0hR%b+?dprV-)*5nfvj1TG4P|1DsniAFQ6)GF{ zD5(0Eb*93Fn1(^pUMU13KIBB7*@!UVmzo4r-aNr}&O-AOab(~zBGQ=Li8J3`7|N;D zUaa9+uhWy1bs>Ein}7m6Eh3V&oNxYCY^*B2OoG%BI!Y;D)W%JiK7G0!&qGet~mi#Z|beAY4FN+g*JJ_CCcUf=Z=`V zy->veLKGHNBV6+;+lXl@d>QfOM-_I_W{<;SQLa(7q>eI6d6+%S+6c%@QaX^xYL9K5 zbtK(*+c6V;r6pE)6*7~u%R*N2nV1#0L4>i%jwqeR##zYf3$%G2P84g&;ADo8o3N(i z5k@4qtKSaAV5jw&|C2>ryL(N~O70=7VMjf>f!%n(hND8aOub9VkjdB>OpKVF#7-kZ zxk6N$rh?EJTVWmI6onvOEJF{^DmC;y%E}<6LBV9uCC{|a%jUK+i(9ICYXJeZ6wHXt z!DjEUmlxEG_S?rTa9fUiicqBz$oqon4ku4bTbruSxvTCa&FcI4k;fe88v>46#6_R^ zB&irNeMRBc?ExyTbH8JG>FXhXZENZuUoaRRnWQd_`t=e4tNku{PUJ#~!H4y+-|T^) ztHZI_Wi~%-K(xam7=cE5BKso?rn?f;)ADZfzcqURQ5f9?X9_+q4>ogK`9w)eCkm%o zXHQk>u36_+VSVqPu(|_%?vAhwd!)B}rL3G-Syhd?eP5xv`Td^n9`2U53x&_!7q6n{ zA`9i%IdVZ+4ucN$b9MwWjG#nja`dWL#iJOZv=CN-7^A5)V?a4O|w;-jF(d9 z4Eyh=3%-LZd(jP3A2KkSb2mS-KS3jNQg>heN#;+(q6)KGz+hS`qCEcH{_!#;#Jv+EWz{q0Ne5K;(cwlV;}0(YYueT*Bz9JU zLHD`6y6#pv9>aFWtB^lX6~{_~!3BHBS(G02Ih43*#g(uk97h(3n8a-uaji7$#VI

|~>Q0Ig+j!qTyR?3N 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 rEhklCwAUzCDc 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 N|Nr0oUj+b)002_k@gx8M diff --git a/library/ix-dev/charts/syncthing/ci/basic-values.yaml b/library/ix-dev/charts/syncthing/ci/basic-values.yaml new file mode 100644 index 0000000000..30bcb56747 --- /dev/null +++ b/library/ix-dev/charts/syncthing/ci/basic-values.yaml @@ -0,0 +1,8 @@ +syncthingNetwork: + webPort: 30910 + tcpPort: 30978 + udpPort: 30979 + +syncthingStorage: + config: + type: pvc diff --git a/library/ix-dev/charts/syncthing/ci/host-values.yaml b/library/ix-dev/charts/syncthing/ci/host-values.yaml new file mode 100644 index 0000000000..e0f5406043 --- /dev/null +++ b/library/ix-dev/charts/syncthing/ci/host-values.yaml @@ -0,0 +1,7 @@ +syncthingNetwork: + webPort: 30910 + hostNetwork: true + +syncthingStorage: + config: + type: pvc diff --git a/library/ix-dev/charts/syncthing/ci/test-values.yaml b/library/ix-dev/charts/syncthing/ci/test-values.yaml deleted file mode 100644 index c7a3504c57..0000000000 --- a/library/ix-dev/charts/syncthing/ci/test-values.yaml +++ /dev/null @@ -1,16 +0,0 @@ -appVolumeMounts: - config: - emptyDir: true - mountPath: /config -dnsConfig: - options: [] -emptyDirVolumes: true -environmentVariables: [] -extraAppVolumeMounts: [] -hostNetwork: false -ownerGID: 568 -ownerUID: 568 -tcp_port: 32001 -timezone: Europe/London -udp_port: 32002 -web_port: 32000 diff --git a/library/ix-dev/charts/syncthing/migrations/migrate b/library/ix-dev/charts/syncthing/migrations/migrate new file mode 100755 index 0000000000..34a9905591 --- /dev/null +++ b/library/ix-dev/charts/syncthing/migrations/migrate @@ -0,0 +1,94 @@ +#!/usr/bin/python3 +import json +import os +import sys + + +def migrate_volume(volume): + return { + 'type': 'hostPath', + 'hostPathConfig': { + 'hostPath': volume['hostPath'] + }, + } if volume.get('hostPathEnabled', False) else { + 'type': 'ixVolume', + 'ixVolumeConfig': { + 'datasetName': volume['datasetName'], + }, + } + + +def migrate_common_lib(values): + delete_keys = [ + 'web_port', 'tcp_port', 'udp_port', 'hostNetwork', 'dnsConfig', + 'ownerUID', 'ownerGID', 'environmentVariables', 'cpuLimit', 'memLimit', + 'enableResourceLimits', 'extraAppVolumeMounts', 'appVolumeMounts', + ] + + values.update({ + # Migrate Network + 'syncthingNetwork': { + 'webPort': values['web_port'], + 'tcpPort': values['tcp_port'], + 'udpPort': values['udp_port'], + 'hostNetwork': values['hostNetwork'], + }, + # Migrate Resources + 'resources': { + 'limits': { + 'cpu': values.get('cpuLimit', '4000m'), + 'memory': values.get('memLimit', '8Gi'), + } + }, + # Migrate DNS + 'podOptions': { + 'dnsConfig': { + 'options': [ + {'name': opt['name'], 'value': opt['value']} + for opt in values.get('dnsConfig', {}).get('options', []) + ] + } + }, + # Migrate ID + 'syncthingID': { + 'user': values['ownerUID'], + 'group': values['ownerGID'], + }, + # Migrate Config + 'syncthingConfig': { + 'additionalEnvs': values.get('environmentVariables', []), + }, + # Migrate Storage + 'syncthingStorage': { + 'config': migrate_volume(values['appVolumeMounts']['config']), + 'additionalStorages': [ + { + 'type': 'hostPath', + 'hostPathConfig': {'hostPath': e['hostPath']}, + 'mountPath': e['mountPath'], + } + for e in values.get('extraAppVolumeMounts', []) + ], + }, + }) + + for k in delete_keys: + values.pop(k, None) + + return values + +def migrate(values): + # If this missing, we have already migrated + if not 'appVolumeMounts' in values.keys(): + return values + + return migrate_common_lib(values) + + +if __name__ == '__main__': + if len(sys.argv) != 2: + exit(1) + + if os.path.exists(sys.argv[1]): + with open(sys.argv[1], 'r') as f: + print(json.dumps(migrate(json.loads(f.read())))) diff --git a/library/ix-dev/charts/syncthing/questions.yaml b/library/ix-dev/charts/syncthing/questions.yaml index 6964a864ad..c006268287 100644 --- a/library/ix-dev/charts/syncthing/questions.yaml +++ b/library/ix-dev/charts/syncthing/questions.yaml @@ -1,218 +1,422 @@ groups: - - name: "Configuration" - description: "Syncthing application configuration" - - name: "Storage" - description: "Configure storage for syncthing" - - name: "Networking" - description: "Networking Configuration for syncthing" - - name: "Advanced DNS Settings" - description: "Configure DNS settings" - - name: "Resource Limits" - description: "Set CPU/memory limits for Kubernetes Pod" + - name: Syncthing Configuration + description: Configure Syncthing + - name: User and Group Configuration + description: Configure User and Group for Syncthing + - name: Advanced Pod Configuration + description: Configure Advanced Pod Options for Syncthing + - name: Network Configuration + description: Configure Network for Syncthing + - name: Storage Configuration + description: Configure Storage for Syncthing + - name: Resources Configuration + description: Configure Resources for Syncthing portals: web_portal: protocols: - - "http" + - "$kubernetes-resource_configmap_portal_protocol" host: - - "$node_ip" + - "$kubernetes-resource_configmap_portal_host" ports: - - "$variable-web_port" - path: "/" + - "$kubernetes-resource_configmap_portal_port" + path: "$kubernetes-resource_configmap_portal_path" questions: - - variable: web_port - label: "Web Port for syncthing" - group: Networking - schema: - type: int - min: 8000 - max: 65535 - default: 20910 - required: true - - variable: tcp_port - label: "TCP Port for syncthing" - group: Networking - schema: - type: int - min: 8000 - max: 65535 - default: 20978 - required: true - - variable: udp_port - label: "UDP Port for syncthing" - group: Networking - schema: - type: int - min: 8000 - max: 65535 - default: 20979 - required: true - - variable: hostNetwork - label: "Host Network" - group: Networking - schema: - type: boolean - default: false - - - variable: dnsConfig - label: "DNS Configuration" - group: "Advanced DNS Settings" + - variable: syncthingConfig + label: "" + group: Syncthing Configuration schema: type: dict attrs: - - variable: options - label: "DNS Options" + - variable: additionalEnvs + label: Additional Environment Variables + description: Configure additional environment variables for Syncthing. schema: type: list + default: [] items: - - variable: optionsEntry - label: "Option Entry Configuration" + - variable: env + label: Environment Variable schema: type: dict attrs: - variable: name - label: "Option Name" + label: Name schema: type: string required: true - variable: value - label: "Option Value" + label: Value schema: type: string required: true - - variable: ownerUID - label: "Owner User ID" - group: Configuration + - variable: syncthingID + label: "" + group: User and Group Configuration schema: - type: int - default: 568 - min: 1 - max: 65535 + type: dict + attrs: + - variable: user + label: User ID + description: The user id that Syncthing files will be owned by. + schema: + type: int + min: 568 + default: 568 + required: true + - variable: group + label: Group ID + description: The group id that Syncthing files will be owned by. + schema: + type: int + min: 568 + default: 568 + required: true - - variable: ownerGID - label: "Owner Group ID" - group: Configuration + - variable: podOptions + label: "" + group: Advanced Pod Configuration schema: - type: int - default: 568 - min: 1 - max: 65535 - - - variable: environmentVariables - label: "Syncthing environment" - group: "Configuration" - schema: - type: list - default: [ ] - items: - - variable: environmentVariable - label: "Environment Variable" + type: dict + attrs: + - variable: dnsConfig + label: Advanced DNS Configuration schema: type: dict attrs: - - variable: name - label: "Name" + - variable: options + label: DNS Options schema: - type: string - - variable: value - label: "Value" - schema: - type: string + type: list + items: + - variable: optionsEntry + label: DNS Option Entry + schema: + type: dict + attrs: + - variable: name + label: Option Name + schema: + type: string + required: true + - variable: value + label: Option Value + schema: + type: string + required: true - - variable: appVolumeMounts - label: "Syncthing Storage" - group: "Storage" + - variable: syncthingNetwork + label: "" + group: Network Configuration + schema: + type: dict + attrs: + - variable: webPort + label: Web Port + description: The port for the Syncthing Web UI. + schema: + type: int + default: 20910 + min: 9000 + max: 65535 + required: true + - variable: tcpPort + label: TCP Port + description: The port for the Syncthing TCP connection. + schema: + type: int + default: 20978 + show_if: [["hostNetwork", "=", false]] + min: 9000 + max: 65535 + required: true + - variable: udpPort + label: UDP Port + description: The port for the Syncthing UDP connection. + schema: + type: int + default: 20979 + show_if: [["hostNetwork", "=", false]] + min: 9000 + max: 65535 + required: true + - variable: hostNetwork + label: Host Network + description: | + Enabling this will use the host network for Syncthing.
+ The TCP and UDP ports will listen on port 22000.
+ Web UI will listen on the port specified above. + schema: + type: boolean + default: false + + - variable: syncthingStorage + label: "" + group: Storage Configuration schema: type: dict attrs: - variable: config - label: "Configuration Volume" + label: Syncthing Config Storage + description: The path to store Syncthing Configuration. schema: type: dict attrs: - - variable: datasetName - label: "Configuration Volume Dataset Name" + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. schema: type: string - hidden: true + required: true + immutable: true + default: "ixVolume" + enum: + - value: "hostPath" + description: Host Path (Path that already exists on the system) + - value: "ixVolume" + description: ixVolume (Dataset created automatically by the system) + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + show_if: [["type", "=", "ixVolume"]] $ref: - "normalize/ixVolume" - show_if: [["hostPathEnabled", "=", false]] - default: "ix-syncthing_config" - editable: false - - variable: mountPath - label: "Configuration Mount Path" - description: "Path where the volume will be mounted inside the pod" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + hidden: true + default: "config" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Config schema: - type: path - hidden: true - editable: true - default: "/var/syncthing" - - variable: hostPathEnabled - label: "Enable Custom Host Path for Syncthing Configuration Volume" - schema: - type: boolean - default: false - show_subquestions_if: true - subquestions: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" - variable: hostPath - label: "Host Path for Syncthing Configuration Volume" + label: Host Path + description: The host path to use for storage. schema: type: hostpath + show_if: [["aclEnable", "=", false]] required: true + - variable: additionalStorages + label: Additional Storage + description: Additional storage for Syncthing. + schema: + type: list + default: [] + items: + - variable: storageEntry + label: Storage Entry + schema: + type: dict + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system.
+ SMB Share: Is a SMB share that is mounted to a persistent volume claim. + schema: + type: string + required: true + default: "ixVolume" + immutable: true + enum: + - value: "hostPath" + description: Host Path (Path that already exists on the system) + - value: "ixVolume" + description: ixVolume (Dataset created automatically by the system) + - value: "smb-pv-pvc" + description: SMB Share (Mounts a persistent volume claim to a SMB share) + - variable: readOnly + label: Read Only + description: Mount the volume as read only. + schema: + type: boolean + default: false + - variable: mountPath + label: Mount Path + description: The path inside the container to mount the storage. + schema: + type: path + required: true + - variable: hostPathConfig + label: Host Path Config + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + show_if: [["type", "=", "ixVolume"]] $ref: - - "validations/lockedHostPath" - - variable: extraAppVolumeMounts - label: "Extra Host Path Volumes" - group: "Storage" + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + default: "storage_entry" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: smbConfig + label: SMB Share Configuration + description: The configuration for the SMB Share. + schema: + type: dict + show_if: [["type", "=", "smb-pv-pvc"]] + attrs: + - variable: server + label: Server + description: The server for the SMB share. + schema: + type: string + required: true + - variable: share + label: Share + description: The share name for the SMB share. + schema: + type: string + required: true + - variable: domain + label: Domain (Optional) + description: The domain for the SMB share. + schema: + type: string + - variable: username + label: Username + description: The username for the SMB share. + schema: + type: string + required: true + - variable: password + label: Password + description: The password for the SMB share. + schema: + type: string + required: true + private: true + - variable: size + label: Size (in Gi) + description: The size of the volume quota. + schema: + type: int + required: true + min: 1 + default: 1 + + - variable: resources + group: Resources Configuration + label: "" schema: - type: list - items: - - variable: extraAppVolume - label: "Host Path Volume" - description: "Add an extra host path volume for Syncthing application" + type: dict + attrs: + - variable: limits + label: Limits schema: type: dict attrs: - - variable: mountPath - label: "Mount Path in Pod" - description: "Path where the volume will be mounted inside the pod" + - variable: cpu + label: CPU + description: CPU limit for Syncthing. schema: - type: path + type: string + max_length: 6 + valid_chars: '^(0\.[1-9]|[1-9][0-9]*)(\.[0-9]|m?)$' + valid_chars_error: | + Valid CPU limit formats are
+ - Plain Integer - eg. 1
+ - Float - eg. 0.5
+ - Milicpu - eg. 500m + default: "4000m" required: true - - variable: hostPath - label: "Host Path" - description: "Host path" + - variable: memory + label: Memory + description: Memory limit for Syncthing. schema: - type: hostpath + type: string + max_length: 12 + valid_chars: '^[1-9][0-9]*([EPTGMK]i?|e[0-9]+)?$' + valid_chars_error: | + Valid Memory limit formats are
+ - Suffixed with E/P/T/G/M/K - eg. 1G
+ - Suffixed with Ei/Pi/Ti/Gi/Mi/Ki - eg. 1Gi
+ - Plain Integer in bytes - eg. 1024
+ - Exponent - eg. 134e6 + default: "8Gi" required: true - $ref: - - "validations/lockedHostPath" - - - variable: enableResourceLimits - label: "Enable Pod resource limits" - group: "Resource Limits" - schema: - type: boolean - default: false - - variable: cpuLimit - label: "CPU Limit" - description: "CPU resource limit allow plain integer values with suffix m(milli) e.g 1000m, 100." - group: "Resource Limits" - schema: - type: string - show_if: [["enableResourceLimits", "=", true]] - valid_chars: "^\\d+(?:\\.\\d+(?!.*m$)|m?$)" - default: "4000m" - - variable: memLimit - label: "Memory Limit" - group: "Resource Limits" - description: "Memory limits is specified by number of bytes. Followed by quantity suffix like E,P,T,G,M,k and Ei,Pi,Ti,Mi,Gi,Ki can also be used. e.g 129e6, 129M, 128974848000m, 123Mi" - schema: - type: string - show_if: [["enableResourceLimits", "=", true]] - valid_chars: "^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" - default: "8Gi" - diff --git a/library/ix-dev/charts/syncthing/templates/NOTES.txt b/library/ix-dev/charts/syncthing/templates/NOTES.txt new file mode 100644 index 0000000000..ba4e01146c --- /dev/null +++ b/library/ix-dev/charts/syncthing/templates/NOTES.txt @@ -0,0 +1 @@ +{{ include "ix.v1.common.lib.chart.notes" $ }} diff --git a/library/ix-dev/charts/syncthing/templates/_migration.tpl b/library/ix-dev/charts/syncthing/templates/_migration.tpl new file mode 100644 index 0000000000..323dc6fc10 --- /dev/null +++ b/library/ix-dev/charts/syncthing/templates/_migration.tpl @@ -0,0 +1,35 @@ +{{- define "syncthing.get-versions" -}} + {{- $oldChartVersion := "" -}} + {{- $newChartVersion := "" -}} + + {{/* Safely access the context, so it wont block CI */}} + {{- if hasKey .Values.global "ixChartContext" -}} + {{- if .Values.global.ixChartContext.upgradeMetadata -}} + + {{- $oldChartVersion = .Values.global.ixChartContext.upgradeMetadata.oldChartVersion -}} + {{- $newChartVersion = .Values.global.ixChartContext.upgradeMetadata.newChartVersion -}} + {{- if and (not $oldChartVersion) (not $newChartVersion) -}} + {{- fail "Upgrade Metadata is missing. Cannot proceed" -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- toYaml (dict "old" $oldChartVersion "new" $newChartVersion) -}} +{{- end -}} + +{{- define "syncthing.migration" -}} + {{- $versions := (fromYaml (include "syncthing.get-versions" $)) -}} + {{- if and $versions.old $versions.new -}} + {{- $oldV := semver $versions.old -}} + {{- $newV := semver $versions.new -}} + + {{/* If new is v2.x.x */}} + {{- if eq ($newV.Major | int) 2 -}} + {{/* And old is v1.x.x, but lower than .42 */}} + {{- if and (eq $oldV.Major 1) (lt ($oldV.Patch | int) 42) -}} + {{/* Block the upgrade */}} + {{- fail "Migration to 2.x.x is only allowed from 1.0.42 or higher" -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/ix-dev/charts/syncthing/templates/_persistence.tpl b/library/ix-dev/charts/syncthing/templates/_persistence.tpl new file mode 100644 index 0000000000..fae13cdcbd --- /dev/null +++ b/library/ix-dev/charts/syncthing/templates/_persistence.tpl @@ -0,0 +1,26 @@ +{{- define "syncthing.persistence" -}} +persistence: + config: + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" .Values.syncthingStorage.config) | nindent 4 }} + targetSelector: + syncthing: + syncthing: + mountPath: /var/syncthing + tmp: + enabled: true + type: emptyDir + targetSelector: + syncthing: + syncthing: + mountPath: /tmp + {{- range $idx, $storage := .Values.syncthingStorage.additionalStorages }} + {{ printf "syncthing-%v:" (int $idx) }} + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" $storage) | nindent 4 }} + targetSelector: + syncthing: + syncthing: + mountPath: {{ $storage.mountPath }} + {{- end }} +{{- end -}} diff --git a/library/ix-dev/charts/syncthing/templates/_portal.tpl b/library/ix-dev/charts/syncthing/templates/_portal.tpl new file mode 100644 index 0000000000..f3a4926d74 --- /dev/null +++ b/library/ix-dev/charts/syncthing/templates/_portal.tpl @@ -0,0 +1,12 @@ +{{- define "syncthing.portal" -}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: portal +data: + port: {{ .Values.syncthingNetwork.webPort | quote }} + path: "/" + protocol: "http" + host: $node_ip +{{- end -}} diff --git a/library/ix-dev/charts/syncthing/templates/_service.tpl b/library/ix-dev/charts/syncthing/templates/_service.tpl new file mode 100644 index 0000000000..acefb0d5c3 --- /dev/null +++ b/library/ix-dev/charts/syncthing/templates/_service.tpl @@ -0,0 +1,25 @@ +{{- define "syncthing.service" -}} +service: + syncthing: + enabled: true + primary: true + type: ClusterIP + targetSelector: syncthing + ports: + webui: + enabled: true + primary: true + port: {{ .Values.syncthingNetwork.webPort }} + targetSelector: syncthing + sync-tcp: + enabled: true + port: {{ .Values.syncthingNetwork.tcpPort }} + targetPort: 22000 + targetSelector: syncthing + sync-udp: + enabled: true + port: {{ .Values.syncthingNetwork.udpPort }} + targetPort: 22000 + protocol: udp + targetSelector: syncthing +{{- end -}} diff --git a/library/ix-dev/charts/syncthing/templates/_syncthing.tpl b/library/ix-dev/charts/syncthing/templates/_syncthing.tpl new file mode 100644 index 0000000000..d34d2b7408 --- /dev/null +++ b/library/ix-dev/charts/syncthing/templates/_syncthing.tpl @@ -0,0 +1,62 @@ +{{- define "syncthing.workload" -}} +workload: + syncthing: + enabled: true + primary: true + type: Deployment + podSpec: + securityContenxt: + fsGroup: {{ .Values.syncthingID.group }} + hostNetwork: {{ .Values.syncthingNetwork.hostNetwork }} + containers: + syncthing: + enabled: true + primary: true + imageSelector: image + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + readOnlyRootFilesystem: false + # This is needed to allow syncthing assign + # PCAPs to its child processes + allowPrivilegeEscalation: true + capabilities: + add: + - FOWNER + - DAC_OVERRIDE + - CHOWN + - SETUID + - SETGID + - SETFCAP + - SETPCAP + - SYS_ADMIN + env: + STGUIADDRESS: 0.0.0.0:{{ .Values.syncthingNetwork.webPort }} + STNOUPGRADE: "true" + fixedEnv: + PUID: {{ .Values.syncthingID.user }} + {{ with .Values.syncthingConfig.additionalEnvs }} + envList: + {{ range $env := . }} + - name: {{ $env.name }} + value: {{ $env.value }} + {{ end }} + {{ end }} + probes: + liveness: + enabled: true + type: http + path: /rest/noauth/health + port: {{ .Values.syncthingNetwork.webPort }} + readiness: + enabled: true + type: http + path: /rest/noauth/health + port: {{ .Values.syncthingNetwork.webPort }} + startup: + enabled: true + type: http + path: /rest/noauth/health + port: {{ .Values.syncthingNetwork.webPort }} +{{- end -}} diff --git a/library/ix-dev/charts/syncthing/templates/common.yaml b/library/ix-dev/charts/syncthing/templates/common.yaml new file mode 100644 index 0000000000..a864a832df --- /dev/null +++ b/library/ix-dev/charts/syncthing/templates/common.yaml @@ -0,0 +1,13 @@ +{{- include "ix.v1.common.loader.init" . -}} + +{{- include "syncthing.migration" $ -}} + +{{/* Merge the templates with Values */}} +{{- $_ := mustMergeOverwrite .Values (include "syncthing.workload" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "syncthing.service" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "syncthing.persistence" $ | fromYaml) -}} + +{{/* Create the configmap for portal manually*/}} +{{- include "syncthing.portal" $ -}} + +{{- include "ix.v1.common.loader.apply" . -}} diff --git a/library/ix-dev/charts/syncthing/templates/deployment.yaml b/library/ix-dev/charts/syncthing/templates/deployment.yaml deleted file mode 100644 index 996ce1f11e..0000000000 --- a/library/ix-dev/charts/syncthing/templates/deployment.yaml +++ /dev/null @@ -1,98 +0,0 @@ -{{ include "common.storage.hostPathValidate" .Values }} -apiVersion: {{ template "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "common.names.fullname" . }}-st - labels: - app: {{ template "common.names.name" . }} - chart: {{ template "common.names.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} - annotations: - rollme: {{ randAlphaNum 5 | quote }} -spec: - replicas: {{ (default 1 .Values.replicas) }} - strategy: - type: "Recreate" - selector: - matchLabels: - app: {{ template "common.names.name" . }} - release: {{ .Release.Name }} - template: - metadata: - name: {{ template "common.names.fullname" . }} - labels: - app: {{ template "common.names.name" . }} - release: {{ .Release.Name }} - {{- include "common.labels.selectorLabels" . | nindent 8 }} - annotations: {{ include "common.annotations" . | nindent 8 }} - spec: - hostNetwork: {{ .Values.hostNetwork }} - hostname: {{ .Release.Name }} - containers: - - name: {{ .Chart.Name }} - {{ include "common.resources.limitation" . | nindent 10 }} - {{ include "common.containers.imageConfig" .Values.image | nindent 10 }} - volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }} - {{ range $index, $hostPathConfiguration := .Values.extraAppVolumeMounts }} - - name: extrappvolume-{{ $index }} - mountPath: {{ $hostPathConfiguration.mountPath }} - {{ end }} - ports: - - name: web - containerPort: 8384 - {{ if not .Values.hostNetwork }} - hostPort: null - {{ end }} - - name: tcp - containerPort: 22000 - protocol: TCP - {{ if not .Values.hostNetwork }} - hostPort: null - {{ end }} - - name: udp - containerPort: 22000 - protocol: UDP - {{ if not .Values.hostNetwork }} - hostPort: null - {{ end }} - readinessProbe: - httpGet: - path: /rest/noauth/health - port: 8384 - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 2 - livenessProbe: - httpGet: - path: /rest/noauth/health - port: 8384 - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 1 - startupProbe: - httpGet: - path: /rest/noauth/health - port: 8384 - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 2 - failureThreshold: 60 - successThreshold: 1 - env: - {{ $envList := (default list .Values.environmentVariables) }} - {{ $envList = mustAppend $envList (dict "name" "PUID" "value" (printf "%d" (.Values.ownerUID | int))) }} - {{ $envList = mustAppend $envList (dict "name" "PGID" "value" (printf "%d" (.Values.ownerGID | int))) }} - {{ $envList = mustAppend $envList (dict "name" "STGUIADDRESS" "value" "0.0.0.0:8384") }} - {{ include "common.containers.environmentVariables" (dict "environmentVariables" $envList) | nindent 12 }} -{{ include "common.networking.dnsConfiguration" .Values | nindent 6 }} - volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }} - {{ range $index, $hostPathConfiguration := .Values.extraAppVolumeMounts }} - - name: extrappvolume-{{ $index }} - hostPath: - path: {{ $hostPathConfiguration.hostPath }} - {{ end }} diff --git a/library/ix-dev/charts/syncthing/templates/pre-install-job.yaml b/library/ix-dev/charts/syncthing/templates/pre-install-job.yaml deleted file mode 100644 index 33c4cfb113..0000000000 --- a/library/ix-dev/charts/syncthing/templates/pre-install-job.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ template "common.names.fullname" . }}-preinstall-job" - labels: - app.kubernetes.io/managed-by: {{ .Release.Service | quote }} - app.kubernetes.io/instance: {{ .Release.Name | quote }} - app.kubernetes.io/version: {{ .Chart.AppVersion }} - helm.sh/chart: {{ template "common.names.chart" . }} - annotations: - "helm.sh/hook": pre-install - "helm.sh/hook-delete-policy": hook-succeeded -spec: - template: - metadata: - name: "{{ template "common.names.fullname" . }}-preinstall-hook" - labels: - app.kubernetes.io/managed-by: {{ .Release.Service | quote }} - app.kubernetes.io/instance: {{ .Release.Name | quote }} - helm.sh/chart: {{ template "common.names.chart" . }} - spec: - restartPolicy: Never - containers: - - name: pre-install-job - image: "alpine:latest" - command: - - "chown" - - "-R" - - "{{ .Values.ownerUID }}:{{ .Values.ownerGID }}" - - "{{ .Values.appVolumeMounts.config.mountPath }}" - volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }} - volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }} diff --git a/library/ix-dev/charts/syncthing/templates/service.yaml b/library/ix-dev/charts/syncthing/templates/service.yaml deleted file mode 100644 index a35d1ffe18..0000000000 --- a/library/ix-dev/charts/syncthing/templates/service.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{ $selectors := list }} -{{ $selectors = mustAppend $selectors (dict "key" "app" "value" (include "common.names.name" .) ) }} -{{ $selectors = mustAppend $selectors (dict "key" "release" "value" .Release.Name ) }} -{{ $ports := list }} -{{ $ports = mustAppend $ports (dict "name" "web" "port" .Values.web_port "nodePort" .Values.web_port "targetPort" 8384) }} -{{ $ports = mustAppend $ports (dict "name" "tcp" "port" .Values.tcp_port "nodePort" .Values.tcp_port "targetPort" 22000) }} -{{ $ports = mustAppend $ports (dict "name" "udp" "port" .Values.udp_port "nodePort" .Values.udp_port "targetPort" 22000 "protocol" "UDP") }} -{{ $params := . }} -{{ $_ := set $params "commonService" (dict "type" "NodePort" "ports" $ports ) }} -{{ $_1 := set .Values "extraSelectorLabels" $selectors }} -{{ include "common.classes.service" $params }} diff --git a/library/ix-dev/charts/syncthing/to_keep_versions.md b/library/ix-dev/charts/syncthing/to_keep_versions.md new file mode 100644 index 0000000000..1578f1325e --- /dev/null +++ b/library/ix-dev/charts/syncthing/to_keep_versions.md @@ -0,0 +1,4 @@ +# 1.0.42 + +This version is kept because it contains a fix that is needed for migration to v2.x.x +It should be safe to remove few months after v2.x.x is released. diff --git a/library/ix-dev/charts/syncthing/to_keep_versions.yaml b/library/ix-dev/charts/syncthing/to_keep_versions.yaml new file mode 100644 index 0000000000..8d1a6575ae --- /dev/null +++ b/library/ix-dev/charts/syncthing/to_keep_versions.yaml @@ -0,0 +1 @@ +- 1.0.42 diff --git a/library/ix-dev/charts/syncthing/values.yaml b/library/ix-dev/charts/syncthing/values.yaml index ed01a4e16e..03ebb3261d 100644 --- a/library/ix-dev/charts/syncthing/values.yaml +++ b/library/ix-dev/charts/syncthing/values.yaml @@ -2,3 +2,32 @@ image: pullPolicy: IfNotPresent repository: syncthing/syncthing tag: 1.27.3 + +resources: + limits: + cpu: 4000m + memory: 8Gi + +podOptions: + dnsConfig: + options: [] + +syncthingConfig: + additionalEnvs: [] + +syncthingID: + user: 568 + group: 568 + +syncthingNetwork: + webPort: 20910 + tcpPort: 20978 + udpPort: 20979 + hostNetwork: false + +syncthingStorage: + config: + type: ixVolume + ixVolumeConfig: + datasetName: config + additionalStorages: []