From eb5e32d5c238e39acf57d9287431290f1e14d706 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 07:09:58 +0000 Subject: [PATCH] Deployed a22b513 with MkDocs version: 1.5.3 --- .nojekyll | 0 404.html | 669 ++ DRAFT_PATTERNS_AND_EXAMPLES/index.html | 827 ++ .../01_app_with_relational_db.png | Bin 0 -> 17952 bytes .../01_app_with_relational_db.puml | 11 + .../02_app_sftp_file_transfer.png | Bin 0 -> 23065 bytes .../02_app_sftp_file_transfer.puml | 13 + .../container/containers.png | Bin 0 -> 2331 bytes .../container/containers.puml | 20 + .../01_app_with_relational_db.png | Bin 0 -> 76724 bytes .../01_app_with_relational_db.puml | 43 + .../02_app_sftp_file_transfer.png | Bin 0 -> 172102 bytes .../02_app_sftp_file_transfer.puml | 50 + assets/_mkdocstrings.css | 64 + assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.cd18aaf1.min.js | 29 + assets/javascripts/bundle.cd18aaf1.min.js.map | 7 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.el.min.js | 1 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.he.min.js | 1 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++ .../workers/search.f886a092.min.js | 42 + .../workers/search.f886a092.min.js.map | 7 + assets/stylesheets/main.fad675c6.min.css | 1 + assets/stylesheets/main.fad675c6.min.css.map | 1 + assets/stylesheets/palette.356b1318.min.css | 1 + .../stylesheets/palette.356b1318.min.css.map | 1 + ...t-with-testcontainers-logs-failed-test.png | Bin 0 -> 531663 bytes ...t-with-testcontainers-logs-passed-test.png | Bin 0 -> 499949 bytes index.html | 702 ++ objects.inv | Bin 0 -> 4955 bytes recipes/index.html | 694 ++ recipes/testing-databases/index.html | 950 ++ recipes/testing-repositories/index.html | 735 ++ reference/clients/index.html | 2340 +++++ reference/containers/index.html | 8848 +++++++++++++++++ reference/pytest-assertions/index.html | 1285 +++ reference/pytest-async-probes/index.html | 1151 +++ reference/pytest-fixtures/index.html | 3341 +++++++ reference/utils/index.html | 1568 +++ search/search_index.json | 1 + sitemap.xml | 58 + sitemap.xml.gz | Bin 0 -> 347 bytes 73 files changed, 30660 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 DRAFT_PATTERNS_AND_EXAMPLES/index.html create mode 100644 architecture/c4/level_2_container/01_app_with_relational_db.png create mode 100644 architecture/c4/level_2_container/01_app_with_relational_db.puml create mode 100644 architecture/c4/level_2_container/02_app_sftp_file_transfer.png create mode 100644 architecture/c4/level_2_container/02_app_sftp_file_transfer.puml create mode 100644 architecture/c4/level_2_container/container/containers.png create mode 100644 architecture/c4/level_2_container/container/containers.puml create mode 100644 architecture/c4/level_3_component/01_app_with_relational_db.png create mode 100644 architecture/c4/level_3_component/01_app_with_relational_db.puml create mode 100644 architecture/c4/level_3_component/02_app_sftp_file_transfer.png create mode 100644 architecture/c4/level_3_component/02_app_sftp_file_transfer.puml create mode 100644 assets/_mkdocstrings.css create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.cd18aaf1.min.js create mode 100644 assets/javascripts/bundle.cd18aaf1.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.el.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.he.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.f886a092.min.js create mode 100644 assets/javascripts/workers/search.f886a092.min.js.map create mode 100644 assets/stylesheets/main.fad675c6.min.css create mode 100644 assets/stylesheets/main.fad675c6.min.css.map create mode 100644 assets/stylesheets/palette.356b1318.min.css create mode 100644 assets/stylesheets/palette.356b1318.min.css.map create mode 100644 images/pytest-with-testcontainers-logs-failed-test.png create mode 100644 images/pytest-with-testcontainers-logs-passed-test.png create mode 100644 index.html create mode 100644 objects.inv create mode 100644 recipes/index.html create mode 100644 recipes/testing-databases/index.html create mode 100644 recipes/testing-repositories/index.html create mode 100644 reference/clients/index.html create mode 100644 reference/containers/index.html create mode 100644 reference/pytest-assertions/index.html create mode 100644 reference/pytest-async-probes/index.html create mode 100644 reference/pytest-fixtures/index.html create mode 100644 reference/utils/index.html create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..8d8f5856 --- /dev/null +++ b/404.html @@ -0,0 +1,669 @@ + + + +
+ + + + + + + + + + + + + + + + +A collection of recipes for testing applications with testcontainers.
+Scheduled jobs
+Testcontainers Desktop - https://testcontainers.com/guides/simple-local-development-with-testcontainers-desktop/
+[ ] PlantUML-C4 - use icons for technologies
+[ ] SQL databases. For testing SQL, we could use SQLite, but ORMs actually don't ensure that the code is portable between different database versions. + Test the system with a real database that you're using in production.
+Testing integration with SFTP
+AWS mocks like Moto and LocalStack. DynamoDB, S3, SNS SQS etc.
+SQS in, SQS out
+Stubbing collaborator services with WireMock
+Webhooks. WireMock verified
+Testing scheduled jobs. Tomodachi jobs (separate REST endpoint for testing), k8 jobs running as a Python script (with DockerContainer.exec
)
Real infra/supporting services like bank-holidays or leader election
+Integration testing - verify that all system components and frameworks are integrated correctly.
+Functional/acceptance testing - verifying system behavior by real world examples.
+drArETK#QTstgNXayaag%5r^K+GhagweZzAF9Z zj&pWFtMRx4+DD!@^M-ZldjnD}oV0ZTvm${CXwxq&@haal6-oyOrPQd)Uj+pO@+s_j z^o@)_4|O_BhK7dJ9H$<>a&pL0*gTn;nLB?^7OUC|FyR99^z?R=I#lQ`;cr6ZX&FM2 zC3JdW4d&+Nq{Pbc*0i7rx!Bl(2=Z0S%Me)jY;0^8u=m^q_V)G$Zhn@?{kZsR8xrB$ z#tGrJw6facrKN>$kw2mXS|aYw%2N(q?Q-a#cD-V|^fpJ;8;CXtNx{4E!1m>Qa9B5D zLQPJv4ux?4$aDDHS^@Ci7(64y>w<3=o?{SF4Fh;xNri@IEYP+Qpms`h_3{ zTmL=r+3CJjL!*2fIxn33TH`DH$biX|e}Gl_cWG$}Nb0SvExY9!8fxn6ySt)b4DEL3 zuhG$C#2W=d;}a9WkXBz`zY}~y#u3)+E-5V|Ln*7POE@IfvADQ6qm#~RJWR7!>=r48 z3RLC(vIHiM6x5R)3i9wBiA`;&^%;fs!z3K0BH>y`=fD~)Fey4hBd(Or$B$8N*gzuU zj;@fx{zcyi@XBg;`^32g+BCXX^3wJ2&U#cfg-L}<0nd;;+;r9E)Hc|b-k(J z@_s= RFp NKski2YPXm9M zEFG;sCfis_L$^;hBipa-P^o@R{w78 -J0A$i@pVk~Hai#b&}J zvR1L^ncJAy2Y>WKAfATkJ~;EopV5czp@7GKyzFoNTFph{leo5zcZy`T20uGzySJjo zQKmRLXOFt(ZDdb5CWb^_i}7f-+=`Eh^CViMz@Zp;r(|TTE-&MgkvTQ2mdlrRb#;}N z%A6?^n!x6%s1}w{^YY@eG=3+R b90zwUJN$W(3J5%Ka?AGLG{I2IlaBUfa5{j zSyKsFTtukZBK}19+zU^mD$+F~_Do;2x*ICS4|>fhb9a%Z+;F6zEc41cn=d!CjzHxJ zPtD(I-g~;~JsFD_KI|+7d&>o?Sz2g|OJ3{=M&}A@AYZvDcpthiF63%#h_jRP4Px@# z(qt4E=7;9zIoDMU*jkdZOw^pz*f%FCW6AM)nW};%BS@{jv}Y2kxx^Qio988bZgTLS znAV{9NmYU8f{KY^?G2X$y%`ewXSsHdmxU#6i }N2i~1pM7UUN*5f1mo>ONGis;UY_+bCewo~KMg zQ4x)WZeyZtAMQz{*74G$_G&!!19k3^5#e AiJ9Y2bEX-g)BWrd&u8Ivt)?VZ@YcVrOD! zXRo~IZ)9m7MFI_Z4}g7RhuQGF8|_y)xacuJLXj@6o9*rZWose@u?9#kz9MTp$&4t0 zPp33ZjF7SaIjjQhyu&-8Jg?rF^Fl)|(nX_@NhzTLoXlf@%@uaq5^DPMErW6OFltj8 z;%UOk#j %pX4Z9_Dx&`CSbGwCcgZL0gK)?(54_9SU?KKzDfM z69BWx7#3KS57|3Zg+BUlIuGOFJw86Kmk7p4JXxNgCyU(4vXSrE(QJ{kI5nByB{XTO zysd+rK~XG;oX_!GiLA4`JGV!o23!O})uJ5quEW#qS;DOI2#;-Cc{x3tZcl(eKz$^* z#)MX=b#L?Y*m_g@0`|4Hu^OF-u+Jp?U zRo;KjzcJFFDM*k+_V~vA{k`s24GH!L8MbC=PJEy8?ru;R(@kN~m&l?lUZ>I`fZd_? zHg8y+xt3B43jX$Mp&nqQLQAg9Sy*YB9OY#2`LPYu)%PH%Ju7Xlbj`qEafF_rY+nRp z?dT}egaBRub}^*D)??-MasZ>`2n?To@x>B{I)0E-rkn$CnQ0JNIhy^BiL3WC6NIxm z3yWUjvzim&uD?TkmIC|u2DlDSqZU+Q4a&ecPBn};Oc}3I4h-A{JHEhPpd6M2W52qf zxU8(mZ==PDjHr7dOzD7pZDb`p@T(%oHxz<(z!2B{cv96q_P4BfNioXKK2bdzKxl5| zxkaBJFK?Iho!U||Ez>xH->*A3I5Yr=Azd*+2z&aQqowMDZn4;U`*g!Is_z7%OX$|G z#H&Qs;oM_$?|rKDSlpi?eYVLA@ha}X2C3+GbX*+XMcE9x*q+YhujHhpf4dHE#*-*o z9-iCBn?FcMNY@2~oGeFaTCZ&DoVQ1#iB$AG=wu=>XRWP#_7`hS6T8r7pVTDilygHv zB}~8vpJZg u>Yn5FAbHz2&r0xnf(E*3lt?k4ap4H1%{-aiM9kn(X- zgp+6gZTmHeri?L9P(#i*Z|rvTw*O&dQ{B=Iw$eVZ{z1mQ#Ur@za~)EwpM(SUK2{1Q zS3>0*PQ3m1dL!ZQR7;ziin*E{ILOqAjK1UzvlMdSUvF=3ySqi2s-yw~dl;EmaKxGL z tH$v>vYlm zRC5W~K 7NV#Si))k-!9~F+KL%1s7bK!+pkaL&|O7HDxWk>Rd?xVjzI77 zsi|xlq1XT#1AA#-?VUSwb8nZFo}yje?aYdU1XZ32ryhuc_ZNSuwd&yV^0Kz3CO0>? zc+dPJF{7}CfdT5 >Y=3qyHV_QN^d*q+KIvk!u9!UQ>r<=x76*kDgF1-gJ_GCtP72yVblW717ZP7cZZ z1Q38LhFw0~dTA>w?d~5Wa`-;O4AK1hA|YYZ>bxtFuGT+Cu0o>MU>Qr$PQ9o65v`Gd z&}^T@qW(jp8w0#GxjEXdVjB2b6=R}krvWh27DsfA5ad> Y9pY_@)uJm8EZY!ZSfYHQ 97tDlY@nK(W*4H)v}&BzsDy9c4I zo2nK1@??;w?lcSv(dRbu*uL9~j}>sSrh;qahi{CCVV69>f 9=HWr zSXk^ngpc=eqD@nRb~!01pt0e~*s`X8fN)Dmqbr)2H7sD_=g;`J|Exd{i_a56*47d) zz(FFV4bg|A5kCfh2`e72-3{;ZFksbFg@uI$I<7N-QxoY(%d4wHsc!Th$QD}_^x4FL z9WFj?i60rO{^uIxgW4s-mA?@a9<*Gxo3N`fiQvgrHilIzaqD+EFKRW*A{6y`0Xj1d zu05-=%zqX@G&snXyHQ^OWGWKTP`}!Is}_5SnYONH-z>91B(z-5nYt48VjJ&Up;s?W z$5_wU0VG5mG+m)U-ky=aR$R6RFmqFWa(e}Pd${W;ic7MZWA^v|rCQ%qS8 ar zctzusJV^XjDX$%j**yY^BJ7=U%um ZLYe{%YF}Ow@ zrb=GpJ^J{;5v=yTDd`KM6g0|EKdc;u0V6@7XuD4DzqAgK4Zw6&G$qArE~Q#0gzN)Y zKzsE+$%&%p|K=u&LWPqzgENB+RDS#~Vq!)r_y3)jm{0Bd?hGcyNwR;9vVu2(M5+1K z d7XA#_C6K|gHZ2a&=tlW z5q)JP9x--QY^T7TE|2kd{HQNl1Dc~qJj1A|;KDsPN-_V*5Dag(gYow#eudq6z__k% z57FmOSDPOwDJ%^37((ILW?dHZ@evrhP?I5lkB9eF5|@8pIt0PtE!oK%t_fNdW>@;9 zT}8g#czCv#2@9zhiCOm7VG}?k?J}yVsbTUz@McZnzDHtxj^koP7LftEBFAw0g?`P_ zg_1phI+;oqHVea0U9JVq6wYSo7v^1eW#ska_slIh#}8hi=~DX_nR(>Px+YD-l&Oi= ztdEc7QVK3z`4)r2?Oi@vtxPS2FyQUi{RhLbnENibv2PbqJbaGi1gN`p!rkI<;*IpB zyKy{R|L6@$4T;z4UN)9th&8f_-z`PR_3<&Wfdu+0f;ZUczzp2KLytaV@u#e8Gb=F| zT7_cN&f0LsQO_IS`;s{x^!g(~4Q41jo5Rq%=uTdFBq;%mVb2@{@8XSTmsNw T0H0SI$B^y2`35 z!>`5BQBi#?=M>EVf(BzPu4FKIhoXE`BiK$Y2$z0Zj9HSFS5iVx5*W7d1b^u}5aa>} z_+Qu^Zcao^^Pjw4di5Uby}wmeew{~ 7AFBb0gQ-h{ 4O7l-4${)X{w~J5h#UF|~Tyhi|(!N)cbfIEDS-uv5<& z0zFG2k$oY9UK4X2ps{%^s0adBDwWXG)YKC*kl!d(rlk=I+Ar02xH*(mN#NbwS<&lp zB$YcP>9`;4*p)%u2Uz>KQWTA{E-v-)%bJnRB_&}>XKE}Fp$m~UIb!2sWNVK0_9TWH zW>)q4s-Hh!JwN=#AQhlaqyBSz4B&{DFckc79}+U>ZKYhHHopg#Y&QUP@nk9f38wz8 z+fb@cr1rSwdy!}vHVud{lvLLIKAArRFnzD+919O;)r)nFZ_{tI{-MRSx*yJJph7aw z^VK)yq63E*Kd)L$&BkUDKdyBd(bvW4%6=N2gu GL1vuF0i^oH12 nLL z2+?{w|HV&R)uHOCCq!Zno^C!aHyk?{g@fVjF%3*?c4DKwu7Z^)2oJALz~CR%OyR?p zk9>08)v&KBB?UKz-m%G|Ri?cw35s%zhd>}+NGFE`tlm;H+7(a*{WMWUw{*Mupr|_V z0L)cNPR{1ik_=M*jU(9Y45l)K0 Zg8 z64Jv?2!_fOz$fn_ExQATg(T6)OJP3u$YK<8p4I5oNeKCdo0vazLrmQxn%<6KOB{sb zH1RhjgXJc*R8Nyqb*l?e{r4oe$HBN)|G@&muh#=aGG 5CGP-aib^%A?=Zu=t-GkaU%gp%k+%;y^eh5W|h$QqlnB@LX;vyfaf(+g<5#12Ybt zS+qzHGo~nGN#+!On2hbp;re4)y*XjOFQBjNI-Fi{IT_65pynPO>+umZTTZ@W84sfL zZv3^e6QqYoM3xBN0#z?8fzi7S^aDKDb}~-WG7#j#W{>QF^||dH*T4F_J078mTQ+1G z1)zcRa!wV82)jxvZ~WJfh9=se){q}-L3-ZQmi;q1&WOLnJn%Cr0d%_|=1pBCvq32b zYkm+}W2mB|Bg@{JqHI*LZ0n{Pn>dyPe!9C5{iCZoSi;oD1AsxGXa3TT;ryf3el+7F z;(1PTjw)qtYg>tkjgOBIm7SRQ`R{K XzP}0zeoTFHP~myI@3J`-#nn;ZM#Fpwwl&+;!wl*!M2mc=Jua;*{*(CdxjLZRoKn zA1jYnpE6n>`TJSTx<<%RYFjB4pkTT@gU_XMogTbP)b+}xZ$Y7%GJS?A8hjvRc%&P)VI zH+Mz=6;dI7l}m&ga7pf4jX;I@HRey|&wcyzK-}9+=YoOe^WOD!gKaD>D)p?gs9WGn z5H0i&Z8uVv(eGRq=m%WF+o8RKYldt I;M`8=CGT+CbkR_foh8(&MX5pqa?48@HXP^U wX&l7r3 j7O?rPw@PV*Yb%>%q?`u4i>1AYL_O zkwS5W?yk|q;1h+C{6*Tk5(aUUq*#W(B|>C>QVDvT@_C#RaGU~CNb+u{FoYve`rO~I zhd6}hKu|PTO_wrkIOE0vsz?zIta^CkK$424m}l`x@T+gTrH8%T Nu+`pA@jNzbT-)F9XWLj9B1V!ZGE)}JRqEU0cL6)I&z6nA;DC#*x9dU$ z>u?1S%WXb*WcyVf1E~d^rg*HGUx`@s@=W(*pU>Vai7Qf`eP~`-&{*8jMI^;qV)KS$ zr|vF~(5kAeOnO>*?(`s>efR$2Avm5uTEomlZ6E8LU(Wk8!XLE{KJntD%kR#h^POB&?P64WwT|$hu8WcySU@AgZ z-`)bl4v)k`ph~rwjj{b3v O?CI0+`QeZf@0L ziRk=TUuo!}4{H@HC6m&G$Ya6AnNBS=HF1v-GX(#{G}MVg_l@oCz*bbp_x4n`%cn_B zts{lyMKOz~52LYl>D^*X rfcWSMV3}ABJ}&vln8iclcrn(5O8zLi&jE7i=_GQ0 z8I#yC#pG1~eA$4uGOyhz 6Dc z1Bf4sB <*!Lw!9U{*i}09UOQAcsx=euLOxr z03Z(G8{0cMr8mf^tK;aA9*i$gx98RxcF1^-WFa`@&fSy}p>}(mt-&IoM;d-HX^Z-A zZV~WY6nhy!R=WP4EC|lxbN!8ajadno(gy6zgoTAC(pm8@5SPB|BP>#mTM+rltpjaF znmITY$dH0+R(kp$tM-5>r<{0hejY1+U^l2yug%3mQZi(G$gu@sr_~-G;6AMY&n1Ed z1OzVcEv&4xwYB$ sNTr9xKLGMFSAYb(lq_%) zE^>gHE^c=dE{CM>I=KWCtEk9d2AyuKtjKQX5M*TiCy{L$^GR(#k-)XxWFTBJ0(~rk z+(5;rP}Z>7eihiV7y~S|7iO}dNtTTHJWD0=)hkLEcj~N)=m)K8F=}foKq=2lMFoqD zs!Bm_n?61+_dQykFrC@+-pqGy#G<3s4?~Dk0W`K(zwLi#C^TK$b-M;gfq}J8{NO-5 zf)~K#H@pW(b8948xRC~7un8d8H=Xr0oCdU*Dxv_H9Lj5mQ7Lr54B{7UPYHwG30ASb z?0kLvlM)>}shI8mpAw8uokE3IS%4%fxlDZd9fz!6`GuN@wjV(F{@U9Uh3w`41@kHq zn&;%tpM%AoCYCL+rze1}AC943 1IbC#;V**Fdk3m!W_z^nh)hmI3knLjDE0k6QLX|!coHM6 z5Bs;zOxwprKIvS4*ZDGSAp&Ox9($%ZxMz`*1m0XHLfAV5*;&KvPYR8jJtdzc-AE_b zpA%lQ&Q~1Bz?v*o{k93HnQK&^{=G9m99h@qFUZQuMt=Ru$jS;9L}EERJ5y2OTcenr znIXSG#>T-3Q|1Z+G*dg+HB8kq(emZfM4evAU?6U7%f{fxH9M(VB?)RFq+zu>RDUgR zb}GsDtQmJ*xV~4c*uPiji~EU}Th5m_OG3l!#>O%mH~Wu0ioDd)iPgSk@5RfjK5D{{ z+H&;0-Pu{=i??T;ti32%gddZv7?Q&Ynp!!^jd~Ru-w{eik@!$w1?aepym&f>=4`-1 z(y?8Y7~`N>694;w{?7JX$91v10dIh2#j6hM)0c0N%;shLcgBZ@hjJ>Lj?&W7wl+cm z27dlkbB?eNIL>!BH->jmo@)T{MM6M;d5(pJ#Wl&s&HWy_pa#%+&@1h8>HXS67pIAL zP6sdz5ak@eU5C}24BX)=KV!1v+`Mq-c7vW(-X*-saoR#-tGQ+OIY0#jjfh +2%w7|Vupyio*o;byv0TZF7gr2^dL@H@{uQ@7Wh!PSiSh6!>j(h~?L zwy#%^&8XPQ`zA2ix@s$9^=~V|Xd|KXR}M>cg|173?Je*G^1JFfp}Df==Csm`Qhpsx zH9&OJXIeMPA_deK;PT2TOrB*!M)Ugm`bQT)A4>6aEJttbQ>ais8vo~CgMb K zmY6RwJ$y8y4ZC98cGBn&?GsEsz#|cBLLT{4tMKu#ALl)N(QIb5ee?IO>sg|-0iT%* zVa8)z5MEBXm@oc!wUHp4t)GXeHDs?^UWzdlq;)qKeCxhX@nyWT`~3jEvYF!#Dley< zk?FX0vv5>Yj%eDpC8M`L0(dmmEnLLuX%Z$y=08$J{9T>$9ZW|+DyTvQ_n!bo*6$;< zJLOjn7qZ$@vmit6riqEdDFK7<>?EzNFyqYN)FrRdaJ2frLG!69TzrZC%G E#s~v&~D*yKO_WFi~fm9pnCtTpF z$ bgriTZ*)eD2C%-5g;%%)Q rFK>hJ31;BT9+T)tBg3{F;oiQGP|)!e};{s$QMo=?D0;I)FEb41NU( z75%n8f3!aRp)=~bFbtuGN|a~jy2N8KXa%~=;Najp3jVb~Ha0Y6+Dzm|w5UAoWkBQ9 zep1+xe)P^FC$H?bgRUV=HrPdC0-B!^VAhm+oveLusBwvqobh$lcs7gZp>stIngK Dy z?Mn2nR^cg;H?*@}q=^WI-q)8AVO*yb6%*on#OJH#k0oUe0&iXqIJx2&iQeZH0~DLq z+D|Tuad-{}dPbEi_9an4tiD>Lfmf}*HwKB8^mH1G*Of3cU$csMZng*D*jOiX-sTta zn*vSqR{@Prw$k#OH@rn{e05l6AI|Hau5+WjyV};}D=+(q4)wzl_0&;Xuo^Q~%Nhq` zJ1}f~r5%}0dGAY}H3KJsLp9jIQeeMUG#b)0&e3QcFzU2^XJ98axkdmpt^+zwNJ=to zS+__BhFGGSXh|+oM6^|SQ|T1oqEhSpj$N={T6(&brRCgQvy`D>j^m*^CJ;}+40pF? zS38v>sIA$G>c8~u PgKK^CNEo2}7?yn1qKFCPtXi*q@UloM5WKak>AUruj$q^F V>;HFIZ)1hZ+u%0i6i=uz-9>+lNZ_ -%!LB(ro;9+lX zucV};p`jrqB?a7312#iEGQ2GM&IoZ6=y#BVwQw}z`-vv8Pp1bRM^ZM&9tlwt)A}{& z0ab;XqSig_#fbt`H{=&Je7q|Tz$FNpqN_4Kw+D~)=e>i7nhs+a+x l@xN|qU~x3$DpElYg-zDw!PZkNj8sbS%(_W^a>kUfKkRj%cvjM}HT_&2*PUQ; zr2e@LYd}M-IlxWn3EnyKi1Scrk57!8fN}`cB#d8KMfJm&=#83`qyEQ9fa0o$t9R6~ z1-O+6bSP$n 7+G@U>GO$C^i|6VaUra2FeqO5^gPonx3BK zBSqBJY%z7d*HIOF%B-75Yy4 ?a_wXrjsqynFZ)L} W+l9 zj+%p=v7;hJ8<|2Ks#o}j?_C t1VM;S^xlaYHG_;6oJ0_gUZVw32NObq5iLhAqxarobd#9qQtp TdH0qhEbxWls~(pU$S^nv zF6*OeCniIQCEzK#y~$4JSrb%w+rTSbEQ? ms7ai#m V!_^U z0D9O>?(-@J*lz-xrib3J1%mwJ#i7>*J-U!DTy!RKAmBHwU3jl61NS}OlL!EfG-Ir; zo@NmL_-ffKMf#MG=~&6%ST>0xcwpSR`0Vm7^*?ZSXlx$l9I&4f%2TbmjAzA_d8)0@ zInhJuNN11!pUd}i+*Thft)JVQMocVkCL2ocJW0Oz?n!3IbjhpV^tV3ir-!F4Cypv_ zLs)TsbMLQc(&d!$)|%N7ku~o}Fx$JaLsg;8L58HE9^#Pthr9vn%fu#`6V20s-F@EO zuU`#1qiWzX!Ef$#0u5^A;gMao&%d*rhiPnb9{b_=*fPOkYpV~0>0vGVEbFuiDbwpa znO_-OnPe{0r8BFg=!zpsBuQq7Q9{yk(aRs5f+ z_$Ij2nWbG-v>IQ7YYl|OFb1(@FOs}9hnfq>!eTt9=?(L2m*(a%Qt$;_f2#qZS}6cV z!AL!#DyhFxRWzA}$RRLVe(2}Jtz|Soss$>j#g3u-*MxL5;tS;*kaxY7-e{?!q~CDw zI`8ni?pt`4GDPz?q|T8jJpQ2?W2XIeMyc4+fr #P zfIlLrIyHIgkN=t#v-ejgr|sllZQG>y0s#;)R=cU(2}tO(qgEKs^wrz#cZVMtY{p#o zB7L6gs^bx&;InAKNqVP}t %t(fOY*VpZi5z_8cc&Ob-u~W#x?l@N|GNd{G3TJp zYF*b#4jJDk_T_HG#9f=PC%R7s1&a;UsRgAoe^`HBND-;9F4p&>Vsa$^$7OF&^rQ&O z1ZOCcB-C%@_xPgi94sG~U5-EI{rthNL()uo!66K;q_Tm!rpB25{S9uN+~Q$Su#$&D zP+-ac#$13-)ClNchq`bP1wUm9=tXAkbK*|i=Q*#^R{8hf=i#hx3pdtw=i}}*3nJcS z?Q3!bfYa=6cIA4StWh9%`+i6_f0GpGxkg;<^qBNpuxV1IE{r?RetKHRS%U7?!Khzs z+1=urF-u; Gd*PD+=YjQuty4`irN0yF}n~54c<-H|E=)!Ihe!#*)kMR$U8ox?3sq z>0~+KbH-DXbl%A8OfUh51ZNgrPZyNK)Gs*p8teZt&P+SBKch*LXvq)ngoBY;a3K0~ zjw-6j-hB$O)N0uXeO1l&69A|OM41qov <##hT&+<;E0=2`1n(2rm%~ zn6YTHmAD)MX|@WD4rrlENVjd8$+8+feN=RAc=_pb!s56DSvOZ#Z*mL{gZ4t12}&vd z0gNgZmX?u(*KV$jm($bJ1Hizz@vOr#QR4#yrx9Yc-qDKVP0TF71W_ >-e%rtA1drP(o_1l83&9>%YC7BG{A-h8$i>yAfS&IFCU+NBl#7;?04mX@~Zkp;{C#N zp0ORIDb$WG^yk=dSr;Pc&z_v|sb!(#>Y`-PsExWh)I`LP#1I(gP~)AV2JColQ~4La zA=2c^3=IHU^s(Iy-Pz&co4ZddA}}EH>Yffd7yZh}DIrb09D$Fbw)!IDuIFy4I?40H z$_v{Y5)1nlvL~-
eP QSil21zekVwzpWvKkZ$QCys)`+mksU!QF?T!sotP0fLzwX2SC1U}n>0(Qh0Urju! z zt*L~6QogIqcySpAtJP*jc&4p{L_kk@%g zpijOUr (&c(p}=gEzXKguFQ1SeODl%W2AzBB0~W_ZIm&+W^8QPS8Bj^^ ztEg{xgFZu1IO!Pe-Ck^*2_IioTsHHl6P7XLd+shWHdlMEzg2wjc}F|5q(W>Gjwff) z!yc1lC4im-{-9DgAUE}r3TZ$3?$CZPlm*>FhVf3g)EJcUH9{?*_{4MS*?L#u#0_|n zpm_*O<@kP7Q%T8XD!d6<*$dMRbJ|`06Yv%%nI0a#w684M!-#Lk#te!*D^XR7>;alh z39Mp^!g#sW%uGz0i>z|5^In7->EPL2nZVa48Uo&F<3Lt W$SvW77zSO8Z{vWJi zUc`tn7iyI7ojVN2B!6~8Q*(25a=(Xy{r7&ew882@wv{Ekqv*nc<5YwrW-mm*F4Z1J zFbVysf{otl{DiG_0T=z$jEVv4_~XKD6JEmxwM9SE)45Mf@kJIOemW1q&7)e^z3SjH ztc ;z;*F0gaDP*~9 zVXU)WDsS`rMZ`**yP_;Bz7q@zoO(j7%G!l|8mwx>AUQg|nTwTN(jP {u(%^F&3M}zn6*AA)!&ko9FyqK24pbV&LmONUkQms zrRA6tHW^S3c1<5-KXYJxk$97r&4Y)N^Fellai!GouWa`tCX9sZ-h;it*B(&g5t?bDUb34C)@@ *eGf z3EnnyK6Sx3s7R9bOMe@=Q6aZVBOzWyh#lr)k1}D=K5nvV9Qx{`Z3;};*&cclULT*L z6R%oh+=GJ=GP&-#L?qA|8{$AhNDZ=C%MMqoXRpi&E;jxLG8!zWnL03uN4Qc1f@gwY z+uCQUA`N&S NZ6V(LOPq z(YB)Ga?`<~2?+d~8dRd3JUqxYl8R44`*P1qzj$8-csLDH2jPuQPa05cxc9`w$S7j~ z%VP#VBIXTL+$UB&Q|tM$uU21VBMnTck<3oREtc{#sR$v~X;KLzO@X18j_IhfpPbx! z3=y(a&mFo{{fPt@se4CPKy^!sFe3Cm^Q1e}#RcW=Fx*hO+ChCdh?$L%v>fYew7QQ< zl!)^9(E|+qW2zJ5n3J28b}u$6UIxd-=$ic1esq#x!rqpjH7Pf-6~1MI2F&4~GqlJ0 zoPG(iIB{@#=hu=RrIlF =h{&f||6%=+6llw0NpbADO^@Kgl9*Cl%WpX{WbW+FrAk^C0 zLdPMe0B5*w gmZHMt09fTn%gsQZL zhz7Fu9GgEqZT6}d7}@+pY+GW9g=nwsb#-(+pu2td+dZzt!YDQ|F{)Kn(k1SpRZP~S z)eu7cl}}WgIgD0bBzrx%v9YA-YM~?7L@H$2{YwSX&eeYs1K6)r>*sG{uvjjxv|b4g ztG6ZnVCCv0jihr=i$h5*)$7H1W-TPyH1rZ=0JBnXk+!?~ka0?o$1tdQyUU`dPS$LW zHP=dk5iaC`yTZ?B;>gjvoWTv;5sQ^X`%2=SbQj3c i=}8QW0+LOJxJ-kA+E7pLlKg>h#wMSBZ@d@g+HKIuB>Hr=*8SE? z^W3fm4F=kUxjBKw)m~8$M>yW}IyQieHvUYL@!{UZmhS=Ud~d79qGHxR2B@=AM&{;M zG2!Q7o~P$Bc&S|EY`Lkask^%#4Qok1DCO2D4X_5|OwAO^r0Nw|R&R#imSzC*9&vpr z?nQ2tvl!7nXh~kWY)qN8c(9v4dfJViQj4!YcBveFPnA2@uxe%O9C02oe##^?%lht= zBcUWnH@k{~2?we^A=>8Al!!+=-oxdip}wv4(f9bl-Ony)d34@>$qr!By^56@FJ{5 zO~Xys?s4j|jDK7;P=1!EXAwxl%&aYjFLi@_qMVUJRJd#s0%atqAv$0n>K_ 8(=Dv*kgi-}ZD>{sd6J0ajj@?4thGRE5BUo#sw1=VN5)4NTz^;;5cE&+i0S+zgv9 zvPaa#+Q=KYiYW<5?YWA_zZ=iKL}GR5JUJcDBl|dJvYYmVJlj|k$}K$ZFRb#vH(RQ| z$@|1;>f~gwAU0aKGaWf4SEXc8qnxb>o5EiKZ$u(V274Ev`M*kCr_8|K&DrYP 8jG_RLFM5Q<3T9tGML#9MmdS26)QLNrQ4scirPY(%ZwaGFB3ZE! z#%t)q7 XcKLL^cXzCuX-dp5hQS*qj4LAtiTHczddJLKy6c@MT(wbbb9cwc?0 zBtw?*(-S*99pG&Ro#iqXWHSC~8Q?Oyw}-9;b)aHeWLb-(AnI_V5q^eLwKLRW5jCXw z@Ad${$_2mu{{OF@1RvK%0F*jD!Q6hL4Ts cefh~ybLFxa+UyPJ(R@imMMt?(@xk-|0jvPv`v3p{ literal 0 HcmV?d00001 diff --git a/architecture/c4/level_2_container/02_app_sftp_file_transfer.puml b/architecture/c4/level_2_container/02_app_sftp_file_transfer.puml new file mode 100644 index 00000000..c52efab8 --- /dev/null +++ b/architecture/c4/level_2_container/02_app_sftp_file_transfer.puml @@ -0,0 +1,13 @@ +@startuml +!include ./container/containers.puml + +title Container Diagram - SFTP File Transfer Application + +appContainer() +externalSftpContainer() +s3BucketContainer() + +Rel_L(app, externalSftp, "Reads files from", "AsyncSSH") +Rel_R(app, s3Bucket, "Transfers files to", "aiobotocore") + +@enduml diff --git a/architecture/c4/level_2_container/container/containers.png b/architecture/c4/level_2_container/container/containers.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6bc16bfa6c7d04232c3a7f415e8a99fe4c1cb1 GIT binary patch literal 2331 zcmV+$3FP*PP)^?c_3(XbZ~PzFE4OxVQzGFZEP-MZ*6wY${zp#2#;x0Safh~ zVQzGFZEOGm0001Zob6p*kDE9Yeb29O+kKcyZ8s1CWHhQ8NRZm?sNH7TKCD(FLfjeD z3}k^!XLi;9zP1CzU}GTjfwjwx)K0+1_i(vBzA=Hki4!+UwpZ)H6F>0Q+Z6;Sw)U&7 zo!eoMxPAbm*Mq^6O%!@?wT&QfH=BIV(enX7wttUyz5q|Bo6Xwy+{6!qr|9j++vG9~ zUVtRL3RkXo=|6owcmjh}-e;lz2(AgzUC)-4j%Ldvx*c-zDSr!AZsIQ87!u!MoLoe3 z@%wxHZie>6Nf^ObLJIIEff4Fy@hz!7*7NyIazwX8{o89F1_@X=XCFZfqiYypulOzg z-|^Ql2FT5|zk(~Uyag`s2trIJ9$8!OJ4~v>p0&WvMqo+)#vZ3%7ho~Mf4vQMM8P*i z0^k_97rZFEL2q#~4Bq5 OH+nA~n4KH6O@)FLEH?dFKTws6~`Ir=y8J%8h(GuRm9Mp5`9ZJwSaofz3dox0Li zJ_8uVVbH?4hmu*?9Pf#fTNG#a2aLljSaBLoPL}wLy3uWZo;e-roE>Z?;WoQ0TM*AH zH@<|ca;&}YDCzIR6@d^(n>CVzoqNH6_*prs@4>M1hVi9xLnBtpd>>d2ju&ut@N~_C z49TuZ?1ov_EXd#$l3*M?P&oFw*L6%{h!Q05;4-}Fno6orG>tknsu}lnaDjM`dSVm# zF+7(=N2H;YN{TdmGIf!LP%1Rd_;jH;(nP8tKhm(um59seAW=G~Cy_wKw{Zfmq!A}6 z=%m6V1(!^eq#% gNP`&cE-YFooFm)c4f+BUqreZW_*Tv2shLP z7fZ{W;#bvTjWnFH)f#CC<;ykFFv`|z+7P0;=Wo4Jhzg4}(!{B_TGKJD3NhGy&be mL1e zkNHBV6~8<_dNHt&qk-Bn_edTOkLDk~FO3`Bn(Iu7O|)1iz%;VE#ihZ#45)MgJ3p zX4um12cS(X+nyR~Lx4VaQnN-40E+EUX4C?dxl=H+4q!Va)5QRz+}?2%5kO(vI};H= z=KvfLz~TWk0btGp7y zN2J!oE7=R*O27ba5(Xqy_GQ#T%p0ZJ)Q z%z$7=oF(d?J4DC1lc~b)<%+<_m|E6E=QO`BnQ0DC$A)QA+A=mxT~jInMtZcfiLQ-C znvuoJ(zpPPJ9<)x!U8x+LD@_#1GvMVvbj 0q``KwP{;`B_Dt~2ENRf&7c5vsfR61zciQ3+V- =O=odzmVAKe zfd}0_toeznC@}KPYB@D(05c}}Y5;li 5QXwl_Nyw;rDhiijBE#xb59kyy=48h0YE#;sHc++MM%gT&!It3($lB zn+1%8fLU9>{B8h!GSM=Ct*QHP?cX54WMZa5iiN>Q0VIAp-K~-RiT_gwz@`A?!)G>~ zkg8v$0b>G~Q2=Y-CPk0L08;bjIf667ssT7tlbU_ 9`?!i2;C5vh-=2YlS9~&ksGI z5>T$DY8I!;wOJhjW~QBr0i5)-MF8HX)46ELf;;t31psalD_VAWXaI^j7f?7E6u_*g z+|7cM|2v>{Scej(#$y0@Gl CA-~K&eKmOGedNlg{W;3(KBH*xwi4 z-xuDFNPl0ry!VCoH-@+8)ZZB1-xz*RagyxD@OBS_$sa;<-%PcUIh&1Hrox-XWnfc& zh*gJFm AN3Rt1$ccRL!ApQT1j_hWn;efdV9yt405^C(I68fM z2I6oVdFbH%IEnn_7XNhB^T9j!+6AAsLE>M*WAI@EgLkvvvJGG!T>DW-eqCws?#t=E zfv&x@`~)n>FHV6kr-Rw<2bmDU3s-({aST46IWNt@dlZc=3hXg}!N5j=NTS Tb?&;_U~1OWBFYn54)25A5Q002ovPDHLkV1nyp BKT7}r literal 0 HcmV?d00001 diff --git a/architecture/c4/level_2_container/container/containers.puml b/architecture/c4/level_2_container/container/containers.puml new file mode 100644 index 00000000..a45d1df7 --- /dev/null +++ b/architecture/c4/level_2_container/container/containers.puml @@ -0,0 +1,20 @@ +@startuml +!include + +!procedure appContainer() + Container(app, "Application", "Python, tomodachi") +!endprocedure + +!procedure relationalDbContainer() + ContainerDb(relationalDb, "Relational database", "PostgreSQL", "Datastore.") +!endprocedure + +!procedure externalSftpContainer() + Container_Ext(externalSftp, "Client SFTP server", "SFTP", "Files provided by a client.") +!endprocedure + +!procedure s3BucketContainer() + Container(s3Bucket, "S3 bucket", "AWS S3", "Internal file storage.") +!endprocedure + +@enduml diff --git a/architecture/c4/level_3_component/01_app_with_relational_db.png b/architecture/c4/level_3_component/01_app_with_relational_db.png new file mode 100644 index 0000000000000000000000000000000000000000..8fedcbea08aac53c8ce591c58f5c8625eabcb78c GIT binary patch literal 76724 zcmbrkbzGEP`!71QfPjKhQX(*PcY}1NbR*p%9V#K+-Cfd+l$3N!sf2WQ*IxL%&s*oW z&u5=~{_$qUnKkQP>$<+R?jQv@aWoWs6bJ-@CMhAJ1cAWfLm==Ck6^(&^9yHX;6m*r zs_tZDYv*S5*2D=S{?_KLgMrgqV-iC*5;G?!J4bE?20JSQ8z*OLD|#ba>vzNb#9*}F z<|^t=f4>ib0pqx)?&|z-_`!+kwXUYmcm3pxp_a=Sy*xE0xhna#74JLV<4BoCGvqq1 zED3bU?lG&?1ssSi3G%$>t9J!jszC^6FzCsGaPSBxS|igsKGp1TKDblkKR+{ak0A!m zElO2Shg%yA_{3;)b8@mCa#-n}mc`etZU^}Pdi_;z{{8D}70*r%reH^5me+00r)+cL zSl^h!^7dZT`R}3Kqo*0gcumN%PI%pFo>ycy*#F+q3}N=EEumEQFe-I&xt4NCy%3JQ zz~8l--H$A<>>sATiumxU3(s}t)`a%3sI{AZtoc!^(i7=m7?t0_&2z5muO9PdzuPpZ z$@NhloSkYz4PK#X2vSi{Nv-#&s2(`F&C0#}yu)UIKbBN!t7-)+Bc&rlrXX^5O6 jmApHM!i6sf>AraskfETj~2Y@pnC8vV0nw z;qr4*s=LFLMjipS)i17x=k%7@E?+d-J2bVT-qMH#2%`O(p+BlzkC7tzrJ417OmMh| z9HpThSM7Lzk|f<{+mJzYg;t{ZVpXMgg^g5=V(kdMT*E?Lqv!p{vX1<8_3#<`BJQ^- zPSnvu1uC$5snvP?JY0mv_|x=_$e+Et2G!Q>9Su0R n zrF FOW-!Cat@IxDPb#Dfrwub$(igMLM8yG8c)LwewWptHs;NoM5 zUyof%r5Wv0F;MdBOVe>mC23jp^rqdW6HQ`f@ARB4dBoJ>H{lkFBath4j& zhKjfJSntxFN4A~4Ru@U!M5x563mWODse4c7ZZ0u-z4hwu=b|i}^HI4iEt)vgrGj0; zMdzAd1;cjy6SDM@jShwCpf9V=?~84mRx+;wl{DSM8@kGB?+8ARFjSk)zCP!T`{ire zUOTdeNL$ITX2LJNBG9 pb#5c-0fEQbb0F=1jhF+foH-3ym0uckS0&V`0P~8qyus-nLj% zX9a>jb;}9%)x Y(0-sK{anmE4!{)+BjPjc2VxsYt5A? zT~zZZ2@As9RHTFw&QnFizH*-$v*%yuzJ*j5;m>6RPCbnYMBgoS><9l~^`q^UvVgyw zAKA}_C= $0SlrN1EZ{+v{wCUgRDzsrtcJ6Js7$(cTcEfL9G%Gfbu`j34XVvp#-kpXx z)gnNbr377CC4w{&MzQhm;^2BTZo9L!5I5FNam3&HMnNhl;bcU8g^=~>VMC=Mq_?4O ziIEe7AUT-rx#oGICTT8G5K@++Jl}lT*LK?hX%2!MMupmez2^<)8h0J^+@YvRPRDBg za+w0@G6mwV-d`y A4j23A?ZX(p!$$ZB2F_p~`Q O>AEds_uvQQTFvcaxh7Qm0bT^)9Mw81d|;O1V2f zLN#IHZo5?=%HTU{Qywdd=(G@H(^ts)1T1~SqDs|Kj}+Lk3?c_*vOFm|f_D#n^E-vo zf`lz3N|>;+m_s3_D345EJyWox5YEGawHOj93>6mC@tR7AZOY+{EAsU1gQNNN^YdXC zO`?8RUyId5A!N`YtQ__UM{C0;2gr1D4!R18#7IF;oUaoOTACm-$u>MJhw`H*4S3X9 zuLh)gqU?{Urd#X0@ZJ r6tQ>t z#9=c<`B4_0%Zg&ZF{69VVQ-fVyqY|z-qJ#1?WH^+` QxMdP#0`*iurWM~5&F zf8QOeVncgs9*z>y$QS0&Rfy2>WIrUkV8U%S+TU&?BNpNpGgI|8VIA>F2`Wrc%2$}l z4@qB=saN*V&8()v{bZNPA=ytwu+AEU7D*8;(6frh*oZR86C9(pr6J$T5u*Dki(vaj zLm+IZ5^qQ#5ML;g3Z0zf<4+#i2qb&<_D`St=E{qU#=>!yKfTJcAJd$mTu;E4aKeAN zgBs|yH1w&x)z0nQzq99HEmhx$)9SGgDUW0wQ}e6= lr74soEwE?rMD1tfGPM73kZI|-Lv&65J@phld2`s5Pd*n1EB)vYr z6}nU0X*^Ob)c?w2q(INM&i8%EscB;+jEf@T4NL8)c zp&|m_t$Pr^VieZWJc?F}&5AAH0h*)aMG~d<@MqVitq)yp%4X@tXgbh00ef z>FX(KcSG|KjcVnxm%OBY;(iC8o)9rT({z=+uB+*K+1(L9Fo35-Yba6Y^m6QjKiR;u zCqz%tJ3f9qSR`pa<5S#5T6)eyNfplQZ}ed)QJ<6IV&6rkg4VWfk&n4qJm9>SVK2(q zGeVoJ0u8b5E9)!RANu+)9$S5M6BGXP4lhh8sqLtH1J|R-M=+Q#c5TgnQ9mI$G%)hm zP9+gET&^U9C1c0?@lueq`O>UO2Huu`ap>E!71@3YhWWf==f1E752^X1ulvG8E3vr- z P$F26O%M9~9t&!687$rX!HZH@|)qsZNdpFX5NARKY^ Odoa)cy6q<)AVFZHMoA%G5%3O@mQ-cEGB&?m1v!D$B`uQHRe-#NrJ@}L zE6a(N<_v!_XSg}7^FjrklkJ7e20_YBicPl0h5)QyV6*~1kHG!lw& w5jXSCYOlMaq-UxZE~gWMa_vf4wpSAN9GWbUMcjh zjCQD@3@pS=rkj2yQP#BFr8#kcg7QP6DHL_bn kpF#vlKNKC?v=1|t5~ih?$qwrB+KiwarOyXTy(A_HpM>l@09Gz z#(6xs8186~&DA;R&5!m>Hf?`y#UDKg+FIGd}YGRUysDMih@}zu90; zoO2d`B{Vvxl|98O^4Kv!nG3DX! y;1lOWpx4ch+&w4HY&;#Z zv&OboaJ%0Q6ft0($-w7-;Vltyar%)N74{is*SKy}x<@Fz0Nt7DYHZCmT9OIDD=R8| zdzRKOd}26`t8JFP%H}J?Nwxr$A(A3ODz3UaX-KZmzMr4JE+2;%dZO}7 %U7ihkz;6(*YBo?@^ zLmYs8ZATQ8121MEy~yD50>TA6s6O2P^rhsO7#7oET8%2>u1`-74-czNhOQRw?_750 z*qD0rE>EZRruj{7uTGILh?;%wTkYF3g+6}x@S)Cj!DeTY2ZNY@rOk8iCs(BmU#-P= zYL!9-B_+&=xp!f+b?n=2Tb}+t)-cQLVqa$BXw EnyU)kSADjPifb@YKFVGH9LEV9W}8POt5HvN2{DiTq|N zBMo5yHlD_3Yu*@r!p8u80Cn+=nS`97k&$^xWU9hIK7W7M3ywOgS!VO`+y$R|oyXr< z`1$!yIEt>xv3UcuO!wzoe6DxvyF+jS0|M51qdxNLc^)Dl5%9dDB`06KI^C9+E3i#w zv+VKk7|Rv~pQgbs5t-?%uI`bkS9@nMfZpLLi!*rD+!NIqh@sbDXV4jd=GOMb?KmIz zob1h%ZIk{x9iu J+YmqsD8 z{e^9_&|Hp_CRmrdwG>+lD74;eEL$W9lg)A}H~+Pg%9nS$(d5$awx`0-SwmkHY0VX@ z(gc52DH`9ItuFoS1E#6- x(l0_nq3w tN=et1a|$87c7vc+ z#+o$hYoFt9#6Bv)v{uZhq8&u^pDR7i_t5ZJ3oX7E*OU$ $YsP z;n1o_PIWfB9naX>3~eKn_Vxv!y>NXo5sW?X_~PnHiOPC8o=$6RAR!_^tKMcvw3#d9 zIgMD}XUX#BqkfhV-p 7x?d9#k#~o-ri@eX_dSw zEi9xgj=9P3x#PMvSIbqLGvaaDP$<*pDq8|YtZI=Nw`jmgoA<`140C(h`W-Ht#WU4f z^9c$mQdWg}8=bt~4hj#8sH$K;#d&qVgaoyZh-hZ7Op-Oi#&^jl<7?xM21f+$Wkktr zS!I$!rdh1n@E=MB?fzs!K1qIfy5j?%^Sh*oSCVpt;^RfiP<-#()9E;+fzmmL&gu&N zS#6{7*`zo0?RnT|6y~+#J}<*mOkO@LZIN0zQJDA1m^fL <*0H+~jf3!< zTnU5eaO!x@uiYQ@j;J$D&NN};2Ivt)oOUF~hijh|a}alfCko`(Ni75;i1@OtHw`9@ zRwcNr@>@1m`eHzTo--1lYAN4KGqgBeotUF6W|ydy+srp7Av&z~cL&}uG#|i*MNf2) zsfd(*>okPUIU!{V2=m}_U7ziiz*AmFWJ~h6?42;C(q=!bVVY@^%`a|zKF by_ zQ0ILkyQ-Q&nC3%G&u7|v?&G1Ac7>uyW;Ki|>t#A$T(OIainNVwVl GNtf)AW&R6vQkgOwvxn5sBEe%tWk0qWS z|KfN=pmC$Dx+a8v3%>+st2T9PJNf}hNykZy>)ieVu>2@}2%J a#@zl- zbs`h`;Aw^jo>0Wtwq6DVn Jqq^= !uP&~(%gsq#_I{o|9$gAjYHXBbemkVn?u0~g zAz?k9D=FoB#1KxvHU7oLb_;(ZD>5*vUT8Rp#dMsJ9JLi)sCw-!V|)xAiwWhaG>sx@ zsYX5Q>Gt$G7j+_!){sVyWDEt^9o<@s=lkZ(C8o(Y8gFBYsF{gYOT~N?Ht>_R;PQVA zG}L{rCCH;j;8&K{%JsTF%ae-BPDcq-Dvt`67r47H3V(VR+lWwY@{T}~P&OF{&1vta z29>)-N!`x_<{<`k_UXjNS!8MQKUL`XJ^2pRF$#Mwt5I@;^8G!&H7s}Z+G}o9OI-#t zQMt37+0N|*c|6omVuATiyMF)fo4ea 5P<=y`9ae zb_F~nB<;ypZq(!q6YX6=SbUEOf0T(?&DHdEkR?@_Q0q6rjYhqiu6VbrN$yKipi}0w zInF928-GvBp}~EUZ?NTlEJp(>g)gy0B&f#Z7m9-3N G3m16{FFZ`4tuM?WCuRuFWvmwB5P1oD9b%z%l-ud^L5rgA|s#RqoJXlGHNrf z<1Wc-=rRseFZY5k-R=9_FEj3SW4@`gKq_ZKt;Tv20!c{zkwU9NbAyT+wKkXKFDW5l z7NtHAw79q^6Y|%RP;R%J%~=u!I5yxg=&Ib*%om~dnMU#voqvjB;R1Nts}gg>86Dvj z%Wo?q6Uug)!hQ&t^r&JJLEbTD)GS9V%&b8^gTI3er32mW^5|_Vic+J)+bP85{y?-B zYX%!;69=Hpb`2sUWjed9TR-}*TrPD6_K!uX$PKDyi)dEcR3j3mj=!hA{VE%g<#vdN z%U{7*-}jj+x<9C@^irM)d&+n7EP5)xc$HF>DmORRj*7{4o_F=xlf!8}AN$aQ0$PT| z)meKoy mDeCn+tx zZPB1E@dZN2tD*h}nxf6kzWv-Km&CxpC|LfGFPk!67Zedu;CFHM!`AT?E?`Mi3^r8$ z_DcR$d*i-na`7 oj%s^sw9fya*)ru3$tC3n$`B z4gdS!wi5bLRVk$9~J%?vII=m>I!&dzS!ztq9uV7<8Kx1E>P#ye^Mc-NZcSGsVL2 zc{OXy#z;kj4;cGG6+W&?eb%ejFq*3|CyHQTqdAc6yt}(gTH{D!6IJ3;tYh2l M|f%lG1Lozo?15#^pr>1hH!{5X8I-mP^MJ9(2CdAfA9 zMDLWuGARt*Fy}m4nwu{K_I@_Tm>N8mA5a*Y)XBNkZVXaJUhLm|R00H7%}mW;R#ui1 zrHH6)^PyP&lHtQ1NZi-RrE#;E3@)NvZqhB|)2bQXHVxs|+>hRg1)BE&v^2)(e3Qv$ zVi2Q2iFudFDD@-xzC3X0C+sRds%5*AN77Whf4mVz~H6S5B%1Who_0hbP^iqFc!p z4RMVf=SDhiHIXfOcYt5b$dly&GvE>9Z{hD_@G{zTtkH4(CP2I*?wy$pW;EK>s <0&u*K7)Wb;TKTLt{DO8CTB| znM_C0
D|pxb$z zw^lC6)XKD PM~R`ELD!RGR}sLJY7ZwzE~DC%|FZ z*~(?`^BH!1YG~lBY)?(Sxmb?KMg?Z8cTh%NzU|#^@&+3eI+^oS2fXL&_CHy#|Cns= zDm(`Y90bBBp2BV|lEC%g*dT*1`92~%{FRCRzcF&il9G~9QBeS8e~;Z>pO*vu`J>KS zUhFLnk1DFKvcgMfgCee3u>Eq+VLkR#xgJCO+Z50VibFy|LgR{B1_c%{b|~v388|v? zD B=1a1yq*W3I8Rw*M?3F%Z66ALSjNIpNT7(sAA zP|kO1w!#3;5_xHL^>n}OKKSWuC($k9IA(FRVvd+045SQo1>P*Jw^za<5{UJ;qDfqi z`SzQkcq|)*J_n0mCtqet=; o2r=jg5`Lz`y_t_Ke-_$oR~5 zzS-^KU`a&_DAZ&QTYj&rlOOfAF+RWovi3_$tA^n+32W|x?&$37OkuNJTVJ2f5sv^u zM?8YaJ_^(GcUKS$9OA|G^|!9BQA5fJ*i0c3sNjTxo}W8eZ2!c>1Xwj`x@y&uH&Sy$ zp0tRuQD7VT@lwH#M-)RGr{$)~bfi(+*#LR_a})gf;<8REb+Q6ARaZ}}ujfFMPvwld zp?ULJVNKK!i U4*MdfDEXdjyW|m9`d~&2j$m^ Cy#P(Ea5nDRHSF#vYgroS&moJ5amIkHWcwfEx$mf|IM4|GW zBo1rqs~u4W^IMbzl%K6$9)Qm#zvFV+WfnwvtH;N*c$_=b_6PA4`|;(zld=Q(0TA1g zIb<2ySAc)1p2KFctvGym;r||crp1G!U`#H;fa~z|G!M=*{Ari(BMb~^L|dEB6l|z? zOiYX$46xwYGG&5!-rn8>?dnueAP?6r9<0D7NDyW^*T49Ql0IKj>O~%X