From a6aa358c1777e12df9d1299700782c6154deadfe Mon Sep 17 00:00:00 2001 From: Nic Date: Wed, 20 Mar 2024 15:08:52 +0800 Subject: [PATCH] Revert "release: promote apisix v2.x helm chart to default branch (#733)" (#736) This reverts commit d75cc710b43dffa9eb8f06a87ba376d9add5069a. --- .github/workflows/ci.yaml | 42 +- README.md | 5 - apisix-0.13.2.tgz | Bin 0 -> 83738 bytes charts/apisix-dashboard/Chart.yaml | 2 +- charts/apisix-dashboard/README.md | 6 + .../apisix-dashboard/templates/configmap.yaml | 10 + .../templates/deployment.yaml | 26 + charts/apisix-dashboard/values.yaml | 27 +- charts/apisix-ingress-controller/Chart.yaml | 4 +- charts/apisix-ingress-controller/README.md | 44 +- .../crds/ApisixClusterConfig.yaml | 100 + .../crds/ApisixConsumer.yaml | 422 +++ .../crds/ApisixGlobalRule.yaml | 77 +- .../crds/ApisixPluginConfig.yaml | 127 + .../crds/ApisixRoute.yaml | 665 ++++ .../crds/ApisixTls.yaml | 266 ++ .../crds/ApisixUpstream.yaml | 838 +++++ .../crds/customresourcedefinitions.yaml | 3041 ----------------- .../templates/_helpers.tpl | 11 + .../templates/apisix-configmap.yaml | 174 + .../templates/configmap.yaml | 18 +- .../templates/deployment.yaml | 67 +- .../templates/ingress-class.yaml | 12 + .../templates/pdb.yaml | 38 + .../templates/rbac.yaml | 4 + .../templates/service-apisix.yaml | 44 + .../templates/servicemonitor.yaml | 5 +- charts/apisix-ingress-controller/values.yaml | 103 +- charts/apisix/Chart.lock | 10 +- charts/apisix/Chart.yaml | 8 +- charts/apisix/README.md | 264 +- .../apisix/charts/apisix-dashboard-0.8.1.tgz | Bin 7143 -> 0 bytes .../apisix/charts/apisix-dashboard-0.8.2.tgz | Bin 0 -> 8013 bytes .../apisix-ingress-controller-0.13.0.tgz | Bin 20799 -> 0 bytes .../apisix-ingress-controller-0.14.0.tgz | Bin 0 -> 21599 bytes charts/apisix/charts/etcd-8.7.7.tgz | Bin 43592 -> 0 bytes charts/apisix/charts/etcd-9.7.3.tgz | Bin 0 -> 44977 bytes charts/apisix/ci/default-values.yaml | 0 charts/apisix/ci/etcd-password-values.yaml | 21 + .../apisix/ci/topology-constrains-values.yaml | 9 + charts/apisix/templates/NOTES.txt | 14 +- charts/apisix/templates/_helpers.tpl | 102 +- charts/apisix/templates/_pod.tpl | 267 ++ ...ig-cm.yml => apisix-config-configmap.yaml} | 4 +- charts/apisix/templates/configmap.yaml | 237 +- charts/apisix/templates/daemonset.yaml | 33 + charts/apisix/templates/deployment.yaml | 270 +- charts/apisix/templates/etcd-secret.yaml | 10 - charts/apisix/templates/extra-list.yaml | 8 - charts/apisix/templates/hpa.yaml | 2 +- charts/apisix/templates/ingress-admin.yaml | 22 +- charts/apisix/templates/ingress.yaml | 22 +- charts/apisix/templates/pdb.yaml | 12 +- charts/apisix/templates/secrets.yaml | 14 + charts/apisix/templates/service-admin.yaml | 28 +- charts/apisix/templates/service-gateway.yaml | 70 +- charts/apisix/templates/service-metrics.yaml | 6 +- charts/apisix/templates/service-monitor.yaml | 23 +- charts/apisix/values.yaml | 959 +++--- docs/en/latest/FAQ.md | 2 +- 60 files changed, 4393 insertions(+), 4202 deletions(-) create mode 100644 apisix-0.13.2.tgz create mode 100644 charts/apisix-ingress-controller/crds/ApisixClusterConfig.yaml create mode 100644 charts/apisix-ingress-controller/crds/ApisixConsumer.yaml create mode 100644 charts/apisix-ingress-controller/crds/ApisixPluginConfig.yaml create mode 100644 charts/apisix-ingress-controller/crds/ApisixRoute.yaml create mode 100644 charts/apisix-ingress-controller/crds/ApisixTls.yaml create mode 100644 charts/apisix-ingress-controller/crds/ApisixUpstream.yaml delete mode 100644 charts/apisix-ingress-controller/crds/customresourcedefinitions.yaml create mode 100644 charts/apisix-ingress-controller/templates/apisix-configmap.yaml create mode 100644 charts/apisix-ingress-controller/templates/ingress-class.yaml create mode 100644 charts/apisix-ingress-controller/templates/pdb.yaml create mode 100644 charts/apisix-ingress-controller/templates/service-apisix.yaml delete mode 100644 charts/apisix/charts/apisix-dashboard-0.8.1.tgz create mode 100644 charts/apisix/charts/apisix-dashboard-0.8.2.tgz delete mode 100644 charts/apisix/charts/apisix-ingress-controller-0.13.0.tgz create mode 100644 charts/apisix/charts/apisix-ingress-controller-0.14.0.tgz delete mode 100644 charts/apisix/charts/etcd-8.7.7.tgz create mode 100644 charts/apisix/charts/etcd-9.7.3.tgz create mode 100644 charts/apisix/ci/default-values.yaml create mode 100644 charts/apisix/ci/etcd-password-values.yaml create mode 100644 charts/apisix/ci/topology-constrains-values.yaml create mode 100644 charts/apisix/templates/_pod.tpl rename charts/apisix/templates/{apisix-config-cm.yml => apisix-config-configmap.yaml} (93%) create mode 100644 charts/apisix/templates/daemonset.yaml delete mode 100644 charts/apisix/templates/etcd-secret.yaml delete mode 100644 charts/apisix/templates/extra-list.yaml create mode 100644 charts/apisix/templates/secrets.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6813d8f7..e0c3219f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,15 +9,40 @@ on: jobs: + helm_docs: + name: Check the Helm Docs format + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: '1.19.2' + + - name: Run helm-docs + run: | + GOBIN=$PWD GO111MODULE=on go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.11.0 + ./helm-docs --chart-search-root=${GITHUB_WORKSPACE}/charts + DIFF=$(git diff ${GITHUB_WORKSPACE}/charts/**/*md) + if [ ! -z "$DIFF" ]; then + echo "Please use helm-docs in your clone, of your fork, of the project, and commit an updated README.md for the chart." + fi + git diff --exit-code + rm -f ./helm-docs + helm: name: Helm chart runs-on: ubuntu-20.04 + needs: helm_docs strategy: matrix: k8s: ["v1.16.15@sha256:64bac16b83b6adfd04ea3fbcf6c9b5b893277120f2b2cbf9f5fa3e5d4c2260cc", "v1.17.17@sha256:e477ee64df5731aa4ef4deabbafc34e8d9a686b49178f726563598344a3898d5", "v1.18.20@sha256:e3dca5e16116d11363e31639640042a9b1bd2c90f85717a7fc66be34089a8169", "v1.19.16@sha256:81f552397c1e6c1f293f967ecb1344d8857613fb978f963c30e907c32f598467", "v1.20.15@sha256:393bb9096c6c4d723bb17bceb0896407d7db581532d11ea2839c80b28e5d8deb", "v1.21.10@sha256:84709f09756ba4f863769bdcabe5edafc2ada72d3c8c44d6515fc581b66b029c", "v1.22.7@sha256:1dfd72d193bf7da64765fd2f2898f78663b9ba366c2aa74be1fd7498a1873166", "v1.23.4@sha256:0e34f0d0fd448aa2f2819cfd74e99fe5793a6e4938b328f657c8e3f81ee0dfb9"] steps: - - name: Checkout uses: actions/checkout@v2 with: @@ -69,18 +94,3 @@ jobs: && ct install \ --charts charts/apisix' - - name: Setup Go - uses: actions/setup-go@v3 - with: - go-version: '1.19.2' - - - name: Run helm-docs - run: | - GOBIN=$PWD GO111MODULE=on go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.11.0 - ./helm-docs --chart-search-root=${GITHUB_WORKSPACE}/charts - DIFF=$(git diff ${GITHUB_WORKSPACE}/charts/**/*md) - if [ ! -z "$DIFF" ]; then - echo "Please use helm-docs in your clone, of your fork, of the project, and commit a updated README.md for the chart." - fi - git diff --exit-code - rm -f ./helm-docs diff --git a/README.md b/README.md index b78e7abe..90496317 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,5 @@ Currently, APISIX Ingress Controller automatically manipulates some APISIX resou | | APISIX | APISIX Ingress | APISIX Dashboard | | :--------: | :----: | :------------: | :--------------: | -| Chart v2.x | v3.x | v1.x | v3.x | | Chart v1.x | v3.x | v1.x | v3.x | | Chart v0.x | v2.x | v1.x | v2.x | - -## Changelogs - -We have made numerous breaking changes to the APISIX Helm chart between v1.x and v2.x. If you wish to continue using or updating the v1.x, please utilize the `apisix/1.x` branch available in the repository. diff --git a/apisix-0.13.2.tgz b/apisix-0.13.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..c398491d87e53a4a69ba73e00093d67bcfdd98cf GIT binary patch literal 83738 zcmaG{b8IIt-`{q#ZQJ&Cv+dn%+q~JfZU2VbcC&5UwvFF&Pu{%$K24LRNz=3`zU>D@ z(a`81|4l#|5IQ3%6=oADc}_Vm9u8wR4Q5kS4l8X{9!^CK4NiGYTWceGQ!h1Tho4er zwss(wUp^k2ob$wpGdo{2j?^>j;}Mt9j2hkw+j`;}l->ucT}e5YHB^!k$*1-)tKd)| zI_K2eGv9pFy3qRXq&iOb{F1qBCW+v%p^#r_u1;}s1R1V3#4L@fF? z`m-Y~rO+5+%0gkh3Zp#P7$QS0Y?>oRK5&piP7uP%PxWpFMWWzLSz+qSBgRJK!gA?u z!oeiYUdB4$f;(ip&EfBXti9?UU;K4ifJU05LLWxmXUu7yL06!^aqad4v=y&dSdqRFkemQKWt+d=G`Cylr?N{I}vf zPf(U+KR54~6F=FhsjHvYxBsj$@|K%rjm)|PGkOGezPl=?SfL)Gi;a??vhj2C<37hDB0k^!_3(6+^L{mRm=#>T`Tdhe%F!Q~5kn;j75-{CPt{dC z=9f=?@O4<=!F)~R|I_Qu4T-R-;dGn&byaJr~8Yq7PQuy)Z5bd52N5Q&1O*Xp+LTmpU)62|G(bw3~fG{z1vHbb~36Fh?6c z!9`Fg%b;SPZ1e>};HIpk6K}KS2i6c?!km_b`mbGM0|q=UXc zAKrgD1Db;U1bW`TuR7=+AI64;#(lV?fXLggON;9yvJOB*Yc%;uxO&iUdvv#PuP z3KQ{n-N`tY`#5110|tc6(qZl($Jx@9$OgusLDSWs9OEvsVRD(@YD0rkujF8~~?QK*A*EUJzfbN6z{5CdiRnrRFRsYW`Sd;J2vT0%xEB$pUtS~v1jARWr8t4 zjxz_RB6R(Fj@n9)Th#WVg2rtCpNbrWN#mxqEE>IOmO{*4Xo|}7 zL7k9GE9pXy9iRTz-nC&F$RS^Wi9KRs(w@XkOO8P!N#FX@OOimD(^Mig7H4{QcUNbv zR4dm2B|k_L>oEI)vsZ$#P0Lovr?B>yZ$t#uUainx_3@^YuoK?k=EZ%fL<;5@2U+Mr zZzzv>o~5Gn?6bo0$9*U>fn>m93r0a{R>lFpO^~ zLrm>nDV>9fZDsA2;Qfm7{him4P15W9poElU#VmHHkVLP{QRjlcvrE%9-H;;;z)?V# zJ%Jf#NtZ=$5?hgj`$1onX=?6` zlb~IIe41&rBQ;vOzy25ouUxPZ39hd{BbCJ(8!ciqXh~VUIz*p6dxn1^HC-N*XxFy`QF|l?!XYlW!eVS*hi25%0J>&_kB#h)aftb!cKXgmQbUO z_194LB_WGAQIuHCtP2r0rMs9WFw=B)e8Cv@Tu7uFLx_2QRy&QcAMQGkY3e%(YE zlN1Y5@(@{Qxu~yeB_%U_S!*MAfko!nKpUHMnhIMLZ1M#iuSHUeKi^CcU$_wCbc-{L z;CmzJUbD?i-zFkYqGa$h8fW|s(p9{qCOoM+?wG!`0kSwx@|IidB$-PtjvIwM`JzyY zp95l>5&EQ;Y4Om*VD2ggCJ2?aPn*j2R2G-BMNrOq3G>z?|8K9v&o8>C*Nh9J9T0K9j-7#hi18Uul|K2fZtBh!#c0f|xdyZxL}5^no9>WNfn{yG$xEH-d{^RXmGm8)m5M zy-Lkw@!Q!+xC zl_nwBcetNNOknLJGZwZmhQ7<#bOEs|GS@&)YjKJxy4cHM$9aWIeb<$ zY0?}eE~iCu>7C1ho4y?=f=pOQN1X>-8a1K|qf>Y&j(OqVhHiaDQyXFmH?9S#Kv!#6 zqBg!*s}wy=h$_ynO8qItR%I?$!X89Hr_?{oFiqQaSA~&z-N0U^p4F(6r4^Y@YiEbF zceoQ8faGtz6`pPy&XC3B z#a!W-`06A0fT;4KhVVUnQPl(}f#kcz=~v9Yj2MX5-Dm(le z=ROOzUVO=;1pDuz`w!W^g>B(yMF!tqY&TUrMN0N!=e3}KXKU94I+G_VyVE(IH+2@W zV!OWkNC~X4|x(tBbttG1hZYxJp>TCUJN6uWMDhk?3dFK9H1*!<} z@GQvl!$p@pMa4h8IsGC%?>+7E7wVHS28!6-yN;=H!kTnpu$4l+;7}6jjo9T%sFg+Q z8z9!F3>*{M#Sgj#De@5PrdK)&0@ z3|7K6qS1NmQNHQ*d1S^J1*Yk`x}BU)PmMQN$bBRWpxSdtJeB8_ntJsX7(+_ztmhg^ z2$Q9p!ag>;MCqYR5Cx4mgFUtO^yBp{OI)@auPXf*gFbJ%ksD41WuoqJRx~YQlw%FI z(%H|&j%#c2c~J65gavtT^_|Nv@KEx7P}F zwpiUt^E%T~6)5l=K_pX8%%W3tTY@%kIo7WMC1o2nVaW~%hMs!S{h&k{WqRzCsFF+9 zyE@9^jEja%u9rqm0#%MZ&&uwUWw=)2{3c>6pB4&|98Ze{NOMjz-U;mf^A0`N1TTcM z72sbIWyYlwb@Ru4eSS8@&s}-p-m<-`v6**hR;_KdFvD#L$ymuC-yvJ=CaibMq`~s{MYNX$k>q;^zu%HQdQnQI<$7t56sf6>Z(1)M8(Iy;rh= z5$&qt4s)b2o7B!!XgZd}Xu#*J!;sHLF|mtw&!3Kph!7IKJp?^_bC8qJ_~U0Uek>hs zp?3Y{C2-s6!ll_ijiXDk>AN=kg}D-?54C1|LGW)18f|%d zCdslFv`cPwSrNu&Zb(lOV^Kw{7$k8<&`Zo(O!d^cB_#ao+>y|SJ|iz^X>s1ouk>0< zmf+iXg5x4g^SLr)d@Te@1){~58DYHKnF}@DbZ$lZwDX+L5pp~g>L|hr%h-(G0zr+H zBf>M1q9Mgj=#tV08x-{?a5?gki`^tn*$HTv z+M+;;!ed#+T4uUdGSIgr-(LgMIO*nhe=3Sri&g91bbzZ5j+XbfNX7lazm@ET5~!U6 zJl>!8RWj*#Ccs(nEWyCA+A8AIwYZMSNis{Y%_Cp_%%7bmu=zWsCE;S12qK_JC;5Fo zm9+ZT_xN+4-4Myg8SEdv8v3$x$HY^8P1(^?w^4LXqd=@v~=d)o}StE%#{gyAs_$xU=Z0%XHhn`eZq{ ziv2tsXU{;$l!#K*#a|(Qxj3wb1lh5i65zjpy*#Cu;Y1=-!@PGD2fjEBW{Sw*T>nj| zadnH|&gHHifoC1Vl+aolEkNc45=zz1MDGa4bu#8 z-CD;$#EL%k@sE3AYP+E6(~y;B41BjG=yq^SLDk77cnb&z;|g|>xHetMv}m{YXk93ZYwLQ;m^$H>b+wH~hkmdsB%AMbP&QqU zq>gf`(<(+ad@zmJhSDn~ccW=yBz3{WU3hWci`?iWBV> z3s&`5{;0oXbJLh>MKQAc5m=_jkO}^4&i;UaU+|JsbjLt1mOi9HwUXNwrr*)ej(jy| z)e>IS|H|_;0gh*3BPXe(vi?DbZ@vPY%wMEw5NxrVx`{_dDJoQK2KbFX$J)zOT!k_bbHs?vuaLeBvw-=gLFdPmGjEZwo4H&^(cVEk-fL<s?6VecHKaNs9MSS_4;6n|fm zu1p+7CSz{-FC7FddU-3(-%w^Xl&Zrie!uGfWF#Z`c&mT!+R{Iw`6BDs_sI<3rMPmi z&uzIa2bgCnL-7YdQqs?{-ogmLKtGZ{=rS58UtNEz5`PpEwx(itM6!!*iQF=Vgu8Wt zx$`X!Z*cIIrcA3|OrkL4R%5Q##mj7{n-`oO)1&A?kh&5Ur|Jm+{-|BB_hvBFiV8i+ zLunK^k))Zpb6rXXn|L~eOe1&sGn&u5%sw#tb%zI$CbNrYO5t?SI3F5{&*%^SD!K*> z{&kimG^Y(EZ&ah#r`KB9f)^={kMp3Wv*Rxb^WzD7%NY7%iFC8&#e-Z$#F<^`h_xt0 zQ$&0cGlZ!%o@|Od^IRU&0>DR2C*B*1;KI>CE#kz9_6U(pHy!`nQNY{70_I0`#unC_zmw(GYRRttv3kt0DMhS>dpClWxh90Rvb;Nbs(VPPJ!l~??B zyEg#!kp8W2e-z{~`!i5;GKbaE-2l4OcxG&5ujvCH&S}E){?7kr#|ks?H~`R{d6MI_ z2E_K|trtdE?fsGF!dmDdQ@sGuepC*Vcz3B?%hBC?hJ5w1S*{~e&IaSNbe&t`(jO&L z9xHrB8gc0(jQ&yArB-AcfjE&K_xBh_jVf!7Mg?Z!vJfPX|U40fU|NkOnR#n~%zmh|zH5D{SZS|CNopU9b2azGhA+%)UNbfM!S z!^zpsc*4Rt?>fP@;R1k;UPQG0+sFOx`11Vn{{8-Pzx-jL>EdQbU*C?N-P^}Wor+~? z0ed6v<6%G87>2T6*6BwC_6IUg9yZV1v6Ym$fPX|vl$9=kCL0XBpXcCK?Wlkzo72_} zKzlHLy6NJ{(^Em~33jC4WHm*juc3)41BDZy#C%F=I)}k(6bi3xeYz#lGwpF}9+4+_ zU^-3SHZ0w*9C1l@Io0D|#=XH&;n!1OVOZZq?8O@=_+0&=_ zGf^J2@UJ_9!at?f9F6{PX@TC>5>$CcaVFA#g~SHAS9E-iXswf; z`yVS2iTC&|(-g;oO7ufl&b=anbS9e$7Nq|y^bvZqF4v!2w$3m?&4K7YUS@v_AAZer z62Lzfi$3KuVD$MPpK%8Pd6Aby&~7h-1O6Bz6S(tYY>YENm_eoDU9L}_El%ZPgu2~w zis=RaT{T z51n_?I+cu&)X`JGE8x}W8AnVQwai1qaiaw=J#CN}N;HwY*P0lUGg2JS`v|D=ioT^X zb(W)br9;e^|Iqmf!s;**<#k4UV1`j%p&D(Y1>n>+&}_q)Z6*;DY>bf^Zf&`#TGGIE zorZrxgjBEY7gmO@B^x8e?HHZ@DP}eVKWO$REX;Cx_HQuMbu>{-o>zE46@tS;Mr3_c zpJr~9D8jDJ6{?X{i~Wh1GcFu()o9WQQIc6k?~nhfg7-UAkgb_9dT88}X&VWB_;iY! zp%6+Ps7e#+H!co`R&ZNO>UbzjN5>JdmKZZt#O9G4axz0X?)Zb-j>x-#<7}D4!Dxt! zzDBt2$mN*>f$8_H3HL^zmolnb#8N<%H+QJMq}Z^ue1AIBdH2T-V4Iktda}>>>Dt${ z66TF@5r{D1goRp8GAhDO|$CCQBtVGL_+qVjCNkB;V)MO?w=uK&zD~#Gz9E z0^-rCUNnB$X7}!uD3e9^TinA+F%ZA~X$>1E~Mm02)l8Ul&?U&EvZo$)YYD08Ol9+K28k7Y-{?x7_n zsLuxUtQiBUrSgl_*~Sk=1NDnDWdS9W_9PZrDV&@OZ0(wScMZhRdNWS z)#jUq{c3cpdLh~&6*hrvxeXvSP6dh54@G_uIlPtjo?dlunaEMHT7yb)3aBIKokK_xnB0X)-QV$UadWUfEId*sg&~*X zzzh*r2T(R2=o?fq5jEh(8-G%Jxx2kr4NBGe7l<8svhPCLt5vV521dytw=z(&S`Q4x z_Rc=YNlJitt6k;|vEy(H2R^?bPmt@nSF%aYBxU%wkwA};^5udtZTDR3H zH=?U!zAqY|b?H^=>17VED>$a!>-?A#M%(qIX^b&f9Rd8rfaLUG0EDQ=9AqMFM)>-z z+`KV#Y>G=Y;w4#?StVkjHfHyR8OE?(u{A8S;luR8$kY$EXNlshtM2;3H{Yvl6cM6T zim!&;VLx9!MV6%ut97X71iao`C4X;x#;ntf@hdiv7kwOGEv=c6-y9w^H;@1~{D8al zX~44r;5`j+0qgBw075EO@UkGC?TB8H0W#}~|Hfp@kbviVc_}~<7d+b};k@32WY(cL zJCLLvbK;~p#c^!hHf^X1R??yiQZoC}phaxe(EsiI;xlvYYDT;PG_s8AZw!#nmd5+3H8y?IGqPV84Tg2sHU{!v?HKV_YZh|_2 zE*~jo^lQBZHWDsZi^Kb1+wU_%1Tv3d>B1rCLuzbGN*LqDr$;PPc;7@R4_^tKrTehg z6RL&>Pe@WU_|zU@;6WKdkl^N%=9h}}aX`WIx448Zil+sk0Azp=zsWMSr}-?lfD5{g zurIK4vK>?in&z29?8FfoLE2XoSpv;D`k0;Wa|(^9gcaP4znTyAf@;YTD%qiL3kkOJ z*_l?aN0)qth=0`>rTEtUgTz-KvCyrKO9I8ve&Kbwwut%9J}AV?OW#+QRyLDmS^}S` zZKoMR z91w@Vk%v@H^RasM8w`X2n1j{~s?$sgN)cFs9+R6SgU{oYj*LdOqOLLNtRaDG82H!g$G^mzs_w#(2V>jE4TH z9^#K7jF4vU`mwh3ZDBU;6# z3hr{-3IegxH-LqlJ)>pLWv4+>A!q|{L7ppVT(%&MxbY~xkSoQt`bsb79=`%L&M6p(kyk@NK{&f%iscjb2u(**0`9c?ks@_^~oFq&KiMPl!N8gI2NL@16J+$ zWk%-((-KFj1t9>#<|D`yW-kisVvFMH)V1_Vm;U+*nC+L zh<^I2FskGjDG%8@2CQ*z7`@O;%G)1j>MZ$?VMNa0LesZ4p}>S3^92y`cDChToDgPt z>r9DOI9`tQu@~z48N59tW8eSSe0!fO+CWkHJqgX>UkS=yb+%h6jT=LG>6M!tM7$4( zq{(5&o>$0Ez2N6wd{BA0TEV(&kT3EQxf{-I;;ZN3_ul?r>+Kbqns==?I+Ud=U*iom z7y_IwoFfm7>NaZ!9Tcvr6hXyuVagjG=7sP^#MKa21;sl`5=|kds0b~nx!IH=+ng}R zA&Rm?{dDt(#Icd+g*%2wB8tl49;<`mPHwBHt(5myF(PH^U0P}KPYP>QOTVr!&SIaI zd2}~Es}V`T<)bx9Aq8rc6$I3Q4(t9rvV?Qb9}^NE0DsTFf)yV?sIT&mp6*eA9Yo{d zxE$2a(AspXUvOP>G-l@H-6%twIe#jtS(t{Q&Q zZ9WJED!CubUdjoT5uXf%Y=9NLV}P`;wOqi^F0R7LcwIJcl2kqc?q?T&=wPgJy3K9) zS3Wl4=W5SuZWuF2R}U~-Crd&xNC9jc^KLb;9L9n-+J7I4Pq)=?C#B`B9WPd>M=UNZ zx5GY7Yc4h{e-mlyJW$p~A0hB}4HAPG6tRN-(MEWAaTDEPYt+7wcv4fn>*Wk+4HAZ@W^s7&Tv-+Y~HeTmH~x zfoj1sSY^fM95rI?Tr*(UbXgjfjpnuW=OkN2*2|5n%#1 zfQGsrLmOA^8-$My)xg4a^RHykw(N`shvh&Cb5j5-;9Z7B7C!_jtEet$21&rkS%FVlEbeVqv1v z*bY->)i<^jgT`WF#VRIwjW<Soo^LfpwaR zq<>Y>Va}1oc0^g8T0b)AEomMmGTrIijs4_MrE$|CWixTrpHUS>O}|R{CeCUZqiOhq z*}fCjwLRb~590(*kYiB$?N<>Fxeusz&(gf7z#l4+k}dV5mL&K;?cQ#hp;8;XuR@;L zu9c~biO+sj`$iZ|_wy<@17+r#?F-}cNFG%j=jURw#KT_fGMV|=x%3}743fB{hH9-9i^u?F{ zo)3L20Nw-!wY*EsoHYl;Z2c6A8c&YugT{fcFpFPT7#)J8&f;p<6~!N~jJ26dO%>Y^E+7{e*(OM>9!oDm$KM1|JEE-P#|oMU+q~B znvXDTEvouKaSWPAGb%qdNdlD6aeJ*9m)qYPjC_|Xk#r7Pua%Z*KWSk{yvbKC21sO9 z?cAfioLPC9ltYtpX(M~sfpdI58(+8|Jrb}kX{gLbM1`>kcRj)SHwA>ikNeYI zE8vUlXWli?za0oX`v%^B1GCtlSSLxK`%12RxqMY{$qp!&lw4hEf>k~Uemm5#gfsn; zp%q5osCwv>lJ=?u({-l}JN<14k8^`N{1W)noN00dV$bB2nSymyR9FV$6E1u;$RIE7 zg#YWiQTRLFs?77!q8c>&5NO!r_x*A7y?gfgg7x-u3`q3`BnSHYzX5BHOY=)0Bf#n+ znX>{Q_2lI?v@XbX(SkI`s#?c&HkA8&JyWxyrbIiFHKMgdyQqc^qrbE6dr;FpsO@Uf zfgh4x=?EXd0xr)apuzqNIWYeanEYu#1GM9|Kf8NT4^WxaG5Deyd$|g!4?PdXLYQ+P zfp+rI>Lsf&ML2cRU}Ie&_5F^LxMmC)`L%?*UR+~)Xz%Cwdj2eV9ay~yc*m~R6Mg^0 z0POLvSFP+4njG0k;c56wFS*$YQ6ZK0B#AM7q+QLd-xcF#cv66Pe2*eAcuPxvFYg01JXxqI@jvUHdIqSWZ$42_3{tg*h=FuS|(p`pIG%jPcP zh9G^6&bCwJ-=D89@;;+xbLNK=Cxf>%^iLWuPcaS4#C5db>ek>|hIkF=@+tU7SXC(5 zCwIS3KT~ib*Kdgl?K+aN;#_?p7^5eI7E4E0%My!fb~osah3(=Fjk^t~xYmf(^|A z$@$A5tdQn*muv$l6xP$MG{#g23TRYAJ`8?VzP3ERrA)=&xx>F25;ACV6lj^Wt>x)yDryal`j-%$xL4EKljol2aDsA7ZZZ*f^Cef~ zuG6}IXNXP~fAELXS=K>(rNYk{IdlhsoOkr&*U8DtF>qkzXAdeTk&tALz0@WKxM=CC z3K4E80g0-u?6Oscxc(H>OnU#IJguiY@oMEI4#bn=*#OI`gIXbvB!PV&5S|UI>k{*< zbWpR-B<8DS6Wi8!{q-CF(*dKOL!jogzSAtwprw>AS7vd?O^#LiZyb89E7~>g9F}i| zqWZj5G05U;?ePWT{4~g4qy|tCI1z3f@S{KCAB7#J5aD?m)7q7&L~_*$@mp1^47IpE z&0fVh?;tDVfkG?NdvvW6pobW+)D`S9XT=?$sh(T`XcBi+L zk}4fvYCmVz)aE>9>3rx2HxWQuxhu|mS$V@hu$-z&>2-Zex6{^_H66C~bANM)?JS(h zU9fzoCc30q-id_DcMS=7C;h@reQLA(@c~=+Yj$nCvSRB>oFcQBr!SM4YliM?rQflC zs*klBJ*3I(DhXpFZ+XXlbiSv0OGz~nzmeFN#^PB`1S1<($2EOQ)J`xD@A{{Mc4ZE= zY~KE2XJwxAKD`~j^Nui_j6DV!*p%{KxxQ^^YTX<2AJ<&Y&POc1Xl^?4Jqn1x!aoGi zNvu5qjl0~d!uV8=3eF;~B6U3E$B>pXLRdN7*e1fr6XQu8I*s$Fk1;T7utcb1z^jHV z8tyI)-kauyh;?4mMdNbz)Ds*rUa=WjN7CY%jjTW&HETzvot)OET^Fy7XhCY501wD* z&Hd~~8>oM8yY?IX*gxG@mSej`@0dtwR?r%X5A@$uN|qCOA5;SezNOj-Ukzbl`)hdx+4EIe{ z&R|1roem5arY-HE3>)3n25x>Lo{6x5ud*>6VVS zLW21{tT-Z6X>a+_J=-siTWM2YGm2MfFau;I$mUi2&LW%NH+3E?JMOYHrFvN12E!h? zOGk9aed|%deC-CrBNn|L2FK4uN|tk}vZi$rD9YYq9L>;jbGzTa>G}D7yLqAJ<>);_ zjqC|3_`@^x2;$%qB0Q}`bL{9&_3b5owfp-j)vmqEulx&xhmRl0!c6#GzrSX_{cdKf z*FIZtvzKaX!sm3(9^meH=o_` zc`uXo0Y;fx%CJr@?W|vGU|b%9oWvNEJE}H^>yDR^HhQS|y#C!^4{azz)ip)HO0;an zK3*gAWlK2UU{qJaRn#*-bT{YcXJ3hW*k8}RQr(1N#M_0a1ZB;xFZQ5HH3=jn#BcEe zuyGcK;dLy|25a4B2BY zp*fE^2PKz(3KJ(8tP(YaIR2UMxQ;^>8e*$-cLS3OED>=JJ}WOEm978@xqd&nMq0rX zj3PHG`(0iCd@A5czz{7wcbp=bS8!#q#j-Wh)$A`JyC_tb$>V;%Z(ETIYNN=t^)Pt4 zHmcTb4ZOvC{rPK*R-czkdyv6l0dUa8iGbEPpE&-7r$XjOcXYSL5``(TWZ3|Mj@NMuuxb5qUfLbw?Vt?{6si!^`!>C`U<^t-K3(|d7#Ltl0l#lCWJBsRgt{W zb>bBTYKRlmN=S_mRgU{@dptn8Cvf8J**w_2O%G4R9P=b5N^(5TZwDWwnHa+V0wwyV7Wq&?l6q6rAX-TIubo(%-sU_ z{!7xOK4oibD=&bZKQc4>)XVtSZo)kLd)CYF(40&ctKHNdp$_FcvrCGqVoz&m#IP|A zKDB0RYQq==>TCO<<*engV8z%O0r|(=gRzFNw%KC;`VC28@^p(!wzK(CoY?t%s8W`p zjQ|5Rpqr~Jlm~M^?aowBUdP;S_Y^WkCl|o_rBfn`T;2ql?n>vrASa@vCI zM?9fH4A*~V+D6Hi$yh&3TZf5-Q~TP+s@-h4A=CO^jmxy|>HB|7?!}@zk+v=Zo$-jZh{MiCGo20#z%Xua-SARI z3~o_#z|^jLU6;RJpLFv`Q z+s>n^=!+8q&}ShqxyOZYouKIeQ>~Y4!DVHj*6XPmc~zwE2BT|2^H#t1m=^A!fpo}# zS#AFJ-BhxUbxg@;U63dx*MtEdfKWKn;c|KQa`MJ84W!DL)S`^|R5=0q1P2eK$36hR z%0K-L4qsfqfoGqu+?ZL&$+xGhFD$1z{-zh2g|gAU5xr^S<-)G17_ zE74~^0@9DfTfANDK)&_#^cc(lJ(y3Q@(zLNumAsP!g~YKN@CkcgRG49m#s2QxMBsf zB(7G0?64{Ln`I83MNm+cVek2y{{|uHy@P$ANxV+0>3#_EM>jQ<=oZlSE4KZ%!>Oi71@3~yy zX=N5T8M!vH2+DQpA0Gbo{)H6&wY~6#^l#}(fIrXt72kKL&itQe%a1Y?px|S%y~|Q? zBU8E>eAeA zfgfc=Pw@l#0Y$1g2Q2cHC1PTN=qARPB9BP4Q~8`jVJA4=ECc&cjk;?B)2!w&g#XBi zel}8=&17X^mRljg4h?i)(!7q0O}aRP^wevduM=Vaq2o9B=DWDbD@=d2Msf?rvM)0l3@IQ2OguvDx7a zWivXGxG+DS7e(yk+h=Wkip>oGw5mQ$R_hVMo4+K_K9MyAZDF$FT?c>v#AddhfS-$? ztTPzW6=)qEQzzV9^4xeV4Kh6y-x2Ax`>}MMd4xZqb%bdS`1u+}8-998Fg5i^XP=>Q zpKPI1>r7N+eE|#K_~4ZnR9C8aja~SQhJW}DVJzwWXjYF1bZZ@Me=Rx2lC@T@`Q}GR@zwu{Ox;%lN;~ZATOq;9_a7rxmf)H{9wwz z?D@CJ8-aP3Jyahz3!gxHmlq6-&H(zo9n7(m(bNr49$BkS*Y#$NN=bPT|6{#?XICgY zwTy*J(?BcOrfJ@%t?U-5K)V7pr1jZp$mM~|T71XF9ZAJ@;F`+Fd6RyW0{jNXo!j>mfU5+;B|96IYOQ1L!*iP z^Xnwl!;8JYZ8;m?1~9L05~OBv3rSWoKibkFWm8%!m(+r@XBMLE>==k{|zYquZn8uYbNX#b@BZ(i8~z1KdcC zS^feE)10@(9g0CKV;}Zvy(VB5TF(Wi!wng1>S@E%)vvjuxNI2)sfDc8gQd8XM8Xo8 zk}Kn2cUAAPWq_0PdBeD>VNJFXTF%2?1%v7N<{W{=uVuJ>aKSD}t$vLo1$| z-QE-y{E7Wt?^63mL^yr^;Z6R7#i2ht*;$SP+wj;yYlHCj3#8=JCm=Yz>pS@qh}v_y zbo5lZNcx#FbwV#Hn5$nD;yf2wrslo}e40EJJ23FV`rhfzkncDLUKal{-9nwk9^n$N zyOF>4#faSKd{Ac}=E?<-@@V?ADU{~|z6~s(zCw7+LWNEM(_&QPJRkoIL{vpEeR_I1 zP5vH5p%Gdl?TYk=bAIMu206K%?|1ZBR6UY-7c0O%VZh2SU{~MV!u!8rVn)lJqwk7rC>%W^lbd)cZ8c0crv_HK9&;YP0UpIuCApo|Jo*Q&0e_5J>@h( z$VUj}46~8D!9!*pz$^AC2%!a;^+gI5MOZ+?Md%BeLE&hp((!D{wF2uITU_x10 zpCgQ-iHD<|%Ruw};pRwUL7vPGIc0{_&@k`v$n$YTXd6UJMtSabKr~#t0A?L{WJ85L0a{RsZS)VRZMDSg(a~y#PpfFJz};kgwlx?8+Tx6 zGO{Xa?jzg8NL9@8A*z&SucuRKIRM+eLzUKI2-`Pyo%R&hA*K>NEw#Nvx!k3cKGid< zP0VDtBmw^fY>%D8LvF?;jm8AQEQEZWeOFwAEJWq83nob6DK@GCS!T}<_*43XB21<_ zVo;8wyD3;ACqSB%da?%K%N*^uDEO*#LRSJ(F!a4sFziK1uCSnRBBMof+d7QF3tCm} z&2EAO%l6J}5SE2V6qY+3jzlzAQ+z9wa|my*&iO*AO%9rY_(TeqMC0v^;Yzw2=V#*N z>F@OXetCF*`93ukZ_$Gt5cWZiCt+tXhanpJ`;wBJB8j+$ z#-v00isHWAYJ5dWHx^w@Bl$;JuWl`*!m+LJc;#MfGM8*UGJV<>F*X;(4r6h-u=C~S-SwB=A%JV8^&@~=Sps8d_ubs26qhFA z1=JTQ4D^4B#toT%DLKn}GQIz3%&>t2Z>S;0=iY#~%nAyPI<5GU=Q!8-9T zEDM^oBBw2Y^#xwX-#WJ+j`9!gXcasy7PmuWd75Kzk`Koull)H#ky{&?Nl`emk7l3s zdGH=xr7{K7D20^9`r~LP5P>kK9MGy4Tw-jNrx)K&iX5fc0S-xl8LA)}b44M?Bk~*p zxUC~p0jb^%J|-4}V{g!q(km>nWO~}_%XtXmfidG|ZtA{^)Y69nTuyW8Ij{BF4kG}h zMQJYz;K%yVSFK9s5&41Gs2LZ7BXsL?xJw#3%~~S8fWWqRkd$;&<*I58Rk!esMMyFO zdFTEk3G>D^x7oopK3x@#vN^2V)KZv~AnA zZQHhOW7@WD+qQe!n6`EAe%`mf{q0?qO66~oN-84wwXHA6cgJ|Pr+F%TL@HKh`$wzR(`a8M70MF;`fZ zfZ=UKp@~^mb5j>C{UWBdRsW0grm@OZ&pHSV0cRfPOxqD+vK^xad$FwsDbhLd(xY!x z&a$O$E7Z%~WbR=#K)~^IG<2q^|`g6WCrn?1iu9Y>dfc_SD?%MUqvlK`BR|2<%OTX z?Xqxmpw5t)vdW8TYqUXkesxVvbZE7hsiq0%&A;bJsh3UMjrBG|@;Idb|FR_eOp!D) zM)u?}M-Kv+Auzr%NE6Y93@)pP#k+bb&WzIKIEl`xYnqz~K3A!f)((3}UU z2wr-tZgQj-h8wB2!ZLUe6$=1_!#h+Gs^ce4V{*9>)NKWF`;?v+BS>#%^;;Y`fbJ~WezZvC6mm#$g^`)XlxhOC>?Ya^eQI>cnl=5^&aH~B zW^5sLt*}!|{Fe5n&yoT*=#;VR;=h;^Phn1ltMg%wi(p<4o~fk!gCzQHh{z5`=aY4{ z1@0WVn>D%`t0jrE)+b175DQQ#SKqn(+NzXQl|Phn6_r}N}F%*0Irk&I8Pth%vRK0$^n1D0s2}G8XHQ271`4@F{Vq=jAbmZ!+yxgZV zP%`8wLTqNHHWM2GTh)j)g@wvzE%`89W|~A2ODdX=rS9kp+Ji`BJn-S%r)Vl$4T;Ck zn>n<@Cc<3X95&XhlcO6xzsjP~V&$7vVhms|+WT<V&#rK4icoHx%BRMY>dE-`uqAaS(6Rq`dHj&t>h82D!v6JbgB zDVN{bs|moIe?*ruBW?Qv9Lf0@Nz3@vagwhWwoE$0835!yDL5Bf1>MkwSkH$3L&o3swRboLcEZVc=W zp6ujapd(C??VvMo*FlVZ>Eg}|PKY?OL=*gc1i!b zs3le10PA8_2d@amvwJ_Fy0ZFfM%1`P947mNO#aP79OtW3Jzk>e!50EApVd?{m8+lQ zi|hi_RJZC>vHvIMzE=qi@#IGIYOi`Xq;+=)`CWysE`>wQ19Dh@?-{6^c{Zc);M=F7 z91)Y;iAaIU-huFnId-9soBnq>=s(A!eL)!-xB(<;VoF88aq!rkg)~k3dLRpbyz#xU z);58gYWcA%qzAQV*F*)-K#(n$HlT1HuUfnT+TP(H|bChxWC;0 z(?f7-B6O2NX1x9A9cXU@HuTlgKdrkGnoX%Ht*W-OxC|He!K<+(&`=p=>T9|8b)#;N zD2MDVCfLJ`uep~`)>7bET&_d>nU}U-x#d!L*DAB}Z<~r5{55=6MXd){IpcscG*AH1 ztGEr1DkomW{a;5UI{H`G%HYGihow6Uk&CCaDXgDJEMn*D^HH;2K?$$)H2TC4ma@^D zk9u_tr_t|--@&Rt%j^k;)Ib8OnD)b)*`*9aF8zsA&_2H>FBG^kSN2uIokW9oL)J@Y zup2)=-PR-wm~Eci&PCwxEQ3|8ZAwlIc+e^n7^g&=yk%dBif9FDy5xa-ynHR&76y=9 zb4lGwJ75-{^N%)G&Z*sZ(cA=qJEHQw-NcxDMW&(ks1y>RtSeO;mS7r9lfPS=m1MBS ztZ{zv85U>?nj{j#@DcpSXEB1uQUL&?JA;q|K#MK(96uAxX=US6bAeMxJENq zypUO;k!D@swX4nSXq!sxLihFt(OQ0k%WRCQ31;wOsI${6Nj{`#==GHK2TWL;M8elB zGK3Z`;!V23Mg>7r#d7v_hfA=;W*6;NkOdU7Cusdzffcf!Ykwq8brL1eo)WT@c>l`1 z$!p4MDTDr7WRyngMH}+!#c>~r85iR_mpkRQq1;5ZH=|p`c8|4qff4)rxkBN&43{r%_m3=>Q{Z)-Tk0N z60h1+jc+VA!=lmE0Zz7>;FrD@v>G$q8|d%rHX^QdSh|X4#V}#|FLB;* zz8ldSuwi3bH8q=ks|n78Zc!witaYB=pao|9DIaBE0KB&i!A4ZN2G~6>p4G{w+r(AibKfQlk*+N}_09 z8Wg3P1)k6q@yXd0x>vV)YA&&ms#~-EDA&E4$Ahin=KP!MT3y126}E7qGlnt`WEy0y8W3X-xw_0`jZYzHMkJf_Ck7Y-eYiKUrmvZL<^6ybW5Utz?j>CCG@ z+0MW#gW!==>$C-xWW8%tU=!J9UDBl$;@Rl$1dT-4NydM|a*{yGuI>6W;P z61m5Ybk zen0gsDR=!k#v*qnn`lvL{m+1ceflt$GVcMO1;BWfa=?ou7y5r)>Q@rkXjkG0i%i7hRxxaVcn=d;ZK%cEI#*_>wxXAF@{ z8kNL&aEsPbv9-$lJdzzsEhOj=*?lxsv+YzXxc(ZM=rpD-TRy~E_e3VuDnqXI*}9Ry z5^b3FM6<@OQrfi{!XViX9QgGavj1#H(o?B;_f+a`1e#XPUmcp`plmj&)^XYI#$vvz zDE~61IZ)V&)qzmcI}`?T-(#rXUH^&q1wO7vtvSP~(FjI1BZkeQWLq{kg;ogb_UL8j zCwb}FOjJ2;Tj|9{HfsqP?lzDz9Gd<0dpE%}o5=^|3e1?s0w-uoi+9`ueKP=~1}M@< z&SN~12t5X&`{aT;(wt@;2B=M8O!nd?s@HI`RN2CL@_{1-$2`GI;9Si4DpQ4pGJ3Il zRVmP#{@a(@b_JWKW59F=yRli{AU&00qC1=@`8qNg0O~C`ii~V!hIR!;LyjdYbhzl) z9MyoS3|1ynRf>O|W>^hA$2(J@rFNZ|tSv_h?CvSl5oU>LU85ZKmr%AFV%@91HsmB9 zPX&0lSp{k)8wyJziBwumy_fb6)WRwH$fZmC`#$4F2$nvI7Wxc9xQ|t*Njlqyt4(;qSjIF)5 zU^+8~d**ms?a=U6onp;TF`3ssxnr$fpzoTU7CtMG9uxdam=#-=i70@9+{!5Ssx^0+Y0&9=}`C&M~Ka9$hs_40ekeye}FU1 z)wS|m5IfDX#*7ui*AuB*$bSUSFc#im3j zci4Cn(Ub*SEKj~|7e3Hx^&cz9y>yA5FD65t)eU_DD*h5i(!ubpb%gUFKSG)#TOQAU-_9qg}2G^;BdasSsUgwepcx5@uSG^=~I6pWy16O&As=d zPxj3p0^;do@8u=$-rqN4Px-s9>{DO)KTGV@V2Xrfh^Axs=xHJ?<4#x^V5IB-}99O&^KI{H0Co;xfBMAbVPpc zn#2UyMa;3FEB@p8U~opw?a0NVHX>bABBM1|D&xZGNEXctoGr`kEMv>DRBw!OFY*6v z$&)+27H3!FeoxZ4d3827{8)(A6YC+zTm0Ut|L#FG%G(`%f7-)`)myy*cz8P8rT{*E zFv&H*qZ4p={*B-c2rtZ)<+YaU>}RRI6XhK#pMSpPm-q9*y_l$wC^!)Ub@+=q6p4i$ zRnP|MOylyIX~KoGquX1IYJwVe7CU=0MpiXkC5OCuC(jP2*tZmDP+$l_2-H;R#H+3e z;fWv>@!o1eY19^UL8^X9pmJh~O~lWR-T&TQZ3bk-O9#CU!WooineZ3>SKza;o;q6Xq|G)<;RPHn zS*^Fs;O5Tl$1sfuCfK71b}uOFc0o7~)S|p2?xtKFlh#bGQV;XOtRCUn<-Yl<$}9G>vqW@B|J33AHREchKD5GKgG*YJfS9aR6gO+JT6>dN!xXQH_zW zh=UBEV-*70aAn+gU0G$chX-XgnuRX3NX$58w=w&@8^V>`s^qC=&s<8){DnqGTo6!S zd0nDCTf+&Soe_>Xitg|-4I-7fk;$lwlsT>8j-tPMmgBv1;vD6@83K(3&m29Gx9wsmOykH^ zp|f_L3;0N^4m|X(eh9>O7B_{JKx)USPC~WO3fhFZKub1}m8z7=U1daTSqjjV!q{gk zdP)VPBkW9N?qw+o8-%x_yw6aujS({ia9J(vIV`u`nGa&P{V`4+L#IpeHQqNPSi=$T)OMIh)x77<93 zD(ifnB#gS%sH_q$I+eWo1)mxDLa6zz+*QEKqe>xMp4ulD!7R-Q=KhACAoT?pO)|qN zXuq30Mwfrrn^kK$C8l-Mqe(EABvMtN%{ic>G&w^AvP(sIy`6^Og{4Sk{9YLOC z@-N0xWu{Szx=BK#FmyHTuTwMWY+Kw$NhrNaGgA)8U6er^nCOE6-aD-fj479ld|N!p z&u9v5T|W#elV&-=v|vsQDLN%>$rA@Z%T60YJq5Fnb$;Lp@3s+M#>W9j$YQu&y|}S* z=~c3iX=sCTBKVBp!LK41RVG5|CgWD6}y+?>yCx{@c;OD`sjn` z`O{PO^^+#J6hFfs?R{pO`%hZ6=x!Fwy=Zbc05;O-Bi*24Wt&{sewq3oRTa~4$o_YU zAl)Afu**e6V4L09;^~_kRpGe{SJTSLh!1b)irf0Fp1w8N^YzvLJk@`^lmFHbhw{k0 zBe~bK@r-NsBCF%OfAKg$SRH1y)y>w5+tb(fdOizDu41oE7#7O*t=!JkWg z6X@4n%!Y5YIe6>=vv?EQk^hXtJ*|j0Qm-8(qEHke+yW;_mniZcV#q?sHr0TZgz;6d z{T@i8N&V)aS2ZuJ> zVi+b@r&DkYXPEWp?8i`z@UL8eL-w#||56sM=c(K@tNhDuZK<{BT&KAMp60J?ua;tSU$B34;460+#C5 zJ>?@g)^nKKLj?ca%TrJ!qZ9q6hDl8`_~WrkanmoT+rs9lM&7#sKBM+l-}ipz)|>}K zNeFT9d-(v|X9TM|{owC|sevD+{ln+)@c(zy`yBi7{aR*1E=)hox#f4^q^O_4KX){94#E~-#{O{t2DWjk64+_ZO%)7z`7CfaZt@*Am0HuQz zc?yZuvMc!W?3~C@*u7FqJ{R$P`mn}~(YVKr=eVnr@{hGTCIhrX6P^DftzPPg)$Qt3 zHb$*m5x5o2z7_wDzhPm=9V}>THDQ$|YZpKGmW};q2K`5>s-)38o~^MxgNVA%Uf81~ z;zwB(BoEuO;cq03i^KUXp$k~@P}Ac>?8sh{kyE%;NBUL;W!0Gb=70Wn`(Gqd#+acd)?mYd7U(N4?}!S+8(O_{#t(!-K1?BX;+!2z=AKrxp;;|w|7!`pB! z07}?r*G}qVI!dKhOBN_l0D@Kx6;fSBGivG8Vf?5zOtl_8q8QPEtH~v=M8$;cf~7~D z8*N=D&)UAYp|L?BcBB9sKF|-h@L=8cQ(Rby65CAM09M6a1aeq;(M{oCwN>kK!O#sA z5f-fdS32h^T+5o}aucuINAXru?O5D9uario>KXr?svroxOd+gT7S_wWCF3mA!8u!1 zXqLHI!^|7K<4WbISeA_IS|9Z;29cGv99`O>w~bi&70ur_)%{l)ru}Q_)nygXD1)o54{p%}@aLu61iX+R>H$6|Z|RE9Lmy-8)*nmN)G&HOY^i*U(%w+ zg`BzXl+F=Jc_lI&kn$g%EUOB8T$heQ5h#OW7}3oHy2iDFf7g)kY3d#774aoD8yp6m zRDaFl#FAzNFFJ)356LY5sL5H4gh3-JxlcnQhVH6XO>bIqsYOu(SrQ7yahu!of#7?hF3< z{yr7=^m?oN1NhmAeGfTKi&r4NvOEAjjfw>%v(E|8c#g7JKTK7>%`DPN>`Kz?#ptX( z7pkPLi#OX)5_Am@X!Eq!+Ya>E9L>HslxWj)B-#w%fUa)RE`2*yy`=x@KA4o)Vsr?4 zL6Vt1rg~Q#bnY3}f+iRatTJwc`Me_E@bmqhsFccIQkmR4rbb`>c33lM3h!0Is4Cqv z>$R0lEkJ)iL^uns)h2{ri^%R!H?-5aW@3_uRbZZ?I&M_r3P(*|Y}vq(3;LGthOWZ4 zLG^{>j8?~JYD8=M{qQaT<+Y)=)p%3|+g%Gs?@!&(c)HQuPCwzM*6nV z`V7o6tFike9ZBZ8y#oQ=cTVZ6wOT;Es@pP{t78&XH#d9ZLcN|0>EJVF0c(Po1nDgh zRZMgzEu&De`r72E7sw6l6KlZlHc*=ZgKP6d-c7#L@1(jW#&iT&3PoFff#Sdh^u>L$ zQaUpYDBYs~W<@ashczLzktd^KHLBl*iqX5JB(m;7VoywL9ef4(q3K53WZ$Wc;W~9A zGa5@X@v(BWr`31|azbijO~h_(vut&cZ)Zsppg;QBYM8He1h`xKajF3SJwPw- z{&j%UPk_^J-PpA3CS(&)vCA(kq;(BgzhatKS*h3qtfzQa#=%~m2jKl0yR=*sUj`LZ zio_e~(WEVCfe!4(v}Rj`NL4ZQ#=4PJ)yc^-DJsVh(aH;`c^~^#3G_I4Z-?6BZ9zSO zSrJrGRC>8Z_R7FRRznZLYB8&>MYy6U=HO90Hl4Q~Q}PwttFGrJ5WOChMK^i#x4G@^ z?oiluA^(rUM>N0lu}>Kc2BB!S@2I~$*BzwUu}qv>%L-Q z1fEnHe1(;bN_YuK>mZ|E11Y`#uwsmPYFmW*+C*do>r8n*3>UQWCh)&oCG}Mi|4O&y z1|tDX6sqiD7tXE5V183Pp655Q3gvTzw2Eviz)bs^TKl^d1C0d;`)2|AdJkTYvFuV4Yl%kX(5c3pf*fepzB1E!tcsLR+M5dT z1ya3*XLE>d$lSc=iiYNFvA>M+Y+w9+mt3hC^IZXXF)$y1fuq~}Jpljc(hcD2d+!GD z^xU_J{VMAeMAuW(KEKcWPWew040*dq^OAWb5|H!b7WNV7lmoc&Vu@1oTCyLVzK+w6;MzxeqmP5^*+hwVIoe~LLojv*nWGUwW|L{S!LvKDP%zn3@$UU?cEMBWI(MJh`9xM(puMhScpvi|4FO$!^3&duA zm;W0Xi2Vv0ui_{M;B;8qF5<)Tg%XmTdgu3d`+OW>c0b-Li9LDZ-{8+geFjV{90vP+ z`KOezg`XJQcD_Bd?$hQ_%G3X||?h)7N899TnsMsO0P+aL8Y9`htn zRV*K?41)?H#S-oq0W&t3uxQdCi8+fA6Rw02AcxE}h;I)7VJ1T}aTKXI3^-IXxu7F9 zEw%?NM(LR=(yKy5TcWwk)^bn-4lnT~+b7QoOcQj6sAYp_-5J(51kGatsAfR~Ukwzb zXo{X(?8f$33{lCik8bOrrx8T*ospGYe$Sj6+&=%)ju*=g1094Hf>xKvtXLAl+Fo9C zJJxO_OT=NR5<>paK!k$b>eCiB9QRyO9ulRB8*Ceg-x*Q~5gppnL8_oNC4V z5ArGLkw#BwcSDe0T+mM@s#&h^x7C{RN&>?^mn@2SqhF$$3)&Loy|m$M1%^SQ>8BL) z{jV?Kas$&cS7#MTMVk_7twtErzhFZI1B7K7N$vMO#Wo^>?ahTMeqm zT>D;OSb9i;nBjR+_?WP}MS0`kJ>q||((_*|Pb}XsUNnF@G#5Swyv6x004I6d`nT4% zd_6AVyTn|{jZj|kyWihq+K+gIuX>JI2R$a~1vHQq)g~L-x^G&P$tpXzMGRM0^O`5=>2su;wIuqQU!Q8ltIlU{x(2WMHoHe zI;MVp@w@OVT?HZANhyuM^_!`CRXhPV3tMY_2(l`L2QHAB1mWJoDAN?aPh;2?&uUPV zwl@2dv`D%3qW6snSm?^l@Ty(zaxmJl!cpzArxcJ6zB^=ZRJtc`Zq9Jlp_nxpoi9zqdsY`JjubkQOH``GfBzL&J~Hl#gt zXbBTir_k*_phlwVE-*pH!7cL9a5AYo5+~X0S$!qPQAqN{-({V+DE$Ob;3L1~ptqx9 z6G8NfEL<(d!qVA_jBGS+Uv?$}gNHaGAp2QVRGe~xNT_#cDCf{k`fUvv;1&*A^GSet zVb!Wc`jOE*3Kn6DCDkJPvIwok;~U!fZ{N$7yU1V}8zI{bu>YY|!%q{`34|~hYq<9e zvUbr>shYgZtjy|^O`%+&ONKeuV;48lJ`kMtQ>mY9v(f2Ke04IB-#FMq%1sWPU$R@# z_X#uY2#2ZpB(J!BMrx;I*1hnbSA`pU%Ktni)7*NyCH)i^EaQr^bSj>JxB|t6Y zN;O=jO<{(rVgR8Q21WzcJM)Pf;oy}e;xQ2kMwe1drlP3B_Ryuuwv>6Z_{eAXWC_Y~ zAMPQ&L!tEGHo@(Go2Mx4HSXtRBsKw?oU<7FuD6b;c9*xuMC%8J4OXj_$zs& zsA4&D5;*=k_~?8i#cqh}H`N(-iOYG%Z=v(JRRUA2`>V}L9kqrFo<1WtE&b3&dQ18O zqw8Sk`Au!2L(?SpW6{|xQs6uUouIN2vI%{l82uF?$x_@>BQx(@aEVY{#Xt_lFxc3- z?IjJNXT;SFt9HYx;WnFq733h?g3|HR%q85Sm%RP{{Hm`#U4@2Cu7@nI%}+oa{B!i3 z{wPFv&lkX$r{}A$4e;^|*!|wy0`O;k0bcf)BMr-ypo2`K^eyx$k00M0U;U52?ag3b zU6vR~Y>JH>cIkk0ssMXOj(6XCCfhdv{A0@3B}rMYINtRg5U!}>Suhx{s4#;F%oE(a z7l@1*^C+_GL~gv-jg6J&`bg}lNlC5-gJTmJb3~8EG)?!`CT?8?KBHk7rLTBw@#q28 zjctXKhx2~MY`gule+K*c7DyuZ`tffdMK{6H`Hm2%>2l8q@c8(+xVShtuue$qQ`UwF z;9RZ>RRSb$As|)O`PW98P<0TNTD=Y28SM~xgZkx{@9H=gZm{_yfK!Lh_U3N{cyGX7 z{QcvL|N963*BAcf_nZL)r`$zk!Fq0HlxsKRQ#2gM;F&*OpT~812Guzcc^J)YibsKt zwDt5aPUulLJYza_Jwzxfb98A@VYHp2L_k_!WAIaMI>AV<{F zy+4{A0}}e9DSrn+vf;qqkHITHe&7cSif)2%dP-Sh&R?>F)KKu3C>dn_?$N}BFL^NL zVi?%Zi-7>iF&$D+RmwYxPk6a97Iu}8F`n6dk{XI};T6LZFlsuba^6rt$J?}B5*dzE z$i|9`IOiE650B(h+XZQJ4*)_TufcF&Stg%LB87Y6{LBq0lA~2mzaxbgPXEVE0q=+y zn#KDM0nuTdm=K(wZMD|4ad2S|F%{*8Y#%g0@E?!BL^j}Kr0S1E11iYUP~u-and5b} ze@vYQ9$?Qc1l#RV0(AlKOU(#uv2=O*1o09X`~lOqmSv{8ZwDU)DNQCKA?%%mO{67j z#BaGnfSvSesoUBKGKAAin~MRRWLYTaZ0GS~&})EB!uV^6HK9Bj?naK@uYFx5l~RBB{}KH%CB79UWM}7YFn!H!+`ooEM#m`4LMFH3twxiUuRd(Jopa8U~z##K%#pXEE8{ zNo!QmnVG&oGEVc&lI+opZfVnl0ralytja5Ubot?9QS<#OEMQL)uG42cK&OMQ0Sj;$ zrr^4@LAH{+Oux(+qD;@XEhJZ|7!~JdVe3EHjGr9?xGv%!%EvZpnRt^ zVm$~#@25Nc&f;9}ZYolE?x^4=aywScg$8`Ri|QCDGqGR5398>x$ime%EW~PZK&%c* z78(lFGP6N?@Zk53%EB)gV-@zx8tYgI2nUohpKhr}2Z)$JfXKWxRs81^*h;qyWY@`Z z-p957S|q{|*eHyfOr4$)o;W?+flQ3Q)|wb6ZU>+)z{QpEU5&TSY$!r%2*Z*2P)13N zh8LyWoD*AcT8OL{;=~+VF2s{Xu#7im@NICokHj{?c7B-KsOU8ud)a?|dvK$>HRHpAT9fVZ*%6p!H1`ont9r2sdN6-wQi4 z-1SJi{KxKQ@4oWH4OfC=2M zm>GKi_E#CyY>dl`%85A>a#2LN=bdK9v&UYc_LHK*DSx=9bMAM*E-nc;mTl(dRIb=%B#f9rCCI$zbfNi7zGe5@sCRaV3iybbYA- z-ILW{s3wT3d}T~q%|WNGrAiFw{)E6|x_{(RcL^4_4A8yM;KS}F@EBq%LQ*95EnUa~ zWMh!eX=mI-^-3Tln*JQCI3VwJT|Pc;TAaI-&Ph_5T|}y#G1yTX)5?MW zaHGnz@-28*9OASYoBn#L-mADJCp>@Iv;N{DjRwI0(vcqSODZG|oYd zqm>5c>dW9!++qiMi?k`Vknr*U>&uLfkAsK9lPeD&cOu_A`kg$qvG8qtGojN&)g%0q zV?ycaZ)LRwZsmR2PN}PYL5tVGN9C~K8p!{7D_gR8AL(G3Y%B^eBNPf`WBN02s+E+3 z=I_XFe~||Vx;mO>PWJh=IyiYUlZ|9!Cf|7&{Ayp(^#Jz86De!ZDe+m z9Pm&0^G|AUfPs~=J6|y$WH^<}Y)!wyNh<_e$=`vNqe&+4(zod$iQTp9fERQU&9oI=^r7A}C?b z!sgp;{_f%QmYsOrA1yS?SxT_z6q{~*axp~%8Ta82OA=UAo&QP5Kr@y<)XT<)c~{xx zn?5?^*>TmBIYzAqIak|)(>H%cOds8eKmYHSI{@G0L-4asYh1~~-09qc4Y9g^u`7Kp zm-gLxKsQLk<<*L^L;2ftRk(p1BB2&yL3fkwT2ZHm={Qu$G-8)$sI=N=D^ai9NQX4K ziTO`ScX{<5`j)u=C!+|wDBy@CszJk#`*Q~lRP%1_ki9l>6X+R#NOx%?S)HCfUS6M% zyN~Nmk|x zS4$BO4*5oKHx333_dzwI{b|asf$27dKeRG^lPJY|SiQ^U-rxQ$B!)7W?xO1Mx9H!1 z*ZLH|`Mx7Q;QWxM2Oxd}SorW?|HkhF@OiO#Jkzm_8Mpokx?jcR`F*}$f~cP#9P`)Y z_+QF1L0mCq*TWhvm^2XrE^dF`zy(ppT(G;v87xeoGFtCDIH{br!dey}b)O*}!hj;S zfc$zNUt}QcUZ|D8dt@QTLu1xlPQ9av;*5WNcg2uhVV)s6peUT#wg2|sOc5V zOQ<5LzzWkU$1txA0t{~RCEYJu%+5|ms*_~r&MY{)zb*27M!7InYT_r)Uov~y6;wx|)vQNMW!BA9uV9Z^t-K|VQ0?gfl*MJJaol@h z=L-S2ynIwA04^N)pN~KM^AfFEqVo;a za&P^yR>qC3s_3p#vby>T_PlEKwsc)gpC?#~l=w0c4=o5Ss265ZIk?EIzAHv-^f*QQ z4)s4yoj*LSz-DPutyE*S%J&M+n0{#HcD1HTs62+Usy!9he?V@xTpCdxn6kaX*Ia(1 z`Di@gm7pn8qhvG%9m94`vOZQqvBN0sCN77ujW0H=#&?2M9Qj+u{;V(~nWF`#66c3< z1?!+&d#Gf$u?TZ$?uqtFD>BK$H1#h%@*m~ih!{s}mN9Q}_TV~rl~BCOd_UYR72IpZ z7ZA3fng_hu?XpkrFZzKvinN~hNs9~84uxK8bq@H=(Zc;pwZVF3yA}>g{RV317|-Jx ztpK!~sVD;57sh`xB;K1Lm5%XK-h8U^&eDuCYjo{@Ok0{y+)8lUYt7P=t3pDRiAh$7 zRKPiHsjHaz%hYF;)mbIvZCN(Gg=Ds1x9N_j328ajH_)!EwcW1?9db6|D<>Re*=&;q zM%w9O{E)O%WK{AXOx`Xx>Q#CRmwg+#4z(7j4vVR-dQ8=<8Qy$%J*C^$08Ouwx^O_W zFMzT5KDuMTCO_uOJ7CPi>#J`K;QiGn1{nJx4wh=&Wt4}PY3ofJW`22|ylor4GFCja zz7v`@Zrhbti1U2XJ!3UroEW|>=^IVy7ubsdyltHe9mKMh{qZWwX7-D+n#LeZ){Mpk znDS}ET_+P(Cg;`Q8Q~6v5xq|ItU52;)2b5ph6C@s|Cc#Xq1a3PwIzgiD9B$V>gy!S z;(bhwQs)0c_gyJrT23m&`>eT0E3SdYZTzd6j-Bs~RY(rrnc)s@M>k?aIq6=ii5`q{ zlu$L!^ieDtKii@m=ay}$bZh{XU$Z7mkKgZV3IiAEkGB5_79fRe!d!ww*crrT{hN&1 zC~;|caB_!0s_!?*84Qkm%^%&+t1DpnEgr}XHVdS**cJt#fv3|-d|#av!KbjOU=BjxBH)l`F#(B=Xr)m5yZlA;aU5qPDLyS zYt5SHfZ(Fyry~jRQ}~ltF~Y~{&WUVK^|`WuI2=vdT1uwj zsMh)Qh=o5R)09q7R4Y*Thz?*;pWZOhv^trMtWpj%Dft~)K-s;EN>vgj2zdv_AN#x& zq=w6mQS!ip1cogg)Oxc{w87XiQ5pOHJ9Svq-7EYlBRIxL)H$mIol1#v)oOvZ9N>cw!;{jf# zumx^chS{0%@bA^@ktRIBc+ehmCzTRLH|N|$_p6@2;_FH6VEOpeQ>=fv+a+k5j$YhV z@n~7G-Mu65q#yEFF39@D6H7_jXffRh6UF=bO1;BSdCP5eWhl&&pzY=ahIq3%2k)Wko#=l-`KC4F#C<_m?<(+cZH|zpQDYGc?tz_89vW ziiuCM_Eg&D?A4UU(u9@ecH%eqZ?*Ye+NJ$sTV*v3MLABTw?%EVmz)M8_E7!k?aYMq ztibY6*VSnPZ^6mpUj@oXl2;2^>8-0R)d{J}n(?*9%!7!>TZW4huh^cn1=nKd>8EN7 zy@9|%R7Wngs` zc>%n?(s%q6jP17;$epyz96Z`2I2*b#?QI6d0Nst#u8DIv^(A9Cr@lDNI&%33U*TO7 z`TDih@qamAe(94NoD+dJzxm_w;Qe_7NcsalihgR#exS_PxBe=?@u(<#oVUS=rbCkf z`}#YgBPV3?iGo<=+MjxSS|cjLib-t6BVko=ati;qL<^=7$D^8)L`%yM0rv4oV$l3z zh1_gceFtk!##EY5<;|$-3f0xUHfv0@dey^5rWEOLmIg@NK^!Cqcax$&HnRs-%;>83rFVJ`|ZYAsrnOl4Wg922F2eeFS+IFkH*ok0hB}ZeXgWa`mh5rwzQ8N7jHCyb^ z!4d5sFXtmGp$bW*@PmM<39x&RQHX0IMB>*zA^-hZKjWVR&jy{CBfzwLZ=4ubKGt(> zGNuRzpU2UCmdEXQ&cWpXv3m8U9ispeLkdUsci1GKNjnY{BF1(&L>E` zlA{QK({6pOm>1IvTDs)=mB-KR_x?Ad>)w7r?BRWnpX0ML9boC>v7QI;OEDiS=jYm} zkyNnTdB*Qv-IJ5v+vN!%=v`W{K#DMB0;y27q=0j_#6Y`GtHQbQ6d^#GX40S`#Q>U- zw^EL&hB^ctiRs-6Ncc(06k)+1o1eggmpRYRr+LV#YE@izZHu6;`tPA!>}jq=*ne4}u36^VI~2i=^%=Z5~kE zogUS}ZXk%}IU^~#VozKcJU*Ul#EIpEe@V(CCg+i~pur^wDmmgqjtQ=kBsGm!=I3*S|A}$&-cs!oDkh&B9FW8yn60IHRx5A>Gk$bNJrb{w_#&w+ z_*p|6juxb2R?S70Bk3u+xv(l-j073yf4GjZcB2z~MIdBB&?J4`^bKcaF-7YlDeXom z(_N4uV$}r&2$)17U7fri4_{x(UOdvvs(~ zU%uieN_NZA%n|6U8lX;T@d28;z+&8b;B!dQfBS(rnFGu_e~U!xV(2OjLj^L*pFYx% zkbU?5HqL{@2}ywT2MZhHZ4MKuIN#^rKYP+TAHwd2-s5o*U!B|G6~Qu+OflORgD(0@>r{vIbd9f?I)rO}Yo z!S-!c=&b%U5rQB5FSr{ec);;DV7xo|D-c!wYJUwZFZEyrc# zp`w@@>AlVtMKs}hj6wdp6%y?TVtBTjfU<#~tvkMWVZ7 zL~0f9Jet#2qPquLI4EjAYNMP~Dn6S#0|$gQ_Z3k_b|^6jiL|*Y=Iy6hs2s5=`wIiP z_gPrFA%--KQY#+w#lQ$c(}U>{3@6Aj6Ic*gHiOGMYSMC7JsV+E%4KKpRi~FKWUW!q z$77D$E?)vYX}SykX#$*LRxUP7eu)ge7NDNB!&sr zMBaBQXi$EC1gn!yEwNWq_%G4zHmoT7k`!S=!b3e#W3m>aA{8E-8$K@*M%eBW5{j6f zVt#QLs*crP(tcIDWrr9`47a~X7Z$74f$8hTdVuhGqblmq^K4{h6D0DO9EeIc)&uV5 z52(D|3_IG->wP}_0eSjyd4SI=z;_=m6_6k_YvovNKUwF&M4OP4H>|r`LgNxV_)Q{o zhF?eI4^_;y3Y7mI;Y9}mh~7Zl;J%duvizO=2kHjARnP|i_NYh;J>vD`93~{Uo$(5d zG`i7*yii1tK--faI=UKCZwjfkH(E#=1T{Y=SC{y(^u0vDkclR|oc&YqcM`rha7bUN zH~uVm@lsA<^}|PZLV+zCdir*-wqsfpU}e_PT$&zklcB%JhtQXhZ>ndLqz)qZZ*tR|M&hLM3 z)&2B-N$;e0lCJ9KNp)8CTDv5q#9?y(K3wrq=WtKL30_m>({?Y>JFcIg#cihahZX^-490teQ44QP(e~O-tF0H%^4}eKTT` z3it2m0eb8kWeRv~A3A)N5p8l)1Emqr6k4wiWTlfTa3M#?0@uJr*sQ|enMP4xiLTU% z80*a>jYh1VCN~=dNvmeB>p^~{`7HS^*>OD*pPqhpR|nbV7dtdpn~-Nzt%S%|XLs=M zNU+{5)P`=z+7i;0qpYlM!jyIn-%@J_K`=?0r--E3J%&MN@(vOehLmzBqdnRDBl@>c zaU8S^Ocmx<4)q98-#dNv{azs=n55K0YXVa-b(V{Q) ztgO#AS*EhTDJM}UpFyJ{@yMJrfY-_1)JRcc3$ys5d9h|YIj?ois<~3N=fbgxofc;v zzPLKLm)&j1m>*A-C!fli0~en**lj4fKoU!7!@;Sx(s8y#N`O$>w&V@RYv=;nOU)ga-EKJk{{;YQlbwXQyTw4+5O?`{6PYBiPhPUC*iG25Iw zaRk)JrOX>EYcE5K@>;%cd`TXV1Rf<30*}~+zX%{Qf_u>*Pm4<%eK3XBo00B zf&hAhpRABs6s|!Pk%%v0H||ba8{@;Wu{7POgbV_x}N>-SF>Azyyu!)}PfK1U*$6sLDZsRbIAB{Rud}| z7Jf+whF}3#SWEMS*rGNARvG^HmSRC3&TT;=(B-# z{-ONaQjVd81~w9GUeoFc?C3dJpi>)Xsi~w+n>;7iI`e`6p}Uem1xWP zUiL^`B-R=jbb#0w<^&`*a%yVVab})60!j^P+gF(v%6EKIqrq6s%2{hi*bmf^SQA_+ z;1=6aHmlO~rc7QQ{JDyCGgs(lPbM;UG{ZEZwGNJUQ?3kE7tV`%^cn8w4kj8QMWDo$ zJIC_UEA7&X@{S>kHcg|a?G;=hRFrD6EO2N7AxV1#3uVzF=qZ*wWyi5+Obt-6lo8SP zZyZn0HW8of#!9KU=Vf#DZU#oJV5s7wcTDk{h-Ot=*xroeEL#H`$1qKR($G$>!W#?n zevbeOKLZ3LRt9-r%A<1()@&*xxGKO94{QxT){w9|agbC7)E;x#Lr%L|rAl>Zu^~N> zQ=B3!qq?Sa$8YA7!R5qd(Me!!yR{?=^F{*OjaSRKE8)_K7se6UBWtF0GTk!+`KTM5 z7;cwQ<9N?r-?s;nqXGm)e7`}j)w3cU?OS}{7>S|QKhBs39i)zfI2Qan40y2qE`<$G zr3RHk9r`ev%AMO=yf0IqW`s+9AYj;P^XyJBpjZw`1AzQ8hKnw>Hts;RTwb9<%K5i3 z#NO<2tFAO`zz9#N3dZ&NJGsdO8aEbGWY&zDTP)PQ6zLC89K(D5D19EcmCaEam3ek_ z9uj@ZqCu=CfjP8>v_TtZIHh3@%>p(>jo1PlV7~JEw*iAcHzqyW;14CBi)PF^KbJU7UGhB}RN6W?KVZd#o4yP7k7RbS|E0q z1dGK2#*O(lv8`S#DR4B+&Mu_}ZsT)M*hEE>T|u=#%U<_+K4vkPyR0gbd+!6Bb|a%WFB!AqR*h^^G}$j* zoKOly-~M&{o;njh&MtL3CqHi#^7ubx@jr{BKjo1>;RgiHy%c3|0CpCe;rXST4Cr~I zaC_=*{{|d+Xe-*uise=H;9GOXhsM~UN$XWgxFQ=oXrY`iyiDW%tVAf1m%jx__*|L{qRIWAI4nqX?83 zqw$%Ui)|>;n7N1!C6T1+Z&(pa#M8BFZ>a}A$1Ei5{tZ-0#Z89q-QL{2?PzeuhZZFX z{l`Iak`%fOthMLfPo*h4U)&>sa7HwQ$!{k}DW%4&k>(0&6`}S~e=mGS>Hy;pWnOX~ z`Ui$yVuT%G;`95`X}l^WQ_OQ+e*VV)P(x}~*2_-m?s1dE`}=XTn0kleIQ<>xP&m2s z%1=}nwpog5iZrnj38M0-AI6AXk)iwG#9wW}fGEv8V-FQEBvl3^B}pJ`ujm_v!ee9O8uoSbG9U<{8*0l(N0_<72spN+Pbp1 z^u)wZ`a5@}_N41dAR#hq`xf`#gEJECP(x&Rk(;3quWd1-b(1Of-z}^oU}0zVfuW2C z>CgP7Wy`@WM6 zjL<7dtXt^xamkt(9xtQo-0%y$Q%~^Y-%WTsjlCUAydRamd`!x(OVYy`HSf(z>ZSVB z&G2yte}-|E94{2lhf*hu9Obhywbe0GTftmgQGZ{*S3+)=tj`?O`OaQSD?jO}Jfusc zpZx3QOUQQ$f%m&|kRPWyzy6fdwLIi{-*Xv=>h5n_2hta%U@!eA?^cii6L4i(<4D zU%7hJJ)MT-4Ol=Smr{-=c&eDR!=~6jSxcH?4EB{f0aB=}t$*P_`TAt4vibABn?4&2 zmU!d8nIBH!&ZTFMoaJYayy<>U=G+M2x4$Yl6AEgDdKG1tDcP!&Y7Mbg+|cJx@i&c5 zQgTCaN^5u8sA;-NI*WB~H(TC{o=WWwno3QfKQW?B@xEtI%3c8d!n&=I-rRb2bePi< zPS%PwJzfuvj@InT*Cb!eLepI*4lPP#4%b=g|GDm~zkTf;Nm_TZ1zXv9Ov<@ibk@wi z&>L?xYJ?Wa&c|rk1Go~5$(#%fT7u2O)y)OWTFH=cPVt$RqV;Nqra*=J9>v~0Q|d}R+Kf`~|A!PjMP zhFmGR()EkFV0$n7ttb-fY|yeGh{#WN%1}`fg<9VO4<>G2kUDoEyGG6+{nL=Jhjk~W zYiQhJCtSWuFv})8s#)_8P%`^`8$G+M+I7+8<80=L2ocUKqGF{Olz^P*dVB3f24g4D zpuz4h7OWeowq;!`nZz_weEmynEGegHrrph3JWnFdu_aF00=KHMFGTpIRZby_yE^ zhkDQ;+>xHreDf)M0!+9r9d<5_?Ab}kL!795CyJM(XqnTAiQsnkU)5nMsNQ0u%6o-Z z5N9VWN2EIekc;C;&H0silWv8UBI!I$M=E>4}yvc?31 zylMzTo19z%ckKlTvR|xtRq(?_G1MRAsKa=VdGl}8y6Ddjq@gWvRbF+(N~$;TV(Q@) z2fj88(7C0f^`!8n&q;CfncE$RtB$(CLC?W;zF6h=PA}j4$3^`EteYRV+jshbUiaID z`U@f9w!XW%2#sa;c1VY7TXd=O{rSDUChsEH@owJl|gUZpC7ThH6FW9|2>{`aK% z&r|>4R`2!K)yA2B+&0hq)BFy9V{`vl6qM8Dhr1d$AJh3&MTYN!8fbOK-tbJ?=5LLWQp!o5zxS!|ZBp#A921yD@u_yAGY(Lb@8%&Qn+A<(2Z*Oc_co z2I^9gp)R&8&WK<-xq0)BpP$xCHE8*WItI4R8q5-z{LJw8hVg+}Gz*_I7P=!D6?* z|GO!5?>GEe<<3XNOV4@!KlN_+)GJ+6>&fSuhUpS7bul?Yl=m zrS5zc*Til4iWY+#a#P-J?dwtJ$t&JYuh|-Ut_sgzfZnRz{ovihP6wYyUGnDNQ$0>6 z7IUhbICy`UL~Za2a_r0r=F2&G*jz8tfL2$+_3A~HduAtkI_Id&{0I|Ste!Dpa?O`8 zwM%!fo^t)RApOrHoY${?^Q#NC%6(d}Em(^>|691vS^If`^L9Gi{P}G*mH)l}Tkmcm z`k(J_ljf~9?qf{~{FdqsoQ8*&d*3#0ojW)UUpKeG4cxy@;DNPmb#VE3=op09KDyLX(~yf4fKc6*DAitZz=FhL@g%)_|1{q3522ZhDjN zGhf2rLC_msLN9#@uadgy4|}WWi&Zgtbepcj4Ry*X3&NN%YZ^>) zAAv(07#u;YW6>3;LVhBTI)OBR>#4(y-XVI)2`r}VO-|NnHlRNEg{-6`Mq54fSbF8~Hfjf%1%kdh@0B4042mDKG zlK9@genP$mb7{(hsR0>><3sbxZ|7oq*5kF(Squch_!4p4XeDZ3Zh)5OO?u`7 zonHCm9S-iw>cpw25dICcOFT`W6PMvs4_D;lfS3EvYFoBFu5Zi0kRztk;bf*PM@O4S z+|;?CU`X7o9KGC6c(z*YasG}DF+2%hh01!41`@M;L~UolDNdwmA0jcs1rZ14H`Y=%ILhYKQTZ%G{|5(*YWA_HR(qk+JG#p|lusr|{1OyH?9Od|n-p)D{1^Ml630mU`cRlCO^X!Rw} zbND;krb+{GVu+psuQf&UU;{}s5CRS5;P!LoQTtffz+U%40Vy-FJ(#pXgM$AFwX&X(xu~yZl9jW!3Y!%&#Buawm)kN|7{^9! zor}^8XQdi-9By|Gmu?=lVWv9SY(*%Oc`lYsdJ5LYsz?4LC7c^B*&HlMOlxl$Qlkmv zp8f4qsJ^?y@RVKV`;}s!8%+C9YnrtK>+`i#ler?R+~Kya+PY7mJ;!>p8fFQLj4etbI=Fc!DsL*#(qB#=YT2!fhB!R270*2NIMF z?u2T&6+=KLw4)q0#@!Vq+@Q|QJ^zw&uBa681(z>I?2-qiIhWPI(04s62vq~ZS@sCX z&Z6|_0NeMQ0Z~1aYBx}Gn&`vTqiaMk!kqBUwJqEaH;)l&ku(DBK6I1SAD535I?Q+f zhl^$Ui*;l`yNAF=(2pqF-jsOx*7=AYWH5+^ZKuX$7)1@k!LdDZypCjpX zG?(<@tafls455d8&6s36dGm0iYFR(rzOoY`6HmFGL}r>h?)$G$wJaYbBYHYa@Ik8* zA9rqddL?EaQE$LQuvShf^AnIblxPiiImsAl4QKKn2=O^d^;*@E)oF+h%_Oit(!YNj za+*yE)sab$iC+-2ocoXRI0^%ece#21tFgRVRd|*|5xU?H3D~XlJ!HI!e+>Mi-J8fM-5;?f4vRQ1=L2j(HXQvTWm!4lE zk4D1PscC@VLHQy@7~ml;8UjclSp+C;4lTX{tm&+1%bCT#hKQ?Xd{JNwM@S4{u`_55 zXsML3iEa)PO2R6!=JglTcPS#!bc!$>hL4xf{2NK?J_63<294&R@m@m`z3MP%k)|9- zAnr&XQecD!>o9m`Vz_C$fGNX@H0mxZ*iZm>&iWk44!*)LS4x@9rS>k2Py7u}TG`>B z@QqKhE4$CKf6w~ZJDaap+<8XFegj^QfIF60uEtGz839;t8 z!;${A%7ow(#(vsy-DoA1TwGI$BOsVxXrG>?IUoe$qcJsApFF7%S1+1s)8M`FWhDMMR+AI1S&1t~FVF}h;jH=N`7M}q*<7+YdT2rq7cePoii zr0?W21}SJK;;Xbx?1nlz+DHI1BzEtT@4=E44oD&XlsznE70-cWg~{ANaHBx5bjA#* z`%r*?H*WH?OO*NM5*mE^k&1Ek{k7MNgd-Jq);mOf|0Q+lh5$z@ptn!+7L7Ly`ZB(b#{=BVP7tH0FP%MelVy z=3?3ZbE*G-CgacJXbhU!|NJt%-;GBW7V(*%M`Ql-n|-qLntcY{M3>$rT|doO&;==e z?_2N><7=hJzxC>gb`A{hP^&Pb*clv|=;XaQ4SBas%;FBs zlOyit`998WDGY=7I5=(s)g81fm?5O<6zd9eK4Gnibub*Xiib(^z}xGJouUMN!C!^! z?=VQ$;C#V|s^T=5yE1}uC&@hMS&TI4WQ;e5SZ{wxCBj7gWR=g4!w^EbdBU3G*1=0~6X}dr1g4_}usI1*G z97_6Y{-r8#llUY(;S(RsV35=bg&#G=QcwIy$WJURBcy>c7=?keA$SYp@ zQyP8j9k(ifTmKPm#h%Nx#IEy<#RrD+*_>l2Q9TvB*|VOOQNO2xGo|u`8BXgU>w)p< zY@(=A6M-^4Gs|i6T}L8rCSCi3@mI)z?$n1lx`T{0rd%4Qw|acY0_iPgCdevvOfU~8 zAj|&HO!dn0@K1sPT@4SG>R@;Cjc$ozhvB*8@H?kw@@)_VqDb@y4F8%%q>8+8$~oN| zEOt!H3rOL(R(T#>r(yC@12@Xja#VR<9F2RnZ=EWO!Ymu*F;^7i`B{#MJ$0g>`Y9d9 z-!ksC1u!m1M7Bq|%%2Xb9Jb9k%snos{qr*#=+k}OGV=AL6arcR_7SQqy z+Vb-?qG6+xmTcR~j;$KS{rPZ1Ze81&^RqFM77d6kb-Pv7jea6)V4L`|?S8Jxyf`LD za_MT-I#7-Dm>k-yTHU{TKddELO$JXcct3Dh^rB93Wm04i#wjCNBJF=6a zH^%I?vhfheRf3n(@ z$!99|k6vI!RLA9R9{x=C1S$G)U5>cRz`YqJ+io*C{vn$9nqJXrnL~;yk3?;H?y`Gp zRjJayk443%AQsX?SE`6FbB5pLm*dIp)MM`SW|`aw(eL`mrQqMi(?wPzJUceKQC5Zn z#Uagkl~BkHV>cW+44dgI;H*ZnN$PlfqixOBNc|AKYFnGl#qh93deHV>*-YC=aHslv zIB7K~Z8w#-X4)753cNr9y5)3S%feJH5y3r z4p3BJ%BqI2O%NkV0&{82=Y(#`p2jNzYKPOJLPb|NGgO=#9Zwsj_-Suczh26FdFK|Ltr#y!g?w z!ZNqh)fDCLr2qJRZ2CJ-ujkt4?;H)i3yJ=G`L;Kc-3#+OT{NlRQ#VnM?DRjMpNF%w zSI-+we($ELivqo}=+ZBpmhBe5T`B~A3p|P60?F^c5j@v^J07g;bWQR9?`e`xwk zaOW=r2ag|*FAs-@FZXTC!^y+N^$yR{Q}&FV9|Aq~ZR~T>5|#TQg!lWQPLV4+V+;@7 z@W+N(RKC8Cc}kK_@yN?R;DF=HbC=Hz9-J>y@-TS}IL?F)-P@%($R;mlC|M$dr+kZ( zOTO_>j6@m^4Uua}1~R=N$!3PUhQzd_dDrk5G%_88v+@{wAieZp>>)vt&p&w{iD_x# z5Z-t)#A0lC5b>ChKslLCb^(jHWCf0(un@^uyah$%u>wy6{T%5mFb50Zbxusra zNw2>g=c##)GUiw&Ax@QmJop95$01$^_+A3JFT*^oZ+xYj_q=tBy`O{M9D+pmXtm(Ba}Kra4zF=#&mK9ny5XZ|7o+)cjiQAdDiNVPlc;NR7I6BD0vH-B_! z(BaRq^|Ox4@8|S5z51b#|5dx!`?Y?3uTtfo3h|8x+BfpVkBQH-O<(gfnjEb6{XsE1 z1NSa3mxA&jEMd+e@=Hn*1u^ugYc$s53*ABmrS2jKMKUi)F?m)H0Tncg42{|Z+~YjW zVnBOEC@NC%ga=JTC-Xy~O_&aUZZM!HC_BTzww;{s$i2)xAtC(H}AjKnf2 zJD=v%lmK*WEc44FHT?VN2xpY3_ADnfW%>fvQ1SypfYp^9tRzWL%D=MIob3bKlEx0o z02Yv<7+VrROvAV|l8I!3Z4Z1k;KyDDlPmc=60viq- z;^sET?7mmg8^xPZv6`^uZ%p+q!gl^3UDA1Ti81FU`}jT$a0CGd3wJ5$38by)H?d~y zlsgrnCNcMt;t2vdg(mXv7_FPKARIE?`AQtACL!FIG#@;q$binAeqRKDl_n!VVI>PE zT-{7gKY&trW)6cHahGA!1X<6vfDR^yTYdl`hBv5c9|1ZDZ{VJRh*`#7%z#i3J0NUJ z0}vj#4ha3NoEfhnlc-8a8LH2@j;wHXLgpUqY$u55a*$})kOJLNf_-Rp1Ob3_JK{=Vo4Cqxem(8SOs7sWm`5~Kz{ zwNuciNWEmN@lW=20F7R_PhrWUjCss?9v`rR78Tra0@H(}{d;?50eSX(kxsMb3$q3X z(`E=v1M+u$!NxP{#QFJRhyzsL)oM$O3A7UeJR~Ic=E$|6BICE-ji$6=2xkR^>0k$5lf1|^rCC)j+K7LiuKpyqLGe|Q5Otd_8+E(tm!hS0 ziC0(q1~#;4s2+yth#rbmNaThdVuO8?g30!ZFtyayDDM46s?A?_O1k+|Nuinj6;Qvqm?Svi=XQ}XK#N3SMmyJML$IBc9Mjb}t;dJH=RIag*CtLKf! zv<#JaIN|IbgZN`xq$Su;99{&R^yu)<2#}nKop31p|AiC8Aj%Ql2?S2cMqEZrz@Cnk z;o+0!FqkKT@L>u<`!pdl?@KIz&JQTwOchUySwvm7s3_O=#ejKZu=_4Gfc8RtoMMPa z@!6+ifse5#E*~N#1bv4(Akh#yOt7;Eva>+?&3si8*+7mo{Sa&+w+4m1VIYBiM$yN@ zD&uGlj!SMNNrdQ8;gV;%E20~@wkG%+XFmhuJRZ_7iHw0-#Oc{Bqs>{aTv6feY$RgL zYw1vPm)M^;T?cobQO&Knl!~vz+H|^4hOn*ltnKLK^1XEjIU&5nu#2xc%_UqO6g!x( z-BpZ8nQ)}h!`=bF0Es+3JB3L3)nuRm+yzQ1R?ab)v!ifaY9D1+b4=Z`^Z_4ljVe15fF5qJP-3&kzmgw=CekNLuIJ{ zFJjH(u-`r~Qt+F+K{By}3>zC#7@bptxzHD9Wk}pvOkI`tulSS|t+EIdvhbWWQuDO; zu)R28zsx>|QaC`|Wl19+##IFNd4#M?oA3#oz#$yGnxg~`&f5&X{X#50pBf$P>%J64 zD#ZY0QROk?T`JsU*=eBFF<>DK@9PQd?U!AyA69i`-}0|7|^^}Li!e^ronNF!ckY)e#g`Yk)Qq(@aG5uEU=<#-bzlM@aM>KKx z%t9Zx-D)LrKO9f3HPY@DOAv!Bn7bqad0PbIk0ofJP;NaEQv;m;TEi=W$vIWffC+)Y zC5{}Mky&WfT&cXxAD|&+d5g(6*76DOxOi!P`Q=myW zK$#VzZuO?m*GqBhmjR=PkszTo6KL!UmL-IAMzmp{>0p5oA={x@0Y>E+^nO_3JR%)N zjHgWI#9cPZR&ODUMA;d7SsRuoH$$(t%YTGHIJ2m4V6U^ek0B+-Sm~ zAtozpp0KXn{Y6A?H0S8hy7>T;MKF)@>LIzSsYDm0T;o-&<5Kgf?Qw9eK5xY>Y0ACh zZn|0#7ppBN(kLLir#@kQzVRJtb3NBJEfW1#Bcbfx8=J{Pn@28=nj%oHnGvDsj{r9B zc8hGheF?&w+Vz1w?V047z)~x(t&GA-S-|Aaw%5NW4Lzx;_e4ov)+yQPclfbQBO^O} z6bm|jm)}JMVw>6+IE9Z%JDBYzv%DGpJWWQH@Qt*NrO$;rjLdp7H@D=n$41#(Gc(ncviG` zmthR0tl*7dQ&?DR1rXkX#l_Sb&dY$0F97t&`UryZ0g_ngIYZ356xG+Mp%`+}TyXa) zCW#^-4oef4m*jdtG+w>4lyI@ZYV31?kvQtAeZ5$jK!`YXM)nA)T&ZsE(dx?cPsG0& zJ3$cN2}GB!a5WHdp60XkM5zrL12mC92nUbC86momoQtw^U9X^lqYWrtb|QAEan`B* zet~I44r;aG7^{?0F9wc_+5aNRLkK}5GR_eb0?JO!B#BT&bPVczDrEg4GX>!BX(Zd2 zb`mZ+;N4u8QBZaHBhg_#QkR#>lhp84<_ZO>QT^OU{*KN+7@$HN0o9y<<`QE`!y;xJ zhe0<88I40cw{r=+2w0Nn5kX+s=Ok1?=5T)zoCL@tz^h48IEYvb494OZ)Bt4^;OljB zeB+y+)XLEzM6Li9%}Y&i{invUUE&-D3hUV9K&c(Ge=!_Enway^5MK%&8pqgBXnh|v zR?`(F7o+-|RF~TG9qxAwV(2n57W#)#OUa9NHNE2Rv*_NN1t>wADQ1%Wv`nF*8%nSU zn2r%qnn}@Y!NMRGC%p_~#7_gytg?(i#1D`OO#p0Sw8dU zhDvVWany;}l*}VCMdJXYmsyL=(>Z9|a=8iSMNGm^04o_DMTOn z&;{uw$lz?@6Mcp$xZrGGoE~dndkf9LoT-c2fid!27&orPVDEZbkN=ZYviw~dCDsfB zb}4v$DVo<;DcF26`q{S3L{pQSr4d)5-8`BWhv&RNOb}0Ii?d=9X*PC!@!;oPX9@&N z|8%)W%dt#kI3)Q4$r2Azh#>u5(0L=rk$};R{sT&|^2$5ft~2?q!>-lL@I!c2-N96{ z!c6!;pmm(3DK$>F%o>Bh+)fp-*DzoMmNH2u&^zbzQQj!%fABD=nwDe2(fk;3{caKV zM2&EiuLmgxtnfe|DJ8RGOaj4!$M zR^STi5g6*2+&rck2TbJEAfapC0YhI7%1nXrxpk<7?-rDM?o2c{B4Pu+U=xPnj=Ka% zI$wzwxg+_2vkCTQ;wSpIi;FYy8YFc4z&e$US^0&`Ig&|n8Bch~7RG5ZxPgutR7uH9 zwGW9A(h)ni>b?w`L#&|a7w`x`xk^uTc?!rSYrYiIa)3YqCvnFS8$qzom8Dsn=m)sI zzcCDk#n0|I$CZwZ@3#PxB7>_$4eeN`9CG8E$~uPpE~+QF7b6r)Q zzBU+ntWv-7sJ(D6-dxU4p9Rt&VhiAXKzaayu3T*%P)hmLQc=8&Yv}LNKAL?0SdZ}K zVlo2>KCHPKd8qnTPT)hUkR~$vX)dS124J~XVJI=_4)&cS=D^Yo>Z42A8pRdk5tWVS zoD!S{IZQf``H@7HR&w70E691yL`|cQUJgpW`&dv55lFtoUtCk%C6AGK4-x4zM-D2h zs|6!3V@-7BfQAH9A^E4vhOi?7eGWw7A&uo$qN7YwM#lxxR9H?C!84}sd5_ldu-u=aDA-A`jVN#aR0^3a)z z^@aclyqY1x1oHBSdGFSfbWePUILEkUEqF#-D>I#;T$%|cBvV@PThML#DKI;^?9p01 z)}ZAlfLlaL?~9cjPK9<1MvsdZ3So~nLmB2$>re3J)@Cm5<0Y=%aDijA3P;Jdz*uxL zr56tycqD}6G>Xn389&GfQVn%EOa+*Dqh((4xMcIJdDYYg(jbFIa)d*T57o`gPs8ty zWf0;S_%#}ON(6~}!r!^c7%-5X^G$G>FBv~duAn`>IkgG#kP`ClILL$L-qQ-<{z!W0 zNjn>1nj!UUMu0n5zZIaU2o-}P{rrR$U|RLHa*~wTM^YI7%tOPVPSL&tc=7Iu$pHOa z6uM6ES`<~i2IH5IgcS^6GVdG(ci73}SbBO#0Q;3*SZa5N?oB`0GWFuZSFOT% z@SuNDY0G}nDP)`bqzmYp@uDl}n)9aH@0#;L>Ja>y%{~1+4xay&Pu;pIN?q3TRb4aT zw%7wbv_iQ9DiMCR4JtEQz747}YN-dnTIVlcX(z8Ta|h2j96!>s0+`lz^8CDLU`ZkS z{rmIZ-@>7A%+o%Al}&L^7eo!25Tm2PVrMA`FZ>sv+X;a8FQ7v{Ju`s{=Nz>Y0vOJa zsO|>50z&Je<5&P7<#Q>fl2Bc8 z&>NdiX|IYYco9YRS5a!(@lU8-9v9DTWcbBdVXr%BEa1x;GN~wwd|bwRwflDzbV27< zY7L||_@P;GY|TVX1^r%Zl>Daq^&xFqQIuDYkI(mt>H z%gioXJODG#N-aW29deED^V^D#PvtD{WcZ^!XD;;7SN+hGe`jv@#xKh#&|3UIiLogN z=iA0~Bv}z(ruD$TKernOz;MqTNP_PpFw!;Np@Y;IY=|m}ePFKfE~h+AFLL2Z{ACjR z;3o}BO2(GZjh zh9Bc9%FaukuJuNx?4E%}NUhNjn(8QIh$jP2z{7Z*(iXp`dUqEjd{Geh2M4sq8mI~d z&o>&ETT;eV*7D`N?$7!RPc6j14`>_@!$UYH?xfm#V6g7!E~T=vk)9h)J3PNa%=PDm zsnS9S>xU8*x!gLnq3U{}3Iir#MLMN4#e!6kq6pw3lUqs;BXF#Sr&B;t;CzLqJRw~l zP(2YuMBcUqAiCDb=)ZD~q)UxCh|g?yF*B9LND6KkK1iY&H2%|wLoGwDTS_my$-1|z zysr4xSX<0^mqPDYURq4R4S@L-d8OQ?w2%?*_@^_Zw8vY3h%Q6N6-W1kUd%`Mq5VX( zGqWfZN0#vK&#r^T*j+=|ZrhcUWK*MMA7Y|^Kf>TyCa&Hu={ih!$WjKY#4s;}L!*T6 zues%IfVV5Q)+hJ&utwqCq<;)g66$B6elA1pLRZnm6H=r zBPB5qO-?Qaid_Uo+AxPBu6u@&AylSs;Im^$wZIcg*QG%50rtpJ!fF%gY8Ortn0LtW zudRZI<=2+HWV=UE2OKaEvvX7ie<0aT7wk%=X^1CKa*^9Ho}^<9-dEhHI!&BrUs84? z2PEdpWw@UYg{w}}r2u9?y~19|P=h*zVfOQ$ark&ELyXB%dMXPqGmk5CbPx3*;bOnI z@$E@{H9^iZ$!uX@Wn$r(AQ0X6&iP88N>52+CEV^9eQiT#g@Ws^u#0oOmB9T!wOWK%8m_Wo{E~paFvPCz)U{O| z+?CP4NNjonA@zmggyDKV3i>LQb6{b3*6#FP;PQ>Ric8Tb3xSSWIRvOydySzgQ7wQb zzSCeh!((s=7QSZ@j+jceGH-C4a>R9YdX1vG)3L2Nacgo}@iS8NHAuC8bY3E85asip zOF%QQccwYxio0E~*cexQ-ohcPEr(DxZ&LNUNngUwcH8)x)Yrqw@9E<5e7e7XeLQM> zs7(K5FMJ)*pH;CoC(L~q+Jtf%nZSLuUyTjc92esznYd472tg3{5orZz=l2{|m;ON> z8tyrHPqnLZEjGaL$ZR<*y{=xLd^8kUgOZaIxRobv?p|)WY>kq<(c-WOXg(ZGZMmL$ zkB2t9A^MRpjzhg%Qnhs)@DwOo5^^r^JCS8On&x-K!k_r^ji3+~KAQ0MDqR~r+w=kj z=Pv|<-O$hCwnj20s z)}r_u_kOjvuv*nnPqn0=K;2)wIl34!r86f*-U5E$2z!r}mIK7u&I)^VmMXGBlV)Ip zs^m^9g(!#^vAWS=V#d@_1kaqxm)D$*o>2{7UgymPzUB%a#IwgW)klj&;-jii@snK! z=)3`H*g3D$w&bMD;rm>3I_ga7lqN z?FEcF!{JiTVdSQNtnYh2(u@{C*`*=H2~!5l3)vFX63`tdW{c^f zry^dBB~nBN_((GMtv-7a@tuRbJ9gq>=2pTT63%IY;%KD$vHjF3)jf1B-7j4VXs1*e z{>`pH-(DKmdxMb38goxbVEz-~>|V|W)|znLg8kGIWTEDk7`db#wxut6MgUaLCCGA^ z;|gjWE?~Vm(nvwYm~jqMZrwPTn0mWqUw2tiq4MBQRtS}kgmWLLdk(uBQJ*vmD&At6FOyO2aKxeDQfa*K-kdY78?w@bjM@)^4^n4dX|S~?TEMN zSJXT(d)G*v3w4s{`0&F7c$^ZF`*ggIN97y@X_yZxlwAEP&vcbLC@W!z%qLay# z9~Yb5R3kY;&e|+zo7=Onmlv1iE7`NfW486pMKW({_nXgm-7s=>MC3akG*YqC+!asY zO2ln0tpyX=($3$J2w^y1}`mVu@x6~ zh|^|ghxn$O!tYql{_d@DDGd7$CG-zB7N`_)l5}0_auv!lMd#Wjt}9o^U;><~;Vd#& zmUDrMm)J-k`$K->Sh#pky&b1HpI}*_%^H!j0^&DF`a8NyNeE|z)PBbPOTAFr5~8&S zJxSXzPJ9n{^>3yj*~MKS(r;7|C3q_Xwg7d3;tJ8pwFass3o@`NEEO3jywz5Yrm35E z>70qP<&HHJDsGra0mwU91eI3drXAxa>;BYy>H)kOawc9TZl#!b3SzrpOxL5^|VrRS)w5w;3_iTqv5 zpv**cq5UR~md+UM6XUTbT~Xn8!D6!HnrOi2>YgE$0scIHgHR&Rv8)|D_HZS1Atfmz zL{{in!u8S|0k#X7Ud>UF($pU>d~COA_Vkrtb1RybhESl%*iTt9V~D>rCv4X=JJIFmAQp;AdvuU1iHrX_Jrk%?qp}M&yaA$`vo;?>ZaSZjTC2a(j z1KXHvbo9nRr>5820qE>8Z}BM-L$dcEz1Th@Y>|HTCG2#BQ~~u{O_*K-U_W$`e!w3U z%kYMG4o;;XTi_*rgmFcHgG^VJ`xqs+h{B8#_&A4|fgDpe^~qSdM(fWRwps-!b=48 z86Gl&g273@_&J+-rXvy#{zC$g1x$sG0}J9lnnIOp9ucgWCh>Ux<@igxxHTG|HFcx! zC_^n({&JPFd5WfsEsRZQPn#&wquRLTDKRi(X9Ui4R&B8`EMVP^_n-9-;|Rk$B1y+cU7zZC7Egc$fK3 zvi=zEhH@yTImRrKB$fDP(4-i8Ao|aO3ZQML{oFP;_f7Vu3?MgJ1WDPghFm5l~r*n z3J28I9dYh(zM_r+L~1U~o&+qJgB}Kb zKldjjEmr1eMg_?{GUISes_=)xPv0Nr{PX=`$+5#_u$3IYq8GkD^kzYHq@R~ua+}R( zvN}#TCdr6IDd$CWEbcT=*GZd9LS{IK^qWc>h0P%k(W~8Wi<9C{zeL%q_8tDzWZD^C z2oFS`pn29^PiqYd+~Au((Fex?3qEy)^bOSkyXwAU-Sdn7>9v=BO4pmC*X#9O9~{7c zd%a%nzq_yYb`QSUJveyPd$qg&>R|Vq-tOyzUhf;!+tebfK694hV_xBx@ z6k&_}uI=nr+U*6@9H?72;SfYBOBu0{J*vRs z>TM4l@fSY;l?JzD2Rd_U8PovADDI-E+FRo`@I}$>TPOpltIX5L>}nR+Z)aDl*V;IF zaC+v_KBw)MFVUrt_lE?UH(1Y6iTN-(3918y}FCmdnk~Z4%gHejw@NK(nX=>)Stkuy*&$rP7 zih{`J*gN2BMo5%>+TgTMajI(0){nBbnaY(4g1~Sg%kc%#1W>|7tx*~xF8Dx;PA9X4 zawaHWfL>-7{rnkqLWJYkv*k3XOc;&Gn|wC_=SU?F7KyR==}}58pA6>{3p5il{$)d` z(g6K8zX8z252*jsDZ0Ek`5)Bjpdn_{R_iQ6H1SCybh|=`BzEyVoibM#4wQM9VMR&;vY2vu`Zn`la~nNC zG1%7!sN-*EcZUS~w10eZ+<*J=^!()V;_SSC{iglJ>E>|VGtq9yT{?=@cRGlLgv2O_ zWT-s9)uK!!U?lDGox+g3bFKrEq~k;B!H`0yPURD2{RmJ?ERtWwi^L^Z)Qo zb~OP_WzxuBY)==|d3^yArO?leXaiQR19 z>@yamWX3-9e)U+2(>e37?)`9BgHrT${3S7Gz+46 zYE)FRa!;LIN`05sa(L1NgV5iE2m2I?NThRNt2;z5EXI4=^nl(q#@!2x#I8@T-k%*i zsI2kS%^7|tYj=MS{|`x#&=!{>KOsexW+ovO7Jz!&aMQ^PPu>A-{{PjqkgacRu3b(< z#xt(+SS$SU0Xt)w+~LG;hGcd->NZC7x(i(!Q|SLx?aA)mcV5rydAsZ1qb>6>xuzV{ zYN40>$<4nO{^Q~oc(M!qDfY$NZye$Y8gx2yMiRuumBZ&;4*6)wPy@3P0pE3XFL+Sn z+k8Wc>g+O=QX(EvN&q^vj%#t6Kdh+c+8Yc1VsAaro{)ZmBPO@Cs`Z?aqj^gEZ?BCl z<9{{Vu@T`XF9-?J4k}%ZZ~AXdzJ5h?)|mK z8q9|t0K|XOfEXgIi9+5+y95GX&Q`bbfIpLkF=p-BBYoojZY(rp`UqeYCp4D1EJ0Y6 z9{z@K3&tA}U4T7wI`Ile#eNwmV^3pAwzoEiYI+F7wii{i262dT%65x}1cTSwU930u zL3=f|N7x&2F}Cquo7?WvO5Nck3Ze<~5>Y_Ak0;q}Dqg_~h0F9TNfuHV3mzb#AjK&W zedQYj-Yzn5z*ibl{&)d3S4XvAIx?g9u*rVoV|Fr90G<9y7uGh~ifHQk-HH_1hS}r; zOfBLx9a#%8w0}R7MY~)p+!hOITdQr40}}Edi#I~sHM^eq4Z<Jav;~A!v9RqT0AJe{_V4(qwEupbk}xI-^U^q6V~!g8@4=3ek@EaCvnlp};(UcsbmtAq$bziowNIFjo`iIW!|ZGE_cqG0)iQ`PV9}P+b_C6Gd2N?0ujF=K zd%1mjUVG(6Ht>X| zbVS3Fl|o8z*`#gCI+m!yTNPe@s&SlfIlm3!dNu^SmmE#nPPw4bdQ=|u>J`ak>a}Ys zdCxxfs<;TAdnU*#yCv(h)b5#FHN+$FEtjL(ma@ZAKp1`CIbn1{;<1W^cI5c#VNo2`SkDbr7;Yir}VgFsHLCnOT5_4mEhdm*jPya>X+;O>B-0Aqa5TbYo9vO z)}e`DjN0F_wzUf`dXP_uCS+KnOeuvRzZn+cE-`=cxl#aPyBvy94g%F^ndh|X=bivN zMt2>(%44W1z#5qf#9uQUmvI;MyLcWtn2UCLS1n7?w3WtTMK|NIqS;Pyn2rU18*SyU zsDi3wdkG{Zb3rv3UXbt=Hu8qZD1}`H||`Z0w+N=-218nBe11>gCwf76Pm0wIfPP2NkDFi zFYK+-0Lxo@l{i#yV^CdGF-8|Q>KYh>+qZN>bi4W&ul#Yj@?^b+TKQ6p!aaKk`Vk%76t9qW{>4^3vPNu zYZlS`xHcWA!O`vfc9(WwyiFcr$Ad_PqpJWZ2(+qr&^iOEqOz;6K>%E%yRgAH`ODFO zqArm`BM|BaX?Qss(ap_vw)ViNG&(vUuRM|q;uHI?~mS|ogDSgF3u1C5y3-4b$S4LsK3zAd$~|m zWI<()=vaAapbDpsUpT^)BaI z!|wDqgrwy+I}gs<`)yX2QVURs1o-m|Zs|QPa>$Y$EzLt@ZK$IPmAQlYK?H)=Sfss2 zq*#+n?v(>B2!|@)npN#TmG(ca-tZQ9wz>td+Wyzu-G7yj|NQRNcdwu9e~%Df?QZKPi2OsD)#x3LTQibkAE%HHRHR0@zh6@)2k!?X1*F>z@B#fk zrzsJwb-2C5ok6BARAtQC$ScO272e09uS_LrHmMIuL(Z5qYe2&b0y!e!ve&G3LMeb| zX2TL;b5^c{^+7c!sDamjR*{0%5POSRc!(Z4o4}x{7Oe!y0O)IGSXR`kxPDj)3?e37ISl`PWCa+;~7K<+c^7m>Rzqk8pOnF@FJkf9dmpJL$nh|XdfK`nmcL>Zmx&UQ&cO>5%K z5mD3WOQQ4h7_kn7_?Y{%%=)dQfYv0rWPSG?gi`ua! z^+b{B@K@~s>E)Ri$|`=UZ8mswgR-j@%QrtdfdR^WI;cAgqOOkOwtwr$IwJPB4~6d# z8cpe4ggRHqRV66D3AzTa3`DHhSXF)a^JmnxQ%#rCZvnil=C4kduRggWQ&9`Dh}0~- z>smQjs^%=?_OFZ3IL{dWi1FXid6Y620SNL|$n6-(EbR|uExg3(^w7N(P5?$VrwV)` z-1jr8I8&>gpyubLAVOBNli~pNJhg1h8qT`R&KK^J32eB+?Nbu?^_1>dNkm! zH5PXv2XjNR{dj$Tbb0;LMgQYZXV?9UtG|DId-m?EUkPgcquf;{qK2%R$I@40T)E^| zoTH5dnb#a<6$J1_z_3Hpi;z^{vn(vT8mVv3PS5)Sw@1J9f2vqimZ!0Fv|O;k<}p+g z-tER$-bJot#5z>{K^Nz`Zfk#9C-q1rlB{T(G8FwFOIsH|!j1K3vbZ8+cMC(+Tot$O zfKz;+ig8J2%R9UDa%v`_))nQbeT6mE(dClRoG zfvqbh7m%>++9S!jxTt-I_Fla%;Ko6P&8SSf%cP=Kh^VYl007+R&fQ$1!lm2$S2iP8 z+JB+WdM6B6x|RvJ#{Z|c`}$Sh{`=kDlmE}7d^lZ;1a?_mS(@Mz$Sp1Ns=GqGYc&+M z9^zm41pT=`mFGVq=^agOV$db7&H`%A|Lgs|UHkm+^4f(UXhJaN}8rfk*Gn|g5Z&%$W z79r7av zZ^Cdc%PsL9kjF0*dBqop=+(X<1*;Sxhv=7+%cf2H$CuXZbe=-xJe6!(RpO#h%}N&~ zR`pg(A#<5gFU@3x#!H~S46~Rr7r= z0ty=32tO+yeL3bP^C;WLA&3g}`1L4HqScHs$z6OL=2KavC+j!1G+zyAwy?uX<+d+q zZl6wy^Q6?C7D<)o*Y7ec*)*i(lNI(I)~V%S(Uii6GsGgGa5;FT z&p@54S_wFp)Gvi-HCkU0FI9ki3Dh_U$@;3AEzd}r1S6K$vMbgXCv-;ADVa0GMhT8( z27lSBnhWmjfA`lShi!5(NKxfW-3)5@Wv+%N-NLG$%J+ZluO0jGO@sKq*ZX<>-|K_k z-qZX4F+TZwI4k>_3;1y80Im0ZT=K9Nii1n)XBA^b!C3c`zoBc$(~JL4{o;2}omCMS z`q>42O)pw!^D3k`s{e{9a>aY|lQ_Cq)3BA)7DhXV=HhYhvTFWM{TYpdlqO%&{+L`B|3~>aVifX1Xa4(``tKxF7;>q3S4g4>qKP-638BC=x;kR~QV+1fJ3zUB zRzRColW|-akQXAC-mPkk?d^YqyQTC&VqgU8>i8?c>;$>VG}V=3{{=2dzIcI$Q&~1f zYm3Db&hl7^g>#Gf_G_|xL6nl@)>K8QZ>-y}QBUXNwt9N;Z0!d#Lg$9!&HB0ykdiT0 zf@Vrghd=Rm{rq;X6(&wYCemmaI&AgTnv_^MTNzRQWv$gD1Q;LWlhfUdFAvcMj4w6w zmT-r%g_UUNKvIJ{LMc!>rIpD3oZ?`${HOIx$vh-0%YZfV-`@Ui!T$fhX=8s) z0kh^>teNXyUl%h;=sbq|t+VveLx^7t>#m|?FJS1>1$_lw$-m;K^8Oco;_S=jf9mbN zdbOAL|K0CB`Tsr2=l)S^I64yuiUv>SfPX)8K)Q&@A-ah1?{lKl1-hbS3S~USP{n!^ zmNZw=^#KiEACPEd6NN3*m5iL=$Uh3>DL$Xi&~C44s6UBex`zKl^s!8y|Ha;ayRTm5 z-+!-PJ-z=P<#XSpv_U!NHe0vwJf#q5XMf+PHzcwSW^R_MeyGehJRhf7tlaQ)H`Knk zavKqD4odgPD_v!VSW>)f%1El}!Ykh+WIJF#RaJrc13dMg^#EF!cT9= zf*KP;`rmid&tj^s2=@P$1SxrkqeaV1q#;z7?t zm@%DTpn8m44|BZx4b=5$`l;ssDNf0F9x}340)T4%|LS1xb&>x+`Tsu7XBih?lN?I? ze6MAb>nDZYzcVvVNE`+u%q%`AzdVLQj9<)O0;!sh=MKpr%L3R~EQqQ94o7%GW+X}- zDOVl8i;nZy$0@l^6P%LCV!b?{_E>crV&|sM=cQlyuo%8G&EogIXyjf28p}zk@Z5L9 zT$1*Ft@G0?oqaX<8rCKKa=*lSN`_x=UCruEsZOIQ8Qrk?tZUW%vF?*CIOXWMr%E<> z-(yBDaXLlqTphFaHjp)&;=Na|*?hJV#IADEB|t;dj!e_l7-q8mGfSQE<$65M9DPaeJqN6KJPx8DT^KAuezP8wdfbK}TG^E~2zuZ6p{j&S zb`cR)KGR^Oi#W$~^BVI(b$ceZLSz>!XaO+jD`wG0#y^+{t8c;hk{%z*>|vUd9o z?Vhh# zx2H*6tn$Rtic)=?;@sAm8JwLcb~0M)3s*NCTDcRGA}6 z_Fbze#{FtlIqo-KL*st6+8G*>OO8UBZO%diaG%)t)rA7y=orEv%f}d5zvo6V%QQ9M zhRgH5W}L2|52E z261Va@`x>zplVWn>aj~t86}@CFHSz5UAo|Lm(LgnB=k$lX25UaQe`Pl=OEnV2G33H zs5Z6!lrulizMrG>ogicI~ZtNzCyt}fo`;!O1f$A?7i zh_>rpY?>_m3RR` z_^5w&kuM=uxeM@`7MV;|3+CB&{01pY&uNq^Ayvw&if{ha>j*WjAymPG>S_nAUN>m< znnBK+D7Rcr1|RzuKcD7FKq8p@ZsSpyq=d%%x4YC)>8@CM?zg*iCr*Of&J9_-DXWYF z19!h=J1m$)of%1|)PM6W+ey>#&9{ce+<=0QiBs}3S$Jbryvosx5BLtob1o$fYcg(1 z`JxIFESSY1DMyBC;2OSegHGO`UiHtePgS+FU#{Mk@&EgK=VRsb=fiH-=53y8>UyJn z{_K?nnL`0V-Z%f|I&6^ec&7?J^_zYPt_sD7;*hWr$@`mou?daq$3mGin@^uz_fOB) z+=ZS8|JMXt6`-7*pY_j<-Ws%Vd3t))1Sabt{FUiKDlFH;m?<|(hN=c+lIFB_yOrour&1MXb=|6p zWFhoZo|VqcU#i6R{IJ*kqkcI(snU>5yZVT^qHP(|kKSzh~?$Vkr*8ZOgn6;P6-g z27Z=Rd-&XLj}G6UFkpqka`#ytZL))&2fW=pN`o+m-Uc(gK{$^2j^%&YGPR0aa5(IC z;h&ya`1bHyKd*3n9ypkXyU9xRa<%%lP_C}Y?VsEH(ry2Z1`%rSvb7qtKOx}FX8OK+QEC0eHzYWcd0m34-{V2$A>^@YD|ZQ<&pmWp`qT>qZsh30Q0pC+3XE*#?B~a-Ma>^*Jvu-f z+KO)9TN5Qar~~hufoCq9gdwU-qPT+RaSfau29)_y={>- zvkPkyYUD4!AUXfii^|m%LS~tAS1EN%yR%#sHaTITCSiVF&i7WGHSeQSJ*V7H`!LsA zS#QjzPseiXZ5ei$}~nDPEJA#6%Rzha<#)BI3l z9E4n?Y%o;5X#>ZUIZNs6tvN~+k*w#c;+SiLZYv4Feo#a5cAGyQ&F9vz7SZR%T9xW^ z!>mE}xsleQ``lQo68@DnOeL*sfb?^-ZIJdsaGl2$lyA29gM3{pWI8=!P+rVY}07>vniF$&2~l-{uXO(lO@ZvnX}R&YrKN137( zY1?34GkQzjk=c+W7m*I^=x2dpWh=7}K|-!m8s`tG>pWMS=;|{aCxoRmw$F3vPSs!0 zUoxiPj~qdOR`;zj-N-w?-K8DqPys-tt4*#SzvM2WaB+yzWKNcNZqmfoN|ftqs?`#i zcUUteNBw+DXh6zPZK+>6f+8vqZZ%&HhxJOG&0wW;sm)iZ6;!LO(8{l1Xba?is5Am+%DZA=`_GQbl@Z}fApmxXM<!?ZdPl>=MBfPoTRXyHHQLBP072|D} zxkPI(P? z`?^v>y@aq4tb=uD8Jr75d;yF*Q;+xyLpXQ9cQhLv;VSP+29P z{=~&UwU@F8nYO2H(nCmHqG&-v#^RKQ)I9zo&(Kkbb#{6y8Po;v> zNsRO98<7j=Wk?+nSBU_GHkmK9Y_dkVzY6EX%v|S4>WnO(WhV$(7yGn|%B?PU3ddp1 zrHWQx+6kj2#E!JlCP2k((Y1TV3R%L8T&bJeEmo5(tY)i_%L74T!yAQ|WqI0+S)HJu z_9Uc39A-a?zqbpA6E!&uKvT`cdzyf`M>v`>OVcor>d?~ZJ~t~ z(kVYB_SQVKkfT@yJmN5(;#_%OnJQT$H^ z!$8i7k^1)`I;RnTWykYj7_jL%O|ST(k9L2yZBH5;uzEHlC`(SeT)~NC~^jU`0YIAJ=fiD_r04l5Th@P9`K3ZgjbE9cWjf zRZWpz<(FT9rIKk@L3ka+4bZLq50^%^?R{vXT8>#Q{?%p1KPVNQ>hAw_YyW;zfB(Ne z*v;4feSNU^RR8HwJ|)Muq^N&03E`>6$J(Mm$+moyQ8bs2JB zI=9i;afKO${mVJ8_-Q@Iw(41{nX0uK<4I#kt62aah~C9{OWq3w#iN!)*GR@w`zWx_ zRwWC|I8)<8XrIEZ(uG8F=+edH8$d1y(>|pdR3mJqd9q3F-I=V)ZWb4G(L4-WPBpEI zg!q%9NI=f_&&uQj51O(mN(jgZ-}+;bk8?5h&uf!T!#N&_Y|5{X1Oq@ziglGN(-?Ir z;d29T;(vR~Lgo9vSc7V%IqK>^_x29*`u~I7{ipZ;V|?zHtZr7K4d6{`%>~-6?+W7OIdui1+j|2`)zg?5c%FD5fU*@Q%wIvFQwCk(gI0~)?QAkoNGbok$v6aIUC z9Q@y#l5iGGBASrR%u&Ptd#`q1<@CR=c6+-|{QogN&(I}K`O}`Elp?X~;OK;g^C0wt zXo6xqy1^5|yw)?+p9T!Ec??26Vp9@^XcE$)DBc@HlO2?h5U0T{K`~CJ#`ie#ThCBL zCeoiUPRKa;M0|7?q*L@C+a9`z!Uduc^yDC+m?S6+BI32Ylk1PyDNRW089D~0iQXSy zBR@!3%bNsg7yeg(-|~k4OuF#D>Wk^5%l}9H$!?==Hqa1{Zssu>2O(jtmma%|TQ9vK zzG=Pm(plVk`Tw<^q4zim=$xUmlT+66;)MQ2Mrq3ne1f~8T|$5RGcr!c`M)|nI(c{M z&HPQxQF;D%_YZmn`_IANll|v$KL7n6olXbgIPS>YNa@H&ozDNXTF=D4<>~j)aDl!T zfjO-frxO$~gpnVxGzo_Dl=$d|EIJ_IfKMDjK4HNmB0lFV!n7MM)K56Y2#*rV_#jdb z?jbeqUEuS!b4Gj=L?}+EKZpFah(-vDnsbPbQIImuZvs)HezAiC?POJXg@#*M>Bpu#<8~G#->4M_`s0V%c zS$o!GgIV4-+lnI5oGB0T4?mG`mbK^0^VoD-5doS(5%|PwwInHs6)-fy5gHOf%W&1f z{5Xztv-58}pWJr0(U>MC)O_D(y2d=;ehv#d7UKtzf|hxJ%*%v;XFCg0!dk5k%GQf^ zz1_e5XR9Ly*!T9l9{=m|JwIZ%0e{w!MBVR-Oy~Rw6E1-0qj7>+n#@P(JRx%HV2c%+ z0H{{0PxanI&;x8HtX`0}pan?QHpqx$aQHRouRkS>sMvcZ5ieK~6&NrOs0c&iM(I?o z&>O)7K3w7i&j{a_U$>sc`j2hS3*mrrR>DMhg8mhyQ=BTAQKJ$c`SV0<04zvM(`x+> zdik;+#4leSqPGD{5nroZD3i2107USq#8LYt3d(kDu72wJ;P?(do7-a$rE{lbx2%Uo zutF~qX%!e!lwqQl&SDyoC}jvUMn?fo)se|)h>szrVJ0a_%GYS*e?CJ$f)lZU-B#-X zL8@ct=K-A%kywH6PLt0Af`>eMXg#1#*#}kpR^0=}9SB!wQA_5EO!$Sn7>L>B0#AV5 zi86F3kxkt24%+PjDvoPZgC7*e)g#K-8qmog%n*(cP7=J}<9_%xH?H&qhmyDhWWjrF z`~=MIQio6=5ks-XwrzODhDwRO;f5~1pG$qz<{RHskiqg)uoB6b-|)@gH;Yu*4Q$|l zpvj0x`-^!DZ$)dgCHM#26eAo95i1}}#RxHyZdc$&Y@CgoL1fsL23GUy6!=?8`R1kp z4*641S)rUdLZtN6XzMQEJRS$&QdhWPw#%SVBjq77q2Xy1jfa#fsiGhPEe8!S*&J@%c_%p+KZSpytO1%) zpP((iS8+mzgg>;xkV_hVz=Xpezh6`1zE%z73Ghj@t)YQZhl5IJx0nho%<__BQr(_1P*`nB9VoFHPRSG3Tt*o>L9tYz6=>>FP<59yHQx>GO3`z^e zs2P1M4Ws!G8Wdqn@uUoeMHo{&**J(C#(nRVchK?4Fu+k~cej)54@?-ds>%)U$Qz?r zcrR`e#^Izu)ihf}sKbvXW0YVa&vAh*Ov zdAex{Tzul!Ts_|l^uZ7$mqBG!`Z!!xe`nUi6TVF1!4#v!FVo(cXo;DlPQ#!-^gooh* z$@Adk3`>BK!>6-s&*wh; zn2dt4&WkWpz1AVWjI?FkA=jqCHluxbweDhbg#lpRfK&Bz#7At6{0JrNe*M0 zU__$ZAfXYMV{UO0@T1A39)%Hb?@~a^EnNb}QXQ#X{jdD(s(3gl;?v;fM6HCcU@5_; zDIQ%CPbrMo1(|1c0Bc~>w!oSZPBNb=xr@pexix2GJP(C`x{!QCDI1}fX660}IT%a# zT3ZO0hLQK&5P(%M8fHYeH^%djQ~pXO#r%@KlzDMEN13Iqe;fIf`Olc;ftu;LAJDnJ zF=3zN5T+Zz>X;nt=AJSf$a(DJlw79?PRV3ZrSZ)M`UUzRCOd)BcSkuMa*|3Zx}xAF zD4Ws*UC5NU1=%eJq}5TH>|*M_(@v~aRy$*$OKN$(O6#4{73IohY12!NB5;lG6%lDb+y$mc>K)O6W?CMud;Cw(jqF;%)xr=fNg|t=#((ORx z$R<}~Q9c$L7H~f1&)!clUi@+WD`lrr!;f&DI4fi=I>Ip$zC8e29krU0-;kXE(3DReoW}xEp-Y72T3)6FIW*k zIlyW_?)G}SrQ6*YpE*os4niBiX9*@tflTJn5&MM|Nz}lk?(D*+9^eaN66QFk(N*3q zycCdffHg6xlX!a}JZGB-b~1cN)~FNx>%&#oS;eJ4a*S$JSTD4D0jr5n$ zYNOC)K(gy_T@kDTkZxvPS9QC1Eta3|b>S{K-Bsnh%MOm?bZ-c&aCg@N z+2DA)Pxoe^EIBwewZol?b@%Ds1enc$Y;e5GPWOg@be(Qj+3`B{zdYS$*VSNh0qF`G zsH-jRlFZ9b_quRDph2$=lTEH}_vzjcR!dHIMOpMx0mF5=Hv?tK!Ktj2Uc!Rhr+X7% zmN4_m!tf9rAA2BcZxt*JWt0(AP|g2SZgQP_CGfI&6^?E8UeqDr}Hn|C@7wrO44zUS1OMr~2UyKv21JVd0ZANQL0O>k7G4+d~wKW3?qqE2xxLGL6fmC^; zA)u(<;v`HYSmnl!p_hlwAkmeNf-xGX9|tI42!73bnhY2nrvpS2G??NnBBUfv8MZqO zmH<=&8KpsIJuBnI;+?NI;TF#qf*8~tO;dVG<*@r8&YW$lRyGVf+JH( zMTWIH5F31&11Z*7;q_twDcWuf&Jq@s4b=4WfOJB6ezIdupo|5RXxUg_H;}H=%`tf` zQx-QiC2LHw4Z~Riq^vX6l#`3+L)K^WK)SZuaMb!S!6R~6`xbjZ@>k(aNqrO%;saey z_y{7+gBo{T-%4?JkEX<*ha@?7`g}SEGTlIL{=$$R18vcCN)nV#aioOJ#?B-aK*mWx z!F&^9#u@=?1F8BWsP`#du^`peaIunr;Q}(5NBkk%9L5}wvcD6?nEG4I-Et~`OleF* zI$2!D{GoD8BbFvOs1knp!4Z9s=!A@3YaXOBQEiE8%L6$O7m^biGL?^iO7GC+`(p-K z>wH-uS*EAr*w)?&Ahn}w>7Q|3^v@{K1ua=m8H51Q(s1`3k}19oXd+y(M8*wp!$CTE zApg>Y4l08C^AYiLKwgp5Ogpk1kg|sKpb|)Mpv7?<283l0=YUhVc5in9NZ~0atM&*- zg?U1j_Z0ggo?*62STlF9FXH}X4=OpgQ9_|iYj5P6k+sl3R9p`y16{6RU_(-_wtY}x zH9~i%YKV%W5OW+tq0AK^F-$NPB%=(%LMHQ?vzrjqr#55Wpi}0J{*;h*rn0z z-N}_rvz;v^-nXb!*X^KDNaw!P*##rFB-IcSv%DFO#s5lMO6M@C)=4J7uh^E zt8g~RcRH27p|i_PGzxB2cEuVV|6T!A-J^MtO&Z?-IT~NE^`vwT18N*=4&332)@$ z_Rdmsg91(%Nz)*jWC+Pu)LRiJLcr9iJ4Z{%mg~!u?qp@vg5>%Fq_6HZ!og#QXc)T6Fh(tpuP<9d|UP&lgVOl%o>Vsn*nRyk7)T{MKc180PrnS#z zQMu1)?(+Td5__9hO}VE9Q|mkG6ESUZwMW7j3r!kL`=NbBu>ZFtNXbPsBJE!X4kQQv zG+(T+GKJPF;gp#f3n0(Euvb+~`hZbHhyYuhFh%kDW6u*gdiqkW1Nq}EMuExqm+@lQz1h^4T8H! z3fB|xwO4w*jDBu)LgpErM`=uh2tpqQ+MWDRd-|886j1bBgx!_1QF!(kK#Ojj*dWF) zkiM}bZDT#`W-iC(ux~W2qmj;0l|X>nJcDZ3?HrHIVc%%F#|Jdn-Oc5Al)qHLZs&e% z4*N#aK$fI`Yyx|h6Eb@c%d!>q`PMh_DG4zxhusxU(FE_RA5!5I8-d+%c{PGPi?Ub_ zcGd5T!Y(e~bCTZC#N1~u66Tf_vaFkx@%pSS!Zc16*zF2By2$CJqKD)sCqM2 z_><_%!ebmeA#W?kl#s_$z58tq$q9{Kq(BfsqSHbNb2sEAqfsO(d^o3+g1l>${6&2h zO%lRb?lwR2ed!Msh~H5%m$?u4b#1S>Fr_@_WmBFOXZ(Uw%F)iR-({6~<)bxAbT1@Y zkyoDHX=Mf^@er0!T^N+9DdnlEn(~tR)~v!aC0uP0M2uH?m?&>2amWX|+@RDP6= zINDjjn>Sh>_;)no@^Q%~JfLG?z`E2e(UrP&!FhU=;F!N@)ha|@jcj=rkd}xp8;_X* zUxj%Eygv6i#+(%*4kC0n4MtNF@d0O=5u{c5A|DQ`05FIqgHqswC?&})4)ZMDG{mSj z2&Zx#3g2u>=b;a2A^29fEzqk0zu#lFlGOpcm{f)+4BWuWI0uBsDM=*wpy`CZd>csQ zZw&AyfX^IpP481nJ*#dXqwW`|&KWh1gjK0yL~ltV+*b@*TMqap2bPVd#Fg~#8opOq z%&jx}2%iTun5Jnwr~y6=nV}HRIzy^NE2$M=Td#s}QUN6g(@sLGVYvkOCYVnMP(=_~ z*@zxYK(Z!MF8lJI+>6l$UPE>@4_yumn$Kf%6`FTnTK&-$4jEMU@= zApztJwyXKP-KEIuO+H_|Ujbr$XKhLMJS{29n)TTbOSzjV%$th%D&UJ8r!lv&7ql^k zQ%Uo#&9XZiGXh*b0kf6!dA0dZf#!vze;whNO(_`G)=a*&IibIx^SoD3%&&qKty8JiLx{YHmOWH3!@>edxv zL2IxhSNW3#Rv}Mah71kF4odMvR=D;{{oD59kQZa5M)VC(;-C4vRdOTA_0#I8C@R2gi0xum^FuD6H~%K!ZKYRiOeL!xhDj z*?7n~p}@;avz}^Si2^v$*rEd^ok?deJQB|S>j-FTif1cXQZ^!rkwf)O9*sw-=*$=mya!oclyqq|d{VGk@f!4l5&{ zo$td&v#M3+%pezFDQR%%)_(fv(^Yo3)_%_D0i;KkKP;S_BGrH>a}uy*E>`ya+@Fy0 zGo$H7PcaLkqgxz=d^mCazYC&ZHlN9C{N0!&BNC;Yi_)>U<={y#b+rkB(#J|H_8||; z?zf6EVG8`|mk4K*JfL^@Qpa~+M@GK6=POCK-3`R6!G$gI( z$ZUybi;gO?{ErqwVm@~b#5cmxLRaQ9OQZ4`TCM(+AUveESz%;GWPJpXon;-w?83=v z{0;2E2VSf7Kj{3Te|m^6q7gyqG+<~n#fc2^5;e4UPyl~NG(|CGEZ`{S%ny9GU}A_D z6J=mtFeJPo&5DOR{FO0981$Hla3Y~uQAf6evI_4W>YHOTYjmrOqENACb&+>uTpGgB zqUbip(AMR9wyia(P)7;Y%5j*Gj!cLhq&teC7ne4i2VvR?B82@Je=Mb3(!1s8P+^IR z2)$P8CqV>fz#jm~DXc?w55#S`}H)-+9HcG&Iubi_Ofs5hdsZkAG{ zJEeD>ly>KlPZE~m$nPX#zz!dyW3=3Ewa$RDS(?yj5-vbJFq;VjjkGBQ76|db zb5YgBr~~1l{uInRY@QH?7IbbBC-Nx~XGqevU6Cq~G6vM}#}f{fNTn_V7claJ@t7oh zB;mQ$YJD#dAk?F3H?dGn0b#=k9F_cuXjT*-%VxLykO)r|K09z~-EK$JgB%AV9BEHY zI2)rR0JzcZJd8+!hd~&mfvWK2iG5V@c9w-hurCF;h91gEeADMe5xRG>ev0`gj|D>5dD(v5!*fcSI-{2suqptu_y zO3@9Xae`Tz%tw4)I5^!2NjsoHBfd$B^1O5`q;$7MNgz=INa%&&oD9K`7>1G$%3~t& zs}kd>ti{UFTcEgzS~aDjs4E(h&Jc5iD~2t?s{yC|x7Vt!o2bUhQJL^thtrap)N8dq zyd^k^1n>f24UsHdzfruJe3wRDp#?)2TXF`bc?Y@fIS4T~YrHA+cbuFu^FHjG5I1I0^JM zW@jS%6h_EI=fE!A4i!_h|F!4NzDdVj0Y|QyB zr&x{*k|2^KV5**y2;I@-hR*8VROs}vg;ni0;!12$tehb>g15_6QA zGlpa=IF&Sp1kuFF2ZjK3S3#`V@*}VXF?B~yt?>wsRZv*SaIF%EQywNFb}-8sBAKW9 zS{8Vc&L@@;QeOYEgHI#Ef5*PBBs6J4E^3wyv!bw7zy&34WCfOX1c2+8h-)32o=PN2 z6ObeLK@i+T&FrvpJ9msI{HSRkkAuq@^;Z32RxALUKxDtli4bQIqKPj~EEmyStql2j z2c>rui7;WoXSJ+w*lKm;RL+84hk^*e1(T`h#j@I8;zb(6)5rovMLl}Rgq*(tNqH@? z9oR=x*3MNZixV1?BwctY_s%f;VWaXFO%PT^wsbJ8do9M}IA3y1K2Mxwz9dKi;TP0k zFyIe>mf7%-zkb1S^$?x*k54`x{nEeqczp5h^60pKc5(jk>a>4)&i~ay2#IIOA!_&9 z`F=m09$odnKRxPyJUj27UcEnhYjxOt)oY8li`rhSsAOQ(w;LRyoU|nOT5HT(3dQv_@ypW$wJ5Wqm95rwz~B4w0wFOIv*1yRq`{Dj zE?m-6*UOH$an-MxBc5eNmE|r4qr|r~@cHi`(en9xGD)zXJp#!siPAX^k(5A?u(*;> zQ#@xv%1}V(t+EObKcO7@Fmy=HyfI>PezOw(qJs=k02!JDwT)m`-nmiO!na5Co9ui-X%erIj5^R_=#|oH(jS{X{&=?s9#K(ti2}BRcp4}e5I9_FP+oy323OYYMa{V4{|XVmJ)(S zP)F_#{^m%U;RU+GLMblQrlL0;{zgWr*7v&Wjsi8|IDWx$f)Y&-qcbAMGIVEB1vU#t z3Du?_#h}%2Liwp(v4k=kGq}2leY+b{`FI|NI%kZI+Y%8ray12UNZ_n^&0b3Z@e+!N zsZ5|8ky@`V0pLiKGN3qHLdMW3UyT{Fgrdgr{2_?^GKG;nyOQBQWMX-lBwwW?uoYIq zjiD1$zY|fPbf2l&Iymw>R(f47&>x9-(M-m%B^;f=5z^dRGa1PT<#;>dFLR0=;J=ZT zGdH`PrGDmvQqPR&Y-X<7p#p-fV%;<$q&owxVb|`h)*BGEtu*g_D){S;C|Sw3u9!r5 zrz~kP=v5sVZjD_Ria*r16$h3)}-d(1p_0DSQI<} zKfpn9Dn%+DffEvu1cyo+Z+7oYNjU4k1f77fIbq__hkl84C@$7h)ZqN8mVuvh1jZ|$3{&)f8Z5OQ8pfr%@!3u;EU!a-G8X#yWwXNVpLQWL=2B~G0#xzL7 zIuPk$xrisM`mQ#f7{j14&#oVx8^ik1(b-utIX8x@jbkXgM6?WdtoHecc-4aC!t zOQJK9Ob9=ye8SvFYOY)z(3b=0&A?Ab3Z2my-%@Zlc2tX%5S7&xRnv%L@Iw$1E#y{C zl+*pd97WZQ9GpmnTceRJz2Ht!WhbX9=X>WZ7k73L`7862a8K)drZX7!|7aXlnpx?xGv#8G>iBd8|q|Tcvt{O9P_B zNN=qY+uE9|M^kr2z7)6dIN`(ejaypYBVC+KDh8CTBuaQ&TNv%=Bm+T|l8Jo70q=E% z)k*&cb^8eIwDf&cHVm=VJ7_phZQ};NmQ69BH$h}@xhDiAYLs@pN0M?U(%U-fG~htzc}{_IGQg^a)Lp-XU0*+DaW zLl6^{({P$;$CRgwVQW$=3kXvNNAih`=0YbQEtJ?}ZUabZA1)$v&ZVs(Nzm^84%+MO z^>)Og=5|k?y0OX)3eG;x<#R;KwLjz6)0}naxRXvvCr&7*(`{+;6VDAp+7{M6#*doH z`>$+&ikd`*bu9=1c*n4GVPeG6$u5XSG>K^@ziKa_Ox)zWg5L;Yjr(w3#V8{hDTB4P z_&_VU0u-c-gkzMD2~M<1MB(c6;;qw6sN4j>iwSJf;uR^kM9k`|Ac&1w3gz(deB9TD z!ahX@-hsD!0CqtDO}Rqd!G)6$20kv9v(iHQsNPAs8-QKu>f)mR@$%^U`fnFkCj+N- zOuaTuuf&i}7?;Z7hJkzTHjw6GLE9*p&4?f1l!WT6nvZq;%!X%Ilfx(;&fVR=_I3?S z?29wdm?a8(N2V!{XetbVicI0wR=(H3ZePCSdoxNoubeZ&IKdrVp7HD8$oH9fz)E88 zcvG2PN8k#_QU_s3%cc@yNLY&E1dq~S1g6D4)wBlraP-4pc92Jr?I;I*oOv&(k|xUZ zV>(p?sqpXP+|u-j@X$pRF62t(Q(4@avZwF0@}7~(Id@1xp@UHn3w<9P_2EKX{ld;@ zhLnmc*yVn)V?69Qu%-vi`{NzKGjy1$@FC#5FlYP7xr0XJPWywJx(~x&x$G(NX5VP! z$UOT7(*C=fu;8EM&0l^D>}lLVx%qKw!e!sg7M&5e5LI=_hqUru>O0RLW@_?2MY~HL zE>qr^QC~d}WmtoH0O~vM1v50>%xnE33F(d|H#mW-xa12cSa;dc}xCsrZF#g>c#ey9(#fhu!Yo-JOR4 zN{=R!ZYWx@?%T8D)AQ@o4oHT-2s+R*z;K~14}OS4dlY|H^7(`$~2CWOD zK_QMNb37qv!udUze9T0KIPzN%wkkFJh2?nPJbnHRKR6Cp@JR_cAOXsMi)Td_uC(Mc=l9b$ zy|w4cFYZtBG29{#TL_JCN+vW}9HKMpZP3DTATNSLbi3EWajgH`^>$x-y_TPa@*Sch z^j1E$jYk&eS&(HKybOg+ETofQgoY%&BP3E%kQ6Ds7D9b1I*MO2;=TqhK3vGRl-HWl z897Ajyr)~ih(oT1FrQ35y^BJMebx=>gfguNpW)=ji=#>FhAbeY>af+33u|?_tQV7{ z)j=tl#r(0>>Y(vF63$>9wbs@Q2br&eawkw1G(z(vY_P7D=qBfu&IEk8`kq-Eey^I# zZl#Nu93rV$Xx-*E{A-i$(`N&pTK;b+>Q<}EN_{*JN`fp|& zEu$$pL@&FaKet-ES?h|V^Mt?A`2!i5Zc|25KGeFuSISG&7DVJ3l*79*kB`tsTYfM~ zQTv80+Nk}*#YG#n#dXt0TVcRb)c*eHs?GoR|7mY;qt55gEdb~KzN74dH8b!oF+`dr z#6N)|wK6AI5KUw$a`E-4Fm%vJSV~1F5{-!R^n~2tr{Za@#AW3JdP5e6=>8sgH)Mf6 ze{N;D9jLU#ae>uRZ!gy$qMWCNPHeX1$scg&uL2Xzw+)R^3~UOB$!Oo zL$upcKXi&4ImL-zwvmnYkq_`?_fgEiyQur9`8Jx#tNJ9FNrZR)OnX_eduwc*-ZOsM z+o&y0%NN-}v3X)mP?Z)zVO=$+Tsi#OjB9wtfFxwZ9#zoGGNXzf)~FKS6}Sf$XtNN*yc{7b*p`y)0ka*k9QiEzhFD=Q@6P@_ZO2C8y~p!kDKGLt$5TL zAGF+*#Y48_5o>b5Dvs2~PSfLv8e*mmNE*gnxH&#{u)C@tD)`8NqY7q}-N782bwPT^CY(QKy*)LGnxJ%K^H9rKHZwz`r-}5EOK6+~ z;Dx0PcPgsS*NG{IkeAYHwr8=di>Jr4c8-zRElD7FJ0Yn3-@D%4Zl~8S-u&fs;BD&x z;r2#tF=h95cSusa+qThK*0#MdT*)GGa^cOelq(|G6j|S`jVtmgB@rkyn&C?V8blNC z<}V->Y!Y=UUw1R4sn(B4TSG3cHA9tZx;gY@K4%RvWOQhZq}_u@Cn_ArY@>)W{U4iQ z%Ixu&sFF+n8c34mEgK?8wJt%9x_ng8&+?y)5p=5tO_U`4bqLly@n6@T*u_pa!iAr( z_SkpV)%QooSw@bAr%HtAHRd<#-}hp|c{-&@@K2E)av2m>b>AE+kFQReB5;)WOW<#P z(!+6(k^NGrE9tp8tQ}pR$q>DUxWjRvIy6UNZxbk#rRtZbztX;&L*q}Jv}u&$5c2UK z%~J{?{YgWtPGh`;M7qB$I<>abykR-!_6oR?kO$GEd%FisYLHv#P=?mp&ds-jA&3=` zIkh3uLd3LXA$t4X{(pL{BXoxsB9}cG-ITPx!@}EB$8`E=9;HF38|-`gUQYxR*e_~6 zjKuPeECnk=ky$Q(SNs0+=Qhfc2Y4!H5CpU2kY2R<%e&}`n`s?<~5C8Ay zUtfOy{Jf2}EcBoUl+x=I5=KeAJs$_ir;6IXwyx}7@w1HnSL82R&iCt^djGHe-GjXU z*Y0<_`%n7c$M`hU{{oxuPZK(yOa-r_J2nS@UH1ic$Oo^)MU~BIL9;6M(uGxLLa(_rk!4|o!!p`2zS2}gu6>XxT_&7fFjSU3fkA(QiQ}@ zmbSw=cBF`cZQI1nWr8c^H>|7RKmrSyVJANu>L7U)bdc)lp|>0WIyPGKYdVM~sx(ys zGRF?Td_)peL3%-o?r8KPMd>u5cj}Vl^GYaD2OaBwW%FHP2=7ZOe_eHjsJHu93;2M4dd%gcYS zUw!u^|2@WM3Hi^^x`-V5vOtgYBr1p>l3d_FZM21iv;lu!QJQ96b4vb6r$n?yZDGAv zB1PG4Y|o(OG^toxK+Va+H^|d-dg>>$aZFi|(vs%t$E-t&C%IPq8{T}$V4AM72 zjG!P=u3*I_yea8X>UCiJI~eB%GnGAK)c%%rzh#Hu2xm3R;{}#ot~P>^)G!qto2c|8 zah*VxNpv<7Rg2}CWho8tdP7@Ta=t@Rl*FQoghW0`F6Ut=dNHN8*{&ehIBT9GS}hot z((Ud}`EPsM8CBapDose-g31swjqf>80(cy!d0I0mP{t*gBxT~LqkR$!GrU1Kj`_Y> z-+E3$wEt>ZQ;S7e-Q+LvBLNbO(U$2)Y7Dat`;kY>VGdGjVwgpRZbMv04h{>9&Cx&M zk4RCKNWQeWIIJ%03L-C@jE$3e?on7n-VS)`iCq4w9(J53tAAS?ty+{jm&q-4w%fn~ zDOd&4IFzaZv2a@{&_J_{-YeTM_V>1c}sy%3tMQ^0!Nxq}gxsue^Tp($Gd4V`@dDCyLe6v7HJ~7C@0>o4xrwx_9?1 zN<9Q$L1MQpn#h7p+bXS@?B=1fRFn}O5|k!5V!AFwmT(lRLyN?$P*Yf`JF(PpEed={hq6sRaq$otD0i=Gg%;O=yo0vGBd9*g(RHKH|nOF8~p0Y zyTtifM*f#UyPMYk@9q}l|J~R7ub$-p$M`Iv|2JfLT~SAnL@7Iv6r-989#9O))-q0> zi9rywXWT`qRs+yzMHl#8_9@N>2IgoaW}oB#ub%w> z9_OXDiCWl#hJ!5887?-Vpk=89hUMNMQXXjfkJDUp; z|5l2K2b7RF#3O>*|Jg?EkL}eLg*D>F^DtbX-{&|C#sLu(syUoq>u*Gi4((Gu2Zx+# z7j!7~Yux17t5G~#AV<6^krObqB~f*9e$Cs0CM+hSZLf7UwksHDCwl|;L8jmWyn`D( z6#o^_R^yyEEIcF?ov0r*t#ooBh=m4?@NPaKpGVRopfSA~aB6gjQS7Tz!)krIG=O<3 zv_=#2E<rpgh;r;)1Ytey1B6D>uX_cGIsqMm%? z#)i`hn9RdsOj>bbDqC&f*l6_FQ#Cz0u9Qax@UCCiK1$9}H+`gzbmb+JdPO!T;pR*Q zdVC^6+Gg`G4LVsPqjrs~v@!(mQIW#G*X z)j_A$7hN5DauJKDP+=qG(CB*EnF&~V5yJOIWdt+{Zb_t`6>~-snSxJC8%DsWS-PD@ z#6xfm2#Z3XN>Nf_9aOO~Tffa&Dvie)`P-soxVto(2N3*c5RK`2by1$F^^2JStA!0Q zqj)k*iaG+a=vuhox62(7)kjtR_8d;3UbmSY=S$nOZ5l0zF!gNTvRdmq)PW#t=r{TM zMT$DbeoMXiZwUA?x1U(cMX6 z*?;D1D^5%Hq@Rr|ub7s00P@F2(hTE&L@9?mKKO*A2*fzJ1|!V4$S$upL4js`hPpCM zs+I}psTiYdzLYfUH>Rg!qnjaMkc4!aGEP^c#R+=g6{Qh^Bwy912~wvv1(mKN;PdH_ z>ixMTs?HFM3PYzL4-Mp~sac($b=x5(Eqn4~bs_yK_EQbebjU(?3UEya$A#TZQT>i_;PP#BYNhv#e2|69Scs{XXv+#2^6%|B=zDoYmbMcz6f+g{j|Jz%qBGuGx<^t9@<5 zs)TI%jbmV|WxBEt3tQLXIfVi$Z!4noI*CDNCYNt(t3O$g^WMm}>#O_WoimS4#jXiw z!pGd#?ma(wb+E=*b?LtbVpI$sh=k{ z?DE_hp2gfL)f#6_Ny|Q)Hbt?qW69_^6jdmxdjhRUib{a6Qudc}uX<(Ke5^q-GrPfO)^&Y#xujU`qP{-t1PPqrg^gBaMBYs7IBPax=byZWE+k||<10R1l5 zPU5&+>Z{44@>{2F+^X_Cz_>IA*L{G-=*xxPs6URPw^%52s`L5tCx;iH^S?Xbt2ElU zVBp2Fm1mxp^1TcvvJ$xg$0x~X6rswYS3T*JIxZRYE}53dTTo?nFn`Wvj9rDT4^O`_ zW;O&dLo-YhUbYsXYj*NwyhdHJ$ydBLN3Esd-ej!U-uCj#jN3BARQG0+c>;Z}G~v_;T?_3%5wrTwVUkyxK;8 zsBNHJk!}H2wrjXsMjv|o-1*#b^DMY_Mbo$1kg2Auwl|N9$-{fv%>P-QhjuGK!~DN@ zxL1n*c)q{?IRD?p(`x=FAz~?-sKMG4nzeeeD3G!uQ3%Lq3aMBMG$^rbTx7Y4!VF&8 zznf(MNjCF|II?ftq%u{vhq<3@`?C~6`7bz)y47Dlpu8e&#=k}Y*MI(FZ?Ba9`NhHG z`Hwq!T8w{vm>(0JFJGO!6%>r6KX1Kjv!_=-185a8+mvG@%(!3d*4w1V=2!Ji&;GdN zyin6{>S50yvoSx_G^_Tm=xZ|j2${Xc6Mcy(6Xsr5UBS0+FQ05*Cqop7NHNC(4^G(b zviG=}EDXk12R#aY=ak6F@nz>P1$q0jgg*5D?c28w_zH%Qqr>N*r;^+iL7G=kok729wZiQ3w-bXavIwt)sLebB8ih}Azc?6S6&nz#&+ExjW~ zr*^T_5^R**!i}3WR6_r&)tD+(oS{~-H)b2lk)Yqn;%>~?Gh0p_=VP_zi1)+a)eXyq z?S-_Mk!IRbDPG5^r&qC26YH>hhGrP)NPI*DW+ohhj=n?yC*>^c_Pp#5j5*e>{2# z%s)-3yq38|i$Y#)!_=?bc5lqId zU4TaXcdvy1?(aX||9vM<3;X|*7C(SPnh0~@3!_n_PGQ0EBC|i$98>-Zju)i=zMxbr zn(ZrVb1_p$La?186CE3L+yPEP@2<%yTFl=4RqqA=h)D=KJ@)x?`1dDY`2_C2I6Ug; zbfce+FW#NK`{xn3$a)V#Bv2qw2)3n3?j#QX_U%aiBFlXH*4+Wdxoz$Si`4~XDliO@8D^B|V-qSkyZ#0W!yCl7y@Wyq@Toj4J=020 zw$gJ-dJcB+xP<&Sd0Nc>PHfBWZvo^Sl90hA7K4WQ|HWSaurU8WKYTp@cQ;Rq`QJnW zA#h@4pJm3&t_*@qUsG7R;%k{$sZ6WV3hTfjoA@;i=CVQjd5>Ya5Rm-o5>rlxePo@r zDb^V>u^%=DKBYQ^KX}hjtJ}3vW>t~tej1pbwPX*?L7sg}nPjUEPPNx}r2AXDMlQ=- z#|JGOeW~zhvKma4rDIjO`b-GmQWfd4g&M-)2aeb|LnHiUscNp#+}9r!YO)c7ZY*Ku z8)fGg3T@`Y+LT#AnKm4r6wm#r479~FWNMGKYhN0M=%keSlR~A)K3)W`+C)W`x?39( zS)sh0Cc-itto*JzzA@W?X`TaAj)S;#U!JYEB81Y7NvsS>T#$hw`GO-1+1xoGpfPQg zl>v_@!a{D86;AvuoZK3Rip?CdV7j`8X`_+s9KhyhBsv;X3lz6pQY?iU#;EyvpV%)d_UXKTF+0Ne!iX8XWQ6}&sV|HRvw@I-c$z@ zFRrb|J#wLyAJn*w7nF(`*O57|I=NOW z>XFN@4Ks1-NX*ZT-#5Fji@(1>afAb{|G1N9CHzOq z{`A$qF*N?i`avM0SPusTa(i2k1ZlEwi3Pb$Z3qx5v$q`}WWHYuAe67G1`t{d=V)_Gjklm)$w4P=#PHI-6%LQ6CkI5BQ zvX1r75M?h`<>_9r? z0aNYwjlG#pw2=F%*jr64x5eH}wGSM7TN+&{7~!L;P3&u!R4-=s%wSyPIbf{O4TDeiI;&qgD?F3Cd`yhl8>*x5I>-wl)I{ zRWrC1I^0V%{`(i zRNE!2Fp1YLDvNuNH>V3uOwFB2m8G0^9QD+iqHf4<{K};0 zcEN_c)b9;zYFISZX;RP8mtEfloaNOQn!wWn+onQs?m>d;b+A$9ZJS>R9C zw$ZlYHA7WS7h7t~YM|AEif)Nqxx#wb@RbESN+w}T5!9HK8w5kv>mDrKqm9fSStFtS+^EYEYRPm52+&+|`FgSCLZ>`>NNsLwt1$n*n=E%v=tZ z)t@bg$kqnjou3jb%tOyoYM}d`t1VhYS@Ua!EQV6k` zNp8`l*^{I414qY+n6#ItQQ>A96OPVXk@+CdeCOuEj6=7HB+PNU9zjj}F6p;T8@n$L z**WoN1#MdpJLi_H$F}oRaBah_u+3{EoS}61O?YT-Gx#7R`jbHpK{Al zuI)KHf$K2|wvEjI{_`d1KkqIriAuBM7W!XVp96NeE03Mj^UK$E3!AH}*TPPX?Ijy9 z*MhFNb`+^yY<}QTUGwgUmFnFv81LJE`re;a{eO3rYeE4U{Qu{N2Sxw?#s0yINB{pW zo>km`;||L*%F!R9vahdgcU4{u>=Q~xdwX(n*)E!V>7~Ewr%s)(p9V7+6REeiXUyc9 z*81yht)I5GjLBDL>FH~aD|u7Zh4K~11u=lwS?p~ut3i&diMiHVP-}@Os>#??g^6RK z_;Waoa;F_LXRiiN$;^scJf*r_4#tQe1_cUtmp^7{Zh>!VUl%idGsJ{Y!0IOI;~ti< z>$9aw-x%$u=vdBSYStc($++Y$WIF7pg0A(8%pLg^*Gn&F-lke+ubf{v+MD}S+m}x9 zih{-=Ii2_1vY9pP{P{R&?sm`=T#ZugpqKBSEvhcSb^7N3$+CyB@<2v@n?ac$J4MWL z)r;D*5m$G(Qk&GaV-7~u>A1L)-^rYxu04e5{8HZSo|X2wpUhx-VpI+Xvy|nEjFC7= z7(*lj6+4|Ga05x0&KzdODBvfyr8=&ukFMxzGW!Ub8zfmnM&`qStIS;vbP=uEN1w@O zVxtlN#y^t^Pe(VdDVLHn9Pqm}fnIq8Kv)0tZ~SR_T1zizhG7Vv_IlDRlJ3^aC$hMi z1tb-ague8`GS$eW@BC&NSmMOP@M{|Fe}96aDIOEb(5h`T*#CPk_6zs__J25h@x!D2 ze;3adIEO;cR9xz|ma|-T2pA?f3gs*w!{8c@5%;|nQ1M4NaJ6RPaB#K6p=}IiN&+DM4k9K$E;^6biZb$>ZD`<=Zz8mSHzZpH+l4ZII{~j}% z#Bxf}x&R{V)C(8+AiD7L?78fF;~CV%qcrI^8vY%f?iTL&zuI6ClY4X~T1n#L`Yp zODVcwj6d3TXMOJ)lkf;g4<3(yhOswA0!r&ylB@}?aGB%_?vIiv(y@?gN85fioomww zbbdlnM8PM@qOhZh*xCYTL@*jAY8%4y)FiD9k(kjL4iN{?^4#KivR^S`9NbKBFaZH1 z(gafQzdGnJLlKPuK{rMoAd!Z()`pV&yLOQPQ%K+#G2ioE<;0n5K+X8Syh(-##xc)o zyEeZlacGqZQ5@0vR2qlUSk=|5f6@_9nt7t@#{>jX!Uba7*UOZ8tJyGt91Nw73B;w3 zp*Cw`S;a4wOi2wRNFWZ*Q(l6Lga|xEc@kqrLm$)KF4%tc=KP}TgHuH%kpHr~Krj(> zsvMfDx0fJ5OyCg?pg?>_>it+UQ}u`vshaYivcGehFaYB;Ow5dfbA}X_z_CEw^Lj41 zeZT)7fA@O2zX$%lzxQ|jjdXI6WQbG=1V%K9=#6Yhz+r^c{;}R7v8n)P5J&2r@%+qC zHaeo>UjiB<5hhq*N$6Kem0ZSgh=}9>V!(aAf>Xo;hLxKL zmVUm1*I!~3Nba7II1$Yscwc*qpQiWg`s}Os6%5RfhbgCgLPP1h(vcW|uiyfSgb@IN z`~k>!hN*My0OKlleFXzIzWT@a?>h!);TCu7ygI(<$p8M|PImwnk}`oT%#k90xNA~k z8d|25xDwOQQnD-mCIVMcmXZ?CX-o+sA|)sTi3WL9sU<}-rNouZk)j6F35?+oM@tT= ziovqd7+e0S8jZ~Z?)F1z9SykB4jexFa-uhD`k>fdBYinT3drPa?@Y&bdwE+gm_dZ) z9BI!V;SsRm22KkAa|J?hB)Y!T6MvxBHDDA2)Y2I+N`9w9KQloFRdm8QW;AA4LAq&C zwdB|uR*-uOIIC+tL}+2nX{jQkSJuu4E`k7#4F= z*(T^DNZe3%eO@MaSvpM(?PzRGCyenWVly0|Rp+JS^D|q+2IW49;Vt#^C(7`jln5As za~gusMm~9 z*2;L=xYe|-r?oG%T&*qaw~ZTa>v}drs5=yp(lbAa#|(xjJ9?qFBjwz8Ccq7jB7g`_ z)B%&q^D|>SLqy~7H%R@Wt5m3g1~q(eHUfie15~T{z?zbJV-cIy#Dvis00~e8D&Rr= z&IOJ2Fw_(Ss9bqJ^Hqus6hm0-3nzdj{i)vtdDq5_#wtFf)rMM zT+PKwCi;JsmZV%)kXD^h5=B6jRB&cl0!DXKkqb&iCv|#k^p%((-4^KB)8S7BJAfku zemS$B{kpxS$}mbrH;tg?f+Z>sq7N!M5GPTj4_NR)Wd}}aaE+MOL2!Y_my023|{47-J{r-P-o_x+vvcl+IpH~B0lgQ|{~ zs9L@IHd9P?@{OmsF<*Ztt7Zu8o3uka?qkWmyV+)KPdjMlJ{I@y#-PZa+<-KW^$-Tv zh=hX*5rBW1*ew9&M#XQ`#!PV9Ena_y|xs5(kJ>2K#$ zMb8Z(>zK({Hu;Ms%}$H5Z9)YO3L7ID0rN549Y%D#yT8}}kKMf=cKiRn3uD}KzUDnl zdi`GiaMzjE=S09S>9#_EIH+Q(^)Jq$m|V?cG;lh2&M*<&9*Z#!Mr;b&n6@;20flQA zOBF811Ai7V)d>0|f}G2heNe|#Tqw9!=KeQfYJiydS#O74pg$7CMP^r(n40EM^5Orm#CQ~(WDbPghWr= z6|_q>%jtnQk=W@WPbsZ|oepG)_cO#84)awt=|nz=C67{`Fr*D0yB8*l&A}fDjHKW~ z0OMHEwh%^Ljso@H7zQY}-*6m7^v0YQ)j_^#Ig=xk>Q0AffugkIflG?RgSx&07%FQ| zFS1;~C{k1KQ|{2Z90f|WrM*l2m1-)E626)(xoBh>?{o3kyycku4!y3H&*F*YmJ`Z% z=wG#b+|i&<3App3<9-$ALvy5Hv23g^hWqyiROhxV1&ca7%hMo!8;b9Uq!wb-D$75mcE$jW`aPaZAmp~Jpx z3qTw7g9`SgN1iAH3<-wO45>hPJOVIc2!?YIsFfr1T|Yi|O0H*8Xy!QtIwk}({Fo2F zvP`yZ_dDg^_B&nBi4Yl!NeA@zK!*!P$vDflCFg(BOz!VYiFbhheh27pm93}C9$U9j z`!6&-h*qV2N}_y_+eWkrARvetnyL8w^hlg#t!1D7-Up5BtB%C_o*ugn3(DXatuF@i zeiq&JMQ+~Ds+Ut{EfPP7Aa~(;7oRs`0}5Knv^ADy8W)HJsCuGw3RG;VoM&%;-QIG_ z)@-XN4Z4bTj@@I%J#KNu7!jLw_WQh-hv<4suS%;K@L)n$jCF zTKhrZX0&LtyG3hL^d;bh4XWJQs&;j+;@GfW)n6qz3IQTB%qW@a)4&X?(+J8y*C7#5 zn+z?(!L-U&B@k${$d|iOIDnkO<;rzu`V0wAPlQ;TL?=XOtqTo?i|w8HRW;JHKjybs zi`^(3eb*+c$mW6(qtg@|8UQ-{9R4KzKokD^pqd;i7N|`BZ{6S?bD>FO-gp!^u?RKMVR9~ZcKi@fJN>_Ey z%vv9_LZ+SxS9yDV>>* zZl0`Px3_HW7}d`%Xpmn%Y15!eezr(`rZaFR05fX~1bhOe0jpyx)dk5ahh++bpt{(^qR4d0>$c4YBvV^l2*YcJWhC%qPeQCgWxtW(myYR4!eo2}$8zO2%mQ#o6Jc@$nG!(2v6|%5^E`w0=X<=ZEpQp5 z0K*7i#X%lS&=hj#B$=!#%f-aZnU*6D05Olzk*pAtu?IkyiR;K7gt5h)T&wzA66PSH z>I{$v0Qv%_afFUQsJ`+s^*kr7R6|o2X-TEX*~uxlW|Mwumy9v_;&}p&o2u3I2sn1D z>HGadzuybd5JS@I@AcT>f#=0Z6zQYbO_eHUkLCdC>d(^;(<>kpp#AhXx`A{46yQ-t zhveB)bx24&-O-mha3oamv(Y;$&Kcr}h^Lw!6DXDu1Q~;K4*)EXPR_fSQkz>gngec$ zCb|+pM;ZC{kk)o~0e0>@lka&U8YT|Ahx(?B5^Ho{?CE7SU8&hE!q+N*P--{&A{Ydi zj3}GxlM*`78Fz)G@6eFCeN1$i9|@4DY>1A$tyC>tjoZp)GRy1BmgIkp^tXT`e&9;N z+XA}lh9Z+sYzsL1#o5R*_oFoO$zCd=%L8Y(*>{;B`RI9OPh4$xH|gd-CzR_v#2JAC ze56q_Mfr{M9dI_Xy4UG-c7WT=JC%a1(=lnSLd+$d9E5Yp&_E|mvWX^5K0Jys>bl!nJ{MOZ+El(Zav~6MJ3^#iXg; zbCdjfm)s*JVTcplbb+pj8a^lc@-2x6{3k=u-iUW%1Ew$6+G@I&dJ_;;TTa|II zp_guQY8yOeV*%aHPUoifYc&5E#xW*p+Q`*qeoyln>N<@TaE<0B&bJ~MTfW4kjtEV^ z-h5lgY@K2-C3Oq9#BKqQT9vYpy>aRdny0Lkyi^^Qge7vO`eaU`t3=~~Bf_!D@v6q6 zvM}9DeVC-1ojZWjDFOmd5tkL*K%xfaSbnV!2{65{A5+e;N+U7X&6+T1%y^L-+|Q)D zmCfY4hF9wMUawc3meFu!^_+~r9Hr1J6pZ8LKh+|9AHzQql;(EKr195ZPCSJ%{J(Hdumpy zd)P+#Hw)P1M%t$N)9a!@6CC8|@Hyy(U9XA-{gqhI zcUjP14-5JmU_rmg0-MwKgH8Bif-x!R`+NSL=l$}YfOm9;rbEO)|6m8~@9ppHm>f#` z_5d!pf$GfYR5?f^Ofa9IFgve3#$u8TRi<63ye1*?78g(?yhlepF+n|(=)AiF!~}CN zg}+ng=4sMLskrR0F=4WEtP@Dai0fRoI;pUHpQY?IqfEI7g34)uvY4iaGP3ltBLqdl zWL06PQ_t$I9%vg%)gnitF?v;4Pui5}0lX9wmsw}*)W`g zAr%w-(Z1^5f#tnZk(8{?Lan-=uXDd#r%ntED2e7>AN=wYVrX#&Z=1PWssN0!>68v8 z>nguDfJEw42&PnVDf4zU5G1)faMP9Ps6DR-K1eQTJIG`g9+YUB9r!u2M(~f_EmOLu zi0c_GZ=gmtc$HTsec&M0{;##RpDD(w_5PW<2q4QCO__;Kjp7L$B7p-npp=O_p;J0W z1WC!?zxjb&NIWTBn*uZv(wZsbTq;WbX3Jc z8YI%QQBqqxc4qs(%?^H>;;|O-?pFF|FX5;cK#q9Vj1u#TjJ5D=9|Q%n1F0+@I2t7p zh%mY4S{H1~vc+8TdXWgqFpT&vL!3r4)RV;RtN$MKV#-A?BSg!2*Qsxro>UZ9X+Crb z)RTQs?e%8+JweT%2fJ!Ddy4}^q$hboa_um2<&;KD;uYEgOJkOL1K|(@vx9f2X zg9)-V>;Rk7aNpkp+p<8%yy|rS;Yod&!nsntM8zCou17Tb5};U(_<&C12y3_5E*7Q= z-}^690UZjc2Dzltu5P9jfI?ddk{?IAyEivCK2%itl#O>IU5f9%Jv({*?(%hSUoP7p zNQ5}g7Rce;=6P4i*x?P3v&WbrJ*#5^ZWtEo>J&~#;s!G0g_sM5hl$8B$Wnzla0|%E zn1IglB{;k6fLF(tXO}zPr?ab{-ha3PpN=msj^ACKy}ktRFTlzBcc*7pXYb!#g7-gy z<9GiB-kiNV-2n(|An!}8@<~tz@Ki15zISPo!`Q}C^j<-+H~)_g@A>}$009607+3670E!3z`%Giq literal 0 HcmV?d00001 diff --git a/charts/apisix-dashboard/Chart.yaml b/charts/apisix-dashboard/Chart.yaml index 15c6e508..6104f62f 100644 --- a/charts/apisix-dashboard/Chart.yaml +++ b/charts/apisix-dashboard/Chart.yaml @@ -31,7 +31,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.8.0 +version: 0.8.2 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/apisix-dashboard/README.md b/charts/apisix-dashboard/README.md index b45176a9..80560b6e 100644 --- a/charts/apisix-dashboard/README.md +++ b/charts/apisix-dashboard/README.md @@ -63,6 +63,8 @@ _See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documen | config.authentication.secret | string | `"secret"` | Secret for jwt token generation | | config.authentication.users | list | `[{"password":"admin","username":"admin"}]` | Specifies username and password for login manager api. | | config.conf.etcd.endpoints | list | `["apisix-etcd:2379"]` | Supports defining multiple etcd host addresses for an etcd cluster | +| config.conf.etcd.mtls | object | `{}` | | +| config.conf.etcd.mtlsExistingSecret | string | `""` | Specifies a secret to be mounted on /etc/etcd for mtls usage | | config.conf.etcd.password | string | `nil` | Specifies etcd basic auth password if enable etcd auth | | config.conf.etcd.prefix | string | `"/apisix"` | apisix configurations prefix | | config.conf.etcd.username | string | `nil` | Specifies etcd basic auth username if enable etcd auth | @@ -71,6 +73,8 @@ _See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documen | config.conf.log.accessLog.filePath | string | `"/dev/stdout"` | Error log path | | config.conf.log.errorLog | object | `{"filePath":"/dev/stderr","level":"warn"}` | Error log level. Supports levels, lower to higher: debug, info, warn, error, panic, fatal | | config.conf.log.errorLog.filePath | string | `"/dev/stderr"` | Access log path | +| config.conf.plugins | list | `[]` | Overrides plugins in the APISIX Dashboard conf | +| config.schema.configMap | object | `{}` | Overrides APISIX Dashboard schema.json by mounting configMap containing schema.json | | fullnameOverride | string | `""` | String to fully override apisix-dashboard.fullname template | | image.pullPolicy | string | `"IfNotPresent"` | Apache APISIX Dashboard image pull policy | | image.repository | string | `"apache/apisix-dashboard"` | Apache APISIX Dashboard image repository | @@ -96,3 +100,5 @@ _See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documen | serviceAccount.create | bool | `true` | Specifies whether a service account should be created | | serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | | tolerations | list | `[]` | Tolerations for pod assignment | +| topologySpreadConstraints | list | `[]` | Topology Spread Constraints for pod assignment spread across your cluster among failure-domains ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods | +| updateStrategy | object | `{}` | Update strategy for apisix dashboard deployment | diff --git a/charts/apisix-dashboard/templates/configmap.yaml b/charts/apisix-dashboard/templates/configmap.yaml index e869fbbc..e5511954 100644 --- a/charts/apisix-dashboard/templates/configmap.yaml +++ b/charts/apisix-dashboard/templates/configmap.yaml @@ -41,6 +41,10 @@ data: {{- if .password }} password: {{ .password }} {{- end }} + {{- if .mtls }} + mtls: + {{- toYaml .mtls | nindent 10 }} + {{- end }} {{- end }} {{- with .log }} log: @@ -61,3 +65,9 @@ data: password: {{ .password }} {{- end }} {{- end }} + {{- with .Values.config.conf.plugins }} + plugins: + {{- range . }} + - {{ . }} + {{- end }} + {{- end }} diff --git a/charts/apisix-dashboard/templates/deployment.yaml b/charts/apisix-dashboard/templates/deployment.yaml index 6514594f..3689d84e 100644 --- a/charts/apisix-dashboard/templates/deployment.yaml +++ b/charts/apisix-dashboard/templates/deployment.yaml @@ -28,6 +28,9 @@ spec: selector: matchLabels: {{- include "apisix-dashboard.selectorLabels" . | nindent 6 }} + {{- with .Values.updateStrategy }} + strategy: {{ toYaml . | nindent 4 }} + {{- end }} template: metadata: annotations: @@ -74,10 +77,29 @@ spec: - mountPath: /usr/local/apisix-dashboard/conf/conf.yaml name: apisix-dashboard-config subPath: conf.yaml + {{- with .Values.config.schema.configMap }} + - mountPath: /usr/local/apisix-dashboard/conf/schema.json + name: schema-json + subPath: {{ .key }} + {{- end}} + {{- if .Values.config.conf.etcd.mtlsExistingSecret }} + - mountPath: /etc/etcd + name: etcd-config + {{- end}} volumes: - configMap: name: {{ include "apisix-dashboard.fullname" . }} name: apisix-dashboard-config + {{- with .Values.config.schema.configMap }} + - configMap: + name: {{ .name }} + name: schema-json + {{- end}} + {{- if .Values.config.conf.etcd.mtlsExistingSecret }} + - secret: + secretName: {{ .Values.config.conf.etcd.mtlsExistingSecret }} + name: etcd-config + {{- end}} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -90,3 +112,7 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- tpl (. | toYaml) $ | nindent 8 }} + {{- end }} diff --git a/charts/apisix-dashboard/values.yaml b/charts/apisix-dashboard/values.yaml index ffc543d5..2f0d89b2 100644 --- a/charts/apisix-dashboard/values.yaml +++ b/charts/apisix-dashboard/values.yaml @@ -71,6 +71,12 @@ securityContext: {} # runAsUser: 1000 config: + schema: + # -- Overrides APISIX Dashboard schema.json + # by mounting configMap containing schema.json + configMap: {} + # name: apisix-dashboard-schema + # key: schema.json conf: listen: # -- The address on which the Manager API should listen. @@ -89,6 +95,16 @@ config: username: ~ # -- Specifies etcd basic auth password if enable etcd auth password: ~ + + # -- Specifies a secret to be mounted on /etc/etcd for mtls usage + mtlsExistingSecret: "" + + # MTLS configuration used for external etcd instances + mtls: + {} + # key_file: /etc/etcd/server-client.key + # cert_file: /etc/etcd/server-client.crt + # ca_file: /etc/etcd/server-ca.crt log: # -- Error log level. # Supports levels, lower to higher: debug, info, warn, error, panic, fatal @@ -99,7 +115,8 @@ config: accessLog: # -- Error log path filePath: /dev/stdout - + # -- Overrides plugins in the APISIX Dashboard conf + plugins: [] authentication: # -- Secret for jwt token generation secret: secret @@ -165,6 +182,10 @@ autoscaling: targetCPUUtilizationPercentage: 80 # targetMemoryUtilizationPercentage: 80 +# -- Update strategy for apisix dashboard deployment +updateStrategy: {} + # type: RollingUpdate + # -- Node labels for pod assignment nodeSelector: {} @@ -172,3 +193,7 @@ nodeSelector: {} tolerations: [] affinity: {} + +# -- Topology Spread Constraints for pod assignment spread across your cluster among failure-domains +# ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods +topologySpreadConstraints: [] diff --git a/charts/apisix-ingress-controller/Chart.yaml b/charts/apisix-ingress-controller/Chart.yaml index fe96498a..636a794d 100644 --- a/charts/apisix-ingress-controller/Chart.yaml +++ b/charts/apisix-ingress-controller/Chart.yaml @@ -24,8 +24,8 @@ keywords: - nginx - crd type: application -version: 0.11.6 -appVersion: 1.6.1 +version: 0.14.0 +appVersion: 1.8.0 sources: - https://github.com/apache/apisix-helm-chart diff --git a/charts/apisix-ingress-controller/README.md b/charts/apisix-ingress-controller/README.md index 90f84d1a..3fe6505b 100644 --- a/charts/apisix-ingress-controller/README.md +++ b/charts/apisix-ingress-controller/README.md @@ -105,24 +105,32 @@ The same for container level, you need to set: | Key | Type | Default | Description | |-----|------|---------|-------------| +| affinity | object | `{}` | | +| annotations | object | `{}` | Add annotations to Apache APISIX ingress controller resource | | autoscaling.enabled | bool | `false` | | | autoscaling.maxReplicas | int | `100` | | | autoscaling.minReplicas | int | `1` | | | autoscaling.targetCPUUtilizationPercentage | int | `80` | | | autoscaling.version | string | `"v2"` | HPA version, the value is "v2" or "v2beta1", default "v2" | | clusterDomain | string | `"cluster.local"` | | -| config.apisix | object | `{"adminAPIVersion":"v2","adminKey":"edd1c9f034335f136f87ad84b625c8f1","clusterName":"default","serviceName":"apisix-admin","serviceNamespace":"ingress-apisix","servicePort":9180}` | APISIX related configurations. | +| config.apisix | object | `{"adminAPIVersion":"v2","adminKey":"edd1c9f034335f136f87ad84b625c8f1","clusterName":"default","existingSecret":"","existingSecretAdminKeyKey":"","serviceName":"apisix-admin","serviceNamespace":"ingress-apisix","servicePort":9180}` | APISIX related configurations. | | config.apisix.adminAPIVersion | string | `"v2"` | the APISIX admin API version. can be "v2" or "v3", default is "v2". | +| config.apisix.existingSecret | string | `""` | The APISIX Helm chart supports storing user credentials in a secret. The secret needs to contain a single key for admin token with key adminKey by default. | +| config.apisix.existingSecretAdminKeyKey | string | `""` | Name of the admin token key in the secret, overrides the default key name "adminKey" | | config.apisix.serviceName | string | `"apisix-admin"` | Enabling this value, overrides serviceName and serviceNamespace. serviceFullname: "apisix-admin.apisix.svc.local" | | config.apisixResourceSyncInterval | string | `"1h"` | Default interval for synchronizing Kubernetes resources to APISIX | | config.certFile | string | `"/etc/webhook/certs/cert.pem"` | the TLS certificate file path. | | config.enableProfiling | bool | `true` | enable profiling via web interfaces host:port/debug/pprof, default is true. | +| config.etcdserver.enabled | bool | `false` | Enable etcd server or not, default is false. | +| config.etcdserver.image.pullPolicy | string | `"IfNotPresent"` | Apache APISIX image pull policy | +| config.etcdserver.image.repository | string | `"apache/apisix"` | Apache APISIX image repository | +| config.etcdserver.image.tag | string | `"3.5.0-debian"` | Apache APISIX image tag Overrides the image tag whose default is the chart appVersion. | | config.httpListen | string | `":8080"` | the HTTP Server listen address, default is ":8080" | | config.httpsListen | string | `":8443"` | the HTTPS Server listen address, default is ":8443" | | config.ingressPublishService | string | `""` | the controller will use the Endpoint of this Service to update the status information of the Ingress resource. The format is "namespace/svc-name" to solve the situation that the data plane and the controller are not deployed in the same namespace. | | config.ingressStatusAddress | list | `[]` | | | config.keyFile | string | `"/etc/webhook/certs/key.pem"` | the TLS key file path. | -| config.kubernetes | object | `{"apiVersion":"apisix.apache.org/v2","apisixRouteVersion":"apisix.apache.org/v2","electionId":"ingress-apisix-leader","enableGatewayAPI":false,"ingressClass":"apisix","ingressVersion":"networking/v1","kubeconfig":"","namespaceSelector":[""],"pluginMetadataCM":"","resyncInterval":"6h","watchEndpointSlices":false}` | Kubernetes related configurations. | +| config.kubernetes | object | `{"apiVersion":"apisix.apache.org/v2","apisixRouteVersion":"apisix.apache.org/v2","electionId":"ingress-apisix-leader","enableGatewayAPI":false,"ingressClass":"apisix","ingressVersion":"networking/v1","kubeconfig":"","namespaceSelector":[""],"resyncInterval":"6h","watchEndpointSlices":false}` | Kubernetes related configurations. | | config.kubernetes.apiVersion | string | `"apisix.apache.org/v2"` | the resource API version, support "apisix.apache.org/v2beta3" and "apisix.apache.org/v2". default is "apisix.apache.org/v2" | | config.kubernetes.apisixRouteVersion | string | `"apisix.apache.org/v2"` | the supported apisixroute api group version, can be "apisix.apache.org/v2" "apisix.apache.org/v2beta3" or "apisix.apache.org/v2beta2" | | config.kubernetes.electionId | string | `"ingress-apisix-leader"` | the election id for the controller leader campaign, only the leader will watch and delivery resource changes, other instances (as candidates) stand by. | @@ -131,15 +139,34 @@ The same for container level, you need to set: | config.kubernetes.ingressVersion | string | `"networking/v1"` | the supported ingress api group version, can be "networking/v1beta1", "networking/v1" (for Kubernetes version v1.19.0 or higher), and "extensions/v1beta1", default is "networking/v1". | | config.kubernetes.kubeconfig | string | `""` | the Kubernetes configuration file path, default is "", so the in-cluster configuration will be used. | | config.kubernetes.namespaceSelector | list | `[""]` | namespace_selector represent basis for selecting managed namespaces. the field is support since version 1.4.0 For example, "apisix.ingress=watching", so ingress will watching the namespaces which labels "apisix.ingress=watching" | -| config.kubernetes.pluginMetadataCM | string | `""` | Pluginmetadata in APISIX can be controlled through ConfigMap. default is "" | | config.kubernetes.resyncInterval | string | `"6h"` | how long should apisix-ingress-controller re-synchronizes with Kubernetes, default is 6h, | | config.kubernetes.watchEndpointSlices | bool | `false` | whether to watch EndpointSlices rather than Endpoints. | | config.logLevel | string | `"info"` | the error log level, default is info, optional values are: debug, info, warn, error, panic, fatal | | config.logOutput | string | `"stderr"` | the output file path of error log, default is stderr, when the file path is "stderr" or "stdout", logs are marshalled plainly, which is more readable for human; otherwise logs are marshalled in JSON format, which can be parsed by programs easily. | +| config.pluginMetadataCM | string | `""` | Pluginmetadata in APISIX can be controlled through ConfigMap. default is "" | | fullnameOverride | string | `""` | | +| gateway.externalIPs | list | `[]` | load balancer ips | +| gateway.externalTrafficPolicy | string | `"Cluster"` | | +| gateway.nginx.errorLog | string | `"stderr"` | Nginx error logs path | +| gateway.nginx.errorLogLevel | string | `"warn"` | Nginx error logs level | +| gateway.nginx.workerConnections | string | `"10620"` | Nginx worker connections | +| gateway.nginx.workerProcesses | string | `"auto"` | Nginx worker processes | +| gateway.nginx.workerRlimitNofile | string | `"20480"` | Nginx workerRlimitNoFile | +| gateway.resources | object | `{}` | | +| gateway.securityContext | object | `{}` | | +| gateway.tls.additionalContainerPorts | list | `[]` | Support multiple https ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L99) | +| gateway.tls.certCAFilename | string | `""` | Filename be used in the gateway.tls.existingCASecret | +| gateway.tls.containerPort | int | `9443` | | +| gateway.tls.enabled | bool | `false` | | +| gateway.tls.existingCASecret | string | `""` | Specifies the name of Secret contains trusted CA certificates in the PEM format used to verify the certificate when APISIX needs to do SSL/TLS handshaking with external services (e.g. etcd) | +| gateway.tls.fallbackSNI | string | `""` | Define SNI to fallback if none is presented by client | +| gateway.tls.http2.enabled | bool | `true` | | +| gateway.tls.servicePort | int | `443` | | +| gateway.tls.sslProtocols | string | `"TLSv1.2 TLSv1.3"` | TLS protocols allowed to use. | +| gateway.type | string | `"NodePort"` | Apache APISIX service type for user access itself | | image.pullPolicy | string | `"IfNotPresent"` | | | image.repository | string | `"apache/apisix-ingress-controller"` | | -| image.tag | string | `"1.6.1"` | | +| image.tag | string | `"1.8.0"` | | | imagePullSecrets | list | `[]` | | | initContainer.image | string | `"busybox"` | | | initContainer.tag | float | `1.28` | | @@ -147,6 +174,10 @@ The same for container level, you need to set: | nameOverride | string | `""` | Default values for apisix-ingress-controller. This is a YAML-formatted file. Declare variables to be passed into your templates. | | nodeSelector | object | `{}` | | | podAnnotations | object | `{}` | | +| podDisruptionBudget | object | `{"enabled":false,"maxUnavailable":1,"minAvailable":"90%"}` | See https://kubernetes.io/docs/tasks/run-application/configure-pdb/ for more details | +| podDisruptionBudget.enabled | bool | `false` | Enable or disable podDisruptionBudget | +| podDisruptionBudget.maxUnavailable | int | `1` | Set the maxUnavailable of podDisruptionBudget | +| podDisruptionBudget.minAvailable | string | `"90%"` | Set the `minAvailable` of podDisruptionBudget. You can specify only one of `maxUnavailable` and `minAvailable` in a single PodDisruptionBudget. See [Specifying a Disruption Budget for your Application](https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget) for more details | | podSecurityContext | object | `{}` | | | priorityClassName | string | `""` | | | rbac.create | bool | `true` | Specifies whether RBAC resources should be created | @@ -157,7 +188,10 @@ The same for container level, you need to set: | serviceAccount.automountServiceAccountToken | bool | `true` | Whether automounting API credentials for a service account | | serviceAccount.create | bool | `true` | Specifies whether a ServiceAccount should be created | | serviceAccount.name | string | `""` | The name of the ServiceAccount to use. If not set and create is true, a name is generated using the fullname template | -| serviceMonitor | object | `{"annotations":{},"enabled":false,"interval":"15s","labels":{},"namespace":"monitoring"}` | namespace: "ingress-apisix" | +| serviceMonitor | object | `{"annotations":{},"enabled":false,"interval":"15s","labels":{},"metricRelabelings":{},"namespace":"monitoring"}` | Enable creating ServiceMonitor objects for Prometheus operator. Requires Prometheus operator v0.38.0 or higher. | | serviceMonitor.annotations | object | `{}` | @param serviceMonitor.annotations ServiceMonitor annotations | | serviceMonitor.labels | object | `{}` | @param serviceMonitor.labels ServiceMonitor extra labels | +| serviceMonitor.metricRelabelings | object | `{}` | @param serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion. ref: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs | | tolerations | list | `[]` | | +| topologySpreadConstraints | list | `[]` | Topology Spread Constraints for pod assignment spread across your cluster among failure-domains ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods | +| updateStrategy | object | `{}` | Update strategy for apisix ingress controller deployment | diff --git a/charts/apisix-ingress-controller/crds/ApisixClusterConfig.yaml b/charts/apisix-ingress-controller/crds/ApisixClusterConfig.yaml new file mode 100644 index 00000000..d704a116 --- /dev/null +++ b/charts/apisix-ingress-controller/crds/ApisixClusterConfig.yaml @@ -0,0 +1,100 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + apisix.apache.org/app: ingress-apisix + name: apisixclusterconfigs.apisix.apache.org +spec: + group: apisix.apache.org + names: + kind: ApisixClusterConfig + plural: apisixclusterconfigs + shortNames: + - acc + singular: apisixclusterconfig + preserveUnknownFields: false + scope: Cluster + versions: + - deprecated: true + name: v2beta3 + schema: + openAPIV3Schema: + properties: + spec: + properties: + admin: + properties: + adminKey: + type: string + baseURL: + pattern: https?://[^:]+:(\d+) + type: string + required: + - baseURL + type: object + monitoring: + properties: + prometheus: + properties: + enable: + type: boolean + type: object + skywalking: + properties: + enable: + type: boolean + sampleRatio: + maximum: 1 + minimum: 1.0e-05 + type: number + type: object + type: object + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v2 + schema: + openAPIV3Schema: + properties: + spec: + properties: + admin: + properties: + adminKey: + type: string + baseURL: + pattern: https?://[^:]+:(\d+) + type: string + required: + - baseURL + type: object + ingressClassName: + type: string + monitoring: + properties: + prometheus: + properties: + enable: + type: boolean + prefer_name: + type: boolean + type: object + skywalking: + properties: + enable: + type: boolean + sampleRatio: + maximum: 1 + minimum: 1.0e-05 + type: number + type: object + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/apisix-ingress-controller/crds/ApisixConsumer.yaml b/charts/apisix-ingress-controller/crds/ApisixConsumer.yaml new file mode 100644 index 00000000..0fd56549 --- /dev/null +++ b/charts/apisix-ingress-controller/crds/ApisixConsumer.yaml @@ -0,0 +1,422 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + apisix.apache.org/app: ingress-apisix + name: apisixconsumers.apisix.apache.org +spec: + group: apisix.apache.org + names: + kind: ApisixConsumer + plural: apisixconsumers + shortNames: + - ac + singular: apisixconsumer + preserveUnknownFields: false + scope: Namespaced + versions: + - deprecated: true + name: v2beta3 + schema: + openAPIV3Schema: + properties: + spec: + properties: + authParameter: + oneOf: + - required: + - basicAuth + - required: + - keyAuth + - required: + - wolfRBAC + - required: + - jwtAuth + - required: + - hmacAuth + properties: + basicAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + password: + minLength: 1 + type: string + username: + minLength: 1 + type: string + required: + - username + - password + type: object + type: object + hmacAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + access_key: + type: string + algorithm: + type: string + clock_skew: + type: integer + encode_uri_params: + type: boolean + keep_headers: + type: boolean + max_req_body: + type: integer + secret_key: + type: string + signed_headers: + items: + type: string + type: array + validate_request_body: + type: boolean + required: + - access_key + - secret_key + type: object + type: object + jwtAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + algorithm: + default: HS256 + type: string + base64_secret: + default: false + type: boolean + exp: + default: 86400 + type: integer + key: + minLength: 1 + type: string + lifetime_grace_period: + default: 0 + type: integer + private_key: + type: string + public_key: + type: string + secret: + type: string + required: + - key + type: object + type: object + keyAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + key: + minLength: 1 + type: string + required: + - key + type: object + type: object + wolfRBAC: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + appid: + type: string + header_prefix: + type: string + server: + type: string + type: object + type: object + type: object + required: + - authParameter + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v2 + schema: + openAPIV3Schema: + properties: + spec: + properties: + authParameter: + oneOf: + - required: + - basicAuth + - required: + - keyAuth + - required: + - wolfRBAC + - required: + - jwtAuth + - required: + - hmacAuth + - required: + - ldapAuth + properties: + basicAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + password: + minLength: 1 + type: string + username: + minLength: 1 + type: string + required: + - username + - password + type: object + type: object + hmacAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + access_key: + type: string + algorithm: + type: string + clock_skew: + type: integer + encode_uri_params: + type: boolean + keep_headers: + type: boolean + max_req_body: + type: integer + secret_key: + type: string + signed_headers: + items: + type: string + type: array + validate_request_body: + type: boolean + required: + - access_key + - secret_key + type: object + type: object + jwtAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + algorithm: + default: HS256 + type: string + base64_secret: + default: false + type: boolean + exp: + default: 86400 + type: integer + key: + minLength: 1 + type: string + lifetime_grace_period: + default: 0 + type: integer + private_key: + type: string + public_key: + type: string + secret: + type: string + required: + - key + type: object + type: object + keyAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + key: + minLength: 1 + type: string + required: + - key + type: object + type: object + ldapAuth: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: null + type: object + value: + properties: + user_dn: + type: string + required: + - user_dn + type: object + type: object + wolfRBAC: + oneOf: + - required: + - value + - required: + - secretRef + properties: + secretRef: + properties: + name: + minLength: 1 + type: string + required: + - name + type: object + value: + properties: + appid: + type: string + header_prefix: + type: string + server: + type: string + type: object + type: object + type: object + ingressClassName: + type: string + required: + - authParameter + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/apisix-ingress-controller/crds/ApisixGlobalRule.yaml b/charts/apisix-ingress-controller/crds/ApisixGlobalRule.yaml index 7eff6f87..a502ebff 100644 --- a/charts/apisix-ingress-controller/crds/ApisixGlobalRule.yaml +++ b/charts/apisix-ingress-controller/crds/ApisixGlobalRule.yaml @@ -1,88 +1,73 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: + labels: + apisix.apache.org/app: ingress-apisix name: apisixglobalrules.apisix.apache.org spec: group: apisix.apache.org - scope: Namespaced names: - plural: apisixglobalrules - singular: apisixglobalrule kind: ApisixGlobalRule + plural: apisixglobalrules shortNames: - agr + singular: apisixglobalrule + scope: Namespaced versions: - - name: v2 - served: true - storage: true - subresources: - status: {} - additionalPrinterColumns: + - additionalPrinterColumns: - jsonPath: .metadata.creationTimestamp name: Age - type: date priority: 0 + type: date + name: v2 schema: openAPIV3Schema: - type: object properties: spec: - type: object - required: - - plugins properties: ingressClassName: type: string plugins: - type: array items: - type: object properties: - name: - type: string - minLength: 1 - enable: - type: boolean config: type: object - x-kubernetes-preserve-unknown-fields: true # we have to enable it since plugin config + x-kubernetes-preserve-unknown-fields: true + enable: + type: boolean + name: + minLength: 1 + type: string secretRef: type: string + type: object required: - name - enable - status: + type: array + required: + - plugins type: object + status: properties: conditions: - type: array items: - type: object properties: - "type": + message: type: string + observedGeneration: + type: integer reason: type: string status: type: string - message: + type: type: string - observedGeneration: - type: integer + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/apisix-ingress-controller/crds/ApisixPluginConfig.yaml b/charts/apisix-ingress-controller/crds/ApisixPluginConfig.yaml new file mode 100644 index 00000000..910e705d --- /dev/null +++ b/charts/apisix-ingress-controller/crds/ApisixPluginConfig.yaml @@ -0,0 +1,127 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + apisix.apache.org/app: ingress-apisix + name: apisixpluginconfigs.apisix.apache.org +spec: + group: apisix.apache.org + names: + kind: ApisixPluginConfig + plural: apisixpluginconfigs + shortNames: + - apc + singular: apisixpluginconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + priority: 0 + type: date + deprecated: true + name: v2beta3 + schema: + openAPIV3Schema: + properties: + spec: + properties: + plugins: + items: + properties: + config: + type: object + x-kubernetes-preserve-unknown-fields: true + enable: + type: boolean + name: + minLength: 1 + type: string + type: object + required: + - name + - enable + type: array + required: + - plugins + type: object + status: + properties: + conditions: + items: + properties: + message: + type: string + observedGeneration: + type: integer + reason: + type: string + status: + type: string + type: + type: string + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + priority: 0 + type: date + name: v2 + schema: + openAPIV3Schema: + properties: + spec: + properties: + ingressClassName: + type: string + plugins: + items: + properties: + config: + type: object + x-kubernetes-preserve-unknown-fields: true + enable: + type: boolean + name: + minLength: 1 + type: string + secretRef: + type: string + type: object + required: + - name + - enable + type: array + required: + - plugins + type: object + status: + properties: + conditions: + items: + properties: + message: + type: string + observedGeneration: + type: integer + reason: + type: string + status: + type: string + type: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/apisix-ingress-controller/crds/ApisixRoute.yaml b/charts/apisix-ingress-controller/crds/ApisixRoute.yaml new file mode 100644 index 00000000..479b67d3 --- /dev/null +++ b/charts/apisix-ingress-controller/crds/ApisixRoute.yaml @@ -0,0 +1,665 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + apisix.apache.org/app: ingress-apisix + name: apisixroutes.apisix.apache.org +spec: + group: apisix.apache.org + names: + kind: ApisixRoute + plural: apisixroutes + shortNames: + - ar + singular: apisixroute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.http[].match.hosts + name: Hosts + priority: 0 + type: string + - jsonPath: .spec.http[].match.paths + name: URIs + priority: 0 + type: string + - jsonPath: .spec.http[].backends[].serviceName + name: Target Service(HTTP) + priority: 1 + type: string + - jsonPath: .spec.tcp[].match.ingressPort + name: Ingress Server Port(TCP) + priority: 1 + type: integer + - jsonPath: .spec.tcp[].match.backend.serviceName + name: Target Service(TCP) + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + priority: 0 + type: date + name: v2beta3 + schema: + openAPIV3Schema: + properties: + spec: + anyOf: + - required: + - http + - required: + - stream + properties: + http: + items: + properties: + authentication: + properties: + enable: + type: boolean + jwtAuth: + properties: + cookie: + type: string + header: + type: string + query: + type: string + type: object + keyAuth: + properties: + header: + type: string + type: object + type: + enum: + - basicAuth + - keyAuth + - jwtAuth + - wolfRBAC + - hmacAuth + type: string + required: + - enable + type: object + backends: + items: + properties: + resolveGranularity: + enum: + - endpoint + - service + type: string + serviceName: + minLength: 1 + type: string + servicePort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + subset: + type: string + weight: + minimum: 0 + type: integer + type: object + minItems: 1 + required: + - serviceName + - servicePort + type: array + match: + properties: + exprs: + items: + oneOf: + - required: + - subject + - op + - value + - required: + - subject + - op + - set + properties: + op: + enum: + - Equal + - NotEqual + - GreaterThan + - LessThan + - In + - NotIn + - RegexMatch + - RegexNotMatch + - RegexMatchCaseInsensitive + - RegexNotMatchCaseInsensitive + type: string + set: + items: + type: string + type: array + subject: + properties: + name: + minLength: 1 + type: string + scope: + enum: + - Cookie + - Header + - Path + - Query + type: string + required: + - scope + type: object + value: + type: string + type: object + minItems: 1 + type: array + hosts: + items: + pattern: ^\*?[0-9a-zA-Z-._]+$ + type: string + minItems: 1 + type: array + methods: + items: + enum: + - CONNECT + - DELETE + - GET + - HEAD + - OPTIONS + - PATCH + - POST + - PUT + - TRACE + type: string + minItems: 1 + type: array + paths: + items: + pattern: ^/[a-zA-Z0-9\-._~%!$&'()+,;=:@/\*]*\*?$ + type: string + minItems: 1 + type: array + remoteAddrs: + items: + type: string + minItems: 1 + type: array + required: + - paths + type: object + name: + minLength: 1 + type: string + plugin_config_name: + minLength: 1 + type: string + plugins: + items: + properties: + config: + type: object + x-kubernetes-preserve-unknown-fields: true + enable: + type: boolean + name: + minLength: 1 + type: string + type: object + required: + - name + - enable + type: array + priority: + type: integer + timeout: + properties: + connect: + type: string + read: + type: string + send: + type: string + type: object + websocket: + type: boolean + required: + - name + - match + - backends + type: object + minItems: 1 + type: array + stream: + items: + properties: + backend: + properties: + resolveGranularity: + enum: + - endpoint + - service + type: string + serviceName: + minLength: 1 + type: string + servicePort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + subset: + type: string + required: + - serviceName + - servicePort + type: object + match: + properties: + ingressPort: + maximum: 65535 + minimum: 1 + type: integer + required: + - ingressPort + type: object + name: + minLength: 1 + type: string + protocol: + enum: + - TCP + - UDP + type: string + required: + - name + - match + - backend + - protocol + type: object + minItems: 1 + type: array + type: object + status: + properties: + conditions: + items: + properties: + message: + type: string + observedGeneration: + type: integer + reason: + type: string + status: + type: string + type: + type: string + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.http[].match.hosts + name: Hosts + priority: 0 + type: string + - jsonPath: .spec.http[].match.paths + name: URIs + priority: 0 + type: string + - jsonPath: .spec.http[].backends[].serviceName + name: Target Service(HTTP) + priority: 1 + type: string + - jsonPath: .spec.tcp[].match.ingressPort + name: Ingress Server Port(TCP) + priority: 1 + type: integer + - jsonPath: .spec.tcp[].match.backend.serviceName + name: Target Service(TCP) + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + priority: 0 + type: date + name: v2 + schema: + openAPIV3Schema: + properties: + spec: + anyOf: + - required: + - http + - required: + - stream + properties: + http: + items: + anyOf: + - required: + - name + - match + - backends + - required: + - name + - match + - upstreams + properties: + authentication: + properties: + enable: + type: boolean + jwtAuth: + properties: + cookie: + type: string + header: + type: string + query: + type: string + type: object + keyAuth: + properties: + header: + type: string + type: object + ldapAuth: + properties: + base_dn: + type: string + ldap_uri: + type: string + uid: + type: string + use_tls: + type: boolean + type: object + type: + enum: + - basicAuth + - keyAuth + - jwtAuth + - wolfRBAC + - hmacAuth + - ldapAuth + type: string + required: + - enable + type: object + backends: + items: + properties: + resolveGranularity: + enum: + - endpoint + - service + type: string + serviceName: + minLength: 1 + type: string + servicePort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + subset: + type: string + weight: + minimum: 0 + type: integer + type: object + minItems: 1 + required: + - serviceName + - servicePort + type: array + match: + properties: + exprs: + items: + oneOf: + - required: + - subject + - op + - value + - required: + - subject + - op + - set + properties: + op: + enum: + - Equal + - NotEqual + - GreaterThan + - GreaterThanEqual + - LessThan + - LessThanEqual + - In + - NotIn + - RegexMatch + - RegexNotMatch + - RegexMatchCaseInsensitive + - RegexNotMatchCaseInsensitive + type: string + set: + items: + type: string + type: array + subject: + properties: + name: + minLength: 1 + type: string + scope: + enum: + - Cookie + - Header + - Path + - Query + - Variable + type: string + required: + - scope + type: object + value: + type: string + type: object + minItems: 1 + type: array + filter_func: + type: string + hosts: + items: + pattern: ^\*?[0-9a-zA-Z-._]+$ + type: string + minItems: 1 + type: array + methods: + items: + enum: + - CONNECT + - DELETE + - GET + - HEAD + - OPTIONS + - PATCH + - POST + - PUT + - TRACE + type: string + minItems: 1 + type: array + paths: + items: + pattern: ^/[a-zA-Z0-9\-._~%!$&'()+,;=:@/\*]*\*?$ + type: string + minItems: 1 + type: array + remoteAddrs: + items: + type: string + minItems: 1 + type: array + required: + - paths + type: object + name: + minLength: 1 + type: string + plugin_config_name: + minLength: 1 + type: string + plugins: + items: + properties: + config: + type: object + x-kubernetes-preserve-unknown-fields: true + enable: + type: boolean + name: + minLength: 1 + type: string + secretRef: + type: string + type: object + required: + - name + - enable + type: array + priority: + type: integer + timeout: + properties: + connect: + type: string + read: + type: string + send: + type: string + type: object + upstreams: + description: Upstreams refer to ApisixUpstream CRD + items: + description: ApisixRouteUpstreamReference contains a ApisixUpstream CRD reference + properties: + name: + type: string + weight: + type: integer + type: object + type: array + websocket: + type: boolean + type: object + minItems: 1 + type: array + ingressClassName: + type: string + stream: + items: + properties: + backend: + properties: + resolveGranularity: + enum: + - endpoint + - service + type: string + serviceName: + minLength: 1 + type: string + servicePort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + subset: + type: string + required: + - serviceName + - servicePort + type: object + match: + properties: + host: + type: string + ingressPort: + maximum: 65535 + minimum: 1 + type: integer + required: + - ingressPort + type: object + name: + minLength: 1 + type: string + plugins: + items: + properties: + config: + type: object + x-kubernetes-preserve-unknown-fields: true + enable: + type: boolean + name: + minLength: 1 + type: string + secretRef: + type: string + type: object + required: + - name + - enable + type: array + protocol: + enum: + - TCP + - UDP + type: string + required: + - name + - match + - backend + - protocol + type: object + minItems: 1 + type: array + type: object + status: + properties: + conditions: + items: + properties: + message: + type: string + observedGeneration: + type: integer + reason: + type: string + status: + type: string + type: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/apisix-ingress-controller/crds/ApisixTls.yaml b/charts/apisix-ingress-controller/crds/ApisixTls.yaml new file mode 100644 index 00000000..5a403031 --- /dev/null +++ b/charts/apisix-ingress-controller/crds/ApisixTls.yaml @@ -0,0 +1,266 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + apisix.apache.org/app: ingress-apisix + name: apisixtlses.apisix.apache.org +spec: + group: apisix.apache.org + names: + kind: ApisixTls + plural: apisixtlses + shortNames: + - atls + singular: apisixtls + preserveUnknownFields: false + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.hosts + name: SNIs + type: string + - jsonPath: .spec.secret.name + name: Secret Name + type: string + - jsonPath: .spec.secret.namespace + name: Secret Namespace + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + name: v2beta3 + schema: + openAPIV3Schema: + description: ApisixTls defines SSL resource in APISIX. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ApisixTlsSpec is the specification of ApisixSSL. + properties: + client: + description: ApisixMutualTlsClientConfig describes the mutual TLS CA and verify depth + properties: + caSecret: + description: ApisixSecret describes the Kubernetes Secret name and namespace. + properties: + name: + minLength: 1 + type: string + namespace: + minLength: 1 + type: string + required: + - name + - namespace + type: object + depth: + type: integer + type: object + hosts: + items: + pattern: ^\*?[0-9a-zA-Z-.]+$ + type: string + minItems: 1 + type: array + secret: + description: ApisixSecret describes the Kubernetes Secret name and namespace. + properties: + name: + minLength: 1 + type: string + namespace: + minLength: 1 + type: string + required: + - name + - namespace + type: object + required: + - hosts + - secret + type: object + status: + description: ApisixStatus is the status report for Apisix ingress Resources + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - 'True' + - 'False' + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.hosts + name: SNIs + type: string + - jsonPath: .spec.secret.name + name: Secret Name + type: string + - jsonPath: .spec.secret.namespace + name: Secret Namespace + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v2 + schema: + openAPIV3Schema: + description: ApisixTls defines SSL resource in APISIX. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ApisixTlsSpec is the specification of ApisixSSL. + properties: + client: + description: ApisixMutualTlsClientConfig describes the mutual TLS CA and verify depth + properties: + caSecret: + description: ApisixSecret describes the Kubernetes Secret name and namespace. + properties: + name: + minLength: 1 + type: string + namespace: + minLength: 1 + type: string + required: + - name + - namespace + type: object + depth: + type: integer + type: object + hosts: + items: + pattern: ^\*?[0-9a-zA-Z-.]+$ + type: string + minItems: 1 + type: array + ingressClassName: + type: string + secret: + description: ApisixSecret describes the Kubernetes Secret name and namespace. + properties: + name: + minLength: 1 + type: string + namespace: + minLength: 1 + type: string + required: + - name + - namespace + type: object + required: + - hosts + - secret + type: object + status: + description: ApisixStatus is the status report for Apisix ingress Resources + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - 'True' + - 'False' + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/apisix-ingress-controller/crds/ApisixUpstream.yaml b/charts/apisix-ingress-controller/crds/ApisixUpstream.yaml new file mode 100644 index 00000000..11163daa --- /dev/null +++ b/charts/apisix-ingress-controller/crds/ApisixUpstream.yaml @@ -0,0 +1,838 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + apisix.apache.org/app: ingress-apisix + name: apisixupstreams.apisix.apache.org +spec: + group: apisix.apache.org + names: + kind: ApisixUpstream + plural: apisixupstreams + shortNames: + - au + singular: apisixupstream + scope: Namespaced + versions: + - deprecated: true + name: v2beta3 + schema: + openAPIV3Schema: + properties: + spec: + properties: + healthCheck: + anyOf: + - required: + - active + - required: + - active + - passive + properties: + active: + properties: + concurrency: + minimum: 1 + type: integer + healthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + interval: + type: string + successes: + maximum: 254 + minimum: 1 + type: integer + type: object + host: + pattern: ^\*?[0-9a-zA-Z-._]+$ + type: string + httpPath: + minLength: 1 + type: string + port: + maximum: 65535 + minimum: 1 + type: integer + requestHeaders: + items: + type: string + minItems: 1 + type: array + strictTLS: + type: boolean + timeout: + minimum: 0 + type: number + type: + enum: + - http + - https + - tcp + type: string + unhealthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + httpFailures: + maximum: 254 + minimum: 1 + type: integer + interval: + type: string + tcpFailures: + maximum: 254 + minimum: 1 + type: integer + timeouts: + minimum: 0 + type: integer + type: object + type: object + passive: + properties: + healthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + successes: + maximum: 254 + minimum: 1 + type: integer + type: object + type: + enum: + - http + - https + - tcp + type: string + unhealthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + httpFailures: + maximum: 254 + minimum: 1 + type: integer + tcpFailures: + maximum: 254 + minimum: 1 + type: integer + timeouts: + minimum: 0 + type: integer + type: object + type: object + type: object + loadbalancer: + properties: + hashOn: + enum: + - vars + - vars_combinations + - header + - cookie + - consumer + type: string + key: + type: string + type: + enum: + - roundrobin + - chash + - ewma + - least_conn + type: string + required: + - type + type: object + portLevelSettings: + items: + properties: + healthCheck: + anyOf: + - required: + - active + - required: + - active + - passive + properties: + active: + properties: + concurrency: + minimum: 1 + type: integer + healthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + interval: + type: string + successes: + maximum: 254 + minimum: 1 + type: integer + type: object + host: + pattern: "^\\*?[0-9a-zA-Z-._]+$" + type: string + httpPath: + minLength: 1 + type: string + port: + maximum: 65535 + minimum: 1 + type: integer + requestHeaders: + items: + type: string + minItems: 1 + type: array + strictTLS: + type: boolean + timeout: + minimum: 0 + type: number + type: + enum: + - http + - https + - tcp + type: string + unhealthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + httpFailures: + maximum: 254 + minimum: 1 + type: integer + interval: + type: string + tcpFailures: + maximum: 254 + minimum: 1 + type: integer + timeout: + type: string + type: object + type: object + passive: + properties: + healthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + successes: + maximum: 254 + minimum: 1 + type: integer + type: object + type: + enum: + - http + - https + - tcp + type: string + unhealthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + httpFailures: + maximum: 254 + minimum: 1 + type: integer + tcpFailures: + maximum: 254 + minimum: 1 + type: integer + timeout: + type: string + type: object + type: object + type: object + loadbalancer: + properties: + hashOn: + enum: + - vars + - vars_combinations + - header + - cookie + - consumer + type: string + key: + type: string + type: + enum: + - roundrobin + - chash + - ewma + - least_conn + type: string + required: + - type + type: object + port: + maximum: 65535 + minimum: 1 + type: integer + retries: + minimum: 0 + type: integer + scheme: + enum: + - http + - grpc + type: string + timeout: + properties: + connect: + type: string + read: + type: string + send: + type: string + type: object + type: object + type: array + retries: + minimum: 0 + type: integer + scheme: + enum: + - http + - grpc + - https + - grpcs + type: string + subsets: + items: + properties: + labels: + type: object + x-kubernetes-preserve-unknown-fields: true + name: + minLength: 1 + type: string + required: + - name + - labels + type: object + type: array + timeout: + properties: + connect: + type: string + read: + type: string + send: + type: string + type: object + tlsSecret: + description: ApisixSecret describes the Kubernetes Secret name and namespace. + properties: + name: + minLength: 1 + type: string + namespace: + minLength: 1 + type: string + required: + - name + - namespace + type: object + type: object + status: + properties: + conditions: + items: + properties: + message: + type: string + observedGeneration: + type: integer + reason: + type: string + status: + type: string + type: + type: string + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v2 + schema: + openAPIV3Schema: + properties: + spec: + properties: + discovery: + description: Discovery is used to configure service discovery for upstream + properties: + args: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceName: + type: string + type: + type: string + type: object + externalNodes: + description: ExternalNodes contains external nodes the Upstream should use If this field is set, the upstream will use these nodes directly without any further resolves + items: + description: ApisixUpstreamExternalNode is the external node conf + properties: + name: + type: string + port: + type: integer + type: + type: string + weight: + type: integer + type: object + type: array + healthCheck: + anyOf: + - required: + - active + - required: + - active + - passive + properties: + active: + properties: + concurrency: + minimum: 1 + type: integer + healthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + interval: + type: string + successes: + maximum: 254 + minimum: 1 + type: integer + type: object + host: + pattern: ^\*?[0-9a-zA-Z-._]+$ + type: string + httpPath: + minLength: 1 + type: string + port: + maximum: 65535 + minimum: 1 + type: integer + requestHeaders: + items: + type: string + minItems: 1 + type: array + strictTLS: + type: boolean + timeout: + minimum: 0 + type: number + type: + enum: + - http + - https + - tcp + type: string + unhealthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + httpFailures: + maximum: 254 + minimum: 1 + type: integer + interval: + type: string + tcpFailures: + maximum: 254 + minimum: 1 + type: integer + timeouts: + minimum: 0 + type: integer + type: object + type: object + passive: + properties: + healthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + successes: + maximum: 254 + minimum: 1 + type: integer + type: object + type: + enum: + - http + - https + - tcp + type: string + unhealthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + httpFailures: + maximum: 254 + minimum: 1 + type: integer + tcpFailures: + maximum: 254 + minimum: 1 + type: integer + timeouts: + minimum: 0 + type: integer + type: object + type: object + type: object + ingressClassName: + type: string + loadbalancer: + properties: + hashOn: + enum: + - vars + - vars_combinations + - header + - cookie + - consumer + type: string + key: + type: string + type: + enum: + - roundrobin + - chash + - ewma + - least_conn + type: string + required: + - type + type: object + passHost: + enum: + - pass + - node + - rewrite + type: string + portLevelSettings: + items: + properties: + healthCheck: + anyOf: + - required: + - active + - required: + - active + - passive + properties: + active: + properties: + concurrency: + minimum: 1 + type: integer + healthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + interval: + type: string + successes: + maximum: 254 + minimum: 1 + type: integer + type: object + host: + pattern: ^\*?[0-9a-zA-Z-._]+$ + type: string + httpPath: + minLength: 1 + type: string + port: + maximum: 65535 + minimum: 1 + type: integer + requestHeaders: + items: + type: string + minItems: 1 + type: array + strictTLS: + type: boolean + timeout: + minimum: 0 + type: number + type: + enum: + - http + - https + - tcp + type: string + unhealthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + httpFailures: + maximum: 254 + minimum: 1 + type: integer + interval: + type: string + tcpFailures: + maximum: 254 + minimum: 1 + type: integer + timeout: + type: string + type: object + type: object + passive: + properties: + healthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + successes: + maximum: 254 + minimum: 1 + type: integer + type: object + type: + enum: + - http + - https + - tcp + type: string + unhealthy: + properties: + httpCodes: + items: + maximum: 599 + minimum: 200 + type: integer + minItems: 1 + type: array + httpFailures: + maximum: 254 + minimum: 1 + type: integer + tcpFailures: + maximum: 254 + minimum: 1 + type: integer + timeout: + type: string + type: object + type: object + type: object + loadbalancer: + properties: + hashOn: + enum: + - vars + - vars_combinations + - header + - cookie + - consumer + type: string + key: + type: string + type: + enum: + - roundrobin + - chash + - ewma + - least_conn + type: string + required: + - type + type: object + port: + maximum: 65535 + minimum: 1 + type: integer + retries: + minimum: 0 + type: integer + scheme: + enum: + - http + - grpc + type: string + timeout: + properties: + connect: + type: string + read: + type: string + send: + type: string + type: object + type: object + type: array + retries: + minimum: 0 + type: integer + scheme: + enum: + - http + - grpc + - https + - grpcs + type: string + subsets: + items: + properties: + labels: + type: object + x-kubernetes-preserve-unknown-fields: true + name: + minLength: 1 + type: string + required: + - name + - labels + type: object + type: array + timeout: + properties: + connect: + type: string + read: + type: string + send: + type: string + type: object + tlsSecret: + description: ApisixSecret describes the Kubernetes Secret name and namespace. + properties: + name: + minLength: 1 + type: string + namespace: + minLength: 1 + type: string + required: + - name + - namespace + type: object + upstreamHost: + pattern: ^\*?[0-9a-zA-Z-._]+$ + type: string + type: object + status: + properties: + conditions: + items: + properties: + message: + type: string + observedGeneration: + type: integer + reason: + type: string + status: + type: string + type: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/apisix-ingress-controller/crds/customresourcedefinitions.yaml b/charts/apisix-ingress-controller/crds/customresourcedefinitions.yaml deleted file mode 100644 index 0981fcc7..00000000 --- a/charts/apisix-ingress-controller/crds/customresourcedefinitions.yaml +++ /dev/null @@ -1,3041 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - apisix.apache.org/app: ingress-apisix - name: apisixclusterconfigs.apisix.apache.org -spec: - group: apisix.apache.org - names: - kind: ApisixClusterConfig - plural: apisixclusterconfigs - shortNames: - - acc - singular: apisixclusterconfig - preserveUnknownFields: false - scope: Cluster - versions: - - name: v2beta3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - admin: - properties: - adminKey: - type: string - baseURL: - pattern: https?://[^:]+:(\d+) - type: string - required: - - baseURL - type: object - monitoring: - properties: - prometheus: - properties: - enable: - type: boolean - type: object - skywalking: - properties: - enable: - type: boolean - sampleRatio: - maximum: 1 - minimum: 1e-05 - type: number - type: object - type: object - type: object - type: object - served: true - storage: false - deprecated: true - subresources: - status: {} - - name: v2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - admin: - properties: - adminKey: - type: string - baseURL: - pattern: https?://[^:]+:(\d+) - type: string - required: - - baseURL - type: object - monitoring: - properties: - prometheus: - properties: - enable: - type: boolean - type: object - skywalking: - properties: - enable: - type: boolean - sampleRatio: - maximum: 1 - minimum: 1e-05 - type: number - type: object - type: object - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - apisix.apache.org/app: ingress-apisix - name: apisixconsumers.apisix.apache.org -spec: - group: apisix.apache.org - names: - kind: ApisixConsumer - plural: apisixconsumers - shortNames: - - ac - singular: apisixconsumer - preserveUnknownFields: false - scope: Namespaced - versions: - - name: v2beta3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - authParameter: - oneOf: - - required: - - basicAuth - - required: - - keyAuth - - required: - - wolfRBAC - - required: - - jwtAuth - - required: - - hmacAuth - properties: - basicAuth: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - password: - minLength: 1 - type: string - username: - minLength: 1 - type: string - required: - - username - - password - type: object - type: object - hmacAuth: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - access_key: - type: string - algorithm: - type: string - clock_skew: - type: integer - encode_uri_params: - type: boolean - keep_headers: - type: boolean - max_req_body: - type: integer - secret_key: - type: string - signed_headers: - items: - type: string - type: array - validate_request_body: - type: boolean - required: - - access_key - - secret_key - type: object - type: object - jwtAuth: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - algorithm: - type: string - base64_secret: - type: boolean - exp: - type: integer - key: - minLength: 1 - type: string - private_key: - type: string - public_key: - type: string - secret: - type: string - required: - - key - type: object - type: object - keyAuth: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - key: - minLength: 1 - type: string - required: - - key - type: object - type: object - wolfRBAC: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - appid: - type: string - header_prefix: - type: string - server: - type: string - type: object - type: object - type: object - required: - - authParameter - type: object - type: object - served: true - storage: false - deprecated: true - subresources: - status: {} - - name: v2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - authParameter: - oneOf: - - required: - - basicAuth - - required: - - keyAuth - - required: - - wolfRBAC - - required: - - jwtAuth - - required: - - hmacAuth - properties: - basicAuth: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - password: - minLength: 1 - type: string - username: - minLength: 1 - type: string - required: - - username - - password - type: object - type: object - hmacAuth: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - access_key: - type: string - algorithm: - type: string - clock_skew: - type: integer - encode_uri_params: - type: boolean - keep_headers: - type: boolean - max_req_body: - type: integer - secret_key: - type: string - signed_headers: - items: - type: string - type: array - validate_request_body: - type: boolean - required: - - access_key - - secret_key - type: object - type: object - jwtAuth: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - algorithm: - type: string - base64_secret: - type: boolean - exp: - type: integer - key: - minLength: 1 - type: string - private_key: - type: string - public_key: - type: string - secret: - type: string - required: - - key - type: object - type: object - keyAuth: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - key: - minLength: 1 - type: string - required: - - key - type: object - type: object - wolfRBAC: - oneOf: - - required: - - value - - required: - - secretRef - properties: - secretRef: - properties: - name: - minLength: 1 - type: string - required: - - name - type: object - value: - properties: - appid: - type: string - header_prefix: - type: string - server: - type: string - type: object - type: object - type: object - required: - - authParameter - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - apisix.apache.org/app: ingress-apisix - name: apisixpluginconfigs.apisix.apache.org -spec: - group: apisix.apache.org - names: - kind: ApisixPluginConfig - plural: apisixpluginconfigs - shortNames: - - apc - singular: apisixpluginconfig - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - priority: 0 - type: date - name: v2beta3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - plugins: - items: - properties: - config: - type: object - x-kubernetes-preserve-unknown-fields: true - enable: - type: boolean - name: - minLength: 1 - type: string - type: object - required: - - name - - enable - type: array - required: - - plugins - type: object - status: - properties: - conditions: - items: - properties: - message: - type: string - observedGeneration: - type: integer - reason: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: false - deprecated: true - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - priority: 0 - type: date - name: v2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - plugins: - items: - properties: - config: - type: object - x-kubernetes-preserve-unknown-fields: true - enable: - type: boolean - name: - minLength: 1 - type: string - secretRef: - type: string - type: object - required: - - name - - enable - type: array - required: - - plugins - type: object - status: - properties: - conditions: - items: - properties: - message: - type: string - observedGeneration: - type: integer - reason: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - apisix.apache.org/app: ingress-apisix - name: apisixroutes.apisix.apache.org -spec: - group: apisix.apache.org - names: - kind: ApisixRoute - plural: apisixroutes - shortNames: - - ar - singular: apisixroute - scope: Namespaced - versions: - - name: v2beta1 - additionalPrinterColumns: - - jsonPath: .spec.http[].match.hosts - name: Hosts - priority: 0 - type: string - - jsonPath: .spec.http[].match.paths - name: URIs - priority: 0 - type: string - - jsonPath: .spec.http[].backend.serviceName - name: Target Service(HTTP) - priority: 1 - type: string - - jsonPath: .spec.tcp[].match.ingressPort - name: Ingress Server Port(TCP) - priority: 1 - type: integer - - jsonPath: .spec.tcp[].match.backend.serviceName - name: Target Service(TCP) - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - priority: 0 - type: date - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - http - - required: - - tcp - - required: - - stream - properties: - http: - items: - oneOf: - - required: - - name - - match - - backend - - required: - - name - - match - - backends - properties: - authentication: - properties: - enable: - type: boolean - keyAuth: - properties: - header: - type: string - type: object - type: - enum: - - basicAuth - - keyAuth - type: string - required: - - enable - type: object - backend: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - weight: - minimum: 0 - type: integer - required: - - serviceName - - servicePort - type: object - backends: - items: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - weight: - minimum: 0 - type: integer - type: object - minItems: 1 - required: - - serviceName - - servicePort - type: array - match: - properties: - exprs: - items: - oneOf: - - required: - - subject - - op - - value - - required: - - subject - - op - - set - properties: - op: - enum: - - Equal - - NotEqual - - GreaterThan - - LessThan - - In - - NotIn - - RegexMatch - - RegexNotMatch - - RegexMatchCaseInsensitive - - RegexNotMatchCaseInsensitive - type: string - set: - items: - type: string - type: array - subject: - properties: - name: - minLength: 1 - type: string - scope: - enum: - - Cookie - - Header - - Path - - Query - type: string - required: - - scope - type: object - value: - type: string - type: object - minItems: 1 - type: array - hosts: - items: - pattern: ^\*?[0-9a-zA-Z-._]+$ - type: string - minItems: 1 - type: array - methods: - items: - enum: - - CONNECT - - DELETE - - GET - - HEAD - - OPTIONS - - PATCH - - POST - - PUT - - TRACE - type: string - minItems: 1 - type: array - paths: - items: - pattern: ^/[a-zA-Z0-9\-._~%!$&'()+,;=:@/]*\*?$ - type: string - minItems: 1 - type: array - remoteAddrs: - items: - type: string - minItems: 1 - type: array - required: - - paths - type: object - name: - minLength: 1 - type: string - plugins: - items: - properties: - config: - type: object - x-kubernetes-preserve-unknown-fields: true - enable: - type: boolean - name: - minLength: 1 - type: string - type: object - required: - - name - - enable - type: array - priority: - type: integer - timeout: - properties: - connect: - type: string - read: - type: string - send: - type: string - type: object - websocket: - type: boolean - type: object - minItems: 1 - type: array - stream: - items: - properties: - backend: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - required: - - serviceName - - servicePort - type: object - match: - properties: - ingressPort: - maximum: 65535 - minimum: 1 - type: integer - required: - - ingressPort - type: object - name: - minLength: 1 - type: string - protocol: - enum: - - TCP - - UDP - type: string - required: - - name - - match - - backend - - protocol - type: object - minItems: 1 - type: array - tcp: - items: - properties: - backend: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - required: - - serviceName - - servicePort - type: object - match: - properties: - ingressPort: - maximum: 65535 - minimum: 1 - type: integer - required: - - ingressPort - type: object - name: - minLength: 1 - type: string - required: - - name - - match - - backend - type: object - minItems: 1 - type: array - type: object - status: - properties: - conditions: - items: - properties: - message: - type: string - observedGeneration: - type: integer - reason: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: false - storage: false - deprecated: true - subresources: - status: {} - - name: v2beta2 - additionalPrinterColumns: - - jsonPath: .spec.http[].match.hosts - name: Hosts - priority: 0 - type: string - - jsonPath: .spec.http[].match.paths - name: URIs - priority: 0 - type: string - - jsonPath: .spec.http[].backends[].serviceName - name: Target Service(HTTP) - priority: 1 - type: string - - jsonPath: .spec.tcp[].match.ingressPort - name: Ingress Server Port(TCP) - priority: 1 - type: integer - - jsonPath: .spec.tcp[].match.backend.serviceName - name: Target Service(TCP) - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - priority: 0 - type: date - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - http - - required: - - stream - properties: - http: - items: - properties: - authentication: - properties: - enable: - type: boolean - keyAuth: - properties: - header: - type: string - type: object - type: - enum: - - basicAuth - - keyAuth - type: string - required: - - enable - type: object - backends: - items: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - weight: - minimum: 0 - type: integer - type: object - minItems: 1 - required: - - serviceName - - servicePort - type: array - match: - properties: - exprs: - items: - oneOf: - - required: - - subject - - op - - value - - required: - - subject - - op - - set - properties: - op: - enum: - - Equal - - NotEqual - - GreaterThan - - LessThan - - In - - NotIn - - RegexMatch - - RegexNotMatch - - RegexMatchCaseInsensitive - - RegexNotMatchCaseInsensitive - type: string - set: - items: - type: string - type: array - subject: - properties: - name: - minLength: 1 - type: string - scope: - enum: - - Cookie - - Header - - Path - - Query - type: string - required: - - scope - type: object - value: - type: string - type: object - minItems: 1 - type: array - hosts: - items: - pattern: ^\*?[0-9a-zA-Z-._]+$ - type: string - minItems: 1 - type: array - methods: - items: - enum: - - CONNECT - - DELETE - - GET - - HEAD - - OPTIONS - - PATCH - - POST - - PUT - - TRACE - type: string - minItems: 1 - type: array - paths: - items: - pattern: ^/[a-zA-Z0-9\-._~%!$&'()+,;=:@/]*\*?$ - type: string - minItems: 1 - type: array - remoteAddrs: - items: - type: string - minItems: 1 - type: array - required: - - paths - type: object - name: - minLength: 1 - type: string - plugins: - items: - properties: - config: - type: object - x-kubernetes-preserve-unknown-fields: true - enable: - type: boolean - name: - minLength: 1 - type: string - type: object - required: - - name - - enable - type: array - priority: - type: integer - timeout: - properties: - connect: - type: string - read: - type: string - send: - type: string - type: object - websocket: - type: boolean - required: - - name - - match - - backends - type: object - minItems: 1 - type: array - stream: - items: - properties: - backend: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - required: - - serviceName - - servicePort - type: object - match: - properties: - ingressPort: - maximum: 65535 - minimum: 1 - type: integer - required: - - ingressPort - type: object - name: - minLength: 1 - type: string - protocol: - enum: - - TCP - - UDP - type: string - required: - - name - - match - - backend - - protocol - type: object - minItems: 1 - type: array - type: object - status: - properties: - conditions: - items: - properties: - message: - type: string - observedGeneration: - type: integer - reason: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: false - deprecated: true - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.http[].match.hosts - name: Hosts - priority: 0 - type: string - - jsonPath: .spec.http[].match.paths - name: URIs - priority: 0 - type: string - - jsonPath: .spec.http[].backends[].serviceName - name: Target Service(HTTP) - priority: 1 - type: string - - jsonPath: .spec.tcp[].match.ingressPort - name: Ingress Server Port(TCP) - priority: 1 - type: integer - - jsonPath: .spec.tcp[].match.backend.serviceName - name: Target Service(TCP) - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - priority: 0 - type: date - name: v2beta3 - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - http - - required: - - stream - properties: - http: - items: - properties: - authentication: - properties: - enable: - type: boolean - jwtAuth: - properties: - cookie: - type: string - header: - type: string - query: - type: string - type: object - keyAuth: - properties: - header: - type: string - type: object - type: - enum: - - basicAuth - - keyAuth - - jwtAuth - - wolfRBAC - - hmacAuth - type: string - required: - - enable - type: object - backends: - items: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - weight: - minimum: 0 - type: integer - type: object - minItems: 1 - required: - - serviceName - - servicePort - type: array - match: - properties: - exprs: - items: - oneOf: - - required: - - subject - - op - - value - - required: - - subject - - op - - set - properties: - op: - enum: - - Equal - - NotEqual - - GreaterThan - - LessThan - - In - - NotIn - - RegexMatch - - RegexNotMatch - - RegexMatchCaseInsensitive - - RegexNotMatchCaseInsensitive - type: string - set: - items: - type: string - type: array - subject: - properties: - name: - minLength: 1 - type: string - scope: - enum: - - Cookie - - Header - - Path - - Query - type: string - required: - - scope - type: object - value: - type: string - type: object - minItems: 1 - type: array - hosts: - items: - pattern: ^\*?[0-9a-zA-Z-._]+$ - type: string - minItems: 1 - type: array - methods: - items: - enum: - - CONNECT - - DELETE - - GET - - HEAD - - OPTIONS - - PATCH - - POST - - PUT - - TRACE - type: string - minItems: 1 - type: array - paths: - items: - pattern: ^/[a-zA-Z0-9\-._~%!$&'()+,;=:@/]*\*?$ - type: string - minItems: 1 - type: array - remoteAddrs: - items: - type: string - minItems: 1 - type: array - required: - - paths - type: object - name: - minLength: 1 - type: string - plugin_config_name: - minLength: 1 - type: string - plugins: - items: - properties: - config: - type: object - x-kubernetes-preserve-unknown-fields: true - enable: - type: boolean - name: - minLength: 1 - type: string - type: object - required: - - name - - enable - type: array - priority: - type: integer - timeout: - properties: - connect: - type: string - read: - type: string - send: - type: string - type: object - websocket: - type: boolean - required: - - name - - match - - backends - type: object - minItems: 1 - type: array - stream: - items: - properties: - backend: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - required: - - serviceName - - servicePort - type: object - match: - properties: - ingressPort: - maximum: 65535 - minimum: 1 - type: integer - required: - - ingressPort - type: object - name: - minLength: 1 - type: string - protocol: - enum: - - TCP - - UDP - type: string - required: - - name - - match - - backend - - protocol - type: object - minItems: 1 - type: array - type: object - status: - properties: - conditions: - items: - properties: - message: - type: string - observedGeneration: - type: integer - reason: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: false - deprecated: true - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.http[].match.hosts - name: Hosts - priority: 0 - type: string - - jsonPath: .spec.http[].match.paths - name: URIs - priority: 0 - type: string - - jsonPath: .spec.http[].backends[].serviceName - name: Target Service(HTTP) - priority: 1 - type: string - - jsonPath: .spec.tcp[].match.ingressPort - name: Ingress Server Port(TCP) - priority: 1 - type: integer - - jsonPath: .spec.tcp[].match.backend.serviceName - name: Target Service(TCP) - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - priority: 0 - type: date - name: v2 - schema: - openAPIV3Schema: - properties: - spec: - anyOf: - - required: - - http - - required: - - stream - properties: - http: - items: - anyOf: - - required: - - name - - match - - backends - - required: - - name - - match - - upstreams - properties: - authentication: - properties: - enable: - type: boolean - jwtAuth: - properties: - cookie: - type: string - header: - type: string - query: - type: string - type: object - keyAuth: - properties: - header: - type: string - type: object - type: - enum: - - basicAuth - - keyAuth - - jwtAuth - - wolfRBAC - - hmacAuth - type: string - required: - - enable - type: object - backends: - items: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - weight: - minimum: 0 - type: integer - type: object - minItems: 1 - required: - - serviceName - - servicePort - type: array - match: - properties: - exprs: - items: - oneOf: - - required: - - subject - - op - - value - - required: - - subject - - op - - set - properties: - op: - enum: - - Equal - - NotEqual - - GreaterThan - - GreaterThanEqual - - LessThan - - LessThanEqual - - In - - NotIn - - RegexMatch - - RegexNotMatch - - RegexMatchCaseInsensitive - - RegexNotMatchCaseInsensitive - type: string - set: - items: - type: string - type: array - subject: - properties: - name: - minLength: 1 - type: string - scope: - enum: - - Cookie - - Header - - Path - - Query - - Variable - type: string - required: - - scope - type: object - value: - type: string - type: object - minItems: 1 - type: array - hosts: - items: - pattern: ^\*?[0-9a-zA-Z-._]+$ - type: string - minItems: 1 - type: array - methods: - items: - enum: - - CONNECT - - DELETE - - GET - - HEAD - - OPTIONS - - PATCH - - POST - - PUT - - TRACE - type: string - minItems: 1 - type: array - paths: - items: - pattern: ^/[a-zA-Z0-9\-._~%!$&'()+,;=:@/]*\*?$ - type: string - minItems: 1 - type: array - remoteAddrs: - items: - type: string - minItems: 1 - type: array - required: - - paths - type: object - name: - minLength: 1 - type: string - plugin_config_name: - minLength: 1 - type: string - plugins: - items: - properties: - config: - type: object - x-kubernetes-preserve-unknown-fields: true - enable: - type: boolean - name: - minLength: 1 - type: string - secretRef: - type: string - type: object - required: - - name - - enable - type: array - priority: - type: integer - timeout: - properties: - connect: - type: string - read: - type: string - send: - type: string - type: object - upstreams: - description: Upstreams refer to ApisixUpstream CRD - items: - description: ApisixRouteUpstreamReference contains a ApisixUpstream - CRD reference - properties: - name: - type: string - weight: - type: integer - type: object - type: array - websocket: - type: boolean - type: object - minItems: 1 - type: array - stream: - items: - properties: - backend: - properties: - resolveGranularity: - enum: - - endpoint - - service - type: string - serviceName: - minLength: 1 - type: string - servicePort: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - subset: - type: string - required: - - serviceName - - servicePort - type: object - match: - properties: - host: - type: string - ingressPort: - maximum: 65535 - minimum: 1 - type: integer - required: - - ingressPort - type: object - name: - minLength: 1 - type: string - plugins: - items: - properties: - config: - type: object - x-kubernetes-preserve-unknown-fields: true - enable: - type: boolean - name: - minLength: 1 - type: string - secretRef: - type: string - type: object - required: - - name - - enable - type: array - protocol: - enum: - - TCP - - UDP - type: string - required: - - name - - match - - backend - - protocol - type: object - minItems: 1 - type: array - type: object - status: - properties: - conditions: - items: - properties: - message: - type: string - observedGeneration: - type: integer - reason: - type: string - status: - type: string - type: - type: string - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - apisix.apache.org/app: ingress-apisix - name: apisixtlses.apisix.apache.org -spec: - group: apisix.apache.org - names: - kind: ApisixTls - plural: apisixtlses - shortNames: - - atls - singular: apisixtls - preserveUnknownFields: false - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.hosts - name: SNIs - type: string - - jsonPath: .spec.secret.name - name: Secret Name - type: string - - jsonPath: .spec.secret.namespace - name: Secret Namespace - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v2beta3 - schema: - openAPIV3Schema: - description: ApisixTls defines SSL resource in APISIX. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: ApisixTlsSpec is the specification of ApisixSSL. - properties: - client: - description: ApisixMutualTlsClientConfig describes the mutual TLS - CA and verify depth - properties: - caSecret: - description: ApisixSecret describes the Kubernetes Secret name - and namespace. - properties: - name: - minLength: 1 - type: string - namespace: - minLength: 1 - type: string - required: - - name - - namespace - type: object - depth: - type: integer - type: object - hosts: - items: - pattern: ^\*?[0-9a-zA-Z-.]+$ - type: string - minItems: 1 - type: array - secret: - description: ApisixSecret describes the Kubernetes Secret name and - namespace. - properties: - name: - minLength: 1 - type: string - namespace: - minLength: 1 - type: string - required: - - name - - namespace - type: object - required: - - hosts - - secret - type: object - status: - description: ApisixStatus is the status report for Apisix ingress Resources - properties: - conditions: - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: - \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // +listMapKey=type - \ Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: false - deprecated: true - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.hosts - name: SNIs - type: string - - jsonPath: .spec.secret.name - name: Secret Name - type: string - - jsonPath: .spec.secret.namespace - name: Secret Namespace - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v2 - schema: - openAPIV3Schema: - description: ApisixTls defines SSL resource in APISIX. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: ApisixTlsSpec is the specification of ApisixSSL. - properties: - client: - description: ApisixMutualTlsClientConfig describes the mutual TLS - CA and verify depth - properties: - caSecret: - description: ApisixSecret describes the Kubernetes Secret name - and namespace. - properties: - name: - minLength: 1 - type: string - namespace: - minLength: 1 - type: string - required: - - name - - namespace - type: object - depth: - type: integer - type: object - hosts: - items: - pattern: ^\*?[0-9a-zA-Z-.]+$ - type: string - minItems: 1 - type: array - secret: - description: ApisixSecret describes the Kubernetes Secret name and - namespace. - properties: - name: - minLength: 1 - type: string - namespace: - minLength: 1 - type: string - required: - - name - - namespace - type: object - required: - - hosts - - secret - type: object - status: - description: ApisixStatus is the status report for Apisix ingress Resources - properties: - conditions: - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: - \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // +listMapKey=type - \ Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - labels: - apisix.apache.org/app: ingress-apisix - name: apisixupstreams.apisix.apache.org -spec: - group: apisix.apache.org - names: - kind: ApisixUpstream - plural: apisixupstreams - shortNames: - - au - singular: apisixupstream - scope: Namespaced - versions: - - name: v2beta3 - schema: - openAPIV3Schema: - properties: - spec: - properties: - healthCheck: - anyOf: - - required: - - active - - required: - - active - - passive - properties: - active: - properties: - concurrency: - minimum: 1 - type: integer - healthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - interval: - type: string - successes: - maximum: 254 - minimum: 1 - type: integer - type: object - host: - pattern: ^\*?[0-9a-zA-Z-._]+$ - type: string - httpPath: - minLength: 1 - type: string - port: - maximum: 65535 - minimum: 1 - type: integer - requestHeaders: - items: - type: string - minItems: 1 - type: array - strictTLS: - type: boolean - timeout: - minimum: 0 - type: number - type: - enum: - - http - - https - - tcp - type: string - unhealthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - httpFailures: - maximum: 254 - minimum: 1 - type: integer - interval: - type: string - tcpFailures: - maximum: 254 - minimum: 1 - type: integer - timeouts: - minimum: 0 - type: integer - type: object - type: object - passive: - properties: - healthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - successes: - maximum: 254 - minimum: 1 - type: integer - type: object - type: - enum: - - http - - https - - tcp - type: string - unhealthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - httpFailures: - maximum: 254 - minimum: 1 - type: integer - tcpFailures: - maximum: 254 - minimum: 1 - type: integer - timeouts: - minimum: 0 - type: integer - type: object - type: object - type: object - loadbalancer: - properties: - hashOn: - enum: - - vars - - vars_combinations - - header - - cookie - - consumer - type: string - key: - type: string - type: - enum: - - roundrobin - - chash - - ewma - - least_conn - type: string - required: - - type - type: object - portLevelSettings: - items: - properties: - healthCheck: - anyOf: - - required: - - active - - required: - - active - - passive - properties: - active: - properties: - concurrency: - minimum: 1 - type: integer - healthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - interval: - type: string - successes: - maximum: 254 - minimum: 1 - type: integer - type: object - host: - pattern: ^\*?[0-9a-zA-Z-._]+$ - type: string - httpPath: - minLength: 1 - type: string - port: - maximum: 65535 - minimum: 1 - type: integer - requestHeaders: - items: - type: string - minItems: 1 - type: array - strictTLS: - type: boolean - timeout: - minimum: 0 - type: number - type: - enum: - - http - - https - - tcp - type: string - unhealthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - httpFailures: - maximum: 254 - minimum: 1 - type: integer - interval: - type: string - tcpFailures: - maximum: 254 - minimum: 1 - type: integer - timeout: - type: string - type: object - type: object - passive: - properties: - healthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - successes: - maximum: 254 - minimum: 1 - type: integer - type: object - type: - enum: - - http - - https - - tcp - type: string - unhealthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - httpFailures: - maximum: 254 - minimum: 1 - type: integer - tcpFailures: - maximum: 254 - minimum: 1 - type: integer - timeout: - type: string - type: object - type: object - type: object - loadbalancer: - properties: - hashOn: - enum: - - vars - - vars_combinations - - header - - cookie - - consumer - type: string - key: - type: string - type: - enum: - - roundrobin - - chash - - ewma - - least_conn - type: string - required: - - type - type: object - port: - maximum: 65535 - minimum: 1 - type: integer - retries: - minimum: 0 - type: integer - scheme: - enum: - - http - - grpc - type: string - timeout: - properties: - connect: - type: string - read: - type: string - send: - type: string - type: object - type: object - type: array - retries: - minimum: 0 - type: integer - scheme: - enum: - - http - - grpc - - https - - grpcs - type: string - subsets: - items: - properties: - labels: - type: object - x-kubernetes-preserve-unknown-fields: true - name: - minLength: 1 - type: string - required: - - name - - labels - type: object - type: array - timeout: - properties: - connect: - type: string - read: - type: string - send: - type: string - type: object - tlsSecret: - description: ApisixSecret describes the Kubernetes Secret name and - namespace. - properties: - name: - minLength: 1 - type: string - namespace: - minLength: 1 - type: string - required: - - name - - namespace - type: object - type: object - type: object - served: true - storage: false - deprecated: true - subresources: - status: {} - - name: v2 - schema: - openAPIV3Schema: - properties: - spec: - properties: - discovery: - description: Discovery is used to configure service discovery for - upstream - properties: - args: - type: object - x-kubernetes-preserve-unknown-fields: true - serviceName: - type: string - type: - type: string - type: object - externalNodes: - description: ExternalNodes contains external nodes the Upstream should - use If this field is set, the upstream will use these nodes directly - without any further resolves - items: - description: ApisixUpstreamExternalNode is the external node conf - properties: - name: - type: string - port: - type: integer - type: - type: string - weight: - type: integer - type: object - type: array - healthCheck: - anyOf: - - required: - - active - - required: - - active - - passive - properties: - active: - properties: - concurrency: - minimum: 1 - type: integer - healthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - interval: - type: string - successes: - maximum: 254 - minimum: 1 - type: integer - type: object - host: - pattern: ^\*?[0-9a-zA-Z-._]+$ - type: string - httpPath: - minLength: 1 - type: string - port: - maximum: 65535 - minimum: 1 - type: integer - requestHeaders: - items: - type: string - minItems: 1 - type: array - strictTLS: - type: boolean - timeout: - minimum: 0 - type: number - type: - enum: - - http - - https - - tcp - type: string - unhealthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - httpFailures: - maximum: 254 - minimum: 1 - type: integer - interval: - type: string - tcpFailures: - maximum: 254 - minimum: 1 - type: integer - timeouts: - minimum: 0 - type: integer - type: object - type: object - passive: - properties: - healthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - successes: - maximum: 254 - minimum: 1 - type: integer - type: object - type: - enum: - - http - - https - - tcp - type: string - unhealthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - httpFailures: - maximum: 254 - minimum: 1 - type: integer - tcpFailures: - maximum: 254 - minimum: 1 - type: integer - timeouts: - minimum: 0 - type: integer - type: object - type: object - type: object - loadbalancer: - properties: - hashOn: - enum: - - vars - - vars_combinations - - header - - cookie - - consumer - type: string - key: - type: string - type: - enum: - - roundrobin - - chash - - ewma - - least_conn - type: string - required: - - type - type: object - portLevelSettings: - items: - properties: - healthCheck: - anyOf: - - required: - - active - - required: - - active - - passive - properties: - active: - properties: - concurrency: - minimum: 1 - type: integer - healthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - interval: - type: string - successes: - maximum: 254 - minimum: 1 - type: integer - type: object - host: - pattern: ^\*?[0-9a-zA-Z-._]+$ - type: string - httpPath: - minLength: 1 - type: string - port: - maximum: 65535 - minimum: 1 - type: integer - requestHeaders: - items: - type: string - minItems: 1 - type: array - strictTLS: - type: boolean - timeout: - minimum: 0 - type: number - type: - enum: - - http - - https - - tcp - type: string - unhealthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - httpFailures: - maximum: 254 - minimum: 1 - type: integer - interval: - type: string - tcpFailures: - maximum: 254 - minimum: 1 - type: integer - timeout: - type: string - type: object - type: object - passive: - properties: - healthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - successes: - maximum: 254 - minimum: 1 - type: integer - type: object - type: - enum: - - http - - https - - tcp - type: string - unhealthy: - properties: - httpCodes: - items: - maximum: 599 - minimum: 200 - type: integer - minItems: 1 - type: array - httpFailures: - maximum: 254 - minimum: 1 - type: integer - tcpFailures: - maximum: 254 - minimum: 1 - type: integer - timeout: - type: string - type: object - type: object - type: object - loadbalancer: - properties: - hashOn: - enum: - - vars - - vars_combinations - - header - - cookie - - consumer - type: string - key: - type: string - type: - enum: - - roundrobin - - chash - - ewma - - least_conn - type: string - required: - - type - type: object - port: - maximum: 65535 - minimum: 1 - type: integer - retries: - minimum: 0 - type: integer - scheme: - enum: - - http - - grpc - type: string - timeout: - properties: - connect: - type: string - read: - type: string - send: - type: string - type: object - type: object - type: array - retries: - minimum: 0 - type: integer - scheme: - enum: - - http - - grpc - - https - - grpcs - type: string - subsets: - items: - properties: - labels: - type: object - x-kubernetes-preserve-unknown-fields: true - name: - minLength: 1 - type: string - required: - - name - - labels - type: object - type: array - timeout: - properties: - connect: - type: string - read: - type: string - send: - type: string - type: object - tlsSecret: - description: ApisixSecret describes the Kubernetes Secret name and - namespace. - properties: - name: - minLength: 1 - type: string - namespace: - minLength: 1 - type: string - required: - - name - - namespace - type: object - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/charts/apisix-ingress-controller/templates/_helpers.tpl b/charts/apisix-ingress-controller/templates/_helpers.tpl index 4426f908..6efcc0ea 100644 --- a/charts/apisix-ingress-controller/templates/_helpers.tpl +++ b/charts/apisix-ingress-controller/templates/_helpers.tpl @@ -85,3 +85,14 @@ Create the name of the service account to use {{- define "apisix-ingress-controller.namespace" -}} {{- default .Release.Namespace .Values.namespace -}} {{- end -}} + +{{/* +Key to use to fetch admin token from secret +*/}} +{{- define "apisix-ingress-controller.credentials.secretAdminKey" -}} +{{- if .Values.config.apisix.existingSecretAdminKeyKey }} +{{- .Values.config.apisix.existingSecretAdminKeyKey }} +{{- else }} +{{- "adminKey" }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/apisix-ingress-controller/templates/apisix-configmap.yaml b/charts/apisix-ingress-controller/templates/apisix-configmap.yaml new file mode 100644 index 00000000..f26fd320 --- /dev/null +++ b/charts/apisix-ingress-controller/templates/apisix-configmap.yaml @@ -0,0 +1,174 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{ if .Values.config.etcdserver.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-gw-configmap + namespace: {{ .Release.Namespace }} + labels: + {{- include "apisix-ingress-controller.labels" . | nindent 4 }} +data: + config.yaml: > + deployment: + admin: + allow_admin: + - 127.0.0.0/24 + - 0.0.0.0/0 + admin_listen: + ip: 0.0.0.0 + port: 9180 + etcd: + host: + - "http://127.0.0.1:12379" + prefix: "/apisix" + timeout: 60 + + apisix: + enable_control: true + enable_reuseport: true + + stream_proxy: + only: false + tcp: + - 9100 + - addr: 9110 + tls: true + udp: + - 9200 + + ssl: + enable: {{ .Values.gateway.tls.enabled }} + listen: + - port: {{ .Values.gateway.tls.containerPort }} + enable_http2: {{ .Values.gateway.tls.http2.enabled }} + {{- with .Values.gateway.tls.additionalContainerPorts }} + {{- toYaml . | nindent 10}} + {{- end }} + ssl_protocols: {{ .Values.gateway.tls.sslProtocols | quote }} + 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:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" + {{- if and .Values.gateway.tls.enabled .Values.gateway.tls.existingCASecret }} + ssl_trusted_certificate: "/usr/local/apisix/conf/ssl/{{ .Values.gateway.tls.certCAFilename }}" + {{- end }} + {{- if and .Values.gateway.tls.enabled .Values.gateway.tls.fallbackSNI }} + fallback_sni: {{ .Values.gateway.tls.fallbackSNI | quote }} + {{- end }} + + nginx_config: + error_log: "{{ .Values.gateway.nginx.errorLog }}" + error_log_level: "{{ .Values.gateway.nginx.errorLogLevel }}" # warn,error + worker_processes: "{{ .Values.gateway.nginx.workerProcesses }}" + worker_rlimit_nofile: {{ .Values.gateway.nginx.workerRlimitNofile }} # the number of files a worker process can open, should be larger than worker_connections + event: + worker_connections: {{ .Values.gateway.nginx.workerConnections }} + + plugins: # plugin list (sorted by priority) + - real-ip # priority: 23000 + - ai # priority: 22900 + - client-control # priority: 22000 + - proxy-control # priority: 21990 + - request-id # priority: 12015 + - zipkin # priority: 12011 + #- skywalking # priority: 12010 + #- opentelemetry # priority: 12009 + - ext-plugin-pre-req # priority: 12000 + - fault-injection # priority: 11000 + - mocking # priority: 10900 + - serverless-pre-function # priority: 10000 + #- batch-requests # priority: 4010 + - cors # priority: 4000 + - ip-restriction # priority: 3000 + - ua-restriction # priority: 2999 + - referer-restriction # priority: 2990 + - csrf # priority: 2980 + - uri-blocker # priority: 2900 + - request-validation # priority: 2800 + - openid-connect # priority: 2599 + - cas-auth # priority: 2597 + - authz-casbin # priority: 2560 + - authz-casdoor # priority: 2559 + - wolf-rbac # priority: 2555 + - ldap-auth # priority: 2540 + - hmac-auth # priority: 2530 + - basic-auth # priority: 2520 + - jwt-auth # priority: 2510 + - key-auth # priority: 2500 + - consumer-restriction # priority: 2400 + - forward-auth # priority: 2002 + - opa # priority: 2001 + - authz-keycloak # priority: 2000 + #- error-log-logger # priority: 1091 + - proxy-mirror # priority: 1010 + - proxy-cache # priority: 1009 + - proxy-rewrite # priority: 1008 + - workflow # priority: 1006 + - api-breaker # priority: 1005 + - limit-conn # priority: 1003 + - limit-count # priority: 1002 + - limit-req # priority: 1001 + #- node-status # priority: 1000 + - gzip # priority: 995 + - traffic-split # priority: 966 + - redirect # priority: 900 + - response-rewrite # priority: 899 + - kafka-proxy # priority: 508 + #- dubbo-proxy # priority: 507 + - grpc-transcode # priority: 506 + - grpc-web # priority: 505 + - public-api # priority: 501 + - prometheus # priority: 500 + - datadog # priority: 495 + - elasticsearch-logger # priority: 413 + - echo # priority: 412 + - loggly # priority: 411 + - http-logger # priority: 410 + - splunk-hec-logging # priority: 409 + - skywalking-logger # priority: 408 + - google-cloud-logging # priority: 407 + - sls-logger # priority: 406 + - tcp-logger # priority: 405 + - kafka-logger # priority: 403 + - rocketmq-logger # priority: 402 + - syslog # priority: 401 + - udp-logger # priority: 400 + - file-logger # priority: 399 + - clickhouse-logger # priority: 398 + - tencent-cloud-cls # priority: 397 + - inspect # priority: 200 + #- log-rotate # priority: 100 + # <- recommend to use priority (0, 100) for your custom plugins + - example-plugin # priority: 0 + #- gm # priority: -43 + - aws-lambda # priority: -1899 + - azure-functions # priority: -1900 + - openwhisk # priority: -1901 + - openfunction # priority: -1902 + - serverless-post-function # priority: -2000 + - ext-plugin-post-req # priority: -3000 + - ext-plugin-post-resp # priority: -4000 + + plugin_attr: + prometheus: + enable_export_server: {{ .Values.serviceMonitor.enabled }} + {{- if .Values.serviceMonitor.enabled }} + export_addr: + ip: 0.0.0.0 + port: 9091 + export_uri: /apisix/prometheus/metrics + metric_prefix: apisix_ + {{- end }} +{{ end }} diff --git a/charts/apisix-ingress-controller/templates/configmap.yaml b/charts/apisix-ingress-controller/templates/configmap.yaml index 107a7fb5..01612165 100644 --- a/charts/apisix-ingress-controller/templates/configmap.yaml +++ b/charts/apisix-ingress-controller/templates/configmap.yaml @@ -24,7 +24,11 @@ data: key_file: {{ .Values.config.keyFile | quote }} http_listen: {{ .Values.config.httpListen | quote }} https_listen: {{ .Values.config.httpsListen | quote }} + {{- if and (eq .Values.config.ingressPublishService "") (.Values.config.etcdserver.enabled) }} + ingress_publish_service: {{ .Release.Namespace }}/{{ include "apisix-ingress-controller.fullname" . }}-apisix-gateway + {{- else }} ingress_publish_service: {{ .Values.config.ingressPublishService | quote }} + {{- end }} {{- if gt (len .Values.config.ingressStatusAddress) 0 }} ingress_status_address: {{- range .Values.config.ingressStatusAddress }} @@ -33,6 +37,7 @@ data: {{- end }} enable_profiling: {{ .Values.config.enableProfiling }} apisix_resource_sync_interval: {{ .Values.config.apisixResourceSyncInterval }} + plugin_metadata_cm: {{ .Values.config.pluginMetadataCM | quote }} kubernetes: kubeconfig: {{ .Values.config.kubernetes.kubeconfig | quote }} resync_interval: {{ .Values.config.kubernetes.resyncInterval | quote }} @@ -50,16 +55,27 @@ data: apisix_route_version: {{ .Values.config.kubernetes.apisixRouteVersion | quote }} enable_gateway_api: {{ .Values.config.kubernetes.enableGatewayAPI }} apisix_version: {{ .Values.config.kubernetes.apiVersion | quote }} - plugin_metadata_cm: {{ .Values.config.kubernetes.pluginMetadataCM | quote }} apisix: admin_api_version: {{ .Values.config.apisix.adminAPIVersion | quote }} + {{- if .Values.config.etcdserver.enabled }} + default_cluster_base_url: http://127.0.0.1:9180/apisix/admin + {{ else }} {{- if .Values.config.apisix.serviceFullname }} default_cluster_base_url: http://{{ .Values.config.apisix.serviceFullname }}:{{ .Values.config.apisix.servicePort }}/apisix/admin {{ else }} default_cluster_base_url: http://{{ .Values.config.apisix.serviceName }}.{{ .Values.config.apisix.serviceNamespace }}.svc.{{ .Values.clusterDomain }}:{{ .Values.config.apisix.servicePort }}/apisix/admin {{- end}} + {{- end }} + {{- if .Values.config.apisix.existingSecret }} + default_cluster_admin_key: "{{"{{"}}.DEFAULT_CLUSTER_ADMIN_KEY{{"}}"}}" + {{- else }} default_cluster_admin_key: {{ .Values.config.apisix.adminKey | quote }} + {{- end }} default_cluster_name: {{ .Values.config.apisix.clusterName | quote }} + {{ if .Values.config.etcdserver.enabled }} + etcdserver: + enabled: true + {{ end }} kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap diff --git a/charts/apisix-ingress-controller/templates/deployment.yaml b/charts/apisix-ingress-controller/templates/deployment.yaml index 6ee1226f..76d74858 100644 --- a/charts/apisix-ingress-controller/templates/deployment.yaml +++ b/charts/apisix-ingress-controller/templates/deployment.yaml @@ -19,6 +19,10 @@ kind: Deployment metadata: name: {{ include "apisix-ingress-controller.fullname" . }} namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $value := .Values.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} labels: {{- include "apisix-ingress-controller.labels" . | nindent 4 }} spec: @@ -28,6 +32,9 @@ spec: selector: matchLabels: {{- include "apisix-ingress-controller.selectorLabels" . | nindent 6 }} + {{- with .Values.updateStrategy }} + strategy: {{ toYaml . | nindent 4 }} + {{- end }} template: metadata: annotations: @@ -57,6 +64,12 @@ spec: items: - key: config.yaml path: config.yaml + {{ if .Values.config.etcdserver.enabled }} + - name: apisix-config + configMap: + name: {{ .Release.Name }}-gw-configmap + {{ end }} + {{ if not .Values.config.etcdserver.enabled }} initContainers: - name: wait-apisix-admin image: {{ .Values.initContainer.image }}:{{ .Values.initContainer.tag }} @@ -68,6 +81,7 @@ spec: securityContext: {{- toYaml .Values.securityContext | nindent 12 }} + {{ end }} containers: - name: {{ .Chart.Name }} command: @@ -75,12 +89,19 @@ spec: - ingress - --config-path - /ingress-apisix/conf/config.yaml + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: {{ (.Values.config.httpListen | split ":")._1 }} protocol: TCP + {{ if .Values.config.etcdserver.enabled }} + - name: etcd + containerPort: 12379 + protocol: TCP + {{ end }} livenessProbe: httpGet: path: /healthz @@ -92,8 +113,9 @@ spec: resources: {{- toYaml .Values.resources | nindent 12 }} volumeMounts: - - mountPath: /ingress-apisix/conf + - mountPath: /ingress-apisix/conf/config.yaml name: configuration + subPath: config.yaml env: - name: POD_NAMESPACE valueFrom: @@ -103,6 +125,41 @@ spec: valueFrom: fieldRef: fieldPath: metadata.name + {{- if .Values.config.apisix.existingSecret }} + - name: DEFAULT_CLUSTER_ADMIN_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.config.apisix.existingSecret | quote }} + key: {{ include "apisix-ingress-controller.credentials.secretAdminKey" . }} + {{- end }} + {{ if .Values.config.etcdserver.enabled }} + - name: apisix + image: "{{ .Values.config.etcdserver.image.repository }}:{{ .Values.config.etcdserver.image.tag }}" + imagePullPolicy: {{ .Values.config.etcdserver.image.pullPolicy }} + ports: + - name: http + containerPort: 9080 + protocol: TCP + - name: http-admin + containerPort: 9180 + protocol: TCP + - name: https + containerPort: {{ .Values.gateway.tls.containerPort }} + protocol: TCP + {{- if .Values.serviceMonitor.enabled }} + - containerPort: 9091 + name: prometheus + protocol: TCP + {{- end }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.gateway.securityContext | nindent 12 }} + volumeMounts: + - name: apisix-config + mountPath: /usr/local/apisix/conf/config.yaml + subPath: config.yaml + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -111,3 +168,11 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- tpl (. | toYaml) $ | nindent 8 }} + {{- end }} diff --git a/charts/apisix-ingress-controller/templates/ingress-class.yaml b/charts/apisix-ingress-controller/templates/ingress-class.yaml new file mode 100644 index 00000000..0099b3a4 --- /dev/null +++ b/charts/apisix-ingress-controller/templates/ingress-class.yaml @@ -0,0 +1,12 @@ +{{ if or (eq .Values.config.kubernetes.ingressVersion "") (eq .Values.config.kubernetes.ingressVersion "networking/v1")}} +apiVersion: networking.k8s.io/v1 +{{- else if (eq .Values.config.kubernetes.ingressVersion "networking/v1beta1")}} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: {{ .Values.config.kubernetes.ingressVersion }} +{{- end }} +kind: IngressClass +metadata: + name: {{ .Values.config.kubernetes.ingressClass | quote }} +spec: + controller: apisix.apache.org/apisix-ingress # fix: https://github.com/apache/apisix-ingress-controller/issues/1653 diff --git a/charts/apisix-ingress-controller/templates/pdb.yaml b/charts/apisix-ingress-controller/templates/pdb.yaml new file mode 100644 index 00000000..46cdca9c --- /dev/null +++ b/charts/apisix-ingress-controller/templates/pdb.yaml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{{- if and .Values.podDisruptionBudget.enabled (or (and .Values.autoscaling.enabled (gt (.Values.autoscaling.minReplicas | int) 1)) (and (not .Values.autoscaling.enabled) (gt (.Values.replicaCount | int) 1))) }} +{{ if semverCompare "<1.21-0" .Capabilities.KubeVersion.Version -}} +apiVersion: policy/v1beta1 +{{- else -}} +apiVersion: policy/v1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: {{ include "apisix-ingress-controller.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "apisix-ingress-controller.labels" . | nindent 4 }} +spec: +{{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} +{{- else }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} +{{- end }} + selector: + matchLabels: +{{- include "apisix-ingress-controller.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/charts/apisix-ingress-controller/templates/rbac.yaml b/charts/apisix-ingress-controller/templates/rbac.yaml index 385b8625..96c0c933 100644 --- a/charts/apisix-ingress-controller/templates/rbac.yaml +++ b/charts/apisix-ingress-controller/templates/rbac.yaml @@ -110,6 +110,8 @@ rules: - apiGroups: - gateway.networking.k8s.io resources: + - tcproutes + - udproutes - httproutes - tlsroutes - gateways @@ -121,6 +123,8 @@ rules: - apiGroups: - gateway.networking.k8s.io resources: + - tcproutes/status + - udproutes/status - httproutes/status - tlsroutes/status - gateways/status diff --git a/charts/apisix-ingress-controller/templates/service-apisix.yaml b/charts/apisix-ingress-controller/templates/service-apisix.yaml new file mode 100644 index 00000000..4abf0f3a --- /dev/null +++ b/charts/apisix-ingress-controller/templates/service-apisix.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "apisix-ingress-controller.fullname" . }}-apisix-gateway + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $value := .Values.gateway.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + labels: + {{- include "apisix-ingress-controller.labels" . | nindent 4 }} +spec: + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 9080 + - name: https + protocol: TCP + port: {{ .Values.gateway.tls.servicePort }} + targetPort: {{ .Values.gateway.tls.containerPort }} + selector: + {{- include "apisix-ingress-controller.selectorLabels" . | nindent 4 }} + type: {{ .Values.gateway.type }} # LoadBalancer or NodePort + {{- if or (eq .Values.gateway.type "LoadBalancer") (eq .Values.gateway.type "NodePort") }} + externalTrafficPolicy: {{ .Values.gateway.externalTrafficPolicy }} + {{- end }} + {{- if eq .Values.gateway.type "LoadBalancer" }} + {{- if .Values.gateway.loadBalancerIP }} + loadBalancerIP: {{ .Values.gateway.loadBalancerIP }} # specify load balancer ip by user + {{- end }} + {{- if .Values.gateway.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.gateway.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} + {{- end }} + {{- end }} + {{- if gt (len .Values.gateway.externalIPs) 0 }} + externalIPs: + {{- range $ip := .Values.gateway.externalIPs }} + - {{ $ip }} + {{- end }} + {{- end }} \ No newline at end of file diff --git a/charts/apisix-ingress-controller/templates/servicemonitor.yaml b/charts/apisix-ingress-controller/templates/servicemonitor.yaml index 8d1af143..7f37908f 100644 --- a/charts/apisix-ingress-controller/templates/servicemonitor.yaml +++ b/charts/apisix-ingress-controller/templates/servicemonitor.yaml @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -{{- if and ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) .Values.serviceMonitor.enabled }} +{{- if .Values.serviceMonitor.enabled }} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: @@ -35,6 +35,9 @@ spec: {{- if .Values.serviceMonitor.interval }} interval: {{ .Values.serviceMonitor.interval }} {{- end }} + {{- with .Values.serviceMonitor.metricRelabelings }} + metricRelabelings: {{ toYaml . | nindent 6 }} + {{- end }} namespaceSelector: matchNames: - {{ template "apisix-ingress-controller.namespace" . }} diff --git a/charts/apisix-ingress-controller/values.yaml b/charts/apisix-ingress-controller/values.yaml index 09198637..928cc75e 100644 --- a/charts/apisix-ingress-controller/values.yaml +++ b/charts/apisix-ingress-controller/values.yaml @@ -29,6 +29,9 @@ labelsOverride: {} # app.kubernetes.io/name: "{{ .Release.Name }}" # app.kubernetes.io/instance: '{{ include "apisix-ingress-controller.name" . }}' +# -- Add annotations to Apache APISIX ingress controller resource +annotations: {} + rbac: # -- Specifies whether RBAC resources should be created create: true @@ -48,7 +51,7 @@ replicaCount: 1 image: repository: apache/apisix-ingress-controller pullPolicy: IfNotPresent - tag: "1.6.1" + tag: "1.8.0" podAnnotations: {} @@ -61,6 +64,17 @@ service: port: 80 config: + etcdserver: + # -- Enable etcd server or not, default is false. + enabled: false + image: + # -- Apache APISIX image repository + repository: apache/apisix + # -- Apache APISIX image pull policy + pullPolicy: IfNotPresent + # -- Apache APISIX image tag + # Overrides the image tag whose default is the chart appVersion. + tag: 3.5.0-debian # -- the error log level, default is info, optional values are: debug, info, warn, error, panic, fatal logLevel: "info" # -- the output file path of error log, default is stderr, when @@ -87,6 +101,8 @@ config: enableProfiling: true # -- Default interval for synchronizing Kubernetes resources to APISIX apisixResourceSyncInterval: "1h" + # -- Pluginmetadata in APISIX can be controlled through ConfigMap. default is "" + pluginMetadataCM: "" # -- Kubernetes related configurations. kubernetes: # -- the Kubernetes configuration file path, default is "", so the in-cluster @@ -124,8 +140,7 @@ config: # -- the resource API version, support "apisix.apache.org/v2beta3" and "apisix.apache.org/v2". # default is "apisix.apache.org/v2" apiVersion: "apisix.apache.org/v2" - # -- Pluginmetadata in APISIX can be controlled through ConfigMap. default is "" - pluginMetadataCM: "" + # -- APISIX related configurations. apisix: @@ -139,6 +154,12 @@ config: # -- the APISIX admin API version. can be "v2" or "v3", default is "v2". adminAPIVersion: "v2" + # -- The APISIX Helm chart supports storing user credentials in a secret. + # The secret needs to contain a single key for admin token with key adminKey by default. + existingSecret: "" + # -- Name of the admin token key in the secret, overrides the default key name "adminKey" + existingSecretAdminKeyKey: "" + resources: {} initContainer: @@ -154,11 +175,21 @@ autoscaling: targetCPUUtilizationPercentage: 80 # targetMemoryUtilizationPercentage: 80 +# -- Update strategy for apisix ingress controller deployment +updateStrategy: {} + # type: RollingUpdate + nodeSelector: {} tolerations: [] +affinity: {} +# -- Topology Spread Constraints for pod assignment spread across your cluster among failure-domains +# ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods +topologySpreadConstraints: [] -# -- namespace: "ingress-apisix" +# namespace: "ingress-apisix" +# -- Enable creating ServiceMonitor objects for Prometheus operator. +# Requires Prometheus operator v0.38.0 or higher. serviceMonitor: enabled: false namespace: "monitoring" @@ -167,7 +198,20 @@ serviceMonitor: labels: {} # -- @param serviceMonitor.annotations ServiceMonitor annotations annotations: {} + # -- @param serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion. + # ref: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs + metricRelabelings: {} +# -- See https://kubernetes.io/docs/tasks/run-application/configure-pdb/ for more details +podDisruptionBudget: + # -- Enable or disable podDisruptionBudget + enabled: false + # -- Set the `minAvailable` of podDisruptionBudget. You can specify only one of `maxUnavailable` and `minAvailable` in a single PodDisruptionBudget. + # See [Specifying a Disruption Budget for your Application](https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget) + # for more details + minAvailable: 90% + # -- Set the maxUnavailable of podDisruptionBudget + maxUnavailable: 1 podSecurityContext: {} # fsGroup: 2000 @@ -179,3 +223,54 @@ securityContext: {} # readOnlyRootFilesystem: true # runAsNonRoot: true # runAsUser: 1000 +gateway: + # -- Apache APISIX service type for user access itself + type: NodePort + externalTrafficPolicy: Cluster + # annotations: + # service.beta.kubernetes.io/aws-load-balancer-type: nlb + # loadBalancerIP: a.b.c.d + # loadBalancerSourceRanges: + # - "143.231.0.0/16" + # -- load balancer ips + externalIPs: [] + nginx: + # -- Nginx workerRlimitNoFile + workerRlimitNofile: "20480" + # -- Nginx worker connections + workerConnections: "10620" + # -- Nginx worker processes + workerProcesses: auto + # -- Nginx error logs path + errorLog: stderr + # -- Nginx error logs level + errorLogLevel: warn + resources: {} + securityContext: {} + # capabilities: + # add: + # - NET_BIND_SERVICE + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 636 + tls: + enabled: false + servicePort: 443 + containerPort: 9443 + # -- Support multiple https ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L99) + additionalContainerPorts: [] + # - ip: 127.0.0.3 # Specific IP, If not set, the default value is `0.0.0.0`. + # port: 9445 + # enable_http2: true + # -- Specifies the name of Secret contains trusted CA certificates in the PEM format used to verify the certificate when APISIX needs to do SSL/TLS handshaking with external services (e.g. etcd) + existingCASecret: "" + # -- Filename be used in the gateway.tls.existingCASecret + certCAFilename: "" + http2: + enabled: true + # -- TLS protocols allowed to use. + sslProtocols: "TLSv1.2 TLSv1.3" + # -- Define SNI to fallback if none is presented by client + fallbackSNI: "" diff --git a/charts/apisix/Chart.lock b/charts/apisix/Chart.lock index 632b1d7b..bc811c30 100644 --- a/charts/apisix/Chart.lock +++ b/charts/apisix/Chart.lock @@ -1,12 +1,12 @@ dependencies: - name: etcd repository: https://charts.bitnami.com/bitnami - version: 8.7.7 + version: 9.7.3 - name: apisix-dashboard repository: https://charts.apiseven.com - version: 0.8.1 + version: 0.8.2 - name: apisix-ingress-controller repository: https://charts.apiseven.com - version: 0.13.0 -digest: sha256:6ca1fc0eb06fef4d4502a3153ed77c9cd5a382ebe65e676791afe4272ac7c796 -generated: "2023-12-14T20:21:52.603033345+02:00" + version: 0.14.0 +digest: sha256:8d727979670a2b62af7672c36ebb2a4d294bc967b16fb5d1e144ed77c948062d +generated: "2024-02-02T14:07:24.846532+08:00" diff --git a/charts/apisix/Chart.yaml b/charts/apisix/Chart.yaml index e40a01b4..6f51a779 100644 --- a/charts/apisix/Chart.yaml +++ b/charts/apisix/Chart.yaml @@ -31,7 +31,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.6.0 +version: 1.11.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -42,16 +42,16 @@ sources: dependencies: - name: etcd - version: 8.7.7 + version: 9.7.3 repository: https://charts.bitnami.com/bitnami condition: etcd.enabled - name: apisix-dashboard - version: 0.8.1 + version: 0.8.2 repository: https://charts.apiseven.com condition: dashboard.enabled alias: dashboard - name: apisix-ingress-controller - version: 0.13.0 + version: 0.14.0 repository: https://charts.apiseven.com condition: ingress-controller.enabled alias: ingress-controller diff --git a/charts/apisix/README.md b/charts/apisix/README.md index f39508d3..8dc266ce 100644 --- a/charts/apisix/README.md +++ b/charts/apisix/README.md @@ -40,47 +40,38 @@ The command removes all the Kubernetes components associated with the chart and | Key | Type | Default | Description | |-----|------|---------|-------------| -| affinity | object | `{}` | Set affinity for Apache APISIX deploy | -| apisix.admin.allow.ipList | list | `["127.0.0.1/24"]` | The client IP CIDR allowed to access Apache APISIX Admin API service. | -| apisix.admin.cors | bool | `true` | Admin API support CORS response headers | -| apisix.admin.credentials | object | `{"admin":"edd1c9f034335f136f87ad84b625c8f1","secretName":"","viewer":"4054f7cf07e344346cd3f287985e76a2"}` | Admin API credentials | -| apisix.admin.credentials.admin | string | `"edd1c9f034335f136f87ad84b625c8f1"` | Apache APISIX admin API admin role credentials | -| apisix.admin.credentials.secretName | string | `""` | The APISIX Helm chart supports storing user credentials in a secret. The secret needs to contain two keys, admin and viewer, with their respective values set. | -| apisix.admin.credentials.viewer | string | `"4054f7cf07e344346cd3f287985e76a2"` | Apache APISIX admin API viewer role credentials | -| apisix.admin.enabled | bool | `true` | Enable Admin API | -| apisix.admin.externalIPs | list | `[]` | IPs for which nodes in the cluster will also accept traffic for the servic | -| apisix.admin.ingress | object | `{"annotations":{},"enabled":false,"hosts":[{"host":"apisix-admin.local","paths":["/apisix"]}],"tls":[]}` | Using ingress access Apache APISIX admin service | -| apisix.admin.ingress.annotations | object | `{}` | Ingress annotations | -| apisix.admin.ip | string | `"0.0.0.0"` | which ip to listen on for Apache APISIX admin API. Set to `"[::]"` when on IPv6 single stack | -| apisix.admin.port | int | `9180` | which port to use for Apache APISIX admin API | -| apisix.admin.servicePort | int | `9180` | Service port to use for Apache APISIX admin API | -| apisix.admin.type | string | `"ClusterIP"` | admin service type | -| apisix.customPlugins | object | `{"enabled":false,"luaPath":"/opts/custom_plugins/?.lua","plugins":[{"attrs":{},"configMap":{"mounts":[{"key":"the-file-name","path":"mount-path"}],"name":"configmap-name"},"name":"plugin-name"}]}` | customPlugins allows you to mount your own HTTP plugins. | -| apisix.customPlugins.enabled | bool | `false` | Whether to configure some custom plugins | -| apisix.customPlugins.luaPath | string | `"/opts/custom_plugins/?.lua"` | the lua_path that tells APISIX where it can find plugins, note the last ';' is required. | -| apisix.customPlugins.plugins[0] | object | `{"attrs":{},"configMap":{"mounts":[{"key":"the-file-name","path":"mount-path"}],"name":"configmap-name"},"name":"plugin-name"}` | plugin name. | -| apisix.customPlugins.plugins[0].attrs | object | `{}` | plugin attrs | -| apisix.customPlugins.plugins[0].configMap | object | `{"mounts":[{"key":"the-file-name","path":"mount-path"}],"name":"configmap-name"}` | plugin codes can be saved inside configmap object. | -| apisix.customPlugins.plugins[0].configMap.mounts | list | `[{"key":"the-file-name","path":"mount-path"}]` | since keys in configmap is flat, mountPath allows to define the mount path, so that plugin codes can be mounted hierarchically. | -| apisix.customPlugins.plugins[0].configMap.name | string | `"configmap-name"` | name of configmap. | -| apisix.deployment.mode | string | `"traditional"` | Apache APISIX deployment mode Optional: traditional, decoupled, standalone ref: https://apisix.apache.org/docs/apisix/deployment-modes/ | -| apisix.deployment.role | string | `"traditional"` | Deployment role Optional: traditional, data_plane, control_plane ref: https://apisix.apache.org/docs/apisix/deployment-modes/ | -| apisix.discovery.enabled | bool | `false` | Enable or disable Apache APISIX integration service discovery | -| apisix.discovery.registry | object | `{}` | Registry is the same to the one in APISIX [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L281), and refer to such file for more setting details. also refer to [this documentation for integration service discovery](https://apisix.apache.org/docs/apisix/discovery) | -| apisix.dns.resolvers[0] | string | `"127.0.0.1"` | | -| apisix.dns.resolvers[1] | string | `"172.20.0.10"` | | -| apisix.dns.resolvers[2] | string | `"114.114.114.114"` | | -| apisix.dns.resolvers[3] | string | `"223.5.5.5"` | | -| apisix.dns.resolvers[4] | string | `"1.1.1.1"` | | -| apisix.dns.resolvers[5] | string | `"8.8.8.8"` | | -| apisix.dns.timeout | int | `5` | | -| apisix.dns.validity | int | `30` | | +| admin.allow.ipList | list | `["127.0.0.1/24"]` | The client IP CIDR allowed to access Apache APISIX Admin API service. | +| admin.cors | bool | `true` | Admin API support CORS response headers | +| admin.credentials | object | `{"admin":"edd1c9f034335f136f87ad84b625c8f1","secretAdminKey":"","secretName":"","secretViewerKey":"","viewer":"4054f7cf07e344346cd3f287985e76a2"}` | Admin API credentials | +| admin.credentials.admin | string | `"edd1c9f034335f136f87ad84b625c8f1"` | Apache APISIX admin API admin role credentials | +| admin.credentials.secretAdminKey | string | `""` | Name of the admin role key in the secret, overrides the default key name "admin" | +| admin.credentials.secretName | string | `""` | The APISIX Helm chart supports storing user credentials in a secret. The secret needs to contain two keys, admin and viewer, with their respective values set. | +| admin.credentials.secretViewerKey | string | `""` | Name of the viewer role key in the secret, overrides the default key name "viewer" | +| admin.credentials.viewer | string | `"4054f7cf07e344346cd3f287985e76a2"` | Apache APISIX admin API viewer role credentials | +| admin.enabled | bool | `true` | Enable Admin API | +| admin.externalIPs | list | `[]` | IPs for which nodes in the cluster will also accept traffic for the servic | +| admin.ingress | object | `{"annotations":{},"enabled":false,"hosts":[{"host":"apisix-admin.local","paths":["/apisix"]}],"tls":[]}` | Using ingress access Apache APISIX admin service | +| admin.ingress.annotations | object | `{}` | Ingress annotations | +| admin.ip | string | `"0.0.0.0"` | which ip to listen on for Apache APISIX admin API. Set to `"[::]"` when on IPv6 single stack | +| admin.port | int | `9180` | which port to use for Apache APISIX admin API | +| admin.servicePort | int | `9180` | Service port to use for Apache APISIX admin API | +| admin.type | string | `"ClusterIP"` | admin service type | +| apisix.affinity | object | `{}` | Set affinity for Apache APISIX deploy | +| apisix.customLuaSharedDicts | list | `[]` | Add custom [lua_shared_dict](https://github.com/openresty/lua-nginx-module#toc88) settings, click [here](https://github.com/apache/apisix-helm-chart/blob/master/charts/apisix/values.yaml#L27-L30) to learn the format of a shared dict | +| apisix.customizedConfig | object | `{}` | If apisix.enableCustomizedConfig is true, full customized config.yaml. Please note that other settings about APISIX config will be ignored | +| apisix.data_encryption | object | `{"enabled":false,"keyring":[]}` | Enable Data Encryption | +| apisix.data_encryption.keyring | list | `[]` | An array of 16 character strings used to encrypt/decrypt fields with AES-128-CBC | +| apisix.enableCustomizedConfig | bool | `false` | Enable full customized config.yaml | | apisix.enableIPv6 | bool | `true` | Enable nginx IPv6 resolver | | apisix.enableServerTokens | bool | `true` | Whether the APISIX version number should be shown in Server header | -| apisix.extPlugin.cmd | list | `["/path/to/apisix-plugin-runner/runner","run"]` | the command and its arguements to run as a subprocess | -| apisix.extPlugin.enabled | bool | `false` | Enable External Plugins. See [external plugin](https://apisix.apache.org/docs/apisix/next/external-plugin/) | -| apisix.fullCustomConfig.config | object | `{}` | If apisix.fullCustomConfig.enabled is true, full customized config.yaml. Please note that other settings about APISIX config will be ignored | -| apisix.fullCustomConfig.enabled | bool | `false` | Enable full customized config.yaml | +| apisix.enabled | bool | `true` | Enable or disable Apache APISIX itself Set it to false and ingress-controller.enabled=true will deploy only ingress-controller | +| apisix.extraEnvVars | list | `[]` | extraEnvVars An array to add extra env vars e.g: extraEnvVars: - name: FOO value: "bar" - name: FOO2 valueFrom: secretKeyRef: name: SECRET_NAME key: KEY | +| apisix.hostNetwork | bool | `false` | | +| apisix.httpRouter | string | `"radixtree_host_uri"` | Defines how apisix handles routing: - radixtree_uri: match route by uri(base on radixtree) - radixtree_host_uri: match route by host + uri(base on radixtree) - radixtree_uri_with_parameter: match route by uri with parameters | +| apisix.image.pullPolicy | string | `"IfNotPresent"` | Apache APISIX image pull policy | +| apisix.image.repository | string | `"apache/apisix"` | Apache APISIX image repository | +| apisix.image.tag | string | `"3.8.0-debian"` | Apache APISIX image tag Overrides the image tag whose default is the chart appVersion. | +| apisix.kind | string | `"Deployment"` | Use a `DaemonSet` or `Deployment` | | apisix.luaModuleHook | object | `{"configMapRef":{"mounts":[{"key":"","path":""}],"name":""},"enabled":false,"hookPoint":"","luaPath":""}` | Whether to add a custom lua module | | apisix.luaModuleHook.configMapRef | object | `{"mounts":[{"key":"","path":""}],"name":""}` | configmap that stores the codes | | apisix.luaModuleHook.configMapRef.mounts[0] | object | `{"key":"","path":""}` | Name of the ConfigMap key, for setting the mapping relationship between ConfigMap key and the lua module code path. | @@ -88,58 +79,64 @@ The command removes all the Kubernetes components associated with the chart and | apisix.luaModuleHook.configMapRef.name | string | `""` | Name of the ConfigMap where the lua module codes store | | apisix.luaModuleHook.hookPoint | string | `""` | the hook module which will be used to inject third party code into APISIX use the lua require style like: "module.say_hello" | | apisix.luaModuleHook.luaPath | string | `""` | extend lua_package_path to load third party code | -| apisix.nginx.configurationSnippet | object | `{"httpAdmin":"","httpEnd":"","httpSrv":"","httpStart":"","main":"","stream":""}` | Custom configuration snippet. | -| apisix.nginx.customLuaSharedDicts | list | `[]` | Add custom [lua_shared_dict](https://github.com/openresty/lua-nginx-module#toc88) settings, click [here](https://github.com/apache/apisix-helm-chart/blob/master/charts/apisix/values.yaml#L27-L30) to learn the format of a shared dict | -| apisix.nginx.enableCPUAffinity | bool | `true` | | -| apisix.nginx.envs | list | `[]` | | -| apisix.nginx.keepaliveTimeout | string | `"60s"` | Timeout during which a keep-alive client connection will stay open on the server side. | -| apisix.nginx.logs.accessLog | string | `"/dev/stdout"` | Access log path | -| apisix.nginx.logs.accessLogFormat | string | `"$remote_addr - $remote_user [$time_local] $http_host \\\"$request\\\" $status $body_bytes_sent $request_time \\\"$http_referer\\\" \\\"$http_user_agent\\\" $upstream_addr $upstream_status $upstream_response_time \\\"$upstream_scheme://$upstream_host$upstream_uri\\\""` | Access log format | -| apisix.nginx.logs.accessLogFormatEscape | string | `"default"` | Allows setting json or default characters escaping in variables | -| apisix.nginx.logs.enableAccessLog | bool | `true` | Enable access log or not, default true | -| apisix.nginx.logs.errorLog | string | `"/dev/stderr"` | Error log path | -| apisix.nginx.logs.errorLogLevel | string | `"warn"` | Error log level | -| apisix.nginx.workerConnections | string | `"10620"` | | -| apisix.nginx.workerProcesses | string | `"auto"` | | -| apisix.nginx.workerRlimitNofile | string | `"20480"` | | -| apisix.pluginAttrs | object | `{}` | Set APISIX plugin attributes, see [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L376) for more details | -| apisix.plugins | list | `[]` | Customize the list of APISIX plugins to enable. By default, APISIX's default plugins are automatically used. See [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml) | -| apisix.prometheus.containerPort | int | `9091` | container port where the metrics are exposed | -| apisix.prometheus.enabled | bool | `false` | | -| apisix.prometheus.metricPrefix | string | `"apisix_"` | prefix of the metrics | -| apisix.prometheus.path | string | `"/apisix/prometheus/metrics"` | path of the metrics endpoint | -| apisix.router.http | string | `"radixtree_host_uri"` | Defines how apisix handles routing: - radixtree_uri: match route by uri(base on radixtree) - radixtree_host_uri: match route by host + uri(base on radixtree) - radixtree_uri_with_parameter: match route by uri with parameters | +| apisix.nodeSelector | object | `{}` | Node labels for Apache APISIX pod assignment | +| apisix.podAnnotations | object | `{}` | Annotations to add to each pod | +| apisix.podDisruptionBudget | object | `{"enabled":false,"maxUnavailable":1,"minAvailable":"90%"}` | See https://kubernetes.io/docs/tasks/run-application/configure-pdb/ for more details | +| apisix.podDisruptionBudget.enabled | bool | `false` | Enable or disable podDisruptionBudget | +| apisix.podDisruptionBudget.maxUnavailable | int | `1` | Set the maxUnavailable of podDisruptionBudget | +| apisix.podDisruptionBudget.minAvailable | string | `"90%"` | Set the `minAvailable` of podDisruptionBudget. You can specify only one of `maxUnavailable` and `minAvailable` in a single PodDisruptionBudget. See [Specifying a Disruption Budget for your Application](https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget) for more details | +| apisix.podSecurityContext | object | `{}` | Set the securityContext for Apache APISIX pods | +| apisix.priorityClassName | string | `""` | Set [priorityClassName](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#pod-priority) for Apache APISIX pods | +| apisix.proxyProtocol | object | `{"enabled":false,"listenHttpPort":9181,"listenHttpsPort":9182,"tcp":true,"upstream":true}` | Enable Proxy Protocol | +| apisix.proxyProtocol.listenHttpPort | int | `9181` | The port with proxy protocol for http, it differs from node_listen and admin_listen. | +| apisix.proxyProtocol.listenHttpsPort | int | `9182` | The port with proxy protocol for https | +| apisix.proxyProtocol.tcp | bool | `true` | Enable the proxy protocol for tcp proxy, it works for stream_proxy.tcp option | +| apisix.proxyProtocol.upstream | bool | `true` | Enable the proxy protocol to the upstream server | +| apisix.readinessProbe | object | `{"failureThreshold":6,"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"tcpSocket":{"port":9080},"timeoutSeconds":1}` | Set the readinessProbe for Apache APISIX pods | +| apisix.replicaCount | int | `1` | kind is DaemonSet, replicaCount not become effective | +| apisix.resources | object | `{}` | Set pod resource requests & limits | +| apisix.securityContext | object | `{}` | Set the securityContext for Apache APISIX container | | apisix.setIDFromPodUID | bool | `false` | Use Pod metadata.uid as the APISIX id. | -| apisix.ssl.additionalContainerPorts | list | `[]` | Support multiple https ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L99) | -| apisix.ssl.certCAFilename | string | `""` | Filename be used in the apisix.ssl.existingCASecret | -| apisix.ssl.containerPort | int | `9443` | | -| apisix.ssl.enabled | bool | `false` | | -| apisix.ssl.existingCASecret | string | `""` | Specifies the name of Secret contains trusted CA certificates in the PEM format used to verify the certificate when APISIX needs to do SSL/TLS handshaking with external services (e.g. etcd) | -| apisix.ssl.fallbackSNI | string | `""` | Define SNI to fallback if none is presented by client | -| apisix.ssl.http2.enabled | bool | `true` | | -| apisix.ssl.sslProtocols | string | `"TLSv1.2 TLSv1.3"` | TLS protocols allowed to use. | -| apisix.stream_plugins | list | `[]` | Customize the list of APISIX stream_plugins to enable. By default, APISIX's default stream_plugins are automatically used. See [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml) | -| apisix.vault.enabled | bool | `false` | Enable or disable the vault integration | -| apisix.vault.host | string | `""` | The host address where the vault server is running. | -| apisix.vault.prefix | string | `""` | Prefix allows you to better enforcement of policies. | -| apisix.vault.timeout | int | `10` | HTTP timeout for each request. | -| apisix.vault.token | string | `""` | The generated token from vault instance that can grant access to read data from the vault. | -| apisix.wasm.enabled | bool | `false` | Enable Wasm Plugins. See [wasm plugin](https://apisix.apache.org/docs/apisix/next/wasm/) | -| apisix.wasm.plugins | list | `[]` | | +| apisix.timezone | string | `""` | timezone is the timezone where apisix uses. For example: "UTC" or "Asia/Shanghai" This value will be set on apisix container's environment variable TZ. You may need to set the timezone to be consistent with your local time zone, otherwise the apisix's logs may used to retrieve event maybe in wrong timezone. | +| apisix.tolerations | list | `[]` | List of node taints to tolerate | +| apisix.topologySpreadConstraints | list | `[]` | Topology Spread Constraints for pod assignment spread across your cluster among failure-domains ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods | | autoscaling.enabled | bool | `false` | | | autoscaling.maxReplicas | int | `100` | | | autoscaling.minReplicas | int | `1` | | | autoscaling.targetCPUUtilizationPercentage | int | `80` | | | autoscaling.targetMemoryUtilizationPercentage | int | `80` | | | autoscaling.version | string | `"v2"` | HPA version, the value is "v2" or "v2beta1", default "v2" | +| configurationSnippet | object | `{"httpAdmin":"","httpEnd":"","httpSrv":"","httpStart":"","main":"","stream":""}` | Custom configuration snippet. | +| customPlugins | object | `{"enabled":false,"luaPath":"/opts/custom_plugins/?.lua","plugins":[{"attrs":{},"configMap":{"mounts":[{"key":"the-file-name","path":"mount-path"}],"name":"configmap-name"},"name":"plugin-name"}]}` | customPlugins allows you to mount your own HTTP plugins. | +| customPlugins.enabled | bool | `false` | Whether to configure some custom plugins | +| customPlugins.luaPath | string | `"/opts/custom_plugins/?.lua"` | the lua_path that tells APISIX where it can find plugins, note the last ';' is required. | +| customPlugins.plugins[0] | object | `{"attrs":{},"configMap":{"mounts":[{"key":"the-file-name","path":"mount-path"}],"name":"configmap-name"},"name":"plugin-name"}` | plugin name. | +| customPlugins.plugins[0].attrs | object | `{}` | plugin attrs | +| customPlugins.plugins[0].configMap | object | `{"mounts":[{"key":"the-file-name","path":"mount-path"}],"name":"configmap-name"}` | plugin codes can be saved inside configmap object. | +| customPlugins.plugins[0].configMap.mounts | list | `[{"key":"the-file-name","path":"mount-path"}]` | since keys in configmap is flat, mountPath allows to define the mount path, so that plugin codes can be mounted hierarchically. | +| customPlugins.plugins[0].configMap.name | string | `"configmap-name"` | name of configmap. | | dashboard.config.conf.etcd.endpoints | list | `["apisix-etcd:2379"]` | Supports defining multiple etcd host addresses for an etcd cluster | | dashboard.config.conf.etcd.password | string | `nil` | Specifies etcd basic auth password if enable etcd auth | | dashboard.config.conf.etcd.prefix | string | `"/apisix"` | apisix configurations prefix | | dashboard.config.conf.etcd.username | string | `nil` | Specifies etcd basic auth username if enable etcd auth | | dashboard.enabled | bool | `false` | | -| etcd | object | `{"auth":{"rbac":{"create":false,"rootPassword":""},"tls":{"certFilename":"","certKeyFilename":"","enabled":false,"existingSecret":"","sni":"","verify":true}},"enabled":true,"prefix":"/apisix","replicaCount":3,"service":{"port":2379},"timeout":30}` | etcd configuration use the FQDN address or the IP of the etcd | -| etcd.auth | object | `{"rbac":{"create":false,"rootPassword":""},"tls":{"certFilename":"","certKeyFilename":"","enabled":false,"existingSecret":"","sni":"","verify":true}}` | if etcd.enabled is true, set more values of bitnami/etcd helm chart | +| deployment.mode | string | `"traditional"` | Apache APISIX deployment mode Optional: traditional, decoupled, standalone ref: https://apisix.apache.org/docs/apisix/deployment-modes/ | +| deployment.role | string | `"traditional"` | Deployment role Optional: traditional, data_plane, control_plane ref: https://apisix.apache.org/docs/apisix/deployment-modes/ | +| discovery.enabled | bool | `false` | Enable or disable Apache APISIX integration service discovery | +| discovery.registry | object | `{}` | Registry is the same to the one in APISIX [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L281), and refer to such file for more setting details. also refer to [this documentation for integration service discovery](https://apisix.apache.org/docs/apisix/discovery) | +| dns.resolvers[0] | string | `"127.0.0.1"` | | +| dns.resolvers[1] | string | `"172.20.0.10"` | | +| dns.resolvers[2] | string | `"114.114.114.114"` | | +| dns.resolvers[3] | string | `"223.5.5.5"` | | +| dns.resolvers[4] | string | `"1.1.1.1"` | | +| dns.resolvers[5] | string | `"8.8.8.8"` | | +| dns.timeout | int | `5` | | +| dns.validity | int | `30` | | +| etcd | object | `{"auth":{"rbac":{"create":false,"existingSecret":"","existingSecretPasswordKey":"","rootPassword":""},"tls":{"certFilename":"","certKeyFilename":"","enabled":false,"existingSecret":"","sni":"","verify":true}},"containerSecurityContext":{"enabled":false},"enabled":true,"existingSecret":"","existingSecretPasswordKey":"","existingSecretUserKey":"","host":["http://etcd.host:2379"],"password":"","prefix":"/apisix","replicaCount":3,"service":{"port":2379},"timeout":30,"user":""}` | etcd configuration use the FQDN address or the IP of the etcd | +| etcd.auth | object | `{"rbac":{"create":false,"existingSecret":"","existingSecretPasswordKey":"","rootPassword":""},"tls":{"certFilename":"","certKeyFilename":"","enabled":false,"existingSecret":"","sni":"","verify":true}}` | if etcd.enabled is true, set more values of bitnami/etcd helm chart | | etcd.auth.rbac.create | bool | `false` | No authentication by default. Switch to enable RBAC authentication | +| etcd.auth.rbac.existingSecret | string | `""` | Name of the existing secret containing credentials for the root user | +| etcd.auth.rbac.existingSecretPasswordKey | string | `""` | Name of key containing password to be retrieved from the existing secret | | etcd.auth.rbac.rootPassword | string | `""` | root password for etcd. Requires etcd.auth.rbac.create to be true. | | etcd.auth.tls.certFilename | string | `""` | etcd client cert filename using in etcd.auth.tls.existingSecret | | etcd.auth.tls.certKeyFilename | string | `""` | etcd client cert key filename using in etcd.auth.tls.existingSecret | @@ -147,65 +144,82 @@ The command removes all the Kubernetes components associated with the chart and | etcd.auth.tls.existingSecret | string | `""` | name of the secret contains etcd client cert | | etcd.auth.tls.sni | string | `""` | specify the TLS Server Name Indication extension, the ETCD endpoint hostname will be used when this setting is unset. | | etcd.auth.tls.verify | bool | `true` | whether to verify the etcd endpoint certificate when setup a TLS connection to etcd | +| etcd.containerSecurityContext | object | `{"enabled":false}` | added for backward compatibility with old kubernetes versions, as seccompProfile is not supported in kubernetes < 1.19 | | etcd.enabled | bool | `true` | install etcd(v3) by default, set false if do not want to install etcd(v3) together | +| etcd.existingSecret | string | `""` | Name of the existing secret containing user and password for external etcd, overrides etcd.user and etcd.password | +| etcd.existingSecretPasswordKey | string | `""` | Name of key containing password to be retrieved from the existing secret, has a value of password by default | +| etcd.existingSecretUserKey | string | `""` | Name of key containing username to be retrieved from the existing secret, has a value of user by default | +| etcd.host | list | `["http://etcd.host:2379"]` | if etcd.enabled is false, use external etcd, support multiple address, if your etcd cluster enables TLS, please use https scheme, e.g. https://127.0.0.1:2379. | +| etcd.password | string | `""` | if etcd.enabled is false, password for external etcd. If etcd.enabled is true, use etcd.auth.rbac.rootPassword instead. | | etcd.prefix | string | `"/apisix"` | apisix configurations prefix | | etcd.timeout | int | `30` | Set the timeout value in seconds for subsequent socket operations from apisix to etcd cluster | -| externalEtcd | object | `{"existingSecret":"","host":["http://etcd.host:2379"],"password":"","secretPasswordKey":"etcd-root-password","user":"root"}` | external etcd configuration. If etcd.enabled is false, these configuration will be used. | -| externalEtcd.existingSecret | string | `""` | if externalEtcd.existingSecret is the name of secret containing the external etcd password | -| externalEtcd.host | list | `["http://etcd.host:2379"]` | if etcd.enabled is false, use external etcd, support multiple address, if your etcd cluster enables TLS, please use https scheme, e.g. https://127.0.0.1:2379. | -| externalEtcd.password | string | `""` | if etcd.enabled is false and externalEtcd.existingSecret is empty, externalEtcd.password is the passsword for external etcd. | -| externalEtcd.secretPasswordKey | string | `"etcd-root-password"` | externalEtcd.secretPasswordKey Key inside the secret containing the external etcd password | -| externalEtcd.user | string | `"root"` | if etcd.enabled is false, user for external etcd. Set empty to disable authentication | -| extraContainers | list | `[]` | Additional `containers`, See [Kubernetes containers](https://kubernetes.io/docs/concepts/containers/) for the detail. | -| extraDeploy | list | `[]` | Additional Kubernetes resources to deploy with the release. | -| extraEnvVars | list | `[]` | extraEnvVars An array to add extra env vars e.g: extraEnvVars: - name: FOO value: "bar" - name: FOO2 valueFrom: secretKeyRef: name: SECRET_NAME key: KEY | -| extraInitContainers | list | `[]` | Additional `initContainers`, See [Kubernetes initContainers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) for the detail. | +| etcd.user | string | `""` | if etcd.enabled is false, username for external etcd. If etcd.enabled is true, use etcd.auth.rbac.rootPassword instead. | +| extPlugin.cmd | list | `["/path/to/apisix-plugin-runner/runner","run"]` | the command and its arguements to run as a subprocess | +| extPlugin.enabled | bool | `false` | Enable External Plugins. See [external plugin](https://apisix.apache.org/docs/apisix/next/external-plugin/) | +| extraInitContainers | list | `[{"command":["/bin/sh","-c","sysctl -w net.core.somaxconn=65535\nsysctl -w net.ipv4.ip_local_port_range=\"1024 65535\"\nsysctl -w net.ipv4.tcp_max_syn_backlog=8192\nsysctl -w fs.file-max=1048576\nsysctl -w fs.inotify.max_user_instances=16384\nsysctl -w fs.inotify.max_user_watches=524288\nsysctl -w fs.inotify.max_queued_events=16384\n"],"image":"busybox:1.28","name":"init-sysctl","securityContext":{"privileged":true}}]` | Additional `initContainers`, See [Kubernetes initContainers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) for the detail. | | extraVolumeMounts | list | `[]` | Additional `volume`, See [Kubernetes Volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the detail. | | extraVolumes | list | `[]` | Additional `volume`, See [Kubernetes Volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the detail. | | fullnameOverride | string | `""` | | +| gateway.externalIPs | list | `[]` | | +| gateway.externalTrafficPolicy | string | `"Cluster"` | | +| gateway.http | object | `{"additionalContainerPorts":[],"containerPort":9080,"enabled":true,"servicePort":80}` | Apache APISIX service settings for http | +| gateway.http.additionalContainerPorts | list | `[]` | Support multiple http ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L24) | +| gateway.ingress | object | `{"annotations":{},"enabled":false,"hosts":[{"host":"apisix.local","paths":[]}],"tls":[]}` | Using ingress access Apache APISIX service | +| gateway.ingress.annotations | object | `{}` | Ingress annotations | +| gateway.labelsOverride | object | `{}` | Override default labels assigned to Apache APISIX gateway resources | +| gateway.proxyProtocol | object | `{"http":{"containerPort":9181,"enabled":false,"servicePort":9181},"https":{"containerPort":9182,"enabled":false,"servicePort":9182}}` | Proxy Protocol Configuration | +| gateway.proxyProtocol.http | object | `{"containerPort":9181,"enabled":false,"servicePort":9181}` | If you enable proxy protocol, you must use this port to receive http request with proxy protocol | +| gateway.proxyProtocol.https | object | `{"containerPort":9182,"enabled":false,"servicePort":9182}` | The port with proxy protocol for https | +| gateway.stream | object | `{"enabled":false,"tcp":[],"udp":[]}` | Apache APISIX service settings for stream. L4 proxy (TCP/UDP) | +| gateway.tls | object | `{"additionalContainerPorts":[],"certCAFilename":"","containerPort":9443,"enabled":false,"existingCASecret":"","fallbackSNI":"","http2":{"enabled":true},"servicePort":443,"sslProtocols":"TLSv1.2 TLSv1.3"}` | Apache APISIX service settings for tls | +| gateway.tls.additionalContainerPorts | list | `[]` | Support multiple https ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L99) | +| gateway.tls.certCAFilename | string | `""` | Filename be used in the gateway.tls.existingCASecret | +| gateway.tls.existingCASecret | string | `""` | Specifies the name of Secret contains trusted CA certificates in the PEM format used to verify the certificate when APISIX needs to do SSL/TLS handshaking with external services (e.g. etcd) | +| gateway.tls.fallbackSNI | string | `""` | Define SNI to fallback if none is presented by client | +| gateway.tls.sslProtocols | string | `"TLSv1.2 TLSv1.3"` | TLS protocols allowed to use. | +| gateway.type | string | `"NodePort"` | Apache APISIX service type for user access itself | | global.imagePullSecrets | list | `[]` | Global Docker registry secret names as an array | -| hostNetwork | bool | `false` | | -| image.pullPolicy | string | `"IfNotPresent"` | Apache APISIX image pull policy | -| image.repository | string | `"apache/apisix"` | Apache APISIX image repository | -| image.tag | string | `"3.8.0-debian"` | Apache APISIX image tag Overrides the image tag whose default is the chart appVersion. | -| ingress | object | `{"annotations":{},"enabled":false,"hosts":[{"host":"apisix.local","paths":[]}],"servicePort":null,"tls":[]}` | Using ingress access Apache APISIX service | +| global.secrets | list | `[]` | Secrets to be created with apisix | | ingress-controller | object | `{"config":{"apisix":{"adminAPIVersion":"v3"}},"enabled":false}` | Ingress controller configuration | -| ingress.annotations | object | `{}` | Ingress annotations | -| ingress.servicePort | number | `nil` | Service port to send traffic. Defaults to `service.http.servicePort`. | | initContainer.image | string | `"busybox"` | Init container image | +| initContainer.securityContext | object | `{}` | Set the securityContext for the init container | | initContainer.tag | float | `1.28` | Init container tag | -| metrics | object | `{"serviceMonitor":{"annotations":{},"enabled":false,"interval":"15s","labels":{},"name":"","namespace":""}}` | Observability configuration. | -| metrics.serviceMonitor.annotations | object | `{}` | @param serviceMonitor.annotations ServiceMonitor annotations | -| metrics.serviceMonitor.enabled | bool | `false` | Enable or disable Apache APISIX serviceMonitor | -| metrics.serviceMonitor.interval | string | `"15s"` | interval at which metrics should be scraped | -| metrics.serviceMonitor.labels | object | `{}` | @param serviceMonitor.labels ServiceMonitor extra labels | -| metrics.serviceMonitor.name | string | `""` | name of the serviceMonitor, by default, it is the same as the apisix fullname | -| metrics.serviceMonitor.namespace | string | `""` | namespace where the serviceMonitor is deployed, by default, it is the same as the namespace of the apisix | +| logs.accessLog | string | `"/dev/stdout"` | Access log path | +| logs.accessLogFormat | string | `"$remote_addr - $remote_user [$time_local] $http_host \\\"$request\\\" $status $body_bytes_sent $request_time \\\"$http_referer\\\" \\\"$http_user_agent\\\" $upstream_addr $upstream_status $upstream_response_time \\\"$upstream_scheme://$upstream_host$upstream_uri\\\""` | Access log format | +| logs.accessLogFormatEscape | string | `"default"` | Allows setting json or default characters escaping in variables | +| logs.enableAccessLog | bool | `true` | Enable access log or not, default true | +| logs.errorLog | string | `"/dev/stderr"` | Error log path | +| logs.errorLogLevel | string | `"warn"` | Error log level | | nameOverride | string | `""` | | -| nodeSelector | object | `{}` | Node labels for Apache APISIX pod assignment | -| podAnnotations | object | `{}` | Annotations to add to each pod | -| podDisruptionBudget | object | `{"enabled":false,"maxUnavailable":1,"minAvailable":"90%"}` | See https://kubernetes.io/docs/tasks/run-application/configure-pdb/ for more details | -| podDisruptionBudget.enabled | bool | `false` | Enable or disable podDisruptionBudget | -| podDisruptionBudget.maxUnavailable | int | `1` | Set the maxUnavailable of podDisruptionBudget | -| podDisruptionBudget.minAvailable | string | `"90%"` | Set the `minAvailable` of podDisruptionBudget. You can specify only one of `maxUnavailable` and `minAvailable` in a single PodDisruptionBudget. See [Specifying a Disruption Budget for your Application](https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget) for more details | -| podSecurityContext | object | `{}` | Set the securityContext for Apache APISIX pods | -| priorityClassName | string | `""` | Set [priorityClassName](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#pod-priority) for Apache APISIX pods | +| nginx.enableCPUAffinity | bool | `true` | | +| nginx.envs | list | `[]` | | +| nginx.meta | string | `"lua_shared_dict:\n prometheus-metrics: 15m\n"` | allow customize meta in `nginx_config` section | +| nginx.workerConnections | string | `"10620"` | | +| nginx.workerProcesses | string | `"auto"` | | +| nginx.workerRlimitNofile | string | `"20480"` | | +| pluginAttrs | object | `{}` | Set APISIX plugin attributes, see [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L376) for more details | +| plugins | list | `[]` | Customize the list of APISIX plugins to enable. By default, APISIX's default plugins are automatically used. See [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml) | | rbac.create | bool | `false` | | -| replicaCount | int | `1` | if useDaemonSet is true or autoscaling.enabled is true, replicaCount not become effective | -| resources | object | `{}` | Set pod resource requests & limits | -| securityContext | object | `{}` | Set the securityContext for Apache APISIX container | -| service.externalIPs | list | `[]` | | -| service.externalTrafficPolicy | string | `"Cluster"` | | -| service.http | object | `{"additionalContainerPorts":[],"containerPort":9080,"enabled":true,"servicePort":80}` | Apache APISIX service settings for http | -| service.http.additionalContainerPorts | list | `[]` | Support multiple http ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L24) | -| service.labelsOverride | object | `{}` | Override default labels assigned to Apache APISIX gateway resources | -| service.stream | object | `{"enabled":false,"tcp":[],"udp":[]}` | Apache APISIX service settings for stream. L4 proxy (TCP/UDP) | -| service.tls | object | `{"servicePort":443}` | Apache APISIX service settings for tls | -| service.type | string | `"NodePort"` | Apache APISIX service type for user access itself | | serviceAccount.annotations | object | `{}` | | | serviceAccount.create | bool | `false` | | | serviceAccount.name | string | `""` | | -| timezone | string | `""` | timezone is the timezone where apisix uses. For example: "UTC" or "Asia/Shanghai" This value will be set on apisix container's environment variable TZ. You may need to set the timezone to be consistent with your local time zone, otherwise the apisix's logs may used to retrieve event maybe in wrong timezone. | -| tolerations | list | `[]` | List of node taints to tolerate | -| updateStrategy | object | `{}` | | -| useDaemonSet | bool | `false` | set false to use `Deployment`, set true to use `DaemonSet` | +| serviceMonitor | object | `{"annotations":{},"containerPort":9091,"enabled":false,"interval":"15s","labels":{},"metricPrefix":"apisix_","metricRelabelings":[],"name":"","namespace":"","path":"/apisix/prometheus/metrics"}` | Observability configuration. ref: https://apisix.apache.org/docs/apisix/plugins/prometheus/ | +| serviceMonitor.annotations | object | `{}` | @param serviceMonitor.annotations ServiceMonitor annotations | +| serviceMonitor.containerPort | int | `9091` | container port where the metrics are exposed | +| serviceMonitor.enabled | bool | `false` | Enable or disable Apache APISIX serviceMonitor | +| serviceMonitor.interval | string | `"15s"` | interval at which metrics should be scraped | +| serviceMonitor.labels | object | `{}` | @param serviceMonitor.labels ServiceMonitor extra labels | +| serviceMonitor.metricPrefix | string | `"apisix_"` | prefix of the metrics | +| serviceMonitor.metricRelabelings | list | `[]` | @param serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion. ref: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs | +| serviceMonitor.name | string | `""` | name of the serviceMonitor, by default, it is the same as the apisix fullname | +| serviceMonitor.namespace | string | `""` | namespace where the serviceMonitor is deployed, by default, it is the same as the namespace of the apisix | +| serviceMonitor.path | string | `"/apisix/prometheus/metrics"` | path of the metrics endpoint | +| stream_plugins | list | `[]` | Customize the list of APISIX stream_plugins to enable. By default, APISIX's default stream_plugins are automatically used. See [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml) | +| updateStrategy | object | `{}` | Update strategy for apisix deployment | +| vault.enabled | bool | `false` | Enable or disable the vault integration | +| vault.host | string | `""` | The host address where the vault server is running. | +| vault.prefix | string | `""` | Prefix allows you to better enforcement of policies. | +| vault.timeout | int | `10` | HTTP timeout for each request. | +| vault.token | string | `""` | The generated token from vault instance that can grant access to read data from the vault. | +| wasmPlugins.enabled | bool | `false` | Enable Wasm Plugins. See [wasm plugin](https://apisix.apache.org/docs/apisix/next/wasm/) | +| wasmPlugins.plugins | list | `[]` | | diff --git a/charts/apisix/charts/apisix-dashboard-0.8.1.tgz b/charts/apisix/charts/apisix-dashboard-0.8.1.tgz deleted file mode 100644 index 0a93cd59d0cbd8490e9bbae62df9516e567c6725..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7143 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 diff --git a/charts/apisix/charts/apisix-dashboard-0.8.2.tgz b/charts/apisix/charts/apisix-dashboard-0.8.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3a9992e6f47c50463c6134c3f89f47aae65df022 GIT binary patch literal 8013 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 P009609_6Qn0I&c6M+x!% literal 0 HcmV?d00001 diff --git a/charts/apisix/charts/apisix-ingress-controller-0.13.0.tgz b/charts/apisix/charts/apisix-ingress-controller-0.13.0.tgz deleted file mode 100644 index 6f741aac4052363860e2d326b4aea6c8183b2a3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20799 zcmaI7QIa zC`=Vl89*kqQm&Xiga&=vgxBBpr9v>A8wsf$$9EO%lKKY+!RnoKbb?T=URMV8W64Gd z62fwmNkp2xIU-ZL=-Xkw-DWFxZ(op~pN|4RzJ7l9eT5Eu8$79Mm{os`M0IrZrvUQo67JUWrjH{fr6;TSIiwg_#Bum{GutQ5lJjU zJySC6S7`$$|3sF+rP_yKh$O_39G?yTm?HED7#4^jXEG*~n#&<~@%hOn^v3K`T#m~l zSB{&B2KO_bIw~THd}ScNlJiu+ti%X;VuPuu$w0^*;1kXJ@(uuFK=`8AV)16+9O3loi9 z6K4s!coHVKd0JfoemC`aeF={?Ew6)BtcjC~3++L;H0Ug66Q#>5I$|2t@N1k*I)x=BkEa(Hu=dn#3lC{d|7EKRUxva19Dd z$f^npa0z|uZi0LzV0RHeYdJ!gdug!2fdYwC7sG}_jIm05=g9?4kf4vTc1IeE(^+yS z=*VMqq3vY-9xxfi&{?OV-ZQ3H`BC3l{ktBVgCAVHZFe0^St1GWy|(?0uaktsum=|w z7Me*4&(`^*G7O3oERCfaWO`QAtS<}Cln4WZV?pMF8q|m%q;PEpavzUFcn8D9e(~hw z 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 diff --git a/charts/apisix/charts/apisix-ingress-controller-0.14.0.tgz b/charts/apisix/charts/apisix-ingress-controller-0.14.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..9d8693f456659b82fbb7f4d31ab6289735271978 GIT binary patch literal 21599 zcmV)`Kz_d;iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMZ{e%m(IDEj@ar@)pwr*TH4B;OKicF%0raa->uj*sQce6!Ph z4n#r{#uUKGpR)a3kwUtx?y1fMwsDS2Zu9? z7;`)la!P^#(f;uqQtqzcBKVJcK7+wvaIm*0|2r5A^8Xzi4EO(IxVOK*e=vMD*d6}I zV0f^*JNOSUxNpNvo|th+|6_3Pw(_0(ojfoM35Oh$kc~P3K+5qHdVC&FTuk~AMHB@H zGBg6+DGV6uc3_16fhfZy9D(Id2S!oybLc*I2OS?VkK%~SS4R=_<_H{}pN>!e6P&7P z29A?y2Bw69pW_LlA>xR2uqSHGIgi+=--oicOX#d0kQrfpidbJwS^Xb33TK^bw7MbG zXQPe-^i1wJKo#gXAe`Y){MVy?X901@Ar29hr9-$tBfudU?(FXE9~>O)?(TNf%hHw6 zVI-y=lJyOuGb~Bwk%h)tqvy;~uy8!FlsbGBNw86XJxTG-(hzRo4)@$a=Sz%#>H1&7 zAV%yV7(n&<-`N{JTU-D8&-UB({}|6!XA8W<9ts)q0VjZq#j4iqm`wQ%qzL>#;?S2f z7Cbo`|F8|>&_@)I5CKBLf>6}i0&?cyNz4fafdUBNj3Tr^A!jZCV}vC1v)7lW$0uNl z0|b1`R3+qt8_egOEx_lPfg3`vC1-%Xk43{U063fyx=?6PG=tQ~;S6{rT2VZkb3ksy zqMqZ(?QDTd(T(vB1{0>h$~HLx|01#OgVkM4g&xrC4D7gr&K7tgigfkI?)Klnio{?6 zS0E%D#0*)G(XEFf4sZxOvWNl? zhGLGxSr0Hh=$)<1;H16TF_c~kPpQo2Uy?%2E{&{q9 zaddWhdNKyDFTnBZvlpkAr?1b(;PnsS=j z#{nKS3aZ zOsqT{aw29H1spA+0CL0xGC~r)ULs1dFC=ic)0xIWu>Mx!Y+eChBOkyC3K)Ql;aRAL zIxCKKUqIRyK#`Je9aTAP=EEmJz3fXlJ7E;L*NFfZT7#0G-47ptd!e)k_Y5u&`1Gk; zQUiyKi`6m$-+uT2aOefGk3hGaz!$^mQ3N^iJ3#+60-VOE(_x4%v4@U4kHjIbfDFMn zQ?wqo1|>M2po-xlIWU|EX64G#r&Gzi7~*14XlP>g3V1yL6&%dK426h7x&E10P6Do( zfXPJd0IfxJy9Sqkn$EZkLxQdpMTB8a=t}5XwklSj$pH|>L2yn2?5#%Nbb3bkIYkUfL^zy{ zKv(Lt-A*SW{!xCGL=+Q>`RX`;jGY-GC|u6tAQ&T$BF;wO?YoW_#Ec{Qf(Q+C1oTfg zARY{o`5`(G5z0s4`JmJBNI1na@eXm%7ex>izciIkLdnj>H=sTWju{f(OE`d#OhRjS zWi2Et_#^dBzDmfJK+P>0@!g`SE?G+CI!J=tAd>XfMJooN5)y~Aq=;ciOwQ2cJGhw> zhHPSp&r%r&soCOcFmkwe-FQff+6;LUR7@C2U> zCXD-t(w<-@3VXR=lX{qet}41rFjxtI*pu~z zvIi)FzMOhu3D4sN4F3j*SnxNPAqh;@&H@x##{V3@J_AZN8kimol^CQ9Yfyf=ygZkT7zv%2aTE%LRxqK=uysez2hRthrqJ_V%7P>7 zZ3f=B8Nj{0T?3F=5cTT>q9qJ(a1dyP7J-w{j|dLAk|vlLaRNAz)#Jz)WS06DhdgE( z^<0Y}W9=J3sicn(RH~>%Rmct&K@auW(sPtt=L9ekEH!-0V+EGaAy1~Y4>=SQG(=K} z3zuz`jIG|87(2w1SSgFxdE0H??xe&ke4u!Ymco$ zZ%#>we-n+TUKC3;5o(ZRn?kZm7JZ?=jaQ*}s-X!vH%}(Uc@WQVxIi3ABID3-UcFco zIt#K>63^z~Sc8j1Himotkl!yo&Er2z|Y<;;DCP=IXUx^2SgBHgMeT~MP+<<_DGoz-Jsv3YICmk-K z@L@i;deGA_Eqo8=>Lo=iJ5&dA3xi}bUojLQPnh2nMM{Q(31nDlTI!>iCJPwC8S>ML z%+=78v_OF`Wl0=~Sqm5zR;>0^fuXzS4s`J!h%nXQA_`E?=<2TS`FA&vdvhGl6wQt9 zEeUHr$@Wq#v_Q~CODR0rcv5Su`#b_~yWMx$>7jZ|LV*3mShNNtKv0-}9$Z8a&q6Z* zBn(!vsQ#X!EcuL&0=z_Yl`Ju#PlU5{0Hq)V#-L%~31nj3_*gJZwk_CYCrgz@Y|duOGD@F zRUcu5!HkkPG8py@H|mCn-w=9@!&!ehoFEQ|T{9TjZ(Z;t>ut{T_R#L_c2D{XG!%5p zQ7F9#X$u+7l5Hl_&%`;NE0lKFn0}n-d1i#~IKW~CQK&x8VVHcs@ltvNXuNqp2UFu2syfeDRvzm3IC3LggmWLa<7)DveuDx*s6}=r%$gH!@%goXXJ_ zB`EU9Vu3pZi_y)xHXew0b8?}&P!CURFU}>pS1id-< z9&xD54MEl)k8C4Oclqf2v~au=<|K^nWN=MGRRbugh9A?Vm>H(5if!dmu+)i}J`km-~0+N3JgLY{om^#p3;Lz1*v!$oZbk#Ep zSh7hZ%jdt!rbZyk)$Ky(($YU1K35V|0{I!OMxcv)f9M@f2fKT_yZh7O?!ol=Gw46x zn;h)yd(WquduXPu9S?e3a-3AtR>HPtgPSb%<&Ijm%iSDPOU7JQJ~}^52UHGUMlR`g zenP=QTiANG39FP)F;+1X;@0v2$>qYNkHn0K0Hxl55FuacuR>-kFS(Fx0aAvU+#C>{ z;^Z2IN}UoP3>Cp-WqP9*&Mjs_0a8wxtQvP_InHdT0-&)RWHo!1Nh?ItOB9q|v94*q zThQo{{-y@G+vy~Fy7DLC5c6ZA_b0`4SMC`wiP>sGZjDcB==1)pe{21nGbPj!l{==Q>Xp?gNrujrrFyR^ ztY#lV`z57YS*&|)Q@g8h4$yxj6Rs4Py;+fi zXnhjWFXwiygt|bSV($V;EO0nu;FbMG+3Aw4!YC4!4gpM>a12b8YJ!C|!?j~HHw~j? zJd$aczUs?uE8fq@@7%8~h2Irb=v=9Amz3hd5xJi1;rsqp|ecejocYl()|Q}&~&Fc@??tfZI+BRIhU=2-cqwg3P=C6W2t z0Y@)i>Jo*KhDP9MinbP@_Nt)diF&k+@ zz)5OKbqji)5RsTO6ikJLmg4V>_)_^4Gx(Mx8p7a`3K{2_otWdqJGKRKA!1vp0_zIR zA-9zaZWM%Q~d;RJ3d<397aXr^x`!<$}(S`J_q%`dg_jcW# z-Jv^h2mRqe;z$%VfoT!oh*@1bJvUBU83<;X5ohAJwDu6akdXmrM2wKKtuwEu%JIK5 z*i%0F0tiA836(pCSrCrXwGJ_Z132-YPxl9tXJ|5f zwu5$k$!Rsab&RdEf{S45<>BGBHr-78)Un+YvmkU=0FFjrxbsY`Dt8y8&z6Z$@WAPL z&k7vqWvrjXsCYk+AO`Q<1i0DIKHS^ew_d6NxDo`}$&6VhDuP=<4a$TvBOpibDj(XQ!h6 z6b8Wrde;Dp$q~wFptm1Xvz>3sj?Ydd@?Sdmv3)Ayf0ID8{@Lrxld;Qh`5oJ+ ziT@uC2hXzczdM7$&a*cD_c5LywJvQb@ZinGOR;ci9EN%;i6P*T#X>N`Q3u^hsdxVR z#nsu-tCR1(c_Md5c>shF5fPsO$4TsMkPib?Z$EtkP5`>a!Gqsz8U)xY4=MbvC=3xe z1pJ$kP^e7bbw9Y6qXm0Ac;}i;ZwdQTciVLK`1RT4(dpUA#nt)ii_7&cH|y~?hGzNp zg^lDUx`xC=Y7yd(j0z%A^5z6||A86iCNS8@?xBnsF*_2{ma_)7+c8)-!d775ObNY# z)VELwC{-;l!4<8(101H#7R!4Et^3q^-)!|yHj=29& z2kq=r9pIxd-$D-@?8-m!VjNGW_!e}XF3_-0=!-uUzQ-ztA0{nK;~-dpUt<^uOWGIX zFMHy4{)rT9S)Pj)M6Vc_APyVilPv zE6CIs>j|Su$^D*<##z=&2RYw4o9^mw!_YqhilRVhx81*XLHDY=`7$Gm1qsbw-v&6V z8Vcz-3KlM#_hmmupqZ_sJMAj8n$$4ipf7dPt~KK{VUChR5aQdq4V6Ry2peIo%17{P zOgPFBY8{FWICUngQO4LXA>~DcHoNh6Aa%aq1p3##aw;FEGGq@G@wt))ZOhe z=%Gyzi|r-xEG9In5r86!HkI_!b}kV2>-M!R64V>VYSl>w@@KR%<~%20iewzJ6`?ex zWT9h|HsYaa7?#U2u}Ou)srDF5KwN21Q(mZUSj`^0G>)otV7|2J^oMww*#EkW8qEca zHq8l9lmB6`HyGsX|DF9|oB!cap4R?v?f=&Px9oqRwyg=i^!&A}_g9s|W@SPecCK;g zkJ6KH9kZ7(N>0cZXmQT$CS|PIIK?u@d>UgYH&vymu2-aj#0>ZdLL3U|5B3B!gQD)L z;O!&ue@oD5IIY=TmQvaL0BRrkD)$lqCkZAP^mq0$A9R2~e~`iuwXf7^RvQS8My9m& zHp<4#tE2I0HF?@H(_nXPi)6U7`|Plr6pARC;@c7E_U)rc;^BCKNX$pzV9>FSu4H%G zuQZLV4fo^|MKMDPW0ki+ePx^?xVVZaxm~5mk}z1=@hB1lFUt1jPz742FQD&JL64#R zS_Qh;2muiLc~CopL4pwr(vJ#xHUIQ7$V4Wj3&7M^A3R47R0)jCo|X*>tc8Y@K#*UH za8V0F#%UDQD+`EO2cZnU%z7CP)=Fuu)VyLWxQfy!iW21QPz&3PwxM`9nj^|apnG!s z;-?emP04|kqBKOVnw#y=hH>>rHO*Ncj8NzI-81M_wF`ChhW;Wt(D_@|@e zpN@70&iU(?{~GQN_N|)h-^#HmZ>=0!LEp>zUEF8=rLcGreadK4K$rAOVevdAim9OA zu2XBBN?ACC^+mHb1}9_Z`1|8s@grqx+O~tCU%9>uzvZHm@{?A_WL;U|Rf4g`jP~UT zDih`=1J@V}`epnf6X+xp2URS(dvwT(NU|ZC*H2aBx%s zNmm(xo!vpA88`sq^7iu;cMh$JDp=3xjWreR7Ns&%S}$91cz8Il`uJ;%73URnRvDh})kpsXBWK1x)lahPd2TQO~M%K;O} zy}6@@lU232mlD+h9-(W6OY2#P;>e*$*q?=z$<)g%jTknrw{v)SXwB0pqKKAN&egN} z$LO?S|8@?aTX<6JOakHwhF4o}u)dy_Fu>YrQ(Eu2RZq-qEKdar##Y_lzC{-gG6%+d z-lTu~htEq zt+$urIbT4palPHN-UKpSQ88O@C$0DI8{T{zto3(|R?X|#l7fURUX(6~OuapurKy0z zvNkjI27?`Ie!>zIi|P$?^W_??ynw*#x_TBrlgg13keT@ZEWZkK9CVlygbOUs*i_>= zwE3VGpwbmtThEd$svbo*6!U_bxq8p7^+2zu0l8^F&*5NjkkT{4&V(Y^fG-UP18W@# z9Z#~CChhI6)r-S*rnFvfCs!{oYRl?b+CfNsfD{f zq5v0kFjMW|z~b^grbT?Zpjt*au!w{VmCP5r+H;G?U&HA&bmUB{Yi&Q7Vp|UI}S z*2`8)CBuwHp2H~&nMeHfDV?o$kgaxuCJjikZ_Udno&!9C@;GUTe)Nfa#n}mH1lzyl1h!86mR(IbJ|wzo5NrwRBFhfK_xYS1p~B z+^eEUuG)TXy_HtXR!fJQ3T=@uel4k)t(FcqTd|;gO6E29R6+GO=$j?~aex}ml3iQP z46t`SCowCooUN7)H%Fl-4O%(gUcjoVrNfOw7L{|?ywZ>|JfSU6!eNmlUXvZB8u;%{ znor6Edzg~o$)G0+Z>Oj8y_j*bFrEg>$dq{;w4qtqxP|d-QP#Nkt% zw<6ZTr%xuCv))8ZdS_ytYcXlk^#bZyTjZLUGY*~vC@g`P$#K6826^0+L+nc5HjqZ1 zQ5eop6PN~|BYV{VW$UNbU86KL{yJrH+4D_Rtpb`nMptYVdRJ-6zjZj}N%9Ryt#F(0 zzAJB01Sg;Ner+Y@vf5{J%onWA^khg{a6RroC5x}@p#>?MTHc11Rr*Wjjs z!BH#)O(q7vLMB_d&J11&vLKgu3ePMf5_8lL#q~Vj>uBnQt(oH$jBwppsKMz{*D$!?v^l3Y9|n}!yv8v6Xul};6VHGvFW#WWbL=lwVwJ|84EqbAv? zMWY!}Q-*~}b)8L!y#XerWLXC}sw=C5LK}7G-iYZqY_~}{qY22A;C2Q3Zm)ayP%^4& zPS)^fRymo}#J-k!s6TuV|NHdGeR1-`(VLf-SH~~kj4w|vu8v;3Iz7Ak`Q%^nb2p9h z$}2FH@T(Wh&uG%Li?fC_{{E1I}iUFC;-aQ*yU7 z6w_u&f_Q-}ayptTXD%PH;siWnqS=87O>MOFk!fSIAaqFe$lfr@6#z0*e^H4IjZ?d) znH(MW>1pmfI>;EfHkvjUZ-8p%ZmWW!x`CKGYuBmiy6PG%OAutBsTG&=yJSmnILn{# zy@MA_5me?u9)Y*tviY|?@U7#0+XLM=o-_b>C&Xn|0VcP**;O_v|rgA{}kkyHf51ia8W3WlzJM%!0`* zAg^K_q^Z`XKL0KM@xBD52>STzLde|4Q@5JZ3*gJwkcWhiscX65_ud)IDj8=smsM&bQ;a6a}na6Am zHA#J1k*m;M&)c$Q7v58+u9iIO0BdAXSp}t`HkCkSP(F)HIvhM7G-m8J*fmAI2>9@h zz*(&z-8l15wZPgi{2iEMvRP7Q0^C8eq|&hVjWAl1q0L2vp-K}`v8gg=U^iFls)SLs zg)1IgToosqDHm9k;;7#1V&5HX1w7d|3O}fq$GVz0EoI+V{GhFwi;t~18*>%%1NW-r z-eJ3sWmgktF_BrEt%S|r)Z+A|_u#(d(`5g59>F`F{7_HL{V#h51^0jL?X>&9kMXqo zzwQ2SyZ@WL|0Sd7m26OEwu#dscDSKkbD3VVpf;0#A{757bi?4B_(!@VqL00^{5f`c zWlt_4ogtpskVU)d;{DprIso_V_X39(MO(-AXjo-*C3st3DJ`QbspF^C#wtrRM2XT(dJX7NIPVrIC-NQ zu(fOj%4*O02A7D!8L~c>lBgNx`NW8|qWu?W%t|13@H_}Z^zwj6!N zS@1PYf{pumx51VBPG5rw(nSAHJ_eAnJ6HmB_x}!_?d0!&80-yN{r@o@>3AKKqkkKKGadaKf`<;Ph5{I`l?R({&62O z79-Xl9_;V_sl6tDoTmx@kNnB!^#APc4Dv`j{;bu{~he^t?mEq3|jr~QJz-+YxTcY|I6I}m=WTV z_odfY+v<({1Y>TisO=5_kW}$j*?&(2Xs}e z;99_!qpmknab!zGCw85u-Oa%z$APR|!zQs%@+KmF`a=iD*)QaIw<45;=4bv6FiU^P zd_Q4XaP3wEgMv7dh;rO?4F(PyUTOuGJLt3jTn%Mt(ARMShVq;f8js3qfILO=oJG%#M{O_YYt^MEH|E>LBZvSV6P>ClX z5#Bk8ch?<_3dz?*?!lN7c_J!{&Lz3dC1THYuBu)uPyd+DM)F^o(Hrjs)XD#6gWbIR z-`Q#7{~qP3Vq*`qBfEYD!kx0-HOYHttjU7>cMY?PefAu9)=BJw6WB$keO20s(Y34RqFl2D4czXwLJi$=L_-){svBJk4(*%zg(VA80j{4asX#ST zC0{IhTU$YMpPpkX0?f&&e5n&l_{UAsWgv_;!>RF zx2RV2oe0$puQ~f{$6*5$?D|!B7!4|k_EE78wkni(@|ZVA8P{HQ7jW*1(ZcIHYw8pv zRLG=Q%T-s|OD>Qc036N|N9o#!vfC>T3R_;gtkXI_BGp@?X*Qhm2|PXNAMl!wB3(Iu zF6ED|FP7_n?i>XRJPQd$_iUp^{~PS@?q~JC;lciHd;kBVJX_!#a*k-oq$VJT8{EuM z2qrNOq>2?m?;6e!Q+gFE^O<)lD{FEX-zVs zXo_#O;s^fQwhLZ|!AfeCkwQs`ZxG-RxgGb#_-f3Rrg=;j3lf5V9FKvIDeJg1%=_|R zg?`7K{6_ooU-M!<>x+NPPqqyEDWD1TuH#6maIEvxWj9ghsXKw!ou@8eh`$NNv(D51 z-Pr>FfE1IMfzuZ!tm8(M{2O_^<66}ibg*Jyv1aQbW z41~VEhy#wJ02TDFCyY#K1-!R2t`L*<$klgytNy&Vv`fJ;S0tthVUloVx6_fF(wjrd z!GsXbIE9fgLO>~9Kzh%nG^fDZlthZqqkcbw;x^DBxSE2Z6K{V)!6F?OA;eua-!@zv zEMN#{l2Th+;G809Br?nq>vWDJY6UbhrX;gR&7`#(y2FFNDtJF44lYncz-c%oozDCB z?>!PS5}=O215oivP+QR;NkJpYq;3pHOB9M(WL40y)bHQFmu;M?K?U;uj!x(4)6<2J zMlj@~r%wS9GDOtf1*xP${yHvtZh*HJCofNq#wRkr|2t53g$i(-)I`eOi~t-*g@>gj z6w;S-WUg+}W6UaMftXiwWE0v9GFD&A4JMg87TiwfN?6EmGjHEL*~%Fj6!g(;DRS8Os*3g4s&Wl*J(UDCZ$BdH&{>`u(*$ePJnhL#9FHIcI zO0d9UmiHyIx{?@ec_}=H&ygbs$eBoZrmHxdZM)!-0EUnp^JGp>0t85;Om{iPKH?Ay zhA;XhWRf{WnY6Sr^u-0lHF0gdHKV<@}E46)c~ec0HX+^9=6 zSS=4RtZWOM6F<3|uhV(Ic1_=Vbz=yiXo@HbJ>&x@Eo?xh00PBseDMCQk zRiDg_eNud&Ti)p$CHDuIcS3$Iu`flx8aN1U;7SNoA5F0^0VrPL0L_qGtkCl;fuuac zl6Zv5)2;yO5jK%XAV5nLxSdW@5+oGv&rpb{AgfhOu%P~O=u2S1JEONaLc2Z3CslAtj|6r8>Q!@*$S%C#vkad2I?lV&9@y266S z;Sqbo5FN?7={tQ^YFE4zU=lgb#Nsoq=b0#_P?x(DJz+Tu``PM`oXQJGSGqKrN~mfM z2SM6NSL!l?Km8hGjsP}ljTo2fklgeDR>XauqWE5DIb?x3@_Pl1Nit0kpoH)zgYBnJ z1%}w03xdkA7xZUfMg-TILBVg;`(*rN4j-&ET9Wn(vm9&G3-IaFi1=#piN?eX3H2@m zLwuBujr0LJ3~{i2$)}qP%Xk0h|NY0&%Qq+g=l^R^K@ucaqj>CcY@!*SY$GH$$8c*4 zC{Jyt^AY@vR^TJJTtx_c1TVD0C;nm{#ghMmkDZT>c+|hsASc#GVHE|UktqxqN>M4vxGhs!iQ>b- zptx{8mzFGCShOZVaZ>wvaZAST`3M-NLJ#@~-glQfT~YX_^CM#ysr9IWj4@NmzX=up zRT)Wpi6SpQiB_^VVP@d#Pp-V#rkmiExqd4;-lgh}L_0n8`e(H2j=ISA zhu-0Iu)DXryFVT79!#G__G8A9b_pe_BQc-Hr~2&j)IHs!1r_j#BZn*b;NsspRJ9QaFy> zazu#Y;)fYn7kDrfTs0liU28P;SQoXtc0HQaux$1+ZC04^+FVKft!j@^$vf*>G$8ko zRgw)?0#ScUo@V5_-f0%PcYwe(TImgT(K{}W_()kQKA0&2CM(me`tDfcUC^^Lt+Wcl z+HH#Fv~*WE_W)TUN~LmWTf3s5)O^zkT!4~&Eo}yg%ybh7od`yxtQgGHGPRqw0ZC0M zH$PpFyUce4GHoOXEj_(v*ReHu%EznFJ2ks`8LWqMiK`I+$(ElOIkpPDIVGX8#Vivz zz0gZ=YBigzwmn4o4>-utr;oVTzd@5ZA=iCTgvo#12rZHYartr##7jKI9^^;`Jw%Yt zGm}Gc_;X68I8e|Hr{^@5j9!%xnvX8B#1Pz|iR#}J3e@L>@sXJIeIHHYSw9k`GmA_> z%Qn1zsb7JVIZ=&^!a$W4OE@Gv16&p_gT8jvUWSsV(=)=)DPkz(l5{y?DetNlm34l^ z%0{ef1as5b^0Ah-V%M%{L|u$)LEm-v-GSqy35H=Qa8c`ZW~rv{Z{~!d%wVOym*m3T z40*E=gDEPb=Y!{iWCs3pd3i3QDdfhGEDe2MNQo@}RkiZ)S#bkw5wVh$8&q*hnRg-+5v5sc-V?2) zfhs2PPP}Vj0!k#zHC2Ch`+@E?8%n z^2>Enjb%5E6nVi%NpC@?x9{@$%{5vzVp-Q{wZ^feq$}i9sePT-oRZLjwBQ6b?xNuNgLhdecF09$9}IX z`lq_86tK0>jPB@dxBITwrHEM~s5|N&%)7m=%-dpSMR{H=}lq<2Qm zEXJ&=&q66J`&`hBHI>RG4#P?RW|SP3#>>xxS1o_3MWQO zF;h(RP1hB3&;@6Nqmc@Tm?FqyD$P7ErWA!dSn23OA1zTpBDtw2&@+*vGQt%yfNmq? zapb$;R8B+jjUwf}_LW0I2nWoSjvrCt$BN!4Tw+Q>0ogSU_!}fG^*Hphh-2wQq6m6( z@IB&C`8~um`SGZXT)8_Z)@FBNu*m&U>5vW+`J=fh7K${tb|;lP+rA1zYS=g|*zZbr z7?(qL_}m=`eCK#JS1OydB+|XuZpG$p7d-J%M3K;1{q33#7cS^5Yh7Q-#syNbiVH3! z>E-W50Z(!}<2D5jZ3=An6k|)X1X@sSww7(6tnaC)DA8ClTWq%DFA=TTX1hJWR5Upb zO`@n=P2-%5nV9~?c&&*nTTSS8rJ|6OxiW!)Lh)4!IG8{t7O1e76sHPjdJEjQQboGf zjB2arShH8%V>Rg46>M z46)Y(Q^*CiGq}8tc@*b-I*j{>rlOLlBFTyoJTpNtgPf|^Q-OGDYMMG?acQ_x%rowj zn0I>uhQuE%AZ2qE_7VjUhrufG`ZKlnL=p6*a1-ld9xq_{Hzi$fFhhlaa0veA`1P5# zBn&*w+9F7qI%N=1GNW+80D=q$SxKx?MZVIp@5iqS7|ppXV#4Era=QtOQ#X`MR$+ut z63^y(kNOpivdWxVFeYB!n5hL#%5p{Luk+?e{=7RYteHL1pJ`4Xxm#~FoZ;}+l@sA5 znU&6Udzd9dS*OxMiBox$GobsSB3WmZ~1?d$LhH%rRzwy!MC1Lmfu znU3w08S9g6tOZaKwkF*d>ZE25s6dQtoKIaGUVjphNq;c$4)zf|gr5Iw=V1EmaQb`z z(Ev{T=hOYcDZ8cRlzSf7aI%lMPT_y-a7uUE+uOt%+;qj5} zDou8<&re<%Z%nLD+$|BsQ)Lp_&Q;0!HTz54_&x#S@yq_@%Q2Y4&}VZf6gwrU4GT)L zZ-Xbuow?G}xjtl57z7jOU60RB3;Oy(?emI{oB&f6;3)`6DD51rUn#cl1z6}>`8LFy z+$k6a;|E@=U?-qS#m|- zPz~p1JJU7Ff!TM_%AwpZD?Lr5TmhH?2>x~S>ZPNWxmY1WCb{4R@&ch%Eg{8XMaTs$ zwI`-HqKPI>4qm&8E+O%4^QTbCM8rR;+{8Df^0xrxJfC{8Ccek)9YNjEu-CQkAnJ~~ zhl9U#WeY+o)kZGSICS(;R2f`mMKbx5{#r;`8P*LpcnAePW@@9UsM{rgbC)7zBMHVx zImB~?$aJ$N>`R<7lTOgmZs)yS^nFP?t~^aFG-Q*SiI{UVWD4GAaeXhn206I)zHq_C zT&_|$l>A!>Tp>uy0Nq*XA z@*$UHHiCT-$hs&?l>=kgUVMLaY;DDA>suHxI%rb@UAwg{8?{oaj5bt4Gf6y(;#)S! z1iIe)f9gIb)#P!G^V3X>f(qI+0#oObE^2%OBEww9)e`01m$`OT=5uXjfuKK0gkG*0(zhWo7B z>*{l@vhdnzUiCV(;%w5x>xz+U1}Zxy@XnrI*SM+iJf~zKMj~c_M542Vy5Pc`6)E@% zmIHS;+kP-sNqHB!Z^^2PgJD({AU39Z^ zm}Z$&m={c9`85h+3WMUNRTj@Vq1;MZDetiLJoOESvp9gXuzClm013K8Z$iPl!ykkm z$42U4nGi=FvGTBYfU%~N^q6VD@<{G1WHO}dK!5#CCL4tYMF2>II^%po?e_dTEsrWNm6@NA9>DAUuVUY=B=*`8;vidr8pmyi}ebn#2 z{jbrxzmA^#;{SE~Zf%-0%Ee7O2BU(n3b4|~*FLA)E_b10>ZdQIL=6P-sI8>(@1_eA zLIMQCO8S*_Q#|Z?bpwOzlCC~3vOsT+TnN3T3fKbP;zhg|fnil49O^>u06ByGTI9lb zF_G)Nyhte_D?XQeDtIlKQkJJMPAHtAlsUFpMObYHPqE}%F9X0{hGR8j$W3=DZ@x?E#(Qo!Nv;RoQ;sv_H)i3g? z$^W~*Kg{3%I@}qw`F|hf`P%G1J<}f8^wUs_tUl9Vg~3;B@1-!CnR-d;82|TY?Zte4 z4k=t9j%bl+AR&4^EmKOWl@?$W7wjFye0~oY*JyQ52sb2{UVMLad=C)+zTx*oV!nW7 zl&Dh%5-OI#uNbGM2&!_@Gx-2;RL-XhG`)xVlfbBItO+1sR$OHXsoT6n;f&9#RUpvB zhEPvaatZ8eHK_`HQ#^9$9)eU6WbB5}8l*o5xq#g9`MQV7U|3Vk5b=JaT3f_0m6kEw z1rTT%1K5C6YPbICy4-gXjgsyS`%A=%yJ+9C9=(HBi-qLXY_9 zDyH~KMsnBCsi|Eqo@<1ntGP^>^MFtn@b-$LU#}*_Z#Y&>$e`BUgO0yC;MbG@n4@~y zZ_v6a3MqxF%92YM$aF-4sxe}G1IpHqS5sz?uD?c1wx-}ih###Lx6fIusKz$VhC zsi@F#v?K7-cxV6Mp*Yn9GIX$arAEIo3ii%RH407GI=YP-xBUEIPX|8LwcLdDH{ki7 z!yE|k6mh&jS2GGdbQK|rNv&Oykl^9EA5pv%-2Wj(UldOQ>^-bBZ8SL_m`QwoDWe@g zt(3V7Akaz~umP#Q2&4OYmYVUDwrlM!fIz#}z$O}96yaKF-dOl48}dqBKl^|pl`f0- zM(zOa{wuWNbNLi-vKu{}Mj-zbAx7=~*H^Ls)f7bF!>HXt(@!hetmi9}Z0#0W`O|Kp z-4jmB807Q2WDM;VTDyhTZlSeXXz9~#p_M$X^f6Dnh1PDN6}Q`Np|x9Rjf%8eXeCc8 zWz5rVp*_q}Gfv8Ot=$C>`0{HFgmDmjHLEFRh+g@H2cg%IdQcbLm0zVwwY$v)&!26n z{GP;8yW6~Rk!;EA?;is)fx$%_pgWxaugU+l`|Q~ufBt)KcfURV z{TR)=SXpFEq5vmWnF5@tP8DE@nfz0i+@*<2vs(LW zr1v$@B^oHKwNPqkT9^N*RFQNv9ZTm{(Y{ob>Y*oHGo>R@6E;{D9tjnrc=(CEK#U3P z=01Z>CQ5DkQDsXO@}mY^wey!E$m(HK&%Z(%Zv;XX`E0Yd0p1fK?0lwuIc2qx{-^F` zzH9o|I{ok2U~et|&$EMrR{wj9=PT3y6kGiq>0j+RT%ZGH8ZOrYqvB*hcJ1G%9{6=9 zAZk^-uR+CYl{53S%GstU{pppnI~;uZ%0xu#Drn_M>ndoaQ9(CaX|yST-=V9Zeg1$? zBmd6@iTT~O{^V2b|2Y`!?C<6LKZE_jZtMSfjOQ!!|4=d09@gSRM>M7pu zqZ-<0aPf#Px^vE>x9{8qdWrWvg(*>`4ZBZyh}|MdGgcc<@t6YCd17!;a=KrJtfZxY6VRr1{6$;B=o|z7ZeII7M;D9YP&dvC zXHavF#5_&Ufu!YGTqp7D(qvr=EiPDnT;;1nm!Ue4%{3EYEi~y)GkKu!JNY$+RR_B4 zvS);EQv63@RUvvguQ_&})_92++o1Sq(}HJ&H!gdDX6W{nSfQI#I3s-HIBvmsH8 zH?AS{<}3lo33eVN;`zkTz6efwnluf4y0 zH~Js_U!J~u`peV5f2Avnq6OjT$oC(_==ma@Xl9D$_oIs1sbuMo6V0Roe6CawSk1-Z z58LKr_~7bd+ia8@3HW=*xv8hg7R4qRzrIY0ghq60wpwbkC^U5aR;}A)udfD1wNH!V z1tM{UUD9l3dL#^M&6~!FDqxMu+Yk^#;X?pwFe`4*gc0w$${?+u`*jnma#A_Uc~|=P6gsOe#~tf`u*YB%=5w^wy%?mKBW-Oy;Z&DC%-quEwQ2DL+^pgH4U9(H z7n^NfY_N54kBy5a+ZGSFBlz$R|4PR7ARd1!Vy9;I!CSQ(bFja^yI(g^RnaEXv~IpM zBYkn;QBiwegPKbTCmspPTdLz$4!Ar%ul)YzMfvwy6dyyHm3}wWc}!{7o*^g)*PbEx z{hw%SBVzL{w-K>_xQJM@g4$r%%u^w9Di!-?(GCr~B~|JGs5fvQ6_YqpbT3Aw4IWOO zHh8$A;2$J-xGu4_dYboR0vT$MS$U%o7C2tT6hA1?xIS;~X7Cug;z8qEfSNej+xYK% z!A9}lp!!nF^l1ad+d%P$ZN3c@Po6eV+oJBTlC{;D}yL<8aNve5bCoVexHP zd{V3pi!TG%hQ-?e+pu`~v|;gWSbW9v#|VpWc>Uo95ZgfeqGsAa``THN?5&qK=OgA( z9Lc?N@Wzw}6ipEYoajV^<^wpsC|8SW`BSDXE5o6Iejyq~p@+n{afm|(U;zROIZ^Hb zcwrMB@xadW2la{9FUSWuZSmR8Jls1kdV6T1qF{SyBLB39CVrQPCgy}aj1+HAU)WD; z*|e5TYuQ++R9iOfA)@vWQT}NU5#1fc@B0u@dlAW(eHz{WaT&0?-~Lf||Htm`{$M|U z|Hp8zz5n%5p0Diw4<4`wzW(DfP+KM0%Rgj0@_pgmA6!?;-~OTA8x{7A(qMnk3amK~ z`Pr@pDLnf)KFgd%Y7Z^{bewK1zk!@-yE$Ol`6}r70-y0r-rDKA&vV~xfphjU zV89oP1u-xlzXV3a0UUy(^V9L^f4UZcGDXN*ra3X3Y4TfvmnxSu%IC;TKjiDq05S!9 zjv1gxPUetHYKqq|)WX}<2RxZrB5~jg?QV%E2NZc^7UJI$Xbf;7n+YICj7zPFhA>bO zFg*Z6A1vSsP$b}jIJ6+hBFqJ^2o)rml94m+xKpcq)@4MhM1jlfJf@8?gXD79wD02k)niJa=A?p>2Y?FecuEmRQ93fAP zk|3L?g{S(IqnPZf)Oh^T-Ned~#4l303ov*U^B4w~0Xvqp)cxbS;6$&^g)9RuUyi}? zkz6fHMDcVbm{eg9UY)t*LB(au%z^?uHCxUi_H*L4F>G7#M~Pv=;PaGgiX&*?fobS{ zY2+tK5PqBn>-{Y?-WCTG$Jx^`k1d04_t=0*!vuW9Ar6>Cl!ORCAuhR66%p`aN~O-hAxDY+ zcyxZ6^uh&>D;ul zE&x9e3eYWFL;>o_u>wC3qA9K#{2)8p?}Lj(v67IL<4;O`CUsmeCFEO{?UQRN|16BU zA{1nskfIUzrF*o5IDnG?{nG7$U%Ka%$RWkyOuP_`;Fs-uxA! zGxRfBeJ25CK8-nr9L-kWEkv2*TYwqATt(=+1&lH;U%@B?C>d4;-o6uB)pF>jL;YTu zQlnqGX`gyzA*M{kSHE;Y27}QrU5SHvZ;&4S(iN?V*OYKFiKnAqx|0=0tT*gY6!pX^ z{w{6dm+pJ;OK6ZLe2%CZX$C%Z@8}E;Amf)5$^$jZ25cCcvtH4xRq;gzOsUD9kc=m# z#T*vOxL6u`Wpe^xD7)n9d9N&`2?95B6iQHW=p!1egfWmp_2w{~3C$dwiiHH_QW09a zbSU&h#Sp~ISP&Ag1fp1TYOQE6(g^W96mc;j%M>yomf!+%Wd=I}=6&4GwGR0V;dNonOFPBiVL$o*g`Y ztc`>W8P+RWHlXZh>f)HCW#kOW&dVFf07G0Rr|>}>3AzXdi9^O==%F6K(_&ya;d{Xf z40n29qDj2Y@!sCPa|=+$3>@}y_z0smmcl~JE^veST-dx)f@tqRfdoMbzV)*fhx}l# ze0b{*Q$NI(PG&S!VLQ$)5@G-@7La2PU|(3pQ;euRwMD0OMIjP1RQ#4{K4eYyb4vW! zLsSYbW5C)BN|@VnH7JJB3*|{tQhtY zMLvLF7DEa{j*u_dk641bti|$R>SQphQ7u))tOSbMF(FrMqoq0=>{O0*u@eio*>Lu$`BgK3a$v{mP7JPf8dv1(!5NJ@5kz80rD- zYc3~R{kHkH0$|=HlPe-yt1hE4`FvZJ86ru|hD>cvV>z>cODC99NLQ9p4m=o2-y1{I zH~>!=Lck4)kJh>Cw&J01f&` z+kb!Zi(C19`>8UJEG?>4l+y2tp_hJELtpw? z^rgZB@`q3G+3ssS+`iV`vr4vmSMAeYsPlQfhix9qMLDbMz;%5bj=N}~~t z!&ay~x=;~x`T^n~reC)h_zdEYd%u&OYo1b%C-NTKbnkeMcU^VX_cP?0{saLVCWU!J72dn=a9``mu`Sp^C|}{AuZ=Y>hqOH784w* zV62L=^Xl9B9N<;o|L4eUy?9Z6HAo%1yGErt)jr`(Ac5xoVf8d-_nXP(28xS%HoJDUu@a-64KAVGP@&OPHc@NTvk4KC zMjEO(b_>n!$8BzC+prtoi`v+*P|pThimuRn@`8)tcz4?tD;PY{-<_>N3H0CQCt(Q#}dhkZcwOhvq3!#Z|1Drcu-HXTWu>hA?!lUwjxZ8nhgn4tY%vxEmpZX zp`M1LU$IfK5uAF-)ocJ7Y+#t8)!P`RROM!dDO9_qp`J#xXm(X(>A4-yZ245XqZ+!Q z8gQ#-2VXg@T%iwiz*a`~SIn~dV~jQWkOO8k@@jCbKAl*{pqnu?F%yyZFt-g;1Rvt6 ze*jqJUF3}c)lTj^pIob)iIsD(diIsiyYd-VG1n?)S(PHLsug{!PFN%__I~*NQ2VG- z(bGszxcAk@k8yeQJ+HJ?gnHmj?7GXDGFmtC&bl&Qhf;tt`Ack{18$C$cpxnf$pXzZg?s7=x;teFAHjX2^6n$J(5=dtd{*YG%#7QK zT{_JkWPpHBz8A909NIQXc4CH9!muQ%4whM9j#nUdr29308KvnrxQdbvlkMp<3`R@j&UUId^`Rx`$-wn>(P*9ZDc zVQyr3R8em|NM&qo0PMYMcic9zD4NgxE3n(iv6QQBJ^V`g?(B6GNlCP0NxdY+IdijT zSrCctM#LsK04TY~_WkW=;Yol5AN`P%%$S+6BoZhT3WY+UP^dyYig%A@kn-UI&XX@5 zH!czj;4ezM&KB7cncZo0g&Jbr3|qVILu%)LxY3iUJqvY z4WbN_bOi1XdN9lEpU;LbhOc@t%1|1kG{T6DdIONcIU0e8%;zNS0YFhk80NCA8Rr=r z?e0c`583b*^AyhUFe39^{d*4p4yO{u0nqOT7S_FK`C#~N_^uZt7EzpW`ART2zzjeT zW5y}I%{hv}9a;?TVUi=jIH3r{h~a69V!#PtD9R~H7UmP=um=E)C}9Fjl;n&fI<$}< za4bsa48;JaAfqJCBhfe@DS%N#@{|KI0hlvDQG($uPB35W^Z=N^JmCXQ5=3DdApp}D zAjps?o-;J;&4?hHq0bcaS$^x%MU!loQ-pTs5U2Koz^;cQK>}0Vr7L6%akk4ijP95$ zyo={k`O84Q92^|%y*qgJe3+%v-W^&z5E{#Ilz<0@484IQkmQsBhy;7|1_gP00w)e} zim1Z`-`hdWY0{y4JylJ%%t%fn#ZgW5h-tNsG)47@P(+xlF6q#-?DWm>)$mpCkDj8B z`Z)4GA<^BVw9z8}_ntkg$p5`pd!Ob1r+79kr5#axFnrdF@f0yW0&E5kUc4L~M6dQ= zzIgHcU=r=^-+qg}{pR+?t5;F{&F%i)w=d#76n}H@@>Tro`R%u_ZeOAo-|WNv{Z}t< zC%50A=W%q~o1zp^$Wc53{e!)OXM??i!T$5>gZ$ zdAq4c&VMPY*`q0djq`th@8!X(z4H8j_Waf7`Tr@NCr`ltW=N?kKPKcBCLn_p&JjnH z^`1O2FONxdhbX{vI7Our<3y+|J0K+-0X~Bq@R?MLk_3=@L@AENdsL~s18^E8d5qI3 zaOKbrh)6oY)0`@WEN80zRH332iziROQBEmJIe_;NC-640C2EizsW+EsDm1~xj{0+) zC&?9xDB?`&Uqb7HQ*@L-Cc4)XE&Xo^M1voCP=W-a`eRL9x5?iirEu~05*PzOD5Df{ zDV7<40z)7xR3W=~8)#SVy9uFSEW|V8f@*I_lF!i=+ZLTvFob&Tb#4Uu{T={Mo`93# zbf|tS_h6)63&niCFcp7B3-$RN&XFu&K)W@;Z-4IrkKnSwp39U+aw+mz&K;Ax{1)k* z2l#=|2muc16mjr#ev4>|IAUf|0$Vu~y!I1H<{*NZQp7Q008a$>0*1Jxh67U~RJ10> z;ll9r6{i9mCjvW;VUjEghF44IP!8O1k|&Ay4RAEi637wQlGDRz$CAA%k`qa`A<=Lf zE8$@P25=FdI^!XlDZ?r?r2xE!wwA-l88y1kOhi?DkX=? ztv&+pKUN?g7CX=ay!*0i8%~{aLu#*bOa#5bF_POZmqBy^5X%x0q+4ZVH+>0-VB$bV z?>L3W5+ys655*6$gOeW(o&tY`J9xl+=8m{%&jBQ-g=pg>l|n7XaGDavaRlZhMnJQR z0yak}7xjxmXCy{?PHH6mZ$l)(#&zJg1eG&NZjqMZx1tPFb%cNvjSGs4-%SC{ZZS%? z&1~1rjKBmY3^gHSfF0?doD}RUkSR8Efxhe3Gz`&kA&FRmP}bBYq*DeC#XqaGCTg3e za5}*$<_lkJN#j6OXz87=wjIc|LJKGHm7+$$EICaZ#IIR>>n!Z~~ztKc|fD5w=fN(e*4z=E3)CSB7a_tC# z%n;uRC=sgdo@`k*c0Oz2BiZihVe$YM?5XIjB`m-UJQbpu@uxcg zB@78l$l|AybHc|IF_iMB3Y^C=cUGVcG1-kt#CCIr=wO=T812dy*zS{zqJh8~r_+IY zXSllP;Rv{G)exhs!IY_@R2KyuTu5`ATq2pFkXB`+ZLFjkXkEiJG0zznVrCB0T*8Pb z61zadTyk~GV1$O<$igAJW4l(%9AqRO*m=JzuverRWE9^+js}Lyb`^XyoN5u9t)d8J z6&AyWGL zF3B{DLa*^%gCo6#k&?CrnMBc{_%Kwg0InV|k7lCZYT*Hw-ya?UAEJgKf2e9BNxxdy zFiFV6IZ088EQjK~*_uec7i&7nx!t)4Wvm5*8sIG`Q9}3_GWI}d3@!=b0tX5*{b~rV zg<@gfV+NpAssFNCl3&>hNJ8dO5g%w)=!XkO5z0hz-bOAR)2=!}Bab1DM8x-yf_VB0mPF zhWt`e^_VK(z>-#Ht7Ab0Rv;JbIS^llYI>kp?bO)_JXP2~1%!g9zdy*us~e51XfX3i zNroo_MJ+>a+X2!32q+5GAg@LG&uB56-~`F-kjv5HrOQF$ovtI9OR%ySFZ1ocf4v4S z9?eazHkFpf;r!zIWCTv9DWPJOoRmlJJ2fJH@xwsN&}-MI`!MHZU~RDyep=v9QY7S# z*imPc+~XLOx`8Gdn(MFK|B&on$zFmz#@<#!B z1TL=*Uc79WAUtuJzrKFGMzfqJBe1_WS5oEr^;K#9N@j=>j8Z|l0Ymg2QMn(=Q(a{F zl~|sEV!p6zuxcPEYSgEpIySwgFl8B`+*^<%y2yANl0aE!L=PiGIi83QQade%z;C12 zTh<|!GqJi70kgnIaIesYB1e^!)2ONG0#bXct55PW1|0`?$)(hwDW!c$j#u=k8DYH4 za^aC0f=l#|98<&^7u7(k?IacL{Locgt2!=jp62I(8p*$`tf_DNXS7(Oc~^**QE?!T z#P>F2;Ieoe9R?@?PPNHXZpN@S?cB7n$9F<8xDo64jiZz)twDX;(IyjRW5Z1R?mO0LWeCxrXcHeg2(}gkH!9d9N}pJ)$u>7E)Y=DiNuj2Y{40nw ziRn@TP1IOloY{7l5oYD4HzCRtBHaa<#9?VMR?85M5Zjpi@_I;)$UKA65PU{rxm6;9 zzx6w5#MuG23)@VFC?+wEhTsiMaItafn-BdR(5L7gGfdL{P_#AxPtC`taze#=a|D!C zh9WL{Owt|GiasBjk(}xiFTn8}fjq^sqefQ;TWB~Pf*12`(~xOdHDvw*X+FP2wA|iM zTZ&3VXr$7msazqI1uL7L-$#+$h`7FcIF)_!2)efe<_M9($FQPK7DY)WAqtgb#GTfG;cMTuGo znZ8E%C;?Z9GYK&vQ;^74#^|HYLMVw4V*#Q`6Xeq!@D!&LB7QzVnu?!@QbNTq8BB2` zewjcH6G79SX?FzrqMD1+9KIV<5;5=^&#^{IvnrVYl8H^Ll;aD=(H!s@MKET{b0L!Z zSQO+KiLP9vN5)=#jp!VwYVQBS z5P)Dz(G@2dm=SU(ro5_HjKy4nV2%w;yfw^C(&7vZ@B+BNgwN1I9{}1@GQp~*n4D|+z%8Wu&s+GP)%RdIdX9;YoV`2GZgb=R}?u zgcz7<8>$?-g3fAuTmrgqM?HNcqE^ZuE-p0r)chZT{w<_^djf81f#3dKgXqzjRTof| zmX6|pOh-fqSh^)1NHoxsbJZsU;PpKi-VaFQp2A4(_Pp3o|0I5@XrSVGX> z9N!2f0g4(UAcO+=C5y!}%s7P{O&1kW8aU#MNE)Gxv)ubLO1G>`-z9XU)pQm@3iNV~y)Q8aiqU-c>(=^LSJSbWp$kr9*dI4ldU<@ft668A1 zh;7(mf+0htL*$IadXJ{QE`__;PT~l$L5jHO2TrHEFpdW(|gAIiI zmA?*jbGxDw4sxZrRa(rf&yw}UG76n9A?0c;>Ei=1zDlLi8KKHcfMh837dusAED8*b zjYs{E_6f1ieU}lT3Al6KYBFI!a*s7ey5%+?J-_y-un>cTXRp3BHWhI2?3+E?xs1f@ zsSu*l`XZz@NAEf@X7hQyvFFHF=pEmE!Vn+u85)$o3?_sQps4Q8ErXLrsdR1@x1nDT zXu^J^B+ukwy#ex+Re%6pPS2halu@sGGN&ty!2aIeewBS3ME^K4d&)tX>pGD<)Sm$1 zYk|@{J!HQyM2i8iWkbVY%XbETPEvUYzXW_;rArgiMPN+vJxPvTVW#z-dI0T+X5yOe6JEh;cC>LTxIvYNpiw1aoe-h8mF_ z!18D&8b8A+7X2TBQ{~?i6Yv02uOCjeJXL*FTZ9P_LxWT4sh8kXlz{Q?Ig_8~l0T5( z8Aum9vh&U^G0Lgf+fpbAGZ9;hr?#ch)1jx|>DNOwg2j3$9Z@WK^;b_l2?>Y-o@I{` zMEO=)oDA$*puGZV?Z*BN&a=e$$10qx-xi3nd<0(XnX^^^#7&IHnUi~1Wdnm3DFEwSvL)|vHWWVFdWYj$+>}Z zt^QmA&;;Tnr|5b{5u1@D20y45(txDibO*+A=`>dWyHYP&fc3l=A-NqGi4l0YClxY> zo+I!~yz_}O0xx<1lu;8~FaXNE7iC-c-7@2!jp1#jAjkV(>#Hrt^If5~a(!1o9r(U0 zsE(Z96CN$mCaSATF9adj z$dyCmh9>k-lpAnsm%vLgpe|MxCau8L2PG~N%w%8?7{^!@0r$GDIiQe62WwW=kVDpS z_34b{DPN~$4Zt>U<&VB6T4}3mEm6unLE^+YCsZA_hY3E!(s9Cq z(IU%d}w=bDSUfnz>r%9f@7Dw+}RUHEdZ;2OY2VE^FRb8}+qpzBkI z;TT1*o-X=(SJD`8e|n-=M168(ByPR@S)K^p?ZD(7(R+*@cC`^$*?IMC%v~q$(XO_- z)!!e@NL;@Es*cGL^|pfK-COBZ!53$M#v8V{ zWOyfU9Qosi4$uJpQ%d;0F-_gMH1pkP0TJS5(ca*Ur0*j+I#Kxg3|GS&5*7 zMTw0ZhoT=TjL_KI{h6QA>yyMFMJSdNYbwgB&=%I$XsKn%i3n$Z9oUoDfjpeueIkAg zW-yHtL z?`_|r386?3dJXOqBEn!b$S6Yd%rao5FJ)gkb(r4Xcf zD(W*N5a7<;`WIsGvUS{Fk~QJhC8UIme3-P3wZr1Lh+vIHYmpjE;^6Rg*z z-Jt2UAj$|_A~8GlOO2p?>-tJwQ=vLW%AG2wsO&4L{nh-CP5PzUM>&D2uGD+EQ?Nk* z*a12A~TVcv9ZoUfcLjTBNVvbS#_)Yd@8E9mhbTKqAH9o)~goe|h?xU?Y z0_P+}#T8@wx)gxNG?=+AZ`xP}GBKM}u%Uqz_3AcXVDlr%GSK(g=wN~=dVoo?`-CFKDUSF+gP9QO zb$Xz?Q?{Vg_0F-W?C%ZL|Mqqdo`;C%)hkDRvU2(zM>K`W>DarGA>V=1aYs^ho1CVt z0nThVD5w2a9QDGcz0tq=>g@3J{O!@j`Ss!H`N`$m^TV@~ufDQeYia?m*F!gG8buS? zpH)X*u4)6@Awl+m8B-bYOk$BvrMIdMr=VDHfU|Pny?)t+wT=`NN?E241gzJ#cAnl! z37yLWIJsG{ksojLk;sh_(%TLW8elE?VerVLI7EV_)049NurUlv#~q=z7-9^Q)EfG( z)Zf14ue$i#yAXY`zW2o*s;@lMPsdt(oKBoqGT<+h#+G{AE4F;=A-3ThCHl|GRs zWZ}tJIrx9Jw^xI_h9y|Q(_3w*;HaXq7Tf2{DWt9tRU!-nsa`MZ*<0x71AQj0%sNGT zzQXK$u*&Y~M4KaWbt^KAne?ue8onxs<{4icV>)bCgxyBH@XOVvbR=e=!b+Pd5TglB zQM}{DKvq_u|8!sdm#v}AEd4=0RH@(J0S_}A&CI=L2I55u=QvWgyT!QUbZVjHsm1_o zIX98FfsD@}8%pye*#Rl3G$yqUfSF-AX1@-BrGWd;&J@usEbr|VJG2u$N`8+ zacogD&~a%Bb zvVf#JEjgsD#E2` z$NmuM@`KD7)>0_sZqRLbl zls)y4Zl&qIKi0i8eFba7H`AJDU;S;hc6ng=#N&+)O;sSb{{nJpY@@>0m_DB@iI+w=m9jEX#ol?;k*E!n6uUB7auA|Th9K69S8*E*G zj*-@$_Bh_mS>dW|-;3^7ipAFB%Kf6g${mh&&@F#eB`8VINB~YbO5>$rpS;T`^0fJK z1Je0Vv=aIZblfYk3p!21B}#6B}!10AbPe(SJC87N(^RY*G(C3D1QC}*a+4ecep`OJ}~ ze>*})aW_@Ps?H(`rSr0o^!-2qH4ppm--F>Bm2NT|$>!rneL~=%X1pHGNQ#YNrxZ)C zNCB+U`R*3256tY?y-mpN?i|W9qhk`~LMhcw#~B{Z<0mMMrLDs0w{Ei>9@rtaE>Sq` zC?AWl{Q@qHGAA$m2}+6e*brRX%`Ltc8r@)GhEP!104{|q;JND*sBFUyWic~;b8c&C z;Yc=D0E+?*jmpam_b~BX66{OJb@Qg*Y$nsy+#*F16uT&xY9sJ$kF__gAedX9Zu|Nm zMDG<82GW2gYe-+SH1^x}fOSNmxW!c#N6uM~kxC}gq;V@{#Nie%>smza5mi2q#i#|h z;TxI(MJ2J5^U~FndT6%@Edw({a|Eu`51lc`od!PPMJd&%cF;Uw`Z%o!5c2w}6dO^} z*S3d%nc>Vj^meCfh@dMGnI}wP88Ua+ZaEvc2)esDZ4vTb0evgakCk1vhZL|o4IV|3 zW99Lr(b^p0QG8aKo7<98RjUsbscz()^X@WFO2I9yB=*YGN@K57St7$Ot#3)22{lo_ zZ%S+PjdlmWQ8A=twCS4GB~5O&mlxwcn2;#1F5eP&yUrLFZ>vmS>fE9h#CDCmub5J6 zu&T(rj$+P7xTB<7TK)tE!X10rwmkX7MX-4Qo`3;>2@-nB$@S4On8_GgAVDzJ39CdI z|BTRi4FJpMb11XsR_ph@k}+Zt#hDHnn~@m2e}D7-{msXZ;7dimp?>-Cqj)Kuje!h^ zES)Q!+U@6&m1j@6Ew_5rWv|klsc!@Fn=dvolRZl3@OPAK=y$A45kZ7OHOnM zd8rU;c&ukawj(>n8KQHTqLe2KkPwC#n5$|q1zYEX{q5ZY6I6Q#U=C!YQNW2Zg-R*_ z%o$21#R+Z#nVY)YG(S|?d=&{VH3iH0eEqLwljpjlP|LDaMhk`5p69nMgUp^TO;{@N8_%DSUyVg&kM?>^fDU#tJh z%ULb1Gb~tPA!Einaf)@Ylu4cdv0Shjiox&XmZ`An`U-$W!Udwjs&u21?*30<9K1R1 zw7dg2oKDr68JDtxgg`EVQJoDz-K_WR2xfw6gF&YgvsI!rIK2x*YtRiBA(@(v_0*2Q z@IP`RZglNI+nL|vp87rVx!rC+9sBNGi7(%TcZG#}uTaBY<66ACpDACD?})j3 zcfNdQeoe%ex+)1xweN=_U zWPC-8i-?7(wQcRqX7+WrBu{P1%`O)_cK{5M8f+Dw)G0KDpB`Fx1EiIv7cq9ay zx6ux0z^w$U^NsY@Rp|$s(*E0KRsYg;dmWAb+_#}WxIEC{X5gW}d0^P*!lbj)W6-BT8Mgz=A&g=PHIl!F60Sc z)y5!IYN5;?V@7jnhXLQ`@f7iD5}s~cK=ahSo8)pue5>v*#J8n83-N8uw1aiH)l9$Y z&4l=NILGOs-ChdKZJy6{BCOpE(Fmnn$RaXPYnn9I=`$IM<`AcLPh}52$Kz0m z!z^?Eg=pWVxz>9Oxcdw}Tw{4*!)3Eg6I45a2!|TV7y}@Rm9{Ba}^8EDt zN44$w-uhMxt)cIt{hf#P4(L}CBTMb5FFG%Q^;dCs?a0bPlb0q62TC}dwDlyp$1-Il z6gvnUgA6kEK;*?Sw<;xskM*a1vFs0f8)px}&tfMcc>C+G&25QW1Tx5_AIrlGC&)>$ zi5a*>q6;d~8H&NzU)yP6I6cO2ni9rwbVlOh{PN?+-n9iZg8~vt3qUvpMMarhR)$bi zv5%PIAXP&rLsb?g>Bp%u%~_aY@A5z~=O~p7G!hJAQ_M+hl|lyk;w?#sJWG^s*^r_% zMzjyMVjOYMmv8%ZT{A8Bb;_VV_;MS304YvmLA~dq&j6_Ga~o_{CcbNGv-hJ;v1mdh zOC{xYp|gVGbSgLievDfVg&#fKY;6>PQdu$_`kql0B#|h^?Ii% zAT&l)*`1Ywi~Jm*Hd3}a)MPe=sx)32_EEBCmt@>r^4ZnpWxn=ZlybU|&KW~CYbZza zbSMy$Q!rtQPU@gg9X6}26N&M6Cy9*S35MX~$6?*@4B34&biL*j_+uh9bkX%| zyK|N?-wGKm$RV#jGXT99DKsy4#~&lZL!w;Q4(PB7U@)Lavcq>z&(S@iPr*Q4_VFR9 z4E^H0s;&hgp@CIj_pbV(kdI(6KQFWRUT{{g1 z1pLlOnn6DMuK#`*Lk@?cYXh+o4a_R_u@64TG}$kogF(DqtQ{Kdlk217qwCjiPtK3W z7pLdfSKsv?oo`0#&WV0U=`t{)elP$mK_~+_)u9cJ-YAG?GT|zifqR58*KvX+C=bV|Vn&xb~kktW!z(!U_(bAqd z+Fe+U|EP}&grZ70IKMbPd3!o8&Bjz-cJDTB{v5*`&Dn2ze;+aqdCrC~j;Rp$@}2(U zV}HAX!uaCyx`f0k&5Lb-njfM)6U*vj->BfMGmmK$qZv`G1Ae)DJu+c%zSLwJeQA;3 z?K^9pHz3{)q-jueVs2${;qXo@858sX<~Yr{lSs{r6?Qt-wm55n8S3L90De{8^)s0} zhUe-WaRi=vg7?1b1bygCyQdzDU7cLMIXwz+S?8v^3;aP*?)`iDe;LFIYzZy$9WY$! zMt(9^7Qo)NT7shJuH%Z_W z+zbXeLlg*gW%Q-cL*9Bi)Qy{fM2xyw7lz;$hP*wbT%1klE2=h8Mgbam)3w^npH@{1 zjg3ctHMT=(JwewLrc4iOQ|X+c!<>`r*H_MviNCsyScJsP!wCX*gCsXbqD#9I{Ep`o zv0c^Ht|&ar&>Rc~cWBYM+8tVmTJ_^!+JCLl2X~_<5fa}lB902{l2DYf?ut?_7rk2< z;Lm8`z-;Y%YG>TvoQ@{UP5~KyI@7U7rLwATA2`abJXlgUAK(z2Oox@J;_nR1K~!f= zc5iJ7)pZi6VXvBI9p+G3-Te|B83wL3y3h{n2kUXwkKiy8YHa7Rc85J=m3n|Q#p#p{ zsmkMj4X4Fws&>JKgv->di6T;gB{v|_Kngihb@d)Z?p^eyhS*q0#pXqtxdx^Lv$sa7 z8=K;rfH^2wLE7|JTCldkR!Vs2yLXFaTehY*V5So%Jn}l?SpR-Ti+;UTxUV|W_j=o( zV3dfD)fJ&1YTdT{9e|m1NvVDcqdIWdXiy#*x8w<>g!&sy%`19@B_n7fs7d!Ql+o*~ zG1S2A2hj7Zpo1E=ls698FwdqG#%O40!bj7!VgHU#>HPQY z3?&(&Y{;`@V{NpY|Gs?wY_D|w`~1b;!RPbePw~8ezxy?~$McblNFr8Pd8RoRWQk^I z1is!?i{0+my-UP%n(AaQR;rh7H3^V%J*TlLo^!Lf`l22SV7#ZgBYQ%kM7 zAlNjHP9(9m9%gP)x1V->@W-~L!2`3RrYI-U|xa%T)SJ&}W6;Z0P^D~7r zD)jumRM!g-a=#QP(huqdo%&{1wly^2r3h1N}ijBvqRjczx@Gt@83!F{5;B zvX!_rSKL<66Da>@Cl-pnSy4x5`PEXRUpI;T;q%zGLeg#EkV)dW6uW3+t-L^{Scjrm za4byfgtco*XqpHCTR`IkXsz5fjCRhr+!JKd4m{H~2^A%czmX=Rb!^jVYj0(`D~i!Q ziq#peKGYSZhmG_#`)z3sX%e;}O0^Ymfcqm9{FC4P%b8tE7dhW7bT8;C5Xh^NcS-r8Js9qeaDR zw%K{T996o`@s>_>pYLseHZ=DKzd!JSY-=+sN4taw?BLAZeskMQ-dbzefd_A=rFCm{ zhuegm7Vi#lmRZdm4BH}RbV9EU$ObeG=Zg9I+|oLEO`IcpW3v9LoxEUIw|KZ0wQ3c* z@by7$5HKe!UAkNYP@mPblcQKPih~{fOU096Y2dZAJ|goBCkVhK0p{!m;FJ@w*5GuS zAfP?7)HU`<6r4bu)UDa&V;j4R(_mQjw8s5nP9f~Ot)^3rf^cDqwCpZQD|4I8!(SdWD#g;Xdft~#SlfF58{maP}cysvr^!V`l^x}N< zKdIcMnMxldKeR8(;EnF6NdjU*f(*QXLo(&8y`Zg=-|0m5m0@rXUAypOJHyl{nDyb5 zyiG|9_|idPT>u<4-U9tmTTmq_tq(UrKGEAULNeQ|zHIRy{~_DbH$*gGfH~M23>e~V zhI?z@ti&(pHwIOrdg%j!bZ5I3{(!{^`>aKd8R4jyEfmrsohKu z4f?W!A^ex(m8!(9;f&gVSKc@WQoy-GTn3^DyhbPeF+$aZczUb?c*(nMjYAXMQ~my+ zuK0U|Dy@p4J*m488W>WYAmlF3K>vQf5Bj!n)y;0}akf9(ZZ`_V?4eSO-Z`)PG32l> z_rn9d*F$sZt@rYIjG~Y}I7R8$?gv4iGT5luxxfF>=dz#bDV_gY!{l%Q=bQ2XXg>en z+kd`aIsbq4>ec7-|4;FRg-FHBJe0;Hm|=aVdj#(Hdv`dEM>^u#8O(Zf#G#m^BOA8m z{rg9>yUQ)N6S_9+BK!gTBPSfG(l$&;z|~2IT{S5w`(RkTk6JNdsk%A@u3M!2x+)0X zSM>lo9#SB1JGL+!SqHTWYHk!ib*0ve(Xu|OZUZg&I@lUEv8PAF#XK2-4}(om&^`KS zM9D$ukDiBr)KixKIuhCjrGI<;kC!3;ul>*R|5H3|reF7P-xdD>ub&8J@D?YSV=)Ug zBNcVDC$e5NC`tdD+_o+mn>L_+UNHWm3kJ)OjCvT6G|DMOX|youH-8}X7RNm|1h8`p zpglOTH{eCQ-~T4J%#WVi1*#WDSVH`r++J(>s=_v!uE_9?-WL^~vzQU)S(yv>4}f!! zC7x>hiHOWIlA@H4+=#eNr8W^!6EoOrcymnDwfUMLA7zSo6GA=i_$>{Sy>7JjqdVqq+*1#L7kyM7BX>mGg}4;)OVY5$@6_Y*J-@yVKVhW9 zMfwB8NlsBcU1WwfFP*k~qq3-0%DJs5Lc~O`hXnc>R9~z|ih8RM#5ai5r|@)O&%YJ)itOw*BZzrQQ>G!^ZI!4+1nadzIW@IeC+%NWu?fyG@hJFbBu_aDF@R!k zL)?KAuh)NMVAe6@vr%{`f(S${vr4)_h1X}$FsD|VLEYy|MTKk@CshFLGPMq7i)3A9 z3#i-{r>d&{P67b z?eWR?zx)`OuaX!e6-a=lkS=r*OVHPG8{IWkO$`-#t(jl8>t{`Yo4Mb8I6ke%tpBXv z2;l9-`P-krxoQBgK&&3b+27t?U0=ODKRi2Wq)zMZyQ#zP)iqbS*)I0lqwm5|9m3TG zcl@B63*CziU4O5K^b>+{f*8{ww9Tbw_pD30Yj~~pXS!Cu$iXpJ?eWFg;putfs1@BAe#K-^Fx#sT1*&6I!nq?;zr8v?9AEu(asBqE)2r)? z%fG#SeR_6!-H2-YmOYdwr-kXd2kdC3xViV!Fv~U)$)aVdo0~?Df`%XeqKZiaJ?mmW zG!ymp>B;%EqV3@?*FQCMst5*K3$1jcY4a3ni6IfDSJ`#724Wkj{-m7?Eyk^%)`@S_ zNF?t{Umb~l(7FAqk8)Z687(f+BwWHVQa1(12;iw6nZ~`QvUgphcIoP-zqVy1YTcuC zweu7Z|KyvlAfZ-V5afJn!J%;y2I^7-a+)N4+ z?gR7>&HWLZuM+EEp6a@?XarAWEMb*}+(s(#eDu8~rgTFosAXxG{#B$ZmIf`IfRJr7HXhHDtZKj=KVbpDIpaS8_sW_*K3z%Bkid;2e6l+J%& z>_2&k&Hohf2SV>MY4+Qc z2xyuAFP|Okm*@Yh7tcP=|4;Fh)CE2M%Ixdv-O6p_-2Ghk2dRW3^c+Hb$Q8Gcpd(19 z0EeG_I{xZD9r8F!pN`8O%^{CwuU8!=XZuk-==Ddb^Ed_jUVy7HmX|QGgQUdk^&&IM z`v9D(5YhUt6Y~d>zvy(I;4n$Z1Bg>5w`)nRQ^AQEGLC1Vjj9(T@Zy=HpqdatBk;@d zxNFhtqp{aI$+^txX@bq0EP+I3+OrAMO)ltK%tGg%V>cM7qolXjkwKko4Nm;_O6+Bx z_1J9xdFw_zz;9m3$Kty>)SSIfv)mUdpyI)e$g_Ir%Lz9fN8O(eIIZyGAIEu`tnRg> z(!wWjKG9jaih2{zDAkc?Da3uW&qG!}Sz%1g_Uy|$ zwAcY(sszf;!O?QKSWXe(9JNStxCY*M*x%-3R)fx%#I+c$#_KE6r3sP8AWeXgyjRU) zd5$>65i1+Ojp)lLnIk?!IRh-BFw+@4bggD7c<}7iw^a$-Wns{&%44kz2K+Kh!)M#V zs!wVEpT!%#`|(AG`+qN=mF<7eUhaR6|NBXv@;Y3kq+asEM^>}3SB8TziHmI3Dw%b7 z%iqzbPnJt`h0n5dw zUCYYypTu*LVovC%JO6q1@aG=X6@ zMuZ|Fg~qPEF+R2cHn;{D-^~VWi)>P%7#CvCUW&5V1Y>*q-(YR2-H2yooWU* zx6RF~ZR<6jBa%CYH}7>DA~i5p!e)kCUp)19d;5N^6&mIVQ(-h58@741CMPzwR>zdz ztkoNeq~Mbw5p6Z+H#2@iFJEXGZqqb zZHN8D8*@t^kgU%WV|#DCiV?Em*kp7)+D5D2;rk@Rhn6$P}jWVUo?@c|HgGdrhGJ zA_vnI`7f^m>r4@!X#cnWqI~}Qa_{Bm{of~f-gn9BQ7^gO(mj}SBJaTY?`8OAZ(^2O zX{rb6e8bCED62_JKCca}JFe0|B%8xB40)xc%u!3Ki%lI%H7$7c!xV^L_h}c$B?qk1 z&CQM)Tp97d(h~S@{gl^#a|JfLk2bamZ1w*-sGR>lfAx9&|0GYq{@X3vMtgEMwdK?1 z-q7XgvQqIm81UzP<5H$eC}Z`Wk+`@=b%|j7E5#h0!F17c<60Sm6)NIH4wT zUL$8S{LgZvU{&=ffsEPv{>?B-HC%Y_|DfC>W%Yhu~2HMhFOsBcE!;<}{I?ql?)2K;*c>XwVjRElOOx?}l#*US6k ztu-p7C-`z`@-Pg)hYXD&pMicU<5_=OvNfB*gBLGZK3@srniPB?q-D{8j;_@iXSWtx z7H>Db!TTj+?bnA^m=VSg6AYOfT+Vs9o{V#$FX`DAz!gp=IK_P7hy?v+JuEHUjwpH| zlPwB%+{C16#7kFEx36Mm(c+7&By%*FF+~jV+PlzRA_Y06Io=co4ya|YNJ)%3qaX^` z;ot&N2nuvzsq0A_ONMiYRP%|)N#)6!{9Hgu^Xz# zi+*|=u+=T)j-_)b|FmtbE_F_cq9qhIv|}nk-Q2!oC91eEJ7o=8H)GIaWD5$Wwy4Vz zRLu}n%?|V_G6T60iJj&f69d&G1uF4v=Y&9iU^1XC$+qg_Q5#N;A%~@*a|1sINgR}; z-iuKFpZ6+fhGR98NiTSVMa`+0Ar+#kT&XdBm9D#1rj7TjrTTdPsS|U&Uo9br#d9nO ztmEW)M3S;8bH0WMBnlnL3!L>ZBJX<%iklg#gRER$GIo=L74!5m8K535`_mG6^@=0A z_N-5TM8>C3S4uf042aF+x(ad|p!26qY1M(kvi^oqTpFh`VJlg$x@5fi)Y-0_EK}o) zQe$E|35r}2>sqf#ueE{HTJ3qn zYI2CR=MSsR9pi@$1|3i}Mqi>a*`t<1V`t+ilp{#K{ zXS5hjOfs!NF#+&Q!V7kVCoN${wQABt35Mrc zg6fH33WUIiN3kcX z!@3LiGS8u?Ti(TuIs|{-X~NHZvm4J(j&64sVQ4PAl6I1>-nn*i2a%{sT5?3@8I(cL zg>v2|X)oR$U7U>%kHixF_Uz)gUO{bWqhST@v^qHOE)f@Nb2W2hBjT4Q*Fw{1&@$Ru zTdNCm_-;%|REZ^RaQ^Y)?C}4LFE5U2_`(f8QUj_Pktr`(3HKYxXJ)0zAsbq34a>@F zuzIcx?!IZ-2$aEIT_0Z8^OMOixn&i=6g~7o-&`Q*7xVX&ou-V#B-!?kGcZh!6k^in zv}p{#^vi?McOb#6lK<{~5mOxPfG@Eqm!}*jCGvJ?;X44cOpI9hgJ;AP`ow5=SN=M5 z^Yf0rip%!RFL3~zKx4l^c!Z0rl-Adpiz`|6x~%@C!LJ?m-w94Zf2Uue%W^ZYdoJWp zo(DN_M%I*qF;pgJVwXa$UthJ0!Ry-9rkXG}XxCakJ!E4#g=H}*o5V_X&SDpHz zwaU;)6uM7)iNK0;zq$Qo=e?}B^sH9|+{o0Ipw^o%4HVhT+%LmwCC#6xKg&-2c1w1f z0%Z;8vhR)O1@(=YJF-rH+pX7L>sR$QXxCs{WZCY6{;p8x?ET!n?>V)x`^1gb+V+uA zdB@WGH;@K*SgW4nd2lKbbOTf*h9?JOcS$CGpNT(aDrREKj{}o8b9UYilsQ zk6W1QOZflk*uK<T0{x@iI6*1)(P~t^%%U= z#0tzU9d4?pNZZczpObrZhUT}3UZnOS$#roNuC8Z3Gf{NKNmgd|(7b4v8O?Jeqlj^m z`SYT7q}qn>aqlqvnQtrr->A72_BJsRkkcG(*A*(9b1IuD*N1)Z`vV`y8V$HMI_s3` ziAC!oO%@}G-V!@gLVW{9y-BCpf>Ai6b+d=Gx3`3`q>j{{rDmX*r-9&J@#SdPZvWW~ zRcgE1y_eROwOS9o&=ZbfL63)tFww~U3dT~bPtwWmY6!O;U2Szez^n#;ubyIVH_v-j zVIXJn@>5@*`D}3RceL|YNfbO!sS>Ds;?qJNQG8Y6NQ?NUNaGpI-Z-ny#*L{S@O3Pz zW!pTCQ3N-4t=7U@=|ZiNO4X~tkF?&luC+P}jjwfE2jYN}uy$u{@-fzDEoUS~BXIEI zWj!_ibywexD{mGGk?M~|BwkhHLR1lUacShiKYYDzU#pjW%8@wAJ6vos`1|s_CLpe{}fMCUa!`K92*X&{W<8n6`++E)#d^yOtKj) zrGD1&GSMJUDT480fYLZ4Dt@EmMjY(!pDW{)S>9D*NPRg-M)ioy?;~(dQY5t0{5HXC zc24-E==5P6Q^aJXVQtrRobt+cKut^?Ux`q;(Yd%sl;YynWW#lj8mD^P!h}rSvj5jKPX4w5U#JgYBwM>p62a zx7sXJz1}$6R%b_2Tw0aet7^M7d%}uk+3q&h2td`k@$=_aqX;V`Q|C$O&%&+Rj-(oN zZD+~_Wc(BN^wbn+CfG{t6pg$O2X(7kSwh&Qd6M*kcK8qriEU$*fr5M7mDxvbTI-sq zVIb$q;-8Csf}Qa{ugy9g+xSFmQ@?yrC=psxt!osS4%DTT&kfi;{_T&BO8ft6X1NWt z(U$*x?^PxL`^#sa^S^(R=lzly3~Q_bqDbp;k##!#OP&{X+vxr|^6;vi?nMUwk)xg& z5=;JJhUT^IyuUy2Yc)oK2DdMtqcjR7D*v~YnEzUjl>fsSO6GW)5{e$9jTZU8_hSD= zN&X)^+y8w2|4E)FU<|p~+B3ijP&^>r@W5@3lNhH{kiqB_30;>ht{n z6wiPD$6zo3Fv|uy9vF{eFc|z-ulGd#u4jJ?ZWrKtb;GRJ6I=r@0}#ZRaf)wqj$&|! z76YloNT){xV#M$?MX``9>i9lcm`{*H03%A60HW>SLtx-O;8>K+8Hxc;K}JcO%b3l8 zqyVbCj(|)6=1j;N3~zCQ`C&Yie%(qAr&zTk!A?4X9!TlG89Q6$Soi+ zSMJKHOME79njk7*3Ap4TRgkz3AR_Y&rWi3PK}9D7;(UhYASQ@OXL3Bxk_CY2LS~Up zu#&KZ3Pp`jhD6K5Uhl~haQ*uKJ-+PqZf=+;MHvAwj=_8}kiQ#}L^DV^ z8|tftLMJuX3{^#}LNlv+QvEg{)OGTkn;Y5gY0B*w_Ii?{5;V9agfmWICivhtl8^kC}$U<~kG7I?aXX`9gfc6}ywhaSS8U1 zS%Fubm;iwbI8yL&YOrN$NXHb(YZeT1#Cp8}DEbTbhx_0DKfQqh@N9T6+!KF|--sD? zkHszyQL~&IuFS=*Bw0uvPbU;IPV}N_TLFw!Pj5AmexkpAX;|si+}hY`Q!jfZUaX z54{gyQ1^g_Z_PC%+#BW8t`aU?qN!L}7dNVP-N9oL-3g8qB>>e$!ua0w`!}Epcbq4Q zGS{%13S0|OU-6O#762K5DS(v1g@F6p-%D_{PruA>eFHpvubfX(%#H0$9-yxBY_V-0 zUpbyyGw(Q_%Ma&Lj~RRCO#>G!&jc%RjQd86g;-LwVeZC9{s%%Mq|aI0S$MBXgDoXI z_OmA->%}8#Qh|ZEjNM4C%%ze#ND5<3tQD$1o9FK6Ba>v;_iVod#PE zSO|ECr4CS8TDI%3F_6j_x!8y@-7)FNH$iM%HzA)k+I5Jl1yKA*5-o>O49Kn6bFyx2 z2eEnou?`!@%6ManyOzg|qg02Dn_}U{Eq<(5-@y7DtAq?|JVndHghVj8QP{|HsbksM z(wsV!!jMdWEMn=viBTyky3cahNEutAO*p2i5aK8DS5OoHa}p!4CB`bFZp#usPBYIVq--z@$*!3ysR^yvxw0&k}^P zz9vx!8%U?@#*EaIJq{`c8=NXnkN)3_^$V$;b2n|I1oBbWvPx^^rA@zYQgd3?qsM&e zT2ox0GF4Jna|-rZSs7Y&s0~s0CYH+85R;n{g)PDvVVILTls$ygZfvv`!tQ?hCV()9 z(>mf-5$16EsQ3zmpABCOUkze(i(xw0-yhKZ=Ql3GF`gpE>v8rFR)vjVcz_GQX7J#} z%Mpab;cy7XTH_#c*CfqAdYsLCP2D@H?FA%=I ze*H*@ItcIY&6{{Qd?(zqUbsthL>C#?&hi6J1`N@AMCC?2PxZ7k7X9njSAI;bZV0#N z5|v18)s?P580MVJp^z6zvH&{wz2MJPa9a=I`n7JUNmoH!%)GYoC?VW3=^8@p-Bc*7 zwY3>xyu5&fxnKw`Ra`aJaoOukVK)Dnp{4rv!6b3OMvj1daEf4{5MFqZA zthJ3t3E?g*Q7_c~d}6JVUUd0MSB`7hW$5dkcCi-9M|!g+!Yd24E@G{eUNbc5Iw8Cf zq1MjBPWt~d5(jrla*ITi-<5LSn3EXofZK(20a590a5MyOV1kPcQ{Q~(?|?o<%EP8V z+z`Sx;N?vl!qk+MGGKlmMRM?6-#nax8Of>Ft-T#EM=)i@DbcbB2NLs#ih@&B&K}`0 zQ8KUrP0@qeeHwwV^cJ)Q;eqg%xRafzig3Ll#q;l~C9^hYmz=?_G8Ey7GF=H(P4I|~ z+&x^(yHIm!3Rl99*I3|B%%XZ^f{v?W>S{+;#IifWMaI>pLzxqKxQ^0$Oi3!wX73@z z#@+^Q5nxC!O5$3mxgbO&9hm z>NEU|#AntWzUfrlg)}Cf6TLnj_jERQDlGAQ05@YuVUk#_QDQ0fxrYgc40VtT29nYp zNvwCts`@g>G+`NXBJ-0)c0%+6u+c!wMxnIc&Sc`r6|oFEB?h96wrRXa$~q>mGH?RW zyNn2x(iOd371}D62hU!8d((`i*v59?OR?E~1ROP%-|UsK%w%5HoT^wv9KGXB2bvnv zi4Ol~_>(;a1_;nlRzWeSde>n&VLwumhm~1iHf0vWr>u&hhOioz`+Ix)wIkl0q9s}u zo`)NtXbmlEv7~u=$bMk~Hg#xeYlkRmAv_{2WgF)ty{!08EQO_p@L05zo-JdF?{R{r z=!8Wu(HlnVaWAj3;KUjSjPpXC0?0s0(#%v}hL#~`T$_$!n8`21`H7f19Y(khHIuS9cj)8nF!VrH^GGk$1=t zYpiauCo?J3S!|=|6<9uN#nR70Uh774t%^MYnjgT; zi-4}~V_D8jUSsn4K^2pBK9#|IQ+Rg5vYd&%2Foi|>~XLR?RzMKF?vW{Ws=v;@lD{_ z4a+W*yl#$f2+PnMm+43IY>8#OnB#8U)sPBd8PeQ5EITdZjdOfm#6N(Wy*65QTE@e3 zd_#1tnd2UootE*MIldV*Yi5s!Wv6Alc8+fX&l;)jVcBUJubtx?!ZI|+mC5|It0=Tv zU@F!uqiCqRlB=TFV9kq+ z{X!m3NJlTG4`|h?R)U#~uL9#3t0E>TyFIy;)~_ZkLsr&G68kPEMayHU6XaV|?KXJJ zKR>F$QY<(2JietLa>8anjHIGjp`vRHH=LlT7zXq;_4mx zRxF(x_TBhx2`odiCnIq+?m!zPbqcSuwr&*7dMr)!e0k%r!vUH)?|~*oKqjjV!KsY* z7Xv&2H|FCFzzoQ*WmlaWMkf3Q5DIQ)u(S&V>i-V;q zyfH*;BvApV^Ya1NXbqM+v1VtH zu67hfrOjg*8ga+b?MDhDG;ZIZeE|Bia=;}qND+!9Z%zdW6%EG#UQUs#nLR9;p*T+v zJrBAGhatJH!*|~>V1a-w!e@vAK7*-IK9};Dsgvpy6M4*&K*qXZ>SJjD0GZ)hANj~& zfVYd4w2cs!G*89;b_pa)SZV-4Br_6kE$4q!H{vr$(O8{**_iAdPf}#v;^fRmdIvZK zP@vdJke9IxSztKHNJ6HIt4!>$j!4Qlg}6~?7js-y0;(2ps;xQa>-0+-H%)CTjuMFH z)*)Ou#gwdEALMx`B?&W`RA%G>jNcqF8E;g@*0a$DrEjxw4w1VJaHaiYuB!eqHMH!6 z<--i6R}s{Re$a8?9G~@DG=uk;P~{w_f+$H(C}88hikB{Wm;s97Jn~)EKY*J{#N9|z z%VDWpmXvl?kEQgThFO+i#0r#4*cobvN4$ci^w-k~*OZq?PSNuIdXM6s=lkV#^T~S@ z7d#)RmN`!Lo4TdX2_dG_SW4w~J(}FuOglF|CQYs(`r4VYJ(?8XDxXgd6Pd?)1x%c? zBoC9Qz_3!up@~65cLm-iaTHehI%48xrWD(JG5)|ZfO6UaR3)xlohFWEqvaW#CGE^GzYuWzl-N_s>a+`hZZ-SDweG<9-zrQ79zsgIPjvDl}n;bDT~Kf|Qe? zu1FK9U)osA(GsfV`YL5O=47)TxxW4whEUoNRMfQ(;B+F@upJqr3|8Y;1G#$`igI#C zqzcN^lE;`1Ypxnrn)PF7e+aarLumsQOS_%Oq03g4X8oyIJ&_PBH-2-p#MqYYXu)O^ z?-0TUK3=88WtxTZc>0XQNcFZ#qyz}Vt{x*KKL zJu{k@%C)sPSCNTP)bUjlBYZ)IF;96ZtS&!QTWnFU7!z8*O5>pVC6UE^gvY`WDd_hc2MBDXuz!< zaU%qG@5ti?3wELe>z@Oe4DP16BYx!I?j3o&Ai^KO&Hla{I`~^}cV5>KKcaB=jyzs) z;kxV9EgkVA4R`Oz;{_eAi#FV$BSi$_!cw8;+n_zQ$;O|$>)5p&30>pqG9soPFt>O% z-;uz|->D*Q++IV=%yFvzWBx$M= zZUvjv8?jI?-*F00(A2Giqy~GQE%oYm1Trchs4?J&a|hNj<5WnjDkZYgPF|C95^-HYw-r8R8U2 zEABb|1lx|%mSd?v7k~6tqtw0*Q>6x^{o=(3aH6b_I=qt_$4~c^wiX`ptxlaa1`|r= zh|f^YY=2CQqK!CrddR!$SsD2=l8Q}3%^-XLN9y=-Y)gVmvj9uS{fNR0r&HSt6{n`? z-h~V&Mpg^B)JA!Od>Zr|QIp%cggne}G;;}$h0IK40Ha5F1g;7}oKA0Qk;f@V^d2T< z3GW`GnKA%!-48==HY0fw%dje9D8lXot0DhvkNGC@0P?C)eL?0XjJ&>P1K@-ss?nEr zYFSqd14`qKA-)9ih4;7X@$4Db&En%^;gkm-j5t%mOPv*oU6=Bba(Hby|Z!%_hbMzBDAHdCwb8DNaL!KwhInF35%W$t=lsQRl+Y2OEMcRaz^+j8a$~DM$ zp*%&BD{$&X_xj)>QWVi@+2cQ@ourSv#q2UqLhdG3&O^5sR(6lQ`d|wtj2I1@1r~DU zEU0y9n8vl3NaEaVH_LgyN>$doa=yC0N{sEAwWa+)t)hIXbMILYE5(3wttw5(S0zqo zY2$ZjV*;m<=R((H2R#F#-r?Mp@M1~ZJIjN%8$ zJq+F>i$I$o`2cRd-hH+QzE=O;w4gJ?j1#($v5(yo*CMc@zREnw6Ci{co1qx|PHvfs zHOyP`$X2c)w@^p-@+S|iN}R`n7#4{gz~OYN1bN?9_R`9K> z&FF-KR(+8CBAPBN#nvpmlzDq)blm7vjp!_8q+Sx8@CB*r9Vl<0mbh}TBs$@nP}R#$ zYoOzwm4wmB?xTiv;sZDYbC~8*#;M?+alo-bD6O(`BRXBAvOvf8?(l(xJUv!cL1|)L2J9TT?q*=@?}rnppWb zMSJ`mDw;H=@GKVcU7dl!`aT+x+QXKb>fW(Rsp)Wjj-sx6L9E;^C+4yOq0;yeXj;#h zP}4Hoj`;1$dw)&tP_(`)|>U&%V#&DXO0`mThbkbDSRDL!1b3YVkkADW2zZokC+bLo`Au7c!Jg)EX!E^V(2L z(Of8yMk$VE2%!D13}ebB;JaT^STynhoWXZpnwZ0dV2wG95y%S&#k~8_>lwo=g3;{% zviJ7gZQDrW=>E-5fh%X9SXqmb>?GaC`*`oqanh|%)7aN`)3Z<7TSFuyp{58HpyX(q z+|PawW&jd=(~B+J$*#HQbYl?&27|$1W-u=~AsDkgcyf0-iltiGKLA(m4?EdEf4L-7 zj;3%}r-EFLSu`O$Rw<35OP_ozBw-)vB#GFL=UrZ21|n7>VxHTMOy(VFY%V{0gy3lP z#dQzR4a7{KWy?6v6scpFMZGZJ9&3< z@n)Z##DVdw3C2{K*t{eXa~AFp4u8iYC5cdqYy4`)2TpDlE2OeXrV? z4Hfgy>bYthO4c#CF4vz^9Ct6QRwU9T{=&zpp|`)2XU{Hp^6c3@`KOoyFcvp9yU_=yhhMgxKiZlFn`$4{x~;Ko;J_b3t=dHj zx%CH=>7KklC&!b?G=<%q(vkXQdz_|;+V6Hl5h&ld*ZF~%bo2Z*-Lbgtq@p{GLnc*9 ze1?GQ#4>8uu0jC#l&u!^SEQYO7DfOA7X~_=id)|k)jLH~+M}RYkj4$U#@#=D2 z5qHu0*Rex(+kPd22l4U2rMZ0g5l_d{0Ss)tb{z(hO2)c+Q)Dmo*KOnI3FYFPV;2Gx zXo~Vg;fqU>&~$8fSvG**6f}c*2<%?CVk|*s3j+jFDCL&u&;)Uj;dz3o&nWp&={%oy zj%1$;SOY!nfF-Hw8a=t2AD_0BkhnA>O!Ezg>;2hxGSusn_z~9Vc8R$G)NM zS2VbqCPrq#nuQq+T61+HpEV+cA`_-LI#&}_2k#Cth5gw0fxxxUT z?pla5CVdY~0*CIHp))*!dleM&avZD>an{cS<3IBZHHMYipG~PXi7s#k_yHqPMks@I-o%^JubGYA8 zr|h1PgxaEZSwM6BTpTsIT<_1QDz#Qey56wdkVdK6||E;E8MB=I(ff%T!Z$ z7a1j;2_EYAAm8foLN<~#%vC}*V{tmA5it@7!HZY+aZINQr3?#n`Eu3*5=x<=kD?km zS~n(Ys!vuHLIy34A)l0t_>9GQZ?--$N;UYKV>3`Vu>PlJ?ty@KnOyzQJ1e(eUQ3?l z9_n@sy(4OhF5jk>vZn5*_SI7WBeXmR#r!Nq(~cbj5GkPEF=&Oc0KY{tjnUwf8638m zKk`ZI#iZ5t^*DCerzTlF{$&g5mWK1ob9L%9->wX^?|IfD!JK=3r{MEoZZ^kI=&f9I zj@d8RN2=>_VA1I{z<<#1O^~y|Essga3)BoTJ$Vx0Oeh`G87k>UbahCjn1okOV_?kY z)CJ1`W>3pyG@2x4X|!OR_mp{8OA?9E2&o67Lr-0OLJg3e1n{8 zMS5;zZZvH;bvuJV$k5P|?#f9Hk+)I_3!H<%j^-W$y59~cR~`KWFmd?PeU<-unnmdC zlf&qm&K10a>>c|a+Oloe`p2wKLP()R-9G8>?mfqaJm(W0QR(ts>O`FslR7(mx12ND zWx96G#WoK#^X92*8h#B1tGv8zcKHv2v6hx3BLNg+yoSFuk|uOct|{8bjSUsQ7K7hd zkY>i;`l`P`O*BcKs*2X#frzf zBbE=RQIsYA$)dL~&c@89A`c^C36)OeXHE>nuWgsp_mj z_^q8SXR2+D@D~EP>kig^)eBcm-o4Y5D;tcgHCdINHAgETxhUEVJZ}*tjKwwXP%W0| zErjq}>xg6#HNu)P96VKUAA^$u{qF;8qgtED0v&L~VkT*1P4n*OoiU3h9T=d)m6|ez zIv@El(b6Hz2~s`^@>jp-_ss6GhHJ@YOq#ndV^=o>o@k*&Ocj~X--INC=_DcBAHLCj z+-$M+fxDH8&NsbYyX}*A8kx=w$R!&329n0XSj$eAd;W_{LPwOxL~k3UWI4(2o<5-2 zkj+@6C4W^5mu}PHcpc+Fb@bigyMMfSd-9L1{4%1GU0=Yew^0dAU3{TTm$#?k9D!3J zn(4K-X2w8Bds__4;%Ce7P0cd6*)Hl4k_wHG=a*W1QPa@~s}>ICcaDUj9yZ}4NmG{3 z6U9PI(=iZYl$-k_bJdaZt9a3S!rQ<^^HP{x6)JCGwc%GB?B4-(+J`lGVYgKj^H|% zL?RwB3DT&RrVTvc0-^FKl*~Gq@OZS77Yx%l1KK9{IhhHq7Uh1RpvgYI3YT>0m>e|$FRVThIA&tRk)@^vVo|nMy(wN$@g0xu}m;sI8e!8 z17lR}Ev9p3tYj%#mqc_`8da^~<8b zf4M^_`4I7eq;if7KbKncLF}tB>Px9ec%Ztb>90n%+|q5@kYYz~85V~u4(2}jL5uAL zWy}cfAi~A$noLtfOknM;Lotm*@1My zhBhTDc;;{~148_m{*u-A2#mN2h< zCcXf8M=*7~6{N;Tj>mzJiO8kS%#9}(5;dpL=K;=f4|Xf|5{TH|F=v-F(8|n!@KmvA zNF*CknHe!GuHKxyt-aZ^UVh+)1lP!@`I#lbQ9~QPu(8WM(>9wJ|OSlR;J2|=d_4M%k{HK$%*O#>yT2@1JoeCo{ zQd*XV^94@188%vK3L;?e_n>*LN_nhkIaUhKN@b zxotZZDc;#xGKDkSx=jPKefCVRO^|9%IaN$)f;&7t)`!7i7%F#zHAKznrY0>8;)*85 zZs5quuHj(7R7w&_gOmqw8+aiyT7x_`nX+y^Fk4aWSl@b@I~>@eH}JyL;rfC5^ z7A6k2nOOt43n#6^b8>v%BCih5kI#3!pN=oSJNfZ~{B(GBcKGh%_{}*vIU`3W?_M8Y z9G|>9Cnw*M!*~BA-ygqwy+arWg9Q7SK!!9edQU)B@x61#3WI0K)6InkiD*2U(h(yg z&FSHK#!W*=BUhn1e=kWi%Ua$QB z{eJ)DpZd?A_jY^F`@NUX|J3V0fBE9&pGa>*<1c)sn&1AZck8jrllw{@$1iW+BP5_H z8wokzC&vXz*CWL8j(x-PH1F_e!VSmUC$n9TCQ0_^uD|Q=d0`%EwoeYpTcb`oiiF;s zkTDvZ-|(&`5+fdv0ZXqLi^-s1bo4z!E(!rWnw{dQ1pI0+H~NC_jm3oRlbdUd9uG9! zwgXow2*q_A2^y+yBt}AIX^1|_>cw^!Wu7$RgUqZMZ5;b&%SbHS~+#~4+dvekuEj)W# zWIN(2C9PM7XD$8T|82F~r1SZ+2hjZSN5@`qEg3<7l0c-BWZ`S5bZb&m@pxp)uj9{e z&}uJYy!6A5SR63xXb1_a-=MZ>rDf}ac*W-XKIy9Id{LZVsgjCMO2rov&#v7p&eb7A{*ez1dr&g}dcWRuC5t=LD5)2^8nG zW15-6+ts*+?{vr_#frTmy{ywKeo^Sv;Clh?ZPoDa*&3*KKFSxs{SC0ZGI|T2BD}=? zk$lST(OX3?*RfFGEZtf*OD)2WymGYI){LJzk zFxFc}mouVCKIA^o^>%rE(8}*m3Me;NY?DtU=5eT}+wT=Ql-bL%NXa&oI&_fME;l8K z|2&9-2BZER=VkCcTYZ9vF!&ce;fSk6{nCSpCbD*PY$EVlmyG|AE)-P{7S z*#6V+@4k3mwEyh(cAr1mf9~bEf&B+7PRbEW-4IxF6V%AD3Z$gZBXd!hAMt#cNfx6> z3}{qfG3A$TA8x}1tvXIK;A+m_Ry^>JTsXhazxHh}c7Vp7UDjqs*~|zl>88f#Pl`lx z@F~k~Xl+zsn5D=ZK!!|zwKYpjb-t{>!pbQ&nK22$4_He3ts+{R+E$g?o8ropvNIE34NIj`hN~j$n_J_GeN0&l)~wa=WdP;z z$iMn4h=rR(oy{A*8q#d*`=qUb7FJh7m2J8?^yEHtD`Lp`U}YrrpWi!C(IinDMU?B$ zxf-V2FYXgnX6g@tBvWK_MFiQ_4al*Fk1ajg{L1MeYqdfXt4}-(!PXD_-?tvPj-76V z3qNA*zR#|+SBFP=MvxVE6^0wG%x`Xg-s6DNbSxzQ7pA9N2Zf71-yABB&R(yIz(9s; z;P3XNM-!ft{aUDN_;PbtJ3Ku$;f5>XjwalGusRBRn?Ru{tG_<|HGaD}G=8T^Tf`}i zpfbSWG!>9mK(2_@aYEOSNcYx7XJ+elPgsq)-3qP@j3334kRG@*6r$Ez=g zA`tsxQhYIhamu5t!Jfb8_b^1F zs8Q=~43>9HMOqV9txEaBT7P{0+#-1*1mET?(qM7rjtx<)l8x9$Fml^4Um}KJnI1O7 zKt6va0~Sz7+NpcSG;Pv`cM-QOkIDb+`FkcR)8t`qL51KU4H#eqf?->j&c^qiJ-ZMX z;e~l7Ao(wZ>(G=&V)Rsz2^6u2>sI60vlWGEjFwXltcCsHV5arQ_UuEi^WVR;pMCg$ zKmYRV^XDfmvRyzA`9xB2oO zuSHr|ASV0AJ8*_+4LOTK_yn7Fdc9VDK35>@-xY-YH6ZL~5LQ4jyVs^5$d;uFi946JqP$KRf{#4NmtDNbBd=W(qhbZ_dt6&al7@ z>_?OO*5+fBfQ5YjmNvN)h3mJP2R$&NWZ}ow&(&IE??h^HY_J)NO`Rjj+^RV{L_}es z8j`7mg~_~3p4hql^~yxiR;m^d2(wlj0sGsjgxFIzHG&DW$G}_-S4uXMD6qSgPrifX z*MY)Fooro9d$Tg?22=cV=_BJiQfO8s$WLTQdGvUz|2030bPp z-ADQFKAtt?Kga5VN&HQPAV|AhBYqg-f&XifZGzGU{COrsn)?x2`6nGSY)x8td*3QM z1b~3ibT${q%cM4AW|~7S%>4u6XAt=ImD@NGil?HXxqX>`pqLhJQX%1}-FL=KnVj$# zPlsYZDIK{guxtORcYH9u4A_H(**eZuCwb8DMWdI3^KU&|4r$0oOr;II_ z8h6eIH67K=+8x}wEdE(_|E%=?TBVtl*T;dTF!oZjp&{VcBDi9b98a)9v%!<87xE6u zH*V+24EM3}N`cxWi$f+)r%{AoDQg;PFW3@E-n_IiGU2;%Z}fMX-|e=WcFrmrrvQ~B z$U47kLI&_OPRsP^l8Fg^ammodQ77~Itc-9#Xp-o4EBxx$5^wP@uP`)Ds_>b4liU*^ zd`PxkPhF>*HmpY(E&C-%3j@O_HWdH_50&63fU!CHXIfFk(o060*CMwS5f%`6WoK-h z)Juxz67sHrXE~9Zw^n)7eBA!Ku+X+evjdx1(%N<#*dUdghctLc2C253H@#kq@l!U)`FKyh-sVP@e9 zjKSVUpPF7;c)l(p+3IHwp>5ZA$ozF}51ERK4CI+y?5u&vxtW)Rnc7iAl>%;aD|{Z8 zdRr5()z23@AgzzyJI8K@+M%cq@*FV?jd zjB0NwkyVYU`ku{6q3c!|5hl+tUWG`_=2!Y`N%LYfY#ON!4JNGBcG=s1iZjY$`QHR7 z->v<>-|z2M?ElYSJj(y~@vLG0cVzjjIuH^_BReqkW1Axns0O5GGESL^=@-g(&LUfP z0w{LDC-B~UQymX3nB&06RrWgF3ToB%$XdeAU|#&fINjD;+e{$5sn;!H6ZGRlg-~Vk z1-SA5SZrk$6k9CAZ6SfcZPB|fs{Rcb;(yq)nExYz+>-q-wg0^MrhNbV@|)eq`0smp z*5LndJ|d<)#fil4gW$&5+KLqYcr_bH9|kTa~1t>N^&pBVNI?NdF5hFoPX=um3d zImvUa5!DvRdv6Q=a7DHas$Rc4*KNTPmaw4hd&k3KMTX4D-oZW34P1bCaHEIf!wBtS zoa=@aMbgrVeVNfprxb!%X|NLBT@~_4YcxUj=;kaCJt4!8 zw#hU~c_(k=)Z#IM0zR_CodC#JAL$or`VskqTT%^CH|&Ez+9IvwtqS;4O94 zA#VylbhFr#lLVte@s3nOlhy3buYj$GAN=mr$si*>W3g2$riw|E!7!6HoPbfce7uO6 zPv9898wG9)YYMy_w6QVUzfDzYE{`+hx3O$_eW^DeAovT9hvGIBaJKC1aa_P@WjWj! zo*a)@MZ%Pji{|=dzh+oT)mD%%VH7HlySZ`h`Zl{rp%npU`LR&Av(BWh8Uz)(J}93* zM$oB#x8~8>F#*wKs?TLB@Nuf#JLflR_DP-2Wv+9@ z<|{FsD<>7`O?VDw>AYg#Xxw^aEcd}!uGqXj9PpiEZ_GRCmG)#FE{QiPj%!yT*ww1c#XU$`CR#CkU(A|Y zj-Tz<#MJJ#+N2e+c$AJ?q~C)z6nYK8hoGpz7yiA_dCYA63dNF6fn=ZJN~8|7#Hy=$1#4q^UiUyESs z_b9_~%O^kaC?W|DuE>x}mF7kGjYFW>pCNXJpyHa44)_=4+)~4gZ_G?bhBiYYX&j14 zhB)j7my>kJD7ojTuC2ra~*0M9n7yfp>E&be&r-YQ&tlW=ubYq|grS-=Cs%##zaCQn+ zs1zC0_VJL=8WPrHLBZd=JSrUHmi8=mpDOcZP7T(em%)nn3N)=5CePgh#Gci}#j&VT zSr9OJdd21ohe>U66r^leGp@?#aK0t2y%15!!nQ}qu1`+0xOO|$8K>n2mwnj8}c1sCe zX2yq5A>8bwDn`xnnQd=M@`4 zSfAOOrJr+FP%c7{y|7Jf$A*hJ?fX6Ao9Snb4Gmbz`W{7;@;N$9d8GUiOTTCHZ>5-M zuI`p!QZ3?_Sif_C<;qIau+A$S<+E&P>jZ9oB7>LDSsb`C zcjxWI1(t%HOpW|vIH}!e2k!1_iqd&vT`^CcZClQ#QcsCi#I)$MsZ;=sEel4=fvARf z-H5R=D3BE4Mj2tMv+7jW=6y{%5lquk4~V0^Y$`2GGc2|Hyck{O8wstn_~)t2X0jcL zYbMFIK06MhWK2oF-NrxPO(#t9fb`pBdzvKGR-a66m0w#;`xn})fb$A(Zu)?Y*vB)x zyg!Vhw>$-#RqN-Ue{ygELC~MHFsD*UUaZ=Au91OGW-yVrC~P=2o(_i*tKE9_Os6t& zji`6iNd>$GUDiAJ7gWi_CD=Nr>ZxMNkvxV{OiEETdNb}2p~drSuE1|v5uTddQ7Gcr zlhddTD`=W{n5?T`nsMHnkV3<@CUfM0U#TwWPO71oht>ht)qR!;e0KFaPUbEYY+BBb z1;p$h>xPNu-?7wj1P~ zwtLzjq8f#riqW_9SrMmoLPMQhxWH0o1$5Piz+4-3o{~he85dJk)k>(V-l|o22DV(r zGaifythq^+?GZcM5@BwZD63NVW4g~T>sfODp9)Dw>~7<~`~8>CEBF5|UOwLc-^a6l z{wFto$T`vnftbHq-f9Ra&<*myvn)Md!0K<~oCbMHo5db+rJ-^Yk9h$w!o`o%xnFqM zsb*p--{_cx9hJ}A8ivIY4;Fv4@RAhxX7wxcYMcEI7r})l?b6kfJzU*381(#e>*to6 z1I5)LmVJv#OFd+bvw39fU*5Br|L0j(ZgT=G;s3pty>H6=|K;9e{=a*9*5dzh$Yge- zfEPB|^^B#OMUK=pNqk5#i%-o_P_KM9odVS%N*ug$hd;}Wp*iPElgPet6F${d4|G4- z_Gg*q^G`a7+Vx*QaLyn1S-k(z?tjq)-i3G*&)!pM ziy5mclV$^8T5#%=|V$CZL zT7Q83$JZ?|2gv8opIhV;8BoPuJ|`W>M_IO~yqfYTBrKkh8I^dWj{as8!*G@^WCIYiJk~)S{maeY$5Ofj7Tivj%mFL$u;{elwA3)*t}n)LvY|* zml6x(l^sCM^uZ@5dneh9NyWa`Kf;{={ApShsmyI!UgVqkQ24cX&h3KNf%C>t0RB@IsD6$PijneU%cFJVJhIC4$s~lzx&5NIm>5HLYA^1Wg*$tGPqMJ z;PdBw{fln%`Ez@R7#SnZYTsZ&Pjruo=0q|*O%@v$S~?RvtYX{L227wpAvlM!c*doO zF>ngPGny;V7~C+aY!Mo8;)Og-9WzQtkJ52kdXDYl@yz%)c^2}2$8)XwYe1EvaVY89 zhrts5|DxA_S>*q_yS_kZ{Dtik_{*B>KCmJ)K8nY?5el~|^FY**jFnK#SvAkJ7s66h8}2 z$w#tbvsC5Z3aQcRlh>%`?c;nK&&XAg>nNS2@V6QjChx&?SqZEx^k>|CSLz7cmU;*W zKPo0qB^&aOD|K_l=01K@>dATsyMDvDGL-wTmBuW(u!2}2Bnl2s%CUctfw~+;3U{n+ z`_do;lhPKW1uI^>s%))V#{;@D-A4E48scp&11vXuRo~V7GUpdC%Xt9gI7uq?GHt&# z?$WORajpCDf($Ivk38a3&Yd73v}r?D7CsuM*2X4eDdu+}b6dJqZ04W^?CJs7#!|2g z7BxQy(V>{K+kf6C?yYj1tu=6$JP{UkxpGIFT6nW_^Qo-2_LjTVFZ$|>Vf$HO6)j$f!AALs&;o{`l?s?s0_wDWkEWXwYO+xfSl&# zo~G%zS#>P+qYqmBL4(?OCPdnxI!fnNt1xO!Kl=E!ZYEA2Q}grE@0Y8ui@!f(NyGyn zk*4WXTU2}fLRI4ODmALbg@(P19>0<#gm;1Dwz0g{KgoaJkOno)&S0KXtt2;nb9ZZWc z_Mc+NS>*)Wm@Q|6!oVtU-@uq-yRGT(CWf39yVU1)8gOj4U%2_k zWvA=xv4T){hsK*b+-`*_+-9G-C(=3_tKqv18|L)>U1Mc)G5f1r)g1gKE9!E|x)pPO ze^@iz8ulL%kHj6=fBL=W<^12f{TDCx9_>H(@!ZJ%qbcF_tN)U0^ta6$fee{_IYuCN zw#}9x1pAh@Aa|%cG6+@CyPiSFe7_NcP_eHDgV16#PO*yyGtN?@QfX4nMx`&!AoQB1 zbU;=4`_TM+Uk0UfW&=B_rX+l~w5P*qI)0PWiqlU<7Y$}8`1wsUnXO|laiLhEi{63t z3vCcC2w$XG%&@xu0J9i=;BK!wO z+TI#^xvlNZbo+(d-d48IG)d5RX`$J$p3^voWo8;@L*2kkbEhWJMJmbHyEM1Ai`pf- zd%NgEn`Z9iS;PJZnO<)a2)fMw>&0Hh|7)-J82@=M&yDPV^Yj1b?dA=Cg-pT^Z}x*p z-l^vojBrP0zA`e`GxEXL8!_>@J>Agbs{qW6{k_~?9=*LDy}ha$KJ4iK0HfAJ`+5~P z=NDyFdSFj4B)~^MuZOWUEj{x#XKC8h!M_~ln`l_j>DO&zf+?)L+BdZ?)%I~)>k@SO zh1-@^Hexi3Zg*+IxSQ>DYs&@htFPRjt6q%$>Q-}g6Jf>;zidCQn?9@Ce-fe6kz_Y8 z0xj|X>c6bme|GmCNeKD4x9HwS-P~PTtHX&!MyD<#aBX}+A zkkiF2)4OU7_?r3Kza^`q4qR{Y{&^MKZrYO`9* zHmmv7=FNI-&ED8hikT`DMe~Zmkh73$QK7qv`RWzz2sJ~L*JA;)*EJ|CB+ivq;BL(e zi)Z#F85(XTK8GyeA*s<>xoofvR zB7Fj>#5LptmO+bExOr@#wntcri8mf9i)T<2r%OsqLrtaHR?avMc_O8R?Bfbw70NT$ z(cXjEnwFoS>sca}_vajRh^WR=-)j(Pd64A}v-O&?&0M}+UQ-8_dK*%^IGqLhbmJK7 zcD!Lzl{3XPDduKIs|6k1(sJc4)|YL*vc`^zNVw(_G>DaVXbjn`da&}0?u2{fO@GWT zM3-|Akd>=ja{=8FcaJ3%k+E3QsqUj{%eaxWE2mKXhA}MWimmU_idl>ui>h@pBLVmMC z5KH|3UhegJW&gk3$NG==^LRHg0H0}6xSQ}_q_Qu@_6y)Nn|qP_I1>Idxi+NoL7V3WDMQLbLa53Fn~uJ;0~IthkcxyHw}P?ebw zmm|q-x-xnSQ2wac;WQnuzn+GKm%}(!>~t+KzX)r-Q>rk>&}}>k3)pV9pk{N|@Y|t{ z+*dT&IsRuQYFpqt=eBINZ5LT^i_rg+(i91>acDDivECAb$yiGp*?KuBM}dKJgFPh|D;n)7_2VisVlk66Wnp*qFiTVRecAZf%*@RI6VjB{57F%R zu!3BlA5~Z)+RvXD(XT`!+y5Vje3zOieFPtdNuJjqcU4#e&KFkKBvaH zw8|w4mTt+(yyLdbrD5lvkDKOxH%&>^sPs-c#p&6mPypANpJPbYGfY4O8T#vN%HrNB z+bnNdnLXceO~I8YQrn3+HmX+3wLAH(T={9+AWY|%>TUO|a?kx_Mze@fy&cR^R%kL} z>Cse57UxFAR;z5dp>ddT4#P1@_7gi&6V~9P3-KnNy{FQ3l57AY*I~#-t}X}I1W9}U z=lJK?dL#Z>{T$b5Iyg8&u2;@rz;8D=dKE1I*!|N#tEW}AmKA8GVMv~KI$A8!>ej&% z-P~{i4F!!uUu$7GY2>T#{ALkY!NixL*VM@W{+LA*K8l58n;Bz?{NH=ATdM!tf6;sS z&7=H(AI}y!rK#prO4By3x;}PdGMMrx)LcBF!4(}b<$GJ?V$2m$(zxIdmsH^{D|5UTMn|Cyz z!PPVY-A8%Pe0808&-?+s@}BwWB=Mg8f8G{(PbC*qMUG#;QJ$Yj@f!fe2amE3!(|?EkYjhp&Hl<4?j(jj?$DzwGbsJumJ5=ezyK{eLgd7J0?fm`=Fe z4R85CYN_Q&(}d?8k`LdpXj1(7m+f(yCThRi)klS|#@$c^s+)?02dW!k(_al$ZRs{` zuz!!Fm?oN~Af=H=jCeo>EWKu$;TS;hJKyuRw#dcXzr8;5yvxf=Em?aZOIRGTIN;1k z@A_=rH~qmmZ%nECr0;+9KU%LFp?E6fe4kjr%^+q>KM<3y`L`YnMhrx(M8v!&M9+X^ zW6#Mn(V}YB5I~~|e{YAL^}Q<|hxjaIbccjX zZTr<^j?xineaE6mke`H%!WIItwMCBOREls4HxZr(d>UnuM2Z;?nIhDp-5U7xyb>lA zxgPUiOadBfDF|)=Al6~VB9V}oU7IB#Q!QH~K~zYfZO;iZp)nmX>3iO*!ip9K0H*)p z`{{tuBvE;9SLPQ#WV0?(O~{f+%qLnt)bc8J4}Xdw0pdKu{&`G-XsS{s4fUK#1{%2H zDN~-;A$mL+vy>^)_xu0-7q5dI?D@NX?=Sd`Rt=f%Lt~MVp@<@Jt>>N6LB!zJ6)zSn z_UMfA2;Lce$!q|FR`41LM8ZIy3i)uzK-N_(K)po|yG0I%Lmu;#Yd}9~sPy5-Ll&oe z$eASW^NGA>Dv%tME3)$QiM;ukus|zW$8j=Emw(`W>MVYiz2DSlpS(}x((DqNVakt1 zs5L$@OfU8H&R9B?F`-2NLi9_6)j8^oycS=d$ffI-{O!p}%NQt>wb!*?9iFxHfB(1D zz6889Lo=o_EJCAyxqoO95oV~V;3g5F1*WV29jCk&xD1*=OcD{ZIL%r|0V{0E>B$6!AX-uibQfS(PmBIytF;sVBOb% zGe4Efpsot1)59IYsZyG<;WSdL4CtzGx;@+-oIHl0n_H~A?O{D+t_!Ce(4Yp$HQ+pZ zb$CQ1Q(`Iuwhp*!?xV0C%$4ChI(vNsWUdQmA|f8l>p)!d$^Rwdlt$!Kgye9V z3Kh_3nfS0S|1`!vttSH*Z7prJUe}P{?p$!&)N?n0x?6z(o%z#bBx%UAYkRVotP zh6pjCU}W%fWu-ho*(Jrka2!&ypZaZ5)U?cQJf6_ea#iNOtQI$ZmhF-IGIrefaVeL> zn&AJ{N|O3qVMsc|X%rD?3AV}V3K-gfCTBvVtxV~$-c;$B;aH?)qrIP8?hwTo`EYDM z`(=9z+DIYNcIFYSQaOdZhCZp8Kr)RY446=twG((Pf-5GG2FV#4ah1wBF)e*&#oPB?%`Q2_i$4xP7$z|QdD^T5h z`Zn`R9?7OMBe2^1BL%-1J09Z5zCUiWv1dKg%tIXRUyVSKKZOlx6zc&Eu2>w_ z823Jre;8jZLhZ&hBu~s&gvEMe;w_Rs_62U^!_(tTQeJP_?XFd*tXMBOAzImQrvkj; z22{2TGuA_Xu%KDCsK<^)$^%xsh(QaO&qa3-iBWgA*Z=Qs@0)J_uU(q(j`OwZ@VL|O z^j~%zwmy$j`Z2rk2$&*uNVWRKDNV;0^MqYG6FikXPL&OFF$zXv8d@K<%pZY;8`w)V zD#sW8EJCVT=%a`#rBC+DCZzIG!;K>M-vp@vlj#q5w|T~XpE8x^a#aPXnI53O>X<80 zLgQGZCJssOlZ&_KMDbB<+VLR|;FyLxLzdbLMY~_!&$I3C{MaCtS<7PHu;G5<&XEeT zz*{g-jS6ZjIRI{Mi=5moi2PD^6bA=Qb0;(e zX%7!smC`5z7W`B>u&xFHEN$iP62F3>l4z=KCQB~bnMV7(m%aHFYF}$U_rhSlLVat^ z$K4$m1yIK)9kr~?Cr#+U;P=QkU_nDNL($NVGSDds{$1M zFKf`4g*pjIBugb{GX@Uud`M^{84c$ofD z`>pD4yR9~9MJyhr;}+@nNK2(s#G^dRmOdxUFol2TM7=}s`yGPcf=q~Q53PEMdXC5f z(CW|#E34|RNAm;_lq8bPz&}3=iL)rSXvBVevJ{OCj$~iaW6$kWNIGJh^Co?m!+CQ) zs1I{07Kj>`#1A5>Tywr_&o|3Pz!Z~HYof(Em9jWs^^DVLP;&)yn!o*Jd&_Cta18?# zbdg|=-6gW$$}-;B&$txv1fzi^hqww5+|h-C zqUf-u`xugJT>^o14*BXdN&(23c^y=JiNQF^<^`ixCc%UVYtzCK!Ntzb{0f6~?2pAO z+43|>q3F3@(~kR-kp( zZ!@XFE>}a<7x^q(zf!&^Wv)sgnR(R4@rXxaJ| z(qgGBm|)HIgR;<@TD{u!gA`W}ym}gjFKF%Rs>fcgy>?Fh;EgO`b?uyjmk+yuPVJg| zS;ZymS1Jf`!@cK}|G3rqRo4xZxj*cZIjN-YXV0y$ZUI$_#-XHzwOe=Hj%+U*;+xg= z%iw(AHO%0+uXS8@=81SDZZEUwUS7Z2z|JF!7SRCv&_^FaaleNjm|}jSGUoAUxgBN& zo6D`tB1;VkD=6)^((7HSzBX9#rHCRPk1ps)pZo?{gbu_sH3@=D3zE_iF!?P0=W_jc zAa84noF^>cG$I@@sDd$@P~}9P>8|obOwz=_?0bZy^Mvi|4tYHC2nqA$+P8r-wz-pQ z72}w=B9VZYA&(IDkxr6`?UN9`^11LlC#}?yq0X|FK*)KdmD{sPKh=##JpSl;DIG2A z7W+x*$nB=@_h0(`PRItF#+`nzBVX=$UNVg$4BcMVDIj||CltFs%|6UZK!8E}>0xwD z=jtip!yFEcv!@VLls?_TVh)O>(END#PNb)jDHf+s5gy}MmIFkkq;roDo-$0%yBJcN zTQ-^#Wr2>d6C#E=_%^6(J1>A;h=1}uFJyzMgYE%V%BY|Q=VGIsfn5Q2i})2d9BS%j zA5%#QkB34|FtP#@ohf&bu!e@F?ZX(|0^@+0&IWAX+seq&rMRs^CbJ^FY-#*Ato{~p zmY=vQ;cXF|x`D_f6Wb!reR00COnsE4c(O%Busv~Zn|&7v8jqf5?!@7`dl_y1V=NTr zA<%*JAnmI{9j84JLmsmYmD&Me{j!B zXgXfj@2N?CJ;)a_EcBG+&09pymUM8@w+hRFc-}Zf!!h`lPYy1TXE`pHqTJ0aS0RFfK4^0`pHDDL!xn_SgbhY zc!j+P5~iD`kH^_%=MGU~!br*|Oz94;X$+fkq`$_X0*UwfiBO6|+KD+1Yuu)}RAp=^ zKVRLgoRfDAuHg4hr&FJk(O~7~2^onAy}%QSCdulb;u4-D^!F*t5u?oK*PqI|}_@0;w~ES~LqR+6-NGEWcB&wn~Od+p^y=FDFF?t8B6 ziKv7+Y{TN41?X};akKpCOtH-}8H(_u(Wa@5GEv227Iv-VWLA?e=y|&ZS)&uuHBf z#F$P%K^pRyt1%1n`0f!;$I}5MKGwu*5+ZM@l%`YF5yMV8W*w90yuCxxF;`?le-qNp z>x7|KN>A8`FnQeTn8qWf^!XTZ%qXni=lOcgE&~-I6`CywnTRY{BTtk&WHg;h-BlQ3 z5?!3?9?DSAi{6Pw=moc)Y$!7W!c)bfp;oJ?%mT73%HEv3^*!&|v!B4{(ExtUBqQ8p zRc59bN*M|N_p@i7*CD6Y|J?kn5FK2(^M#1KqDXQ{wrx~pu;C#EidzgF6Q28f08{uvYkAY-b?KuhmJ8t>F78Pfqvc>o&H5NOdJsBAT&|25uMryVpsCN;^3qxXxXtzg1>Z(;U)*U<=mKbAa(Wv)xWA z%s=%FXKqT|O>COs}bAUdUA{`CytB5M-g^int9lGmc5?@SGf&dJHQwEtH00030|5|H}@&E_~0BH-!#{d8T diff --git a/charts/apisix/charts/etcd-9.7.3.tgz b/charts/apisix/charts/etcd-9.7.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..dd19be34e0182c9660246c4219867a0bef307a6f GIT binary patch literal 44977 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 literal 0 HcmV?d00001 diff --git a/charts/apisix/ci/default-values.yaml b/charts/apisix/ci/default-values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/charts/apisix/ci/etcd-password-values.yaml b/charts/apisix/ci/etcd-password-values.yaml new file mode 100644 index 00000000..e337e446 --- /dev/null +++ b/charts/apisix/ci/etcd-password-values.yaml @@ -0,0 +1,21 @@ +global: + secrets: + - name: etcd-secret + values: + - name: user + value: root + - name: password + value: root + +etcd: + enabled: true + replicaCount: 1 + existingSecret: "etcd-secret" + existingSecretUserKey: "user" + existingSecretPasswordKey: "password" + + auth: + rbac: + create: true + existingSecret: "etcd-secret" + existingSecretPasswordKey: "password" diff --git a/charts/apisix/ci/topology-constrains-values.yaml b/charts/apisix/ci/topology-constrains-values.yaml new file mode 100644 index 00000000..029316b3 --- /dev/null +++ b/charts/apisix/ci/topology-constrains-values.yaml @@ -0,0 +1,9 @@ +apisix: + replicaCount: 4 + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: apisix diff --git a/charts/apisix/templates/NOTES.txt b/charts/apisix/templates/NOTES.txt index 43d3bf38..6796d00b 100644 --- a/charts/apisix/templates/NOTES.txt +++ b/charts/apisix/templates/NOTES.txt @@ -1,20 +1,20 @@ 1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} +{{- if .Values.gateway.ingress.enabled }} +{{- range $host := .Values.gateway.ingress.hosts }} {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + http{{ if $.Values.gateway.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} {{- end }} {{- end }} -{{- else if contains "NodePort" .Values.service.type }} +{{- else if contains "NodePort" .Values.gateway.type }} export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "apisix.fullname" . }}-gateway) export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} +{{- else if contains "LoadBalancer" .Values.gateway.type }} NOTE: It may take a few minutes for the LoadBalancer IP to be available. You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "apisix.fullname" . }}-gateway' export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "apisix.fullname" . }}-gateway --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.http.servicePort }} -{{- else if contains "ClusterIP" .Values.service.type }} + echo http://$SERVICE_IP:{{ .Values.gateway.http.servicePort }} +{{- else if contains "ClusterIP" .Values.gateway.type }} export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "apisix.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 diff --git a/charts/apisix/templates/_helpers.tpl b/charts/apisix/templates/_helpers.tpl index 1b920600..e3b09f1f 100644 --- a/charts/apisix/templates/_helpers.tpl +++ b/charts/apisix/templates/_helpers.tpl @@ -47,8 +47,8 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} Selector labels */}} {{- define "apisix.selectorLabels" -}} -{{- if .Values.service.labelsOverride }} -{{- tpl (.Values.service.labelsOverride | toYaml) . }} +{{- if .Values.gateway.labelsOverride }} +{{- tpl (.Values.gateway.labelsOverride | toYaml) . }} {{- else }} app.kubernetes.io/name: {{ include "apisix.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} @@ -80,16 +80,16 @@ Usage: {{- end -}} {{- define "apisix.basePluginAttrs" -}} -{{- if .Values.apisix.prometheus.enabled }} +{{- if .Values.serviceMonitor.enabled }} prometheus: export_addr: ip: 0.0.0.0 - port: {{ .Values.apisix.prometheus.containerPort }} - export_uri: {{ .Values.apisix.prometheus.path }} - metric_prefix: {{ .Values.apisix.prometheus.metricPrefix }} + port: {{ .Values.serviceMonitor.containerPort }} + export_uri: {{ .Values.serviceMonitor.path }} + metric_prefix: {{ .Values.serviceMonitor.metricPrefix }} {{- end }} -{{- if .Values.apisix.customPlugins.enabled }} -{{- range $plugin := .Values.apisix.customPlugins.plugins }} +{{- if .Values.customPlugins.enabled }} +{{- range $plugin := .Values.customPlugins.plugins }} {{- if $plugin.attrs }} {{ $plugin.name }}: {{- $plugin.attrs | toYaml | nindent 2 }} {{- end }} @@ -98,7 +98,7 @@ prometheus: {{- end -}} {{- define "apisix.pluginAttrs" -}} -{{- merge .Values.apisix.pluginAttrs (include "apisix.basePluginAttrs" . | fromYaml) | toYaml -}} +{{- merge .Values.pluginAttrs (include "apisix.basePluginAttrs" . | fromYaml) | toYaml -}} {{- end -}} {{/* @@ -113,25 +113,79 @@ Scheme to use while connecting etcd {{- end }} {{/* -Return the name of etcd password secret +Key to use to fetch admin token from secret */}} -{{- define "apisix.etcd.secretName" -}} -{{- if and .Values.etcd.enabled .Values.etcd.auth.rbac.create }} -{{- template "common.names.fullname" .Subcharts.etcd }} -{{- else if .Values.externalEtcd.existingSecret }} -{{- print .Values.externalEtcd.existingSecret }} -{{- else if .Values.externalEtcd.user }} -{{- printf "etcd-%s" (include "apisix.fullname" .) | trunc 63 | trimSuffix "-" }} +{{- define "apisix.admin.credentials.secretAdminKey" -}} +{{- if .Values.admin.credentials.secretAdminKey }} +{{- .Values.admin.credentials.secretAdminKey }} +{{- else }} +{{- "admin" }} +{{- end }} {{- end }} -{{- end -}} {{/* -Return the password key name of etcd secret +Key to use to fetch viewer token from secret */}} -{{- define "apisix.etcd.secretPasswordKey" -}} -{{- if .Values.etcd.enabled }} -{{- print "etcd-root-password" }} +{{- define "apisix.admin.credentials.secretViewerKey" -}} +{{- if .Values.admin.credentials.secretViewerKey }} +{{- .Values.admin.credentials.secretViewerKey }} {{- else }} -{{- print .Values.externalEtcd.secretPasswordKey }} +{{- "viewer" }} +{{- end }} +{{- end }} + +{{/* +Key to use to fetch username for external etcd from secret +*/}} +{{- define "apisix.etcd.credentials.userKey" -}} +{{- if .Values.etcd.existingSecretUserKey }} +{{- .Values.etcd.existingSecretUserKey | quote }} +{{- else }} +{{- "user" }} +{{- end }} +{{- end }} + +{{/* +Key to use to fetch password for external etcd from secret +*/}} +{{- define "apisix.etcd.credentials.passwordKey" -}} +{{- if .Values.etcd.existingSecretPasswordKey }} +{{- .Values.etcd.existingSecretPasswordKey | quote }} +{{- else }} +{{- "password" }} +{{- end }} +{{- end }} + +{{/* +Key to use to fetch root password for rbac +*/}} +{{- define "apisix.etcd.auth.rbac.passwordKey" -}} +{{- if .Values.etcd.auth.rbac.existingSecretPasswordKey }} +{{- .Values.etcd.auth.rbac.existingSecretPasswordKey | quote }} +{{- else }} +{{- "etcd-root-password" }} +{{- end }} +{{- end }} + +{{/* +Configuration of user and password for etcd +*/}} +{{- define "apisix.etcd.credentials.config" -}} +{{- if not .Values.etcd.enabled }} +{{- if .Values.etcd.existingSecret }} +user: "${{"{{"}}APISIX_ETCD_USER{{"}}"}}" +password: "${{"{{"}}APISIX_ETCD_PASSWORD{{"}}"}}" +{{- else if .Values.etcd.user }} +user: {{ .Values.etcd.user | quote }} +password: {{ .Values.etcd.password | quote }} +{{- end }} +{{- else if .Values.etcd.auth.rbac.create }} +{{- if .Values.etcd.auth.rbac.existingSecret }} +user: "root" +password: "${{"{{"}}APISIX_ETCD_PASSWORD{{"}}"}}" +{{- else }} +user: "root" +password: {{ .Values.etcd.auth.rbac.rootPassword | quote }} +{{- end }} +{{- end }} {{- end }} -{{- end -}} diff --git a/charts/apisix/templates/_pod.tpl b/charts/apisix/templates/_pod.tpl new file mode 100644 index 00000000..bfa55437 --- /dev/null +++ b/charts/apisix/templates/_pod.tpl @@ -0,0 +1,267 @@ +{{- define "apisix.podTemplate" -}} +metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.apisix.podAnnotations }} + {{ tpl (toYaml .) $ | nindent 4}} + {{- end }} + labels: + {{- include "apisix.selectorLabels" . | nindent 4 }} +spec: + {{- with .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- range $.Values.global.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + serviceAccountName: {{ include "apisix.serviceAccountName" . }} + {{- with .Values.apisix.podSecurityContext }} + securityContext: + {{- . | toYaml | nindent 4 }} + {{- end }} + {{- with .Values.apisix.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{- with .Values.apisix.securityContext }} + securityContext: + {{- . | toYaml | nindent 8 }} + {{- end }} + image: "{{ .Values.apisix.image.repository }}:{{ default .Chart.AppVersion .Values.apisix.image.tag }}" + {{- if eq .Values.deployment.mode "standalone" }} + command: ["sh", "-c","ln -s /apisix-config/apisix.yaml /usr/local/apisix/conf/apisix.yaml && /docker-entrypoint.sh docker-start"] + {{- end }} + imagePullPolicy: {{ .Values.apisix.image.pullPolicy }} + env: + {{- if .Values.apisix.timezone }} + - name: TZ + value: {{ .Values.apisix.timezone }} + {{- end }} + {{- if .Values.apisix.extraEnvVars }} + {{- include "apisix.tplvalues.render" (dict "value" .Values.apisix.extraEnvVars "context" $) | nindent 8 }} + {{- end }} + + {{- if .Values.admin.credentials.secretName }} + - name: APISIX_ADMIN_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.admin.credentials.secretName | quote }} + key: {{ include "apisix.admin.credentials.secretAdminKey" . }} + - name: APISIX_VIEWER_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.admin.credentials.secretName | quote }} + key: {{ include "apisix.admin.credentials.secretViewerKey" . }} + {{- end }} + {{- if and (not .Values.etcd.enabled) .Values.etcd.existingSecret }} + - name: APISIX_ETCD_USER + valueFrom: + secretKeyRef: + name: {{ .Values.etcd.existingSecret | quote }} + key: {{ include "apisix.etcd.credentials.userKey" . }} + - name: APISIX_ETCD_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.etcd.existingSecret | quote }} + key: {{ include "apisix.etcd.credentials.passwordKey" . }} + {{- end }} + {{- if and .Values.etcd.enabled .Values.etcd.auth.rbac.existingSecret }} + - name: APISIX_ETCD_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.etcd.auth.rbac.existingSecret | quote }} + key: {{ include "apisix.etcd.auth.rbac.passwordKey" . }} + {{- end }} + + ports: + - name: http + containerPort: {{ .Values.gateway.http.containerPort }} + protocol: TCP + {{- range .Values.gateway.http.additionalContainerPorts }} + - name: http-{{ .port | toString }} + containerPort: {{ .port }} + protocol: TCP + {{- end }} + - name: tls + containerPort: {{ .Values.gateway.tls.containerPort }} + protocol: TCP + {{- range .Values.gateway.tls.additionalContainerPorts }} + - name: tls-{{ .port | toString }} + containerPort: {{ .port }} + protocol: TCP + {{- end }} + {{- if .Values.admin.enabled }} + - name: admin + containerPort: {{ .Values.admin.port }} + protocol: TCP + {{- end }} + {{- if .Values.serviceMonitor.enabled }} + - name: prometheus + containerPort: {{ .Values.serviceMonitor.containerPort }} + protocol: TCP + {{- end }} + {{- if and .Values.gateway.stream.enabled (or (gt (len .Values.gateway.stream.tcp) 0) (gt (len .Values.gateway.stream.udp) 0)) }} + {{- with .Values.gateway.stream }} + {{- if (gt (len .tcp) 0) }} + {{- range $index, $port := .tcp }} + - name: proxy-tcp-{{ $index | toString }} + {{- if kindIs "map" $port }} + containerPort: {{ splitList ":" ($port.addr | toString) | last }} + {{- else }} + containerPort: {{ $port }} + {{- end }} + protocol: TCP + {{- end }} + {{- end }} + {{- if (gt (len .udp) 0) }} + {{- range $index, $port := .udp }} + - name: proxy-udp-{{ $index | toString }} + containerPort: {{ $port }} + protocol: UDP + {{- end }} + {{- end }} + {{- end }} + {{- end }} + + {{- if ne .Values.deployment.role "control_plane" }} + readinessProbe: + {{- toYaml .Values.apisix.readinessProbe | nindent 8 }} + {{- end }} + lifecycle: + preStop: + exec: + command: + - /bin/sh + - -c + - "sleep 30" + volumeMounts: + {{- if eq .Values.deployment.mode "standalone" }} + - mountPath: /apisix-config + name: apisix-admin + {{- end }} + {{- if .Values.apisix.setIDFromPodUID }} + - mountPath: /usr/local/apisix/conf/apisix.uid + name: id + subPath: apisix.uid + {{- end }} + - mountPath: /usr/local/apisix/conf/config.yaml + name: apisix-config + subPath: config.yaml + {{- if and .Values.gateway.tls.enabled .Values.gateway.tls.existingCASecret }} + - mountPath: /usr/local/apisix/conf/ssl/{{ .Values.gateway.tls.certCAFilename }} + name: ssl + subPath: {{ .Values.gateway.tls.certCAFilename }} + {{- end }} + + {{- if .Values.etcd.auth.tls.enabled }} + - mountPath: /etcd-ssl + name: etcd-ssl + {{- end }} + {{- if .Values.customPlugins.enabled }} + {{- range $plugin := .Values.customPlugins.plugins }} + {{- range $mount := $plugin.configMap.mounts }} + {{- if ne $plugin.configMap.name "" }} + - mountPath: {{ $mount.path }} + name: plugin-{{ $plugin.configMap.name }} + subPath: {{ $mount.key }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.apisix.luaModuleHook.enabled }} + {{- range $mount := .Values.apisix.luaModuleHook.configMapRef.mounts }} + - mountPath: {{ $mount.path }} + name: lua-module-hook + subPath: {{ $mount.key }} + {{- end }} + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 8 }} + {{- end }} + resources: + {{- toYaml .Values.apisix.resources | nindent 8 }} + {{- if .Values.apisix.hostNetwork }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + {{- end }} + hostNetwork: {{ .Values.apisix.hostNetwork }} + initContainers: + {{- if .Values.etcd.enabled }} + - name: wait-etcd + image: {{ .Values.initContainer.image }}:{{ .Values.initContainer.tag }} + {{- if .Values.etcd.fullnameOverride }} + command: ['sh', '-c', "until nc -z {{ .Values.etcd.fullnameOverride }} {{ .Values.etcd.service.port }}; do echo waiting for etcd `date`; sleep 2; done;"] + {{ else }} + command: ['sh', '-c', "until nc -z {{ .Release.Name }}-etcd.{{ .Release.Namespace }}.svc.{{ .Values.etcd.clusterDomain }} {{ .Values.etcd.service.port }}; do echo waiting for etcd `date`; sleep 2; done;"] + {{- end }} + {{- with .Values.initContainer.securityContext }} + securityContext: + {{- . | toYaml | nindent 8 }} + {{- end }} + + {{- end }} + {{- if .Values.extraInitContainers }} + {{- toYaml .Values.extraInitContainers | nindent 4 }} + {{- end }} + volumes: + {{- if eq .Values.deployment.mode "standalone" }} + - configMap: + name: apisix.yaml + name: apisix-admin + {{- end }} + - configMap: + name: {{ include "apisix.fullname" . }} + name: apisix-config + {{- if and .Values.gateway.tls.enabled .Values.gateway.tls.existingCASecret }} + - secret: + secretName: {{ .Values.gateway.tls.existingCASecret | quote }} + name: ssl + {{- end }} + {{- if .Values.etcd.auth.tls.enabled }} + - secret: + secretName: {{ .Values.etcd.auth.tls.existingSecret | quote }} + name: etcd-ssl + {{- end }} + {{- if .Values.apisix.setIDFromPodUID }} + - downwardAPI: + items: + - path: "apisix.uid" + fieldRef: + fieldPath: metadata.uid + name: id + {{- end }} + {{- if .Values.customPlugins.enabled }} + {{- range $plugin := .Values.customPlugins.plugins }} + {{- if ne $plugin.configMap.name "" }} + - name: plugin-{{ $plugin.configMap.name }} + configMap: + name: {{ $plugin.configMap.name }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.apisix.luaModuleHook.enabled }} + - name: lua-module-hook + configMap: + name: {{ .Values.apisix.luaModuleHook.configMapRef.name }} + {{- end }} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 4 }} + {{- end }} + {{- with .Values.apisix.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.apisix.affinity }} + affinity: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.apisix.tolerations }} + tolerations: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.apisix.topologySpreadConstraints }} + topologySpreadConstraints: + {{- tpl (. | toYaml) $ | nindent 4 }} + {{- end }} +{{- end -}} diff --git a/charts/apisix/templates/apisix-config-cm.yml b/charts/apisix/templates/apisix-config-configmap.yaml similarity index 93% rename from charts/apisix/templates/apisix-config-cm.yml rename to charts/apisix/templates/apisix-config-configmap.yaml index d76fe992..bcd297ac 100644 --- a/charts/apisix/templates/apisix-config-cm.yml +++ b/charts/apisix/templates/apisix-config-configmap.yaml @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if eq .Values.apisix.deployment.mode "standalone" }} +{{- if eq .Values.deployment.mode "standalone" }} kind: ConfigMap apiVersion: v1 metadata: @@ -29,4 +29,4 @@ data: "127.0.0.1:1980": 1 type: roundrobin #END -{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/apisix/templates/configmap.yaml b/charts/apisix/templates/configmap.yaml index e3917c6b..0edb553b 100644 --- a/charts/apisix/templates/configmap.yaml +++ b/charts/apisix/templates/configmap.yaml @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +{{- if .Values.apisix.enabled }} apiVersion: v1 kind: ConfigMap metadata: @@ -37,26 +38,30 @@ data: # See the License for the specific language governing permissions and # limitations under the License. # - {{- if .Values.apisix.fullCustomConfig.enabled }} - {{- range $key, $value := .Values.apisix.fullCustomConfig.config }} + {{- if .Values.apisix.enableCustomizedConfig }} + {{- range $key, $value := .Values.apisix.customizedConfig }} {{ $key }}: {{- include "apisix.tplvalues.render" (dict "value" $value "context" $) | nindent 6 }} {{- end }} {{- else }} apisix: # universal configurations - {{- if not (eq .Values.apisix.deployment.role "control_plane") }} + {{- if not (eq .Values.deployment.role "control_plane") }} node_listen: # APISIX listening port - - {{ .Values.service.http.containerPort }} - {{- with .Values.service.http.additionalContainerPorts }} + - {{ .Values.gateway.http.containerPort }} + {{- with .Values.gateway.http.additionalContainerPorts }} {{- toYaml . | nindent 8}} {{- end }} {{- end }} enable_heartbeat: true - enable_admin: {{ .Values.apisix.admin.enabled }} - enable_admin_cors: {{ .Values.apisix.admin.cors }} + {{- if eq .Values.deployment.mode "standalone" }} + enable_admin: false + {{ else }} + enable_admin: {{ .Values.admin.enabled }} + {{- end }} + enable_admin_cors: {{ .Values.admin.cors }} enable_debug: false - {{- if or .Values.apisix.customPlugins.enabled .Values.apisix.luaModuleHook.enabled }} - extra_lua_path: {{ .Values.apisix.customPlugins.luaPath }};{{ .Values.apisix.luaModuleHook.luaPath }} + {{- if or .Values.customPlugins.enabled .Values.apisix.luaModuleHook.enabled }} + extra_lua_path: {{ .Values.customPlugins.luaPath }};{{ .Values.apisix.luaModuleHook.luaPath }} {{- end }} {{- if .Values.apisix.luaModuleHook.enabled }} @@ -68,14 +73,16 @@ data: enable_ipv6: {{ .Values.apisix.enableIPv6 }} # Enable nginx IPv6 resolver enable_server_tokens: {{ .Values.apisix.enableServerTokens }} # Whether the APISIX version number should be shown in Server header - # proxy_protocol: # Proxy Protocol configuration - # listen_http_port: 9181 # The port with proxy protocol for http, it differs from node_listen and admin_listen. - # # This port can only receive http request with proxy protocol, but node_listen & admin_listen - # # can only receive http request. If you enable proxy protocol, you must use this port to - # # receive http request with proxy protocol - # listen_https_port: 9182 # The port with proxy protocol for https - # enable_tcp_pp: true # Enable the proxy protocol for tcp proxy, it works for stream_proxy.tcp option - # enable_tcp_pp_to_upstream: true # Enables the proxy protocol to the upstream server + {{- if .Values.apisix.proxyProtocol.enabled }} + proxy_protocol: # Proxy Protocol configuration + listen_http_port: {{ .Values.apisix.proxyProtocol.listenHttpPort }} # The port with proxy protocol for http, it differs from node_listen and port_admin. + # This port can only receive http request with proxy protocol, but node_listen & port_admin + # can only receive http request. If you enable proxy protocol, you must use this port to + # receive http request with proxy protocol + listen_https_port: {{ .Values.apisix.proxyProtocol.listenHttpsPort }} # The port with proxy protocol for https + enable_tcp_pp: {{ .Values.apisix.proxyProtocol.tcp }} # Enable the proxy protocol for tcp proxy, it works for stream_proxy.tcp option + enable_tcp_pp_to_upstream: {{ .Values.apisix.proxyProtocol.upstream }} # Enable the proxy protocol to the upstream server + {{- end }} proxy_cache: # Proxy Caching configuration cache_ttl: 10s # The default caching time if the upstream does not specify the cache time @@ -93,28 +100,28 @@ data: # cache_levels: "1:2" router: - http: {{ .Values.apisix.router.http }} # radixtree_uri: match route by uri(base on radixtree) + http: {{ .Values.apisix.httpRouter }} # radixtree_uri: match route by uri(base on radixtree) # radixtree_host_uri: match route by host + uri(base on radixtree) # radixtree_uri_with_parameter: match route by uri with parameters ssl: 'radixtree_sni' # radixtree_sni: match route by SNI(base on radixtree) - + {{- $proxy_mode := "" }} - {{- if and .Values.service.stream.enabled .Values.service.http.enabled }} + {{- if and .Values.gateway.stream.enabled .Values.gateway.http.enabled }} {{- $proxy_mode = "http&stream" }} - {{- else if .Values.service.http.enabled }} + {{- else if .Values.gateway.http.enabled }} {{- $proxy_mode = "http" }} - {{- else if .Values.service.stream.enabled }} + {{- else if .Values.gateway.stream.enabled }} {{- $proxy_mode = "stream" }} {{- end }} proxy_mode: {{ $proxy_mode }} - {{- if or (index .Values "ingress-controller" "enabled") (and .Values.service.stream.enabled (or (gt (len .Values.service.stream.tcp) 0) (gt (len .Values.service.stream.udp) 0))) }} + {{- if or (index .Values "ingress-controller" "enabled") (and .Values.gateway.stream.enabled (or (gt (len .Values.gateway.stream.tcp) 0) (gt (len .Values.gateway.stream.udp) 0))) }} stream_proxy: # TCP/UDP proxy - {{- if or (index .Values "ingress-controller" "enabled") (gt (len .Values.service.stream.tcp) 0) }} + {{- if or (index .Values "ingress-controller" "enabled") (gt (len .Values.gateway.stream.tcp) 0) }} tcp: # TCP proxy port list - {{- if gt (len .Values.service.stream.tcp) 0}} - {{- range .Values.service.stream.tcp }} + {{- if gt (len .Values.gateway.stream.tcp) 0}} + {{- range .Values.gateway.stream.tcp }} {{- if kindIs "map" . }} - addr: {{ .addr }} {{- if hasKey . "tls" }} @@ -128,10 +135,10 @@ data: - 9100 {{- end }} {{- end }} - {{- if or (index .Values "ingress-controller" "enabled") (gt (len .Values.service.stream.udp) 0) }} + {{- if or (index .Values "ingress-controller" "enabled") (gt (len .Values.gateway.stream.udp) 0) }} udp: # UDP proxy port list - {{- if gt (len .Values.service.stream.udp) 0}} - {{- range .Values.service.stream.udp }} + {{- if gt (len .Values.gateway.stream.udp) 0}} + {{- range .Values.gateway.stream.udp }} - {{ . }} {{- end }} {{- else}} @@ -140,50 +147,61 @@ data: {{- end }} {{- end }} # dns_resolver: - # {{- range $resolver := .Values.apisix.dns.resolvers }} + # {{- range $resolver := .Values.dns.resolvers }} # - {{ $resolver }} # {{- end }} - dns_resolver_valid: {{.Values.apisix.dns.validity}} - resolver_timeout: {{.Values.apisix.dns.timeout}} + dns_resolver_valid: {{.Values.dns.validity}} + resolver_timeout: {{.Values.dns.timeout}} ssl: - enable: {{ .Values.apisix.ssl.enabled }} + enable: {{ .Values.gateway.tls.enabled }} listen: - - port: {{ .Values.apisix.ssl.containerPort }} - enable_http2: {{ .Values.apisix.ssl.http2.enabled }} - {{- with .Values.apisix.ssl.additionalContainerPorts }} + - port: {{ .Values.gateway.tls.containerPort }} + enable_http2: {{ .Values.gateway.tls.http2.enabled }} + {{- with .Values.gateway.tls.additionalContainerPorts }} {{- toYaml . | nindent 10}} {{- end }} - ssl_protocols: {{ .Values.apisix.ssl.sslProtocols | quote }} + ssl_protocols: {{ .Values.gateway.tls.sslProtocols | quote }} 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:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" - {{- if and .Values.apisix.ssl.enabled .Values.apisix.ssl.existingCASecret }} - ssl_trusted_certificate: "/usr/local/apisix/conf/ssl/{{ .Values.apisix.ssl.certCAFilename }}" + {{- if and .Values.gateway.tls.enabled .Values.gateway.tls.existingCASecret }} + ssl_trusted_certificate: "/usr/local/apisix/conf/ssl/{{ .Values.gateway.tls.certCAFilename }}" {{- end }} - {{- if and .Values.apisix.ssl.enabled .Values.apisix.ssl.fallbackSNI }} - fallback_sni: {{ .Values.apisix.ssl.fallbackSNI | quote }} + {{- if and .Values.gateway.tls.enabled .Values.gateway.tls.fallbackSNI }} + fallback_sni: {{ .Values.gateway.tls.fallbackSNI | quote }} {{- end }} + {{- if .Values.apisix.data_encryption.enabled }} + data_encryption: + enable: true + keyring: + {{- range .Values.apisix.data_encryption.keyring }} + - {{ . }} + {{ end }} + {{- end }} + nginx_config: # config for render the template to genarate nginx.conf - error_log: "{{ .Values.apisix.nginx.logs.errorLog }}" - error_log_level: "{{ .Values.apisix.nginx.logs.errorLogLevel }}" # warn,error - worker_processes: "{{ .Values.apisix.nginx.workerProcesses }}" - enable_cpu_affinity: {{ and true .Values.apisix.nginx.enableCPUAffinity }} - worker_rlimit_nofile: {{ default "20480" .Values.apisix.nginx.workerRlimitNofile }} # the number of files a worker process can open, should be larger than worker_connections + error_log: "{{ .Values.logs.errorLog }}" + error_log_level: "{{ .Values.logs.errorLogLevel }}" # warn,error + worker_processes: "{{ .Values.nginx.workerProcesses }}" + enable_cpu_affinity: {{ and true .Values.nginx.enableCPUAffinity }} + worker_rlimit_nofile: {{ default "20480" .Values.nginx.workerRlimitNofile }} # the number of files a worker process can open, should be larger than worker_connections event: - worker_connections: {{ default "10620" .Values.apisix.nginx.workerConnections }} - {{- with .Values.apisix.nginx.envs }} + worker_connections: {{ default "10620" .Values.nginx.workerConnections }} + meta: + {{- .Values.nginx.meta | nindent 8 }} + {{- with .Values.nginx.envs }} envs: {{- range $env := . }} - {{ $env }} {{- end }} {{- end }} http: - enable_access_log: {{ .Values.apisix.nginx.logs.enableAccessLog }} - {{- if .Values.apisix.nginx.logs.enableAccessLog }} - access_log: "{{ .Values.apisix.nginx.logs.accessLog }}" - access_log_format: '{{ .Values.apisix.nginx.logs.accessLogFormat }}' - access_log_format_escape: {{ .Values.apisix.nginx.logs.accessLogFormatEscape }} + enable_access_log: {{ .Values.logs.enableAccessLog }} + {{- if .Values.logs.enableAccessLog }} + access_log: "{{ .Values.logs.accessLog }}" + access_log_format: '{{ .Values.logs.accessLogFormat }}' + access_log_format_escape: {{ .Values.logs.accessLogFormatEscape }} {{- end }} - keepalive_timeout: {{ .Values.apisix.nginx.keepaliveTimeout | quote }} + keepalive_timeout: 60s # timeout during which a keep-alive client connection will stay open on the server side. client_header_timeout: 60s # timeout for reading client request header, then 408 (Request Time-out) error is returned to the client client_body_timeout: 60s # timeout for reading client request body, then 408 (Request Time-out) error is returned to the client send_timeout: 10s # timeout for transmitting a response to the client.then the connection is closed @@ -192,34 +210,34 @@ data: real_ip_from: # http://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from - 127.0.0.1 - 'unix:' - {{- if .Values.apisix.nginx.customLuaSharedDicts }} + {{- if .Values.apisix.customLuaSharedDicts }} custom_lua_shared_dict: # add custom shared cache to nginx.conf - {{- range $dict := .Values.apisix.nginx.customLuaSharedDicts }} + {{- range $dict := .Values.apisix.customLuaSharedDicts }} {{ $dict.name }}: {{ $dict.size }} {{- end }} {{- end }} - {{- if .Values.apisix.nginx.configurationSnippet.main }} - main_configuration_snippet: {{- toYaml .Values.apisix.nginx.configurationSnippet.main | indent 6 }} + {{- if .Values.configurationSnippet.main }} + main_configuration_snippet: {{- toYaml .Values.configurationSnippet.main | indent 6 }} {{- end }} - {{- if .Values.apisix.nginx.configurationSnippet.httpStart }} - http_configuration_snippet: {{- toYaml .Values.apisix.nginx.configurationSnippet.httpStart | indent 6 }} + {{- if .Values.configurationSnippet.httpStart }} + http_configuration_snippet: {{- toYaml .Values.configurationSnippet.httpStart | indent 6 }} {{- end }} - {{- if .Values.apisix.nginx.configurationSnippet.httpEnd }} - http_end_configuration_snippet: {{- toYaml .Values.apisix.nginx.configurationSnippet.httpEnd | indent 6 }} + {{- if .Values.configurationSnippet.httpEnd }} + http_end_configuration_snippet: {{- toYaml .Values.configurationSnippet.httpEnd | indent 6 }} {{- end }} - {{- if .Values.apisix.nginx.configurationSnippet.httpSrv }} - http_server_configuration_snippet: {{- toYaml .Values.apisix.nginx.configurationSnippet.httpSrv | indent 6 }} + {{- if .Values.configurationSnippet.httpSrv }} + http_server_configuration_snippet: {{- toYaml .Values.configurationSnippet.httpSrv | indent 6 }} {{- end }} - {{- if .Values.apisix.nginx.configurationSnippet.httpAdmin }} - http_admin_configuration_snippet: {{ toYaml .Values.apisix.nginx.configurationSnippet.httpAdmin | indent 6 }} + {{- if .Values.configurationSnippet.httpAdmin }} + http_admin_configuration_snippet: {{ toYaml .Values.configurationSnippet.httpAdmin | indent 6 }} {{- end }} - {{- if .Values.apisix.nginx.configurationSnippet.stream }} - stream_configuration_snippet: {{- toYaml .Values.apisix.nginx.configurationSnippet.stream | indent 6 }} + {{- if .Values.configurationSnippet.stream }} + stream_configuration_snippet: {{- toYaml .Values.configurationSnippet.stream | indent 6 }} {{- end }} - {{- if .Values.apisix.discovery.enabled }} + {{- if .Values.discovery.enabled }} discovery: - {{- range $key, $value := .Values.apisix.discovery.registry }} + {{- range $key, $value := .Values.discovery.registry }} {{- if $value }} {{ $key }}: {{- include "apisix.tplvalues.render" (dict "value" $value "context" $) | nindent 8 }} @@ -229,80 +247,81 @@ data: {{- end }} {{- end }} - {{- if .Values.apisix.vault.enabled }} + {{- if .Values.vault.enabled }} vault: - host: {{ .Values.apisix.vault.host }} - timeout: {{ .Values.apisix.vault.timeout }} - token: {{ .Values.apisix.vault.token }} - prefix: {{ .Values.apisix.vault.prefix }} + host: {{ .Values.vault.host }} + timeout: {{ .Values.vault.timeout }} + token: {{ .Values.vault.token }} + prefix: {{ .Values.vault.prefix }} {{- end }} - {{- if .Values.apisix.plugins }} + {{- if .Values.plugins }} plugins: # plugin list - {{- range $plugin := .Values.apisix.plugins }} + {{- range $plugin := .Values.plugins }} {{- if ne $plugin "" }} - {{ $plugin }} {{- end }} {{- end }} - {{- if .Values.apisix.customPlugins.enabled }} - {{- range $plugin := .Values.apisix.customPlugins.plugins }} + {{- if .Values.customPlugins.enabled }} + {{- range $plugin := .Values.customPlugins.plugins }} - {{ $plugin.name }} {{- end }} {{- end }} {{- end }} - {{- if .Values.apisix.stream_plugins }} + {{- if .Values.stream_plugins }} stream_plugins: - {{- range $plugin := .Values.apisix.stream_plugins }} + {{- range $plugin := .Values.stream_plugins }} {{- if ne $plugin "" }} - {{ $plugin }} {{- end }} {{- end }} {{- end }} - {{- if .Values.apisix.extPlugin.enabled }} + {{- if .Values.extPlugin.enabled }} ext-plugin: cmd: - {{- range $arg := .Values.apisix.extPlugin.cmd }} + {{- range $arg := .Values.extPlugin.cmd }} - {{ $arg }} {{- end }} {{- end }} - {{- if or .Values.apisix.pluginAttrs .Values.apisix.customPlugins.enabled .Values.apisix.prometheus.enabled}} + {{- if or .Values.pluginAttrs .Values.customPlugins.enabled .Values.serviceMonitor.enabled}} {{- $pluginAttrs := include "apisix.pluginAttrs" . -}} {{- if gt (len ($pluginAttrs | fromYaml)) 0 }} plugin_attr: {{- $pluginAttrs | nindent 6 }} {{- end }} {{- end }} - {{- if .Values.apisix.wasm.enabled }} + {{- if .Values.wasmPlugins.enabled }} wasm: plugins: - {{- toYaml .Values.apisix.wasm.plugins | nindent 8 }} + {{- toYaml .Values.wasmPlugins.plugins | nindent 8 }} {{- end }} deployment: - role: {{ .Values.apisix.deployment.role }} + role: {{ .Values.deployment.role }} - {{- if eq .Values.apisix.deployment.role "traditional" }} + {{- if eq .Values.deployment.role "traditional" }} role_traditional: config_provider: etcd {{- end }} - {{- if eq .Values.apisix.deployment.role "control_plane" }} + {{- if eq .Values.deployment.role "control_plane" }} role_control_plane: config_provider: etcd {{- end }} - {{- if eq .Values.apisix.deployment.role "data_plane" }} + + {{- if eq .Values.deployment.role "data_plane" }} role_data_plane: - config_provider: {{- eq .Values.apisix.deployment.mode "standalone" | ternary "yaml" "etcd" | indent 1 }} + config_provider: {{- eq .Values.deployment.mode "standalone" | ternary "yaml" "etcd" | indent 1 }} {{- end }} - {{- if not (eq .Values.apisix.deployment.role "data_plane") }} + {{- if not (eq .Values.deployment.role "data_plane") }} admin: allow_admin: # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow - {{- if .Values.apisix.admin.allow.ipList }} - {{- range $ips := .Values.apisix.admin.allow.ipList }} + {{- if .Values.admin.allow.ipList }} + {{- range $ips := .Values.admin.allow.ipList }} - {{ $ips }} {{- end }} {{- else }} @@ -312,10 +331,10 @@ data: - 0.0.0.0/0 {{- end}} # - "::/64" - {{- if .Values.apisix.admin.enabled }} + {{- if .Values.admin.enabled }} admin_listen: - ip: {{ .Values.apisix.admin.ip }} - port: {{ .Values.apisix.admin.port }} + ip: {{ .Values.admin.ip }} + port: {{ .Values.admin.port }} {{- end }} # Default token when use API to call for Admin API. # *NOTE*: Highly recommended to modify this value to protect APISIX's Admin API. @@ -324,22 +343,22 @@ data: admin_key: # admin: can everything for configuration data - name: "admin" - {{- if .Values.apisix.admin.credentials.secretName }} + {{- if .Values.admin.credentials.secretName }} key: ${{"{{"}}APISIX_ADMIN_KEY{{"}}"}} {{- else }} - key: {{ .Values.apisix.admin.credentials.admin }} + key: {{ .Values.admin.credentials.admin }} {{- end }} role: admin # viewer: only can view configuration data - name: "viewer" - {{- if .Values.apisix.admin.credentials.secretName }} + {{- if .Values.admin.credentials.secretName }} key: ${{"{{"}}APISIX_VIEWER_KEY{{"}}"}} {{- else }} - key: {{ .Values.apisix.admin.credentials.viewer }} + key: {{ .Values.admin.credentials.viewer }} {{- end }} role: viewer {{- end }} - {{- if not (eq .Values.apisix.deployment.mode "standalone")}} + {{- if not (eq .Values.deployment.mode "standalone")}} etcd: {{- if .Values.etcd.enabled }} host: # it's possible to define multiple etcd hosts addresses of the same etcd cluster. @@ -350,19 +369,13 @@ data: {{- end}} {{- else }} host: # it's possible to define multiple etcd hosts addresses of the same etcd cluster. - {{- range $value := .Values.externalEtcd.host }} + {{- range $value := .Values.etcd.host }} - "{{ $value }}" # multiple etcd address {{- end}} {{- end }} prefix: {{ .Values.etcd.prefix | quote }} # configuration prefix in etcd timeout: {{ .Values.etcd.timeout }} # 30 seconds - {{- if and (not .Values.etcd.enabled) .Values.externalEtcd.user }} - user: {{ .Values.externalEtcd.user | quote }} - password: "{{ print "${{ APISIX_ETCD_PASSWORD }}" }}" - {{- else if and .Values.etcd.enabled .Values.etcd.auth.rbac.create }} - user: "root" - password: "{{ print "${{APISIX_ETCD_PASSWORD}}" }}" - {{- end }} + {{- include "apisix.etcd.credentials.config" . | nindent 8 }} {{- if .Values.etcd.auth.tls.enabled }} tls: cert: "/etcd-ssl/{{ .Values.etcd.auth.tls.certFilename }}" @@ -372,4 +385,6 @@ data: {{- end }} {{- end }} {{- end }} - + + +{{- end }} diff --git a/charts/apisix/templates/daemonset.yaml b/charts/apisix/templates/daemonset.yaml new file mode 100644 index 00000000..b22a775a --- /dev/null +++ b/charts/apisix/templates/daemonset.yaml @@ -0,0 +1,33 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +{{- if and (.Values.apisix.enabled) (eq .Values.apisix.kind "DaemonSet") }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "apisix.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "apisix.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "apisix.selectorLabels" . | nindent 6 }} + {{- if .Values.updateStrategy }} + updateStrategy: {{ toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} + template: + {{- include "apisix.podTemplate" . | nindent 4 }} +{{- end }} diff --git a/charts/apisix/templates/deployment.yaml b/charts/apisix/templates/deployment.yaml index 2a92928c..8ce2fcbf 100644 --- a/charts/apisix/templates/deployment.yaml +++ b/charts/apisix/templates/deployment.yaml @@ -13,282 +13,24 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +{{- if and (.Values.apisix.enabled) (eq .Values.apisix.kind "Deployment") }} apiVersion: apps/v1 -kind: {{ ternary "DaemonSet" "Deployment" .Values.useDaemonSet }} +kind: Deployment metadata: name: {{ include "apisix.fullname" . }} namespace: {{ .Release.Namespace }} labels: {{- include "apisix.labels" . | nindent 4 }} spec: -{{- if and (not .Values.useDaemonSet) (not .Values.autoscaling.enabled) }} - replicas: {{ .Values.replicaCount }} +{{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.apisix.replicaCount }} {{- end }} selector: matchLabels: {{- include "apisix.selectorLabels" . | nindent 6 }} {{- if .Values.updateStrategy }} - {{- if (not .Values.useDaemonSet) }} strategy: {{ toYaml .Values.updateStrategy | nindent 4 }} - {{- else }} - updateStrategy: {{ toYaml .Values.updateStrategy | nindent 4 }} - {{- end }} {{- end }} template: - metadata: - annotations: - checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} - {{- if .Values.podAnnotations }} - {{- range $key, $value := $.Values.podAnnotations }} - {{ $key }}: {{ $value | quote }} - {{- end }} - {{- end }} - labels: - {{- include "apisix.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.global.imagePullSecrets }} - imagePullSecrets: - {{- range $.Values.global.imagePullSecrets }} - - name: {{ . }} - {{- end }} - {{- end }} - serviceAccountName: {{ include "apisix.serviceAccountName" . }} - {{- with .Values.podSecurityContext }} - securityContext: - {{- . | toYaml | nindent 8 }} - {{- end }} - {{- with .Values.priorityClassName }} - priorityClassName: {{ . }} - {{- end }} - containers: - - name: {{ .Chart.Name }} - {{- with .Values.securityContext }} - securityContext: - {{- . | toYaml | nindent 12 }} - {{- end }} - image: "{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }}" - {{- if eq .Values.apisix.deployment.mode "standalone" }} - command: ["sh", "-c","ln -s /apisix-config/apisix.yaml /usr/local/apisix/conf/apisix.yaml && /docker-entrypoint.sh docker-start"] - {{- end }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: - {{- if .Values.timezone }} - - name: TZ - value: {{ .Values.timezone }} - {{- end }} - {{- if .Values.extraEnvVars }} - {{- include "apisix.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - - {{- if .Values.apisix.admin.credentials.secretName }} - - name: APISIX_ADMIN_KEY - valueFrom: - secretKeyRef: - name: {{ .Values.apisix.admin.credentials.secretName }} - key: admin - - name: APISIX_VIEWER_KEY - valueFrom: - secretKeyRef: - name: {{ .Values.apisix.admin.credentials.secretName }} - key: viewer - {{- end }} - - {{- if or (and .Values.etcd.enabled .Values.etcd.auth.rbac.create) (and (not .Values.etcd.enabled) .Values.externalEtcd.user) }} - - name: APISIX_ETCD_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "apisix.etcd.secretName" . }} - key: {{ include "apisix.etcd.secretPasswordKey" . }} - {{- end }} - - ports: - - name: http - containerPort: {{ .Values.service.http.containerPort }} - protocol: TCP - {{- range .Values.service.http.additionalContainerPorts }} - - name: http-{{ .port | toString }} - containerPort: {{ .port }} - protocol: TCP - {{- end }} - - name: tls - containerPort: {{ .Values.apisix.ssl.containerPort }} - protocol: TCP - {{- range .Values.apisix.ssl.additionalContainerPorts }} - - name: tls-{{ .port | toString }} - containerPort: {{ .port }} - protocol: TCP - {{- end }} - {{- if .Values.apisix.admin.enabled }} - - name: admin - containerPort: {{ .Values.apisix.admin.port }} - protocol: TCP - {{- end }} - {{- if .Values.apisix.prometheus.enabled }} - - name: prometheus - containerPort: {{ .Values.apisix.prometheus.containerPort }} - protocol: TCP - {{- end }} - {{- if and .Values.service.stream.enabled (or (gt (len .Values.service.stream.tcp) 0) (gt (len .Values.service.stream.udp) 0)) }} - {{- with .Values.service.stream }} - {{- if (gt (len .tcp) 0) }} - {{- range $index, $port := .tcp }} - - name: proxy-tcp-{{ $index | toString }} - {{- if kindIs "map" $port }} - containerPort: {{ splitList ":" ($port.addr | toString) | last }} - {{- else }} - containerPort: {{ $port }} - {{- end }} - protocol: TCP - {{- end }} - {{- end }} - {{- if (gt (len .udp) 0) }} - {{- range $index, $port := .udp }} - - name: proxy-udp-{{ $index | toString }} - containerPort: {{ $port }} - protocol: UDP - {{- end }} - {{- end }} - {{- end }} - {{- end }} - - {{- if ne .Values.apisix.deployment.role "control_plane" }} - readinessProbe: - failureThreshold: 6 - initialDelaySeconds: 10 - periodSeconds: 10 - successThreshold: 1 - tcpSocket: - port: {{ .Values.service.http.containerPort }} - timeoutSeconds: 1 - {{- end }} - lifecycle: - preStop: - exec: - command: - - /bin/sh - - -c - - "sleep 30" - volumeMounts: - {{- if eq .Values.apisix.deployment.mode "standalone" }} - - mountPath: /apisix-config - name: apisix-admin - {{- end }} - {{- if .Values.apisix.setIDFromPodUID }} - - mountPath: /usr/local/apisix/conf/apisix.uid - name: id - subPath: apisix.uid - {{- end }} - - mountPath: /usr/local/apisix/conf/config.yaml - name: apisix-config - subPath: config.yaml - {{- if and .Values.apisix.ssl.enabled .Values.apisix.ssl.existingCASecret }} - - mountPath: /usr/local/apisix/conf/ssl/{{ .Values.apisix.ssl.certCAFilename }} - name: ssl - subPath: {{ .Values.apisix.ssl.certCAFilename }} - {{- end }} - - {{- if .Values.etcd.auth.tls.enabled }} - - mountPath: /etcd-ssl - name: etcd-ssl - {{- end }} - {{- if .Values.apisix.customPlugins.enabled }} - {{- range $plugin := .Values.apisix.customPlugins.plugins }} - {{- range $mount := $plugin.configMap.mounts }} - {{- if ne $plugin.configMap.name "" }} - - mountPath: {{ $mount.path }} - name: plugin-{{ $plugin.configMap.name }} - subPath: {{ $mount.key }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.apisix.luaModuleHook.enabled }} - {{- range $mount := .Values.apisix.luaModuleHook.configMapRef.mounts }} - - mountPath: {{ $mount.path }} - name: lua-module-hook - subPath: {{ $mount.key }} - {{- end }} - {{- end }} - {{- if .Values.extraVolumeMounts }} - {{- toYaml .Values.extraVolumeMounts | nindent 12 }} - {{- end }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- if .Values.extraContainers }} - {{- toYaml .Values.extraContainers | nindent 8 }} - {{- end }} - {{- if .Values.hostNetwork }} - hostNetwork: true - dnsPolicy: ClusterFirstWithHostNet - {{- end }} - hostNetwork: {{ .Values.hostNetwork }} - initContainers: - {{- if .Values.etcd.enabled }} - - name: wait-etcd - image: {{ .Values.initContainer.image }}:{{ .Values.initContainer.tag }} - {{- if .Values.etcd.fullnameOverride }} - command: ['sh', '-c', "until nc -z {{ .Values.etcd.fullnameOverride }} {{ .Values.etcd.service.port }}; do echo waiting for etcd `date`; sleep 2; done;"] - {{ else }} - command: ['sh', '-c', "until nc -z {{ .Release.Name }}-etcd.{{ .Release.Namespace }}.svc.{{ .Values.etcd.clusterDomain }} {{ .Values.etcd.service.port }}; do echo waiting for etcd `date`; sleep 2; done;"] - {{- end }} - {{- end }} - {{- if .Values.extraInitContainers }} - {{- toYaml .Values.extraInitContainers | nindent 8 }} - {{- end }} - volumes: - {{- if eq .Values.apisix.deployment.mode "standalone" }} - - configMap: - name: apisix.yaml - name: apisix-admin - {{- end }} - - configMap: - name: {{ include "apisix.fullname" . }} - name: apisix-config - {{- if and .Values.apisix.ssl.enabled .Values.apisix.ssl.existingCASecret }} - - secret: - secretName: {{ .Values.apisix.ssl.existingCASecret | quote }} - name: ssl - {{- end }} - {{- if .Values.etcd.auth.tls.enabled }} - - secret: - secretName: {{ .Values.etcd.auth.tls.existingSecret | quote }} - name: etcd-ssl - {{- end }} - - {{- if .Values.apisix.setIDFromPodUID }} - - downwardAPI: - items: - - path: "apisix.uid" - fieldRef: - fieldPath: metadata.uid - name: id - {{- end }} - {{- if .Values.apisix.customPlugins.enabled }} - {{- range $plugin := .Values.apisix.customPlugins.plugins }} - {{- if ne $plugin.configMap.name "" }} - - name: plugin-{{ $plugin.configMap.name }} - configMap: - name: {{ $plugin.configMap.name }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.apisix.luaModuleHook.enabled }} - - name: lua-module-hook - configMap: - name: {{ .Values.apisix.luaModuleHook.configMapRef.name }} - {{- end }} - {{- if .Values.extraVolumes }} - {{- toYaml .Values.extraVolumes | nindent 8 }} - {{- end }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} + {{- include "apisix.podTemplate" . | nindent 4 }} +{{- end }} diff --git a/charts/apisix/templates/etcd-secret.yaml b/charts/apisix/templates/etcd-secret.yaml deleted file mode 100644 index ffc15d88..00000000 --- a/charts/apisix/templates/etcd-secret.yaml +++ /dev/null @@ -1,10 +0,0 @@ -{{- if and .Values.externalEtcd.user (and (not .Values.etcd.enabled) (not .Values.externalEtcd.existingSecret)) }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "apisix.etcd.secretName" . }} - namespace: {{ .Release.Namespace }} -type: Opaque -data: - {{ .Values.externalEtcd.secretPasswordKey }}: {{ .Values.externalEtcd.password | b64enc | quote }} -{{- end }} diff --git a/charts/apisix/templates/extra-list.yaml b/charts/apisix/templates/extra-list.yaml deleted file mode 100644 index 36754065..00000000 --- a/charts/apisix/templates/extra-list.yaml +++ /dev/null @@ -1,8 +0,0 @@ -{{- range .Values.extraDeploy }} ---- -{{- if typeIs "string" . }} - {{- tpl . $ }} -{{- else }} - {{- tpl (. | toYaml) $ }} -{{- end }} -{{- end }} diff --git a/charts/apisix/templates/hpa.yaml b/charts/apisix/templates/hpa.yaml index db3acc56..c994c881 100644 --- a/charts/apisix/templates/hpa.yaml +++ b/charts/apisix/templates/hpa.yaml @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if .Values.autoscaling.enabled }} +{{- if and .Values.apisix.enabled .Values.autoscaling.enabled }} apiVersion: autoscaling/{{ .Values.autoscaling.version }} kind: HorizontalPodAutoscaler diff --git a/charts/apisix/templates/ingress-admin.yaml b/charts/apisix/templates/ingress-admin.yaml index 45b8747e..8d5e3ffb 100644 --- a/charts/apisix/templates/ingress-admin.yaml +++ b/charts/apisix/templates/ingress-admin.yaml @@ -14,12 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (and .Values.apisix.admin.enabled .Values.apisix.admin.ingress.enabled) -}} +{{- if (and .Values.admin.enabled .Values.admin.ingress.enabled) -}} {{- $fullName := include "apisix.fullname" . -}} -{{- $svcPort := .Values.apisix.admin.servicePort -}} -{{- if and .Values.apisix.admin.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} - {{- if not (hasKey .Values.apisix.admin.ingress.annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .Values.apisix.admin.ingress.annotations "kubernetes.io/ingress.class" .Values.apisix.admin.ingress.className}} +{{- $svcPort := .Values.admin.servicePort -}} +{{- if and .Values.admin.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.admin.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.admin.ingress.annotations "kubernetes.io/ingress.class" .Values.admin.ingress.className}} {{- end }} {{- end }} {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.Version }} @@ -34,17 +34,17 @@ metadata: name: {{ $fullName }}-admin labels: {{- include "apisix.labels" . | nindent 4 }} - {{- with .Values.apisix.admin.ingress.annotations }} + {{- with .Values.admin.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} spec: - {{- if and .Values.apisix.admin.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} - ingressClassName: {{ .Values.apisix.admin.ingress.className }} + {{- if and .Values.admin.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.admin.ingress.className }} {{- end }} - {{- if .Values.apisix.admin.ingress.tls }} + {{- if .Values.admin.ingress.tls }} tls: - {{- range .Values.apisix.admin.ingress.tls }} + {{- range .Values.admin.ingress.tls }} - hosts: {{- range .hosts }} - {{ . | quote }} @@ -53,7 +53,7 @@ spec: {{- end }} {{- end }} rules: - {{- range .Values.apisix.admin.ingress.hosts }} + {{- range .Values.admin.ingress.hosts }} - host: {{ .host | quote }} http: paths: diff --git a/charts/apisix/templates/ingress.yaml b/charts/apisix/templates/ingress.yaml index c8a9b819..7ab33472 100644 --- a/charts/apisix/templates/ingress.yaml +++ b/charts/apisix/templates/ingress.yaml @@ -14,12 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (.Values.ingress.enabled) -}} +{{- if (and .Values.apisix.enabled .Values.gateway.ingress.enabled) -}} {{- $fullName := include "apisix.fullname" . -}} -{{- $svcPort := .Values.ingress.servicePort | default .Values.service.http.servicePort -}} -{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} - {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} +{{- $svcPort := .Values.gateway.http.servicePort -}} +{{- if and .Values.gateway.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.gateway.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.gateway.ingress.annotations "kubernetes.io/ingress.class" .Values.gateway.ingress.className}} {{- end }} {{- end }} {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.Version }} @@ -34,17 +34,17 @@ metadata: name: {{ $fullName }} labels: {{- include "apisix.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} + {{- with .Values.gateway.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} spec: - {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} - ingressClassName: {{ .Values.ingress.className }} + {{- if and .Values.gateway.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.gateway.ingress.className }} {{- end }} - {{- if .Values.ingress.tls }} + {{- if .Values.gateway.ingress.tls }} tls: - {{- range .Values.ingress.tls }} + {{- range .Values.gateway.ingress.tls }} - hosts: {{- range .hosts }} - {{ . | quote }} @@ -53,7 +53,7 @@ spec: {{- end }} {{- end }} rules: - {{- range .Values.ingress.hosts }} + {{- range .Values.gateway.ingress.hosts }} - host: {{ .host | quote }} http: paths: diff --git a/charts/apisix/templates/pdb.yaml b/charts/apisix/templates/pdb.yaml index df8b7966..60c71bb6 100644 --- a/charts/apisix/templates/pdb.yaml +++ b/charts/apisix/templates/pdb.yaml @@ -14,8 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if (.Values.podDisruptionBudget.enabled) }} +{{- if (and .Values.apisix.enabled .Values.apisix.podDisruptionBudget.enabled) }} +{{ if semverCompare "<1.21-0" .Capabilities.KubeVersion.Version -}} apiVersion: policy/v1beta1 +{{- else -}} +apiVersion: policy/v1 +{{- end }} kind: PodDisruptionBudget metadata: name: {{ include "apisix.fullname" . }} @@ -23,10 +27,10 @@ metadata: labels: {{- include "apisix.labels" . | nindent 4 }} spec: -{{- if .Values.podDisruptionBudget.minAvailable }} - minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} +{{- if .Values.apisix.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.apisix.podDisruptionBudget.minAvailable }} {{- else }} - maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.apisix.podDisruptionBudget.maxUnavailable }} {{- end }} selector: matchLabels: diff --git a/charts/apisix/templates/secrets.yaml b/charts/apisix/templates/secrets.yaml new file mode 100644 index 00000000..7f07b8ce --- /dev/null +++ b/charts/apisix/templates/secrets.yaml @@ -0,0 +1,14 @@ +{{- range $secret := .Values.global.secrets -}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secret.name | quote }} + namespace: {{ $.Release.Namespace | quote }} +type: Opaque +data: + {{- range $value := $secret.values }} + {{ $value.name }}: {{ $value.value | b64enc | quote }} + {{- end }} +--- +{{- end }} diff --git a/charts/apisix/templates/service-admin.yaml b/charts/apisix/templates/service-admin.yaml index c776c6e2..4a033d21 100644 --- a/charts/apisix/templates/service-admin.yaml +++ b/charts/apisix/templates/service-admin.yaml @@ -13,44 +13,44 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -{{ if (.Values.apisix.admin.enabled) }} +{{ if (and .Values.apisix.enabled .Values.admin.enabled) }} apiVersion: v1 kind: Service metadata: name: {{ include "apisix.fullname" . }}-admin namespace: {{ .Release.Namespace }} annotations: - {{- range $key, $value := .Values.apisix.admin.annotations }} + {{- range $key, $value := .Values.admin.annotations }} {{ $key }}: {{ $value | quote }} {{- end }} labels: {{- include "apisix.labels" . | nindent 4 }} app.kubernetes.io/service: apisix-admin spec: - type: {{ .Values.apisix.admin.type }} - {{- if eq .Values.apisix.admin.type "LoadBalancer" }} - {{- if .Values.apisix.admin.loadBalancerIP }} - loadBalancerIP: {{ .Values.apisix.admin.loadBalancerIP }} + type: {{ .Values.admin.type }} + {{- if eq .Values.admin.type "LoadBalancer" }} + {{- if .Values.admin.loadBalancerIP }} + loadBalancerIP: {{ .Values.admin.loadBalancerIP }} {{- end }} - {{- if .Values.apisix.admin.loadBalancerSourceRanges }} + {{- if .Values.admin.loadBalancerSourceRanges }} loadBalancerSourceRanges: - {{- range $cidr := .Values.apisix.admin.loadBalancerSourceRanges }} + {{- range $cidr := .Values.admin.loadBalancerSourceRanges }} - {{ $cidr }} {{- end }} {{- end }} {{- end }} - {{- if gt (len .Values.apisix.admin.externalIPs) 0 }} + {{- if gt (len .Values.admin.externalIPs) 0 }} externalIPs: - {{- range $ip := .Values.apisix.admin.externalIPs }} + {{- range $ip := .Values.admin.externalIPs }} - {{ $ip }} {{- end }} {{- end }} ports: - name: apisix-admin - port: {{ .Values.apisix.admin.servicePort }} - targetPort: {{ .Values.apisix.admin.port }} - {{- if (and (eq .Values.apisix.admin.type "NodePort") (not (empty .Values.apisix.admin.nodePort))) }} - nodePort: {{ .Values.apisix.admin.nodePort }} + port: {{ .Values.admin.servicePort }} + targetPort: {{ .Values.admin.port }} + {{- if (and (eq .Values.admin.type "NodePort") (not (empty .Values.admin.nodePort))) }} + nodePort: {{ .Values.admin.nodePort }} {{- end }} protocol: TCP selector: diff --git a/charts/apisix/templates/service-gateway.yaml b/charts/apisix/templates/service-gateway.yaml index 7797435a..17331f86 100644 --- a/charts/apisix/templates/service-gateway.yaml +++ b/charts/apisix/templates/service-gateway.yaml @@ -14,70 +14,91 @@ # See the License for the specific language governing permissions and # limitations under the License. +{{- if .Values.apisix.enabled }} apiVersion: v1 kind: Service metadata: name: {{ include "apisix.fullname" . }}-gateway namespace: {{ .Release.Namespace }} annotations: - {{- range $key, $value := .Values.service.annotations }} + {{- range $key, $value := .Values.gateway.annotations }} {{ $key }}: {{ $value | quote }} {{- end }} labels: {{- include "apisix.labels" . | nindent 4 }} app.kubernetes.io/service: apisix-gateway spec: - type: {{ .Values.service.type }} - externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} - {{- if eq .Values.service.type "LoadBalancer" }} - {{- if .Values.service.loadBalancerIP }} - loadBalancerIP: {{ .Values.service.loadBalancerIP }} + type: {{ .Values.gateway.type }} + {{- if or (eq .Values.gateway.type "LoadBalancer") (eq .Values.gateway.type "NodePort") }} + externalTrafficPolicy: {{ .Values.gateway.externalTrafficPolicy }} {{- end }} - {{- if .Values.service.loadBalancerSourceRanges }} + {{- if eq .Values.gateway.type "LoadBalancer" }} + {{- if .Values.gateway.loadBalancerIP }} + loadBalancerIP: {{ .Values.gateway.loadBalancerIP }} + {{- end }} + {{- if .Values.gateway.loadBalancerSourceRanges }} loadBalancerSourceRanges: - {{- range $cidr := .Values.service.loadBalancerSourceRanges }} + {{- range $cidr := .Values.gateway.loadBalancerSourceRanges }} - {{ $cidr }} {{- end }} {{- end }} {{- end }} - {{- if gt (len .Values.service.externalIPs) 0 }} + {{- if gt (len .Values.gateway.externalIPs) 0 }} externalIPs: - {{- range $ip := .Values.service.externalIPs }} + {{- range $ip := .Values.gateway.externalIPs }} - {{ $ip }} {{- end }} {{- end }} ports: - {{- if .Values.service.http.enabled }} + {{- if .Values.gateway.http.enabled }} - name: apisix-gateway - port: {{ .Values.service.http.servicePort }} - targetPort: {{ .Values.service.http.containerPort }} - {{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.http.nodePort))) }} - nodePort: {{ .Values.service.http.nodePort }} + port: {{ .Values.gateway.http.servicePort }} + targetPort: {{ .Values.gateway.http.containerPort }} + {{- if (and (eq .Values.gateway.type "NodePort") (not (empty .Values.gateway.http.nodePort))) }} + nodePort: {{ .Values.gateway.http.nodePort }} {{- end }} protocol: TCP {{- end }} - {{- range .Values.service.http.additionalContainerPorts }} + {{- range .Values.gateway.http.additionalContainerPorts }} - name: apisix-gateway-{{ .port | toString }} port: {{ .port }} targetPort: {{ .port }} protocol: TCP {{- end }} - {{- if or .Values.apisix.ssl.enabled }} + {{- if or .Values.gateway.tls.enabled }} - name: apisix-gateway-tls - port: {{ .Values.service.tls.servicePort }} - targetPort: {{ .Values.apisix.ssl.containerPort }} - {{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.tls.nodePort))) }} - nodePort: {{ .Values.service.tls.nodePort }} + port: {{ .Values.gateway.tls.servicePort }} + targetPort: {{ .Values.gateway.tls.containerPort }} + {{- if (and (eq .Values.gateway.type "NodePort") (not (empty .Values.gateway.tls.nodePort))) }} + nodePort: {{ .Values.gateway.tls.nodePort }} {{- end }} protocol: TCP {{- end }} - {{- range .Values.apisix.ssl.additionalContainerPorts }} + {{- range .Values.gateway.tls.additionalContainerPorts }} - name: apisix-gateway-tls-{{ .port | toString }} port: {{ .port }} targetPort: {{ .port }} {{- end }} - {{- if and .Values.service.stream.enabled (or (gt (len .Values.service.stream.tcp) 0) (gt (len .Values.service.stream.udp) 0)) }} - {{- with .Values.service.stream }} + {{- if or .Values.gateway.proxyProtocol.http.enabled }} + - name: apisix-gateway-pp-http + port: {{ .Values.gateway.proxyProtocol.http.servicePort }} + targetPort: {{ .Values.gateway.proxyProtocol.http.containerPort }} + {{- if (and (eq .Values.gateway.type "NodePort") (not (empty .Values.gateway.proxyProtocol.http.nodePort))) }} + nodePort: {{ .Values.gateway.proxyProtocol.http.nodePort }} + {{- end }} + protocol: TCP + {{- end }} + {{- if or .Values.gateway.proxyProtocol.https.enabled }} + - name: apisix-gateway-pp-https + port: {{ .Values.gateway.proxyProtocol.https.servicePort }} + targetPort: {{ .Values.gateway.proxyProtocol.https.containerPort }} + {{- if (and (eq .Values.gateway.type "NodePort") (not (empty .Values.gateway.proxyProtocol.https.nodePort))) }} + nodePort: {{ .Values.gateway.proxyProtocol.https.nodePort }} + {{- end }} + protocol: TCP + {{- end }} + {{- if and .Values.gateway.stream.enabled (or (gt (len .Values.gateway.stream.tcp) 0) (gt (len .Values.gateway.stream.udp) 0)) }} + {{- with .Values.gateway.stream }} {{- if (gt (len .tcp) 0) }} {{- range $index, $port := .tcp }} - name: proxy-tcp-{{ $index | toString }} @@ -104,3 +125,4 @@ spec: {{- end }} selector: {{- include "apisix.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/apisix/templates/service-metrics.yaml b/charts/apisix/templates/service-metrics.yaml index 6dad0e2f..aa05713e 100644 --- a/charts/apisix/templates/service-metrics.yaml +++ b/charts/apisix/templates/service-metrics.yaml @@ -13,7 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -{{- if .Values.apisix.prometheus.enabled}} +{{- if .Values.serviceMonitor.enabled}} apiVersion: v1 kind: Service metadata: @@ -26,8 +26,8 @@ spec: type: ClusterIP ports: - name: prometheus - port: {{ .Values.apisix.prometheus.containerPort }} - targetPort: {{ .Values.apisix.prometheus.containerPort }} + port: {{ .Values.serviceMonitor.containerPort }} + targetPort: {{ .Values.serviceMonitor.containerPort }} protocol: TCP selector: {{- include "apisix.selectorLabels" . | nindent 4 }} diff --git a/charts/apisix/templates/service-monitor.yaml b/charts/apisix/templates/service-monitor.yaml index 1b4d1468..bda6a1d5 100644 --- a/charts/apisix/templates/service-monitor.yaml +++ b/charts/apisix/templates/service-monitor.yaml @@ -14,24 +14,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{- if .Values.metrics.serviceMonitor.enabled }} +{{- if .Values.serviceMonitor.enabled }} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: - name: {{ .Values.metrics.serviceMonitor.name | default (include "apisix.fullname" .) }} - namespace: {{ .Values.metrics.serviceMonitor.namespace | default .Release.Namespace }} + name: {{ .Values.serviceMonitor.name | default (include "apisix.fullname" .) }} + namespace: {{ .Values.serviceMonitor.namespace | default .Release.Namespace }} labels: {{- include "apisix.labels" . | nindent 4 }} - {{- if .Values.metrics.serviceMonitor.labels }} - {{- toYaml .Values.metrics.serviceMonitor.labels | nindent 4 }} + {{- if .Values.serviceMonitor.labels }} + {{- toYaml .Values.serviceMonitor.labels | nindent 4 }} {{- end }} - {{- if .Values.metrics.serviceMonitor.annotations }} - annotations: {{- toYaml .Values.metrics.serviceMonitor.annotations | nindent 4 }} + {{- if .Values.serviceMonitor.annotations }} + annotations: {{- toYaml .Values.serviceMonitor.annotations | nindent 4 }} {{- end }} spec: namespaceSelector: matchNames: - - {{ .Values.metrics.serviceMonitor.namespace | default .Release.Namespace }} + - {{ .Values.serviceMonitor.namespace | default .Release.Namespace }} selector: matchLabels: {{- include "apisix.labels" . | nindent 6 }} @@ -39,6 +39,9 @@ spec: endpoints: - scheme: http targetPort: prometheus - path: {{ .Values.apisix.prometheus.path }} - interval: {{ .Values.metrics.serviceMonitor.interval }} + path: {{ .Values.serviceMonitor.path }} + interval: {{ .Values.serviceMonitor.interval }} + {{- with .Values.serviceMonitor.metricRelabelings }} + metricRelabelings: {{ toYaml . | nindent 6 }} + {{- end }} {{- end }} diff --git a/charts/apisix/values.yaml b/charts/apisix/values.yaml index 6c7cd9c9..ba507463 100644 --- a/charts/apisix/values.yaml +++ b/charts/apisix/values.yaml @@ -21,130 +21,178 @@ global: # - other-registry-secrets # -- Global Docker registry secret names as an array imagePullSecrets: [] + # -- Secrets to be created with apisix + secrets: [] + # - name: secret-name + # values: + # - name: secret-key + # value: secret=value -image: - # -- Apache APISIX image repository - repository: apache/apisix - # -- Apache APISIX image pull policy - pullPolicy: IfNotPresent - # -- Apache APISIX image tag - # Overrides the image tag whose default is the chart appVersion. - tag: 3.8.0-debian - -# -- set false to use `Deployment`, set true to use `DaemonSet` -useDaemonSet: false -# -- if useDaemonSet is true or autoscaling.enabled is true, replicaCount not become effective -replicaCount: 1 - -# -- Set [priorityClassName](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#pod-priority) for Apache APISIX pods -priorityClassName: "" -# -- Annotations to add to each pod -podAnnotations: {} -# -- Set the securityContext for Apache APISIX pods -podSecurityContext: {} - # fsGroup: 2000 -# -- Set the securityContext for Apache APISIX container -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -# -- See https://kubernetes.io/docs/tasks/run-application/configure-pdb/ for more details -podDisruptionBudget: - # -- Enable or disable podDisruptionBudget - enabled: false - # -- Set the `minAvailable` of podDisruptionBudget. You can specify only one of `maxUnavailable` and `minAvailable` in a single PodDisruptionBudget. - # See [Specifying a Disruption Budget for your Application](https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget) - # for more details - minAvailable: 90% - # -- Set the maxUnavailable of podDisruptionBudget - maxUnavailable: 1 - -# -- Set pod resource requests & limits -resources: {} - # -- Use the host's network namespace - - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi -hostNetwork: false - -# -- Node labels for Apache APISIX pod assignment -nodeSelector: {} -# -- List of node taints to tolerate -tolerations: [] -# -- Set affinity for Apache APISIX deploy -affinity: {} - -# -- timezone is the timezone where apisix uses. -# For example: "UTC" or "Asia/Shanghai" -# This value will be set on apisix container's environment variable TZ. -# You may need to set the timezone to be consistent with your local time zone, -# otherwise the apisix's logs may used to retrieve event maybe in wrong timezone. -timezone: "" - -# -- extraEnvVars An array to add extra env vars -# e.g: -# extraEnvVars: -# - name: FOO -# value: "bar" -# - name: FOO2 -# valueFrom: -# secretKeyRef: -# name: SECRET_NAME -# key: KEY -extraEnvVars: [] - -updateStrategy: {} - # type: RollingUpdate - -# -- Additional Kubernetes resources to deploy with the release. -extraDeploy: [] +apisix: + # -- Enable or disable Apache APISIX itself + # Set it to false and ingress-controller.enabled=true will deploy only ingress-controller + enabled: true -# -- Additional `volume`, See [Kubernetes Volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the detail. -extraVolumes: [] -# - name: extras -# emptyDir: {} + # -- Enable nginx IPv6 resolver + enableIPv6: true -# -- Additional `volume`, See [Kubernetes Volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the detail. -extraVolumeMounts: [] -# - name: extras -# mountPath: /usr/share/extras -# readOnly: true + # -- Whether the APISIX version number should be shown in Server header + enableServerTokens: true -# -- Additional `initContainers`, See [Kubernetes initContainers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) for the detail. -extraInitContainers: [] -# - name: init-myservice -# image: busybox:1.28 -# command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"] + # -- Use Pod metadata.uid as the APISIX id. + setIDFromPodUID: false -# -- Additional `containers`, See [Kubernetes containers](https://kubernetes.io/docs/concepts/containers/) for the detail. -extraContainers: [] + # -- Add custom [lua_shared_dict](https://github.com/openresty/lua-nginx-module#toc88) settings, + # click [here](https://github.com/apache/apisix-helm-chart/blob/master/charts/apisix/values.yaml#L27-L30) to learn the format of a shared dict + customLuaSharedDicts: [] + # - name: foo + # size: 10k + # - name: bar + # size: 1m + # -- Whether to add a custom lua module + luaModuleHook: + enabled: false + # -- extend lua_package_path to load third party code + luaPath: "" + # -- the hook module which will be used to inject third party code into APISIX + # use the lua require style like: "module.say_hello" + hookPoint: "" + # -- configmap that stores the codes + configMapRef: + # -- Name of the ConfigMap where the lua module codes store + name: "" + # mounts decides how to mount the codes to the container. + mounts: + # -- Name of the ConfigMap key, for setting the mapping relationship between ConfigMap key and the lua module code path. + - key: "" + # -- Filepath of the plugin code, for setting the mapping relationship between ConfigMap key and the lua module code path. + path: "" -initContainer: - # -- Init container image - image: busybox - # -- Init container tag - tag: 1.28 + # -- Defines how apisix handles routing: + # - radixtree_uri: match route by uri(base on radixtree) + # - radixtree_host_uri: match route by host + uri(base on radixtree) + # - radixtree_uri_with_parameter: match route by uri with parameters + httpRouter: radixtree_host_uri -autoscaling: - enabled: false - # -- HPA version, the value is "v2" or "v2beta1", default "v2" - version: v2 - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - targetMemoryUtilizationPercentage: 80 + # -- Enable Proxy Protocol + proxyProtocol: + enabled: false + # -- The port with proxy protocol for http, it differs from node_listen and admin_listen. + listenHttpPort: 9181 + # -- The port with proxy protocol for https + listenHttpsPort: 9182 + # -- Enable the proxy protocol for tcp proxy, it works for stream_proxy.tcp option + tcp: true + # -- Enable the proxy protocol to the upstream server + upstream: true + + # -- Enable Data Encryption + data_encryption: + enabled: false + # -- An array of 16 character strings used to encrypt/decrypt fields with AES-128-CBC + keyring: [] + + # -- Enable full customized config.yaml + enableCustomizedConfig: false + # -- If apisix.enableCustomizedConfig is true, full customized config.yaml. + # Please note that other settings about APISIX config will be ignored + customizedConfig: {} + + image: + # -- Apache APISIX image repository + repository: apache/apisix + # -- Apache APISIX image pull policy + pullPolicy: IfNotPresent + # -- Apache APISIX image tag + # Overrides the image tag whose default is the chart appVersion. + tag: 3.8.0-debian + + # -- Use a `DaemonSet` or `Deployment` + kind: Deployment + # -- kind is DaemonSet, replicaCount not become effective + replicaCount: 1 + + # -- Set [priorityClassName](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#pod-priority) for Apache APISIX pods + priorityClassName: "" + # -- Annotations to add to each pod + podAnnotations: {} + # -- Set the securityContext for Apache APISIX pods + podSecurityContext: {} + # fsGroup: 2000 + # -- Set the securityContext for Apache APISIX container + securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + # -- See https://kubernetes.io/docs/tasks/run-application/configure-pdb/ for more details + podDisruptionBudget: + # -- Enable or disable podDisruptionBudget + enabled: false + # -- Set the `minAvailable` of podDisruptionBudget. You can specify only one of `maxUnavailable` and `minAvailable` in a single PodDisruptionBudget. + # See [Specifying a Disruption Budget for your Application](https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget) + # for more details + minAvailable: 90% + # -- Set the maxUnavailable of podDisruptionBudget + maxUnavailable: 1 + + # -- Set pod resource requests & limits + resources: {} + # -- Use the host's network namespace + + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + hostNetwork: false + + # -- Node labels for Apache APISIX pod assignment + nodeSelector: {} + # -- List of node taints to tolerate + tolerations: [] + # -- Set affinity for Apache APISIX deploy + affinity: {} + # -- Topology Spread Constraints for pod assignment spread across your cluster among failure-domains + # ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods + topologySpreadConstraints: [] + + # -- timezone is the timezone where apisix uses. + # For example: "UTC" or "Asia/Shanghai" + # This value will be set on apisix container's environment variable TZ. + # You may need to set the timezone to be consistent with your local time zone, + # otherwise the apisix's logs may used to retrieve event maybe in wrong timezone. + timezone: "" + + # -- extraEnvVars An array to add extra env vars + # e.g: + # extraEnvVars: + # - name: FOO + # value: "bar" + # - name: FOO2 + # valueFrom: + # secretKeyRef: + # name: SECRET_NAME + # key: KEY + extraEnvVars: [] + + # -- Set the readinessProbe for Apache APISIX pods + readinessProbe: + failureThreshold: 6 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + tcpSocket: + port: &gatewayHttpContainerPort 9080 + timeoutSeconds: 1 nameOverride: "" fullnameOverride: "" @@ -157,7 +205,20 @@ serviceAccount: rbac: create: false -service: +deployment: + # -- Apache APISIX deployment mode + # Optional: traditional, decoupled, standalone + # + # ref: https://apisix.apache.org/docs/apisix/deployment-modes/ + mode: traditional + + # -- Deployment role + # Optional: traditional, data_plane, control_plane + # + # ref: https://apisix.apache.org/docs/apisix/deployment-modes/ + role: "traditional" + +gateway: # -- Apache APISIX service type for user access itself type: NodePort # -- Setting how the Service route external traffic @@ -173,7 +234,7 @@ service: http: enabled: true servicePort: 80 - containerPort: 9080 + containerPort: *gatewayHttpContainerPort # -- Support multiple http ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L24) additionalContainerPorts: [] # - port: 9081 @@ -183,14 +244,60 @@ service: # enable_http2: true # -- Apache APISIX service settings for tls tls: + enabled: false servicePort: 443 - # nodePort: 4443 - + containerPort: 9443 + # -- Support multiple https ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L99) + additionalContainerPorts: [] + # - ip: 127.0.0.3 # Specific IP, If not set, the default value is `0.0.0.0`. + # port: 9445 + # enable_http2: true + # -- Specifies the name of Secret contains trusted CA certificates in the PEM format used to verify the certificate when APISIX needs to do SSL/TLS handshaking with external services (e.g. etcd) + existingCASecret: "" + # -- Filename be used in the gateway.tls.existingCASecret + certCAFilename: "" + http2: + enabled: true + # -- TLS protocols allowed to use. + sslProtocols: "TLSv1.2 TLSv1.3" + # -- Define SNI to fallback if none is presented by client + fallbackSNI: "" + # -- Proxy Protocol Configuration + proxyProtocol: + # -- If you enable proxy protocol, you must use this port to receive http request with proxy protocol + http: + enabled: false + # - Specify NodePort (only if gateway.type is NodePort) + # nodePort: + # - Define a Service Port on which the gateway is listening + servicePort: 9181 + # - Gateway Service Port to use as target + containerPort: 9181 + # -- The port with proxy protocol for https + https: + enabled: false + # - Specify NodePort (only if gateway.type is NodePort) + # nodePort: + # - Define a Service Port on which the gateway is listening + servicePort: 9182 + # - Gateway Service Port to use as target + containerPort: 9182 # -- Apache APISIX service settings for stream. L4 proxy (TCP/UDP) stream: enabled: false tcp: [] udp: [] + # -- Using ingress access Apache APISIX service + ingress: + enabled: false + # -- Ingress annotations + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: apisix.local + paths: [] + tls: [] # - secretName: apisix-tls # hosts: # - chart-example.local @@ -199,351 +306,304 @@ service: # labelsOverride: # app.kubernetes.io/name: "{{ .Release.Name }}" # app.kubernetes.io/instance: '{{ include "apisix.name" . }}' +admin: + # -- Enable Admin API + enabled: true + # -- admin service type + type: ClusterIP + # loadBalancerIP: a.b.c.d + # loadBalancerSourceRanges: + # - "143.231.0.0/16" + # -- IPs for which nodes in the cluster will also accept traffic for the servic + externalIPs: [] + # -- which ip to listen on for Apache APISIX admin API. Set to `"[::]"` when on IPv6 single stack + ip: 0.0.0.0 + # -- which port to use for Apache APISIX admin API + port: 9180 + # -- Service port to use for Apache APISIX admin API + servicePort: 9180 + # -- Admin API support CORS response headers + cors: true + # -- Admin API credentials + credentials: + # -- Apache APISIX admin API admin role credentials + admin: edd1c9f034335f136f87ad84b625c8f1 + # -- Apache APISIX admin API viewer role credentials + viewer: 4054f7cf07e344346cd3f287985e76a2 + + # -- The APISIX Helm chart supports storing user credentials in a secret. + # The secret needs to contain two keys, admin and viewer, with their respective values set. + secretName: "" + # -- Name of the admin role key in the secret, overrides the default key name "admin" + secretAdminKey: "" + # -- Name of the viewer role key in the secret, overrides the default key name "viewer" + secretViewerKey: "" + + allow: + # -- The client IP CIDR allowed to access Apache APISIX Admin API service. + ipList: + - 127.0.0.1/24 + # -- Using ingress access Apache APISIX admin service + ingress: + enabled: false + # -- Ingress annotations + annotations: + {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: apisix-admin.local + paths: + - "/apisix" + tls: [] + # - secretName: apisix-tls + # hosts: + # - chart-example.local -# -- Using ingress access Apache APISIX service -ingress: +nginx: + workerRlimitNofile: "20480" + workerConnections: "10620" + workerProcesses: auto + enableCPUAffinity: true + envs: [] + # -- allow customize meta in `nginx_config` section + meta: | + lua_shared_dict: + prometheus-metrics: 15m + +# -- Customize the list of APISIX plugins to enable. By default, APISIX's default plugins are automatically used. See [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml) +plugins: [] +# -- Customize the list of APISIX stream_plugins to enable. By default, APISIX's default stream_plugins are automatically used. See [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml) +stream_plugins: [] + +# -- Set APISIX plugin attributes, see [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L376) for more details +pluginAttrs: {} + +extPlugin: + # -- Enable External Plugins. See [external plugin](https://apisix.apache.org/docs/apisix/next/external-plugin/) enabled: false - # -- (number) Service port to send traffic. Defaults to `service.http.servicePort`. - servicePort: - # -- Ingress annotations - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: apisix.local - paths: [] - tls: [] + # -- the command and its arguements to run as a subprocess + cmd: ["/path/to/apisix-plugin-runner/runner", "run"] -# -- Observability configuration. -metrics: - serviceMonitor: - # -- Enable or disable Apache APISIX serviceMonitor - enabled: false - # -- namespace where the serviceMonitor is deployed, by default, it is the same as the namespace of the apisix - namespace: "" - # -- name of the serviceMonitor, by default, it is the same as the apisix fullname - name: "" - # -- interval at which metrics should be scraped - interval: 15s - # -- @param serviceMonitor.labels ServiceMonitor extra labels - labels: {} - # -- @param serviceMonitor.annotations ServiceMonitor annotations - annotations: {} +wasmPlugins: + # -- Enable Wasm Plugins. See [wasm plugin](https://apisix.apache.org/docs/apisix/next/wasm/) + enabled: false + plugins: [] -apisix: - # -- Enable nginx IPv6 resolver - enableIPv6: true +# -- customPlugins allows you to mount your own HTTP plugins. +customPlugins: + # -- Whether to configure some custom plugins + enabled: false + # -- the lua_path that tells APISIX where it can find plugins, + # note the last ';' is required. + luaPath: "/opts/custom_plugins/?.lua" + plugins: + # -- plugin name. + - name: "plugin-name" + # -- plugin attrs + attrs: {} + # -- plugin codes can be saved inside configmap object. + configMap: + # -- name of configmap. + name: "configmap-name" + # -- since keys in configmap is flat, mountPath allows to define the mount + # path, so that plugin codes can be mounted hierarchically. + mounts: + - key: "the-file-name" + path: "mount-path" + +# -- Update strategy for apisix deployment +updateStrategy: {} + # type: RollingUpdate - # -- Whether the APISIX version number should be shown in Server header - enableServerTokens: true +# -- Additional `volume`, See [Kubernetes Volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the detail. +extraVolumes: [] +# - name: extras +# emptyDir: {} - # -- Use Pod metadata.uid as the APISIX id. - setIDFromPodUID: false +# -- Additional `volume`, See [Kubernetes Volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the detail. +extraVolumeMounts: [] +# - name: extras +# mountPath: /usr/share/extras +# readOnly: true - # -- Whether to add a custom lua module - luaModuleHook: - enabled: false - # -- extend lua_package_path to load third party code - luaPath: "" - # -- the hook module which will be used to inject third party code into APISIX - # use the lua require style like: "module.say_hello" - hookPoint: "" - # -- configmap that stores the codes - configMapRef: - # -- Name of the ConfigMap where the lua module codes store - name: "" - # mounts decides how to mount the codes to the container. - mounts: - # -- Name of the ConfigMap key, for setting the mapping relationship between ConfigMap key and the lua module code path. - - key: "" - # -- Filepath of the plugin code, for setting the mapping relationship between ConfigMap key and the lua module code path. - path: "" +# -- Additional `initContainers`, See [Kubernetes initContainers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) for the detail. +extraInitContainers: + - name: init-sysctl + image: busybox:1.28 + command: + - /bin/sh + - -c + - | + sysctl -w net.core.somaxconn=65535 + sysctl -w net.ipv4.ip_local_port_range="1024 65535" + sysctl -w net.ipv4.tcp_max_syn_backlog=8192 + sysctl -w fs.file-max=1048576 + sysctl -w fs.inotify.max_user_instances=16384 + sysctl -w fs.inotify.max_user_watches=524288 + sysctl -w fs.inotify.max_queued_events=16384 + securityContext: + privileged: true +# - name: init-myservice +# image: busybox:1.28 +# command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"] - ssl: - enabled: false - containerPort: 9443 - # -- Support multiple https ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L99) - additionalContainerPorts: [] - # - ip: 127.0.0.3 # Specific IP, If not set, the default value is `0.0.0.0`. - # port: 9445 - # enable_http2: true - # -- Specifies the name of Secret contains trusted CA certificates in the PEM format used to verify the certificate when APISIX needs to do SSL/TLS handshaking with external services (e.g. etcd) - existingCASecret: "" - # -- Filename be used in the apisix.ssl.existingCASecret - certCAFilename: "" - http2: - enabled: true - # -- TLS protocols allowed to use. - sslProtocols: "TLSv1.2 TLSv1.3" - # -- Define SNI to fallback if none is presented by client - fallbackSNI: "" +discovery: + # -- Enable or disable Apache APISIX integration service discovery + enabled: false + # -- Registry is the same to the one in APISIX [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L281), + # and refer to such file for more setting details. also refer to [this documentation for integration service discovery](https://apisix.apache.org/docs/apisix/discovery) + registry: {} + # Integration service discovery registry. E.g eureka\dns\nacos\consul_kv + # reference: + # https://apisix.apache.org/docs/apisix/discovery/#configuration-for-eureka + # https://apisix.apache.org/docs/apisix/discovery/dns/#service-discovery-via-dns + # https://apisix.apache.org/docs/apisix/discovery/consul_kv/#configuration-for-consul-kv + # https://apisix.apache.org/docs/apisix/discovery/nacos/#configuration-for-nacos + # https://apisix.apache.org/docs/apisix/discovery/kubernetes/#configuration + # + # an eureka example: + # ``` + # eureka: + # host: + # - "http://${username}:${password}@${eureka_host1}:${eureka_port1}" + # - "http://${username}:${password}@${eureka_host2}:${eureka_port2}" + # prefix: "/eureka/" + # fetch_interval: 30 + # weight: 100 + # timeout: + # connect: 2000 + # send: 2000 + # read: 5000 + # ``` + # + # the minimal Kubernetes example: + # ``` + # kubernetes: {} + # ``` + # + # The prerequisites for the above minimal Kubernetes example: + # 1. [Optional] Set `.serviceAccount.create` to `true` to create a dedicated ServiceAccount. + # It is recommended to do so, otherwise the default ServiceAccount "default" will be used. + # 2. [Required] Set `.rbac.create` to `true` to create and bind the necessary RBAC resources. + # This grants the ServiceAccount in use to List-Watch Kubernetes Endpoints resources. + # 3. [Required] Include the following environment variables in `.nginx.envs` to pass them into + # nginx worker processes (https://nginx.org/en/docs/ngx_core_module.html#env): + # - KUBERNETES_SERVICE_HOST + # - KUBERNETES_SERVICE_PORT + # This is for allowing the default `host` and `port` of `.discovery.registry.kubernetes.service`. + +# access log and error log configuration +logs: + # -- Enable access log or not, default true + enableAccessLog: true + # -- Access log path + accessLog: "/dev/stdout" + # -- Access log format + accessLogFormat: '$remote_addr - $remote_user [$time_local] $http_host \"$request\" $status $body_bytes_sent $request_time \"$http_referer\" \"$http_user_agent\" $upstream_addr $upstream_status $upstream_response_time \"$upstream_scheme://$upstream_host$upstream_uri\"' + # -- Allows setting json or default characters escaping in variables + accessLogFormatEscape: default + # -- Error log path + errorLog: "/dev/stderr" + # -- Error log level + errorLogLevel: "warn" + +dns: + resolvers: + - 127.0.0.1 + - 172.20.0.10 + - 114.114.114.114 + - 223.5.5.5 + - 1.1.1.1 + - 8.8.8.8 + validity: 30 + timeout: 5 - router: - # -- Defines how apisix handles routing: - # - radixtree_uri: match route by uri(base on radixtree) - # - radixtree_host_uri: match route by host + uri(base on radixtree) - # - radixtree_uri_with_parameter: match route by uri with parameters - http: radixtree_host_uri +initContainer: + # -- Init container image + image: busybox + # -- Init container tag + tag: 1.28 + # -- Set the securityContext for the init container + securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 - fullCustomConfig: - # -- Enable full customized config.yaml - enabled: false - # -- If apisix.fullCustomConfig.enabled is true, full customized config.yaml. - # Please note that other settings about APISIX config will be ignored - config: {} +autoscaling: + enabled: false + # -- HPA version, the value is "v2" or "v2beta1", default "v2" + version: v2 + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 - deployment: - # -- Apache APISIX deployment mode - # Optional: traditional, decoupled, standalone - # - # ref: https://apisix.apache.org/docs/apisix/deployment-modes/ - mode: traditional +# -- Custom configuration snippet. +configurationSnippet: + main: | - # -- Deployment role - # Optional: traditional, data_plane, control_plane - # - # ref: https://apisix.apache.org/docs/apisix/deployment-modes/ - role: "traditional" + httpStart: | - admin: - # -- Enable Admin API - enabled: true - # -- admin service type - type: ClusterIP - # loadBalancerIP: a.b.c.d - # loadBalancerSourceRanges: - # - "143.231.0.0/16" - # -- IPs for which nodes in the cluster will also accept traffic for the servic - externalIPs: [] - # -- which ip to listen on for Apache APISIX admin API. Set to `"[::]"` when on IPv6 single stack - ip: 0.0.0.0 - # -- which port to use for Apache APISIX admin API - port: 9180 - # -- Service port to use for Apache APISIX admin API - servicePort: 9180 - # -- Admin API support CORS response headers - cors: true - # -- Admin API credentials - credentials: - # -- Apache APISIX admin API admin role credentials - admin: edd1c9f034335f136f87ad84b625c8f1 - # -- Apache APISIX admin API viewer role credentials - viewer: 4054f7cf07e344346cd3f287985e76a2 - - # -- The APISIX Helm chart supports storing user credentials in a secret. - # The secret needs to contain two keys, admin and viewer, with their respective values set. - secretName: "" - - allow: - # -- The client IP CIDR allowed to access Apache APISIX Admin API service. - ipList: - - 127.0.0.1/24 - # -- Using ingress access Apache APISIX admin service - ingress: - enabled: false - # -- Ingress annotations - annotations: - {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: apisix-admin.local - paths: - - "/apisix" - tls: [] - # - secretName: apisix-tls - # hosts: - # - chart-example.local - - nginx: - workerRlimitNofile: "20480" - workerConnections: "10620" - workerProcesses: auto - enableCPUAffinity: true - # -- Timeout during which a keep-alive client connection will stay open on the server side. - keepaliveTimeout: 60s - envs: [] - # access log and error log configuration - logs: - # -- Enable access log or not, default true - enableAccessLog: true - # -- Access log path - accessLog: "/dev/stdout" - # -- Access log format - accessLogFormat: '$remote_addr - $remote_user [$time_local] $http_host \"$request\" $status $body_bytes_sent $request_time \"$http_referer\" \"$http_user_agent\" $upstream_addr $upstream_status $upstream_response_time \"$upstream_scheme://$upstream_host$upstream_uri\"' - # -- Allows setting json or default characters escaping in variables - accessLogFormatEscape: default - # -- Error log path - errorLog: "/dev/stderr" - # -- Error log level - errorLogLevel: "warn" - # -- Custom configuration snippet. - configurationSnippet: - main: | - - httpStart: | - - httpEnd: | - - httpSrv: | - - httpAdmin: | - - stream: | - - # -- Add custom [lua_shared_dict](https://github.com/openresty/lua-nginx-module#toc88) settings, - # click [here](https://github.com/apache/apisix-helm-chart/blob/master/charts/apisix/values.yaml#L27-L30) to learn the format of a shared dict - customLuaSharedDicts: [] - # - name: foo - # size: 10k - # - name: bar - # size: 1m - - discovery: - # -- Enable or disable Apache APISIX integration service discovery - enabled: false - # -- Registry is the same to the one in APISIX [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L281), - # and refer to such file for more setting details. also refer to [this documentation for integration service discovery](https://apisix.apache.org/docs/apisix/discovery) - registry: {} - # Integration service discovery registry. E.g eureka\dns\nacos\consul_kv - # reference: - # https://apisix.apache.org/docs/apisix/discovery/#configuration-for-eureka - # https://apisix.apache.org/docs/apisix/discovery/dns/#service-discovery-via-dns - # https://apisix.apache.org/docs/apisix/discovery/consul_kv/#configuration-for-consul-kv - # https://apisix.apache.org/docs/apisix/discovery/nacos/#configuration-for-nacos - # https://apisix.apache.org/docs/apisix/discovery/kubernetes/#configuration - # - # an eureka example: - # ``` - # eureka: - # host: - # - "http://${username}:${password}@${eureka_host1}:${eureka_port1}" - # - "http://${username}:${password}@${eureka_host2}:${eureka_port2}" - # prefix: "/eureka/" - # fetch_interval: 30 - # weight: 100 - # timeout: - # connect: 2000 - # send: 2000 - # read: 5000 - # ``` - # - # the minimal Kubernetes example: - # ``` - # kubernetes: {} - # ``` - # - # The prerequisites for the above minimal Kubernetes example: - # 1. [Optional] Set `.serviceAccount.create` to `true` to create a dedicated ServiceAccount. - # It is recommended to do so, otherwise the default ServiceAccount "default" will be used. - # 2. [Required] Set `.rbac.create` to `true` to create and bind the necessary RBAC resources. - # This grants the ServiceAccount in use to List-Watch Kubernetes Endpoints resources. - # 3. [Required] Include the following environment variables in `.nginx.envs` to pass them into - # nginx worker processes (https://nginx.org/en/docs/ngx_core_module.html#env): - # - KUBERNETES_SERVICE_HOST - # - KUBERNETES_SERVICE_PORT - # This is for allowing the default `host` and `port` of `.discovery.registry.kubernetes.service`. - - dns: - resolvers: - - 127.0.0.1 - - 172.20.0.10 - - 114.114.114.114 - - 223.5.5.5 - - 1.1.1.1 - - 8.8.8.8 - validity: 30 - timeout: 5 - - vault: - # -- Enable or disable the vault integration - enabled: false - # -- The host address where the vault server is running. - host: "" - # -- HTTP timeout for each request. - timeout: 10 - # -- The generated token from vault instance that can grant access to read data from the vault. - token: "" - # -- Prefix allows you to better enforcement of policies. - prefix: "" - - prometheus: - # ref: https://apisix.apache.org/docs/apisix/plugins/prometheus/ - enabled: false - # -- path of the metrics endpoint - path: /apisix/prometheus/metrics - # -- prefix of the metrics - metricPrefix: apisix_ - # -- container port where the metrics are exposed - containerPort: 9091 - - # -- Customize the list of APISIX plugins to enable. By default, APISIX's default plugins are automatically used. See [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml) - plugins: [] - # -- Customize the list of APISIX stream_plugins to enable. By default, APISIX's default stream_plugins are automatically used. See [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml) - stream_plugins: [] + httpEnd: | - # -- Set APISIX plugin attributes, see [config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml#L376) for more details - pluginAttrs: {} + httpSrv: | - extPlugin: - # -- Enable External Plugins. See [external plugin](https://apisix.apache.org/docs/apisix/next/external-plugin/) - enabled: false - # -- the command and its arguements to run as a subprocess - cmd: ["/path/to/apisix-plugin-runner/runner", "run"] + httpAdmin: | - wasm: - # -- Enable Wasm Plugins. See [wasm plugin](https://apisix.apache.org/docs/apisix/next/wasm/) - enabled: false - plugins: [] + stream: | - # -- customPlugins allows you to mount your own HTTP plugins. - customPlugins: - # -- Whether to configure some custom plugins - enabled: false - # -- the lua_path that tells APISIX where it can find plugins, - # note the last ';' is required. - luaPath: "/opts/custom_plugins/?.lua" - plugins: - # -- plugin name. - - name: "plugin-name" - # -- plugin attrs - attrs: {} - # -- plugin codes can be saved inside configmap object. - configMap: - # -- name of configmap. - name: "configmap-name" - # -- since keys in configmap is flat, mountPath allows to define the mount - # path, so that plugin codes can be mounted hierarchically. - mounts: - - key: "the-file-name" - path: "mount-path" - -# -- external etcd configuration. If etcd.enabled is false, these configuration will be used. -externalEtcd: - # -- if etcd.enabled is false, use external etcd, support multiple address, if your etcd cluster enables TLS, please use https scheme, e.g. https://127.0.0.1:2379. - host: - # host or ip e.g. http://172.20.128.89:2379 - - http://etcd.host:2379 - # -- if etcd.enabled is false, user for external etcd. Set empty to disable authentication - user: root - # -- if etcd.enabled is true, use etcd.auth.rbac.rootPassword instead. - # -- if etcd.enabled is false and externalEtcd.existingSecret is not empty, the password should store in the corresponding secret - # -- if etcd.enabled is false and externalEtcd.existingSecret is empty, externalEtcd.password is the passsword for external etcd. - password: "" - # -- if externalEtcd.existingSecret is the name of secret containing the external etcd password - existingSecret: "" - # -- externalEtcd.secretPasswordKey Key inside the secret containing the external etcd password - secretPasswordKey: "etcd-root-password" +# -- Observability configuration. +# ref: https://apisix.apache.org/docs/apisix/plugins/prometheus/ +serviceMonitor: + # -- Enable or disable Apache APISIX serviceMonitor + enabled: false + # -- namespace where the serviceMonitor is deployed, by default, it is the same as the namespace of the apisix + namespace: "" + # -- name of the serviceMonitor, by default, it is the same as the apisix fullname + name: "" + # -- interval at which metrics should be scraped + interval: 15s + # -- path of the metrics endpoint + path: /apisix/prometheus/metrics + # -- prefix of the metrics + metricPrefix: apisix_ + # -- container port where the metrics are exposed + containerPort: 9091 + # -- @param serviceMonitor.labels ServiceMonitor extra labels + labels: {} + # -- @param serviceMonitor.annotations ServiceMonitor annotations + annotations: {} + # -- @param serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion. + # ref: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs + metricRelabelings: [] # -- etcd configuration # use the FQDN address or the IP of the etcd etcd: # -- install etcd(v3) by default, set false if do not want to install etcd(v3) together enabled: true + # -- if etcd.enabled is false, use external etcd, support multiple address, if your etcd cluster enables TLS, please use https scheme, e.g. https://127.0.0.1:2379. + host: + # host or ip e.g. http://172.20.128.89:2379 + - http://etcd.host:2379 + # -- if etcd.enabled is false, username for external etcd. If etcd.enabled is true, use etcd.auth.rbac.rootPassword instead. + user: "" + # -- if etcd.enabled is false, password for external etcd. If etcd.enabled is true, use etcd.auth.rbac.rootPassword instead. + password: "" # -- apisix configurations prefix prefix: "/apisix" # -- Set the timeout value in seconds for subsequent socket operations from apisix to etcd cluster timeout: 30 + # -- Name of the existing secret containing user and password for external etcd, overrides etcd.user and etcd.password + existingSecret: "" + # -- Name of key containing username to be retrieved from the existing secret, has a value of user by default + existingSecretUserKey: "" + # -- Name of key containing password to be retrieved from the existing secret, has a value of password by default + existingSecretPasswordKey: "" # -- if etcd.enabled is true, set more values of bitnami/etcd helm chart auth: @@ -552,6 +612,10 @@ etcd: create: false # -- root password for etcd. Requires etcd.auth.rbac.create to be true. rootPassword: "" + # -- Name of the existing secret containing credentials for the root user + existingSecret: "" + # -- Name of key containing password to be retrieved from the existing secret + existingSecretPasswordKey: "" tls: # -- enable etcd client certificate enabled: false @@ -566,6 +630,11 @@ etcd: # -- specify the TLS Server Name Indication extension, the ETCD endpoint hostname will be used when this setting is unset. sni: "" + # -- ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + # -- added for backward compatibility with old kubernetes versions, as seccompProfile is not supported in kubernetes < 1.19 + containerSecurityContext: + enabled: false + service: port: 2379 @@ -592,3 +661,15 @@ ingress-controller: config: apisix: adminAPIVersion: "v3" + +vault: + # -- Enable or disable the vault integration + enabled: false + # -- The host address where the vault server is running. + host: "" + # -- HTTP timeout for each request. + timeout: 10 + # -- The generated token from vault instance that can grant access to read data from the vault. + token: "" + # -- Prefix allows you to better enforcement of policies. + prefix: "" diff --git a/docs/en/latest/FAQ.md b/docs/en/latest/FAQ.md index 3e807016..a5d85c24 100644 --- a/docs/en/latest/FAQ.md +++ b/docs/en/latest/FAQ.md @@ -39,7 +39,7 @@ helm install apisix apisix/apisix \ ### How to install Apache APISIX running in standalone mode? -helm install apisix apisix/apisix --set apisix.deployment.mode=standalone --set etcd.enabled=false --set apisix.deployment.role=data_plane +helm install apisix apisix/apisix --set deployment.mode=standalone --set etcd.enabled=false --set deployment.role=data_plane ### Why get 403 when I access Apache APISIX admin api?