From 54f2c0345582ceafeea8ab2d58e9aaee22087c6f Mon Sep 17 00:00:00 2001 From: Steve Reis <stevereis93@gmail.com> Date: Wed, 20 Jul 2022 08:25:12 +0000 Subject: [PATCH] GitBook: [#21] No subject --- .../assets/cache-interaction.drawio.png | Bin 0 -> 26016 bytes README.md => docs/README.md | 0 docs/SUMMARY.md | 9 +- docs/for-developers/configuration/gateway.md | 14 +- docs/for-developers/connector/README.md | 2 - .../for-developers/frontend/visualisations.md | 2 +- docs/for-developers/gateway/authentication.md | 19 ++- docs/for-developers/gateway/cache.md | 27 ++++ .../gateway/connector/README.md | 2 + .../gateway/connector/create-a-connector.md | 153 ++++++++++++++++++ .../parsing-response-with-jsonata.md} | 0 docs/for-developers/gateway/static-files.md | 20 +++ docs/for-developers/gateway/users.md | 27 +--- .../get-started/Introduction.md | 6 +- .../Setup-development-environment.md | 10 +- 15 files changed, 248 insertions(+), 43 deletions(-) create mode 100644 docs/.gitbook/assets/cache-interaction.drawio.png rename README.md => docs/README.md (100%) delete mode 100644 docs/for-developers/connector/README.md create mode 100644 docs/for-developers/gateway/cache.md create mode 100644 docs/for-developers/gateway/connector/README.md create mode 100644 docs/for-developers/gateway/connector/create-a-connector.md rename docs/for-developers/{connector/Parsing-response-with-JSONata.md => gateway/connector/parsing-response-with-jsonata.md} (100%) create mode 100644 docs/for-developers/gateway/static-files.md diff --git a/docs/.gitbook/assets/cache-interaction.drawio.png b/docs/.gitbook/assets/cache-interaction.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..c2972ad28b75c2c15823a2dee32b6fa78a3af3e6 GIT binary patch literal 26016 zcmafb2RzmP_kT%7xfw}ZWea6o+-sC|-D_R@npfG^xVCFvGbt2hBqG_XAtRzP5{0OY ztYl<{Wbe`cb?Ni{_W%CAzyJS{(7o^bdY{*Mo$)-+bKc$5(@}#QgC09{=nzCh9gRJ7 z=m_M{p~FZTD)0(o95n=f9QMMhDIa?F>CE(@Lo{c+RZP8I{p|@Zc8B;SQ3t>AOTZl6 zy}bD)(fkq;)*c?Bc!IS9(c0BZ)XmNtyae8Nb;lFz33m8{Yb0P25+X2Z5ph{Vm=wPx z5-ttCiA#tgVB%&6*IPT-x&2uXAqoQv2%3tE^Ghm&-?RvBKK|gRzl@Zn6kG`WhV<}o zu`{u=(IkMosUjq$MJ1)kAJJ4d)YjscK!M*~2+nrkhnk(Ovpe}CC`Y2ZD|kg!93~+O zBmV&}8d%#~6A6DUL6+Rk+uGqkY7HFGTN*9nf-;s=A-Z7AjL^#X18IHjh+YJDw|_PV zmV+O>;Z5?eJ9yQ>-QB?j+)#pFQUxgPkA}edgg-jLNV{lyz^#3eYWg;M-n!nJ$}&I{ zvIK6{K+=8P>H)Qgh#xG1FecjAdV5Kz=)tV@jLgs~p87sc(q>*5ehFm>XLY=touP-O z8`{~x2dky8?}yWLz}T4*QE(>*RlK393c&>7?INqKrHpg1wYTx|)5l1lVK5U<85vuk zTxC^XEhO67R?6Q&+(<`K&&VFUhE|qD7>K)>xSANj)znPXbPe#zW<-pZUw|G0h4*l` zHu2U(Iy-tgxoh}qIy>6x08P4k5xkJ5I#^#<H<TpN#z{v_3T#PPM+WPs?I*3P=V{_5 zi*?Yznt5Ae%@C#%S}?RL&K}_^A*&&aLikBr!?X?H?nrM<k{L`ArfnGD;iTc_XiY>J zBUMe^5n4Jv2uB03qN+a*>qoG)B_Of(L{n)$Cs{R9Sp-4T7HjY8iAJj<WXT&a)HQQ+ zQ`XTj(h_%+A&NUWquex&u}C#{15Y^K$AzSVl~MM0G6l;S`Iy;~T(q$ITAD6C6835a zBu767V`~^55#UE~QGwyiBw-{~GlI6gy(+leT17_POivu`;fjOHh>L4G$?Dl6Ri)9^ zJ}xL}2NiGy3GMBGQdX7Ka*-q<J^j^9U6g%^2%@I8TY#^THxX%|i@>U*Tzz!|G<-Y^ z#GPCmU^Wt}22M80Uha~<9?DuaFb!`_tR~T4605B3hlhD0kPgo72zwc<p}PjmM?(We zGSG6-c2!pOHd0rEySrL@>H3+uI~wR4xj5_VOB*6kx;Q<Av$%wc4?$I0S<S{2sfTtj zB{@s0o2p6a>&PJeT!|(Iz@(K?dN?$ZNYDyE>w0=hm`Q1QdRwDCO?2&0s#sS)up37W z3>+=3;_idjcG1zqYG|VTTvU8*y_J3Rfu>Z{@wQU-j%r%&NHqx^S9Kk0;J2zqU}14j zcQ>Lq+<=58x*JNNi8>D6_FDGdIxaATu>{suBS0%aRZrW2WUFN$4L)KE{u(+d>l+|E zY;_zR(Hj1a*0#ppz*kjWj7Z{0RcmQCvcGz2`1zplHX2A>5CD`h#&!WDWkVGoFKrZt zq@rwM?d|PhuL&I1#T096<^a<`8rk7&u`=obHtGQyeh$uP6E7kW<AZcEb5k+FNqX3u zU|ls$^jyGVW|{<T2?;%zj=rbAI1Yy}^s^&s__=#(NK1IY$zI{)fpCzKb(Qo4znh2~ z*+@zIVM+SNKq_JYP67vhde})4Na{AmM1+qD)<Me^VPtF#E;b_QYB+0{B7E!#D6k`C zO`JOk1LBRdtClo*Q)r?L+DzS)guxj3AkYEcNO72&sd@lX-OES@Z-~bDyQ>oPfrzRe zl6Y+yZCM0S+e_02CZ+DBuHvcZ?B^~+@N}>>(3i23Avt&w1Kd3gbO}cO(nwhiv^M$v za1#fg06(IEtV4i|qpgFnshclR-%H%k(OZH9GxV|Zw9!L*`AfQLA$7$A#GN$2XWa0z zYAys{J(9PZp1rHMqpF?_!Via+Hr2J$m6CSUlg0t3S4M(Bqa5Icgdq?_GZ#C38+SVw zR|y+u8*e>4+S(fnE>Tt?I+Kk3HG%lHCg7Wyrh}}uohurq?uYl6@Y2w7*9q_=X*hvP z{Q|VS)g%aNZhFqzt`6!R`m%Uy4{fqyi8}g3aWh{DLq8K`Z46S^UB%PGkAN^n<GfLB ze!4~~SPy4)Nt8WY2X3t5tt(~i3irY3ddTSN`Fr~tXgliZ=}2mO$Px&~BqKLj352wy zw}g+2j*+RGx`!W8+R@w75JSYun0fiiSd)XIm!kyC#1+UbiL=32BXw1Li~_Xve2ByV zQyp8Bs<W@OpO3GBhNiE9x26g*z*b+@*g@A?$Hhq<D~mNn5;b(~G&EeyTrf`J0YH3N zL!`IAq=vp4@HMg}c_XAySe${Dsl5}(#Ri^Ix@IckGP24tFrvGvItcr!E^rSon6`=y z-pD{5;fyu)fa^G^6E$2Vkg|Gu;Cxg~&@g|zsWrlytW#@AJ!^fqgugmQ+r};cFC}GY z>Z_|~=4Ef9>1FLL?cqZ-HVZJd!D-kV5%4;?jwBCf5)QBBX=mu=;s)fgfjPOF`bw#z zZHQnsv>!PKk-tDbRsAP_?I$zv?>|65QpGQ<dGF96u0tAVq@lmX+(T+_qwXG6MOwkm z#BAnA7y~o|!?cQCi5?{-<+M51ibbyaeAaOu8g=(;*O-yHY>&AH3wVssw-{2D_e$3S zTQZaq0uzEi%g<f1g(Z$ZHJ|)CPnsH>i(gn+@L1qJtax%`yU|lIxp`FmDkb^rP!;iK zp@TU7iP_-uV27q6fd!hp`Ypby(xW^OAxQ^M+ul9_Ca%Na>p1NW$x2c5*IxZw7E=SC z4`)7K>$HLd_H0>FBvRd>G@#LgYSn*G)&PsXS*GO4<u?CxCEeO{dg^W_-2dF*i#fr( z`WKHpeH#QJpFVM3)}`Q6qVVNsFoJg0EL<~xFkR_uevwF-NLBY8kAzYRLZAz*&`XCg zN7Sfk;||frU1bBW+3VS*@Qpk;lvgj!TN{6fA~Awe$(H8eeO(|%M$`rc?S18|omR(; zSulhV)_uvDVBz2sbdQDaQU;yOgm2h4N;4^4?TkC*NXJdy8PkHs)y|QVjFw!7|Jj8Q z<jfHuANaCo$b{cV-m^=%>JDx&9J8TH0d~rC=r;Gk`wFyr&>)`C<9t@f4r9WFOmTvF zVYUaleM1L6Az4_a#k8OeZt#F{SpCpp42mLC{QAD`-v}J$?OgcicUc_Y$#+I3i1KFm zwFR3YxgTB6&Yr&~GWL8&d!Ul{v)5;CuLwGYVMycg>H=<tL|h~zSeG|(L#G<td-Qh9 z;R8viXf_fe5D#iq#y*+D@+~>5&9f*H_;g~7W~DR7u7;UPuX{0zm~wqGb1HYa!QuLK zq&xXI)baLau^zO|p$!_tm<eYcYpfgv%3#p73VL`TBg0|KPQ4#Re(g_nT+3a*z|2T> z8J8j*It$eF^cdbYG<5hh>jk~EKJs=xGRLLVL_Bx{7V|*-<dG&_rF^<+@oW>_>dTLq zBDB-5kuDgI#;bAEJM-VN^&VDm?5HWYMKCLn+N<)WO^Ie{`1;u)$L0~X?{}9qe6Hv0 zc5ldym#rp+8=-r<)Hq4Iw?9j5<9Kiq_zM<H0+nvaE$?YV_SX=$Tif5ivvyT}M$rjE zA|j4j9wY1c5LaO7F--XB=bserl8tARax@{rxwn|tJS=%};Le=?In<UZJMVMG8nrv< zAIVP=>6nWxj>vy4SABSXK2s@Ada-4}+A05gD}=qnZ^bdF&im$8iDiN7rNj%ybV3ON z4Quk-Fxy6$@a5MhY!y<%K1_Vb4vn<ZN|mRsOP38-nEQHOR%YYl#qs9Uqpn*kMn2k` z{;(m}4yIF>B=qa|w+-37?ukT_#+sUBULy&xP_0rbTVUVsWfqJ4nKI#xCs{28_DvIp z<`N~y_^b&NlSHF03&cLDp<6QC%H%$gA(ORduF&`SjI8oU`1Qe8d1xh$O{I*v6o>ZZ z2C0tREYf;<^RmkcZ|6Zw&HC!(N7hTW=j`vWhMoVI`n`S2y`9i*#T>Ax(q>u8G&}jJ zetYigSU7ZkbgtK;VYLL7tCfD`o#>Sss8^D(fh1G3adCZP|MODUe(a9_xFBBR%je<H zg51&i$WALq(}lc4z)L6(m7RV9d|iC@rzF`W@9P55X<n0#KU%KKP1=j1Y+mlY_r!_R zJ_BJd{q=gj#AOS<L)w%GIKh4=NAWlHlI-r6l;;~I)<;&{dZkj~hR!_{if8&_nOpX@ z>wgc`1o~ezzqqq7fk9m2l04-u<q`w2Y(qVQR+P-oBAU%#$gLG`o6)vp(sG;Dtp=V7 zocM~UKu<p)WsFT0U3Svw8Y=D?S)OS1oLzIJoA2jU^-rW)Zen(Zse*73b8`5W0I(am zutlGPaEGD{nj;7rJx|(7sxuj&&$%Zsyds8MzL!9if~yK#e`XfJ7kI{O?dOf3DUynO zkfr6*UQ?<bUFYa4ib(4m{yAD~6>tr{><|y?FF~`~F%LE$nSJ70g=EN`y38Whc=r+3 zdhdhLM$ohbKV%6$^X2H~()inJMo$)}3mKhW@Z|qL_4+0m?$ZBKbB>MmYtE&iz$sV0 z&>c^gueC=WQq!yM&U7#8H=QV4w!XxCVMXF1!aX8fEjHVJR?2^Vu2Q@_P@0)ka4f=m zHvf);d5z~ug%c@Jw~tRgu~U^iE!>!+k&tO!l<IVMd1Z6CJ90NJ?8q03h<BF3H<sQ- z+geTO++W(ff@m!vP6{|BWw{NkRe4I%4J3;h#Ni(qY=>}idyY2B)J_bT*6TytI1QfG zvx2B7t`l@29hmnb<@;W8ez;0W$GE@`!8Z4BDvQhTQEs2uy&kwe|2=Oi!=yEK#`sb8 zOy5g)PN?6nTWXxz*Rqcu%bb}lM%kZGV3&kapWrlpel+}*x3K^Wk|A*_L+tXiB$<g% z@kb<8W0dk&bjN_?{x9%^wudmCd#|TPkQG@04Lc-3lj{3s6h<|q<5y|}ASsgedOX<Y zM$Yh%ViqdDxoe^GgQ%qJckMg7uV&^;<rAq;4cEkuUOkk@eJHNR^k`mvG|nMoKe+`_ zsOHx17;h9roVF~!{?6ds_ZwGU3PSdfAFx_{N(30=v*hS}xWDZ7&rADmp!P<jlWUuO zd@pi!dFnlFv?OHmHh<C?MUcHV7DorDKoF<9HtKv3#20x+s0f1F7H6;2`kuPr5Oi&- z%q|Ds=uEj__XOmfr#$mZ0YVT_UD#_ia&}^2^azJHQlE8zj-sOHQ$gsqI%iIwtW8+( zSnA)mWLP}NedsFTRLW5<CBn!8><0KZ^HbqO@-fKig1ofJt#pV51b<V?p}B4>^jo_1 zS}gg^r`$?}l88&r{2&Q8T@?c7mv3d4MHX{}1QO6^`ok0@QD8Bi1-Ig)&XF~`=b_{` ztsvmU5#MkZz`kUtw7?>;qZf|zlcU*ZkbV6_Xc(@lfW=tC`~oWysVW`r@A8u0bf!Vy zqjEN5*f0~@4Pp}Vl8bgRdO}@G>`|xq%?l*g`wz*vl%dsB*E&ZkVg`!q5~;Q)8c&I2 z!>f31|D+_Vz3<Ld_3+afmy`F#wZc!Ibk9*RfVw2oNh9822+au>PP4S7gk$+JjW@m5 zs!5JJ_0&l=!&M~7rO8jX+dj+L5-yp_9^i@^+AE4)&_~3nQa|4QizZ+TRTpb|d_Mi^ zWZ>YqqxD%Kdbw`TiM6vPaGimf8NU(CD`s45&MyDjSEV#t<#zQaKcGvpt}#H@9gPEp z1Bq1Z{0-XLrP1)*mPFbHD*E?J_bx29y4PiCG(`LuEMj;1QWS0E+%s~cnzXq3;a-)` zEQ?u%d+hPkqFgGsnD4^^;27o$5y8|aGI6s#{);zGd#rtv4SMZ%HmT^!&DtYWBdVsX zACiT_*$nbWN}D(uOlEts{C@9&uqB%Q5%@`gj>>yFHrP4fd291ca|4y0lRt5M+NsRT ziraL{r$ydgja7UvnId659>-m%UzGYF;?TA-+1&U>)WFFrzQya)@+cA18KkH-d8|$o z{LgE$lsom%aniG9Dy%3bi*br($VWc_Njgb<@Kq4bC(q+1ljC6aQ8PH<+F;=N=-@@4 zh1PgpnUEzuOrlt9ia~y+PLY|6-=3U>s4<<Q%it~H6v-#+7-q3&NwPHyORascJad@n z7;l`t<Y&`=?I^1vfr*NqJ;GLTFRGw34>iRh?=kis5+p&ASUN3~of|F*sa0hT-N%?i z=adKwzI$`+ftc{KWg~B;`ZS<D#kla~<IH-AT?)%|Yc9ig5`_#@F%9zty1bU(-&Xm4 zr(oj8<PKdhdj(g8oV`^}=o;;ou=Cg*Rat#4yF6w4?y-^SOaIb<`N@wDoLV}w?OIDb z7HtsD+_CD&REKnZtc2%`p-cZOgoJ%plE{y~iVG*^`cVXr?|lx*WNY{b8MbYJyxADZ zGK|oAqtjX9)ygs+^h>teH-!{er?@$OH@>sPVOW7#%tZ97{dh?UOe+O;n6x~OoOo>H zIXRVKv{Se^=DD$8-IgxS3ytnLdCqDij$1uh%60s6vH9x=-tBeU?+N@HizCROwHARH zKSoJ5>^TQ09lcPkI{7@)$-430a_t~t!bLhqYE@-4p!kfiApbhz-VW;K#&k1dHLeJ% zlOgvgL_iV}oh<s!<brWwo#o2_qmSo<DqY!=icG^!MYG5oMhNR}`L?nIz4U&xHMphy zpuNaMY=;$!A$Sb8JH+m9ni<%RK}lJ=KY7zfSS%4bZ+>+yd@<1FHlJ*(3fPlN5YWBD z!>^gG8F|9L&ewH^G|hC;cQ#`Bq`+w9aA@o~NSWB^ySFz=gO}~cTkaj7mv*|YELInD z4gwv?GqI?Dq5UB4f`bm?0nELgq9V&I*SftutM9cfH4*>$4hv^Up%hB@%q5l^w@x>; zBg6GJS9=%NS7%MDUD#5k-CWMVhxrbw0ZI_S1Ug-2b+AyEha6K<z}2~0@0~Y#l&zzd zfD0GM@TVvmsBD^k?$AASLuYOv$7gxc-y<I>!Nd7;8v?yP+gqGtv$;h7FrDwgQ-gf< zusCtsFXoIqkk`s6Zq4))obtC^aL*qH@=4_C#v&UctbbmoW!>pe^IyI#9am|E+zH%$ z<#qCN5*fJy81<)|fzpG7;s0jz$$MH;A;|m7Z1<&Apm)y5Ki1J)T7|oIAA6p!yS@rN zFnYcbaiHv2{%;Y3dGJ1%keee@-uK_n1v@=9ni&zijJ;k{pUwvDew6mFbTX2rJG>S~ z4pHiFVnJXIx!#h^ga-8ymkZsJ3Md9b2@CHM>kjbff+$dqpO<@bx&icO0&Q|dc;`sj z^|DLk;Gjg2#N-hTr(=b^!QOc)_Z_T7>(JCJ1M-%P9C>;29YQI;@j;lWf8UN)y2mG* z1E;+8qG=`z?l1iPr|3bzeMHVQqjujF$e%-N@mf(6;x4Dgaw>9+QH_6LlN@bNm+x>3 zV_~H}!O<AFIy*L=g_<ce<Ym9F9o~HH0AHw&go0Jh95V)B+EinB!e;;pbsMU_NzU?* z6NNalU8M<Cp}%WiabBa}zw05|MzG~Kp4K4Sh2L8-x2R0%gjp})cl;N)etoNn&N#uT zn$(uk@k-^mR*J$|fsj2m&eiE~s`<LuLP^N5%eSbthnIK-^?ANLxqNy|S=qy5-3`$N zb6IiJdLVv;fGtohf+ApnzrID<Lv_;RZW_-GjJ>^aTs@xW#;fU<=u(^J)JxK}=C4_Z zxNq5cnjIx1uPd^CCt4Et8~WlH(zbT}VmJ}U%mdaMA0wQ(h<eYw35e}@8BZIzcm??Y z;3WFCO`|I<cjMR#Y#%pGG~5{6PpV7{NU$qzo4<EO_zI_EM;wb>pEHmaoATcy89p}E z4`vvC<;reW;T)MmeFBYXD8G3!UPPB8=%Q<Cfcs1g8-^?7k}qAa`!}VQr3p{`?~vTk zEdt!7hwioSe26;qSh8SNW3I~GbA2^_Vnam+)OBZMuK|~fx^?QjphmpJgkOW=p6N~G z$Ms>ghOO0ZI_2V!-4cgwU%91bUjGU$ww0e>Px%Z7(oah`sCGp_#BG`xR$uqckXAa> z%oS|<<o7{&SQXhM6rKW<RgzHKIxBS<iax>e`9XnT5^2|`+<6dM;oM_5{AKEbA&rUH zm8irB(X*Gb{rk(Rh<numzt`pl)RUw{LKHnIoO_<Vd$l@SN?f#Ay_6E~*!#!;PWaLL z<n+=h(HQ5`qG(a>^M8WBWym%paP8N-@x`%4%p)vDSafHRddqwMjzfB&PD_+<?6Kp= z4J4VD%H4)JaL?^k=G_Jt43mUSYh2iFof5e<tebJCBE2k6^L0>TN#KE-0KVk#Yhamu z2uV@L<o?bQzhMP(fWBq8`Qcti9*VkpdGf)`k-%p=o1VL)@6-v7oh95e(u8Z4u^hMg z9*jOJ@c8-WaM0en(=wzbJRT=upjYfU=GfW(nB=veEb<BQSA|ZV%T&)&F4V6Stu?Pa z;comSLd^cNai_T3xO#;lq1SKt`)AGM_8LF;Gx8x<KAzk0onij^!tHjge1IUKuaqQ7 zoM^i#zrFU(Ot;8y*r&eG>hysRGhwbuLTLG$WI{n4-w5Yvjf%heFgMF9@`RxNvn%6T z4Y%2)<IV>MAi7GnW{XQh##Eo0maDI#>^Uy_%yVc%@v-PV9u=N3&YvafA4c|e8DBZj zzrVwpWq&dElV!-}Q54k)L&@WQzrNMCJu+ZqX3kB5+qEW%V4=Ql{n=~iG}%C@PXRJt z4uq-J1gL88+d$S-BGn~)eV%K{U3hbh(qx*fxWlBDVaToz;s|#j9e(nAaclCT*~Etp z!n}pt?iYi?fs(9?zN_`TCeew)kL)Ffip?*7JmdYd2ht^=W2kv2wZg5)p7A0zHOih6 zFV?_$TFl0(E~HTJS=z<76@5>Nvo$?nA#&d8AGN+b(?0@0oUtT?v6BnM{Vae**dm5# z_kqhcf==`-;wQ^~fKhTG2PF1?2PBYb!^_jI@JZ5q|Nh;vr>gX#2w@;!yE$EiT>&b` zDygtdr<;p8io3;EAbC>{T~mP6(M@0r?{fJ3I2iKqYo*%k<VPcxDN)m_svjSW{S4j9 zQD~2aDst>nL$C#c`~b~e@|{!8VG&tyOyCnV%cXg2^ypfCk(toV_)yh*5mhrS2^W&h z_6%R)HIidFeD@*0`Un!FjXSht?EW-&e(BZ6M5^SR=!!s;>K*jMR75xSoWg+#4*~qQ zU|c)ba~TspC^4G7rU%{0XuF}ARA_6q39=UW@{a|@L7;4<L97tO_d`VMS7m|+PPzZ= zL4B<WZXx_`e)EG6B%PCD@^A?TdaWQbwfE7X<TIU*9j`j$eZZY`&cz9mhyv2XEUtB& zEcVg9jbCUm;jRW_HzV|+a`E=g7YTWA%3iNM6-RE%AbL=E*d|vbTs5GLf;U^!2QjHC z{p!eq^Tn74Wsf%$?0g>+2K#fEXw@&uga62j?#yh8?cf_x0Wa1(HGr;cu-(pwv+~;& zuM0xfK14n-LlN3F1@e%woH-hAqQL<M;0oYB7A2vs_uz@=jgDRN`*nR>cBZQ?G_;vh z!4uR59@p;!J|QzQ>Ax)f0t+>(bh}Nju<^#x08-~SKO|3i^e9`%@J%r+H0?ejvOJ|T zGg%N5&Y`G!_v&e&pp`NmLi?Bl{Og@g1}OBFS%uU0=6GI^G>%5lv0dW~-C>MAE%yG` z;OmZjZT2fKi7MuO7YUtwiDH%<+iP>Eu6*sq(P**JpZ(AKs!5WyTQe6{X1b4q8^3!F z>K0waU1l~(`^M|ECp|{q9RBvwi&}Aa<zyMYCHq5~97#eaO(tv2AMV($#GUwR>eIs~ z_UQA5g;z^Krs+`QMBM5v2WraCva1K$6ITL)HaRja@PPbj(IW&2*x|`;ieU>+61mJ{ z_aRZ7#ZiqA7vcM({cy`&0kzk@b9&{D`uxY2!s<M}zn$@euuC;wJ9-@EF`{$^B$~(* zXO$O6-`!*V^2mVtwCI&L%byiv=j(o3+`R75R~vjONzC#Y+V)3#76x-&bM0rp{v#}Z zTbk_2%av|M)wyj(PmHs`F8fMtBNI+DvN0x(j9C5VQ_Eq-gj2~yya#M-rnE9R%^g;4 z3JZ`;+FLJzL$*Y(jKwORz&-2A(>%R;cmqi)!9ww>-1^z*j*I6x$L)+q-rr^yG%SqU zQnGw*uU+ocjj8dQ?Gahkt`k<g7`i7{X4jf;&xC)kG_E|F+xA)U_Z5wIUn`uA(sty0 zX1-JfZ%gItJiIkuyM014Nm#$`g83`>*Gl(TaLE(gt<x6%hkKuy8%UleEsY~%Ipn_t zN_dF}tT-Z~tyfWml8Z+~pJf08x$-{@<TRs*rf0y~&zsxp^H2Dt9$xghb&lQ`6J9J2 z3Eo<%uksx8SOleucAXq3Aq`uj_BN+Dcedy2oKoU<404h7$H!51a!cPWwvt56U#Z9O zP^iUnyz9)<EOq$I(UvZMdG{Hxtsh@2E)0>T&LU9pk`6ljY)k9rpv3JFS-PhX9B|6{ z|05ydqU+c4s-VrXt@t2KP9qL{|D99o@aAa^PmP9`UQ>Eyc#Z0{ug>as&p}jgL-VdH zDYUol9mNHBPqwikPBL;s?p-i3R=n#lR87L1Fn)GrlR+Jqjz>dNrQM$;N%{Qj>j-UG zFwg+SX&7Fd9ysEU+kpT5<4Aml(AvE%XF4cc-E~JRNto?Jl1Owsui9gJO<(`<BVV&s zqV?)Rf(;%lkLai68&B51z00R@?Xl65$Mo-f6RG+Yx!7YTyz_!Km%g`()uBflZ+53s zFdo_T>mL`EJZ5cez41A8FTAjGp@}n;D|Bzii4z4h_9dOBzx@moQ}!C1HJ<8`!Cs|c zYdjv;E07VCo%_Ud?0sLE-EnLlCND`3w+P~G=CAmRz;ABmg9u{_r}d9lQqHyhn2IPg zDNZ*_(60&bS%o}K>)~k?#M|aSZF#ZPUl&@pRr11Z@M43uMl<96Gy*K9cPhFJJyl${ zhn?>y<a6f-Leb3loYHUIT%0R*q1W1=%@P-I=lQnj@QT;k6wt!Rghd3f5ywuh;M+3t z)1aQ6LH%yLd6HZ5jA|b8LmZ^bYqCwhHH$d)={7(&+y?nt7<+sjsxD+VXi0kPC?=fE z5SI^<K|4E5B9(kd%(=s2OzKf^W?@skv#Wv+jB^x-JTXs;lUBc!kqmTV;_1cNB=CBi zNlTL-pC}lfmGjqgT}gB|SCIjMB46s(Ef+dYg)6(e$(AAdoYi;(moN0j^c<RO930OS zs#>U}HucU4^fW(`SSl($<F`5Uq}XQc{q52hYIrrBa>f?_?YYYCj(dwFz%^!_+I}q| zieBQ2^!?g3k}-rcxz%RXyhnq3i+=~a>Dnu`nOyh}{?va3>cx9h{kfp%)&<38hymw{ zZ9vHHT|Z_)J*D6y7h3P(UtXtqN3Xb(Su1~!o~ex65U<=5-D>8$St2?NZ=IH0nlBT* zqEir0zZVKV_OuCm%c}Vz5tqs>&{MtAsp)jPN*EHKBV?D){cNqd@>MuBz47n~&EUmg zAS*x1^0u$Me2Zeu^Jj@56c*-bEY*o$;J}2R`XY}72}rEtU&@UthBs4t#2?+fDw=Hk zZY7HAsc9)iS&RlpicuW>4U=LEquGjy@R&3avDl}BL$Cdc&CIwvx#|KpCz8A8@r1}7 zolhmPbEcS0DkC&fXCPjU67}h0@)mDyy-8s1!$sVC=8Dh2DOcI07h0a;e%O2`ZT5an zQ+@o6<f2$U7oZzHSKnV9mPqwLpt<E^4*Z8*?7jxq_)GkLhkSAGq!iFeFL&oX`%MBj zYP%BuF^%|i9E5z^!4)}|K3GL163sOlPrp<~FjGitt=uY0Q|Cw_MQyxR58nxFw4aHp zYi*GzJ*(OO6esDEVs!VMcD4`Fo}Gs*9{%Ij&gSxMo~Shotxk{KEg!nGh-0=W<u9_k z(!VQp6p^PKsbp24K|WoNc};>VqU&Not1yhW5f1XZeEGfxUx*!!kLZ~juw8%Qy5^dT zy38`1LNz^kp}0D`=eMGN>PI!s;9Sx41p2))7j+%e1T`uDTkvM#t5N8nJme5rZ}CTE zd&&aWe?1n(CGi!=1_P7pu!qLH5U3@@oQE)$!9qIuqN0xSW3F3=Q*l?h4s5W@R;~*{ zLQpN&{%Jdk@An)GT-@~m<`Dl{3y{U+#5r(Gno%I?<V%V47F{+$=twcQG8UAz;MU}u z8B>T?a)I~O9`0wY@tN&$lswMlfX_$jB;Euv39W;~WvqE0f6_IcN9Buf#FcXXxdD*< zzH(ZZ%P;babb8FaJ&JhFz<s<7cbNlc;WNE5y}>fwOP1?h%iDi?euFX~dwUv-*J$i# z^KGWS*Y2EV)YM-2_1BsC(a>BrB2RqU9lnASEkjhYffm0Aakd;2@hOKl-*9neKDYn) zSPIpuI#!rqWe7#f*<4D(x-tA3s4V_^fqVE@>$Jw;D<1>t$qy|WJWLYXRzNZp;ZD6A zGsII6oqe#(oL)4|@?6BJtBM@5pWtw~;n}<ATbs~=cHf%C-_~*rZYy$}`K>>D*Dkc| zsThb$rBb##8;dgxhj9VxBfQki&GVzT*1Hu$f2VhjxMvHCB^=5_y2AjB+Sl>g&w)t# zOWsO9)`tfw<4?Hal=JGd23G^0%XW?U<%+ZX_$&|6cPAy`O0^$IWd(1q&8XTjeyU2p z{_QtoMRgU(lTCQe*k&yk`aEvf*zF1#&>TRDfs_NH9xy9RIO$~;{730+Pu+&bn{h=G zWd+thGLb*t$U_3+4kMf=irKSrFer2bo(1)bRo3rU+AHKHfHfv+zd!tpZ%b^^N~&~? z|Mbr+K+xUaBfFg9HOc&%EIxdm4G|E}y&V!_pgUXTxDWje_3&>GxfBOpxIVb(YpS!A zaIz))6CB<4RNh}q!;r8s`M|yXnfWEeWgh7awQsU-Q>f;?zo$q8UGL0f{{6f-kPOgy z^*5lLzNHmD`4H8dk4aR7$SW8@we1fRH$KZP)1BZ{c$)O3Wso~ziqMt+$j*(ifM{MD zB-^t--cU^wCj9VjKb`D^=AFG$n{h{upjq)p>V$88i06%DN~9sEr^$FeT~9!(hhIq& zl;D+CG<j@DYfzwLMBzE}MMzXv;$q=O`g1bIT~hnU*Z_C%)pzE4d(mZ3sYkwu0m8~y zuEX2zBaS~L>4tNRA8LcEADIYYcxk>f=r?>L?K(gE!USXd#?R-UOG0+HKo+Zuo|BJ1 zBnwko+iafPiQ-q2=;E3P0<rJ$&%*UYAWhoNseu|kV&T=Fm&u6c)~O5mzZBvHMnx05 z3Um#i<!bE5J;(&0Me062bhV`5fy`a>c}ou_69jGoWS=OlJPRs-vxO;CAdzyu&r`td z@y33`hz`%RPW}dDP#LY_i*<a%%8!nm#doJI3-4A3to+Cl<%*f*x=KSZt@5x2dTE{q z*hR|qvAqzU&9ITT3CgJ$lGbVEt+y!eKt?YU|3p>LJ`s}!Hui#SXZwega;ngv;Kbg> z7(G7~D)NL;)5Zq{D%rPw00z@*gtt*Ou33BuX;F!qXiYYGew;|@;j+K+pT$vg770-k z8s@LOkpNrsIzZjNRb|<$%5+(IqZj3y$hXal`xDIn^R@|8{Xc{Y1X`rmv1*_g?{>M` zCh^pw#_Xd+_4-g?9R0+Sb!hivqxkhut#mnHAw!|RgW*nJ)X%C2YepVBbv{?hM3b#H zms=x&uXIS0i5pTDiCi;RPr*jEIj#KcH~1*mtm?>^N}Tw>ZTmi^gQ0cr*vlV!TNh&6 zt{WEWA?K#Z1q`-8r)bT4WA=OelRcgmBF8@LVE*HPVeRsP?X{YxcNPZy_9MG0sNK#0 zSfA117^;bCl!uh{a_Oea&8T{AW{Q2z2;IAR-srKC)Wufn1?z^0tbo;-neZ29K0-Zz zN1myJ4g@ZRJdko-=(P-ev`Ytp!u7B=cv8X_Hefyay1GnZ@wPS-AqfC5J^9#9lrR9= z=Y5yuJ>3apmuDb~-4M<I$-}wzX+)YJ|7paBdHnK=I*`!o)XUCb!ZVtH_kC8vrMc2X z!72TwubBh$nz~LlFK_^#9m^H->Kz~Igy>4yv=T48WbOC>8p8a+$-N&_sA?$5mFhoP zBLZAcE;c_q!t?3{AN{TsV9&Rkd@}>C_o2FSMG=Ikm;chx;A_Tj6&D<!TI!5>Nc!^! z%E5%|W7h&=JFSX?svaXiE$5B>vwlcl4g1+wJ`K-AF8?Guq*iWNEJxV3wROPJ`>esc zZG_wp51SgH6b5h*5z}_fkLT47qj45|z<q|SfHf`JmIs4MoJ^`*5`wI0C(w%Ajeee5 z?sVgGzHV%_W9xONE9QK8_1)7I!Bc{e7rOCY?CPKxJG)<T&jD)3YWUmz{xXZ*ZCe-h zs8{-=zD%UO@x<3MA;>fBBHoLt1P^p-TE9AQ*P(yh6_D&5j{^NZ!TY3DLfli@B;+27 zu>bn@GQ5c+knXhZ!%-I$g`mOy1WyR)D=x5OSXQ{m65szz;$Iy{E=jq+aOdrpsAG!5 zMR<Z11Sqrp0Ug=#C^+zw6yH@?9{1sP)=_DIE$XuH$V95&cfcy4q%!z6;Klj`PKP<( zOtouHJ>~an==Re)&mpwDx&(DrY1Pe0aQ2F4a2PsDnXXJ};eP}NJ<Q4XF-a;9?V<!T z$d_yXUzZ=ttDm<8WS3vAaQit*-@Sz+uU3AxOlU~8M5cVK3K^s7wEGm3naRbcnM9W? zW~rJACwR<GYVQQjbBI2a4Nnxp-tVV0xu;F=FuHiQmkkp>hMi2K^2$ewnf$R2fQ+8i z1XyoZ4u7qTcS*6NX(niZCZpl@>5JvA$6u-`|3cEF$g#<9uQ!dvDkvw9Sk--*xB=>D zi{`T6ZFNG4yW5#z32+w2$mKsP2%Y;|`kADn9^SuNRS|><zbrW$6QU1Iix*IPkpRNG z)W364?Mw03c0iK1`_lA)qXC4%4|4NhC4%~oL0C0CGyl=^S~^*vUs@%<0wjn(L`wjf zn*r540p>~v=Fm{B*F?^7b+*^&a=HwZw~Qv0Y$=h$8zY&$u`TBS2L(z)1E?1JkwmJl z_A;wzG8?6H^+q>vt&x5AG6U=tnfDQb<lhFD6C80R?<il)f4#wxMktXv-eaf><Rh~) zO^)(pco`Ct55F%(bwG%)ob0Rh5(rqCYn{+wnX11v0~GRQkPi~T$Le}2Obv`pH55Hg zTYZ&$2qcq<1FmR|9|-*1QZcB`Gbfn6B`F2;eKI4vMLILp!aDxYhVOiUYzdlw@+Gh` zX=(dPpar%2`(b+vXkm*Er%XrIM#HuJ*8nbeZ91_sGn^p_JTRUh0w8-9Aisbb6u`a| zP)WcCwpjs_dsgUpIW4e(A>eHnfQI>a!<?yr4iNi#SS6=wwlYdg_%Jzk&8y=wwP^$i z8$Wnm221MCiP%U|fL>9i+Ce?_M-qzv%Vs$eBcegnEyxJ?aIVN!vW-l<<Q!}!7^pBf zLO85*WF0U`3zx7gj@)4Zx7lrHU%1|fIWeb)Y!O!2V23m(KQ@$f<cK?eIwNdZ#c;|p z@Z(#SvKb}daX<9;3+Ml~tGGAs-Ro3VFZ#rh8zw2|Pd$sg@qMQI3C*!%%0qG_4;cK* z+n&-HB`^f>BmRF~<-QVN=NAV-2g6xqX}qO71~nl)R8r;hRDpr4@5FthF9H)4nV;kM z0UfFUj3Gqr1BJ-BlJ5iV`cvWb9;;s~nv<AC4QXC;GSEgpXqnL_>mdAp)xi;pV!%`k z2Cfw*H48U%ZZ7LjulBmOOGt75zi;WPWYv(bO{V_ex(%V@m2WV7z)`W|`8~A34om;n z9nyxGv?kWqqasV3T9~T!OS84j-q}-LBRhh`|84|N!IaqZsgDgGRH9uvd8Byt$lA#L z@7jRchAnYN#IDnPqd&fEQQ+Ec3&I7{zVH4I%|V~QuSZ5w=S%e19H)qtTcQz!^yHF_ z`r+Tk{%;dYjCjLU5iF8OHH$?P+HJ}H+2r^?3=4y@iu+p2f(iE#$_BbP2nhef6F@#w zceMoh>=iR8(fSS|LIzMo2Dc_~m0%ELcJ3s0GO*^pD8A8YWqu26;pczfGKN4yhaKou zCX|S(fH<*s5Z(m9xjQt2oriFO5LCwtSZu0CbIw_C(_|hHoWQIC2vD=+m?ep)1sB8u zUmcFeLMg((tW^NANE0ORSo!~cC_<1hq|>$;P*+|QP*wULb&ZNZKsEjL!@Uco?!yXz z(L4Icpg=WC`Gy{#mdc%bb?Q`v>rYYcDR`a%lfSh7mVl4vsj`^9+B-WBBKqDrs22$w zUh?as5f$c6WJziNk`yKkaqfAF1jOyahYQ7-0F4XkXH$0OYe(1ZZ5_Yl`|}Mb-Ae=4 z-L&q*4$oIF-wA0oy_Q1`DxGBf?*LEjv`S129LfRfYW}@0A7pv*Bg(@AHVGzn0Ag!2 zn+2}hQK-**{rdHhaC(Jy_p_QF!azS3Gh{=G0dYMhf%rKP7y=R0vHvmzg}m?WSt$SM zyyTMLZC}Lek=b}$WCFkD=tzBdbB1DFaqnheGU&?v;Qu$C5?ZfT0|%G<*TI4G;MDy% z51$2E=n>BBmwca^m6dx>V;jVSI?TzYzX@n1P#}O@g!v#puMd6N%Kz6{H3~uMe(zm6 z#v&Zmnk?4zIv-Bx9C;IVq&XGgTy4uX5(FY)%^5NRJLpABqyv(@X96V4e;*{EBwM-I zGXXEoI-fezQ}jd%?d6WD?s&;VuJ2TV_UfX3lyY-Bc9aWY^VJz`0bTRk!xt+AR8pq$ zmr6V_4S=$Y8K`te?Xe9PxDVH=r^1ECGlHts$SZjrtb_;SFJS!g$C)!RLxZol0h`}( zEFZoR`TQ=1Yy~2Joz{W9iZj48p+Ui3ZGljkGdWE6VI+xw)%jS!PNNireO-D*Q|0ua z)zTK^jivpyu_`$sstB+vC2-Val6m#=<{Q9g9E)L-qyp7UZ^1MDx2G+G!T?k!Br@FB zd!Ae0E8PVAe!N$sBDXbxpJ>^W6RQB#=16aj3rl`2E0hxAcp<Nzp5de^Wgd6f$lhsC z6zoTZZ!~A4;nf?X(N*B+#@#32g@AY&jaA%J($kAm*rZJKSf12Q6g7terbk=J+X~f| zKxH|6=Cuk`!SM@S)^HoGOQ)RS<pe$ry@{gAlA!MMnDEFYQS&^Y5RbnUG7|p;<WP&d zC$m5`9RoIE(^q0`S{G8YMXz_~j4aIcD;$hK(P*c_>p{EVsr~tJ(%5b3FZK&`Y!V~D z&SxCT>VrVRbzj!&T+cJ}=<f}YV_>AqKtdvT%iCu(F;O~j&BZ7L<RflLI#AiwgKaE; z;o8U1Yd?4H^FunPs%m9_Ex*&J?7iUX0FU_kULFzwV+#=a>aUSN8Ow)ZeyMd+5)#4i zY6kEEKGVQ<{}mH6I;~bG+>TJ6XuNv($VwnImg!T5Vl1@-w037n(|hI%t$=R2p`RXT zwY6ZEI5VYOzh;774u%d-+XWcZCsJ`!t;zJe+v|~Oe5dZhW7wrn6jv`DQ%0fU&l{Z= zHY=wgK6#;jqdN3wpST?0UHhs$dCBntSmc#^{A&G}nxMT5rAFzdln=hSa1Sdq6V2vu zdPLy2t~dINV0w~jHiF_W$J$7Yh;n})9v<FZIbihI@MeYa=9__oC?T^|*c~Mg;W@F? zoWR#V%=P?`SoOlSRJOR3tDrUZWO%sB^N4%RYEr6596uTrL8q_i-ky0F^tu?Hz~Syg zXUM$=KkMdY(17B>mEoPJa-4ggVHC!R@+mlf&`h}p9+(RcnfWNfZ6yhz5AteDq4HXu zDenxP3;V9>SYT&ZS3`z3v?5`haeBnxw*ds(hhL~puI}c_nX?zY^@d}5i!Ch&nM8&| zey{dg&OBJ(1aoHVzXtEatgpSwsBei?M}0}5N;!OA!tRzCmhX2xo45_--p;aa42S$h zGwBJ(ub}s(f(iEs*adS<d)xE8fYy(1y^HVfc;PzG4p^gd*8!G5&?I8)1?_>yNn+Y* zGWz#~-j4bZ7FIu&US5NHkP<@oIPqHQG-gZbRKMSNYmfs5)88>PB9A-!vBuqV))OD@ z^;Noaf;PuB(4x!H1A_(@H5Wl6t6-RiJ#iruu6`GN9S<4~RW8G|XGJc*Fl0}d5Iq(j z*=rF9A%?#QdNW*3xSJXr*B@3NPMrg~A^xK`1w4LzldVw90{o_vu{EIf{MY&&O1-9Z z<kr7=VHohsKDWUTjqguWpQal-)H*|#ye4BFKL=e=nShl-h~T?H%IEgvxT8fV*=;W| zIwIR;^~9SpS3EJ|s@0uRroY@WsuGSa!tQ;RmXo_ucS`C4_c;OscN~s|kqY;iPczZ@ zscBXcU(5Rm&>mIl>2A$;=%*10WE!7e;<f}lAa_sE<;Y}<09xYDvEk6)<i?1Qeq1nn znXraw$kucLh7XWoDG6s*&$B<Z>ncwax_0h4%L8fm7i<+jK8o*$Mj+y9Ns0LwsCqST zPD8Tc_wUH`9QzLx0qbGHt7e&&+F+p7YrvUnWw6j7#?kp4kfr?HK@5G`D*KlQkO4Xt zY6Hf6+u2ROb^XH${FfZ|AK>G5sS<!iG6Rpuu&AF55&yuVFf}SVRtAnAfeg9**eNnK zK71s}N|PcDP%Fp5odLBXnU`hw2s;xOPCaiJ|N8Q{t}=&g98yQ`ZjHg7|F~W>GMwsB zILml^@MU7(jVq?pu}#Bst7;FxymaRM5(zLNHpapTQqq1<2Fn6Wbg%&yGEUm(yZU>_ zi|IEy1zs9i=(yZfeDxW?7BCVjHuk{1R=>;x46?2K8oYdVt;D%kwBg-wU8v>R9)_;5 z&udV(xY*MGxbU$3CW0o50}JAyB>Er43208|!J9q1iN^*&2X_JV_%Z?EIfHur?c6YE zL#%!`zheVBqwtXJIqBwIQT@7?u_6{1&#%8~dw9v@BeD7DUE=lUX<u1Z<8!hUcNS1* z6hq{eny{5=9H%`!?OY}di_DA$?RZaze9&+2j0Bw@)g*&VrNcfMx7*CnZ82vQf>?=J z6VqJ<-L#%e7bKwqI%#@#>NP~Ov@0jhuOCWT1yAVk%)SPVUw2i{8svWmwgVcdSKia@ zkBu&@9{vr&+Dv%)x8UW?sf@8`v06Rpx0coZjPIgPn<S$@l(y>UalhCAjV8g(I8EsZ zRMofhmbF17pC+wxcadUCwc4P~FVrib5sOSR$kR%ZSh@!~>hH{SKsVB8VBGWvpc&+L zSGxK@12W;z%fvD;k$|BXmkNxhdiev3R=$&*lyUovEOu4*PF9j_?m#&qNAz{#apj3m zoI+#Bmc`yEfT5%DJFQvp#tdBf?~m!Sw+&w||2Xy5k*S?*zE_*t`)ENp8u|f@kvwj( zriF5J{DIQ+135FB5~;A#N*#pb;nM{q$Cn%NOJSC1?om`oqg|Z121;v@n1xT5BemzK z(Hs3Tu?)@=&5W6LJN>dh<Xe@e>2rI?owJwnMIR;h$AXE2$0@OW9~c=K#eeiaFL;~- z%ynj-9FU(wJDUpU?)5XpQ{kTRf!w^4lY|27H*U~dY`q69?3s{<?HmH;0@b#y2B@|1 zc(SD>sI0z&ar3{RyEwTrg&YT=M=__vUK4c%G-RRp`Kwo0gmfE+?OOBzvCq4%On3I8 zp@`)z4XDkn`M%Pe^CtFe<1hW@(_b+VKc~xk+AxO2<sr%JdF22Y5xCStL_+}-&b6l= zkH^v8yvMH#Kp7JBWWW4WZ)}Tdj%;jJxK$WiuJNm^B~8|AJhtKOTSNBoV99i9>HG)! z)U7coO8uRArKG`&qZ)wxLQ&L<x48rGN^VkRlQHmZ>I0E|6C*5Y0<u80;5hK2XeL5< zFy4LgHYU7{xjE!Wd}I~J<{MGa+F8nsQgh1#?CMK1CqVlanzqK%uaMJbATy9K9GH+$ zOC0W~>}?_Nd`NsJm*QP1Fg>8%O<MnD&accPwX__?Mw3J8BE?EVF0QbWpE&?in7B%y zJ&!Zw3E0fYdjKc`V)SgD^}AcAoQkieIeCMI2(yS8vwQ7kzBK_Th#2!&SS>;RSVqv& z&99sbBOg~lOX^yiP4hW>+(kYcp7{?P$5R+hU;DZ~osbiRyxrbiA2xYVWf$78GTmi# zjK>~|*G28^Y<5&Qn{?lyJ$bHh$xavb{q2qJ&-@nlm+&|5mh;-=H#&;mu2lo*{?>f| zZ9s*%u`OBz3POfjNlF1)g!TsTmproLLWr79r;`1sex2*ZgodvCDl>p{k$|v&<o<o) z$ZnoyG7K=?ky6S{<#HNHmu}KEPosG#z$`=r&9yd4xsB$8Y!HNmWEo52b}50C7;r93 z+$>7FpKHCjG!X~sWS4d`6p&K6M<wfPyu~Ydl83J|zYs9=5gxKe8ur{5{eIEmdhB{o z1X#3iD}wyYq|003;nP5|V#+(g*8s1^bX`P(Tp$9irgU1BL&R%Nul_pnk_OaU4`v#< z75>D@YY1Q%Jsu84zX7-Lreps(M-JnEnTJ^24pyXB)??%lnqyr3OH>Z#_FDA(J00@1 z-wgpwE3p40KbH@$5=eeALksBWvj>rVP7p%;st?ALN&{A%e5l_B&es&!v-!`&c07H* z%W=Svj)3}*;&U286_m>(QRD|ekn|T0^3Ekpc*l$7n(KhG;frC<c?zy5QJ}VPKb%)T z%ljsG50vb0{-cWe)soj6piEdWdq3A}i3#5&j^1Jc)qN*xGW<%N=aG!I)ElDp^#S)_ z&_t?v2n8m5o%kz>!vOj%L1StS%sGGi*8ge(RA(!Vd=P-vn%ebqU{ZYOBA>d=UQ6(? z)XtH5GJ9p!Y2Imv3D;zr9&wW~gN~yTuTXpeBSq8&Zysuc%sPR13`aM=-O#wpCA~)V zr%}8SDor)pJwE673GOfU8wfD*O++4OjsNbaxk%nTWN;MpA~P@;{o$&iS3a5-j(|}f zG$;&s#S{~|G}D9EaQuAzWp-WX2cD4UvD&~K_M`RcR9sZtjn{tjkCnS}HNrIubZ3p; zI0Bw-q$UgqYVm2X6A&<$C8ocH$Y7v6cxw<KfA79W2&xZSe9b~p7tuw*h0R|X?%wo| zpyxdC($xpxJ~O*O1mGK!N%0Y0!?&AeitCIkx0b|XukM7>a?S&f^%v-Mn-$8dcV+Xj z2tC6Mq5q)VDE$l=^E+Vl<&T>9Ak_36hEqA9<#h%O&p3AFLqxAsWxClHnZK6079L&- z%5(4ep|dxc__5E=a&vPFUa5jf*tbOiyBq_v1m{)lg_ov2$L4^?+FS=-%v7&}0(J~^ zz*T`~bZ1D|eHa0S+#A5x-=jo;nS=LB6WIk7&b`XHljPEA6b?!!{Kr(I2jPmxL8$B4 zkJvdKV0`AFVE=Ykvv~FTpC^lGlOn*AJ=w-ZW-|k%%}kd`-qmK2NA|&EudM2?IZ8s7 zKH64-iC@qr`VMC58UUBjP3_Hi9n653toniR?H|3xoMguboWb|0jL?WERdSn*PlIVS z%u-=Q3{*kb+BVZfk;}$|D`t6^Q~V6zNrSg!hy#XabCho!`_cU*dF$oM`oi}H(D(a< znrMCfR~cngdxZiKx)&sAFmk^v+Sutj$xFdUE6~>2F(wdtPUm`%fM_5z;so^i2>=Km zI$*-3lu<{krfpt<E>6T&TeA9_Vc^|+=RPcrYI4<g>gB34%KhG1o<aRemk%7h>|Q+- z>za@3@ol9J98|O4pI;=GOxb(O8NUm05sPC@Pv|GffnJhIS79@EtESDZ8B!$inv1BP zqYA0sT^n$EuarBw*u)vx7SS9ksB&&7Xc<%<o)qNK_U<Pp_pUbcN-~kB6~n0@?UnA9 zi5E<Cb}g#X6+=0Ic?T8-;UxIygiK2^&!cAU5`o_pN7olG0;t%~(slPAmLzXIeJ3=F zJt@pHN!k4j>>u)em6lH(3hIMArzAUZ{om$wvYyEdg`gA2ECgz0rwAm+X1iGHEil&h zFcRv&xn$?kS8`a=zD-Xv4uGE<xf*xR6XNVN%c?c(IRR*h0LC{4__O%VIBpcx&c;}5 zp=F%{fXG+D7?%*C`GItC0yBw2xXx|x)ngI+=u|gRzzI?Y4|c(9dxX6w$&&yt8O<JK zbWjLFR5cdmnW7$o0hOEvCyK=+DqMzGXm*I>Jsh=cu=?JKpV<b74xNRP|6c&gQSq^r z+(Py&@<TloM~_(nI|pNk3}6T}+n&?@V`^S)fATIJuWHO2FuK)k5eZ7NF~BJ~afY{1 zHZSFVd?5WKCA|N+!`PGJT5M|y{+zP?xuJkrk)4$;T_@b##LJ~N?^yGYI#B^7JD^r8 zy!+7i*SDKfV8DIOJuZblrKqF}Ov1KOxnJ)gGj)<c`01L1wmlOA2=RB0JfUsWgyK2F zX|B<rz68^i?tc6EX>&F`;=Yt}F_=#xvj8jFYuM(cyy1{-?cKoDneL9~4!RZe%H!PN znKmbT<WO=AEf1pvJC|lGe$whwnryu0OE4T+EG5>e>e%0QrP_bdG><!f$&T}S)LXE* z?lQiVrQcu!_tg8Q!Qh2m_<kxQcR__}0B5#8+)19azr+xg3~xl_Fm%yfKYNk&hg7rH z^`F6DC{i`^$qS=ka>El;PJigOymbzcU%<F8NMGVs)D#hU_02;^dFT7Gy6j(sbuL)G z0@v%4S)@OV<q+T*_s8DI4@sV-VNHnGXyc&_2n|2WRR;NM5HSZ#aOLE#0Hg?Ne>li% zGE_g6-W0$a{pys1hAWRyzNr6AW)HQ<Eb;+|*%^2+1OR#jBdjGy4rg@6#ifLAv}yGn zrWhCr1$vjyKggv*e;){dOmux=N`P2<u7(uoIbqdDb<m;u`&tJybi8mDuzDz+XLq*= z#PQ~=J84P0&rU8im-Y}DCsQOHn3y<h>BRh&L4!2$5QQ8OL2h@NP?TcA7445RNoaoW z9V&&jlKXS*WPbdBt^|%KMyT?e=fEV37Tqc4khG^GPPW|~eC?M55`bf8F74LJ^vQXu zga5cdik!7c*W}u(S@Y^Gx0!Z~?ocm{yb=Y88;ki{$F;d+#$iS@4Ll&AGN^cR@r;~5 z1DQu9Po(lQN-TR!d^kmZf)Oy>*wgkOp1br*@UsxVRP49_E)hH>!S~qk(KX;Hk6ycs z<1cN#{N}?Od*v&b!nvY8Fdp*o&rI{}=Q$v-uv5qUX+MJYfjHQ%1I>=OZPu`M5`!aI z>7#!ua!L~lpw?6T2zjEqg6E}PIe>VMeI?v1!ls#`RdT*RSwB6z6bUK~9ypvCut)mI z?n%Np?9GUsN|*OBY>t3w8n06!c1(iDQ%aq>&sQ)zHQhPu<eLLh4n`_S<OXO{+&-c@ zOKwh)S);JX-1?Xr8vDdY!#+t?=K!ALFh2le2L`sx4=JOYo-W9E4>E>r(GS2?IGy7X z6r`E@oT2u@rQd@LxhVkmY{J9!8AOKeOA=jr*=X7w0ETC#B%HY==?iooVq4Pzrx?y5 zA5b_PyxMKTDjxus0#ulT8nDl?s~rJkTiszT(&b8p-<Q2G^11)`uG@3U{ed2u|1gIi zLp85c#qUeITRc4_a;1vluE76k?@HsLT>EgTLqan4CHuZKWf@D6vJaDGWUEkz?2fb% z$4)3q8I`@kSfXrMDp@M~8bh{<sHD8vX~Fw{X7s+D-t+Z*d4GMLJj;DQ_kX#r|8-^D zNa?3|cBy!2uAU+1nZ~a&2s4{z&@C%!uRd%)^l_-%utUCC#80{>*Emky57Y$<W*yF~ zaBPgi+A^6~A_=r*%K|r#*AQRMk%Ew=AtJ066?MmcQn%|7e6<ibQ%~n=tTjc>7m?X_ zaY3?X<uyb3tAiN5Ps5eW(9u<^u}A?RhUL-b;E=Nk160hWp+#O|a9A*Rua3I9)NKm* zhpt%>R)bwEianhpWLvdTngLJojgipMkfNEbxb>uXU3=0MpXJoeIY{3$hES_NJcif$ z+Mmc^v+Mn55SkOYnmKXa-q$|<9=}REr{{pE<&peubC`{T1N8VEH_#bF8G?qf0O~Ug zt_zmYml!;OQP?O1MR}tyh0ihny364`9%f$0KT5)I+mESE(q-F3dZ=bUDejV(C;^1) z#ECWDAGnp5el^(#v7DPHhbz%A=pAi%W4Dmy-D8tIBnBQO*KFw<fdR`eF2DqK3@T#t z7TP>VozfCt7!;CT`m*>T4^XIy_XZ^fp#<f#lO{@rLTzb3%mhPFG*=kXhSR}1R_d&^ zl|KoF!mIq-Uc1TV5_=eH*dnc&LUChm;>cD7|7DFtdTv>2*=MTu?&Rt$6gvf%h-ECG z-#-TugYdQ}lzbX*o?cEG%(dRBk$OFT7=C|LO)cy>Tt->BXh1y^oZtKu=q~Zcj?cc^ zv52!qF6ufbd~lrI4Kb$Ma1SM_PwUjlDX0->{bFQ_$|HW(j!%-VLJEm{wghuU#g-Za zJWjBqDhhvix+;<CafA0v?ckelp&r9W5cfVNGFLPv!9nP3Pf4+X!3sRagUks$6u??= zHayVqtbT7o@0>;sslxo*91G|r2sqxwaHyUcku$41d>Q&O+t2oHsgQ6++pF*A_Yr87 z9eZ{Egp4MJWVC<salp3%;p|qwEbcuwWlk=z>~gXTT>I>FtjcRM37a_gdAHrn4tRFk zyA*2kZ(azlQ103XRVsV2_ZzJLe222eS2fQO6+}w{$9Cbf=TnB|Pp|YcwWAnoyExM* zw35Qcs|TfczN`UN54y@d#tGJQe}e1qdBtSKV>SNVfK)X>P>x62X}FJ6u_Vbmn#I&! zT$Hw{aE}7y0I3-O8K(&e37L86_X!y*LvjnEidlp41*k2h-zI`27<Aq7KsEpX$Bvw1 zghGVO_PRs))jc^jj1j`<#tCgCd=RI4z-D^3<;{O##qo$6r(c<W*M;;IjZoEJRdg{s z`=KAVcpD}|v8cv4fw=B&6Z6~V29JgTE^z2fweC=qh3F=t7yEP>)XEMm*T#UIG^ynU zpx(8=FbbqPCt<05zRfnJ=|#)MLMyIS?WMjzrPe9d5<lKQnnNxcf)t<c{M!ZyP0>gL z0nc&UQq_B+ZthLnEI^<Ipv0!qxFDzzCJ`Y_NSfRVLecv=_$D+zg{2T`OOIxgLKQh0 zbv|j~&_mFunBOStPw~YWhGieQZu)Lf!VI*;sv!Vs8_20g`%oqW*<o%k3@LeYGXl)! zb}mLqGs%B7sq{QvZf=kc8GRgPFdJYw35w01j^1+~+mCfWO|>MFwLumZsiOX}s8USo z7Z*$v=uDLr+r-}ioRu$TAk1)?LoTFUxB1MsmD3Jg>ARpXkHYlE9|#P99`N|1vh&k6 z3)91#z{4HsF}d&U2!zatFJa)d50K+edAR`*;HKWE4>s@a;UW>W-0U$ZY=BUe0ZJ<S zy135%Qtf<*Un+h}vTA21gP>c4Mw(j%APZ@W!bsq8i4b0VK9)4?@n7+hwXNm?xaA3? z<Gz4MwR2OWfT1?sIv6U+6w9?^%}o^EOw0+HkV{4s%_A_%Jz8-^t>^%j2cZR^O}LFu z;P(fDHxHwG12Vmw97+fwH+G^>A<8d(w(w%yO;S<|pdJCRM>jp44QwQ!XU)T3cW_~K z;z?CjIcozL5|Iw6N`JmdHOr8%>KX0Ja3EcvFhEL4klIxtI25JbhG5i|B!c|CA?x34 z0eBGDcJe(t31^x*--<(I+nz9N<#kjy?YRIpbl&@IBnKq$9+;s3P#zKMdGSIF7?z)^ zUNhlIy`i9Y59$8J|K=mQ)H7P0s+!pVAzG0#+5XcC5oq7NX=jmxOihAGT10w>SV~|Z zOjbIQeOHN!Drl!z=e>Xt;gAvwv?Or*N=O-1a#@`pm`U}&Uj5gu|N7v6o%O(9VeX%e z@B`r6vQ=<P45P~ta@|q?aH@9)17uj3^?iiQ`d$d&8&)gGt}m$@@S-ZZQITM?82kjl zECOwT!f4MI@TtPdKGdNY2iem@4iOu$c432GchG(JS){sk{EsyfQL#!Y<s$<{I3I-M zbqlAUMf}fpQm7e8xTqd@J9%z+JB9a*=D3%lk+h;oV*v$%Rodo$V?a;-;vJ=5mj##P z$5qEXz_}Eg%8!si7o1YsQbX0PTY)?nX6LOAfRSSz^0?qxV?uq!ID~jtoW)FGNcFlc zUU+=9AX7dlsEO)+@t>2NMhI$48%q@dcfc4$HzjMk%ve3%(sx|h;0b_WS79jbQnx7& zjZ(7JhVck;m;Wr;o%o1FM11tFQ=gA5?0QG?33AoxfeIH^#B?J0o_iFyb4U)sh`Y!- zKa>r-)%{NPB`fVzm9%`Ic*-a#1bWQzsD<~>%8n{u;n~NLYn=YHB5mK1&j+JWMB5h+ zxHwTEp-{NJ&rLrxkMSrTza-!VDs+OZg;C-xz?lyfAAYwhxP?$JxYR{;eFO<Ru{~JR zFx20wD_t3V3M9-}cA1l4HN++FEgGQez168RJ?03HMc}H^#l;Vo)Q2m_5u?Wf$JSd; z&+q1aed(uvLscOe;~vSP6(LD%zAnM6k%qw~9yr&?D7Lc}*jQ1JT^?vqF0j-R&DP7% z$g?e%#&V!Nw;$!eQa+zi1i=DI#1kly0XdP~F2=V=V=FBQ;5fmzrsikCLKqB3thino zr$*v|aS5=p;xfzDC%(1;d3B+6S>}aGPsF9F(6)lHA)2G1gjK?%+THq?YM||-3tyK! zL=96c64!_G@jkVtB1S1HEbOg`T0PkY$FJ#}52b$myJ1Jqw}f37KIk&z`7hkG?=8{^ z7)N&|Xa07WUyW_BC>uc6cNqcEc%HTDv-Dtd)%a|@sm~~Mo91x;ooAJL%wkNSDbT%} zsw(v6Ip`#7`PF%>1EO=&AD3*QBkN9*WGw7k7v2x71FU?!OuR9MFA92yq}H3^R3jiC zL^rVSeubMc_$hQ;c{0rI?4shoAlYhpJM41p`rYQ$)3d_zZ<~pyXgckxf@lHkVqTeZ zUs*c36#%LwmFD)xY5OjaOLKs|zqc}@<pA(H#Z)6CwM#uW`_L(QAV8t;4>o__TQHZE zo_=<5NQvyxz3C70!pP40`W;=uDHKO7QF~6<jfW18A5Oz@P+rbi+TYzHDDcfuwI>>s z)H&u-3%mAg5^0LT`|(UnWK{#n&b(r*F&l;o|5USXYw!e2d$Rs(p|MSAs$XXs27BCR z?3H?V3NZoyz%2i+JxW!<DRb^a(eDdk^seZz_WiPU<=X+UI0#;l?0A;AYTx-xw@W*$ zihcIBCQ5}~;g;7P|8x3NZHfCEY`N2+bTkLr!Z4-hz$yS&FQUoD8c`wWM-HyBRw~rE zat3;z)C8Hz3PR6lf4j{{5q#liFMwax<X}+-DikAkG}Gx-4aF}cL5lUk;#7E_+jC*R z{z9JuZ%3nK43oqTe)G0i2kTzMG|~C0aGnKedvb*<X+m?2TZqZ5CbgIhLX`5s`_|)) zH!;6QsHGV!X*EBj3;be0-zpQ%Fy5Pw@9Qd?XblHr7Tx#P#IhW<m-HvlW?R?4tyX@y z-wrNl2Lwo1g2`8rIWWmho*vbroCZxAV8rWA+bco%>*MxvS+&p)^}l&TZ%Mq_1zVas zHWbcq{a<qNtf^Dv!u;zhvs9N`!Qe0mU!nxQ@oxwNh`uH(!LwN=do0n6)Sc;qzvn*0 zcIIuD<+3E-${3xYf=HQwx4(?QMr`i}AHQy5lht?67oW%=c95&a3~i;;T4HDpck7kF zJ#PDL`<@LaDA7?L_(qy?yJvR+hN2O^^b!8Oy)nw2owE3w=qER3n>T>OT@2tdc!_r7 z#}&jnBoKP1$FN7J#u!to7Zla<1@Vvq$_ko%6!c#4dpxgX0^&`L-SL`r@E0@@$?Oft z5)n^q-`uHqGbAzm8r6~nV6pnFs7ljHDJBdyA|)9tN${9KPU=e*K*%fX-1H$AE{Dt< zP)vlW;l~tSCQkgN?h6P%lH8uIAjZKBI@nPks1RJ#z@4Em1ECDQy8u(aF+I5C{$wBC zb16OcSq@eCFi@xLnD8fcLyD8(X{H#91Ag{b)TH4T1A5l^wFlV)8ya(MEGGxrbOP>s za-pV+I!Lg5TXLYK|Mh~uc5w9n@e|d|4*qV>79X^}4UroLhL?z<A|-;?x7f#I7OKqf TzlHyDWs`x<VePwz>_h$yUHz;> literal 0 HcmV?d00001 diff --git a/README.md b/docs/README.md similarity index 100% rename from README.md rename to docs/README.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index e8b3900..3cab1bb 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,6 +1,6 @@ # Table of contents -* [ðŸ Home](../README.md) +* [ðŸ Home](README.md) ## For Developers @@ -9,11 +9,14 @@ * [Setup development environment](for-developers/get-started/Setup-development-environment.md) * [Configuration](for-developers/configuration/README.md) * [Gateway](for-developers/configuration/gateway.md) -* [Connectors](for-developers/connector/README.md) - * [Parsing response with JSONdata](for-developers/connector/Parsing-response-with-JSONata.md) * [Gateway](for-developers/gateway/README.md) * [🔑 Authentication](for-developers/gateway/authentication.md) * [👥 Users](for-developers/gateway/users.md) + * [🗃 Static files](for-developers/gateway/static-files.md) + * [📠Cache](for-developers/gateway/cache.md) + * [🔌 Connectors](for-developers/gateway/connector/README.md) + * [Create a connector](for-developers/gateway/connector/create-a-connector.md) + * [Parsing response with JSONdata](for-developers/gateway/connector/parsing-response-with-jsonata.md) * [Frontend](for-developers/frontend/README.md) * [Update GraphQL Queries](for-developers/frontend/Update-queries-GrahpQL-in-the-frontend.md) * [📊 Visualisations](for-developers/frontend/visualisations.md) diff --git a/docs/for-developers/configuration/gateway.md b/docs/for-developers/configuration/gateway.md index 7f879ca..d38ab15 100644 --- a/docs/for-developers/configuration/gateway.md +++ b/docs/for-developers/configuration/gateway.md @@ -27,7 +27,7 @@ description: >- | AUTH\_SKIP | boolean | false | Allow to skip authentication. Warn: all routes will be accessible without authentication. | | AUTH\_JWT\_SECRET | string | N/A | Secret that should be used to generate JWT token | | AUTH\_JWT\_TOKEN\_EXPIRES\_IN | string | '2d' | <p>JWT token time to live.</p><p>Expressed in seconds or a string describing a time span <a href="https://github.com/vercel/ms">vercel/ms</a></p> | -| AUTH\_COOKIE\_SAME\_SITE | string | 'strict' | Specify the cookie same site option. Value can be `lax`, `strict` or `none` | +| AUTH\_COOKIE\_SAME\_SITE | string | 'strict' | Specify the cookie same site option. Value can be `lax`, `strict` or `none` | | AUTH\_COOKIE\_SECURE | boolean | true | Specify the cookie secure option. Should be set to true if same site is not set to `strict`. | | AUTH\_ENABLE\_SSO | boolean | false | Enable SSO login process, this variable will be provided to the frontend in order to perform the login. | @@ -43,7 +43,7 @@ description: >- #### Matomo -Matomo is an open source alternative to Google Analytics. The gateway provide this configuration in order to be used by any frontend. The real implementation is left to the frontend. +Matomo is an open source alternative to Google Analytics. The Gateway provide this configuration in order to be used by any frontend. The real implementation is left to the frontend. | name | type | default | description | | ---------------- | ------------------- | --------- | --------------------------------------------------------------------------------------------------- | @@ -51,6 +51,16 @@ Matomo is an open source alternative to Google Analytics. The gateway provide th | MATOMO\_URL | string \| undefined | undefined | Base url for matomo scripts and data reporting. This parameter is `required` if Matomo is `enabled` | | MATOMO\_SITE\_ID | string \| undefined | undefined | Matomo Website ID. This parameter is required if `Matomo` is `enabled`. | +#### Cache + +The Gateway offers the possibility to cache some of the most used queries (domains and algorithms queries). This cache use In-Memory data store. + +| name | type | default | description | +| ----------------- | ------- | ------- | ------------------------------------------------------ | +| CACHE\_ENABLED | boolean | true | Enable or disable the cache | +| CACHE\_TTL | number | 1800 | Define (in seconds) time to live for cached elements. | +| CACHE\_MAX\_ITEMS | number | 100 | Max items that can be cached at the same time | + ### Overwrite parameters These parameters can be overwrite by either diff --git a/docs/for-developers/connector/README.md b/docs/for-developers/connector/README.md deleted file mode 100644 index ac68aea..0000000 --- a/docs/for-developers/connector/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Connector - diff --git a/docs/for-developers/frontend/visualisations.md b/docs/for-developers/frontend/visualisations.md index 56395ce..3b6e066 100644 --- a/docs/for-developers/frontend/visualisations.md +++ b/docs/for-developers/frontend/visualisations.md @@ -1,6 +1,6 @@ # 📊 Visualisations -To see the different possible visualisations in the frontend we have integrated [storybook.js](https://storybook.js.org) directly in the frontend. +To see the different possible visualisations in the frontend we have integrated [storybook.js](https://storybook.js.org/) directly in the frontend. Start the storybook by launching this command in the frontend folder diff --git a/docs/for-developers/gateway/authentication.md b/docs/for-developers/gateway/authentication.md index 6c8a63f..df126d6 100644 --- a/docs/for-developers/gateway/authentication.md +++ b/docs/for-developers/gateway/authentication.md @@ -1,6 +1,6 @@ # 🔑 Authentication -The authentication implementation is based on [passport.js](https://www.passportjs.org) it allows a flexible way to implement different strategies inside the gateway.  +The authentication implementation is based on [passport.js](https://www.passportjs.org/) it allows a flexible way to implement different strategies inside the gateway.  For now the authentication system is quite simple and only use JWT. The real implementation of authorization and authentication is left to the connector/engine.  @@ -10,7 +10,7 @@ The communication between the frontend and the gateway is handled by JWT token w .png>) -The gateway will handle the authentication process with the frontend in a unique fashion always using a JWT token. This token can contains information specific to some connector. For that purpose the user model contains a field `extraFields` which basically a dictionary.  +The gateway will handle the authentication process with the frontend in a unique fashion always using a JWT token. This token can contains information specific to some connector. For that purpose the user model contains a field `extraFields` which is basically a dictionary.  {% code title="user.model.ts" %} ```typescript @@ -90,3 +90,18 @@ export interface IEngineService { ``` {% endcode %} +#### How to get the user  + +Whether you use the local login or a 3rd party system, there is a unique way to access the user inside the Gateway. This method through the request :  + +```typescript +request.user +``` + +This request's attribute is feed by strategy policies defined in the Gateway. Currently the following strategies are applied  + +1. JWT cookies +2. JWT bearer +3. Engine (use the connector to retrieve the user) + +Even if the `AUTH_SKIP` is defined you should be able to retrieve the user through the request. diff --git a/docs/for-developers/gateway/cache.md b/docs/for-developers/gateway/cache.md new file mode 100644 index 0000000..f8ce081 --- /dev/null +++ b/docs/for-developers/gateway/cache.md @@ -0,0 +1,27 @@ +--- +description: This page describe how the cache is managed inside the Gateway. +--- + +# 📠Cache + +The cache system is a In-Memory cache (but it can be changed to another cache system like Redis, see [nest documentation](https://docs.nestjs.com/techniques/caching)). + +In the following picture will see an overview of how a request is handled in the Gateway.  + + + +The engine service is like a proxy class for the connector, it implements the `Connector` interface as each connector does but it adds some overall functionality to all the connector like the cache. + +#### What is cached ? + +Currently only `domains` and `algorithms` are cached as they are the most used functions inside the Gateway. + +#### Cache life cycle + +The cache is create whenever a user makes a query to `domain` or `algorithms` and is user based, so a cache entry is created for every pair of `domains|algorithms-user.id`.  + +When the user logout, all entries linked to the user are cleared. + + + +  diff --git a/docs/for-developers/gateway/connector/README.md b/docs/for-developers/gateway/connector/README.md new file mode 100644 index 0000000..e7dc8cf --- /dev/null +++ b/docs/for-developers/gateway/connector/README.md @@ -0,0 +1,2 @@ +# 🔌 Connectors + diff --git a/docs/for-developers/gateway/connector/create-a-connector.md b/docs/for-developers/gateway/connector/create-a-connector.md new file mode 100644 index 0000000..0e82f4c --- /dev/null +++ b/docs/for-developers/gateway/connector/create-a-connector.md @@ -0,0 +1,153 @@ +--- +description: This page describe how to create a connector +--- + +# Create a connector + +All connectors have a folder under `src/engine/connectors/`. If you want to create a new connector, the first thing to do is to create a folder with the name of your connector. Take care that the connector name should be unique.  + +Inside your folder `src/engine/connectors/example/` you need a file name after your connector for e.g. `src/engine/connectors/example/example.connector.ts`. The connector should have the same name as your folder. + +The connector instantiation is managed by the `engine.service.ts`. + +Here is a minimal implementation of a connector + +{% code title="example.connector.ts" %} +```typescript +import { NotImplementedException } from '@nestjs/common'; +import { ExperimentResult } from 'src/common/interfaces/utilities.interface'; +import Connector from 'src/engine/interfaces/connector.interface'; +import { Domain } from 'src/engine/models/domain.model'; +import { Algorithm } from 'src/engine/models/experiment/algorithm.model'; +import { User } from 'src/users/models/user.model'; + +export default class LocalConnector implements Connector { + async login(): Promise<User> { + throw new NotImplementedException(); + } + + async getAlgorithms(): Promise<Algorithm[]> { + throw new NotImplementedException(); + } + + async runExperiment(): Promise<ExperimentResult[]> { + throw new NotImplementedException(); + } + + async getDomains(): Promise<Domain[]> { + throw new NotImplementedException(); + } + + async getActiveUser(): Promise<User> { + throw new NotImplementedException(); + } +} +``` +{% endcode %} + +### Constructor + +The engine service will inject some properties into the connector through the constructor that the connector is free to use or not. + +```typescript + constructor( + private readonly options: EngineOptions, + private readonly httpService: HttpService, + private readonly engineService: EngineService, + ) {} +``` + +The first parameter, `options`, is a key-value store that contains the `ENGINE_TYPE` and the `ENGINE_BASE_URL`. + +The second parameter, `httpService`, is an `Axios` instance shared between all request. + +The third parameter, `engineService`, is the engine service which inject itself into the connector. This can be useful because engine service provide utility functions and use the cache system. So you should always call engine service when you want to access to `algorithms` and `domains` to avoid to access external resources. + +### Experiments + +The Gateway offers two possibilities to manage experiment  + +1. Experiments are managed (save, edit, delete, etc...) directly internally +2. Experiments are management by the external engine. + +#### Case 1 + +In case 1, we assume that the external engine will only offers the possibility to run experiment (not save them). In this case the connector should only implements `runExperiment`. The gateway will recognize that `runExperiment` is implemented and that it needs to manage the experiments internally. + +This is done by using a `PostgreSQL` database. + +#### Case 2 + +In case 2, we let the external engine manage experiments by itself. This required that the connector implements `createExperiment` and not `runExperiment`. + +This also implies that the connector need to implements these functions + +* `getExperiment` +* `listExperiments` +* `removeExperiment` +* `editExperiment` + +This will delegate all the CRUD work to the external engine.  + +### Authentication & users + +There are two possibilities of authentication both relay on a external resource. The only difference will be about how the user token is managed. + +1. Inside the Gateway +2. Outside the Gateway + +#### Case 1 + +In case 1, the identification is managed inside the gateway and the connector is responsible for making the authentication through the function `login`.  + +The Gateway will then manage the token between the Frontend and the Gateway with a Json Web Token. + +The logout is managed by the method `logout`. After calling `logout` from the connector, the gateway will remove the token from the user's headers. + +#### Case 2 + +In case 2, identification and authentication will both be managed externally through a resource that is located under the URL `/services/sso` for example a [KeyCloak](https://www.keycloak.org/) (exareme is using this strategy). This implies that the `editActiveUser` is implemented and allows updating the user (needed if ToS is enabled). + +In both cases, the `getActiveUser` will retrieve the current user logged.  + +### Configuration + +The connector has it's own part of configuration, it's mainly parameters that are closely related to the connector and not really with the overall configuration. + +| name | default | description | +| ----------- | ------- | ------------------------------------------------------------------------------------------------------- | +| hasGrouping | false | Define if the connector is able to make query grouping by nominal variable (mainly used for histograms) | +| hasGalaxy | false | `Deprecated`. Only used by Exareme engine | + +These elements can be configured by the function `getConfiguration`. + +#### Filter + +Filter configuration describe the types of variables that can be considered as number. These types are closely related to the connector as types is depending on the engine used.  + +The types that should be considered as numbers can be configured by defining the function `getFilterConfiguration`.  + +`['real', 'integer']` are the default types. + +#### Formula + +Formula configuration give a list of available variable operations. Each element contains two properties, the variable type and an operation's list. + +```json +[ + { + variableType: 'real', + operationTypes: ['log', 'center', ...] + }, + ... +] +``` + +To define operations, the connector should implements `getFormulaConfiguration`. + + + +  + +  + diff --git a/docs/for-developers/connector/Parsing-response-with-JSONata.md b/docs/for-developers/gateway/connector/parsing-response-with-jsonata.md similarity index 100% rename from docs/for-developers/connector/Parsing-response-with-JSONata.md rename to docs/for-developers/gateway/connector/parsing-response-with-jsonata.md diff --git a/docs/for-developers/gateway/static-files.md b/docs/for-developers/gateway/static-files.md new file mode 100644 index 0000000..22e6e29 --- /dev/null +++ b/docs/for-developers/gateway/static-files.md @@ -0,0 +1,20 @@ +--- +description: This page describe how the static files are managed +--- + +# 🗃 Static files + +As different connector implies different context, there is some cases where the Frontend needed to change depending on the connector currently used, the changes can be related to  + +1. Custom CSS +2. Favicon / logo +3. Terms of Service  +4. Login page  + +A module so a module `files` has been create. It allows to have dynamic resources based on the connector currently used.  + +All static assets are stored under `assets/engines/*`, in this path you have one folder for each connector. By default, all resources are retrieve in the `default` folder. If you want to override a specific file for your connector you just need to create a file with the same name under your connector's folder `assets/engines/yourconnector`. + +#### Markdown files and static files + +For markdown files, there is a specific process which allows to define a placeholder for relative path. For example, if you want to make a reference to a static image inside the Gateway you cannot just use an absolute link to the resource as you don't know the domain that will be used. So for this specific case, you can use the placeholder `$ASSETS_URL$`. Which will be replaced dynamically at the markdown file's rendering. diff --git a/docs/for-developers/gateway/users.md b/docs/for-developers/gateway/users.md index 40dd3a1..c6ed6fd 100644 --- a/docs/for-developers/gateway/users.md +++ b/docs/for-developers/gateway/users.md @@ -9,7 +9,7 @@ The gateway is not meant to manage users directly. This is the engine's role to ### How it works ? -Let's say we want to retrieve the current user, the gateway will ask through the connector for the user's data in the same time the gateway will look in his own database if it has some data for this user. Then both data are merged to fit the User model. Data from the engine have precedence over the gateway data in case of conflict. +Let's say we want to retrieve the current user, the Gateway will ask through the connector for the user's data in the same time the gateway will look in his own database if it has some data for this user. Then both data are merged to fit the User model. Data from the engine have precedence over the gateway data in case of conflict. {% code title="user.model.ts" %} ```typescript @@ -42,27 +42,4 @@ After merging data from both source and make some integrity check the gateway wi #### Update user profile -So now we know that the data can be retrieve through two different sources, how will we handle updating our user profile ? The system is simple, the gateway will ask the connector if he can handle the user's update by looking if the function `updateUser` is defined in the connector. If it's defined it means that the engine can handle at least some part of the update, so we delay the work to the engine. Now if the engine cannot handle all the update data, the connector can decide to return some attributes back to the gateway.  - -{% code title="example return update data" %} -```typescript - async updateUser( - request: Request, - userId: string, - data: UpdateUserInput - ): Promise<UpdateUserInput | undefined> { - const path = this.options.baseurl + 'user'; - const response = await firstValueFrom( - this.post<string>(request, path, { - prop1: data.attrib1, - prop2: data.attrib2 - }), - ); - - const { attrib1, attrib2, ...subset } = UpdateUserInput // Subset of updateData - return subset; - } -``` -{% endcode %} - -The returned attributes will be provided back to the gateway and will be handle internally as far as it can do it. +So now we know that the data can be retrieve through two different sources, how will we handle updating our user profile ? The system is simple, the gateway will check the connector if he can handle the user's update by looking at the function `updateUser` is defined in the connector. If it's defined it means that the connector can handle the update, so we delay the work to the connector. If the connector cannot handle the update, the Gateway will handle it by itself. diff --git a/docs/for-developers/get-started/Introduction.md b/docs/for-developers/get-started/Introduction.md index 8e731eb..988fe00 100644 --- a/docs/for-developers/get-started/Introduction.md +++ b/docs/for-developers/get-started/Introduction.md @@ -6,7 +6,7 @@ description: Introduction for developers The MIP is mainly composed by 3 components -.png>) +.png>) * **Frontend** : user interface (React.js) * **Gateway** : middleware used to abstract calls from an engine (Nest.js and GraphQL) @@ -16,7 +16,7 @@ The MIP is mainly composed by 3 components The Frontend and the Gateway are closely related and their communication are abstracted from the engine. This abstraction is performed by the Gateway. - + The Gateway is in charge of communications with various engines, it could make simple calls and pass it to the Frontend or make any transformations needed in order to fit the need in the Frontend. @@ -51,7 +51,7 @@ The code above is an example of a connector. ### Visualizations -.png>) +.png>) With the Frontend we will introduce a new way to deal with visualizations. Previously the visualizations were completely manage by the engine. As a part of abstraction from a specific engine we want to be able to delegate this task to the visualization components. diff --git a/docs/for-developers/get-started/Setup-development-environment.md b/docs/for-developers/get-started/Setup-development-environment.md index 287f73d..0d39840 100644 --- a/docs/for-developers/get-started/Setup-development-environment.md +++ b/docs/for-developers/get-started/Setup-development-environment.md @@ -21,9 +21,9 @@ In this guide we will see how to setup the last two elements. Make sure to have -* [Node.js](https://nodejs.org) -* [NPM](https://npmjs.com) -* [Yarn](https://yarnpkg.com) +* [Node.js](https://nodejs.org) (16.x) +* [NPM](https://npmjs.com) (8.x) +* [Yarn](https://yarnpkg.com) (1.22.x) * [Docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/) installed in your computer. @@ -44,7 +44,7 @@ npm install #### Run the DB -The gateway need a DB in order to work. [TypeORM](https://typeorm.io) is used to make the DB calls agnostic from the real implementation.  +The gateway need a DB in order to work. [TypeORM](https://typeorm.io/) is used to make the DB calls agnostic from the real implementation.  We provide a docker-compose to run a `postgres` DB, you can use it by running the following command @@ -66,7 +66,7 @@ npm run start:dev Once you have started the Gateway, you can play with the GraphQL playground that is automatically integrated within the gateway, follow this link : [http://127.0.0.1:8081/graphql](http://127.0.0.1:8081/graphql). You should be able to see something like this : -.png>) +.png>) This environment is a tool provided by GraphQL to play with queries, mutations, etc... -- GitLab